From: James Smart <James.Smart@Emulex.Com>
To: Matthew Wilcox <matthew@wil.cx>
Cc: linux-scsi@vger.kernel.org
Subject: Re: [RFC] Asynchronous scanning for FC/SAS version 3
Date: Wed, 15 Nov 2006 08:55:33 -0500 [thread overview]
Message-ID: <455B1C55.1070708@emulex.com> (raw)
In-Reply-To: <20061113152605.GZ16952@parisc-linux.org>
Hi Matt,
Thanks for the updates.
Please note that due to the extensive mods to lpfc, I can't give a quick
response either way. We'll also want to pull this into our regression
environment before signing off on it. I'll be getting some time to go
through this shortly.
-- james s
Matthew Wilcox wrote:
> This is the third version of this patch. Earlier versions can be found at
>
> http://marc.theaimsgroup.com/?l=linux-scsi&m=116136002113903&w=2
> http://marc.theaimsgroup.com/?l=linux-scsi&m=116311295814181&w=2
> http://marc.theaimsgroup.com/?l=linux-scsi&m=116316322719160&w=2
>
> This patch, relative to scsi-misc, adds infrastructure to support
> asynchronous scanning for drivers which call scsi_scan_target, and
> changes the aic94xx, lpfc and qla2xxx drivers to use it.
>
> It's a fairly radical restructuring for lpfc and qla2xxx and I may
> well have broken some error handling cases during initialisation.
> I'd appreciate review from the respective maintainers.
>
> I remain slightly uncomfortable about adding scan_start and scan_finished
> to the scsi_host_template. On the one hand, it's adding two methods
> where one would do. On the other hand, the contents of those two routines
> are completely different to each other.
>
> Maybe there's a better way to do this (like exporting
> scsi_prep_async_scan() and scsi_finish_async_scan() to the drivers
> which was my original idea. But I like the symmetry, code-sharing and
> encapsulation of calling scsi_scan_host().)
>
> Other changes relative to scsi-misc:
> - Add the SCSI_SCAN_ASYNC Kconfig option so people can turn it on by
> default rather than having to pass a kernel command line param.
> - Added missing "none" case to scsi_scan_target()
> - Make scsi_prep_async_scan and scsi_finish_async_scan static.
>
> Todo:
> - Testing. Lots and lots of testing.
> - See if it can help out the FireWire/USB/iSCSI people
> - Convert zfcp to use it
> - Work out how to get Fusion using this.
>
> diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
> index 9540eb8..c312444 100644
> --- a/drivers/scsi/Kconfig
> +++ b/drivers/scsi/Kconfig
> @@ -216,6 +216,23 @@ config SCSI_LOGGING
> there should be no noticeable performance impact as long as you have
> logging turned off.
>
> +config SCSI_SCAN_ASYNC
> + bool "Asynchronous SCSI scanning"
> + depends on SCSI
> + help
> + The SCSI subsystem can probe for devices while the rest of the
> + system continues booting, and even probe devices on different
> + busses in parallel, leading to a significant speed-up.
> + If you have built SCSI as modules, enabling this option can
> + be a problem as the devices may not have been found by the
> + time your system expects them to have been. You can load the
> + scsi_wait_scan module to ensure that all scans have completed.
> + If you build your SCSI drivers into the kernel, then everything
> + will work fine if you say Y here.
> +
> + You can override this choice by specifying scsi_mod.scan="sync"
> + or "async" on the kernel's command line.
> +
> menu "SCSI Transports"
> depends on SCSI
>
> diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
> index 99743ca..3c46005 100644
> --- a/drivers/scsi/aic94xx/aic94xx_init.c
> +++ b/drivers/scsi/aic94xx/aic94xx_init.c
> @@ -57,6 +57,7 @@ MODULE_PARM_DESC(collector, "\n"
> char sas_addr_str[2*SAS_ADDR_SIZE + 1] = "";
>
> static struct scsi_transport_template *aic94xx_transport_template;
> +static int asd_scan_finished(struct Scsi_Host *, unsigned long);
>
> static struct scsi_host_template aic94xx_sht = {
> .module = THIS_MODULE,
> @@ -66,6 +67,7 @@ static struct scsi_host_template aic94xx
> .target_alloc = sas_target_alloc,
> .slave_configure = sas_slave_configure,
> .slave_destroy = sas_slave_destroy,
> + .scan_finished = asd_scan_finished,
> .change_queue_depth = sas_change_queue_depth,
> .change_queue_type = sas_change_queue_type,
> .bios_param = sas_bios_param,
> @@ -546,6 +548,18 @@ static int asd_unregister_sas_ha(struct
> return err;
> }
>
> +static int asd_scan_finished(struct Scsi_Host *shost, unsigned long time)
> +{
> + /* give the phy enabling interrupt event time to come in (1s
> + * is empirically about all it takes) */
> + if (time < HZ)
> + return 0;
> +
> + /* Wait for discovery to finish */
> + scsi_flush_work(shost);
> + return 1;
> +}
> +
> static int __devinit asd_pci_probe(struct pci_dev *dev,
> const struct pci_device_id *id)
> {
> @@ -677,11 +691,8 @@ static int __devinit asd_pci_probe(struc
> goto Err_en_phys;
> }
> ASD_DPRINTK("enabled phys\n");
> - /* give the phy enabling interrupt event time to come in (1s
> - * is empirically about all it takes) */
> - ssleep(1);
> - /* Wait for discovery to finish */
> - scsi_flush_work(asd_ha->sas_ha.core.shost);
> +
> + scsi_scan_host(shost);
>
> return 0;
> Err_en_phys:
> diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
> index 1251788..344cfe0 100644
> --- a/drivers/scsi/lpfc/lpfc_crtn.h
> +++ b/drivers/scsi/lpfc/lpfc_crtn.h
> @@ -193,6 +193,9 @@ void lpfc_mbuf_free(struct lpfc_hba *, v
>
> /* Function prototypes. */
> const char* lpfc_info(struct Scsi_Host *);
> +void lpfc_scan_start(struct Scsi_Host *);
> +int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
> +
> void lpfc_get_cfgparam(struct lpfc_hba *);
> int lpfc_alloc_sysfs_attr(struct lpfc_hba *);
> void lpfc_free_sysfs_attr(struct lpfc_hba *);
> diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
> index a5723ad..600c6d3 100644
> --- a/drivers/scsi/lpfc/lpfc_init.c
> +++ b/drivers/scsi/lpfc/lpfc_init.c
> @@ -416,33 +416,6 @@ lpfc_config_port_post(struct lpfc_hba *
> return (0);
> }
>
> -static int
> -lpfc_discovery_wait(struct lpfc_hba *phba)
> -{
> - int i = 0;
> -
> - while ((phba->hba_state != LPFC_HBA_READY) ||
> - (phba->num_disc_nodes) || (phba->fc_prli_sent) ||
> - ((phba->fc_map_cnt == 0) && (i<2)) ||
> - (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)) {
> - /* Check every second for 30 retries. */
> - i++;
> - if (i > 30) {
> - return -ETIMEDOUT;
> - }
> - if ((i >= 15) && (phba->hba_state <= LPFC_LINK_DOWN)) {
> - /* The link is down. Set linkdown timeout */
> - return -ETIMEDOUT;
> - }
> -
> - /* Delay for 1 second to give discovery time to complete. */
> - msleep(1000);
> -
> - }
> -
> - return 0;
> -}
> -
> /************************************************************************/
> /* */
> /* lpfc_hba_down_prep */
> @@ -1441,6 +1414,155 @@ lpfc_scsi_free(struct lpfc_hba * phba)
> return 0;
> }
>
> +void lpfc_remove_device(struct lpfc_hba *phba)
> +{
> + unsigned long iflag;
> +
> + lpfc_free_sysfs_attr(phba);
> +
> + spin_lock_irqsave(phba->host->host_lock, iflag);
> + phba->fc_flag |= FC_UNLOADING;
> +
> + spin_unlock_irqrestore(phba->host->host_lock, iflag);
> +
> + fc_remove_host(phba->host);
> + scsi_remove_host(phba->host);
> +
> + kthread_stop(phba->worker_thread);
> +
> + /*
> + * Bring down the SLI Layer. This step disable all interrupts,
> + * clears the rings, discards all mailbox commands, and resets
> + * the HBA.
> + */
> + lpfc_sli_hba_down(phba);
> + lpfc_sli_brdrestart(phba);
> +
> + /* Release the irq reservation */
> + free_irq(phba->pcidev->irq, phba);
> +
> + lpfc_cleanup(phba, 0);
> + lpfc_stop_timer(phba);
> + phba->work_hba_events = 0;
> +
> + /*
> + * Call scsi_free before mem_free since scsi bufs are released to their
> + * corresponding pools here.
> + */
> + lpfc_scsi_free(phba);
> + lpfc_mem_free(phba);
> +
> + /* Free resources associated with SLI2 interface */
> + dma_free_coherent(&phba->pcidev->dev, SLI2_SLIM_SIZE,
> + phba->slim2p, phba->slim2p_mapping);
> +
> + /* unmap adapter SLIM and Control Registers */
> + iounmap(phba->ctrl_regs_memmap_p);
> + iounmap(phba->slim_memmap_p);
> +
> + pci_release_regions(phba->pcidev);
> + pci_disable_device(phba->pcidev);
> +
> + idr_remove(&lpfc_hba_index, phba->brd_no);
> + scsi_host_put(phba->host);
> +}
> +
> +void lpfc_scan_start(struct Scsi_Host *host)
> +{
> + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
> +
> + if (lpfc_alloc_sysfs_attr(phba))
> + goto error;
> +
> + phba->MBslimaddr = phba->slim_memmap_p;
> + phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
> + phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
> + phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
> + phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
> +
> + if (lpfc_sli_hba_setup(phba))
> + goto error;
> +
> + /*
> + * hba setup may have changed the hba_queue_depth so we need to adjust
> + * the value of can_queue.
> + */
> + host->can_queue = phba->cfg_hba_queue_depth - 10;
> + return;
> +
> + error:
> + lpfc_remove_device(phba);
> +}
> +
> +int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
> +{
> + struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
> +
> + if (!phba->host)
> + return 1;
> + if (time >= 30 * HZ)
> + goto finished;
> +
> + if (phba->hba_state != LPFC_HBA_READY)
> + return 0;
> + if (phba->num_disc_nodes || phba->fc_prli_sent)
> + return 0;
> + if ((phba->fc_map_cnt == 0) && (time < 2 * HZ))
> + return 0;
> + if (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)
> + return 0;
> + if ((phba->hba_state > LPFC_LINK_DOWN) || (time < 15 * HZ))
> + return 0;
> +
> + finished:
> + if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
> + spin_lock_irq(shost->host_lock);
> + lpfc_poll_start_timer(phba);
> + spin_unlock_irq(shost->host_lock);
> + }
> +
> + /*
> + * set fixed host attributes
> + * Must done after lpfc_sli_hba_setup()
> + */
> +
> + fc_host_node_name(shost) = wwn_to_u64(phba->fc_nodename.u.wwn);
> + fc_host_port_name(shost) = wwn_to_u64(phba->fc_portname.u.wwn);
> + fc_host_supported_classes(shost) = FC_COS_CLASS3;
> +
> + memset(fc_host_supported_fc4s(shost), 0,
> + sizeof(fc_host_supported_fc4s(shost)));
> + fc_host_supported_fc4s(shost)[2] = 1;
> + fc_host_supported_fc4s(shost)[7] = 1;
> +
> + lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
> +
> + fc_host_supported_speeds(shost) = 0;
> + if (phba->lmt & LMT_10Gb)
> + fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;
> + if (phba->lmt & LMT_4Gb)
> + fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT;
> + if (phba->lmt & LMT_2Gb)
> + fc_host_supported_speeds(shost) |= FC_PORTSPEED_2GBIT;
> + if (phba->lmt & LMT_1Gb)
> + fc_host_supported_speeds(shost) |= FC_PORTSPEED_1GBIT;
> +
> + fc_host_maxframe_size(shost) =
> + ((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
> + (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb);
> +
> + /* This value is also unchanging */
> + memset(fc_host_active_fc4s(shost), 0,
> + sizeof(fc_host_active_fc4s(shost)));
> + fc_host_active_fc4s(shost)[2] = 1;
> + fc_host_active_fc4s(shost)[7] = 1;
> +
> + spin_lock_irq(shost->host_lock);
> + phba->fc_flag &= ~FC_LOADING;
> + spin_unlock_irq(shost->host_lock);
> +
> + return 1;
> +}
>
> static int __devinit
> lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
> @@ -1643,13 +1765,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev,
>
> host->transportt = lpfc_transport_template;
> pci_set_drvdata(pdev, host);
> - error = scsi_add_host(host, &pdev->dev);
> - if (error)
> - goto out_kthread_stop;
> -
> - error = lpfc_alloc_sysfs_attr(phba);
> - if (error)
> - goto out_remove_host;
>
> error = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
> LPFC_DRIVER_NAME, phba);
> @@ -1657,84 +1772,21 @@ lpfc_pci_probe_one(struct pci_dev *pdev,
> lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
> "%d:0451 Enable interrupt handler failed\n",
> phba->brd_no);
> - goto out_free_sysfs_attr;
> + goto out_kthread_stop;
> }
> - phba->MBslimaddr = phba->slim_memmap_p;
> - phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
> - phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
> - phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
> - phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
>
> - error = lpfc_sli_hba_setup(phba);
> - if (error) {
> - error = -ENODEV;
> + error = scsi_add_host(host, &pdev->dev);
> + if (error)
> goto out_free_irq;
> - }
> -
> - /*
> - * hba setup may have changed the hba_queue_depth so we need to adjust
> - * the value of can_queue.
> - */
> - host->can_queue = phba->cfg_hba_queue_depth - 10;
> -
> - lpfc_discovery_wait(phba);
> -
> - if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
> - spin_lock_irq(phba->host->host_lock);
> - lpfc_poll_start_timer(phba);
> - spin_unlock_irq(phba->host->host_lock);
> - }
>
> - /*
> - * set fixed host attributes
> - * Must done after lpfc_sli_hba_setup()
> - */
> -
> - fc_host_node_name(host) = wwn_to_u64(phba->fc_nodename.u.wwn);
> - fc_host_port_name(host) = wwn_to_u64(phba->fc_portname.u.wwn);
> - fc_host_supported_classes(host) = FC_COS_CLASS3;
> -
> - memset(fc_host_supported_fc4s(host), 0,
> - sizeof(fc_host_supported_fc4s(host)));
> - fc_host_supported_fc4s(host)[2] = 1;
> - fc_host_supported_fc4s(host)[7] = 1;
> -
> - lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(host));
> -
> - fc_host_supported_speeds(host) = 0;
> - if (phba->lmt & LMT_10Gb)
> - fc_host_supported_speeds(host) |= FC_PORTSPEED_10GBIT;
> - if (phba->lmt & LMT_4Gb)
> - fc_host_supported_speeds(host) |= FC_PORTSPEED_4GBIT;
> - if (phba->lmt & LMT_2Gb)
> - fc_host_supported_speeds(host) |= FC_PORTSPEED_2GBIT;
> - if (phba->lmt & LMT_1Gb)
> - fc_host_supported_speeds(host) |= FC_PORTSPEED_1GBIT;
> -
> - fc_host_maxframe_size(host) =
> - ((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
> - (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb);
> -
> - /* This value is also unchanging */
> - memset(fc_host_active_fc4s(host), 0,
> - sizeof(fc_host_active_fc4s(host)));
> - fc_host_active_fc4s(host)[2] = 1;
> - fc_host_active_fc4s(host)[7] = 1;
> + scsi_scan_host(host);
>
> - spin_lock_irq(phba->host->host_lock);
> - phba->fc_flag &= ~FC_LOADING;
> - spin_unlock_irq(phba->host->host_lock);
> return 0;
>
> out_free_irq:
> lpfc_stop_timer(phba);
> phba->work_hba_events = 0;
> free_irq(phba->pcidev->irq, phba);
> -out_free_sysfs_attr:
> - lpfc_free_sysfs_attr(phba);
> -out_remove_host:
> - fc_remove_host(phba->host);
> - scsi_remove_host(phba->host);
> out_kthread_stop:
> kthread_stop(phba->worker_thread);
> out_free_iocbq:
> @@ -1772,55 +1824,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev
> {
> struct Scsi_Host *host = pci_get_drvdata(pdev);
> struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata;
> - unsigned long iflag;
> -
> - lpfc_free_sysfs_attr(phba);
> -
> - spin_lock_irqsave(phba->host->host_lock, iflag);
> - phba->fc_flag |= FC_UNLOADING;
> -
> - spin_unlock_irqrestore(phba->host->host_lock, iflag);
> -
> - fc_remove_host(phba->host);
> - scsi_remove_host(phba->host);
> -
> - kthread_stop(phba->worker_thread);
> -
> - /*
> - * Bring down the SLI Layer. This step disable all interrupts,
> - * clears the rings, discards all mailbox commands, and resets
> - * the HBA.
> - */
> - lpfc_sli_hba_down(phba);
> - lpfc_sli_brdrestart(phba);
>
> - /* Release the irq reservation */
> - free_irq(phba->pcidev->irq, phba);
> -
> - lpfc_cleanup(phba, 0);
> - lpfc_stop_timer(phba);
> - phba->work_hba_events = 0;
> -
> - /*
> - * Call scsi_free before mem_free since scsi bufs are released to their
> - * corresponding pools here.
> - */
> - lpfc_scsi_free(phba);
> - lpfc_mem_free(phba);
> -
> - /* Free resources associated with SLI2 interface */
> - dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
> - phba->slim2p, phba->slim2p_mapping);
> -
> - /* unmap adapter SLIM and Control Registers */
> - iounmap(phba->ctrl_regs_memmap_p);
> - iounmap(phba->slim_memmap_p);
> -
> - pci_release_regions(phba->pcidev);
> - pci_disable_device(phba->pcidev);
> -
> - idr_remove(&lpfc_hba_index, phba->brd_no);
> - scsi_host_put(phba->host);
> + lpfc_remove_device(phba);
>
> pci_set_drvdata(pdev, NULL);
> }
> diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
> index 97ae98d..e83fcf0 100644
> --- a/drivers/scsi/lpfc/lpfc_scsi.c
> +++ b/drivers/scsi/lpfc/lpfc_scsi.c
> @@ -1278,6 +1278,8 @@ struct scsi_host_template lpfc_template
> .slave_alloc = lpfc_slave_alloc,
> .slave_configure = lpfc_slave_configure,
> .slave_destroy = lpfc_slave_destroy,
> + .scan_finished = lpfc_scan_finished,
> + .scan_start = lpfc_scan_start,
> .this_id = -1,
> .sg_tablesize = LPFC_SG_SEG_CNT,
> .cmd_per_lun = LPFC_CMD_PER_LUN,
> diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
> index 3f20d76..048dd3f 100644
> --- a/drivers/scsi/qla2xxx/qla_os.c
> +++ b/drivers/scsi/qla2xxx/qla_os.c
> @@ -83,6 +83,8 @@ MODULE_PARM_DESC(ql2xfdmienable,
> static int qla2xxx_slave_configure(struct scsi_device * device);
> static int qla2xxx_slave_alloc(struct scsi_device *);
> static void qla2xxx_slave_destroy(struct scsi_device *);
> +static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time);
> +static void qla2xxx_scan_start(struct Scsi_Host *);
> static int qla2x00_queuecommand(struct scsi_cmnd *cmd,
> void (*fn)(struct scsi_cmnd *));
> static int qla24xx_queuecommand(struct scsi_cmnd *cmd,
> @@ -111,6 +113,8 @@ static struct scsi_host_template qla2x00
>
> .slave_alloc = qla2xxx_slave_alloc,
> .slave_destroy = qla2xxx_slave_destroy,
> + .scan_finished = qla2xxx_scan_finished,
> + .scan_start = qla2xxx_scan_start,
> .change_queue_depth = qla2x00_change_queue_depth,
> .change_queue_type = qla2x00_change_queue_type,
> .this_id = -1,
> @@ -1353,6 +1357,117 @@ qla24xx_disable_intrs(scsi_qla_host_t *h
> spin_unlock_irqrestore(&ha->hardware_lock, flags);
> }
>
> +static void qla2xxx_remove_device(scsi_qla_host_t *ha)
> +{
> + qla2x00_free_sysfs_attr(ha);
> + fc_remove_host(ha->host);
> + scsi_remove_host(ha->host);
> + qla2x00_free_device(ha);
> + scsi_host_put(ha->host);
> +}
> +
> +static void qla2xxx_scan_start(struct Scsi_Host *shost)
> +{
> + unsigned long flags;
> + device_reg_t __iomem *reg;
> + scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
> +
> + if (qla2x00_initialize_adapter(ha) &&
> + !(ha->device_flags & DFLG_NO_CABLE)) {
> +
> + qla_printk(KERN_WARNING, ha,
> + "Failed to initialize adapter\n");
> +
> + DEBUG2(printk("scsi(%ld): Failed to initialize adapter - "
> + "Adapter flags %x.\n",
> + ha->host_no, ha->device_flags));
> + goto error;
> + }
> +
> + /*
> + * Startup the kernel thread for this host adapter
> + */
> + ha->dpc_thread = kthread_create(qla2x00_do_dpc, ha,
> + "%s_dpc", ha->host_str);
> + if (IS_ERR(ha->dpc_thread)) {
> + qla_printk(KERN_WARNING, ha,
> + "Unable to start DPC thread!\n");
> + goto error;
> + }
> +
> + qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL);
> +
> + DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
> + ha->host_no, ha));
> +
> + ha->isp_ops.disable_intrs(ha);
> +
> + spin_lock_irqsave(&ha->hardware_lock, flags);
> + reg = ha->iobase;
> + if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
> + WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_HOST_INT);
> + WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_RISC_INT);
> + } else {
> + WRT_REG_WORD(®->isp.semaphore, 0);
> + WRT_REG_WORD(®->isp.hccr, HCCR_CLR_RISC_INT);
> + WRT_REG_WORD(®->isp.hccr, HCCR_CLR_HOST_INT);
> +
> + /* Enable proper parity */
> + if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) {
> + if (IS_QLA2300(ha))
> + /* SRAM parity */
> + WRT_REG_WORD(®->isp.hccr,
> + (HCCR_ENABLE_PARITY + 0x1));
> + else
> + /* SRAM, Instruction RAM and GP RAM parity */
> + WRT_REG_WORD(®->isp.hccr,
> + (HCCR_ENABLE_PARITY + 0x7));
> + }
> + }
> + spin_unlock_irqrestore(&ha->hardware_lock, flags);
> +
> + ha->isp_ops.enable_intrs(ha);
> + ha->flags.init_done = 1;
> +
> + return;
> +
> + error:
> + qla2xxx_remove_device(ha);
> + ha->host = NULL;
> +}
> +
> +static int qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
> +{
> + fc_port_t *fcport;
> + scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
> +
> + if (!ha->host)
> + return 1;
> +
> + if (time > ha->loop_reset_delay * HZ)
> + goto finished;
> +
> + qla2x00_check_fabric_devices(ha);
> +
> + if (ha->device_flags & (DFLG_NO_CABLE | DFLG_FABRIC_DEVICES))
> + goto finished;
> + if (!(ha->device_flags & SWITCH_FOUND))
> + goto finished;
> +
> + return 0;
> +
> + finished:
> + qla2x00_alloc_sysfs_attr(ha);
> +
> + qla2x00_init_host_attr(ha);
> +
> + /* Go with fc_rport registration. */
> + list_for_each_entry(fcport, &ha->fcports, list)
> + qla2x00_reg_remote_port(ha, fcport);
> +
> + return 1;
> +}
> +
> /*
> * PCI driver interface
> */
> @@ -1360,14 +1475,10 @@ static int __devinit
> qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
> {
> int ret = -ENODEV;
> - device_reg_t __iomem *reg;
> struct Scsi_Host *host;
> scsi_qla_host_t *ha;
> - unsigned long flags = 0;
> - unsigned long wait_switch = 0;
> char pci_info[20];
> char fw_str[30];
> - fc_port_t *fcport;
> struct scsi_host_template *sht;
>
> if (pci_enable_device(pdev))
> @@ -1511,7 +1622,7 @@ qla2x00_probe_one(struct pci_dev *pdev,
> host->can_queue = ha->request_q_length + 128;
>
> /* load the F/W, read paramaters, and init the H/W */
> - ha->instance = num_hosts;
> + ha->instance = num_hosts++;
>
> init_MUTEX(&ha->mbx_cmd_sem);
> init_MUTEX_LOCKED(&ha->mbx_intr_sem);
> @@ -1536,32 +1647,6 @@ qla2x00_probe_one(struct pci_dev *pdev,
> goto probe_failed;
> }
>
> - if (qla2x00_initialize_adapter(ha) &&
> - !(ha->device_flags & DFLG_NO_CABLE)) {
> -
> - qla_printk(KERN_WARNING, ha,
> - "Failed to initialize adapter\n");
> -
> - DEBUG2(printk("scsi(%ld): Failed to initialize adapter - "
> - "Adapter flags %x.\n",
> - ha->host_no, ha->device_flags));
> -
> - ret = -ENODEV;
> - goto probe_failed;
> - }
> -
> - /*
> - * Startup the kernel thread for this host adapter
> - */
> - ha->dpc_thread = kthread_create(qla2x00_do_dpc, ha,
> - "%s_dpc", ha->host_str);
> - if (IS_ERR(ha->dpc_thread)) {
> - qla_printk(KERN_WARNING, ha,
> - "Unable to start DPC thread!\n");
> - ret = PTR_ERR(ha->dpc_thread);
> - goto probe_failed;
> - }
> -
> host->this_id = 255;
> host->cmd_per_lun = 3;
> host->unique_id = ha->instance;
> @@ -1579,68 +1664,12 @@ qla2x00_probe_one(struct pci_dev *pdev,
> goto probe_failed;
> }
> host->irq = pdev->irq;
> -
> - /* Initialized the timer */
> - qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL);
> -
> - DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
> - ha->host_no, ha));
> -
> - ha->isp_ops.disable_intrs(ha);
> -
> - spin_lock_irqsave(&ha->hardware_lock, flags);
> - reg = ha->iobase;
> - if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
> - WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_HOST_INT);
> - WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_RISC_INT);
> - } else {
> - WRT_REG_WORD(®->isp.semaphore, 0);
> - WRT_REG_WORD(®->isp.hccr, HCCR_CLR_RISC_INT);
> - WRT_REG_WORD(®->isp.hccr, HCCR_CLR_HOST_INT);
> -
> - /* Enable proper parity */
> - if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) {
> - if (IS_QLA2300(ha))
> - /* SRAM parity */
> - WRT_REG_WORD(®->isp.hccr,
> - (HCCR_ENABLE_PARITY + 0x1));
> - else
> - /* SRAM, Instruction RAM and GP RAM parity */
> - WRT_REG_WORD(®->isp.hccr,
> - (HCCR_ENABLE_PARITY + 0x7));
> - }
> - }
> - spin_unlock_irqrestore(&ha->hardware_lock, flags);
> -
> - ha->isp_ops.enable_intrs(ha);
> -
> - /* v2.19.5b6 */
> - /*
> - * Wait around max loop_reset_delay secs for the devices to come
> - * on-line. We don't want Linux scanning before we are ready.
> - *
> - */
> - for (wait_switch = jiffies + (ha->loop_reset_delay * HZ);
> - time_before(jiffies,wait_switch) &&
> - !(ha->device_flags & (DFLG_NO_CABLE | DFLG_FABRIC_DEVICES))
> - && (ha->device_flags & SWITCH_FOUND) ;) {
> -
> - qla2x00_check_fabric_devices(ha);
> -
> - msleep(10);
> - }
> -
> pci_set_drvdata(pdev, ha);
> - ha->flags.init_done = 1;
> - num_hosts++;
>
> ret = scsi_add_host(host, &pdev->dev);
> if (ret)
> goto probe_failed;
> -
> - qla2x00_alloc_sysfs_attr(ha);
> -
> - qla2x00_init_host_attr(ha);
> + scsi_scan_host(host);
>
> qla_printk(KERN_INFO, ha, "\n"
> " QLogic Fibre Channel HBA Driver: %s\n"
> @@ -1652,10 +1681,6 @@ qla2x00_probe_one(struct pci_dev *pdev,
> ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no,
> ha->isp_ops.fw_version_str(ha, fw_str));
>
> - /* Go with fc_rport registration. */
> - list_for_each_entry(fcport, &ha->fcports, list)
> - qla2x00_reg_remote_port(ha, fcport);
> -
> return 0;
>
> probe_failed:
> @@ -1676,17 +1701,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
> scsi_qla_host_t *ha;
>
> ha = pci_get_drvdata(pdev);
> -
> - qla2x00_free_sysfs_attr(ha);
> -
> - fc_remove_host(ha->host);
> -
> - scsi_remove_host(ha->host);
> -
> - qla2x00_free_device(ha);
> -
> - scsi_host_put(ha->host);
> -
> + qla2xxx_remove_device(ha);
> pci_set_drvdata(pdev, NULL);
> }
>
> diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
> index 148e24c..5c7d65d 100644
> --- a/drivers/scsi/scsi_scan.c
> +++ b/drivers/scsi/scsi_scan.c
> @@ -89,7 +89,13 @@ module_param_named(max_luns, max_scsi_lu
> MODULE_PARM_DESC(max_luns,
> "last scsi LUN (should be between 1 and 2^32-1)");
>
> -static char scsi_scan_type[6] = "sync";
> +#ifdef CONFIG_SCSI_SCAN_ASYNC
> +#define SCSI_SCAN_TYPE_DEFAULT "async"
> +#else
> +#define SCSI_SCAN_TYPE_DEFAULT "sync"
> +#endif
> +
> +static char scsi_scan_type[6] = SCSI_SCAN_TYPE_DEFAULT;
>
> module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO);
> MODULE_PARM_DESC(scan, "sync, async or none");
> @@ -1533,6 +1539,9 @@ void scsi_scan_target(struct device *par
> {
> struct Scsi_Host *shost = dev_to_shost(parent);
>
> + if (strncmp(scsi_scan_type, "none", 4) == 0)
> + return;
> +
> if (!shost->async_scan)
> scsi_complete_async_scans();
>
> @@ -1623,7 +1632,7 @@ static void scsi_sysfs_add_devices(struc
> * that other asynchronous scans started after this one won't affect the
> * ordering of the discovered devices.
> */
> -struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
> +static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
> {
> struct async_scan_data *data;
>
> @@ -1667,7 +1676,7 @@ struct async_scan_data *scsi_prep_async_
> * This function announces all the devices it has found to the rest
> * of the system.
> */
> -void scsi_finish_async_scan(struct async_scan_data *data)
> +static void scsi_finish_async_scan(struct async_scan_data *data)
> {
> struct Scsi_Host *shost;
>
> @@ -1700,12 +1709,25 @@ void scsi_finish_async_scan(struct async
> kfree(data);
> }
>
> -static int do_scan_async(void *_data)
> +static void do_scsi_scan_host(struct Scsi_Host *shost)
> {
> - struct async_scan_data *data = _data;
> - scsi_scan_host_selected(data->shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
> + if (shost->hostt->scan_finished) {
> + unsigned long start = jiffies;
> + if (shost->hostt->scan_start)
> + shost->hostt->scan_start(shost);
> +
> + while (!shost->hostt->scan_finished(shost, jiffies - start))
> + msleep(10);
> + } else {
> + scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
> SCAN_WILD_CARD, 0);
> + }
> +}
>
> +static int do_scan_async(void *_data)
> +{
> + struct async_scan_data *data = _data;
> + do_scsi_scan_host(data->shost);
> scsi_finish_async_scan(data);
> return 0;
> }
> @@ -1723,10 +1745,10 @@ void scsi_scan_host(struct Scsi_Host *sh
>
> data = scsi_prep_async_scan(shost);
> if (!data) {
> - scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
> - SCAN_WILD_CARD, 0);
> + do_scsi_scan_host(shost);
> return;
> }
> +
> kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
> }
> EXPORT_SYMBOL(scsi_scan_host);
> diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
> index ba5b3eb..20ebcea 100644
> --- a/include/scsi/scsi_host.h
> +++ b/include/scsi/scsi_host.h
> @@ -241,6 +241,24 @@ #endif
> void (* target_destroy)(struct scsi_target *);
>
> /*
> + * If a host has the ability to discover targets on its own instead
> + * of scanning the entire bus, it can fill in this function and
> + * call scsi_scan_host(). This function will be called periodically
> + * until it returns 1 with the scsi_host and the elapsed time of
> + * the scan in jiffies.
> + *
> + * Status: OPTIONAL
> + */
> + int (* scan_finished)(struct Scsi_Host *, unsigned long);
> +
> + /*
> + * If the host wants to be called before the scan starts, but
> + * after the midlayer has set up ready for the scan, it can fill
> + * in this function.
> + */
> + void (* scan_start)(struct Scsi_Host *);
> +
> + /*
> * fill in this function to allow the queue depth of this host
> * to be changeable (on a per device basis). returns either
> * the current queue depth setting (may be different from what
>
next prev parent reply other threads:[~2006-11-15 13:55 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-11-13 15:26 [RFC] Asynchronous scanning for FC/SAS version 3 Matthew Wilcox
2006-11-15 13:55 ` James Smart [this message]
2006-11-20 19:21 ` Andrew Vasquez
2006-11-20 20:11 ` Matthew Wilcox
2006-11-22 16:19 ` Andrew Vasquez
2006-11-22 16:22 ` [PATCH 1/2] Defer topology discovery to DPC thread during initialization Andrew Vasquez
2006-11-22 16:24 ` [PATCH 2/2] Add asynchronous scsi scanning support Andrew Vasquez
2006-11-22 17:51 ` [RFC] Asynchronous scanning for FC/SAS version 3 Matthew Wilcox
2006-11-22 19:19 ` Andrew Vasquez
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=455B1C55.1070708@emulex.com \
--to=james.smart@emulex.com \
--cc=linux-scsi@vger.kernel.org \
--cc=matthew@wil.cx \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox