Annotation of sys/dev/ic/mfi.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: mfi.c,v 1.73 2007/06/24 05:34:35 dlg Exp $ */
! 2: /*
! 3: * Copyright (c) 2006 Marco Peereboom <marco@peereboom.us>
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17:
! 18: #include "bio.h"
! 19:
! 20: #include <sys/param.h>
! 21: #include <sys/systm.h>
! 22: #include <sys/buf.h>
! 23: #include <sys/ioctl.h>
! 24: #include <sys/device.h>
! 25: #include <sys/kernel.h>
! 26: #include <sys/malloc.h>
! 27: #include <sys/proc.h>
! 28: #include <sys/rwlock.h>
! 29:
! 30: #include <machine/bus.h>
! 31:
! 32: #include <scsi/scsi_all.h>
! 33: #include <scsi/scsi_disk.h>
! 34: #include <scsi/scsiconf.h>
! 35:
! 36: #include <dev/ic/mfireg.h>
! 37: #include <dev/ic/mfivar.h>
! 38:
! 39: #if NBIO > 0
! 40: #include <dev/biovar.h>
! 41: #include <sys/sensors.h>
! 42: #endif /* NBIO > 0 */
! 43:
! 44: #ifdef MFI_DEBUG
! 45: uint32_t mfi_debug = 0
! 46: /* | MFI_D_CMD */
! 47: /* | MFI_D_INTR */
! 48: /* | MFI_D_MISC */
! 49: /* | MFI_D_DMA */
! 50: | MFI_D_IOCTL
! 51: /* | MFI_D_RW */
! 52: /* | MFI_D_MEM */
! 53: /* | MFI_D_CCB */
! 54: ;
! 55: #endif
! 56:
! 57: struct cfdriver mfi_cd = {
! 58: NULL, "mfi", DV_DULL
! 59: };
! 60:
! 61: int mfi_scsi_cmd(struct scsi_xfer *);
! 62: int mfi_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int, struct proc *);
! 63: void mfiminphys(struct buf *bp);
! 64:
! 65: struct scsi_adapter mfi_switch = {
! 66: mfi_scsi_cmd, mfiminphys, 0, 0, mfi_scsi_ioctl
! 67: };
! 68:
! 69: struct scsi_device mfi_dev = {
! 70: NULL, NULL, NULL, NULL
! 71: };
! 72:
! 73: struct mfi_ccb *mfi_get_ccb(struct mfi_softc *);
! 74: void mfi_put_ccb(struct mfi_ccb *);
! 75: int mfi_init_ccb(struct mfi_softc *);
! 76:
! 77: struct mfi_mem *mfi_allocmem(struct mfi_softc *, size_t);
! 78: void mfi_freemem(struct mfi_softc *, struct mfi_mem *);
! 79:
! 80: int mfi_transition_firmware(struct mfi_softc *);
! 81: int mfi_initialize_firmware(struct mfi_softc *);
! 82: int mfi_get_info(struct mfi_softc *);
! 83: uint32_t mfi_read(struct mfi_softc *, bus_size_t);
! 84: void mfi_write(struct mfi_softc *, bus_size_t, uint32_t);
! 85: int mfi_poll(struct mfi_ccb *);
! 86: int mfi_despatch_cmd(struct mfi_ccb *);
! 87: int mfi_create_sgl(struct mfi_ccb *, int);
! 88:
! 89: /* commands */
! 90: int mfi_scsi_ld(struct mfi_ccb *, struct scsi_xfer *);
! 91: int mfi_scsi_io(struct mfi_ccb *, struct scsi_xfer *, uint32_t,
! 92: uint32_t);
! 93: void mfi_scsi_xs_done(struct mfi_ccb *);
! 94: int mfi_mgmt(struct mfi_softc *, uint32_t, uint32_t, uint32_t,
! 95: void *, uint8_t *);
! 96: void mfi_mgmt_done(struct mfi_ccb *);
! 97:
! 98: #if NBIO > 0
! 99: int mfi_ioctl(struct device *, u_long, caddr_t);
! 100: int mfi_ioctl_inq(struct mfi_softc *, struct bioc_inq *);
! 101: int mfi_ioctl_vol(struct mfi_softc *, struct bioc_vol *);
! 102: int mfi_ioctl_disk(struct mfi_softc *, struct bioc_disk *);
! 103: int mfi_ioctl_alarm(struct mfi_softc *, struct bioc_alarm *);
! 104: int mfi_ioctl_blink(struct mfi_softc *sc, struct bioc_blink *);
! 105: int mfi_ioctl_setstate(struct mfi_softc *, struct bioc_setstate *);
! 106: int mfi_bio_hs(struct mfi_softc *, int, int, void *);
! 107: #ifndef SMALL_KERNEL
! 108: int mfi_create_sensors(struct mfi_softc *);
! 109: void mfi_refresh_sensors(void *);
! 110: #endif /* SMALL_KERNEL */
! 111: #endif /* NBIO > 0 */
! 112:
! 113: struct mfi_ccb *
! 114: mfi_get_ccb(struct mfi_softc *sc)
! 115: {
! 116: struct mfi_ccb *ccb;
! 117: int s;
! 118:
! 119: s = splbio();
! 120: ccb = TAILQ_FIRST(&sc->sc_ccb_freeq);
! 121: if (ccb) {
! 122: TAILQ_REMOVE(&sc->sc_ccb_freeq, ccb, ccb_link);
! 123: ccb->ccb_state = MFI_CCB_READY;
! 124: }
! 125: splx(s);
! 126:
! 127: DNPRINTF(MFI_D_CCB, "%s: mfi_get_ccb: %p\n", DEVNAME(sc), ccb);
! 128:
! 129: return (ccb);
! 130: }
! 131:
! 132: void
! 133: mfi_put_ccb(struct mfi_ccb *ccb)
! 134: {
! 135: struct mfi_softc *sc = ccb->ccb_sc;
! 136: int s;
! 137:
! 138: DNPRINTF(MFI_D_CCB, "%s: mfi_put_ccb: %p\n", DEVNAME(sc), ccb);
! 139:
! 140: s = splbio();
! 141: ccb->ccb_state = MFI_CCB_FREE;
! 142: ccb->ccb_xs = NULL;
! 143: ccb->ccb_flags = 0;
! 144: ccb->ccb_done = NULL;
! 145: ccb->ccb_direction = 0;
! 146: ccb->ccb_frame_size = 0;
! 147: ccb->ccb_extra_frames = 0;
! 148: ccb->ccb_sgl = NULL;
! 149: ccb->ccb_data = NULL;
! 150: ccb->ccb_len = 0;
! 151: TAILQ_INSERT_TAIL(&sc->sc_ccb_freeq, ccb, ccb_link);
! 152: splx(s);
! 153: }
! 154:
! 155: int
! 156: mfi_init_ccb(struct mfi_softc *sc)
! 157: {
! 158: struct mfi_ccb *ccb;
! 159: uint32_t i;
! 160: int error;
! 161:
! 162: DNPRINTF(MFI_D_CCB, "%s: mfi_init_ccb\n", DEVNAME(sc));
! 163:
! 164: sc->sc_ccb = malloc(sizeof(struct mfi_ccb) * sc->sc_max_cmds,
! 165: M_DEVBUF, M_WAITOK);
! 166: memset(sc->sc_ccb, 0, sizeof(struct mfi_ccb) * sc->sc_max_cmds);
! 167:
! 168: for (i = 0; i < sc->sc_max_cmds; i++) {
! 169: ccb = &sc->sc_ccb[i];
! 170:
! 171: ccb->ccb_sc = sc;
! 172:
! 173: /* select i'th frame */
! 174: ccb->ccb_frame = (union mfi_frame *)
! 175: (MFIMEM_KVA(sc->sc_frames) + sc->sc_frames_size * i);
! 176: ccb->ccb_pframe =
! 177: MFIMEM_DVA(sc->sc_frames) + sc->sc_frames_size * i;
! 178: ccb->ccb_frame->mfr_header.mfh_context = i;
! 179:
! 180: /* select i'th sense */
! 181: ccb->ccb_sense = (struct mfi_sense *)
! 182: (MFIMEM_KVA(sc->sc_sense) + MFI_SENSE_SIZE * i);
! 183: ccb->ccb_psense =
! 184: (MFIMEM_DVA(sc->sc_sense) + MFI_SENSE_SIZE * i);
! 185:
! 186: /* create a dma map for transfer */
! 187: error = bus_dmamap_create(sc->sc_dmat,
! 188: MAXPHYS, sc->sc_max_sgl, MAXPHYS, 0,
! 189: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap);
! 190: if (error) {
! 191: printf("%s: cannot create ccb dmamap (%d)\n",
! 192: DEVNAME(sc), error);
! 193: goto destroy;
! 194: }
! 195:
! 196: DNPRINTF(MFI_D_CCB,
! 197: "ccb(%d): %p frame: %#x (%#x) sense: %#x (%#x) map: %#x\n",
! 198: ccb->ccb_frame->mfr_header.mfh_context, ccb,
! 199: ccb->ccb_frame, ccb->ccb_pframe,
! 200: ccb->ccb_sense, ccb->ccb_psense,
! 201: ccb->ccb_dmamap);
! 202:
! 203: /* add ccb to queue */
! 204: mfi_put_ccb(ccb);
! 205: }
! 206:
! 207: return (0);
! 208: destroy:
! 209: /* free dma maps and ccb memory */
! 210: while (i) {
! 211: ccb = &sc->sc_ccb[i];
! 212: bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
! 213: i--;
! 214: }
! 215:
! 216: free(sc->sc_ccb, M_DEVBUF);
! 217:
! 218: return (1);
! 219: }
! 220:
! 221: uint32_t
! 222: mfi_read(struct mfi_softc *sc, bus_size_t r)
! 223: {
! 224: uint32_t rv;
! 225:
! 226: bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
! 227: BUS_SPACE_BARRIER_READ);
! 228: rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r);
! 229:
! 230: DNPRINTF(MFI_D_RW, "%s: mr 0x%x 0x08%x ", DEVNAME(sc), r, rv);
! 231: return (rv);
! 232: }
! 233:
! 234: void
! 235: mfi_write(struct mfi_softc *sc, bus_size_t r, uint32_t v)
! 236: {
! 237: DNPRINTF(MFI_D_RW, "%s: mw 0x%x 0x%08x", DEVNAME(sc), r, v);
! 238:
! 239: bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
! 240: bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
! 241: BUS_SPACE_BARRIER_WRITE);
! 242: }
! 243:
! 244: struct mfi_mem *
! 245: mfi_allocmem(struct mfi_softc *sc, size_t size)
! 246: {
! 247: struct mfi_mem *mm;
! 248: int nsegs;
! 249:
! 250: DNPRINTF(MFI_D_MEM, "%s: mfi_allocmem: %d\n", DEVNAME(sc),
! 251: size);
! 252:
! 253: mm = malloc(sizeof(struct mfi_mem), M_DEVBUF, M_NOWAIT);
! 254: if (mm == NULL)
! 255: return (NULL);
! 256:
! 257: memset(mm, 0, sizeof(struct mfi_mem));
! 258: mm->am_size = size;
! 259:
! 260: if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
! 261: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mm->am_map) != 0)
! 262: goto amfree;
! 263:
! 264: if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &mm->am_seg, 1,
! 265: &nsegs, BUS_DMA_NOWAIT) != 0)
! 266: goto destroy;
! 267:
! 268: if (bus_dmamem_map(sc->sc_dmat, &mm->am_seg, nsegs, size, &mm->am_kva,
! 269: BUS_DMA_NOWAIT) != 0)
! 270: goto free;
! 271:
! 272: if (bus_dmamap_load(sc->sc_dmat, mm->am_map, mm->am_kva, size, NULL,
! 273: BUS_DMA_NOWAIT) != 0)
! 274: goto unmap;
! 275:
! 276: DNPRINTF(MFI_D_MEM, " kva: %p dva: %p map: %p\n",
! 277: mm->am_kva, mm->am_map->dm_segs[0].ds_addr, mm->am_map);
! 278:
! 279: memset(mm->am_kva, 0, size);
! 280: return (mm);
! 281:
! 282: unmap:
! 283: bus_dmamem_unmap(sc->sc_dmat, mm->am_kva, size);
! 284: free:
! 285: bus_dmamem_free(sc->sc_dmat, &mm->am_seg, 1);
! 286: destroy:
! 287: bus_dmamap_destroy(sc->sc_dmat, mm->am_map);
! 288: amfree:
! 289: free(mm, M_DEVBUF);
! 290:
! 291: return (NULL);
! 292: }
! 293:
! 294: void
! 295: mfi_freemem(struct mfi_softc *sc, struct mfi_mem *mm)
! 296: {
! 297: DNPRINTF(MFI_D_MEM, "%s: mfi_freemem: %p\n", DEVNAME(sc), mm);
! 298:
! 299: bus_dmamap_unload(sc->sc_dmat, mm->am_map);
! 300: bus_dmamem_unmap(sc->sc_dmat, mm->am_kva, mm->am_size);
! 301: bus_dmamem_free(sc->sc_dmat, &mm->am_seg, 1);
! 302: bus_dmamap_destroy(sc->sc_dmat, mm->am_map);
! 303: free(mm, M_DEVBUF);
! 304: }
! 305:
! 306: int
! 307: mfi_transition_firmware(struct mfi_softc *sc)
! 308: {
! 309: int32_t fw_state, cur_state;
! 310: int max_wait, i;
! 311:
! 312: fw_state = mfi_read(sc, MFI_OMSG0) & MFI_STATE_MASK;
! 313:
! 314: DNPRINTF(MFI_D_CMD, "%s: mfi_transition_firmware: %#x\n", DEVNAME(sc),
! 315: fw_state);
! 316:
! 317: while (fw_state != MFI_STATE_READY) {
! 318: DNPRINTF(MFI_D_MISC,
! 319: "%s: waiting for firmware to become ready\n",
! 320: DEVNAME(sc));
! 321: cur_state = fw_state;
! 322: switch (fw_state) {
! 323: case MFI_STATE_FAULT:
! 324: printf("%s: firmware fault\n", DEVNAME(sc));
! 325: return (1);
! 326: case MFI_STATE_WAIT_HANDSHAKE:
! 327: mfi_write(sc, MFI_IDB, MFI_INIT_CLEAR_HANDSHAKE);
! 328: max_wait = 2;
! 329: break;
! 330: case MFI_STATE_OPERATIONAL:
! 331: mfi_write(sc, MFI_IDB, MFI_INIT_READY);
! 332: max_wait = 10;
! 333: break;
! 334: case MFI_STATE_UNDEFINED:
! 335: case MFI_STATE_BB_INIT:
! 336: max_wait = 2;
! 337: break;
! 338: case MFI_STATE_FW_INIT:
! 339: case MFI_STATE_DEVICE_SCAN:
! 340: case MFI_STATE_FLUSH_CACHE:
! 341: max_wait = 20;
! 342: break;
! 343: default:
! 344: printf("%s: unknown firmware state %d\n",
! 345: DEVNAME(sc), fw_state);
! 346: return (1);
! 347: }
! 348: for (i = 0; i < (max_wait * 10); i++) {
! 349: fw_state = mfi_read(sc, MFI_OMSG0) & MFI_STATE_MASK;
! 350: if (fw_state == cur_state)
! 351: DELAY(100000);
! 352: else
! 353: break;
! 354: }
! 355: if (fw_state == cur_state) {
! 356: printf("%s: firmware stuck in state %#x\n",
! 357: DEVNAME(sc), fw_state);
! 358: return (1);
! 359: }
! 360: }
! 361:
! 362: return (0);
! 363: }
! 364:
! 365: int
! 366: mfi_initialize_firmware(struct mfi_softc *sc)
! 367: {
! 368: struct mfi_ccb *ccb;
! 369: struct mfi_init_frame *init;
! 370: struct mfi_init_qinfo *qinfo;
! 371:
! 372: DNPRINTF(MFI_D_MISC, "%s: mfi_initialize_firmware\n", DEVNAME(sc));
! 373:
! 374: if ((ccb = mfi_get_ccb(sc)) == NULL)
! 375: return (1);
! 376:
! 377: init = &ccb->ccb_frame->mfr_init;
! 378: qinfo = (struct mfi_init_qinfo *)((uint8_t *)init + MFI_FRAME_SIZE);
! 379:
! 380: memset(qinfo, 0, sizeof *qinfo);
! 381: qinfo->miq_rq_entries = sc->sc_max_cmds + 1;
! 382: qinfo->miq_rq_addr_lo = htole32(MFIMEM_DVA(sc->sc_pcq) +
! 383: offsetof(struct mfi_prod_cons, mpc_reply_q));
! 384: qinfo->miq_pi_addr_lo = htole32(MFIMEM_DVA(sc->sc_pcq) +
! 385: offsetof(struct mfi_prod_cons, mpc_producer));
! 386: qinfo->miq_ci_addr_lo = htole32(MFIMEM_DVA(sc->sc_pcq) +
! 387: offsetof(struct mfi_prod_cons, mpc_consumer));
! 388:
! 389: init->mif_header.mfh_cmd = MFI_CMD_INIT;
! 390: init->mif_header.mfh_data_len = sizeof *qinfo;
! 391: init->mif_qinfo_new_addr_lo = htole32(ccb->ccb_pframe + MFI_FRAME_SIZE);
! 392:
! 393: DNPRINTF(MFI_D_MISC, "%s: entries: %#x rq: %#x pi: %#x ci: %#x\n",
! 394: DEVNAME(sc),
! 395: qinfo->miq_rq_entries, qinfo->miq_rq_addr_lo,
! 396: qinfo->miq_pi_addr_lo, qinfo->miq_ci_addr_lo);
! 397:
! 398: if (mfi_poll(ccb)) {
! 399: printf("%s: mfi_initialize_firmware failed\n", DEVNAME(sc));
! 400: return (1);
! 401: }
! 402:
! 403: mfi_put_ccb(ccb);
! 404:
! 405: return (0);
! 406: }
! 407:
! 408: int
! 409: mfi_get_info(struct mfi_softc *sc)
! 410: {
! 411: #ifdef MFI_DEBUG
! 412: int i;
! 413: #endif
! 414: DNPRINTF(MFI_D_MISC, "%s: mfi_get_info\n", DEVNAME(sc));
! 415:
! 416: if (mfi_mgmt(sc, MR_DCMD_CTRL_GET_INFO, MFI_DATA_IN,
! 417: sizeof(sc->sc_info), &sc->sc_info, NULL))
! 418: return (1);
! 419:
! 420: #ifdef MFI_DEBUG
! 421:
! 422: for (i = 0; i < sc->sc_info.mci_image_component_count; i++) {
! 423: printf("%s: active FW %s Version %s date %s time %s\n",
! 424: DEVNAME(sc),
! 425: sc->sc_info.mci_image_component[i].mic_name,
! 426: sc->sc_info.mci_image_component[i].mic_version,
! 427: sc->sc_info.mci_image_component[i].mic_build_date,
! 428: sc->sc_info.mci_image_component[i].mic_build_time);
! 429: }
! 430:
! 431: for (i = 0; i < sc->sc_info.mci_pending_image_component_count; i++) {
! 432: printf("%s: pending FW %s Version %s date %s time %s\n",
! 433: DEVNAME(sc),
! 434: sc->sc_info.mci_pending_image_component[i].mic_name,
! 435: sc->sc_info.mci_pending_image_component[i].mic_version,
! 436: sc->sc_info.mci_pending_image_component[i].mic_build_date,
! 437: sc->sc_info.mci_pending_image_component[i].mic_build_time);
! 438: }
! 439:
! 440: printf("%s: max_arms %d max_spans %d max_arrs %d max_lds %d name %s\n",
! 441: DEVNAME(sc),
! 442: sc->sc_info.mci_max_arms,
! 443: sc->sc_info.mci_max_spans,
! 444: sc->sc_info.mci_max_arrays,
! 445: sc->sc_info.mci_max_lds,
! 446: sc->sc_info.mci_product_name);
! 447:
! 448: printf("%s: serial %s present %#x fw time %d max_cmds %d max_sg %d\n",
! 449: DEVNAME(sc),
! 450: sc->sc_info.mci_serial_number,
! 451: sc->sc_info.mci_hw_present,
! 452: sc->sc_info.mci_current_fw_time,
! 453: sc->sc_info.mci_max_cmds,
! 454: sc->sc_info.mci_max_sg_elements);
! 455:
! 456: printf("%s: max_rq %d lds_pres %d lds_deg %d lds_off %d pd_pres %d\n",
! 457: DEVNAME(sc),
! 458: sc->sc_info.mci_max_request_size,
! 459: sc->sc_info.mci_lds_present,
! 460: sc->sc_info.mci_lds_degraded,
! 461: sc->sc_info.mci_lds_offline,
! 462: sc->sc_info.mci_pd_present);
! 463:
! 464: printf("%s: pd_dsk_prs %d pd_dsk_pred_fail %d pd_dsk_fail %d\n",
! 465: DEVNAME(sc),
! 466: sc->sc_info.mci_pd_disks_present,
! 467: sc->sc_info.mci_pd_disks_pred_failure,
! 468: sc->sc_info.mci_pd_disks_failed);
! 469:
! 470: printf("%s: nvram %d mem %d flash %d\n",
! 471: DEVNAME(sc),
! 472: sc->sc_info.mci_nvram_size,
! 473: sc->sc_info.mci_memory_size,
! 474: sc->sc_info.mci_flash_size);
! 475:
! 476: printf("%s: ram_cor %d ram_uncor %d clus_all %d clus_act %d\n",
! 477: DEVNAME(sc),
! 478: sc->sc_info.mci_ram_correctable_errors,
! 479: sc->sc_info.mci_ram_uncorrectable_errors,
! 480: sc->sc_info.mci_cluster_allowed,
! 481: sc->sc_info.mci_cluster_active);
! 482:
! 483: printf("%s: max_strps_io %d raid_lvl %#x adapt_ops %#x ld_ops %#x\n",
! 484: DEVNAME(sc),
! 485: sc->sc_info.mci_max_strips_per_io,
! 486: sc->sc_info.mci_raid_levels,
! 487: sc->sc_info.mci_adapter_ops,
! 488: sc->sc_info.mci_ld_ops);
! 489:
! 490: printf("%s: strp_sz_min %d strp_sz_max %d pd_ops %#x pd_mix %#x\n",
! 491: DEVNAME(sc),
! 492: sc->sc_info.mci_stripe_sz_ops.min,
! 493: sc->sc_info.mci_stripe_sz_ops.max,
! 494: sc->sc_info.mci_pd_ops,
! 495: sc->sc_info.mci_pd_mix_support);
! 496:
! 497: printf("%s: ecc_bucket %d pckg_prop %s\n",
! 498: DEVNAME(sc),
! 499: sc->sc_info.mci_ecc_bucket_count,
! 500: sc->sc_info.mci_package_version);
! 501:
! 502: printf("%s: sq_nm %d prd_fail_poll %d intr_thrtl %d intr_thrtl_to %d\n",
! 503: DEVNAME(sc),
! 504: sc->sc_info.mci_properties.mcp_seq_num,
! 505: sc->sc_info.mci_properties.mcp_pred_fail_poll_interval,
! 506: sc->sc_info.mci_properties.mcp_intr_throttle_cnt,
! 507: sc->sc_info.mci_properties.mcp_intr_throttle_timeout);
! 508:
! 509: printf("%s: rbld_rate %d patr_rd_rate %d bgi_rate %d cc_rate %d\n",
! 510: DEVNAME(sc),
! 511: sc->sc_info.mci_properties.mcp_rebuild_rate,
! 512: sc->sc_info.mci_properties.mcp_patrol_read_rate,
! 513: sc->sc_info.mci_properties.mcp_bgi_rate,
! 514: sc->sc_info.mci_properties.mcp_cc_rate);
! 515:
! 516: printf("%s: rc_rate %d ch_flsh %d spin_cnt %d spin_dly %d clus_en %d\n",
! 517: DEVNAME(sc),
! 518: sc->sc_info.mci_properties.mcp_recon_rate,
! 519: sc->sc_info.mci_properties.mcp_cache_flush_interval,
! 520: sc->sc_info.mci_properties.mcp_spinup_drv_cnt,
! 521: sc->sc_info.mci_properties.mcp_spinup_delay,
! 522: sc->sc_info.mci_properties.mcp_cluster_enable);
! 523:
! 524: printf("%s: coerc %d alarm %d dis_auto_rbld %d dis_bat_wrn %d ecc %d\n",
! 525: DEVNAME(sc),
! 526: sc->sc_info.mci_properties.mcp_coercion_mode,
! 527: sc->sc_info.mci_properties.mcp_alarm_enable,
! 528: sc->sc_info.mci_properties.mcp_disable_auto_rebuild,
! 529: sc->sc_info.mci_properties.mcp_disable_battery_warn,
! 530: sc->sc_info.mci_properties.mcp_ecc_bucket_size);
! 531:
! 532: printf("%s: ecc_leak %d rest_hs %d exp_encl_dev %d\n",
! 533: DEVNAME(sc),
! 534: sc->sc_info.mci_properties.mcp_ecc_bucket_leak_rate,
! 535: sc->sc_info.mci_properties.mcp_restore_hotspare_on_insertion,
! 536: sc->sc_info.mci_properties.mcp_expose_encl_devices);
! 537:
! 538: printf("%s: vendor %#x device %#x subvendor %#x subdevice %#x\n",
! 539: DEVNAME(sc),
! 540: sc->sc_info.mci_pci.mip_vendor,
! 541: sc->sc_info.mci_pci.mip_device,
! 542: sc->sc_info.mci_pci.mip_subvendor,
! 543: sc->sc_info.mci_pci.mip_subdevice);
! 544:
! 545: printf("%s: type %#x port_count %d port_addr ",
! 546: DEVNAME(sc),
! 547: sc->sc_info.mci_host.mih_type,
! 548: sc->sc_info.mci_host.mih_port_count);
! 549:
! 550: for (i = 0; i < 8; i++)
! 551: printf("%.0llx ", sc->sc_info.mci_host.mih_port_addr[i]);
! 552: printf("\n");
! 553:
! 554: printf("%s: type %.x port_count %d port_addr ",
! 555: DEVNAME(sc),
! 556: sc->sc_info.mci_device.mid_type,
! 557: sc->sc_info.mci_device.mid_port_count);
! 558:
! 559: for (i = 0; i < 8; i++)
! 560: printf("%.0llx ", sc->sc_info.mci_device.mid_port_addr[i]);
! 561: printf("\n");
! 562: #endif /* MFI_DEBUG */
! 563:
! 564: return (0);
! 565: }
! 566:
! 567: void
! 568: mfiminphys(struct buf *bp)
! 569: {
! 570: DNPRINTF(MFI_D_MISC, "mfiminphys: %d\n", bp->b_bcount);
! 571:
! 572: /* XXX currently using MFI_MAXFER = MAXPHYS */
! 573: if (bp->b_bcount > MFI_MAXFER)
! 574: bp->b_bcount = MFI_MAXFER;
! 575: minphys(bp);
! 576: }
! 577:
! 578: int
! 579: mfi_attach(struct mfi_softc *sc)
! 580: {
! 581: struct scsibus_attach_args saa;
! 582: uint32_t status, frames;
! 583: int i;
! 584:
! 585: DNPRINTF(MFI_D_MISC, "%s: mfi_attach\n", DEVNAME(sc));
! 586:
! 587: if (mfi_transition_firmware(sc))
! 588: return (1);
! 589:
! 590: TAILQ_INIT(&sc->sc_ccb_freeq);
! 591:
! 592: rw_init(&sc->sc_lock, "mfi_lock");
! 593:
! 594: status = mfi_read(sc, MFI_OMSG0);
! 595: sc->sc_max_cmds = status & MFI_STATE_MAXCMD_MASK;
! 596: sc->sc_max_sgl = (status & MFI_STATE_MAXSGL_MASK) >> 16;
! 597: DNPRINTF(MFI_D_MISC, "%s: max commands: %u, max sgl: %u\n",
! 598: DEVNAME(sc), sc->sc_max_cmds, sc->sc_max_sgl);
! 599:
! 600: /* consumer/producer and reply queue memory */
! 601: sc->sc_pcq = mfi_allocmem(sc, (sizeof(uint32_t) * sc->sc_max_cmds) +
! 602: sizeof(struct mfi_prod_cons));
! 603: if (sc->sc_pcq == NULL) {
! 604: printf("%s: unable to allocate reply queue memory\n",
! 605: DEVNAME(sc));
! 606: goto nopcq;
! 607: }
! 608:
! 609: /* frame memory */
! 610: /* we are not doing 64 bit IO so only calculate # of 32 bit frames */
! 611: frames = (sizeof(struct mfi_sg32) * sc->sc_max_sgl +
! 612: MFI_FRAME_SIZE - 1) / MFI_FRAME_SIZE + 1;
! 613: sc->sc_frames_size = frames * MFI_FRAME_SIZE;
! 614: sc->sc_frames = mfi_allocmem(sc, sc->sc_frames_size * sc->sc_max_cmds);
! 615: if (sc->sc_frames == NULL) {
! 616: printf("%s: unable to allocate frame memory\n", DEVNAME(sc));
! 617: goto noframe;
! 618: }
! 619: /* XXX hack, fix this */
! 620: if (MFIMEM_DVA(sc->sc_frames) & 0x3f) {
! 621: printf("%s: improper frame alignment (%#x) FIXME\n",
! 622: DEVNAME(sc), MFIMEM_DVA(sc->sc_frames));
! 623: goto noframe;
! 624: }
! 625:
! 626: /* sense memory */
! 627: sc->sc_sense = mfi_allocmem(sc, sc->sc_max_cmds * MFI_SENSE_SIZE);
! 628: if (sc->sc_sense == NULL) {
! 629: printf("%s: unable to allocate sense memory\n", DEVNAME(sc));
! 630: goto nosense;
! 631: }
! 632:
! 633: /* now that we have all memory bits go initialize ccbs */
! 634: if (mfi_init_ccb(sc)) {
! 635: printf("%s: could not init ccb list\n", DEVNAME(sc));
! 636: goto noinit;
! 637: }
! 638:
! 639: /* kickstart firmware with all addresses and pointers */
! 640: if (mfi_initialize_firmware(sc)) {
! 641: printf("%s: could not initialize firmware\n", DEVNAME(sc));
! 642: goto noinit;
! 643: }
! 644:
! 645: if (mfi_get_info(sc)) {
! 646: printf("%s: could not retrieve controller information\n",
! 647: DEVNAME(sc));
! 648: goto noinit;
! 649: }
! 650:
! 651: printf("%s: logical drives %d, version %s, %dMB RAM\n",
! 652: DEVNAME(sc),
! 653: sc->sc_info.mci_lds_present,
! 654: sc->sc_info.mci_package_version,
! 655: sc->sc_info.mci_memory_size);
! 656:
! 657: sc->sc_ld_cnt = sc->sc_info.mci_lds_present;
! 658: sc->sc_max_ld = sc->sc_ld_cnt;
! 659: for (i = 0; i < sc->sc_ld_cnt; i++)
! 660: sc->sc_ld[i].ld_present = 1;
! 661:
! 662: if (sc->sc_ld_cnt)
! 663: sc->sc_link.openings = sc->sc_max_cmds / sc->sc_ld_cnt;
! 664: else
! 665: sc->sc_link.openings = sc->sc_max_cmds;
! 666:
! 667: sc->sc_link.device = &mfi_dev;
! 668: sc->sc_link.adapter_softc = sc;
! 669: sc->sc_link.adapter = &mfi_switch;
! 670: sc->sc_link.adapter_target = MFI_MAX_LD;
! 671: sc->sc_link.adapter_buswidth = sc->sc_max_ld;
! 672:
! 673: bzero(&saa, sizeof(saa));
! 674: saa.saa_sc_link = &sc->sc_link;
! 675:
! 676: config_found(&sc->sc_dev, &saa, scsiprint);
! 677:
! 678: /* enable interrupts */
! 679: mfi_write(sc, MFI_OMSK, MFI_ENABLE_INTR);
! 680:
! 681: #if NBIO > 0
! 682: if (bio_register(&sc->sc_dev, mfi_ioctl) != 0)
! 683: panic("%s: controller registration failed", DEVNAME(sc));
! 684: else
! 685: sc->sc_ioctl = mfi_ioctl;
! 686:
! 687: #ifndef SMALL_KERNEL
! 688: if (mfi_create_sensors(sc) != 0)
! 689: printf("%s: unable to create sensors\n", DEVNAME(sc));
! 690: #endif
! 691: #endif /* NBIO > 0 */
! 692:
! 693: return (0);
! 694: noinit:
! 695: mfi_freemem(sc, sc->sc_sense);
! 696: nosense:
! 697: mfi_freemem(sc, sc->sc_frames);
! 698: noframe:
! 699: mfi_freemem(sc, sc->sc_pcq);
! 700: nopcq:
! 701: return (1);
! 702: }
! 703:
! 704: int
! 705: mfi_despatch_cmd(struct mfi_ccb *ccb)
! 706: {
! 707: DNPRINTF(MFI_D_CMD, "%s: mfi_despatch_cmd\n",
! 708: DEVNAME(ccb->ccb_sc));
! 709:
! 710: mfi_write(ccb->ccb_sc, MFI_IQP, (ccb->ccb_pframe >> 3) |
! 711: ccb->ccb_extra_frames);
! 712:
! 713: return(0);
! 714: }
! 715:
! 716: int
! 717: mfi_poll(struct mfi_ccb *ccb)
! 718: {
! 719: struct mfi_frame_header *hdr;
! 720: int to = 0;
! 721:
! 722: DNPRINTF(MFI_D_CMD, "%s: mfi_poll\n", DEVNAME(ccb->ccb_sc));
! 723:
! 724: hdr = &ccb->ccb_frame->mfr_header;
! 725: hdr->mfh_cmd_status = 0xff;
! 726: hdr->mfh_flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
! 727:
! 728: mfi_despatch_cmd(ccb);
! 729:
! 730: while (hdr->mfh_cmd_status == 0xff) {
! 731: delay(1000);
! 732: if (to++ > 5000) /* XXX 5 seconds busywait sucks */
! 733: break;
! 734: }
! 735: if (hdr->mfh_cmd_status == 0xff) {
! 736: printf("%s: timeout on ccb %d\n", DEVNAME(ccb->ccb_sc),
! 737: hdr->mfh_context);
! 738: ccb->ccb_flags |= MFI_CCB_F_ERR;
! 739: return (1);
! 740: }
! 741:
! 742: return (0);
! 743: }
! 744:
! 745: int
! 746: mfi_intr(void *arg)
! 747: {
! 748: struct mfi_softc *sc = arg;
! 749: struct mfi_prod_cons *pcq;
! 750: struct mfi_ccb *ccb;
! 751: uint32_t status, producer, consumer, ctx;
! 752: int claimed = 0;
! 753:
! 754: status = mfi_read(sc, MFI_OSTS);
! 755: if ((status & MFI_OSTS_INTR_VALID) == 0)
! 756: return (claimed);
! 757: /* write status back to acknowledge interrupt */
! 758: mfi_write(sc, MFI_OSTS, status);
! 759:
! 760: DNPRINTF(MFI_D_INTR, "%s: mfi_intr %#x %#x\n", DEVNAME(sc), sc, pcq);
! 761:
! 762: pcq = MFIMEM_KVA(sc->sc_pcq);
! 763: producer = pcq->mpc_producer;
! 764: consumer = pcq->mpc_consumer;
! 765:
! 766: while (consumer != producer) {
! 767: DNPRINTF(MFI_D_INTR, "%s: mfi_intr pi %#x ci %#x\n",
! 768: DEVNAME(sc), producer, consumer);
! 769:
! 770: ctx = pcq->mpc_reply_q[consumer];
! 771: pcq->mpc_reply_q[consumer] = MFI_INVALID_CTX;
! 772: if (ctx == MFI_INVALID_CTX)
! 773: printf("%s: invalid context, p: %d c: %d\n",
! 774: DEVNAME(sc), producer, consumer);
! 775: else {
! 776: /* XXX remove from queue and call scsi_done */
! 777: ccb = &sc->sc_ccb[ctx];
! 778: DNPRINTF(MFI_D_INTR, "%s: mfi_intr context %#x\n",
! 779: DEVNAME(sc), ctx);
! 780: ccb->ccb_done(ccb);
! 781:
! 782: claimed = 1;
! 783: }
! 784: consumer++;
! 785: if (consumer == (sc->sc_max_cmds + 1))
! 786: consumer = 0;
! 787: }
! 788:
! 789: pcq->mpc_consumer = consumer;
! 790:
! 791: return (claimed);
! 792: }
! 793:
! 794: int
! 795: mfi_scsi_io(struct mfi_ccb *ccb, struct scsi_xfer *xs, uint32_t blockno,
! 796: uint32_t blockcnt)
! 797: {
! 798: struct scsi_link *link = xs->sc_link;
! 799: struct mfi_io_frame *io;
! 800:
! 801: DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_io: %d\n",
! 802: DEVNAME((struct mfi_softc *)link->adapter_softc), link->target);
! 803:
! 804: if (!xs->data)
! 805: return (1);
! 806:
! 807: io = &ccb->ccb_frame->mfr_io;
! 808: if (xs->flags & SCSI_DATA_IN) {
! 809: io->mif_header.mfh_cmd = MFI_CMD_LD_READ;
! 810: ccb->ccb_direction = MFI_DATA_IN;
! 811: } else {
! 812: io->mif_header.mfh_cmd = MFI_CMD_LD_WRITE;
! 813: ccb->ccb_direction = MFI_DATA_OUT;
! 814: }
! 815: io->mif_header.mfh_target_id = link->target;
! 816: io->mif_header.mfh_timeout = 0;
! 817: io->mif_header.mfh_flags = 0;
! 818: io->mif_header.mfh_sense_len = MFI_SENSE_SIZE;
! 819: io->mif_header.mfh_data_len= blockcnt;
! 820: io->mif_lba_hi = 0;
! 821: io->mif_lba_lo = blockno;
! 822: io->mif_sense_addr_lo = htole32(ccb->ccb_psense);
! 823: io->mif_sense_addr_hi = 0;
! 824:
! 825: ccb->ccb_done = mfi_scsi_xs_done;
! 826: ccb->ccb_xs = xs;
! 827: ccb->ccb_frame_size = MFI_IO_FRAME_SIZE;
! 828: ccb->ccb_sgl = &io->mif_sgl;
! 829: ccb->ccb_data = xs->data;
! 830: ccb->ccb_len = xs->datalen;
! 831:
! 832: if (mfi_create_sgl(ccb, (xs->flags & SCSI_NOSLEEP) ?
! 833: BUS_DMA_NOWAIT : BUS_DMA_WAITOK))
! 834: return (1);
! 835:
! 836: return (0);
! 837: }
! 838:
! 839: void
! 840: mfi_scsi_xs_done(struct mfi_ccb *ccb)
! 841: {
! 842: struct scsi_xfer *xs = ccb->ccb_xs;
! 843: struct mfi_softc *sc = ccb->ccb_sc;
! 844: struct mfi_frame_header *hdr = &ccb->ccb_frame->mfr_header;
! 845:
! 846: DNPRINTF(MFI_D_INTR, "%s: mfi_scsi_xs_done %#x %#x\n",
! 847: DEVNAME(sc), ccb, ccb->ccb_frame);
! 848:
! 849: if (xs->data != NULL) {
! 850: DNPRINTF(MFI_D_INTR, "%s: mfi_scsi_xs_done sync\n",
! 851: DEVNAME(sc));
! 852: bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
! 853: ccb->ccb_dmamap->dm_mapsize,
! 854: (xs->flags & SCSI_DATA_IN) ?
! 855: BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
! 856:
! 857: bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
! 858: }
! 859:
! 860: if (hdr->mfh_cmd_status != MFI_STAT_OK) {
! 861: xs->error = XS_DRIVER_STUFFUP;
! 862: DNPRINTF(MFI_D_INTR, "%s: mfi_scsi_xs_done stuffup %#x\n",
! 863: DEVNAME(sc), hdr->mfh_cmd_status);
! 864:
! 865: if (hdr->mfh_scsi_status != 0) {
! 866: DNPRINTF(MFI_D_INTR,
! 867: "%s: mfi_scsi_xs_done sense %#x %x %x\n",
! 868: DEVNAME(sc), hdr->mfh_scsi_status,
! 869: &xs->sense, ccb->ccb_sense);
! 870: memset(&xs->sense, 0, sizeof(xs->sense));
! 871: memcpy(&xs->sense, ccb->ccb_sense,
! 872: sizeof(struct scsi_sense_data));
! 873: xs->error = XS_SENSE;
! 874: }
! 875: }
! 876:
! 877: xs->resid = 0;
! 878: xs->flags |= ITSDONE;
! 879:
! 880: mfi_put_ccb(ccb);
! 881: scsi_done(xs);
! 882: }
! 883:
! 884: int
! 885: mfi_scsi_ld(struct mfi_ccb *ccb, struct scsi_xfer *xs)
! 886: {
! 887: struct scsi_link *link = xs->sc_link;
! 888: struct mfi_pass_frame *pf;
! 889:
! 890: DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_ld: %d\n",
! 891: DEVNAME((struct mfi_softc *)link->adapter_softc), link->target);
! 892:
! 893: pf = &ccb->ccb_frame->mfr_pass;
! 894: pf->mpf_header.mfh_cmd = MFI_CMD_LD_SCSI_IO;
! 895: pf->mpf_header.mfh_target_id = link->target;
! 896: pf->mpf_header.mfh_lun_id = 0;
! 897: pf->mpf_header.mfh_cdb_len = xs->cmdlen;
! 898: pf->mpf_header.mfh_timeout = 0;
! 899: pf->mpf_header.mfh_data_len= xs->datalen; /* XXX */
! 900: pf->mpf_header.mfh_sense_len = MFI_SENSE_SIZE;
! 901:
! 902: pf->mpf_sense_addr_hi = 0;
! 903: pf->mpf_sense_addr_lo = htole32(ccb->ccb_psense);
! 904:
! 905: memset(pf->mpf_cdb, 0, 16);
! 906: memcpy(pf->mpf_cdb, &xs->cmdstore, xs->cmdlen);
! 907:
! 908: ccb->ccb_done = mfi_scsi_xs_done;
! 909: ccb->ccb_xs = xs;
! 910: ccb->ccb_frame_size = MFI_PASS_FRAME_SIZE;
! 911: ccb->ccb_sgl = &pf->mpf_sgl;
! 912:
! 913: if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT))
! 914: ccb->ccb_direction = xs->flags & SCSI_DATA_IN ?
! 915: MFI_DATA_IN : MFI_DATA_OUT;
! 916: else
! 917: ccb->ccb_direction = MFI_DATA_NONE;
! 918:
! 919: if (xs->data) {
! 920: ccb->ccb_data = xs->data;
! 921: ccb->ccb_len = xs->datalen;
! 922:
! 923: if (mfi_create_sgl(ccb, (xs->flags & SCSI_NOSLEEP) ?
! 924: BUS_DMA_NOWAIT : BUS_DMA_WAITOK))
! 925: return (1);
! 926: }
! 927:
! 928: return (0);
! 929: }
! 930:
! 931: int
! 932: mfi_scsi_cmd(struct scsi_xfer *xs)
! 933: {
! 934: struct scsi_link *link = xs->sc_link;
! 935: struct mfi_softc *sc = link->adapter_softc;
! 936: struct device *dev = link->device_softc;
! 937: struct mfi_ccb *ccb;
! 938: struct scsi_rw *rw;
! 939: struct scsi_rw_big *rwb;
! 940: uint32_t blockno, blockcnt;
! 941: uint8_t target = link->target;
! 942: uint8_t mbox[MFI_MBOX_SIZE];
! 943:
! 944: DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_cmd opcode: %#x\n",
! 945: DEVNAME(sc), xs->cmd->opcode);
! 946:
! 947: if (target >= MFI_MAX_LD || !sc->sc_ld[target].ld_present ||
! 948: link->lun != 0) {
! 949: DNPRINTF(MFI_D_CMD, "%s: invalid target %d\n",
! 950: DEVNAME(sc), target);
! 951: goto stuffup;
! 952: }
! 953:
! 954: if ((ccb = mfi_get_ccb(sc)) == NULL) {
! 955: DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_cmd no ccb\n", DEVNAME(sc));
! 956: return (TRY_AGAIN_LATER);
! 957: }
! 958:
! 959: xs->error = XS_NOERROR;
! 960:
! 961: switch (xs->cmd->opcode) {
! 962: /* IO path */
! 963: case READ_BIG:
! 964: case WRITE_BIG:
! 965: rwb = (struct scsi_rw_big *)xs->cmd;
! 966: blockno = _4btol(rwb->addr);
! 967: blockcnt = _2btol(rwb->length);
! 968: if (mfi_scsi_io(ccb, xs, blockno, blockcnt)) {
! 969: mfi_put_ccb(ccb);
! 970: goto stuffup;
! 971: }
! 972: break;
! 973:
! 974: case READ_COMMAND:
! 975: case WRITE_COMMAND:
! 976: rw = (struct scsi_rw *)xs->cmd;
! 977: blockno = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
! 978: blockcnt = rw->length ? rw->length : 0x100;
! 979: if (mfi_scsi_io(ccb, xs, blockno, blockcnt)) {
! 980: mfi_put_ccb(ccb);
! 981: goto stuffup;
! 982: }
! 983: break;
! 984:
! 985: case SYNCHRONIZE_CACHE:
! 986: mfi_put_ccb(ccb); /* we don't need this */
! 987:
! 988: mbox[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
! 989: if (mfi_mgmt(sc, MR_DCMD_CTRL_CACHE_FLUSH, MFI_DATA_NONE,
! 990: 0, NULL, mbox))
! 991: goto stuffup;
! 992:
! 993: return (COMPLETE);
! 994: /* NOTREACHED */
! 995:
! 996: /* hand it of to the firmware and let it deal with it */
! 997: case TEST_UNIT_READY:
! 998: /* save off sd? after autoconf */
! 999: if (!cold) /* XXX bogus */
! 1000: strlcpy(sc->sc_ld[target].ld_dev, dev->dv_xname,
! 1001: sizeof(sc->sc_ld[target].ld_dev));
! 1002: /* FALLTHROUGH */
! 1003:
! 1004: default:
! 1005: if (mfi_scsi_ld(ccb, xs)) {
! 1006: mfi_put_ccb(ccb);
! 1007: goto stuffup;
! 1008: }
! 1009: break;
! 1010: }
! 1011:
! 1012: DNPRINTF(MFI_D_CMD, "%s: start io %d\n", DEVNAME(sc), target);
! 1013:
! 1014: if (xs->flags & SCSI_POLL) {
! 1015: if (mfi_poll(ccb)) {
! 1016: /* XXX check for sense in ccb->ccb_sense? */
! 1017: printf("%s: mfi_scsi_cmd poll failed\n",
! 1018: DEVNAME(sc));
! 1019: mfi_put_ccb(ccb);
! 1020: bzero(&xs->sense, sizeof(xs->sense));
! 1021: xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
! 1022: xs->sense.flags = SKEY_ILLEGAL_REQUEST;
! 1023: xs->sense.add_sense_code = 0x20; /* invalid opcode */
! 1024: xs->error = XS_SENSE;
! 1025: xs->flags |= ITSDONE;
! 1026: scsi_done(xs);
! 1027: return (COMPLETE);
! 1028: }
! 1029: DNPRINTF(MFI_D_DMA, "%s: mfi_scsi_cmd poll complete %d\n",
! 1030: DEVNAME(sc), ccb->ccb_dmamap->dm_nsegs);
! 1031:
! 1032: mfi_put_ccb(ccb);
! 1033: return (COMPLETE);
! 1034: }
! 1035:
! 1036: mfi_despatch_cmd(ccb);
! 1037:
! 1038: DNPRINTF(MFI_D_DMA, "%s: mfi_scsi_cmd queued %d\n", DEVNAME(sc),
! 1039: ccb->ccb_dmamap->dm_nsegs);
! 1040:
! 1041: return (SUCCESSFULLY_QUEUED);
! 1042:
! 1043: stuffup:
! 1044: xs->error = XS_DRIVER_STUFFUP;
! 1045: xs->flags |= ITSDONE;
! 1046: scsi_done(xs);
! 1047: return (COMPLETE);
! 1048: }
! 1049:
! 1050: int
! 1051: mfi_create_sgl(struct mfi_ccb *ccb, int flags)
! 1052: {
! 1053: struct mfi_softc *sc = ccb->ccb_sc;
! 1054: struct mfi_frame_header *hdr;
! 1055: bus_dma_segment_t *sgd;
! 1056: union mfi_sgl *sgl;
! 1057: int error, i;
! 1058:
! 1059: DNPRINTF(MFI_D_DMA, "%s: mfi_create_sgl %#x\n", DEVNAME(sc),
! 1060: ccb->ccb_data);
! 1061:
! 1062: if (!ccb->ccb_data)
! 1063: return (1);
! 1064:
! 1065: error = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap,
! 1066: ccb->ccb_data, ccb->ccb_len, NULL, flags);
! 1067: if (error) {
! 1068: if (error == EFBIG)
! 1069: printf("more than %d dma segs\n",
! 1070: sc->sc_max_sgl);
! 1071: else
! 1072: printf("error %d loading dma map\n", error);
! 1073: return (1);
! 1074: }
! 1075:
! 1076: hdr = &ccb->ccb_frame->mfr_header;
! 1077: sgl = ccb->ccb_sgl;
! 1078: sgd = ccb->ccb_dmamap->dm_segs;
! 1079: for (i = 0; i < ccb->ccb_dmamap->dm_nsegs; i++) {
! 1080: sgl->sg32[i].addr = htole32(sgd[i].ds_addr);
! 1081: sgl->sg32[i].len = htole32(sgd[i].ds_len);
! 1082: DNPRINTF(MFI_D_DMA, "%s: addr: %#x len: %#x\n",
! 1083: DEVNAME(sc), sgl->sg32[i].addr, sgl->sg32[i].len);
! 1084: }
! 1085:
! 1086: if (ccb->ccb_direction == MFI_DATA_IN) {
! 1087: hdr->mfh_flags |= MFI_FRAME_DIR_READ;
! 1088: bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
! 1089: ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
! 1090: } else {
! 1091: hdr->mfh_flags |= MFI_FRAME_DIR_WRITE;
! 1092: bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
! 1093: ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 1094: }
! 1095:
! 1096: hdr->mfh_sg_count = ccb->ccb_dmamap->dm_nsegs;
! 1097: /* for 64 bit io make the sizeof a variable to hold whatever sg size */
! 1098: ccb->ccb_frame_size += sizeof(struct mfi_sg32) *
! 1099: ccb->ccb_dmamap->dm_nsegs;
! 1100: ccb->ccb_extra_frames = (ccb->ccb_frame_size - 1) / MFI_FRAME_SIZE;
! 1101:
! 1102: DNPRINTF(MFI_D_DMA, "%s: sg_count: %d frame_size: %d frames_size: %d"
! 1103: " dm_nsegs: %d extra_frames: %d\n",
! 1104: DEVNAME(sc),
! 1105: hdr->mfh_sg_count,
! 1106: ccb->ccb_frame_size,
! 1107: sc->sc_frames_size,
! 1108: ccb->ccb_dmamap->dm_nsegs,
! 1109: ccb->ccb_extra_frames);
! 1110:
! 1111: return (0);
! 1112: }
! 1113:
! 1114: int
! 1115: mfi_mgmt(struct mfi_softc *sc, uint32_t opc, uint32_t dir, uint32_t len,
! 1116: void *buf, uint8_t *mbox)
! 1117: {
! 1118: struct mfi_ccb *ccb;
! 1119: struct mfi_dcmd_frame *dcmd;
! 1120: int rv = 1;
! 1121:
! 1122: DNPRINTF(MFI_D_MISC, "%s: mfi_mgmt %#x\n", DEVNAME(sc), opc);
! 1123:
! 1124: if ((ccb = mfi_get_ccb(sc)) == NULL)
! 1125: return (rv);
! 1126:
! 1127: dcmd = &ccb->ccb_frame->mfr_dcmd;
! 1128: memset(dcmd->mdf_mbox, 0, MFI_MBOX_SIZE);
! 1129: dcmd->mdf_header.mfh_cmd = MFI_CMD_DCMD;
! 1130: dcmd->mdf_header.mfh_timeout = 0;
! 1131:
! 1132: dcmd->mdf_opcode = opc;
! 1133: dcmd->mdf_header.mfh_data_len = 0;
! 1134: ccb->ccb_direction = dir;
! 1135: ccb->ccb_done = mfi_mgmt_done;
! 1136:
! 1137: ccb->ccb_frame_size = MFI_DCMD_FRAME_SIZE;
! 1138:
! 1139: /* handle special opcodes */
! 1140: if (mbox)
! 1141: memcpy(dcmd->mdf_mbox, mbox, MFI_MBOX_SIZE);
! 1142:
! 1143: if (dir != MFI_DATA_NONE) {
! 1144: dcmd->mdf_header.mfh_data_len = len;
! 1145: ccb->ccb_data = buf;
! 1146: ccb->ccb_len = len;
! 1147: ccb->ccb_sgl = &dcmd->mdf_sgl;
! 1148:
! 1149: if (mfi_create_sgl(ccb, BUS_DMA_WAITOK))
! 1150: goto done;
! 1151: }
! 1152:
! 1153: if (cold) {
! 1154: if (mfi_poll(ccb))
! 1155: goto done;
! 1156: } else {
! 1157: mfi_despatch_cmd(ccb);
! 1158:
! 1159: DNPRINTF(MFI_D_MISC, "%s: mfi_mgmt sleeping\n", DEVNAME(sc));
! 1160: while (ccb->ccb_state != MFI_CCB_DONE)
! 1161: tsleep(ccb, PRIBIO, "mfi_mgmt", 0);
! 1162:
! 1163: if (ccb->ccb_flags & MFI_CCB_F_ERR)
! 1164: goto done;
! 1165: }
! 1166:
! 1167: rv = 0;
! 1168:
! 1169: done:
! 1170: mfi_put_ccb(ccb);
! 1171: return (rv);
! 1172: }
! 1173:
! 1174: void
! 1175: mfi_mgmt_done(struct mfi_ccb *ccb)
! 1176: {
! 1177: struct mfi_softc *sc = ccb->ccb_sc;
! 1178: struct mfi_frame_header *hdr = &ccb->ccb_frame->mfr_header;
! 1179:
! 1180: DNPRINTF(MFI_D_INTR, "%s: mfi_mgmt_done %#x %#x\n",
! 1181: DEVNAME(sc), ccb, ccb->ccb_frame);
! 1182:
! 1183: if (ccb->ccb_data != NULL) {
! 1184: DNPRINTF(MFI_D_INTR, "%s: mfi_mgmt_done sync\n",
! 1185: DEVNAME(sc));
! 1186: bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
! 1187: ccb->ccb_dmamap->dm_mapsize,
! 1188: (ccb->ccb_direction & MFI_DATA_IN) ?
! 1189: BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
! 1190:
! 1191: bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
! 1192: }
! 1193:
! 1194: if (hdr->mfh_cmd_status != MFI_STAT_OK)
! 1195: ccb->ccb_flags |= MFI_CCB_F_ERR;
! 1196:
! 1197: ccb->ccb_state = MFI_CCB_DONE;
! 1198:
! 1199: wakeup(ccb);
! 1200: }
! 1201:
! 1202:
! 1203: int
! 1204: mfi_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag,
! 1205: struct proc *p)
! 1206: {
! 1207: struct mfi_softc *sc = (struct mfi_softc *)link->adapter_softc;
! 1208:
! 1209: DNPRINTF(MFI_D_IOCTL, "%s: mfi_scsi_ioctl\n", DEVNAME(sc));
! 1210:
! 1211: if (sc->sc_ioctl)
! 1212: return (sc->sc_ioctl(link->adapter_softc, cmd, addr));
! 1213: else
! 1214: return (ENOTTY);
! 1215: }
! 1216:
! 1217: #if NBIO > 0
! 1218: int
! 1219: mfi_ioctl(struct device *dev, u_long cmd, caddr_t addr)
! 1220: {
! 1221: struct mfi_softc *sc = (struct mfi_softc *)dev;
! 1222: int error = 0;
! 1223:
! 1224: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl ", DEVNAME(sc));
! 1225:
! 1226: rw_enter_write(&sc->sc_lock);
! 1227:
! 1228: switch (cmd) {
! 1229: case BIOCINQ:
! 1230: DNPRINTF(MFI_D_IOCTL, "inq\n");
! 1231: error = mfi_ioctl_inq(sc, (struct bioc_inq *)addr);
! 1232: break;
! 1233:
! 1234: case BIOCVOL:
! 1235: DNPRINTF(MFI_D_IOCTL, "vol\n");
! 1236: error = mfi_ioctl_vol(sc, (struct bioc_vol *)addr);
! 1237: break;
! 1238:
! 1239: case BIOCDISK:
! 1240: DNPRINTF(MFI_D_IOCTL, "disk\n");
! 1241: error = mfi_ioctl_disk(sc, (struct bioc_disk *)addr);
! 1242: break;
! 1243:
! 1244: case BIOCALARM:
! 1245: DNPRINTF(MFI_D_IOCTL, "alarm\n");
! 1246: error = mfi_ioctl_alarm(sc, (struct bioc_alarm *)addr);
! 1247: break;
! 1248:
! 1249: case BIOCBLINK:
! 1250: DNPRINTF(MFI_D_IOCTL, "blink\n");
! 1251: error = mfi_ioctl_blink(sc, (struct bioc_blink *)addr);
! 1252: break;
! 1253:
! 1254: case BIOCSETSTATE:
! 1255: DNPRINTF(MFI_D_IOCTL, "setstate\n");
! 1256: error = mfi_ioctl_setstate(sc, (struct bioc_setstate *)addr);
! 1257: break;
! 1258:
! 1259: default:
! 1260: DNPRINTF(MFI_D_IOCTL, " invalid ioctl\n");
! 1261: error = EINVAL;
! 1262: }
! 1263:
! 1264: rw_exit_write(&sc->sc_lock);
! 1265:
! 1266: return (error);
! 1267: }
! 1268:
! 1269: int
! 1270: mfi_ioctl_inq(struct mfi_softc *sc, struct bioc_inq *bi)
! 1271: {
! 1272: struct mfi_conf *cfg;
! 1273: int rv = EINVAL;
! 1274:
! 1275: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_inq\n", DEVNAME(sc));
! 1276:
! 1277: if (mfi_get_info(sc)) {
! 1278: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_inq failed\n",
! 1279: DEVNAME(sc));
! 1280: return (EIO);
! 1281: }
! 1282:
! 1283: /* get figures */
! 1284: cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
! 1285: if (mfi_mgmt(sc, MD_DCMD_CONF_GET, MFI_DATA_IN, sizeof *cfg, cfg, NULL))
! 1286: goto freeme;
! 1287:
! 1288: strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
! 1289: bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs;
! 1290: bi->bi_nodisk = sc->sc_info.mci_pd_disks_present;
! 1291:
! 1292: rv = 0;
! 1293: freeme:
! 1294: free(cfg, M_DEVBUF);
! 1295: return (rv);
! 1296: }
! 1297:
! 1298: int
! 1299: mfi_ioctl_vol(struct mfi_softc *sc, struct bioc_vol *bv)
! 1300: {
! 1301: int i, per, rv = EINVAL;
! 1302: uint8_t mbox[MFI_MBOX_SIZE];
! 1303:
! 1304: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_vol %#x\n",
! 1305: DEVNAME(sc), bv->bv_volid);
! 1306:
! 1307: if (mfi_mgmt(sc, MR_DCMD_LD_GET_LIST, MFI_DATA_IN,
! 1308: sizeof(sc->sc_ld_list), &sc->sc_ld_list, NULL))
! 1309: goto done;
! 1310:
! 1311: i = bv->bv_volid;
! 1312: mbox[0] = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
! 1313: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_vol target %#x\n",
! 1314: DEVNAME(sc), mbox[0]);
! 1315:
! 1316: if (mfi_mgmt(sc, MR_DCMD_LD_GET_INFO, MFI_DATA_IN,
! 1317: sizeof(sc->sc_ld_details), &sc->sc_ld_details, mbox))
! 1318: goto done;
! 1319:
! 1320: if (bv->bv_volid >= sc->sc_ld_list.mll_no_ld) {
! 1321: /* go do hotspares */
! 1322: rv = mfi_bio_hs(sc, bv->bv_volid, MFI_MGMT_VD, bv);
! 1323: goto done;
! 1324: }
! 1325:
! 1326: strlcpy(bv->bv_dev, sc->sc_ld[i].ld_dev, sizeof(bv->bv_dev));
! 1327:
! 1328: switch(sc->sc_ld_list.mll_list[i].mll_state) {
! 1329: case MFI_LD_OFFLINE:
! 1330: bv->bv_status = BIOC_SVOFFLINE;
! 1331: break;
! 1332:
! 1333: case MFI_LD_PART_DEGRADED:
! 1334: case MFI_LD_DEGRADED:
! 1335: bv->bv_status = BIOC_SVDEGRADED;
! 1336: break;
! 1337:
! 1338: case MFI_LD_ONLINE:
! 1339: bv->bv_status = BIOC_SVONLINE;
! 1340: break;
! 1341:
! 1342: default:
! 1343: bv->bv_status = BIOC_SVINVALID;
! 1344: DNPRINTF(MFI_D_IOCTL, "%s: invalid logical disk state %#x\n",
! 1345: DEVNAME(sc),
! 1346: sc->sc_ld_list.mll_list[i].mll_state);
! 1347: }
! 1348:
! 1349: /* additional status can modify MFI status */
! 1350: switch (sc->sc_ld_details.mld_progress.mlp_in_prog) {
! 1351: case MFI_LD_PROG_CC:
! 1352: case MFI_LD_PROG_BGI:
! 1353: bv->bv_status = BIOC_SVSCRUB;
! 1354: per = (int)sc->sc_ld_details.mld_progress.mlp_cc.mp_progress;
! 1355: bv->bv_percent = (per * 100) / 0xffff;
! 1356: bv->bv_seconds =
! 1357: sc->sc_ld_details.mld_progress.mlp_cc.mp_elapsed_seconds;
! 1358: break;
! 1359:
! 1360: case MFI_LD_PROG_FGI:
! 1361: case MFI_LD_PROG_RECONSTRUCT:
! 1362: /* nothing yet */
! 1363: break;
! 1364: }
! 1365:
! 1366: /*
! 1367: * The RAID levels are determined per the SNIA DDF spec, this is only
! 1368: * a subset that is valid for the MFI contrller.
! 1369: */
! 1370: bv->bv_level = sc->sc_ld_details.mld_cfg.mlc_parm.mpa_pri_raid;
! 1371: if (sc->sc_ld_details.mld_cfg.mlc_parm.mpa_sec_raid ==
! 1372: MFI_DDF_SRL_SPANNED)
! 1373: bv->bv_level *= 10;
! 1374:
! 1375: bv->bv_nodisk = sc->sc_ld_details.mld_cfg.mlc_parm.mpa_no_drv_per_span *
! 1376: sc->sc_ld_details.mld_cfg.mlc_parm.mpa_span_depth;
! 1377:
! 1378: bv->bv_size = sc->sc_ld_details.mld_size * 512; /* bytes per block */
! 1379:
! 1380: rv = 0;
! 1381: done:
! 1382: return (rv);
! 1383: }
! 1384:
! 1385: int
! 1386: mfi_ioctl_disk(struct mfi_softc *sc, struct bioc_disk *bd)
! 1387: {
! 1388: struct mfi_conf *cfg;
! 1389: struct mfi_array *ar;
! 1390: struct mfi_ld_cfg *ld;
! 1391: struct mfi_pd_details *pd;
! 1392: struct scsi_inquiry_data *inqbuf;
! 1393: char vend[8+16+4+1];
! 1394: int i, rv = EINVAL;
! 1395: int arr, vol, disk;
! 1396: uint32_t size;
! 1397: uint8_t mbox[MFI_MBOX_SIZE];
! 1398:
! 1399: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_disk %#x\n",
! 1400: DEVNAME(sc), bd->bd_diskid);
! 1401:
! 1402: pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
! 1403:
! 1404: /* send single element command to retrieve size for full structure */
! 1405: cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
! 1406: if (mfi_mgmt(sc, MD_DCMD_CONF_GET, MFI_DATA_IN, sizeof *cfg, cfg, NULL))
! 1407: goto freeme;
! 1408:
! 1409: size = cfg->mfc_size;
! 1410: free(cfg, M_DEVBUF);
! 1411:
! 1412: /* memory for read config */
! 1413: cfg = malloc(size, M_DEVBUF, M_WAITOK);
! 1414: memset(cfg, 0, size);
! 1415: if (mfi_mgmt(sc, MD_DCMD_CONF_GET, MFI_DATA_IN, size, cfg, NULL))
! 1416: goto freeme;
! 1417:
! 1418: ar = cfg->mfc_array;
! 1419:
! 1420: /* calculate offset to ld structure */
! 1421: ld = (struct mfi_ld_cfg *)(
! 1422: ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
! 1423: cfg->mfc_array_size * cfg->mfc_no_array);
! 1424:
! 1425: vol = bd->bd_volid;
! 1426:
! 1427: if (vol >= cfg->mfc_no_ld) {
! 1428: /* do hotspares */
! 1429: rv = mfi_bio_hs(sc, bd->bd_volid, MFI_MGMT_SD, bd);
! 1430: goto freeme;
! 1431: }
! 1432:
! 1433: /* find corresponding array for ld */
! 1434: for (i = 0, arr = 0; i < vol; i++)
! 1435: arr += ld[i].mlc_parm.mpa_span_depth;
! 1436:
! 1437: /* offset disk into pd list */
! 1438: disk = bd->bd_diskid % ld[vol].mlc_parm.mpa_no_drv_per_span;
! 1439:
! 1440: /* offset array index into the next spans */
! 1441: arr += bd->bd_diskid / ld[vol].mlc_parm.mpa_no_drv_per_span;
! 1442:
! 1443: bd->bd_target = ar[arr].pd[disk].mar_enc_slot;
! 1444: switch (ar[arr].pd[disk].mar_pd_state){
! 1445: case MFI_PD_UNCONFIG_GOOD:
! 1446: bd->bd_status = BIOC_SDUNUSED;
! 1447: break;
! 1448:
! 1449: case MFI_PD_HOTSPARE: /* XXX dedicated hotspare part of array? */
! 1450: bd->bd_status = BIOC_SDHOTSPARE;
! 1451: break;
! 1452:
! 1453: case MFI_PD_OFFLINE:
! 1454: bd->bd_status = BIOC_SDOFFLINE;
! 1455: break;
! 1456:
! 1457: case MFI_PD_FAILED:
! 1458: bd->bd_status = BIOC_SDFAILED;
! 1459: break;
! 1460:
! 1461: case MFI_PD_REBUILD:
! 1462: bd->bd_status = BIOC_SDREBUILD;
! 1463: break;
! 1464:
! 1465: case MFI_PD_ONLINE:
! 1466: bd->bd_status = BIOC_SDONLINE;
! 1467: break;
! 1468:
! 1469: case MFI_PD_UNCONFIG_BAD: /* XXX define new state in bio */
! 1470: default:
! 1471: bd->bd_status = BIOC_SDINVALID;
! 1472: break;
! 1473:
! 1474: }
! 1475:
! 1476: /* get the remaining fields */
! 1477: *((uint16_t *)&mbox) = ar[arr].pd[disk].mar_pd.mfp_id;
! 1478: if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
! 1479: sizeof *pd, pd, mbox))
! 1480: goto freeme;
! 1481:
! 1482: bd->bd_size = pd->mpd_size * 512; /* bytes per block */
! 1483:
! 1484: /* if pd->mpd_enc_idx is 0 then it is not in an enclosure */
! 1485: bd->bd_channel = pd->mpd_enc_idx;
! 1486:
! 1487: inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data;
! 1488: memcpy(vend, inqbuf->vendor, sizeof vend - 1);
! 1489: vend[sizeof vend - 1] = '\0';
! 1490: strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor));
! 1491:
! 1492: /* XXX find a way to retrieve serial nr from drive */
! 1493: /* XXX find a way to get bd_procdev */
! 1494:
! 1495: rv = 0;
! 1496: freeme:
! 1497: free(pd, M_DEVBUF);
! 1498: free(cfg, M_DEVBUF);
! 1499:
! 1500: return (rv);
! 1501: }
! 1502:
! 1503: int
! 1504: mfi_ioctl_alarm(struct mfi_softc *sc, struct bioc_alarm *ba)
! 1505: {
! 1506: uint32_t opc, dir = MFI_DATA_NONE;
! 1507: int rv = 0;
! 1508: int8_t ret;
! 1509:
! 1510: switch(ba->ba_opcode) {
! 1511: case BIOC_SADISABLE:
! 1512: opc = MR_DCMD_SPEAKER_DISABLE;
! 1513: break;
! 1514:
! 1515: case BIOC_SAENABLE:
! 1516: opc = MR_DCMD_SPEAKER_ENABLE;
! 1517: break;
! 1518:
! 1519: case BIOC_SASILENCE:
! 1520: opc = MR_DCMD_SPEAKER_SILENCE;
! 1521: break;
! 1522:
! 1523: case BIOC_GASTATUS:
! 1524: opc = MR_DCMD_SPEAKER_GET;
! 1525: dir = MFI_DATA_IN;
! 1526: break;
! 1527:
! 1528: case BIOC_SATEST:
! 1529: opc = MR_DCMD_SPEAKER_TEST;
! 1530: break;
! 1531:
! 1532: default:
! 1533: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_alarm biocalarm invalid "
! 1534: "opcode %x\n", DEVNAME(sc), ba->ba_opcode);
! 1535: return (EINVAL);
! 1536: }
! 1537:
! 1538: if (mfi_mgmt(sc, opc, dir, sizeof(ret), &ret, NULL))
! 1539: rv = EINVAL;
! 1540: else
! 1541: if (ba->ba_opcode == BIOC_GASTATUS)
! 1542: ba->ba_status = ret;
! 1543: else
! 1544: ba->ba_status = 0;
! 1545:
! 1546: return (rv);
! 1547: }
! 1548:
! 1549: int
! 1550: mfi_ioctl_blink(struct mfi_softc *sc, struct bioc_blink *bb)
! 1551: {
! 1552: int i, found, rv = EINVAL;
! 1553: uint8_t mbox[MFI_MBOX_SIZE];
! 1554: uint32_t cmd;
! 1555: struct mfi_pd_list *pd;
! 1556:
! 1557: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_blink %x\n", DEVNAME(sc),
! 1558: bb->bb_status);
! 1559:
! 1560: /* channel 0 means not in an enclosure so can't be blinked */
! 1561: if (bb->bb_channel == 0)
! 1562: return (EINVAL);
! 1563:
! 1564: pd = malloc(MFI_PD_LIST_SIZE, M_DEVBUF, M_WAITOK);
! 1565:
! 1566: if (mfi_mgmt(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN,
! 1567: MFI_PD_LIST_SIZE, pd, NULL))
! 1568: goto done;
! 1569:
! 1570: for (i = 0, found = 0; i < pd->mpl_no_pd; i++)
! 1571: if (bb->bb_channel == pd->mpl_address[i].mpa_enc_index &&
! 1572: bb->bb_target == pd->mpl_address[i].mpa_enc_slot) {
! 1573: found = 1;
! 1574: break;
! 1575: }
! 1576:
! 1577: if (!found)
! 1578: goto done;
! 1579:
! 1580: memset(mbox, 0, sizeof mbox);
! 1581:
! 1582: *((uint16_t *)&mbox) = pd->mpl_address[i].mpa_pd_id;
! 1583:
! 1584: switch (bb->bb_status) {
! 1585: case BIOC_SBUNBLINK:
! 1586: cmd = MR_DCMD_PD_UNBLINK;
! 1587: break;
! 1588:
! 1589: case BIOC_SBBLINK:
! 1590: cmd = MR_DCMD_PD_BLINK;
! 1591: break;
! 1592:
! 1593: case BIOC_SBALARM:
! 1594: default:
! 1595: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_blink biocblink invalid "
! 1596: "opcode %x\n", DEVNAME(sc), bb->bb_status);
! 1597: goto done;
! 1598: }
! 1599:
! 1600:
! 1601: if (mfi_mgmt(sc, cmd, MFI_DATA_NONE, 0, NULL, mbox))
! 1602: goto done;
! 1603:
! 1604: rv = 0;
! 1605: done:
! 1606: free(pd, M_DEVBUF);
! 1607: return (rv);
! 1608: }
! 1609:
! 1610: int
! 1611: mfi_ioctl_setstate(struct mfi_softc *sc, struct bioc_setstate *bs)
! 1612: {
! 1613: struct mfi_pd_list *pd;
! 1614: int i, found, rv = EINVAL;
! 1615: uint8_t mbox[MFI_MBOX_SIZE];
! 1616: uint32_t cmd;
! 1617:
! 1618: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_setstate %x\n", DEVNAME(sc),
! 1619: bs->bs_status);
! 1620:
! 1621: pd = malloc(MFI_PD_LIST_SIZE, M_DEVBUF, M_WAITOK);
! 1622:
! 1623: if (mfi_mgmt(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN,
! 1624: MFI_PD_LIST_SIZE, pd, NULL))
! 1625: goto done;
! 1626:
! 1627: for (i = 0, found = 0; i < pd->mpl_no_pd; i++)
! 1628: if (bs->bs_channel == pd->mpl_address[i].mpa_enc_index &&
! 1629: bs->bs_target == pd->mpl_address[i].mpa_enc_slot) {
! 1630: found = 1;
! 1631: break;
! 1632: }
! 1633:
! 1634: if (!found)
! 1635: goto done;
! 1636:
! 1637: memset(mbox, 0, sizeof mbox);
! 1638:
! 1639: *((uint16_t *)&mbox) = pd->mpl_address[i].mpa_pd_id;
! 1640:
! 1641: switch (bs->bs_status) {
! 1642: case BIOC_SSONLINE:
! 1643: mbox[2] = MFI_PD_ONLINE;
! 1644: cmd = MD_DCMD_PD_SET_STATE;
! 1645: break;
! 1646:
! 1647: case BIOC_SSOFFLINE:
! 1648: mbox[2] = MFI_PD_OFFLINE;
! 1649: cmd = MD_DCMD_PD_SET_STATE;
! 1650: break;
! 1651:
! 1652: case BIOC_SSHOTSPARE:
! 1653: mbox[2] = MFI_PD_HOTSPARE;
! 1654: cmd = MD_DCMD_PD_SET_STATE;
! 1655: break;
! 1656: /*
! 1657: case BIOC_SSREBUILD:
! 1658: cmd = MD_DCMD_PD_REBUILD;
! 1659: break;
! 1660: */
! 1661: default:
! 1662: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_setstate invalid "
! 1663: "opcode %x\n", DEVNAME(sc), bs->bs_status);
! 1664: goto done;
! 1665: }
! 1666:
! 1667:
! 1668: if (mfi_mgmt(sc, MD_DCMD_PD_SET_STATE, MFI_DATA_NONE, 0, NULL, mbox))
! 1669: goto done;
! 1670:
! 1671: rv = 0;
! 1672: done:
! 1673: free(pd, M_DEVBUF);
! 1674: return (rv);
! 1675: }
! 1676:
! 1677: int
! 1678: mfi_bio_hs(struct mfi_softc *sc, int volid, int type, void *bio_hs)
! 1679: {
! 1680: struct mfi_conf *cfg;
! 1681: struct mfi_hotspare *hs;
! 1682: struct mfi_pd_details *pd;
! 1683: struct bioc_disk *sdhs;
! 1684: struct bioc_vol *vdhs;
! 1685: struct scsi_inquiry_data *inqbuf;
! 1686: char vend[8+16+4+1];
! 1687: int i, rv = EINVAL;
! 1688: uint32_t size;
! 1689: uint8_t mbox[MFI_MBOX_SIZE];
! 1690:
! 1691: DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs %d\n", DEVNAME(sc), volid);
! 1692:
! 1693: if (!bio_hs)
! 1694: return (EINVAL);
! 1695:
! 1696: pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
! 1697:
! 1698: /* send single element command to retrieve size for full structure */
! 1699: cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
! 1700: if (mfi_mgmt(sc, MD_DCMD_CONF_GET, MFI_DATA_IN, sizeof *cfg, cfg, NULL))
! 1701: goto freeme;
! 1702:
! 1703: size = cfg->mfc_size;
! 1704: free(cfg, M_DEVBUF);
! 1705:
! 1706: /* memory for read config */
! 1707: cfg = malloc(size, M_DEVBUF, M_WAITOK);
! 1708: memset(cfg, 0, size);
! 1709: if (mfi_mgmt(sc, MD_DCMD_CONF_GET, MFI_DATA_IN, size, cfg, NULL))
! 1710: goto freeme;
! 1711:
! 1712: /* calculate offset to hs structure */
! 1713: hs = (struct mfi_hotspare *)(
! 1714: ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
! 1715: cfg->mfc_array_size * cfg->mfc_no_array +
! 1716: cfg->mfc_ld_size * cfg->mfc_no_ld);
! 1717:
! 1718: if (volid < cfg->mfc_no_ld)
! 1719: goto freeme; /* not a hotspare */
! 1720:
! 1721: if (volid > (cfg->mfc_no_ld + cfg->mfc_no_hs))
! 1722: goto freeme; /* not a hotspare */
! 1723:
! 1724: /* offset into hotspare structure */
! 1725: i = volid - cfg->mfc_no_ld;
! 1726:
! 1727: DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs i %d volid %d no_ld %d no_hs %d "
! 1728: "hs %p cfg %p id %02x\n", DEVNAME(sc), i, volid, cfg->mfc_no_ld,
! 1729: cfg->mfc_no_hs, hs, cfg, hs[i].mhs_pd.mfp_id);
! 1730:
! 1731: /* get pd fields */
! 1732: memset(mbox, 0, sizeof mbox);
! 1733: *((uint16_t *)&mbox) = hs[i].mhs_pd.mfp_id;
! 1734: if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
! 1735: sizeof *pd, pd, mbox)) {
! 1736: DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs illegal PD\n",
! 1737: DEVNAME(sc));
! 1738: goto freeme;
! 1739: }
! 1740:
! 1741: switch (type) {
! 1742: case MFI_MGMT_VD:
! 1743: vdhs = bio_hs;
! 1744: vdhs->bv_status = BIOC_SVONLINE;
! 1745: vdhs->bv_size = pd->mpd_size / 2; /* XXX why? / 2 */
! 1746: vdhs->bv_level = -1; /* hotspare */
! 1747: vdhs->bv_nodisk = 1;
! 1748: break;
! 1749:
! 1750: case MFI_MGMT_SD:
! 1751: sdhs = bio_hs;
! 1752: sdhs->bd_status = BIOC_SDHOTSPARE;
! 1753: sdhs->bd_size = pd->mpd_size / 2; /* XXX why? / 2 */
! 1754: sdhs->bd_channel = pd->mpd_enc_idx;
! 1755: sdhs->bd_target = pd->mpd_enc_slot;
! 1756: inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data;
! 1757: memcpy(vend, inqbuf->vendor, sizeof vend - 1);
! 1758: vend[sizeof vend - 1] = '\0';
! 1759: strlcpy(sdhs->bd_vendor, vend, sizeof(sdhs->bd_vendor));
! 1760: break;
! 1761:
! 1762: default:
! 1763: goto freeme;
! 1764: }
! 1765:
! 1766: DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs 6\n", DEVNAME(sc));
! 1767: rv = 0;
! 1768: freeme:
! 1769: free(pd, M_DEVBUF);
! 1770: free(cfg, M_DEVBUF);
! 1771:
! 1772: return (rv);
! 1773: }
! 1774:
! 1775: #ifndef SMALL_KERNEL
! 1776: int
! 1777: mfi_create_sensors(struct mfi_softc *sc)
! 1778: {
! 1779: struct device *dev;
! 1780: struct scsibus_softc *ssc;
! 1781: int i;
! 1782:
! 1783: TAILQ_FOREACH(dev, &alldevs, dv_list) {
! 1784: if (dev->dv_parent != &sc->sc_dev)
! 1785: continue;
! 1786:
! 1787: /* check if this is the scsibus for the logical disks */
! 1788: ssc = (struct scsibus_softc *)dev;
! 1789: if (ssc->adapter_link == &sc->sc_link)
! 1790: break;
! 1791: }
! 1792:
! 1793: if (ssc == NULL)
! 1794: return (1);
! 1795:
! 1796: sc->sc_sensors = malloc(sizeof(struct ksensor) * sc->sc_ld_cnt,
! 1797: M_DEVBUF, M_WAITOK);
! 1798: if (sc->sc_sensors == NULL)
! 1799: return (1);
! 1800: bzero(sc->sc_sensors, sizeof(struct ksensor) * sc->sc_ld_cnt);
! 1801:
! 1802: strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
! 1803: sizeof(sc->sc_sensordev.xname));
! 1804:
! 1805: for (i = 0; i < sc->sc_ld_cnt; i++) {
! 1806: if (ssc->sc_link[i][0] == NULL)
! 1807: goto bad;
! 1808:
! 1809: dev = ssc->sc_link[i][0]->device_softc;
! 1810:
! 1811: sc->sc_sensors[i].type = SENSOR_DRIVE;
! 1812: sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
! 1813:
! 1814: strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
! 1815: sizeof(sc->sc_sensors[i].desc));
! 1816:
! 1817: sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
! 1818: }
! 1819:
! 1820: if (sensor_task_register(sc, mfi_refresh_sensors, 10) == NULL)
! 1821: goto bad;
! 1822:
! 1823: sensordev_install(&sc->sc_sensordev);
! 1824:
! 1825: return (0);
! 1826:
! 1827: bad:
! 1828: free(sc->sc_sensors, M_DEVBUF);
! 1829:
! 1830: return (1);
! 1831: }
! 1832:
! 1833: void
! 1834: mfi_refresh_sensors(void *arg)
! 1835: {
! 1836: struct mfi_softc *sc = arg;
! 1837: int i;
! 1838: struct bioc_vol bv;
! 1839:
! 1840:
! 1841: for (i = 0; i < sc->sc_ld_cnt; i++) {
! 1842: bzero(&bv, sizeof(bv));
! 1843: bv.bv_volid = i;
! 1844: if (mfi_ioctl_vol(sc, &bv))
! 1845: return;
! 1846:
! 1847: switch(bv.bv_status) {
! 1848: case BIOC_SVOFFLINE:
! 1849: sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
! 1850: sc->sc_sensors[i].status = SENSOR_S_CRIT;
! 1851: break;
! 1852:
! 1853: case BIOC_SVDEGRADED:
! 1854: sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
! 1855: sc->sc_sensors[i].status = SENSOR_S_WARN;
! 1856: break;
! 1857:
! 1858: case BIOC_SVSCRUB:
! 1859: case BIOC_SVONLINE:
! 1860: sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
! 1861: sc->sc_sensors[i].status = SENSOR_S_OK;
! 1862: break;
! 1863:
! 1864: case BIOC_SVINVALID:
! 1865: /* FALLTRHOUGH */
! 1866: default:
! 1867: sc->sc_sensors[i].value = 0; /* unknown */
! 1868: sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
! 1869: }
! 1870:
! 1871: }
! 1872: }
! 1873: #endif /* SMALL_KERNEL */
! 1874: #endif /* NBIO > 0 */
CVSweb