From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx> This patch adds scsi_dispatch_cmd_unlocked() and scsi_dispatch_cmd_locked() which are now called directly from scsi_dispatch_cmd() depending upon if SHT->queuecommand_unlocked() function pointer exists on a per driver basis. Note that by default ->queuecommand_unlocked is disabled, and all LLDs not defining a SHT->queuecommand_unlocked() will be using the legacy scsi_dispatch_cmd_locked() -> SHT->queuecommand() for I/O dispatch. This patch also drops the RFCv6 series and earlier logic to push down scsi_cmd_get_serial() usage into legacy LLD SHT->queuecommand(), and removes the EXPORT_SYMBOL() usage. So for now we still call scsi_cmd_get_serial() for all LLDs within scsi_dispatch_cmd() to perform struct scsi_cmnd->serial_number assignment using the new atomic_t struct Scsi_Host->cmd_serial_number counter. This counter follows a recommedation by Joe Eykholt to increment each serial_number by 2 so that the serial is odd, and wraps to 1 instead of 0. Along with the changes to SCSI ML, this series includes the following LLD commits to enable lock-less operation for certain LLDs: libiscsi: Remove host_lock unlock() + lock() from iscsi_queuecommand() iscsi_iser: Set SHT->queuecommand_unlocked for libiscsi queuecommand() be2iscsi: Set SHT->queuecommand_unlocked for libiscsi queuecommand() bnx2i: Set SHT->queuecommand_unlocked for libiscsi queuecommand() cxgb3i: Set SHT->queuecommand_unlocked for libiscsi queuecommand() cxgb4i: Set SHT->queuecommand_unlocked for libiscsi queuecommand() libsas: Remove host_lock unlock() + lock() from sas_queuecommand() aic94xx: Set SHT->queuecommand_unlocked for libsas queuecommand() mvsas: Set SHT->queuecommand_unlocked for libsas queuecommand() pm8001: Set SHT->queuecommand_unlocked for libsas queuecommand() libata: Remove host_lock unlock() + lock() and set SHT->queuecommand_unlocked() lpfc: Remove host_lock unlock() + lock() and set SHT->queuecommand_unlocked() qla4xxx: Remove host_lock unlock() + lock() and set SHT->queuecommand_unlocked() qla2xxx: Remove host_lock unlock() + lock() and set SHT->queuecommand_unlocked() fnic: Remove host_lock unlock() + lock() and set SHT->queuecommand_unlocked() mpt2sas: Set SHT->queuecommand_unlocked() for _scsih_qcmd() mpt/fusion: set SHT->queuecommand_unlocked() mpt*_qcmd() Note that this patch series currently does not contain host_lock less operation for libfc or fcoe as there are outstanding items wrt to rport state w/o host_lock held in libfc ->queuecommand(). Many thanks to Vasu Dev, Tim Chen, Andi Kleen, Mike Christie, Joe Eykholt, Mike Anderson, Christof Schmitt, Brian King, Jens Axboe, James Bottomley, and H. Peter Anvin for their help with this series! Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx> Acked-by: Ravi Anand <ravi.anand@xxxxxxxxxx> (for qla2xx) Acked-by: Luben Tuikov <ltuikov@xxxxxxxxx> (for aic94xx) Acked-by: Jack Wang <jack_wang@xxxxxxxxx> (for pm8001) --- drivers/ata/libata-scsi.c | 4 +- drivers/infiniband/ulp/iser/iscsi_iser.c | 2 +- drivers/message/fusion/mptfc.c | 2 +- drivers/message/fusion/mptsas.c | 2 +- drivers/message/fusion/mptspi.c | 2 +- drivers/scsi/aic94xx/aic94xx_init.c | 2 +- drivers/scsi/be2iscsi/be_main.c | 2 +- drivers/scsi/bnx2i/bnx2i_iscsi.c | 2 +- drivers/scsi/cxgbi/cxgb3i/cxgb3i.c | 2 +- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 2 +- drivers/scsi/fnic/fnic_main.c | 2 +- drivers/scsi/fnic/fnic_scsi.c | 9 --- drivers/scsi/hosts.c | 4 + drivers/scsi/iscsi_tcp.c | 2 +- drivers/scsi/libiscsi.c | 4 - drivers/scsi/libsas/sas_scsi_host.c | 5 -- drivers/scsi/lpfc/lpfc_scsi.c | 6 +- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 2 +- drivers/scsi/mvsas/mv_init.c | 2 +- drivers/scsi/pm8001/pm8001_init.c | 2 +- drivers/scsi/qla2xxx/qla_os.c | 11 +--- drivers/scsi/qla4xxx/ql4_os.c | 10 +--- drivers/scsi/scsi.c | 98 +++++++++++++++++++++++------- include/linux/libata.h | 2 +- include/scsi/scsi_host.h | 23 ++++++- 25 files changed, 123 insertions(+), 81 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d050e07..672a8c9 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3174,7 +3174,7 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, * ATA and ATAPI devices appearing as SCSI devices. * * LOCKING: - * Releases scsi-layer-held lock, and obtains host lock. + * None * * RETURNS: * Return value from __ata_scsi_queuecmd() if @cmd can be queued, @@ -3190,7 +3190,6 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) ap = ata_shost_to_port(shost); - spin_unlock(shost->host_lock); spin_lock(ap->lock); ata_scsi_dump_cdb(ap, cmd); @@ -3204,7 +3203,6 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) } spin_unlock(ap->lock); - spin_lock(shost->host_lock); return rc; } diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 7b2fc98..272299c 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -608,7 +608,7 @@ iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep) static struct scsi_host_template iscsi_iser_sht = { .module = THIS_MODULE, .name = "iSCSI Initiator over iSER, v." DRV_VER, - .queuecommand = iscsi_queuecommand, + .queuecommand_unlocked = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, .sg_tablesize = ISCSI_ISER_SG_TABLESIZE, .max_sectors = 1024, diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index e15220f..1368f34 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -113,7 +113,7 @@ static struct scsi_host_template mptfc_driver_template = { .proc_info = mptscsih_proc_info, .name = "MPT FC Host", .info = mptscsih_info, - .queuecommand = mptfc_qcmd, + .queuecommand_unlocked = mptfc_qcmd, .target_alloc = mptfc_target_alloc, .slave_alloc = mptfc_slave_alloc, .slave_configure = mptscsih_slave_configure, diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 83a5115..337bc67 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1962,7 +1962,7 @@ static struct scsi_host_template mptsas_driver_template = { .proc_info = mptscsih_proc_info, .name = "MPT SAS Host", .info = mptscsih_info, - .queuecommand = mptsas_qcmd, + .queuecommand_unlocked = mptsas_qcmd, .target_alloc = mptsas_target_alloc, .slave_alloc = mptsas_slave_alloc, .slave_configure = mptsas_slave_configure, diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 0e28031..f2201f0 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -832,7 +832,7 @@ static struct scsi_host_template mptspi_driver_template = { .proc_info = mptscsih_proc_info, .name = "MPT SPI Host", .info = mptscsih_info, - .queuecommand = mptspi_qcmd, + .queuecommand_unlocked = mptspi_qcmd, .target_alloc = mptspi_target_alloc, .slave_alloc = mptspi_slave_alloc, .slave_configure = mptspi_slave_configure, diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 3b7e83d..c079a70 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -65,7 +65,7 @@ static struct scsi_host_template aic94xx_sht = { .module = THIS_MODULE, /* .name is initialized */ .name = "aic94xx", - .queuecommand = sas_queuecommand, + .queuecommand_unlocked = sas_queuecommand, .target_alloc = sas_target_alloc, .slave_configure = sas_slave_configure, .slave_destroy = sas_slave_destroy, diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 75a85aa..b853fca 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -439,7 +439,7 @@ static struct scsi_host_template beiscsi_sht = { .module = THIS_MODULE, .name = "ServerEngines 10Gbe open-iscsi Initiator Driver", .proc_name = DRV_NAME, - .queuecommand = iscsi_queuecommand, + .queuecommand_unlocked = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, .slave_configure = beiscsi_slave_configure, .target_alloc = iscsi_target_alloc, diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index fb50efb..6715b72 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -2110,7 +2110,7 @@ static struct scsi_host_template bnx2i_host_template = { .module = THIS_MODULE, .name = "Broadcom Offload iSCSI Initiator", .proc_name = "bnx2i", - .queuecommand = iscsi_queuecommand, + .queuecommand_unlocked = iscsi_queuecommand, .eh_abort_handler = iscsi_eh_abort, .eh_device_reset_handler = iscsi_eh_device_reset, .eh_target_reset_handler = iscsi_eh_recover_target, diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index a129a17..826762d 100644 --- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -86,7 +86,7 @@ static struct scsi_host_template cxgb3i_host_template = { .name = DRV_MODULE_NAME, .proc_name = DRV_MODULE_NAME, .can_queue = CXGB3I_SCSI_HOST_QDEPTH, - .queuecommand = iscsi_queuecommand, + .queuecommand_unlocked = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF, diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 99f2b8c..b329ef9 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -88,7 +88,7 @@ static struct scsi_host_template cxgb4i_host_template = { .name = DRV_MODULE_NAME, .proc_name = DRV_MODULE_NAME, .can_queue = CXGB4I_SCSI_HOST_QDEPTH, - .queuecommand = iscsi_queuecommand, + .queuecommand_unlocked = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF, diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index bb63f1a..586b291 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -93,7 +93,7 @@ static int fnic_slave_alloc(struct scsi_device *sdev) static struct scsi_host_template fnic_host_template = { .module = THIS_MODULE, .name = DRV_NAME, - .queuecommand = fnic_queuecommand, + .queuecommand_unlocked = fnic_queuecommand, .eh_abort_handler = fnic_abort_cmd, .eh_device_reset_handler = fnic_device_reset, .eh_host_reset_handler = fnic_host_reset, diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 198cbab..7cf3372 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -373,13 +373,6 @@ int fnic_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) if (lp->state != LPORT_ST_READY || !(lp->link_up)) return SCSI_MLQUEUE_HOST_BUSY; - /* - * Release host lock, use driver resource specific locks from here. - * Don't re-enable interrupts in case they were disabled prior to the - * caller disabling them. - */ - spin_unlock(lp->host->host_lock); - /* Get a new io_req for this SCSI IO */ fnic = lport_priv(lp); @@ -452,8 +445,6 @@ int fnic_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) } } out: - /* acquire host lock before returning to SCSI */ - spin_lock(lp->host->host_lock); return ret; } diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 4f7a582..8c1760d 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -381,6 +381,10 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->unchecked_isa_dma = sht->unchecked_isa_dma; shost->use_clustering = sht->use_clustering; shost->ordered_tag = sht->ordered_tag; + /* + * Set the default shost->cmd_serial_number to 1. + */ + atomic_set(&shost->cmd_serial_number, 1); if (sht->supported_mode == MODE_UNKNOWN) /* means we didn't set it ... default to INITIATOR */ diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index fec47de..74870996 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -867,7 +867,7 @@ static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev) static struct scsi_host_template iscsi_sw_tcp_sht = { .module = THIS_MODULE, .name = "iSCSI Initiator over TCP/IP", - .queuecommand = iscsi_queuecommand, + .queuecommand_unlocked = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1, .sg_tablesize = 4096, diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 633e090..7e4134e 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1615,7 +1615,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) host = sc->device->host; ihost = shost_priv(host); - spin_unlock(host->host_lock); cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; @@ -1706,7 +1705,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) session->queued_cmdsn++; spin_unlock(&session->lock); - spin_lock(host->host_lock); return 0; prepd_reject: @@ -1716,7 +1714,6 @@ reject: spin_unlock(&session->lock); ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); - spin_lock(host->host_lock); return SCSI_MLQUEUE_TARGET_BUSY; prepd_fault: @@ -1733,7 +1730,6 @@ fault: scsi_in(sc)->resid = scsi_in(sc)->length; } done(sc); - spin_lock(host->host_lock); return 0; } EXPORT_SYMBOL_GPL(iscsi_queuecommand); diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 55f09e9..cc12cd7 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -191,18 +191,14 @@ int sas_queue_up(struct sas_task *task) */ int sas_queuecommand(struct scsi_cmnd *cmd, void (*scsi_done)(struct scsi_cmnd *)) - __releases(host->host_lock) __acquires(dev->sata_dev.ap->lock) __releases(dev->sata_dev.ap->lock) - __acquires(host->host_lock) { int res = 0; struct domain_device *dev = cmd_to_domain_dev(cmd); struct Scsi_Host *host = cmd->device->host; struct sas_internal *i = to_sas_internal(host->transportt); - spin_unlock_irq(host->host_lock); - { struct sas_ha_struct *sas_ha = dev->port->ha; struct sas_task *task; @@ -250,7 +246,6 @@ int sas_queuecommand(struct scsi_cmnd *cmd, } } out: - spin_lock_irq(host->host_lock); return res; } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 3a65895..8320f51 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -3034,11 +3034,9 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) goto out_host_busy_free_buf; } if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - spin_unlock(shost->host_lock); lpfc_sli_handle_fast_ring_event(phba, &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); - spin_lock(shost->host_lock); if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_poll_rearm_timer(phba); } @@ -3721,7 +3719,7 @@ struct scsi_host_template lpfc_template = { .module = THIS_MODULE, .name = LPFC_DRIVER_NAME, .info = lpfc_info, - .queuecommand = lpfc_queuecommand, + .queuecommand_unlocked = lpfc_queuecommand, .eh_abort_handler = lpfc_abort_handler, .eh_device_reset_handler = lpfc_device_reset_handler, .eh_target_reset_handler = lpfc_target_reset_handler, @@ -3744,7 +3742,7 @@ struct scsi_host_template lpfc_vport_template = { .module = THIS_MODULE, .name = LPFC_DRIVER_NAME, .info = lpfc_info, - .queuecommand = lpfc_queuecommand, + .queuecommand_unlocked = lpfc_queuecommand, .eh_abort_handler = lpfc_abort_handler, .eh_device_reset_handler = lpfc_device_reset_handler, .eh_target_reset_handler = lpfc_target_reset_handler, diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 16e99b6..04d2e7c 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -6450,7 +6450,7 @@ static struct scsi_host_template scsih_driver_template = { .module = THIS_MODULE, .name = "Fusion MPT SAS Host", .proc_name = MPT2SAS_DRIVER_NAME, - .queuecommand = _scsih_qcmd, + .queuecommand_unlocked = _scsih_qcmd, .target_alloc = _scsih_target_alloc, .slave_alloc = _scsih_slave_alloc, .slave_configure = _scsih_slave_configure, diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 19ad34f..9a1e9e6 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -42,7 +42,7 @@ static const struct mvs_chip_info mvs_chips[] = { static struct scsi_host_template mvs_sht = { .module = THIS_MODULE, .name = DRV_NAME, - .queuecommand = sas_queuecommand, + .queuecommand_unlocked = sas_queuecommand, .target_alloc = sas_target_alloc, .slave_configure = mvs_slave_configure, .slave_destroy = sas_slave_destroy, diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index f8c86b2..107c9d0 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -57,7 +57,7 @@ LIST_HEAD(hba_list); static struct scsi_host_template pm8001_sht = { .module = THIS_MODULE, .name = DRV_NAME, - .queuecommand = sas_queuecommand, + .queuecommand_unlocked = sas_queuecommand, .target_alloc = sas_target_alloc, .slave_configure = pm8001_slave_configure, .slave_destroy = sas_slave_destroy, diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 800ea92..33a20d4 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -188,7 +188,7 @@ static int qla2x00_change_queue_type(struct scsi_device *, int); struct scsi_host_template qla2xxx_driver_template = { .module = THIS_MODULE, .name = QLA2XXX_DRIVER_NAME, - .queuecommand = qla2xxx_queuecommand, + .queuecommand_unlocked = qla2xxx_queuecommand, .eh_abort_handler = qla2xxx_eh_abort, .eh_device_reset_handler = qla2xxx_eh_device_reset, @@ -574,26 +574,21 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) goto qc24_target_busy; } - spin_unlock_irq(vha->host->host_lock); - sp = qla2x00_get_new_sp(base_vha, fcport, cmd, done); if (!sp) - goto qc24_host_busy_lock; + goto qc24_host_busy; rval = ha->isp_ops->start_scsi(sp); if (rval != QLA_SUCCESS) goto qc24_host_busy_free_sp; - spin_lock_irq(vha->host->host_lock); - return 0; qc24_host_busy_free_sp: qla2x00_sp_free_dma(sp); mempool_free(sp, ha->srb_mempool); -qc24_host_busy_lock: - spin_lock_irq(vha->host->host_lock); +qc24_host_busy: return SCSI_MLQUEUE_HOST_BUSY; qc24_target_busy: diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 370d40f..771c8c6 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -97,7 +97,7 @@ static struct scsi_host_template qla4xxx_driver_template = { .module = THIS_MODULE, .name = DRIVER_NAME, .proc_name = DRIVER_NAME, - .queuecommand = qla4xxx_queuecommand, + .queuecommand_unlocked = qla4xxx_queuecommand, .eh_abort_handler = qla4xxx_eh_abort, .eh_device_reset_handler = qla4xxx_eh_device_reset, @@ -511,26 +511,20 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) goto qc_host_busy; - spin_unlock_irq(ha->host->host_lock); - srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd, done); if (!srb) - goto qc_host_busy_lock; + goto qc_host_busy; rval = qla4xxx_send_command_to_isp(ha, srb); if (rval != QLA_SUCCESS) goto qc_host_busy_free_sp; - spin_lock_irq(ha->host->host_lock); return 0; qc_host_busy_free_sp: qla4xxx_srb_free_dma(ha, srb); mempool_free(srb, ha->srb_mempool); -qc_host_busy_lock: - spin_lock_irq(ha->host->host_lock); - qc_host_busy: return SCSI_MLQUEUE_HOST_BUSY; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 348fba0..f504469 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -628,17 +628,74 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) /** * scsi_cmd_get_serial - Assign a serial number to a command - * @host: the scsi host * @cmd: command to assign serial number to * * Description: a serial number identifies a request for error recovery - * and debugging purposes. Protected by the Host_Lock of host. + * and debugging purposes. Called directly by scsi_dispatch_cmd() for + * all LLDs. */ -static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd) +static void scsi_cmd_get_serial(struct scsi_cmnd *cmd) { - cmd->serial_number = host->cmd_serial_number++; - if (cmd->serial_number == 0) - cmd->serial_number = host->cmd_serial_number++; + struct Scsi_Host *host = cmd->device->host; + /* + * Increment the host->cmd_serial_number by 2 so cmd->serial_number + * is always odd and wraps to 1 instead of 0. + */ + cmd->serial_number = atomic_add_return(2, &host->cmd_serial_number); +} + +/* + * scsi_dispatch_cmd_unlocked() - Dispatch a cmd w/o host_lock + * @cmd: command to dispatch. + * @host: SCSI host of the passed command + * + * Description: Used by modern SCSI LLDs that do not require that + * struct Scsi_Host->host_lock is held during a dispatch call to + * SHT->queuecommand(). + */ + +static inline int scsi_dispatch_cmd_unlocked(struct scsi_cmnd *cmd, + struct Scsi_Host *host) +{ + int rtn = 0; + + if (unlikely(host->shost_state == SHOST_DEL)) { + cmd->result = (DID_NO_CONNECT << 16); + scsi_done(cmd); + } else { + trace_scsi_dispatch_cmd_start(cmd); + rtn = host->hostt->queuecommand_unlocked(cmd, scsi_done); + } + + return rtn; +} + +/* + * scsi_dispatch_cmd_locked() - Dispatch a cmd w/ host_lock + * @cmd: command to dispatch. + * @host: SCSI host of the passed command + * + * Description: Used by kegacy SCSI LLDs that require that + * struct Scsi_Host->host_lock is held during a dispatch call to + * SHT->queuecommand(). + */ +static inline int scsi_dispatch_cmd_locked(struct scsi_cmnd *cmd, + struct Scsi_Host *host) +{ + unsigned long flags; + int rtn = 0; + + spin_lock_irqsave(host->host_lock, flags); + if (unlikely(host->shost_state == SHOST_DEL)) { + cmd->result = (DID_NO_CONNECT << 16); + scsi_done(cmd); + } else { + trace_scsi_dispatch_cmd_start(cmd); + rtn = host->hostt->queuecommand(cmd, scsi_done); + } + spin_unlock_irqrestore(host->host_lock, flags); + + return rtn; } /** @@ -651,7 +708,6 @@ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd int scsi_dispatch_cmd(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; - unsigned long flags = 0; unsigned long timeout; int rtn = 0; @@ -736,24 +792,22 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) scsi_done(cmd); goto out; } - - spin_lock_irqsave(host->host_lock, flags); /* - * AK: unlikely race here: for some reason the timer could - * expire before the serial number is set up below. - * - * TODO: kill serial or move to blk layer + * Assign a cmd->serial_number from host->cmd_serial_number that + * is used by handful of LLDs, and by scsi_softirq_done() to signal + * scsi_try_to_abort_cmd() that a outstanding cmd has been completed. + */ + scsi_cmd_get_serial(cmd); + /* + * Also check for the new queuecommand_unlocked() to signal that + * underlying LLD SHT->queuecommand() code is safe to run w/o + * struct Scsi_Host->host_lock held. */ - scsi_cmd_get_serial(host, cmd); + if (host->hostt->queuecommand_unlocked != NULL) + rtn = scsi_dispatch_cmd_unlocked(cmd, host); + else + rtn = scsi_dispatch_cmd_locked(cmd, host); - if (unlikely(host->shost_state == SHOST_DEL)) { - cmd->result = (DID_NO_CONNECT << 16); - scsi_done(cmd); - } else { - trace_scsi_dispatch_cmd_start(cmd); - rtn = host->hostt->queuecommand(cmd, scsi_done); - } - spin_unlock_irqrestore(host->host_lock, flags); if (rtn) { trace_scsi_dispatch_cmd_error(cmd, rtn); if (rtn != SCSI_MLQUEUE_DEVICE_BUSY && diff --git a/include/linux/libata.h b/include/linux/libata.h index 15b77b8..8d281d8 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1187,7 +1187,7 @@ extern struct device_attribute *ata_common_sdev_attrs[]; .module = THIS_MODULE, \ .name = drv_name, \ .ioctl = ata_scsi_ioctl, \ - .queuecommand = ata_scsi_queuecmd, \ + .queuecommand_unlocked = ata_scsi_queuecmd, \ .can_queue = ATA_DEF_QUEUE, \ .this_id = ATA_SHT_THIS_ID, \ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, \ diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index d0a6a84..d741cf2 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -106,6 +106,12 @@ struct scsi_host_template { * command before queuecommand returns, but in this case you * *must* return 0 from queuecommand). * + * Note that queuecommand() is the function used by legacy + * LLDs that require struct Scsi_Host->host_lock be held while + * dispatching struct scsi_cmnd descriptors. Modern LLDs that + * do not have this requirement run in 'host_lock-less' mode + * using queuecommand_unlocked below. + * * Queuecommand may also reject the command, in which case it may * not touch the command and must not call done() for it. * @@ -131,6 +137,18 @@ struct scsi_host_template { void (*done)(struct scsi_cmnd *)); /* + * The queuecommand_unlocked() function that provides an opitional + * method of struct Scsi_Host->host_lock less dispatch of + * struct scsi_cmnd descriptors. + * + * Note that this API caller is otherwise expected to function the + * exact same as the legacy queuecommand(). + * + * STATUS: OPTIONAL + */ + int (* queuecommand_unlocked)(struct scsi_cmnd *, + void (*done)(struct scsi_cmnd *)); + /* * The transfer functions are used to queue a scsi command to * the LLD. When the driver is finished processing the command * the done callback is invoked. @@ -604,10 +622,9 @@ struct Scsi_Host { short unsigned int max_sectors; unsigned long dma_boundary; /* - * Used to assign serial numbers to the cmds. - * Protected by the host lock. + * Used to assign serial numbers to the cmds in scsi_cmd_get_serial() */ - unsigned long cmd_serial_number; + atomic_t cmd_serial_number; unsigned active_mode:2; unsigned unchecked_isa_dma:1; -- 1.7.3.2 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html