Index: sys/dev/mfi/mfi.c =================================================================== --- sys/dev/mfi/mfi.c (revision 254079) +++ sys/dev/mfi/mfi.c (working copy) @@ -107,7 +107,7 @@ static void mfi_bio_complete(struct mfi_command *) static struct mfi_command *mfi_build_ldio(struct mfi_softc *,struct bio*); static struct mfi_command *mfi_build_syspdio(struct mfi_softc *,struct bio*); static int mfi_send_frame(struct mfi_softc *, struct mfi_command *); -static int mfi_abort(struct mfi_softc *, struct mfi_command *); +static int mfi_abort(struct mfi_softc *, struct mfi_command **); static int mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, struct thread *); static void mfi_timeout(void *); static int mfi_user_command(struct mfi_softc *, @@ -373,6 +373,8 @@ mfi_attach(struct mfi_softc *sc) sx_init(&sc->mfi_config_lock, "MFI config"); TAILQ_INIT(&sc->mfi_ld_tqh); TAILQ_INIT(&sc->mfi_syspd_tqh); + TAILQ_INIT(&sc->mfi_ld_pend_tqh); + TAILQ_INIT(&sc->mfi_syspd_pend_tqh); TAILQ_INIT(&sc->mfi_evt_queue); TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc); TASK_INIT(&sc->mfi_map_sync_task, 0, mfi_handle_map_sync, sc); @@ -694,6 +696,7 @@ mfi_attach(struct mfi_softc *sc) device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); return (EINVAL); } + sc->mfi_intr_ptr = mfi_intr_tbolt; sc->mfi_enable_intr(sc); } else { if ((error = mfi_comms_init(sc)) != 0) @@ -704,6 +707,7 @@ mfi_attach(struct mfi_softc *sc) device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); return (EINVAL); } + sc->mfi_intr_ptr = mfi_intr; sc->mfi_enable_intr(sc); } if ((error = mfi_get_controller_info(sc)) != 0) @@ -1278,6 +1282,17 @@ mfi_shutdown(struct mfi_softc *sc) struct mfi_command *cm; int error; + + if (sc->mfi_aen_cm) + sc->cm_aen_abort = 1; + if (sc->mfi_aen_cm != NULL) + mfi_abort(sc, &sc->mfi_aen_cm); + + if (sc->mfi_map_sync_cm) + sc->cm_map_abort = 1; + if (sc->mfi_map_sync_cm != NULL) + mfi_abort(sc, &sc->mfi_map_sync_cm); + mtx_lock(&sc->mfi_io_lock); error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0); if (error) { @@ -1285,12 +1300,6 @@ mfi_shutdown(struct mfi_softc *sc) return (error); } - if (sc->mfi_aen_cm != NULL) - mfi_abort(sc, sc->mfi_aen_cm); - - if (sc->mfi_map_sync_cm != NULL) - mfi_abort(sc, sc->mfi_map_sync_cm); - dcmd = &cm->cm_frame->dcmd; dcmd->header.flags = MFI_FRAME_DIR_NONE; cm->cm_flags = MFI_CMD_POLLED; @@ -1312,6 +1321,7 @@ mfi_syspdprobe(struct mfi_softc *sc) struct mfi_command *cm = NULL; struct mfi_pd_list *pdlist = NULL; struct mfi_system_pd *syspd, *tmp; + struct mfi_system_pending *syspd_pend; int error, i, found; sx_assert(&sc->mfi_config_lock, SA_XLOCKED); @@ -1352,6 +1362,10 @@ mfi_syspdprobe(struct mfi_softc *sc) if (syspd->pd_id == pdlist->addr[i].device_id) found = 1; } + TAILQ_FOREACH(syspd_pend, &sc->mfi_syspd_pend_tqh, pd_link) { + if (syspd_pend->pd_id == pdlist->addr[i].device_id) + found = 1; + } if (found == 0) mfi_add_sys_pd(sc, pdlist->addr[i].device_id); } @@ -1387,6 +1401,7 @@ mfi_ldprobe(struct mfi_softc *sc) struct mfi_command *cm = NULL; struct mfi_ld_list *list = NULL; struct mfi_disk *ld; + struct mfi_disk_pending *ld_pend; int error, i; sx_assert(&sc->mfi_config_lock, SA_XLOCKED); @@ -1415,6 +1430,10 @@ mfi_ldprobe(struct mfi_softc *sc) if (ld->ld_id == list->ld_list[i].ld.v.target_id) goto skip_add; } + TAILQ_FOREACH(ld_pend, &sc->mfi_ld_pend_tqh, ld_link) { + if (ld_pend->ld_id == list->ld_list[i].ld.v.target_id) + goto skip_add; + } mfi_add_ld(sc, list->ld_list[i].ld.v.target_id); skip_add:; } @@ -1617,9 +1636,7 @@ mfi_aen_register(struct mfi_softc *sc, int seq, in < current_aen.members.evt_class) current_aen.members.evt_class = prior_aen.members.evt_class; - mtx_lock(&sc->mfi_io_lock); - mfi_abort(sc, sc->mfi_aen_cm); - mtx_unlock(&sc->mfi_io_lock); + mfi_abort(sc, &sc->mfi_aen_cm); } } @@ -1811,10 +1828,17 @@ mfi_add_ld(struct mfi_softc *sc, int id) struct mfi_command *cm; struct mfi_dcmd_frame *dcmd = NULL; struct mfi_ld_info *ld_info = NULL; + struct mfi_disk_pending *ld_pend; int error; mtx_assert(&sc->mfi_io_lock, MA_OWNED); + ld_pend = malloc(sizeof(*ld_pend), M_MFIBUF, M_NOWAIT | M_ZERO); + if (ld_pend != NULL) { + ld_pend->ld_id = id; + TAILQ_INSERT_TAIL(&sc->mfi_ld_pend_tqh, ld_pend, ld_link); + } + error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO, (void **)&ld_info, sizeof(*ld_info)); if (error) { @@ -1855,11 +1879,13 @@ mfi_add_ld_complete(struct mfi_command *cm) hdr = &cm->cm_frame->header; ld_info = cm->cm_private; - if (hdr->cmd_status != MFI_STAT_OK) { + if (sc->cm_map_abort || hdr->cmd_status != MFI_STAT_OK) { free(ld_info, M_MFIBUF); + wakeup(&sc->mfi_map_sync_cm); mfi_release_command(cm); return; } + wakeup(&sc->mfi_map_sync_cm); mfi_release_command(cm); mtx_unlock(&sc->mfi_io_lock); @@ -1884,10 +1910,17 @@ static int mfi_add_sys_pd(struct mfi_softc *sc, in struct mfi_command *cm; struct mfi_dcmd_frame *dcmd = NULL; struct mfi_pd_info *pd_info = NULL; + struct mfi_system_pending *syspd_pend; int error; mtx_assert(&sc->mfi_io_lock, MA_OWNED); + syspd_pend = malloc(sizeof(*syspd_pend), M_MFIBUF, M_NOWAIT | M_ZERO); + if (syspd_pend != NULL) { + syspd_pend->pd_id = id; + TAILQ_INSERT_TAIL(&sc->mfi_syspd_pend_tqh, syspd_pend, pd_link); + } + error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO, (void **)&pd_info, sizeof(*pd_info)); if (error) { @@ -1981,19 +2014,87 @@ mfi_bio_command(struct mfi_softc *sc) mfi_enqueue_bio(sc, bio); return cm; } + +/* + * mostly copied from cam/scsi/scsi_all.c:scsi_read_write + */ + +int +mfi_build_cdb(int readop, uint8_t byte2, u_int64_t lba, u_int32_t block_count, uint8_t *cdb) +{ + int cdb_len; + + if (((lba & 0x1fffff) == lba) + && ((block_count & 0xff) == block_count) + && (byte2 == 0)) { + /* We can fit in a 6 byte cdb */ + struct scsi_rw_6 *scsi_cmd; + + scsi_cmd = (struct scsi_rw_6 *)cdb; + scsi_cmd->opcode = readop ? READ_6 : WRITE_6; + scsi_ulto3b(lba, scsi_cmd->addr); + scsi_cmd->length = block_count & 0xff; + scsi_cmd->control = 0; + cdb_len = sizeof(*scsi_cmd); + } else if (((block_count & 0xffff) == block_count) && ((lba & 0xffffffff) == lba)) { + /* Need a 10 byte CDB */ + struct scsi_rw_10 *scsi_cmd; + + scsi_cmd = (struct scsi_rw_10 *)cdb; + scsi_cmd->opcode = readop ? READ_10 : WRITE_10; + scsi_cmd->byte2 = byte2; + scsi_ulto4b(lba, scsi_cmd->addr); + scsi_cmd->reserved = 0; + scsi_ulto2b(block_count, scsi_cmd->length); + scsi_cmd->control = 0; + cdb_len = sizeof(*scsi_cmd); + } else if (((block_count & 0xffffffff) == block_count) && + ((lba & 0xffffffff) == lba)) { + /* Block count is too big for 10 byte CDB use a 12 byte CDB */ + struct scsi_rw_12 *scsi_cmd; + + scsi_cmd = (struct scsi_rw_12 *)cdb; + scsi_cmd->opcode = readop ? READ_12 : WRITE_12; + scsi_cmd->byte2 = byte2; + scsi_ulto4b(lba, scsi_cmd->addr); + scsi_cmd->reserved = 0; + scsi_ulto4b(block_count, scsi_cmd->length); + scsi_cmd->control = 0; + cdb_len = sizeof(*scsi_cmd); + } else { + /* + * 16 byte CDB. We'll only get here if the LBA is larger + * than 2^32 + */ + struct scsi_rw_16 *scsi_cmd; + + scsi_cmd = (struct scsi_rw_16 *)cdb; + scsi_cmd->opcode = readop ? READ_16 : WRITE_16; + scsi_cmd->byte2 = byte2; + scsi_u64to8b(lba, scsi_cmd->addr); + scsi_cmd->reserved = 0; + scsi_ulto4b(block_count, scsi_cmd->length); + scsi_cmd->control = 0; + cdb_len = sizeof(*scsi_cmd); + } + + return cdb_len; +} + static struct mfi_command * mfi_build_syspdio(struct mfi_softc *sc, struct bio *bio) { struct mfi_command *cm; struct mfi_pass_frame *pass; - int flags = 0, blkcount = 0; uint32_t context = 0; + int flags = 0, blkcount = 0, readop; + uint8_t cdb_len; if ((cm = mfi_dequeue_free(sc)) == NULL) return (NULL); /* Zero out the MFI frame */ - context = cm->cm_frame->header.context; + context = cm->cm_frame->header.context; bzero(cm->cm_frame, sizeof(union mfi_frame)); cm->cm_frame->header.context = context; pass = &cm->cm_frame->pass; @@ -2001,35 +2102,31 @@ mfi_build_syspdio(struct mfi_softc *sc, struct bio pass->header.cmd = MFI_CMD_PD_SCSI_IO; switch (bio->bio_cmd & 0x03) { case BIO_READ: -#define SCSI_READ 0x28 - pass->cdb[0] = SCSI_READ; flags = MFI_CMD_DATAIN; + readop = 1; break; case BIO_WRITE: -#define SCSI_WRITE 0x2a - pass->cdb[0] = SCSI_WRITE; flags = MFI_CMD_DATAOUT; + readop = 0; break; default: - panic("Invalid bio command"); + /* TODO: what about BIO_DELETE??? */ + panic("Unsupported bio command %x\n", bio->bio_cmd); } /* Cheat with the sector length to avoid a non-constant division */ blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; /* Fill the LBA and Transfer length in CDB */ - pass->cdb[2] = (bio->bio_pblkno & 0xff000000) >> 24; - pass->cdb[3] = (bio->bio_pblkno & 0x00ff0000) >> 16; - pass->cdb[4] = (bio->bio_pblkno & 0x0000ff00) >> 8; - pass->cdb[5] = bio->bio_pblkno & 0x000000ff; - pass->cdb[7] = (blkcount & 0xff00) >> 8; - pass->cdb[8] = (blkcount & 0x00ff); + cdb_len = mfi_build_cdb(readop, 0, bio->bio_pblkno, blkcount, + pass->cdb); pass->header.target_id = (uintptr_t)bio->bio_driver1; + pass->header.lun_id = 0; pass->header.timeout = 0; pass->header.flags = 0; pass->header.scsi_status = 0; pass->header.sense_len = MFI_SENSE_LEN; pass->header.data_len = bio->bio_bcount; - pass->header.cdb_len = 10; + pass->header.cdb_len = cdb_len; pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); cm->cm_complete = mfi_bio_complete; @@ -2047,7 +2144,8 @@ mfi_build_ldio(struct mfi_softc *sc, struct bio *b { struct mfi_io_frame *io; struct mfi_command *cm; - int flags, blkcount; + int flags; + uint32_t blkcount; uint32_t context = 0; if ((cm = mfi_dequeue_free(sc)) == NULL) @@ -2068,7 +2166,8 @@ mfi_build_ldio(struct mfi_softc *sc, struct bio *b flags = MFI_CMD_DATAOUT; break; default: - panic("Invalid bio command"); + /* TODO: what about BIO_DELETE??? */ + panic("Unsupported bio command %x\n", bio->bio_cmd); } /* Cheat with the sector length to avoid a non-constant division */ @@ -2358,7 +2457,7 @@ mfi_complete(struct mfi_softc *sc, struct mfi_comm } static int -mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort) +mfi_abort(struct mfi_softc *sc, struct mfi_command **cm_abort) { struct mfi_command *cm; struct mfi_abort_frame *abort; @@ -2365,8 +2464,7 @@ static int int i = 0; uint32_t context = 0; - mtx_assert(&sc->mfi_io_lock, MA_OWNED); - + mtx_lock(&sc->mfi_io_lock); if ((cm = mfi_dequeue_free(sc)) == NULL) { return (EBUSY); } @@ -2380,29 +2478,27 @@ static int abort->header.cmd = MFI_CMD_ABORT; abort->header.flags = 0; abort->header.scsi_status = 0; - abort->abort_context = cm_abort->cm_frame->header.context; - abort->abort_mfi_addr_lo = (uint32_t)cm_abort->cm_frame_busaddr; + abort->abort_context = (*cm_abort)->cm_frame->header.context; + abort->abort_mfi_addr_lo = (uint32_t)(*cm_abort)->cm_frame_busaddr; abort->abort_mfi_addr_hi = - (uint32_t)((uint64_t)cm_abort->cm_frame_busaddr >> 32); + (uint32_t)((uint64_t)(*cm_abort)->cm_frame_busaddr >> 32); cm->cm_data = NULL; cm->cm_flags = MFI_CMD_POLLED; - if (sc->mfi_aen_cm) - sc->cm_aen_abort = 1; - if (sc->mfi_map_sync_cm) - sc->cm_map_abort = 1; mfi_mapcmd(sc, cm); mfi_release_command(cm); - while (i < 5 && sc->mfi_aen_cm != NULL) { - msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort", + mtx_unlock(&sc->mfi_io_lock); + while (i < 5 && *cm_abort != NULL) { + tsleep(cm_abort, 0, "mfiabort", 5 * hz); i++; } - while (i < 5 && sc->mfi_map_sync_cm != NULL) { - msleep(&sc->mfi_map_sync_cm, &sc->mfi_io_lock, 0, "mfiabort", - 5 * hz); - i++; + if (*cm_abort != NULL) { + /* Force a complete if command didn't abort */ + mtx_lock(&sc->mfi_io_lock); + (*cm_abort)->cm_complete(*cm_abort); + mtx_unlock(&sc->mfi_io_lock); } return (0); @@ -2458,8 +2554,8 @@ mfi_dump_syspd_blocks(struct mfi_softc *sc, int id { struct mfi_command *cm; struct mfi_pass_frame *pass; - int error; - int blkcount = 0; + int error, readop, cdb_len; + uint32_t blkcount; if ((cm = mfi_dequeue_free(sc)) == NULL) return (EBUSY); @@ -2467,14 +2563,10 @@ mfi_dump_syspd_blocks(struct mfi_softc *sc, int id pass = &cm->cm_frame->pass; bzero(pass->cdb, 16); pass->header.cmd = MFI_CMD_PD_SCSI_IO; - pass->cdb[0] = SCSI_WRITE; - pass->cdb[2] = (lba & 0xff000000) >> 24; - pass->cdb[3] = (lba & 0x00ff0000) >> 16; - pass->cdb[4] = (lba & 0x0000ff00) >> 8; - pass->cdb[5] = (lba & 0x000000ff); + + readop = 0; blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; - pass->cdb[7] = (blkcount & 0xff00) >> 8; - pass->cdb[8] = (blkcount & 0x00ff); + cdb_len = mfi_build_cdb(readop, 0, lba, blkcount, pass->cdb); pass->header.target_id = id; pass->header.timeout = 0; pass->header.flags = 0; @@ -2481,7 +2573,7 @@ mfi_dump_syspd_blocks(struct mfi_softc *sc, int id pass->header.scsi_status = 0; pass->header.sense_len = MFI_SENSE_LEN; pass->header.data_len = len; - pass->header.cdb_len = 10; + pass->header.cdb_len = cdb_len; pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); cm->cm_data = virt; @@ -2488,7 +2580,7 @@ mfi_dump_syspd_blocks(struct mfi_softc *sc, int id cm->cm_len = len; cm->cm_sg = &pass->sgl; cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE; - cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT; + cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT | MFI_CMD_SCSI; error = mfi_mapcmd(sc, cm); bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, @@ -2687,16 +2779,24 @@ mfi_check_command_post(struct mfi_softc *sc, struc } } -static int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm) +static int +mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm) { - struct mfi_config_data *conf_data=(struct mfi_config_data *)cm->cm_data; + struct mfi_config_data *conf_data; struct mfi_command *ld_cm = NULL; struct mfi_ld_info *ld_info = NULL; + struct mfi_ld_config *ld; + char *p; int error = 0; - if ((cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) && - (conf_data->ld[0].params.isSSCD == 1)) { - error = 1; + conf_data = (struct mfi_config_data *)cm->cm_data; + + if (cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) { + p = (char *)conf_data->array; + p += conf_data->array_size * conf_data->array_count; + ld = (struct mfi_ld_config *)p; + if (ld->params.isSSCD == 1) + error = 1; } else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) { error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO, (void **)&ld_info, sizeof(*ld_info)); Index: sys/dev/mfi/mfi_cam.c =================================================================== --- sys/dev/mfi/mfi_cam.c (revision 254079) +++ sys/dev/mfi/mfi_cam.c (working copy) @@ -79,6 +79,11 @@ static void mfip_cam_poll(struct cam_sim *); static struct mfi_command * mfip_start(void *); static void mfip_done(struct mfi_command *cm); +static int mfi_allow_disks = 0; +TUNABLE_INT("hw.mfi.allow_cam_disk_passthrough", &mfi_allow_disks); +SYSCTL_INT(_hw_mfi, OID_AUTO, allow_cam_disk_passthrough, CTLFLAG_RD, + &mfi_allow_disks, 0, "event message locale"); + static devclass_t mfip_devclass; static device_method_t mfip_methods[] = { DEVMETHOD(device_probe, mfip_probe), @@ -349,7 +354,8 @@ mfip_done(struct mfi_command *cm) command = csio->cdb_io.cdb_bytes[0]; if (command == INQUIRY) { device = csio->data_ptr[0] & 0x1f; - if ((device == T_DIRECT) || (device == T_PROCESSOR)) + if ((!mfi_allow_disks && device == T_DIRECT) || + (device == T_PROCESSOR)) csio->data_ptr[0] = (csio->data_ptr[0] & 0xe0) | T_NODEVICE; } @@ -392,6 +398,9 @@ mfip_done(struct mfi_command *cm) static void mfip_cam_poll(struct cam_sim *sim) { - return; + struct mfip_softc *sc = cam_sim_softc(sim); + struct mfi_softc *mfisc = sc->mfi_sc; + + mfisc->mfi_intr_ptr(mfisc); } Index: sys/dev/mfi/mfi_disk.c =================================================================== --- sys/dev/mfi/mfi_disk.c (revision 254079) +++ sys/dev/mfi/mfi_disk.c (working copy) @@ -93,6 +93,7 @@ mfi_disk_attach(device_t dev) { struct mfi_disk *sc; struct mfi_ld_info *ld_info; + struct mfi_disk_pending *ld_pend; uint64_t sectors; uint32_t secsize; char *state; @@ -111,6 +112,13 @@ mfi_disk_attach(device_t dev) secsize = MFI_SECTOR_LEN; mtx_lock(&sc->ld_controller->mfi_io_lock); TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); + TAILQ_FOREACH(ld_pend, &sc->ld_controller->mfi_ld_pend_tqh, + ld_link) { + TAILQ_REMOVE(&sc->ld_controller->mfi_ld_pend_tqh, + ld_pend, ld_link); + free(ld_pend, M_MFIBUF); + break; + } mtx_unlock(&sc->ld_controller->mfi_io_lock); switch (ld_info->ld_config.params.state) { @@ -131,16 +139,16 @@ mfi_disk_attach(device_t dev) break; } - if ( strlen(ld_info->ld_config.properties.name) == 0 ) { - device_printf(dev, - "%juMB (%ju sectors) RAID volume (no label) is %s\n", - sectors / (1024 * 1024 / secsize), sectors, state); - } else { - device_printf(dev, - "%juMB (%ju sectors) RAID volume '%s' is %s\n", - sectors / (1024 * 1024 / secsize), sectors, - ld_info->ld_config.properties.name, state); - } + if ( strlen(ld_info->ld_config.properties.name) == 0 ) { + device_printf(dev, + "%juMB (%ju sectors) RAID volume (no label) is %s\n", + sectors / (1024 * 1024 / secsize), sectors, state); + } else { + device_printf(dev, + "%juMB (%ju sectors) RAID volume '%s' is %s\n", + sectors / (1024 * 1024 / secsize), sectors, + ld_info->ld_config.properties.name, state); + } sc->ld_disk = disk_alloc(); sc->ld_disk->d_drv1 = sc; Index: sys/dev/mfi/mfi_syspd.c =================================================================== --- sys/dev/mfi/mfi_syspd.c (revision 254079) +++ sys/dev/mfi/mfi_syspd.c (working copy) @@ -89,7 +89,6 @@ DRIVER_MODULE(mfisyspd, mfi, mfi_syspd_driver, mfi static int mfi_syspd_probe(device_t dev) { - return (0); } @@ -98,12 +97,12 @@ mfi_syspd_attach(device_t dev) { struct mfi_system_pd *sc; struct mfi_pd_info *pd_info; + struct mfi_system_pending *syspd_pend; uint64_t sectors; uint32_t secsize; sc = device_get_softc(dev); pd_info = device_get_ivars(dev); - sc->pd_dev = dev; sc->pd_id = pd_info->ref.v.device_id; sc->pd_unit = device_get_unit(dev); @@ -115,6 +114,13 @@ mfi_syspd_attach(device_t dev) secsize = MFI_SECTOR_LEN; mtx_lock(&sc->pd_controller->mfi_io_lock); TAILQ_INSERT_TAIL(&sc->pd_controller->mfi_syspd_tqh, sc, pd_link); + TAILQ_FOREACH(syspd_pend, &sc->pd_controller->mfi_syspd_pend_tqh, + pd_link) { + TAILQ_REMOVE(&sc->pd_controller->mfi_syspd_pend_tqh, + syspd_pend, pd_link); + free(syspd_pend, M_MFIBUF); + break; + } mtx_unlock(&sc->pd_controller->mfi_io_lock); device_printf(dev, "%juMB (%ju sectors) SYSPD volume\n", sectors / (1024 * 1024 / secsize), sectors); @@ -139,6 +145,7 @@ mfi_syspd_attach(device_t dev) disk_create(sc->pd_disk, DISK_VERSION); device_printf(dev, " SYSPD volume attached\n"); + return (0); } Index: sys/dev/mfi/mfi_tbolt.c =================================================================== --- sys/dev/mfi/mfi_tbolt.c (revision 254079) +++ sys/dev/mfi/mfi_tbolt.c (working copy) @@ -69,13 +69,10 @@ uint8_t mfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd); union mfi_mpi2_request_descriptor *mfi_build_and_issue_cmd(struct mfi_softc *sc, struct mfi_command *mfi_cmd); -int mfi_tbolt_is_ldio(struct mfi_command *mfi_cmd); void mfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd, struct mfi_cmd_tbolt *cmd); static int mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command *mfi_cmd, pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd); -static int mfi_tbolt_build_cdb(struct mfi_softc *sc, struct mfi_command - *mfi_cmd, uint8_t *cdb); void map_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status, uint8_t ext_status); @@ -502,6 +499,7 @@ mfi_tbolt_alloc_cmd(struct mfi_softc *sc) + i * MEGASAS_MAX_SZ_CHAIN_FRAME); cmd->sg_frame_phys_addr = sc->sg_frame_busaddr + i * MEGASAS_MAX_SZ_CHAIN_FRAME; + cmd->sync_cmd_idx = sc->mfi_max_fw_cmds; TAILQ_INSERT_TAIL(&(sc->mfi_cmd_tbolt_tqh), cmd, next); } @@ -574,11 +572,11 @@ void map_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status, uint8_t ext_status) { - switch (status) { case MFI_STAT_OK: - mfi_cmd->cm_frame->header.cmd_status = 0; - mfi_cmd->cm_frame->dcmd.header.cmd_status = 0; + mfi_cmd->cm_frame->header.cmd_status = MFI_STAT_OK; + mfi_cmd->cm_frame->dcmd.header.cmd_status = MFI_STAT_OK; + mfi_cmd->cm_error = MFI_STAT_OK; break; case MFI_STAT_SCSI_IO_FAILED: @@ -618,6 +616,7 @@ mfi_tbolt_return_cmd(struct mfi_softc *sc, struct { mtx_assert(&sc->mfi_io_lock, MA_OWNED); + cmd->sync_cmd_idx = sc->mfi_max_fw_cmds; TAILQ_INSERT_TAIL(&sc->mfi_cmd_tbolt_tqh, cmd, next); } @@ -667,16 +666,26 @@ mfi_tbolt_complete_cmd(struct mfi_softc *sc) extStatus = cmd_mfi->cm_frame->dcmd.header.scsi_status; map_tbolt_cmd_status(cmd_mfi, status, extStatus); - /* remove command from busy queue if not polled */ - TAILQ_FOREACH(cmd_mfi_check, &sc->mfi_busy, cm_link) { - if (cmd_mfi_check == cmd_mfi) { - mfi_remove_busy(cmd_mfi); - break; + if (cmd_mfi->cm_flags & MFI_CMD_SCSI && + (cmd_mfi->cm_flags & MFI_CMD_POLLED) != 0) { + /* polled LD/SYSPD IO command */ + mfi_tbolt_return_cmd(sc, cmd_tbolt); + /* XXX mark okay for now DJA */ + cmd_mfi->cm_frame->header.cmd_status = MFI_STAT_OK; + } else { + + /* remove command from busy queue if not polled */ + TAILQ_FOREACH(cmd_mfi_check, &sc->mfi_busy, cm_link) { + if (cmd_mfi_check == cmd_mfi) { + mfi_remove_busy(cmd_mfi); + break; + } } + + /* complete the command */ + mfi_complete(sc, cmd_mfi); + mfi_tbolt_return_cmd(sc, cmd_tbolt); } - cmd_mfi->cm_error = 0; - mfi_complete(sc, cmd_mfi); - mfi_tbolt_return_cmd(sc, cmd_tbolt); sc->last_reply_idx++; if (sc->last_reply_idx >= sc->mfi_max_fw_cmds) { @@ -811,13 +820,13 @@ mfi_tbolt_build_ldio(struct mfi_softc *sc, struct MFI_FRAME_DIR_READ) io_info.isRead = 1; - io_request->RaidContext.timeoutValue - = MFI_FUSION_FP_DEFAULT_TIMEOUT; - io_request->Function = MPI2_FUNCTION_LD_IO_REQUEST; - io_request->DevHandle = device_id; - cmd->request_desc->header.RequestFlags - = (MFI_REQ_DESCRIPT_FLAGS_LD_IO - << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + io_request->RaidContext.timeoutValue + = MFI_FUSION_FP_DEFAULT_TIMEOUT; + io_request->Function = MPI2_FUNCTION_LD_IO_REQUEST; + io_request->DevHandle = device_id; + cmd->request_desc->header.RequestFlags + = (MFI_REQ_DESCRIPT_FLAGS_LD_IO + << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); if ((io_request->IoFlags == 6) && (io_info.numBlocks == 0)) io_request->RaidContext.RegLockLength = 0x100; io_request->DataLength = mfi_cmd->cm_frame->io.header.data_len @@ -825,41 +834,37 @@ mfi_tbolt_build_ldio(struct mfi_softc *sc, struct } int -mfi_tbolt_is_ldio(struct mfi_command *mfi_cmd) -{ - if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_READ - || mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) - return 1; - else - return 0; -} - -int mfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd, struct mfi_cmd_tbolt *cmd) { - uint32_t device_id; + struct mfi_mpi2_request_raid_scsi_io *io_request; uint32_t sge_count; - uint8_t cdb[32], cdb_len; + uint8_t cdb_len; + int readop; + u_int64_t lba; - memset(cdb, 0, 32); - struct mfi_mpi2_request_raid_scsi_io *io_request = cmd->io_request; + io_request = cmd->io_request; + if (!(mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_READ + || mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) + return 1; - device_id = mfi_cmd->cm_frame->header.target_id; + mfi_tbolt_build_ldio(sc, mfi_cmd, cmd); - /* Have to build CDB here for TB as BSD don't have a scsi layer */ - if ((cdb_len = mfi_tbolt_build_cdb(sc, mfi_cmd, cdb)) == 1) - return 1; + /* Convert to SCSI command CDB */ + bzero(io_request->CDB.CDB32, sizeof(io_request->CDB.CDB32)); + if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) + readop = 0; + else + readop = 1; - /* Just the CDB length,rest of the Flags are zero */ + lba = mfi_cmd->cm_frame->io.lba_hi; + lba = (lba << 32) + mfi_cmd->cm_frame->io.lba_lo; + cdb_len = mfi_build_cdb(readop, 0, lba, + mfi_cmd->cm_frame->io.header.data_len, io_request->CDB.CDB32); + + /* Just the CDB length, rest of the Flags are zero */ io_request->IoFlags = cdb_len; - memcpy(io_request->CDB.CDB32, cdb, 32); - if (mfi_tbolt_is_ldio(mfi_cmd)) - mfi_tbolt_build_ldio(sc, mfi_cmd , cmd); - else - return 1; - /* * Construct SGL */ @@ -883,85 +888,13 @@ mfi_tbolt_build_io(struct mfi_softc *sc, struct mf io_request->SenseBufferLowAddress = mfi_cmd->cm_sense_busaddr; io_request->SenseBufferLength = MFI_SENSE_LEN; + io_request->RaidContext.Status = MFI_STAT_INVALID_STATUS; + io_request->RaidContext.exStatus = MFI_STAT_INVALID_STATUS; + return 0; } -static int -mfi_tbolt_build_cdb(struct mfi_softc *sc, struct mfi_command *mfi_cmd, - uint8_t *cdb) -{ - uint32_t lba_lo, lba_hi, num_lba; - uint8_t cdb_len; - if (mfi_cmd == NULL || cdb == NULL) - return 1; - num_lba = mfi_cmd->cm_frame->io.header.data_len; - lba_lo = mfi_cmd->cm_frame->io.lba_lo; - lba_hi = mfi_cmd->cm_frame->io.lba_hi; - - if (lba_hi == 0 && (num_lba <= 0xFF) && (lba_lo <= 0x1FFFFF)) { - if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) - /* Read 6 or Write 6 */ - cdb[0] = (uint8_t) (0x0A); - else - cdb[0] = (uint8_t) (0x08); - - cdb[4] = (uint8_t) num_lba; - cdb[3] = (uint8_t) (lba_lo & 0xFF); - cdb[2] = (uint8_t) (lba_lo >> 8); - cdb[1] = (uint8_t) ((lba_lo >> 16) & 0x1F); - cdb_len = 6; - } - else if (lba_hi == 0 && (num_lba <= 0xFFFF) && (lba_lo <= 0xFFFFFFFF)) { - if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) - /* Read 10 or Write 10 */ - cdb[0] = (uint8_t) (0x2A); - else - cdb[0] = (uint8_t) (0x28); - cdb[8] = (uint8_t) (num_lba & 0xFF); - cdb[7] = (uint8_t) (num_lba >> 8); - cdb[5] = (uint8_t) (lba_lo & 0xFF); - cdb[4] = (uint8_t) (lba_lo >> 8); - cdb[3] = (uint8_t) (lba_lo >> 16); - cdb[2] = (uint8_t) (lba_lo >> 24); - cdb_len = 10; - } else if ((num_lba > 0xFFFF) && (lba_hi == 0)) { - if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) - /* Read 12 or Write 12 */ - cdb[0] = (uint8_t) (0xAA); - else - cdb[0] = (uint8_t) (0xA8); - cdb[9] = (uint8_t) (num_lba & 0xFF); - cdb[8] = (uint8_t) (num_lba >> 8); - cdb[7] = (uint8_t) (num_lba >> 16); - cdb[6] = (uint8_t) (num_lba >> 24); - cdb[5] = (uint8_t) (lba_lo & 0xFF); - cdb[4] = (uint8_t) (lba_lo >> 8); - cdb[3] = (uint8_t) (lba_lo >> 16); - cdb[2] = (uint8_t) (lba_lo >> 24); - cdb_len = 12; - } else { - if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) - cdb[0] = (uint8_t) (0x8A); - else - cdb[0] = (uint8_t) (0x88); - cdb[13] = (uint8_t) (num_lba & 0xFF); - cdb[12] = (uint8_t) (num_lba >> 8); - cdb[11] = (uint8_t) (num_lba >> 16); - cdb[10] = (uint8_t) (num_lba >> 24); - cdb[9] = (uint8_t) (lba_lo & 0xFF); - cdb[8] = (uint8_t) (lba_lo >> 8); - cdb[7] = (uint8_t) (lba_lo >> 16); - cdb[6] = (uint8_t) (lba_lo >> 24); - cdb[5] = (uint8_t) (lba_hi & 0xFF); - cdb[4] = (uint8_t) (lba_hi >> 8); - cdb[3] = (uint8_t) (lba_hi >> 16); - cdb[2] = (uint8_t) (lba_hi >> 24); - cdb_len = 16; - } - return cdb_len; -} - static int mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command *mfi_cmd, pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd) @@ -1100,8 +1033,7 @@ mfi_tbolt_send_frame(struct mfi_softc *sc, struct if ((cm->cm_flags & MFI_CMD_POLLED) == 0) { cm->cm_timestamp = time_uptime; mfi_enqueue_busy(cm); - } - else { /* still get interrupts for it */ + } else { /* still get interrupts for it */ hdr->cmd_status = MFI_STAT_INVALID_STATUS; hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; } @@ -1118,19 +1050,28 @@ mfi_tbolt_send_frame(struct mfi_softc *sc, struct } else device_printf(sc->mfi_dev, "DJA NA XXX SYSPDIO\n"); - } - else if (hdr->cmd == MFI_CMD_LD_SCSI_IO || + } else if (hdr->cmd == MFI_CMD_LD_SCSI_IO || hdr->cmd == MFI_CMD_LD_READ || hdr->cmd == MFI_CMD_LD_WRITE) { + cm->cm_flags |= MFI_CMD_SCSI; if ((req_desc = mfi_build_and_issue_cmd(sc, cm)) == NULL) { device_printf(sc->mfi_dev, "LDIO Failed \n"); return 1; } - } else - if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == NULL) { + } else if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == NULL) { device_printf(sc->mfi_dev, "Mapping from MFI to MPT " "Failed\n"); return 1; - } + } + + if (cm->cm_flags & MFI_CMD_SCSI) { + /* + * LD IO needs to be posted since it doesn't get + * acknowledged via a status update so have the + * controller reply via mfi_tbolt_complete_cmd. + */ + hdr->flags &= ~MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; + } + MFI_WRITE4(sc, MFI_ILQP, (req_desc->words & 0xFFFFFFFF)); MFI_WRITE4(sc, MFI_IHQP, (req_desc->words >>0x20)); @@ -1137,12 +1078,21 @@ mfi_tbolt_send_frame(struct mfi_softc *sc, struct if ((cm->cm_flags & MFI_CMD_POLLED) == 0) return 0; + if (cm->cm_flags & MFI_CMD_SCSI) { + /* check reply queue */ + mfi_tbolt_complete_cmd(sc); + } + /* This is a polled command, so busy-wait for it to complete. */ while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { DELAY(1000); tm -= 1; if (tm <= 0) - break; + break; + if (cm->cm_flags & MFI_CMD_SCSI) { + /* check reply queue */ + mfi_tbolt_complete_cmd(sc); + } } if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { @@ -1375,7 +1325,7 @@ mfi_tbolt_sync_map_info(struct mfi_softc *sc) free(ld_sync, M_MFIBUF); goto out; } - + context = cmd->cm_frame->header.context; bzero(cmd->cm_frame, sizeof(union mfi_frame)); cmd->cm_frame->header.context = context; Index: sys/dev/mfi/mfivar.h =================================================================== --- sys/dev/mfi/mfivar.h (revision 254079) +++ sys/dev/mfi/mfivar.h (working copy) @@ -105,6 +105,7 @@ struct mfi_command { #define MFI_ON_MFIQ_READY (1<<6) #define MFI_ON_MFIQ_BUSY (1<<7) #define MFI_ON_MFIQ_MASK ((1<<5)|(1<<6)|(1<<7)) +#define MFI_CMD_SCSI (1<<8) uint8_t retry_for_fw_reset; void (* cm_complete)(struct mfi_command *cm); void *cm_private; @@ -125,6 +126,11 @@ struct mfi_disk { #define MFI_DISK_FLAGS_DISABLED 0x02 }; +struct mfi_disk_pending { + TAILQ_ENTRY(mfi_disk_pending) ld_link; + int ld_id; +}; + struct mfi_system_pd { TAILQ_ENTRY(mfi_system_pd) pd_link; device_t pd_dev; @@ -136,6 +142,11 @@ struct mfi_system_pd { int pd_flags; }; +struct mfi_system_pending { + TAILQ_ENTRY(mfi_system_pending) pd_link; + int pd_id; +}; + struct mfi_evt_queue_elm { TAILQ_ENTRY(mfi_evt_queue_elm) link; struct mfi_evt_detail detail; @@ -284,6 +295,8 @@ struct mfi_softc { TAILQ_HEAD(,mfi_disk) mfi_ld_tqh; TAILQ_HEAD(,mfi_system_pd) mfi_syspd_tqh; + TAILQ_HEAD(,mfi_disk_pending) mfi_ld_pend_tqh; + TAILQ_HEAD(,mfi_system_pending) mfi_syspd_pend_tqh; eventhandler_tag mfi_eh; struct cdev *mfi_cdev; @@ -302,6 +315,7 @@ struct mfi_softc { uint32_t frame_cnt); int (*mfi_adp_reset)(struct mfi_softc *sc); int (*mfi_adp_check_reset)(struct mfi_softc *sc); + void (*mfi_intr_ptr)(void *sc); /* ThunderBolt */ uint32_t mfi_tbolt; @@ -420,7 +434,8 @@ extern int mfi_tbolt_reset(struct mfi_softc *sc); extern void mfi_tbolt_sync_map_info(struct mfi_softc *sc); extern void mfi_handle_map_sync(void *context, int pending); extern int mfi_dcmd_command(struct mfi_softc *, struct mfi_command **, - uint32_t, void **, size_t); + uint32_t, void **, size_t); +extern int mfi_build_cdb(int, uint8_t, u_int64_t, u_int32_t, uint8_t *); #define MFIQ_ADD(sc, qname) \ do { \