diff options
author | Martin K. Petersen <martin.petersen@oracle.com> | 2023-10-13 21:25:20 +0300 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2023-10-13 21:25:20 +0300 |
commit | 9f4c887fe64e27413509979b5be3fb2630d813ba (patch) | |
tree | 03cc7acf5c670b192709d0c987736fbc048dbe06 | |
parent | 78882c7657bb276bab028d92f99fc185b25a2fc1 (diff) | |
parent | 82b2fb52d6ecc3c902b46b3f9bb4325ab3f6d50d (diff) | |
download | linux-9f4c887fe64e27413509979b5be3fb2630d813ba.tar.xz |
Merge patch series "scsi: EH rework prep patches, part 1"
Hannes Reinecke <hare@suse.de> says:
Hi all,
(taking up an old thread:) here's the first batch of patches for my EH
rework. It modifies the reset callbacks for SCSI drivers such that
the final conversion to drop the 'struct scsi_cmnd' argument and use
the entity in question (host, bus, target, device) as the argument to
the SCSI EH callbacks becomes possible. The first part covers drivers
which just requires minor tweaks.
Link: https://lore.kernel.org/r/20231002154328.43718-1-hare@suse.de
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r-- | drivers/message/fusion/mptfc.c | 94 | ||||
-rw-r--r-- | drivers/message/fusion/mptscsih.c | 55 | ||||
-rw-r--r-- | drivers/message/fusion/mptscsih.h | 1 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aic79xx_osm.c | 32 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aic7xxx_osm.c | 127 | ||||
-rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc.h | 1 | ||||
-rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_hwi.c | 14 | ||||
-rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_io.c | 94 | ||||
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.c | 42 | ||||
-rw-r--r-- | drivers/scsi/ips.c | 18 | ||||
-rw-r--r-- | drivers/scsi/megaraid.c | 42 | ||||
-rw-r--r-- | drivers/scsi/mpi3mr/mpi3mr_os.c | 57 | ||||
-rw-r--r-- | drivers/scsi/pmcraid.c | 60 | ||||
-rw-r--r-- | drivers/scsi/qedf/qedf.h | 5 | ||||
-rw-r--r-- | drivers/scsi/qedf/qedf_io.c | 75 | ||||
-rw-r--r-- | drivers/scsi/qedf/qedf_main.c | 19 | ||||
-rw-r--r-- | drivers/scsi/qla1280.c | 42 | ||||
-rw-r--r-- | drivers/scsi/sym53c8xx_2/sym_glue.c | 189 |
18 files changed, 572 insertions, 395 deletions
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 22e7779a332b..aa6bb764df3e 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -183,73 +183,109 @@ static struct fc_function_template mptfc_transport_functions = { }; static int -mptfc_block_error_handler(struct scsi_cmnd *SCpnt, - int (*func)(struct scsi_cmnd *SCpnt), - const char *caller) +mptfc_block_error_handler(struct fc_rport *rport) { MPT_SCSI_HOST *hd; - struct scsi_device *sdev = SCpnt->device; - struct Scsi_Host *shost = sdev->host; - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); + struct Scsi_Host *shost = rport_to_shost(rport); unsigned long flags; int ready; - MPT_ADAPTER *ioc; + MPT_ADAPTER *ioc; int loops = 40; /* seconds */ - hd = shost_priv(SCpnt->device->host); + hd = shost_priv(shost); ioc = hd->ioc; spin_lock_irqsave(shost->host_lock, flags); while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY || (loops > 0 && ioc->active == 0)) { spin_unlock_irqrestore(shost->host_lock, flags); dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT - "mptfc_block_error_handler.%d: %d:%llu, port status is " - "%x, active flag %d, deferring %s recovery.\n", + "mptfc_block_error_handler.%d: %s, port status is " + "%x, active flag %d, deferring recovery.\n", ioc->name, ioc->sh->host_no, - SCpnt->device->id, SCpnt->device->lun, - ready, ioc->active, caller)); + dev_name(&rport->dev), ready, ioc->active)); msleep(1000); spin_lock_irqsave(shost->host_lock, flags); loops --; } spin_unlock_irqrestore(shost->host_lock, flags); - if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata - || ioc->active == 0) { + if (ready == DID_NO_CONNECT || ioc->active == 0) { dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT - "%s.%d: %d:%llu, failing recovery, " - "port state %x, active %d, vdevice %p.\n", caller, + "mpt_block_error_handler.%d: %s, failing recovery, " + "port state %x, active %d.\n", ioc->name, ioc->sh->host_no, - SCpnt->device->id, SCpnt->device->lun, ready, - ioc->active, SCpnt->device->hostdata)); + dev_name(&rport->dev), ready, ioc->active)); return FAILED; } - dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT - "%s.%d: %d:%llu, executing recovery.\n", caller, - ioc->name, ioc->sh->host_no, - SCpnt->device->id, SCpnt->device->lun)); - return (*func)(SCpnt); + return SUCCESS; } static int mptfc_abort(struct scsi_cmnd *SCpnt) { - return - mptfc_block_error_handler(SCpnt, mptscsih_abort, __func__); + struct Scsi_Host *shost = SCpnt->device->host; + struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device)); + MPT_SCSI_HOST __maybe_unused *hd = shost_priv(shost); + int rtn; + + rtn = mptfc_block_error_handler(rport); + if (rtn == SUCCESS) { + dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT + "%s.%d: %d:%llu, executing recovery.\n", __func__, + hd->ioc->name, shost->host_no, + SCpnt->device->id, SCpnt->device->lun)); + rtn = mptscsih_abort(SCpnt); + } + return rtn; } static int mptfc_dev_reset(struct scsi_cmnd *SCpnt) { - return - mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __func__); + struct Scsi_Host *shost = SCpnt->device->host; + struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device)); + MPT_SCSI_HOST __maybe_unused *hd = shost_priv(shost); + int rtn; + + rtn = mptfc_block_error_handler(rport); + if (rtn == SUCCESS) { + dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT + "%s.%d: %d:%llu, executing recovery.\n", __func__, + hd->ioc->name, shost->host_no, + SCpnt->device->id, SCpnt->device->lun)); + rtn = mptscsih_dev_reset(SCpnt); + } + return rtn; } static int mptfc_bus_reset(struct scsi_cmnd *SCpnt) { - return - mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __func__); + struct Scsi_Host *shost = SCpnt->device->host; + MPT_SCSI_HOST __maybe_unused *hd = shost_priv(shost); + int channel = SCpnt->device->channel; + struct mptfc_rport_info *ri; + int rtn; + + list_for_each_entry(ri, &hd->ioc->fc_rports, list) { + if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) { + VirtTarget *vtarget = ri->starget->hostdata; + + if (!vtarget || vtarget->channel != channel) + continue; + rtn = fc_block_rport(ri->rport); + if (rtn != 0) + break; + } + } + if (rtn == 0) { + dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT + "%s.%d: %d:%llu, executing recovery.\n", __func__, + hd->ioc->name, shost->host_no, + SCpnt->device->id, SCpnt->device->lun)); + rtn = mptscsih_bus_reset(SCpnt); + } + return rtn; } static void diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 2bc17087d17d..9080a73b4ea6 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1793,7 +1793,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant + * mptscsih_dev_reset - Perform a SCSI LOGICAL_UNIT_RESET! * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to * * (linux scsi_host_template.eh_dev_reset_handler routine) @@ -1811,6 +1811,58 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt) /* If we can't locate our host adapter structure, return FAILED status. */ if ((hd = shost_priv(SCpnt->device->host)) == NULL){ + printk(KERN_ERR MYNAM ": lun reset: " + "Can't locate host! (sc=%p)\n", SCpnt); + return FAILED; + } + + ioc = hd->ioc; + printk(MYIOC_s_INFO_FMT "attempting lun reset! (sc=%p)\n", + ioc->name, SCpnt); + scsi_print_command(SCpnt); + + vdevice = SCpnt->device->hostdata; + if (!vdevice || !vdevice->vtarget) { + retval = 0; + goto out; + } + + retval = mptscsih_IssueTaskMgmt(hd, + MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, + vdevice->vtarget->channel, + vdevice->vtarget->id, vdevice->lun, 0, + mptscsih_get_tm_timeout(ioc)); + + out: + printk (MYIOC_s_INFO_FMT "lun reset: %s (sc=%p)\n", + ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); + + if (retval == 0) + return SUCCESS; + else + return FAILED; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_target_reset - Perform a SCSI TARGET_RESET! + * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to + * + * (linux scsi_host_template.eh_target_reset_handler routine) + * + * Returns SUCCESS or FAILED. + **/ +int +mptscsih_target_reset(struct scsi_cmnd * SCpnt) +{ + MPT_SCSI_HOST *hd; + int retval; + VirtDevice *vdevice; + MPT_ADAPTER *ioc; + + /* If we can't locate our host adapter structure, return FAILED status. + */ + if ((hd = shost_priv(SCpnt->device->host)) == NULL){ printk(KERN_ERR MYNAM ": target reset: " "Can't locate host! (sc=%p)\n", SCpnt); return FAILED; @@ -3256,6 +3308,7 @@ EXPORT_SYMBOL(mptscsih_slave_destroy); EXPORT_SYMBOL(mptscsih_slave_configure); EXPORT_SYMBOL(mptscsih_abort); EXPORT_SYMBOL(mptscsih_dev_reset); +EXPORT_SYMBOL(mptscsih_target_reset); EXPORT_SYMBOL(mptscsih_bus_reset); EXPORT_SYMBOL(mptscsih_host_reset); EXPORT_SYMBOL(mptscsih_bios_param); diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index a22c5eaf703c..e3d92c392673 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -120,6 +120,7 @@ extern void mptscsih_slave_destroy(struct scsi_device *device); extern int mptscsih_slave_configure(struct scsi_device *device); extern int mptscsih_abort(struct scsi_cmnd * SCpnt); extern int mptscsih_dev_reset(struct scsi_cmnd * SCpnt); +extern int mptscsih_target_reset(struct scsi_cmnd * SCpnt); extern int mptscsih_bus_reset(struct scsi_cmnd * SCpnt); extern int mptscsih_host_reset(struct scsi_cmnd *SCpnt); extern int mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, sector_t capacity, int geom[]); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index f2f3405cdec5..b3075a022d99 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -536,13 +536,18 @@ ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb) struct scsi_cmnd *cmd; cmd = scb->io_ctx; - ahd_sync_sglist(ahd, scb, BUS_DMASYNC_POSTWRITE); - scsi_dma_unmap(cmd); + if (cmd) { + ahd_sync_sglist(ahd, scb, BUS_DMASYNC_POSTWRITE); + scsi_dma_unmap(cmd); + } } /******************************** Macros **************************************/ -#define BUILD_SCSIID(ahd, cmd) \ - (((scmd_id(cmd) << TID_SHIFT) & TID) | (ahd)->our_id) +static inline unsigned int ahd_build_scsiid(struct ahd_softc *ahd, + struct scsi_device *sdev) +{ + return ((sdev_id(sdev) << TID_SHIFT) & TID) | (ahd)->our_id; +} /* * Return a string describing the driver. @@ -811,14 +816,14 @@ ahd_linux_dev_reset(struct scsi_cmnd *cmd) tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, cmd->device->id, &tstate); - reset_scb->io_ctx = cmd; + reset_scb->io_ctx = NULL; reset_scb->platform_data->dev = dev; reset_scb->sg_count = 0; ahd_set_residual(reset_scb, 0); ahd_set_sense_residual(reset_scb, 0); reset_scb->platform_data->xfer_len = 0; reset_scb->hscb->control = 0; - reset_scb->hscb->scsiid = BUILD_SCSIID(ahd,cmd); + reset_scb->hscb->scsiid = ahd_build_scsiid(ahd, cmd->device); reset_scb->hscb->lun = cmd->device->lun; reset_scb->hscb->cdb_len = 0; reset_scb->hscb->task_management = SIU_TASKMGMT_LUN_RESET; @@ -1577,7 +1582,7 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, * Fill out basics of the HSCB. */ hscb->control = 0; - hscb->scsiid = BUILD_SCSIID(ahd, cmd); + hscb->scsiid = ahd_build_scsiid(ahd, cmd->device); hscb->lun = cmd->device->lun; scb->hscb->task_management = 0; mask = SCB_GET_TARGET_MASK(ahd, scb); @@ -1766,9 +1771,16 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) dev = scb->platform_data->dev; dev->active--; dev->openings++; - if ((cmd->result & (CAM_DEV_QFRZN << 16)) != 0) { - cmd->result &= ~(CAM_DEV_QFRZN << 16); - dev->qfrozen--; + if (cmd) { + if ((cmd->result & (CAM_DEV_QFRZN << 16)) != 0) { + cmd->result &= ~(CAM_DEV_QFRZN << 16); + dev->qfrozen--; + } + } else if (scb->flags & SCB_DEVICE_RESET) { + if (ahd->platform_data->eh_done) + complete(ahd->platform_data->eh_done); + ahd_free_scb(ahd, scb); + return; } ahd_linux_unmap_scb(ahd, scb); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index d3b1082654d5..4ae0a1c4d374 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -366,7 +366,8 @@ static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, struct scsi_cmnd *cmd); static void ahc_linux_freeze_simq(struct ahc_softc *ahc); static void ahc_linux_release_simq(struct ahc_softc *ahc); -static int ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); +static int ahc_linux_queue_recovery_cmd(struct scsi_device *sdev, + struct scsi_cmnd *cmd); static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo); @@ -728,7 +729,7 @@ ahc_linux_abort(struct scsi_cmnd *cmd) { int error; - error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT); + error = ahc_linux_queue_recovery_cmd(cmd->device, cmd); if (error != SUCCESS) printk("aic7xxx_abort returns 0x%x\n", error); return (error); @@ -742,7 +743,7 @@ ahc_linux_dev_reset(struct scsi_cmnd *cmd) { int error; - error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); + error = ahc_linux_queue_recovery_cmd(cmd->device, NULL); if (error != SUCCESS) printk("aic7xxx_dev_reset returns 0x%x\n", error); return (error); @@ -798,11 +799,18 @@ struct scsi_host_template aic7xxx_driver_template = { /**************************** Tasklet Handler *********************************/ -/******************************** Macros **************************************/ -#define BUILD_SCSIID(ahc, cmd) \ - ((((cmd)->device->id << TID_SHIFT) & TID) \ - | (((cmd)->device->channel == 0) ? (ahc)->our_id : (ahc)->our_id_b) \ - | (((cmd)->device->channel == 0) ? 0 : TWIN_CHNLB)) + +static inline unsigned int ahc_build_scsiid(struct ahc_softc *ahc, + struct scsi_device *sdev) +{ + unsigned int scsiid = (sdev->id << TID_SHIFT) & TID; + + if (sdev->channel == 0) + scsiid |= ahc->our_id; + else + scsiid |= ahc->our_id_b | TWIN_CHNLB; + return scsiid; +} /******************************** Bus DMA *************************************/ int @@ -1457,7 +1465,7 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev, * Fill out basics of the HSCB. */ hscb->control = 0; - hscb->scsiid = BUILD_SCSIID(ahc, cmd); + hscb->scsiid = ahc_build_scsiid(ahc, cmd->device); hscb->lun = cmd->device->lun; mask = SCB_GET_TARGET_MASK(ahc, scb); tinfo = ahc_fetch_transinfo(ahc, SCB_GET_CHANNEL(ahc, scb), @@ -2029,11 +2037,12 @@ ahc_linux_release_simq(struct ahc_softc *ahc) } static int -ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) +ahc_linux_queue_recovery_cmd(struct scsi_device *sdev, + struct scsi_cmnd *cmd) { struct ahc_softc *ahc; struct ahc_linux_device *dev; - struct scb *pending_scb; + struct scb *pending_scb = NULL, *scb; u_int saved_scbptr; u_int active_scb_index; u_int last_phase; @@ -2046,18 +2055,19 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) int disconnected; unsigned long flags; - pending_scb = NULL; paused = FALSE; wait = FALSE; - ahc = *(struct ahc_softc **)cmd->device->host->hostdata; + ahc = *(struct ahc_softc **)sdev->host->hostdata; - scmd_printk(KERN_INFO, cmd, "Attempting to queue a%s message\n", - flag == SCB_ABORT ? "n ABORT" : " TARGET RESET"); + sdev_printk(KERN_INFO, sdev, "Attempting to queue a%s message\n", + cmd ? "n ABORT" : " TARGET RESET"); - printk("CDB:"); - for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) - printk(" 0x%x", cmd->cmnd[cdb_byte]); - printk("\n"); + if (cmd) { + printk("CDB:"); + for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) + printk(" 0x%x", cmd->cmnd[cdb_byte]); + printk("\n"); + } ahc_lock(ahc, &flags); @@ -2068,7 +2078,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) * at all, and the system wanted us to just abort the * command, return success. */ - dev = scsi_transport_device_data(cmd->device); + dev = scsi_transport_device_data(sdev); if (dev == NULL) { /* @@ -2076,13 +2086,12 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) * so we must not still own the command. */ printk("%s:%d:%d:%d: Is not an active device\n", - ahc_name(ahc), cmd->device->channel, cmd->device->id, - (u8)cmd->device->lun); + ahc_name(ahc), sdev->channel, sdev->id, (u8)sdev->lun); retval = SUCCESS; goto no_cmd; } - if ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED)) == 0 + if (cmd && (dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED)) == 0 && ahc_search_untagged_queues(ahc, cmd, cmd->device->id, cmd->device->channel + 'A', (u8)cmd->device->lun, @@ -2097,25 +2106,28 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) /* * See if we can find a matching cmd in the pending list. */ - LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { - if (pending_scb->io_ctx == cmd) - break; - } - - if (pending_scb == NULL && flag == SCB_DEVICE_RESET) { - + if (cmd) { + LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) { + if (scb->io_ctx == cmd) { + pending_scb = scb; + break; + } + } + } else { /* Any SCB for this device will do for a target reset */ - LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { - if (ahc_match_scb(ahc, pending_scb, scmd_id(cmd), - scmd_channel(cmd) + 'A', + LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) { + if (ahc_match_scb(ahc, scb, sdev->id, + sdev->channel + 'A', CAM_LUN_WILDCARD, - SCB_LIST_NULL, ROLE_INITIATOR)) + SCB_LIST_NULL, ROLE_INITIATOR)) { + pending_scb = scb; break; + } } } if (pending_scb == NULL) { - scmd_printk(KERN_INFO, cmd, "Command not found\n"); + sdev_printk(KERN_INFO, sdev, "Command not found\n"); goto no_cmd; } @@ -2146,22 +2158,22 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) ahc_dump_card_state(ahc); disconnected = TRUE; - if (flag == SCB_ABORT) { - if (ahc_search_qinfifo(ahc, cmd->device->id, - cmd->device->channel + 'A', - cmd->device->lun, + if (cmd) { + if (ahc_search_qinfifo(ahc, sdev->id, + sdev->channel + 'A', + sdev->lun, pending_scb->hscb->tag, ROLE_INITIATOR, CAM_REQ_ABORTED, SEARCH_COMPLETE) > 0) { printk("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", - ahc_name(ahc), cmd->device->channel, - cmd->device->id, (u8)cmd->device->lun); + ahc_name(ahc), sdev->channel, + sdev->id, (u8)sdev->lun); retval = SUCCESS; goto done; } - } else if (ahc_search_qinfifo(ahc, cmd->device->id, - cmd->device->channel + 'A', - cmd->device->lun, + } else if (ahc_search_qinfifo(ahc, sdev->id, + sdev->channel + 'A', + sdev->lun, pending_scb->hscb->tag, ROLE_INITIATOR, /*status*/0, SEARCH_COUNT) > 0) { @@ -2174,7 +2186,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) bus_scb = ahc_lookup_scb(ahc, ahc_inb(ahc, SCB_TAG)); if (bus_scb == pending_scb) disconnected = FALSE; - else if (flag != SCB_ABORT + else if (!cmd && ahc_inb(ahc, SAVED_SCSIID) == pending_scb->hscb->scsiid && ahc_inb(ahc, SAVED_LUN) == SCB_GET_LUN(pending_scb)) disconnected = FALSE; @@ -2194,18 +2206,18 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) saved_scsiid = ahc_inb(ahc, SAVED_SCSIID); if (last_phase != P_BUSFREE && (pending_scb->hscb->tag == active_scb_index - || (flag == SCB_DEVICE_RESET - && SCSIID_TARGET(ahc, saved_scsiid) == scmd_id(cmd)))) { + || (!cmd && SCSIID_TARGET(ahc, saved_scsiid) == sdev->id))) { /* * We're active on the bus, so assert ATN * and hope that the target responds. */ pending_scb = ahc_lookup_scb(ahc, active_scb_index); - pending_scb->flags |= SCB_RECOVERY_SCB|flag; + pending_scb->flags |= SCB_RECOVERY_SCB; + pending_scb->flags |= cmd ? SCB_ABORT : SCB_DEVICE_RESET; ahc_outb(ahc, MSG_OUT, HOST_MSG); ahc_outb(ahc, SCSISIGO, last_phase|ATNO); - scmd_printk(KERN_INFO, cmd, "Device is active, asserting ATN\n"); + sdev_printk(KERN_INFO, sdev, "Device is active, asserting ATN\n"); wait = TRUE; } else if (disconnected) { @@ -2226,7 +2238,8 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) * an unsolicited reselection occurred. */ pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED; - pending_scb->flags |= SCB_RECOVERY_SCB|flag; + pending_scb->flags |= SCB_RECOVERY_SCB; + pending_scb->flags |= cmd ? SCB_ABORT : SCB_DEVICE_RESET; /* * Remove any cached copy of this SCB in the @@ -2235,9 +2248,9 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) * same element in the SCB, SCB_NEXT, for * both the qinfifo and the disconnected list. */ - ahc_search_disc_list(ahc, cmd->device->id, - cmd->device->channel + 'A', - cmd->device->lun, pending_scb->hscb->tag, + ahc_search_disc_list(ahc, sdev->id, + sdev->channel + 'A', + sdev->lun, pending_scb->hscb->tag, /*stop_on_first*/TRUE, /*remove*/TRUE, /*save_state*/FALSE); @@ -2260,9 +2273,9 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) * so we are the next SCB for this target * to run. */ - ahc_search_qinfifo(ahc, cmd->device->id, - cmd->device->channel + 'A', - cmd->device->lun, SCB_LIST_NULL, + ahc_search_qinfifo(ahc, sdev->id, + sdev->channel + 'A', + (u8)sdev->lun, SCB_LIST_NULL, ROLE_INITIATOR, CAM_REQUEUE_REQ, SEARCH_COMPLETE); ahc_qinfifo_requeue_tail(ahc, pending_scb); @@ -2271,7 +2284,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) printk("Device is disconnected, re-queuing SCB\n"); wait = TRUE; } else { - scmd_printk(KERN_INFO, cmd, "Unable to deliver message\n"); + sdev_printk(KERN_INFO, sdev, "Unable to deliver message\n"); retval = FAILED; goto done; } diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 046247420cfa..7e74f77da14f 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -384,6 +384,7 @@ struct bnx2fc_rport { }; struct bnx2fc_mp_req { + u64 tm_lun; u8 tm_flags; u32 req_len; diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 776544385598..090d436bcef8 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -1709,7 +1709,8 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req, struct fcoe_cached_sge_ctx *cached_sge; struct fcoe_ext_mul_sges_ctx *sgl; int dev_type = tgt->dev_type; - u64 *fcp_cmnd; + struct fcp_cmnd *fcp_cmnd; + u64 *raw_fcp_cmnd; u64 tmp_fcp_cmnd[4]; u32 context_id; int cnt, i; @@ -1778,16 +1779,19 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req, task->txwr_rxrd.union_ctx.tx_seq.ctx.seq_cnt = 1; /* Fill FCP_CMND IU */ - fcp_cmnd = (u64 *) + fcp_cmnd = (struct fcp_cmnd *)&tmp_fcp_cmnd; + bnx2fc_build_fcp_cmnd(io_req, fcp_cmnd); + int_to_scsilun(sc_cmd->device->lun, &fcp_cmnd->fc_lun); + memcpy(fcp_cmnd->fc_cdb, sc_cmd->cmnd, sc_cmd->cmd_len); + raw_fcp_cmnd = (u64 *) task->txwr_rxrd.union_ctx.fcp_cmd.opaque; - bnx2fc_build_fcp_cmnd(io_req, (struct fcp_cmnd *)&tmp_fcp_cmnd); /* swap fcp_cmnd */ cnt = sizeof(struct fcp_cmnd) / sizeof(u64); for (i = 0; i < cnt; i++) { - *fcp_cmnd = cpu_to_be64(tmp_fcp_cmnd[i]); - fcp_cmnd++; + *raw_fcp_cmnd = cpu_to_be64(tmp_fcp_cmnd[i]); + raw_fcp_cmnd++; } /* Rx Write Tx Read */ diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index b42a9accb832..33057908f147 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -656,10 +656,9 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req) return SUCCESS; } -static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) +static int bnx2fc_initiate_tmf(struct fc_lport *lport, struct fc_rport *rport, + u64 tm_lun, u8 tm_flags) { - struct fc_lport *lport; - struct fc_rport *rport; struct fc_rport_libfc_priv *rp; struct fcoe_port *port; struct bnx2fc_interface *interface; @@ -668,7 +667,6 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) struct bnx2fc_mp_req *tm_req; struct fcoe_task_ctx_entry *task; struct fcoe_task_ctx_entry *task_page; - struct Scsi_Host *host = sc_cmd->device->host; struct fc_frame_header *fc_hdr; struct fcp_cmnd *fcp_cmnd; int task_idx, index; @@ -677,8 +675,6 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) u32 sid, did; unsigned long start = jiffies; - lport = shost_priv(host); - rport = starget_to_rport(scsi_target(sc_cmd->device)); port = lport_priv(lport); interface = port->priv; @@ -689,7 +685,7 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) } rp = rport->dd_data; - rc = fc_block_scsi_eh(sc_cmd); + rc = fc_block_rport(rport); if (rc) return rc; @@ -718,7 +714,7 @@ retry_tmf: goto retry_tmf; } /* Initialize rest of io_req fields */ - io_req->sc_cmd = sc_cmd; + io_req->sc_cmd = NULL; io_req->port = port; io_req->tgt = tgt; @@ -736,11 +732,13 @@ retry_tmf: /* Set TM flags */ io_req->io_req_flags = 0; tm_req->tm_flags = tm_flags; + tm_req->tm_lun = tm_lun; /* Fill FCP_CMND */ bnx2fc_build_fcp_cmnd(io_req, (struct fcp_cmnd *)tm_req->req_buf); fcp_cmnd = (struct fcp_cmnd *)tm_req->req_buf; - memset(fcp_cmnd->fc_cdb, 0, sc_cmd->cmd_len); + int_to_scsilun(tm_lun, &fcp_cmnd->fc_lun); + memset(fcp_cmnd->fc_cdb, 0, BNX2FC_MAX_CMD_LEN); fcp_cmnd->fc_dl = 0; /* Fill FC header */ @@ -763,8 +761,6 @@ retry_tmf: task = &(task_page[index]); bnx2fc_init_mp_task(io_req, task); - bnx2fc_priv(sc_cmd)->io_req = io_req; - /* Obtain free SQ entry */ spin_lock_bh(&tgt->tgt_lock); bnx2fc_add_2_sq(tgt, xid); @@ -1062,7 +1058,10 @@ cleanup_err: */ int bnx2fc_eh_target_reset(struct scsi_cmnd *sc_cmd) { - return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_TGT_RESET); + struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); + struct fc_lport *lport = shost_priv(rport_to_shost(rport)); + + return bnx2fc_initiate_tmf(lport, rport, 0, FCP_TMF_TGT_RESET); } /** @@ -1075,7 +1074,11 @@ int bnx2fc_eh_target_reset(struct scsi_cmnd *sc_cmd) */ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd) { - return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); + struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); + struct fc_lport *lport = shost_priv(rport_to_shost(rport)); + + return bnx2fc_initiate_tmf(lport, rport, sc_cmd->device->lun, + FCP_TMF_LUN_RESET); } static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req) @@ -1450,10 +1453,9 @@ io_compl: static void bnx2fc_lun_reset_cmpl(struct bnx2fc_cmd *io_req) { - struct scsi_cmnd *sc_cmd = io_req->sc_cmd; struct bnx2fc_rport *tgt = io_req->tgt; struct bnx2fc_cmd *cmd, *tmp; - u64 tm_lun = sc_cmd->device->lun; + struct bnx2fc_mp_req *tm_req = &io_req->mp_req; u64 lun; int rc = 0; @@ -1465,8 +1467,10 @@ static void bnx2fc_lun_reset_cmpl(struct bnx2fc_cmd *io_req) */ list_for_each_entry_safe(cmd, tmp, &tgt->active_cmd_queue, link) { BNX2FC_TGT_DBG(tgt, "LUN RST cmpl: scan for pending IOs\n"); + if (!cmd->sc_cmd) + continue; lun = cmd->sc_cmd->device->lun; - if (lun == tm_lun) { + if (lun == tm_req->tm_lun) { /* Initiate ABTS on this cmd */ if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &cmd->req_flags)) { @@ -1570,31 +1574,36 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req, printk(KERN_ERR PFX "tmf's fc_hdr r_ctl = 0x%x\n", fc_hdr->fh_r_ctl); } - if (!bnx2fc_priv(sc_cmd)->io_req) { - printk(KERN_ERR PFX "tm_compl: io_req is NULL\n"); - return; - } - switch (io_req->fcp_status) { - case FC_GOOD: - if (io_req->cdb_status == 0) { - /* Good IO completion */ - sc_cmd->result = DID_OK << 16; - } else { - /* Transport status is good, SCSI status not good */ - sc_cmd->result = (DID_OK << 16) | io_req->cdb_status; + if (sc_cmd) { + if (!bnx2fc_priv(sc_cmd)->io_req) { + printk(KERN_ERR PFX "tm_compl: io_req is NULL\n"); + return; + } + switch (io_req->fcp_status) { + case FC_GOOD: + if (io_req->cdb_status == 0) { + /* Good IO completion */ + sc_cmd->result = DID_OK << 16; + } else { + /* Transport status is good, SCSI status not good */ + sc_cmd->result = (DID_OK << 16) | io_req->cdb_status; + } + if (io_req->fcp_resid) + scsi_set_resid(sc_cmd, io_req->fcp_resid); + break; + + default: + BNX2FC_IO_DBG(io_req, "process_tm_compl: fcp_status = %d\n", + io_req->fcp_status); + break; } - if (io_req->fcp_resid) - scsi_set_resid(sc_cmd, io_req->fcp_resid); - break; - default: - BNX2FC_IO_DBG(io_req, "process_tm_compl: fcp_status = %d\n", - io_req->fcp_status); - break; - } + sc_cmd = io_req->sc_cmd; + io_req->sc_cmd = NULL; - sc_cmd = io_req->sc_cmd; - io_req->sc_cmd = NULL; + bnx2fc_priv(sc_cmd)->io_req = NULL; + scsi_done(sc_cmd); + } /* check if the io_req exists in tgt's tmf_q */ if (io_req->on_tmf_queue) { @@ -1607,9 +1616,6 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req, return; } - bnx2fc_priv(sc_cmd)->io_req = NULL; - scsi_done(sc_cmd); - kref_put(&io_req->refcount, bnx2fc_cmd_release); if (io_req->wait_for_abts_comp) { BNX2FC_IO_DBG(io_req, "tm_compl - wake up the waiter\n"); @@ -1738,15 +1744,9 @@ static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req) void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req, struct fcp_cmnd *fcp_cmnd) { - struct scsi_cmnd *sc_cmd = io_req->sc_cmd; - memset(fcp_cmnd, 0, sizeof(struct fcp_cmnd)); - int_to_scsilun(sc_cmd->device->lun, &fcp_cmnd->fc_lun); - fcp_cmnd->fc_dl = htonl(io_req->data_xfer_len); - memcpy(fcp_cmnd->fc_cdb, sc_cmd->cmnd, sc_cmd->cmd_len); - fcp_cmnd->fc_cmdref = 0; fcp_cmnd->fc_pri_ta = 0; fcp_cmnd->fc_tm_flags = io_req->mp_req.tm_flags; diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 122b79db79e3..92c440f2e3a7 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -2996,18 +2996,6 @@ static void ibmvfc_dev_cancel_all_noreset(struct scsi_device *sdev, void *data) } /** - * ibmvfc_dev_cancel_all_reset - Device iterated cancel all function - * @sdev: scsi device struct - * @data: return code - * - **/ -static void ibmvfc_dev_cancel_all_reset(struct scsi_device *sdev, void *data) -{ - unsigned long *rc = data; - *rc |= ibmvfc_cancel_all(sdev, IBMVFC_TMF_TGT_RESET); -} - -/** * ibmvfc_eh_target_reset_handler - Reset the target * @cmd: scsi command struct * @@ -3016,22 +3004,38 @@ static void ibmvfc_dev_cancel_all_reset(struct scsi_device *sdev, void *data) **/ static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd) { - struct scsi_device *sdev = cmd->device; - struct ibmvfc_host *vhost = shost_priv(sdev->host); - struct scsi_target *starget = scsi_target(sdev); + struct scsi_target *starget = scsi_target(cmd->device); + struct fc_rport *rport = starget_to_rport(starget); + struct Scsi_Host *shost = rport_to_shost(rport); + struct ibmvfc_host *vhost = shost_priv(shost); int block_rc; int reset_rc = 0; int rc = FAILED; unsigned long cancel_rc = 0; + bool tgt_reset = false; ENTER; - block_rc = fc_block_scsi_eh(cmd); + block_rc = fc_block_rport(rport); ibmvfc_wait_while_resetting(vhost); if (block_rc != FAST_IO_FAIL) { - starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all_reset); - reset_rc = ibmvfc_reset_device(sdev, IBMVFC_TARGET_RESET, "target"); + struct scsi_device *sdev; + + shost_for_each_device(sdev, shost) { + if ((sdev->channel != starget->channel) || + (sdev->id != starget->id)) + continue; + + cancel_rc |= ibmvfc_cancel_all(sdev, + IBMVFC_TMF_TGT_RESET); + if (!tgt_reset) { + reset_rc = ibmvfc_reset_device(sdev, + IBMVFC_TARGET_RESET, "target"); + tgt_reset = true; + } + } } else - starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all_noreset); + starget_for_each_device(starget, &cancel_rc, + ibmvfc_dev_cancel_all_noreset); if (!cancel_rc && !reset_rc) rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target); diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index bb206509265e..10cf5775a939 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -835,7 +835,6 @@ static int __ips_eh_reset(struct scsi_cmnd *SC) int i; ips_ha_t *ha; ips_scb_t *scb; - ips_copp_wait_item_t *item; METHOD_TRACE("ips_eh_reset", 1); @@ -860,23 +859,6 @@ static int __ips_eh_reset(struct scsi_cmnd *SC) if (!ha->active) return (FAILED); - /* See if the command is on the copp queue */ - item = ha->copp_waitlist.head; - while ((item) && (item->scsi_cmd != SC)) - item = item->next; - - if (item) { - /* Found it */ - ips_removeq_copp(&ha->copp_waitlist, item); - return (SUCCESS); - } - - /* See if the command is on the wait queue */ - if (ips_removeq_wait(&ha->scb_waitlist, SC)) { - /* command not sent yet */ - return (SUCCESS); - } - /* An explanation for the casual observer: */ /* Part of the function of a RAID controller is automatic error */ /* detection and recovery. As such, the only problem that physically */ diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index e92f1a73cc9b..329c3da88416 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -1898,7 +1898,7 @@ megaraid_reset(struct scsi_cmnd *cmd) spin_lock_irq(&adapter->lock); - rval = megaraid_abort_and_reset(adapter, cmd, SCB_RESET); + rval = megaraid_abort_and_reset(adapter, NULL, SCB_RESET); /* * This is required here to complete any completed requests @@ -1937,7 +1937,7 @@ megaraid_abort_and_reset(adapter_t *adapter, struct scsi_cmnd *cmd, int aor) scb = list_entry(pos, scb_t, list); - if (scb->cmd == cmd) { /* Found command */ + if (!cmd || scb->cmd == cmd) { /* Found command */ scb->state |= aor; @@ -1956,31 +1956,23 @@ megaraid_abort_and_reset(adapter_t *adapter, struct scsi_cmnd *cmd, int aor) return FAILED; } - else { - - /* - * Not yet issued! Remove from the pending - * list - */ - dev_warn(&adapter->dev->dev, - "%s-[%x], driver owner\n", - (aor==SCB_ABORT) ? "ABORTING":"RESET", - scb->idx); - - mega_free_scb(adapter, scb); - - if( aor == SCB_ABORT ) { - cmd->result = (DID_ABORT << 16); - } - else { - cmd->result = (DID_RESET << 16); - } + /* + * Not yet issued! Remove from the pending + * list + */ + dev_warn(&adapter->dev->dev, + "%s-[%x], driver owner\n", + (cmd) ? "ABORTING":"RESET", + scb->idx); + mega_free_scb(adapter, scb); + if (cmd) { + cmd->result = (DID_ABORT << 16); list_add_tail(SCSI_LIST(cmd), - &adapter->completed_list); - - return SUCCESS; + &adapter->completed_list); } + + return SUCCESS; } } @@ -4114,8 +4106,6 @@ static const struct scsi_host_template megaraid_template = { .sg_tablesize = MAX_SGLIST, .cmd_per_lun = DEF_CMD_PER_LUN, .eh_abort_handler = megaraid_abort, - .eh_device_reset_handler = megaraid_reset, - .eh_bus_reset_handler = megaraid_reset, .eh_host_reset_handler = megaraid_reset, .no_write_same = 1, .cmd_size = sizeof(struct megaraid_cmd_priv), diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 89ba015c5d7e..040031eb0c12 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -4012,20 +4012,45 @@ static inline void mpi3mr_setup_divert_ws(struct mpi3mr_ioc *mrioc, * mpi3mr_eh_host_reset - Host reset error handling callback * @scmd: SCSI command reference * - * Issue controller reset if the scmd is for a Physical Device, - * if the scmd is for RAID volume, then wait for - * MPI3MR_RAID_ERRREC_RESET_TIMEOUT and checke whether any - * pending I/Os prior to issuing reset to the controller. + * Issue controller reset * * Return: SUCCESS of successful reset else FAILED */ static int mpi3mr_eh_host_reset(struct scsi_cmnd *scmd) { struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host); + int retval = FAILED, ret; + + ret = mpi3mr_soft_reset_handler(mrioc, + MPI3MR_RESET_FROM_EH_HOS, 1); + if (ret) + goto out; + + retval = SUCCESS; +out: + sdev_printk(KERN_INFO, scmd->device, + "Host reset is %s for scmd(%p)\n", + ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + + return retval; +} + +/** + * mpi3mr_eh_bus_reset - Bus reset error handling callback + * @scmd: SCSI command reference + * + * Checks whether pending I/Os are present for the RAID volume; + * if not there's no need to reset the adapter. + * + * Return: SUCCESS of successful reset else FAILED + */ +static int mpi3mr_eh_bus_reset(struct scsi_cmnd *scmd) +{ + struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host); struct mpi3mr_stgt_priv_data *stgt_priv_data; struct mpi3mr_sdev_priv_data *sdev_priv_data; u8 dev_type = MPI3_DEVICE_DEVFORM_VD; - int retval = FAILED, ret; + int retval = FAILED; sdev_priv_data = scmd->device->hostdata; if (sdev_priv_data && sdev_priv_data->tgt_priv_data) { @@ -4035,25 +4060,16 @@ static int mpi3mr_eh_host_reset(struct scsi_cmnd *scmd) if (dev_type == MPI3_DEVICE_DEVFORM_VD) { mpi3mr_wait_for_host_io(mrioc, - MPI3MR_RAID_ERRREC_RESET_TIMEOUT); - if (!mpi3mr_get_fw_pending_ios(mrioc)) { + MPI3MR_RAID_ERRREC_RESET_TIMEOUT); + if (!mpi3mr_get_fw_pending_ios(mrioc)) retval = SUCCESS; - goto out; - } } + if (retval == FAILED) + mpi3mr_print_pending_host_io(mrioc); - mpi3mr_print_pending_host_io(mrioc); - ret = mpi3mr_soft_reset_handler(mrioc, - MPI3MR_RESET_FROM_EH_HOS, 1); - if (ret) - goto out; - - retval = SUCCESS; -out: sdev_printk(KERN_INFO, scmd->device, - "Host reset is %s for scmd(%p)\n", - ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); - + "Bus reset is %s for scmd(%p)\n", + ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); return retval; } @@ -4900,6 +4916,7 @@ static const struct scsi_host_template mpi3mr_driver_template = { .change_queue_depth = mpi3mr_change_queue_depth, .eh_device_reset_handler = mpi3mr_eh_dev_reset, .eh_target_reset_handler = mpi3mr_eh_target_reset, + .eh_bus_reset_handler = mpi3mr_eh_bus_reset, .eh_host_reset_handler = mpi3mr_eh_host_reset, .bios_param = mpi3mr_bios_param, .map_queues = mpi3mr_map_queues, diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 50dc30051f22..a831b34c08a4 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -2691,7 +2691,7 @@ static int pmcraid_error_handler(struct pmcraid_cmd *cmd) * SUCCESS / FAILED */ static int pmcraid_reset_device( - struct scsi_cmnd *scsi_cmd, + struct scsi_device *scsi_dev, unsigned long timeout, u8 modifier) { @@ -2703,11 +2703,11 @@ static int pmcraid_reset_device( u32 ioasc; pinstance = - (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; - res = scsi_cmd->device->hostdata; + (struct pmcraid_instance *)scsi_dev->host->hostdata; + res = scsi_dev->hostdata; if (!res) { - sdev_printk(KERN_ERR, scsi_cmd->device, + sdev_printk(KERN_ERR, scsi_dev, "reset_device: NULL resource pointer\n"); return FAILED; } @@ -3018,25 +3018,67 @@ static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd) { scmd_printk(KERN_INFO, scmd, "resetting device due to an I/O command timeout.\n"); - return pmcraid_reset_device(scmd, + return pmcraid_reset_device(scmd->device, PMCRAID_INTERNAL_TIMEOUT, RESET_DEVICE_LUN); } static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd) { - scmd_printk(KERN_INFO, scmd, + struct Scsi_Host *host = scmd->device->host; + struct pmcraid_instance *pinstance = + (struct pmcraid_instance *)host->hostdata; + struct pmcraid_resource_entry *res = NULL; + struct pmcraid_resource_entry *temp; + struct scsi_device *sdev = NULL; + unsigned long lock_flags; + + /* + * The reset device code insists on us passing down + * a device, so grab the first device on the bus. + */ + spin_lock_irqsave(&pinstance->resource_lock, lock_flags); + list_for_each_entry(temp, &pinstance->used_res_q, queue) { + if (scmd->device->channel == PMCRAID_VSET_BUS_ID && + RES_IS_VSET(temp->cfg_entry)) { + res = temp; + break; + } else if (scmd->device->channel == PMCRAID_PHYS_BUS_ID && + RES_IS_GSCSI(temp->cfg_entry)) { + res = temp; + break; + } + } + if (res) + sdev = res->scsi_dev; + spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); + if (!sdev) + return FAILED; + + sdev_printk(KERN_INFO, sdev, "Doing bus reset due to an I/O command timeout.\n"); - return pmcraid_reset_device(scmd, + return pmcraid_reset_device(sdev, PMCRAID_RESET_BUS_TIMEOUT, RESET_DEVICE_BUS); } static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd) { - scmd_printk(KERN_INFO, scmd, + struct Scsi_Host *shost = scmd->device->host; + struct scsi_device *scsi_dev = NULL, *tmp; + + shost_for_each_device(tmp, shost) { + if ((tmp->channel == scmd->device->channel) && + (tmp->id == scmd->device->id)) { + scsi_dev = tmp; + break; + } + } + if (!scsi_dev) + return FAILED; + sdev_printk(KERN_INFO, scsi_dev, "Doing target reset due to an I/O command timeout.\n"); - return pmcraid_reset_device(scmd, + return pmcraid_reset_device(scsi_dev, PMCRAID_INTERNAL_TIMEOUT, RESET_DEVICE_TARGET); } diff --git a/drivers/scsi/qedf/qedf.h b/drivers/scsi/qedf/qedf.h index 1619cc33034f..5058e01b65a2 100644 --- a/drivers/scsi/qedf/qedf.h +++ b/drivers/scsi/qedf/qedf.h @@ -112,6 +112,7 @@ struct qedf_ioreq { #define QEDF_CMD_ERR_SCSI_DONE 0x5 u8 io_req_flags; uint8_t tm_flags; + u64 tm_lun; struct qedf_rport *fcport; #define QEDF_CMD_ST_INACTIVE 0 #define QEDFC_CMD_ST_IO_ACTIVE 1 @@ -497,7 +498,7 @@ extern void qedf_process_warning_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, struct qedf_ioreq *io_req); extern void qedf_process_error_detect(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, struct qedf_ioreq *io_req); -extern void qedf_flush_active_ios(struct qedf_rport *fcport, int lun); +extern void qedf_flush_active_ios(struct qedf_rport *fcport, u64 lun); extern void qedf_release_cmd(struct kref *ref); extern int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts); @@ -522,7 +523,7 @@ extern int qedf_initiate_cleanup(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts); extern void qedf_process_cleanup_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, struct qedf_ioreq *io_req); -extern int qedf_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags); +extern int qedf_initiate_tmf(struct fc_rport *rport, u64 lun, u8 tm_flags); extern void qedf_process_tmf_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, struct qedf_ioreq *io_req); extern void qedf_process_cqe(struct qedf_ctx *qedf, struct fcoe_cqe *cqe); diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index 10fe3383855c..bf921caaf6ae 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -546,7 +546,7 @@ static int qedf_build_bd_list_from_sg(struct qedf_ioreq *io_req) } static void qedf_build_fcp_cmnd(struct qedf_ioreq *io_req, - struct fcp_cmnd *fcp_cmnd) + struct fcp_cmnd *fcp_cmnd) { struct scsi_cmnd *sc_cmd = io_req->sc_cmd; @@ -554,8 +554,12 @@ static void qedf_build_fcp_cmnd(struct qedf_ioreq *io_req, memset(fcp_cmnd, 0, FCP_CMND_LEN); /* 8 bytes: SCSI LUN info */ - int_to_scsilun(sc_cmd->device->lun, - (struct scsi_lun *)&fcp_cmnd->fc_lun); + if (io_req->cmd_type == QEDF_TASK_MGMT_CMD) + int_to_scsilun(io_req->tm_lun, + (struct scsi_lun *)&fcp_cmnd->fc_lun); + else + int_to_scsilun(sc_cmd->device->lun, + (struct scsi_lun *)&fcp_cmnd->fc_lun); /* 4 bytes: flag info */ fcp_cmnd->fc_pri_ta = 0; @@ -1095,7 +1099,7 @@ static void qedf_parse_fcp_rsp(struct qedf_ioreq *io_req, } /* The sense buffer can be NULL for TMF commands */ - if (sc_cmd->sense_buffer) { + if (sc_cmd && sc_cmd->sense_buffer) { memset(sc_cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); if (fcp_sns_len) memcpy(sc_cmd->sense_buffer, sense_data, @@ -1580,7 +1584,7 @@ static void qedf_flush_els_req(struct qedf_ctx *qedf, /* A value of -1 for lun is a wild card that means flush all * active SCSI I/Os for the target. */ -void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) +void qedf_flush_active_ios(struct qedf_rport *fcport, u64 lun) { struct qedf_ioreq *io_req; struct qedf_ctx *qedf; @@ -1768,10 +1772,6 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) kref_put(&io_req->refcount, qedf_release_cmd); continue; } - if (lun > -1) { - if (io_req->lun != lun) - continue; - } /* * Use kref_get_unless_zero in the unlikely case the command @@ -2287,7 +2287,7 @@ void qedf_process_cleanup_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, complete(&io_req->cleanup_done); } -static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, +static int qedf_execute_tmf(struct qedf_rport *fcport, u64 tm_lun, uint8_t tm_flags) { struct qedf_ioreq *io_req; @@ -2297,17 +2297,10 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, int rc = 0; uint16_t xid; int tmo = 0; - int lun = 0; unsigned long flags; struct fcoe_wqe *sqe; u16 sqe_idx; - if (!sc_cmd) { - QEDF_ERR(&qedf->dbg_ctx, "sc_cmd is NULL\n"); - return FAILED; - } - - lun = (int)sc_cmd->device->lun; if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { QEDF_ERR(&(qedf->dbg_ctx), "fcport not offloaded\n"); rc = FAILED; @@ -2327,7 +2320,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, qedf->target_resets++; /* Initialize rest of io_req fields */ - io_req->sc_cmd = sc_cmd; + io_req->sc_cmd = NULL; io_req->fcport = fcport; io_req->cmd_type = QEDF_TASK_MGMT_CMD; @@ -2341,6 +2334,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, /* Default is to return a SCSI command when an error occurs */ io_req->return_scsi_cmd_on_abts = false; + io_req->tm_lun = tm_lun; /* Obtain exchange id */ xid = io_req->xid; @@ -2395,7 +2389,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, if (tm_flags == FCP_TMF_LUN_RESET) - qedf_flush_active_ios(fcport, lun); + qedf_flush_active_ios(fcport, tm_lun); else qedf_flush_active_ios(fcport, -1); @@ -2410,23 +2404,18 @@ no_flush: return rc; } -int qedf_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) +int qedf_initiate_tmf(struct fc_rport *rport, u64 lun, u8 tm_flags) { - struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); struct fc_rport_libfc_priv *rp = rport->dd_data; struct qedf_rport *fcport = (struct qedf_rport *)&rp[1]; - struct qedf_ctx *qedf; - struct fc_lport *lport = shost_priv(sc_cmd->device->host); + struct qedf_ctx *qedf = fcport->qedf; + struct fc_lport *lport = rp->local_port; int rc = SUCCESS; - int rval; - struct qedf_ioreq *io_req = NULL; - int ref_cnt = 0; struct fc_rport_priv *rdata = fcport->rdata; QEDF_ERR(NULL, - "tm_flags 0x%x sc_cmd %p op = 0x%02x target_id = 0x%x lun=%d\n", - tm_flags, sc_cmd, sc_cmd->cmd_len ? sc_cmd->cmnd[0] : 0xff, - rport->scsi_target_id, (int)sc_cmd->device->lun); + "tm_flags 0x%x target_id = 0x%x lun=%llu\n", + tm_flags, rport->scsi_target_id, lun); if (!rdata || !kref_get_unless_zero(&rdata->kref)) { QEDF_ERR(NULL, "stale rport\n"); @@ -2437,33 +2426,10 @@ int qedf_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) (tm_flags == FCP_TMF_TGT_RESET) ? "TARGET RESET" : "LUN RESET"); - if (qedf_priv(sc_cmd)->io_req) { - io_req = qedf_priv(sc_cmd)->io_req; - ref_cnt = kref_read(&io_req->refcount); - QEDF_ERR(NULL, - "orig io_req = %p xid = 0x%x ref_cnt = %d.\n", - io_req, io_req->xid, ref_cnt); - } - - rval = fc_remote_port_chkready(rport); - if (rval) { - QEDF_ERR(NULL, "device_reset rport not ready\n"); - rc = FAILED; - goto tmf_err; - } - - rc = fc_block_scsi_eh(sc_cmd); + rc = fc_block_rport(rport); if (rc) goto tmf_err; - if (!fcport) { - QEDF_ERR(NULL, "device_reset: rport is NULL\n"); - rc = FAILED; - goto tmf_err; - } - - qedf = fcport->qedf; - if (!qedf) { QEDF_ERR(NULL, "qedf is NULL.\n"); rc = FAILED; @@ -2500,7 +2466,7 @@ int qedf_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) goto tmf_err; } - rc = qedf_execute_tmf(fcport, sc_cmd, tm_flags); + rc = qedf_execute_tmf(fcport, lun, tm_flags); tmf_err: kref_put(&rdata->kref, fc_rport_destroy); @@ -2517,7 +2483,6 @@ void qedf_process_tmf_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, fcp_rsp = &cqe->cqe_info.rsp_info; qedf_parse_fcp_rsp(io_req, fcp_rsp); - io_req->sc_cmd = NULL; complete(&io_req->tm_done); } diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 91f3f1d7098e..a58353b7b4e8 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -774,7 +774,7 @@ static int qedf_eh_abort(struct scsi_cmnd *sc_cmd) goto drop_rdata_kref; } - rc = fc_block_scsi_eh(sc_cmd); + rc = fc_block_rport(rport); if (rc) goto drop_rdata_kref; @@ -858,18 +858,19 @@ out: static int qedf_eh_target_reset(struct scsi_cmnd *sc_cmd) { - QEDF_ERR(NULL, "%d:0:%d:%lld: TARGET RESET Issued...", - sc_cmd->device->host->host_no, sc_cmd->device->id, - sc_cmd->device->lun); - return qedf_initiate_tmf(sc_cmd, FCP_TMF_TGT_RESET); + struct scsi_target *starget = scsi_target(sc_cmd->device); + struct fc_rport *rport = starget_to_rport(starget); + + QEDF_ERR(NULL, "TARGET RESET Issued..."); + return qedf_initiate_tmf(rport, 0, FCP_TMF_TGT_RESET); } static int qedf_eh_device_reset(struct scsi_cmnd *sc_cmd) { - QEDF_ERR(NULL, "%d:0:%d:%lld: LUN RESET Issued... ", - sc_cmd->device->host->host_no, sc_cmd->device->id, - sc_cmd->device->lun); - return qedf_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); + struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); + + QEDF_ERR(NULL, "LUN RESET Issued...\n"); + return qedf_initiate_tmf(rport, sc_cmd->device->lun, FCP_TMF_LUN_RESET); } bool qedf_wait_for_upload(struct qedf_ctx *qedf) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 6e5e89aaa283..27bce80262c2 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -716,7 +716,6 @@ enum action { ABORT_COMMAND, DEVICE_RESET, BUS_RESET, - ADAPTER_RESET, }; @@ -898,22 +897,9 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) } break; - case ADAPTER_RESET: default: - if (qla1280_verbose) { - printk(KERN_INFO - "scsi(%ld): Issued ADAPTER RESET\n", - ha->host_no); - printk(KERN_INFO "scsi(%ld): I/O processing will " - "continue automatically\n", ha->host_no); - } - ha->flags.reset_active = 1; - - if (qla1280_abort_isp(ha) != 0) { /* it's dead */ - result = FAILED; - } - - ha->flags.reset_active = 0; + dprintk(1, "RESET invalid action %d\n", action); + return FAILED; } /* @@ -1011,11 +997,27 @@ qla1280_eh_bus_reset(struct scsi_cmnd *cmd) static int qla1280_eh_adapter_reset(struct scsi_cmnd *cmd) { - int rc; + int rc = SUCCESS; + struct Scsi_Host *shost = cmd->device->host; + struct scsi_qla_host *ha = (struct scsi_qla_host *)shost->hostdata; - spin_lock_irq(cmd->device->host->host_lock); - rc = qla1280_error_action(cmd, ADAPTER_RESET); - spin_unlock_irq(cmd->device->host->host_lock); + spin_lock_irq(shost->host_lock); + if (qla1280_verbose) { + printk(KERN_INFO + "scsi(%ld): Issued ADAPTER RESET\n", + ha->host_no); + printk(KERN_INFO "scsi(%ld): I/O processing will " + "continue automatically\n", ha->host_no); + } + ha->flags.reset_active = 1; + + if (qla1280_abort_isp(ha) != 0) { /* it's dead */ + rc = FAILED; + } + + ha->flags.reset_active = 0; + + spin_unlock_irq(shost->host_lock); return rc; } diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 17491ba10439..a2560cc807d3 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -559,14 +559,15 @@ static void sym53c8xx_timer(struct timer_list *t) */ #define SYM_EH_ABORT 0 #define SYM_EH_DEVICE_RESET 1 -#define SYM_EH_BUS_RESET 2 -#define SYM_EH_HOST_RESET 3 /* * Generic method for our eh processing. * The 'op' argument tells what we have to do. */ -static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) +/* + * Error handlers called from the eh thread (one thread per HBA). + */ +static int sym53c8xx_eh_abort_handler(struct scsi_cmnd *cmd) { struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd); struct Scsi_Host *shost = cmd->device->host; @@ -578,37 +579,13 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) int sts = -1; struct completion eh_done; - scmd_printk(KERN_WARNING, cmd, "%s operation started\n", opname); + scmd_printk(KERN_WARNING, cmd, "ABORT operation started\n"); - /* We may be in an error condition because the PCI bus - * went down. In this case, we need to wait until the - * PCI bus is reset, the card is reset, and only then - * proceed with the scsi error recovery. There's no - * point in hurrying; take a leisurely wait. + /* + * Escalate to host reset if the PCI bus went down */ -#define WAIT_FOR_PCI_RECOVERY 35 - if (pci_channel_offline(pdev)) { - int finished_reset = 0; - init_completion(&eh_done); - spin_lock_irq(shost->host_lock); - /* Make sure we didn't race */ - if (pci_channel_offline(pdev)) { - BUG_ON(sym_data->io_reset); - sym_data->io_reset = &eh_done; - } else { - finished_reset = 1; - } - spin_unlock_irq(shost->host_lock); - if (!finished_reset) - finished_reset = wait_for_completion_timeout - (sym_data->io_reset, - WAIT_FOR_PCI_RECOVERY*HZ); - spin_lock_irq(shost->host_lock); - sym_data->io_reset = NULL; - spin_unlock_irq(shost->host_lock); - if (!finished_reset) - return SCSI_FAILED; - } + if (pci_channel_offline(pdev)) + return SCSI_FAILED; spin_lock_irq(shost->host_lock); /* This one is queued in some place -> to wait for completion */ @@ -620,28 +597,7 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) } } - /* Try to proceed the operation we have been asked for */ - sts = -1; - switch(op) { - case SYM_EH_ABORT: - sts = sym_abort_scsiio(np, cmd, 1); - break; - case SYM_EH_DEVICE_RESET: - sts = sym_reset_scsi_target(np, cmd->device->id); - break; - case SYM_EH_BUS_RESET: - sym_reset_scsi_bus(np, 1); - sts = 0; - break; - case SYM_EH_HOST_RESET: - sym_reset_scsi_bus(np, 0); - sym_start_up(shost, 1); - sts = 0; - break; - default: - break; - } - + sts = sym_abort_scsiio(np, cmd, 1); /* On error, restore everything and cross fingers :) */ if (sts) cmd_queued = 0; @@ -658,33 +614,130 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) spin_unlock_irq(shost->host_lock); } - dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname, + dev_warn(&cmd->device->sdev_gendev, "ABORT operation %s.\n", sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed"); return sts ? SCSI_FAILED : SCSI_SUCCESS; } - -/* - * Error handlers called from the eh thread (one thread per HBA). - */ -static int sym53c8xx_eh_abort_handler(struct scsi_cmnd *cmd) +static int sym53c8xx_eh_target_reset_handler(struct scsi_cmnd *cmd) { - return sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd); -} + struct scsi_target *starget = scsi_target(cmd->device); + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct sym_data *sym_data = shost_priv(shost); + struct pci_dev *pdev = sym_data->pdev; + struct sym_hcb *np = sym_data->ncb; + SYM_QUEHEAD *qp; + int sts; + struct completion eh_done; -static int sym53c8xx_eh_device_reset_handler(struct scsi_cmnd *cmd) -{ - return sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd); + starget_printk(KERN_WARNING, starget, + "TARGET RESET operation started\n"); + + /* + * Escalate to host reset if the PCI bus went down + */ + if (pci_channel_offline(pdev)) + return SCSI_FAILED; + + spin_lock_irq(shost->host_lock); + sts = sym_reset_scsi_target(np, starget->id); + if (!sts) { + FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { + struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, + link_ccbq); + struct scsi_cmnd *cmd = cp->cmd; + struct sym_ucmd *ucmd; + + if (!cmd || cmd->device->channel != starget->channel || + cmd->device->id != starget->id) + continue; + + ucmd = SYM_UCMD_PTR(cmd); + init_completion(&eh_done); + ucmd->eh_done = &eh_done; + spin_unlock_irq(shost->host_lock); + if (!wait_for_completion_timeout(&eh_done, 5*HZ)) { + ucmd->eh_done = NULL; + sts = -2; + } + spin_lock_irq(shost->host_lock); + } + } + spin_unlock_irq(shost->host_lock); + + starget_printk(KERN_WARNING, starget, "TARGET RESET operation %s.\n", + sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed"); + return SCSI_SUCCESS; } static int sym53c8xx_eh_bus_reset_handler(struct scsi_cmnd *cmd) { - return sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd); + struct Scsi_Host *shost = cmd->device->host; + struct sym_data *sym_data = shost_priv(shost); + struct pci_dev *pdev = sym_data->pdev; + struct sym_hcb *np = sym_data->ncb; + + scmd_printk(KERN_WARNING, cmd, "BUS RESET operation started\n"); + + /* + * Escalate to host reset if the PCI bus went down + */ + if (pci_channel_offline(pdev)) + return SCSI_FAILED; + + spin_lock_irq(shost->host_lock); + sym_reset_scsi_bus(np, 1); + spin_unlock_irq(shost->host_lock); + + dev_warn(&cmd->device->sdev_gendev, "BUS RESET operation complete.\n"); + return SCSI_SUCCESS; } static int sym53c8xx_eh_host_reset_handler(struct scsi_cmnd *cmd) { - return sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd); + struct Scsi_Host *shost = cmd->device->host; + struct sym_data *sym_data = shost_priv(shost); + struct pci_dev *pdev = sym_data->pdev; + struct sym_hcb *np = sym_data->ncb; + struct completion eh_done; + int finished_reset = 1; + + shost_printk(KERN_WARNING, shost, "HOST RESET operation started\n"); + + /* We may be in an error condition because the PCI bus + * went down. In this case, we need to wait until the + * PCI bus is reset, the card is reset, and only then + * proceed with the scsi error recovery. There's no + * point in hurrying; take a leisurely wait. + */ +#define WAIT_FOR_PCI_RECOVERY 35 + if (pci_channel_offline(pdev)) { + init_completion(&eh_done); + spin_lock_irq(shost->host_lock); + /* Make sure we didn't race */ + if (pci_channel_offline(pdev)) { + BUG_ON(sym_data->io_reset); + sym_data->io_reset = &eh_done; + finished_reset = 0; + } + spin_unlock_irq(shost->host_lock); + if (!finished_reset) + finished_reset = wait_for_completion_timeout + (sym_data->io_reset, + WAIT_FOR_PCI_RECOVERY*HZ); + spin_lock_irq(shost->host_lock); + sym_data->io_reset = NULL; + spin_unlock_irq(shost->host_lock); + } + + if (finished_reset) { + sym_reset_scsi_bus(np, 0); + sym_start_up(shost, 1); + } + + shost_printk(KERN_WARNING, shost, "HOST RESET operation %s.\n", + finished_reset==1 ? "complete" : "failed"); + return finished_reset ? SCSI_SUCCESS : SCSI_FAILED; } /* @@ -1635,7 +1688,7 @@ static const struct scsi_host_template sym2_template = { .slave_configure = sym53c8xx_slave_configure, .slave_destroy = sym53c8xx_slave_destroy, .eh_abort_handler = sym53c8xx_eh_abort_handler, - .eh_device_reset_handler = sym53c8xx_eh_device_reset_handler, + .eh_target_reset_handler = sym53c8xx_eh_target_reset_handler, .eh_bus_reset_handler = sym53c8xx_eh_bus_reset_handler, .eh_host_reset_handler = sym53c8xx_eh_host_reset_handler, .this_id = 7, |