public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC] Asynchronous scanning for FC/SAS version 3
@ 2006-11-13 15:26 Matthew Wilcox
  2006-11-15 13:55 ` James Smart
  2006-11-20 19:21 ` Andrew Vasquez
  0 siblings, 2 replies; 9+ messages in thread
From: Matthew Wilcox @ 2006-11-13 15:26 UTC (permalink / raw)
  To: linux-scsi, linux-driver, james.smart


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(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
+		WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
+	} else {
+		WRT_REG_WORD(&reg->isp.semaphore, 0);
+		WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_RISC_INT);
+		WRT_REG_WORD(&reg->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(&reg->isp.hccr,
+				    (HCCR_ENABLE_PARITY + 0x1));
+			else
+				/* SRAM, Instruction RAM and GP RAM parity */
+				WRT_REG_WORD(&reg->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(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
-		WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
-	} else {
-		WRT_REG_WORD(&reg->isp.semaphore, 0);
-		WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_RISC_INT);
-		WRT_REG_WORD(&reg->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(&reg->isp.hccr,
-				    (HCCR_ENABLE_PARITY + 0x1));
-			else
-				/* SRAM, Instruction RAM and GP RAM parity */
-				WRT_REG_WORD(&reg->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

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [RFC] Asynchronous scanning for FC/SAS version 3
  2006-11-13 15:26 [RFC] Asynchronous scanning for FC/SAS version 3 Matthew Wilcox
@ 2006-11-15 13:55 ` James Smart
  2006-11-20 19:21 ` Andrew Vasquez
  1 sibling, 0 replies; 9+ messages in thread
From: James Smart @ 2006-11-15 13:55 UTC (permalink / raw)
  To: Matthew Wilcox; +Cc: linux-scsi

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(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
> +		WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
> +	} else {
> +		WRT_REG_WORD(&reg->isp.semaphore, 0);
> +		WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_RISC_INT);
> +		WRT_REG_WORD(&reg->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(&reg->isp.hccr,
> +				    (HCCR_ENABLE_PARITY + 0x1));
> +			else
> +				/* SRAM, Instruction RAM and GP RAM parity */
> +				WRT_REG_WORD(&reg->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(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
> -		WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
> -	} else {
> -		WRT_REG_WORD(&reg->isp.semaphore, 0);
> -		WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_RISC_INT);
> -		WRT_REG_WORD(&reg->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(&reg->isp.hccr,
> -				    (HCCR_ENABLE_PARITY + 0x1));
> -			else
> -				/* SRAM, Instruction RAM and GP RAM parity */
> -				WRT_REG_WORD(&reg->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
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC] Asynchronous scanning for FC/SAS version 3
  2006-11-13 15:26 [RFC] Asynchronous scanning for FC/SAS version 3 Matthew Wilcox
  2006-11-15 13:55 ` James Smart
@ 2006-11-20 19:21 ` Andrew Vasquez
  2006-11-20 20:11   ` Matthew Wilcox
  1 sibling, 1 reply; 9+ messages in thread
From: Andrew Vasquez @ 2006-11-20 19:21 UTC (permalink / raw)
  To: Matthew Wilcox; +Cc: linux-scsi, linux-driver, james.smart

On Mon, 13 Nov 2006, 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.

The main reason the qla2xxx driver delayed initialization until a
'steady' link-state was acheived, was to insure that devices would be
discovered during the first(/only)-pass scsi_scan_host().  This though
is all legacy-style scanning as FC transport aware drivers initiate
lun scannning indirectly via an fc_remote_port_add() call.

Perhaps as an alternative, I'd propose the following change to qla2xxx
intialization semantics:

- perform basic hardware configuration only (as usual)
  - allocate resources
  - load and execute firmware

- defer link (transport) negotiations to the DPC thread
  - again the code in qla2x00_initialize_adapter() to stall probe()
    completion was needed for legacy-style scanning.
  - DPC thread stalls until probe() complete.

- before probe() completes, set DPC flags to perform loop-resync logic
  (similar to what's done during cable-insertion/removal).

Benefits: user does not have to wait 20+ seconds in case the FC cable
is unplugged during driver load, code consolidation (removal of
redundant link negotiation logic during initialize_adaoter()), and
finilly, the driver no longer needs to defer the fc_remote_port_add()
calls to hold off lun-scanning prior to returning from the probe()
function.

Regards,
Andrew Vasquez

---

diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 08cb5e3..a823f0b 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -59,9 +59,6 @@ int
 qla2x00_initialize_adapter(scsi_qla_host_t *ha)
 {
 	int	rval;
-	uint8_t	restart_risc = 0;
-	uint8_t	retry;
-	uint32_t wait_time;
 
 	/* Clear adapter flags. */
 	ha->flags.online = 0;
@@ -104,87 +101,15 @@ qla2x00_initialize_adapter(scsi_qla_host
 
 	qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
 
-	retry = 10;
-	/*
-	 * Try to configure the loop.
-	 */
-	do {
-		restart_risc = 0;
-
-		/* If firmware needs to be loaded */
-		if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
-			if ((rval = ha->isp_ops.chip_diag(ha)) == QLA_SUCCESS) {
-				rval = qla2x00_setup_chip(ha);
-			}
-		}
-
-		if (rval == QLA_SUCCESS &&
-		    (rval = qla2x00_init_rings(ha)) == QLA_SUCCESS) {
-check_fw_ready_again:
-			/*
-			 * Wait for a successful LIP up to a maximum
-			 * of (in seconds): RISC login timeout value,
-			 * RISC retry count value, and port down retry
-			 * value OR a minimum of 4 seconds OR If no
-			 * cable, only 5 seconds.
-			 */
-			rval = qla2x00_fw_ready(ha);
-			if (rval == QLA_SUCCESS) {
-				clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
-
-				/* Issue a marker after FW becomes ready. */
-				qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
-
-				/*
-				 * Wait at most MAX_TARGET RSCNs for a stable
-				 * link.
-				 */
-				wait_time = 256;
-				do {
-					clear_bit(LOOP_RESYNC_NEEDED,
-					    &ha->dpc_flags);
-					rval = qla2x00_configure_loop(ha);
-
-					if (test_and_clear_bit(ISP_ABORT_NEEDED,
-					    &ha->dpc_flags)) {
-						restart_risc = 1;
-						break;
-					}
-
-					/*
-					 * If loop state change while we were
-					 * discoverying devices then wait for
-					 * LIP to complete
-					 */
-
-					if (atomic_read(&ha->loop_state) !=
-					    LOOP_READY && retry--) {
-						goto check_fw_ready_again;
-					}
-					wait_time--;
-				} while (!atomic_read(&ha->loop_down_timer) &&
-				    retry &&
-				    wait_time &&
-				    (test_bit(LOOP_RESYNC_NEEDED,
-					&ha->dpc_flags)));
-
-				if (wait_time == 0)
-					rval = QLA_FUNCTION_FAILED;
-			} else if (ha->device_flags & DFLG_NO_CABLE)
-				/* If no cable, then all is good. */
-				rval = QLA_SUCCESS;
-		}
-	} while (restart_risc && retry--);
-
-	if (rval == QLA_SUCCESS) {
-		clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
-		qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
-		ha->marker_needed = 0;
-
-		ha->flags.online = 1;
-	} else {
-		DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
+	if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
+		rval = ha->isp_ops.chip_diag(ha);
+		if (rval)
+			return (rval);
+		rval = qla2x00_setup_chip(ha);
+		if (rval)
+			return (rval);
 	}
+	rval = qla2x00_init_rings(ha);
 
 	return (rval);
 }
@@ -2208,8 +2133,7 @@ qla2x00_update_fcport(scsi_qla_host_t *h
 
 	atomic_set(&fcport->state, FCS_ONLINE);
 
-	if (ha->flags.init_done)
-		qla2x00_reg_remote_port(ha, fcport);
+	qla2x00_reg_remote_port(ha, fcport);
 }
 
 void
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 208607b..ef2c18b 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1648,7 +1648,14 @@ qla2x00_probe_one(struct pci_dev *pdev,
 	}
 
 	pci_set_drvdata(pdev, ha);
+
+	/* Start link scan. */
+	set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+	set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+	set_bit(RSCN_UPDATE, &ha->dpc_flags);
 	ha->flags.init_done = 1;
+	ha->flags.online = 1;
+
 	num_hosts++;
 
 	ret = scsi_add_host(host, &pdev->dev);
@@ -1669,10 +1676,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:

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [RFC] Asynchronous scanning for FC/SAS version 3
  2006-11-20 19:21 ` Andrew Vasquez
@ 2006-11-20 20:11   ` Matthew Wilcox
  2006-11-22 16:19     ` Andrew Vasquez
  0 siblings, 1 reply; 9+ messages in thread
From: Matthew Wilcox @ 2006-11-20 20:11 UTC (permalink / raw)
  To: Andrew Vasquez; +Cc: linux-scsi, linux-driver, james.smart

On Mon, Nov 20, 2006 at 11:21:41AM -0800, Andrew Vasquez wrote:
> The main reason the qla2xxx driver delayed initialization until a
> 'steady' link-state was acheived, was to insure that devices would be
> discovered during the first(/only)-pass scsi_scan_host().  This though
> is all legacy-style scanning as FC transport aware drivers initiate
> lun scannning indirectly via an fc_remote_port_add() call.
> 
> Perhaps as an alternative, I'd propose the following change to qla2xxx
> intialization semantics:
> 
> - perform basic hardware configuration only (as usual)
>   - allocate resources
>   - load and execute firmware
> 
> - defer link (transport) negotiations to the DPC thread
>   - again the code in qla2x00_initialize_adapter() to stall probe()
>     completion was needed for legacy-style scanning.
>   - DPC thread stalls until probe() complete.
> 
> - before probe() completes, set DPC flags to perform loop-resync logic
>   (similar to what's done during cable-insertion/removal).
> 
> Benefits: user does not have to wait 20+ seconds in case the FC cable
> is unplugged during driver load, code consolidation (removal of
> redundant link negotiation logic during initialize_adaoter()), and
> finilly, the driver no longer needs to defer the fc_remote_port_add()
> calls to hold off lun-scanning prior to returning from the probe()
> function.

This seems like a nice cleanup of some moderately complicated code.
We still need scan_start and scan_finished methods so that the midlayer
knows when the qla2xxx driver thinks it's found all the devices there
are to find.  But the patch to add those looks like it could be
significantly smaller and have less chance of being buggy.

I think it should probably look something like this:

void qla2xxx_scan_start(struct Scsi_Host *shost)
{
	set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
	set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
	set_bit(RSCN_UPDATE, &ha->dpc_flags);
	ha->flags.init_done = 1;
	ha->flags.online = 1;
}

int qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
{
	scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
	if (!ha->host)
		return 1;
	if (time > ha->loop_reset_delay * HZ)
		return 1;

	return atomic_read(&ha->loop_state) == LOOP_READY;
}


... and then add the call to scsi_scan_host() right after the call
to scsi_add_host().  Bear in mind that if async scanning is disabled,
scsi_scan_host will wait for ->scan_finished() to return true, so
everything (eg interrupts and the DPC thread) must be initialised
before calling scsi_scan_host().  But also remember that we must call
scsi_scan_host() before the driver calls scsi_scan_target() for the
first time, so anything that could trigger that happening has to be done
in ->scan_start().

Thanks for looking at this.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC] Asynchronous scanning for FC/SAS version 3
  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 17:51       ` [RFC] Asynchronous scanning for FC/SAS version 3 Matthew Wilcox
  0 siblings, 2 replies; 9+ messages in thread
From: Andrew Vasquez @ 2006-11-22 16:19 UTC (permalink / raw)
  To: Matthew Wilcox; +Cc: linux-scsi, linux-driver, james.smart, Andrew Vasquez

On Mon, 20 Nov 2006, Matthew Wilcox wrote:
> On Mon, Nov 20, 2006 at 11:21:41AM -0800, Andrew Vasquez wrote:
> > Perhaps as an alternative, I'd propose the following change to qla2xxx
> > intialization semantics:
> > 
> > - perform basic hardware configuration only (as usual)
> >   - allocate resources
> >   - load and execute firmware
> > 
> > - defer link (transport) negotiations to the DPC thread
> >   - again the code in qla2x00_initialize_adapter() to stall probe()
> >     completion was needed for legacy-style scanning.
> >   - DPC thread stalls until probe() complete.
> > 
> > - before probe() completes, set DPC flags to perform loop-resync logic
> >   (similar to what's done during cable-insertion/removal).
> > 
> > Benefits: user does not have to wait 20+ seconds in case the FC cable
> > is unplugged during driver load, code consolidation (removal of
> > redundant link negotiation logic during initialize_adaoter()), and
> > finilly, the driver no longer needs to defer the fc_remote_port_add()
> > calls to hold off lun-scanning prior to returning from the probe()
> > function.
> 
> This seems like a nice cleanup of some moderately complicated code.
> We still need scan_start and scan_finished methods so that the midlayer
> knows when the qla2xxx driver thinks it's found all the devices there
> are to find.

BTW:  side-note, this is a bit tricky, as we are dealing with a fabric
environment where ports can fall on/off a topology at any given time
(ISL removed, port disconnected, etc. can all cause a loss in fcport
visibility).  What this condition in scan_finished() is going to
catch:

+static int
+qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+       scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+
+       if (!ha->host)
+               return 1;
+       if (time > ha->loop_reset_delay * HZ)
+               return 1;
+
+       return atomic_read(&ha->loop_state) == LOOP_READY;
+}

is the *first* instance where the firmware/driver has attained a
steady link state within the topology.  The 'found all the devices
there are to find' case may or may not fall within this window...

> But the patch to add those looks like it could be
> significantly smaller and have less chance of being buggy.
> 
> I think it should probably look something like this:

Ok, I've tweaked the code a bit and have been testing with the
following two patches, the first is a cleaned-up revision of my
'alternate' proposal (from above).  The second, adds callbacks for
your scan_start/end() work.

...
> ... and then add the call to scsi_scan_host() right after the call
> to scsi_add_host().  Bear in mind that if async scanning is disabled,
> scsi_scan_host will wait for ->scan_finished() to return true, so
> everything (eg interrupts and the DPC thread) must be initialised
> before calling scsi_scan_host().

Yes, that will always be the case.

> But also remember that we must call
> scsi_scan_host() before the driver calls scsi_scan_target() for the
> first time, so anything that could trigger that happening has to be done
> in ->scan_start().

Yep.  I'll continue testing with these two patches as an alternative
to your original work:

[SCSI] Convert qla2xxx to use scsi_scan_host
http://git.parisc-linux.org/?p=linux-2.6.git;a=commitdiff;h=114cf7c818ee1ba9104dbf0574c3b39e4f3ea5ef

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/2] Defer topology discovery to DPC thread during initialization.
  2006-11-22 16:19     ` Andrew Vasquez
@ 2006-11-22 16:22       ` 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
  1 sibling, 1 reply; 9+ messages in thread
From: Andrew Vasquez @ 2006-11-22 16:22 UTC (permalink / raw)
  To: Matthew Wilcox; +Cc: linux-scsi, linux-driver, james.smart

Modify intialization semantics:

- perform basic hardware configuration only (as usual)
  - allocate resources
  - load and execute firmware

- defer link (transport) negotiations to the DPC thread
  - again the code in qla2x00_initialize_adapter() to stall probe()
    completion was needed for legacy-style scanning.
  - DPC thread stalls until probe() complete.

- before probe() completes, set DPC flags to perform loop-resync logic
  (similar to what's done during cable-insertion/removal).

Benefits: user does not have to wait 20+ seconds in case the FC cable
is unplugged during driver load, code consolidation (removal of
redundant link negotiation logic during initialize_adaoter()), and
finilly, the driver no longer needs to defer the fc_remote_port_add()
calls to hold off lun-scanning prior to returning from the probe()
function.

Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>

---
 drivers/scsi/qla2xxx/qla_init.c |   94 ++++-----------------------------------
 drivers/scsi/qla2xxx/qla_os.c   |   29 +++---------
 2 files changed, 16 insertions(+), 107 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 08cb5e3..a823f0b 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -59,9 +59,6 @@ int
 qla2x00_initialize_adapter(scsi_qla_host_t *ha)
 {
 	int	rval;
-	uint8_t	restart_risc = 0;
-	uint8_t	retry;
-	uint32_t wait_time;
 
 	/* Clear adapter flags. */
 	ha->flags.online = 0;
@@ -104,87 +101,15 @@ qla2x00_initialize_adapter(scsi_qla_host
 
 	qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
 
-	retry = 10;
-	/*
-	 * Try to configure the loop.
-	 */
-	do {
-		restart_risc = 0;
-
-		/* If firmware needs to be loaded */
-		if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
-			if ((rval = ha->isp_ops.chip_diag(ha)) == QLA_SUCCESS) {
-				rval = qla2x00_setup_chip(ha);
-			}
-		}
-
-		if (rval == QLA_SUCCESS &&
-		    (rval = qla2x00_init_rings(ha)) == QLA_SUCCESS) {
-check_fw_ready_again:
-			/*
-			 * Wait for a successful LIP up to a maximum
-			 * of (in seconds): RISC login timeout value,
-			 * RISC retry count value, and port down retry
-			 * value OR a minimum of 4 seconds OR If no
-			 * cable, only 5 seconds.
-			 */
-			rval = qla2x00_fw_ready(ha);
-			if (rval == QLA_SUCCESS) {
-				clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
-
-				/* Issue a marker after FW becomes ready. */
-				qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
-
-				/*
-				 * Wait at most MAX_TARGET RSCNs for a stable
-				 * link.
-				 */
-				wait_time = 256;
-				do {
-					clear_bit(LOOP_RESYNC_NEEDED,
-					    &ha->dpc_flags);
-					rval = qla2x00_configure_loop(ha);
-
-					if (test_and_clear_bit(ISP_ABORT_NEEDED,
-					    &ha->dpc_flags)) {
-						restart_risc = 1;
-						break;
-					}
-
-					/*
-					 * If loop state change while we were
-					 * discoverying devices then wait for
-					 * LIP to complete
-					 */
-
-					if (atomic_read(&ha->loop_state) !=
-					    LOOP_READY && retry--) {
-						goto check_fw_ready_again;
-					}
-					wait_time--;
-				} while (!atomic_read(&ha->loop_down_timer) &&
-				    retry &&
-				    wait_time &&
-				    (test_bit(LOOP_RESYNC_NEEDED,
-					&ha->dpc_flags)));
-
-				if (wait_time == 0)
-					rval = QLA_FUNCTION_FAILED;
-			} else if (ha->device_flags & DFLG_NO_CABLE)
-				/* If no cable, then all is good. */
-				rval = QLA_SUCCESS;
-		}
-	} while (restart_risc && retry--);
-
-	if (rval == QLA_SUCCESS) {
-		clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
-		qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
-		ha->marker_needed = 0;
-
-		ha->flags.online = 1;
-	} else {
-		DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
+	if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
+		rval = ha->isp_ops.chip_diag(ha);
+		if (rval)
+			return (rval);
+		rval = qla2x00_setup_chip(ha);
+		if (rval)
+			return (rval);
 	}
+	rval = qla2x00_init_rings(ha);
 
 	return (rval);
 }
@@ -2208,8 +2133,7 @@ qla2x00_update_fcport(scsi_qla_host_t *h
 
 	atomic_set(&fcport->state, FCS_ONLINE);
 
-	if (ha->flags.init_done)
-		qla2x00_reg_remote_port(ha, fcport);
+	qla2x00_reg_remote_port(ha, fcport);
 }
 
 void
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 208607b..47868b0 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1377,10 +1377,8 @@ qla2x00_probe_one(struct pci_dev *pdev,
 	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))
@@ -1631,24 +1629,15 @@ qla2x00_probe_one(struct pci_dev *pdev,
 
 	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);
+
+	/* Start link scan. */
+	set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+	set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+	set_bit(RSCN_UPDATE, &ha->dpc_flags);
 	ha->flags.init_done = 1;
+	ha->flags.online = 1;
+
 	num_hosts++;
 
 	ret = scsi_add_host(host, &pdev->dev);
@@ -1669,10 +1658,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:
-- 
1.4.4.gef06


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/2] Add asynchronous scsi scanning support.
  2006-11-22 16:22       ` [PATCH 1/2] Defer topology discovery to DPC thread during initialization Andrew Vasquez
@ 2006-11-22 16:24         ` Andrew Vasquez
  0 siblings, 0 replies; 9+ messages in thread
From: Andrew Vasquez @ 2006-11-22 16:24 UTC (permalink / raw)
  To: Matthew Wilcox; +Cc: linux-scsi, linux-driver, james.smart

Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
---

diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 47868b0..636e494 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -95,6 +95,8 @@ MODULE_PARM_DESC(ql2xqfullrampup,
  */
 static int qla2xxx_slave_configure(struct scsi_device * device);
 static int qla2xxx_slave_alloc(struct scsi_device *);
+static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time);
+static void qla2xxx_scan_start(struct Scsi_Host *);
 static void qla2xxx_slave_destroy(struct scsi_device *);
 static int qla2x00_queuecommand(struct scsi_cmnd *cmd,
 		void (*fn)(struct scsi_cmnd *));
@@ -124,6 +126,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,
@@ -1366,6 +1370,29 @@ qla24xx_disable_intrs(scsi_qla_host_t *h
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
+static void
+qla2xxx_scan_start(struct Scsi_Host *shost)
+{
+	scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+
+	set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+	set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+	set_bit(RSCN_UPDATE, &ha->dpc_flags);
+}
+
+static int
+qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+	scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+
+	if (!ha->host)
+		return 1;
+	if (time > ha->loop_reset_delay * HZ)
+		return 1;
+
+	return atomic_read(&ha->loop_state) == LOOP_READY;
+}
+
 /*
  * PCI driver interface
  */
@@ -1631,10 +1658,6 @@ qla2x00_probe_one(struct pci_dev *pdev,
 
 	pci_set_drvdata(pdev, ha);
 
-	/* Start link scan. */
-	set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
-	set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
-	set_bit(RSCN_UPDATE, &ha->dpc_flags);
 	ha->flags.init_done = 1;
 	ha->flags.online = 1;
 
@@ -1644,6 +1667,8 @@ qla2x00_probe_one(struct pci_dev *pdev,
 	if (ret)
 		goto probe_failed;
 
+	scsi_scan_host(host);
+
 	qla2x00_alloc_sysfs_attr(ha);
 
 	qla2x00_init_host_attr(ha);

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [RFC] Asynchronous scanning for FC/SAS version 3
  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 17:51       ` Matthew Wilcox
  2006-11-22 19:19         ` Andrew Vasquez
  1 sibling, 1 reply; 9+ messages in thread
From: Matthew Wilcox @ 2006-11-22 17:51 UTC (permalink / raw)
  To: Andrew Vasquez; +Cc: linux-scsi, linux-driver, james.smart

On Wed, Nov 22, 2006 at 08:19:26AM -0800, Andrew Vasquez wrote:
> > This seems like a nice cleanup of some moderately complicated code.
> > We still need scan_start and scan_finished methods so that the midlayer
> > knows when the qla2xxx driver thinks it's found all the devices there
> > are to find.
> 
> BTW:  side-note, this is a bit tricky, as we are dealing with a fabric
> environment where ports can fall on/off a topology at any given time
> (ISL removed, port disconnected, etc. can all cause a loss in fcport
> visibility).

Oh yes, I understand that.  I'm only trying to solve the situation where
the fabric is stable.

> What this condition in scan_finished() is going to
> catch:
> 
> +static int
> +qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
> +{
> +       scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
> +
> +       if (!ha->host)
> +               return 1;
> +       if (time > ha->loop_reset_delay * HZ)
> +               return 1;
> +
> +       return atomic_read(&ha->loop_state) == LOOP_READY;
> +}
> 
> is the *first* instance where the firmware/driver has attained a
> steady link state within the topology.  The 'found all the devices
> there are to find' case may or may not fall within this window...

Ah, fair point, I didn't *quite* understand the distinction between the
various flags; can you suggest a better condition to test?

> Ok, I've tweaked the code a bit and have been testing with the
> following two patches, the first is a cleaned-up revision of my
> 'alternate' proposal (from above).  The second, adds callbacks for
> your scan_start/end() work.

Thanks a lot!

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC] Asynchronous scanning for FC/SAS version 3
  2006-11-22 17:51       ` [RFC] Asynchronous scanning for FC/SAS version 3 Matthew Wilcox
@ 2006-11-22 19:19         ` Andrew Vasquez
  0 siblings, 0 replies; 9+ messages in thread
From: Andrew Vasquez @ 2006-11-22 19:19 UTC (permalink / raw)
  To: Matthew Wilcox; +Cc: linux-scsi, linux-driver, james.smart

On Wed, 22 Nov 2006, Matthew Wilcox wrote:
> On Wed, Nov 22, 2006 at 08:19:26AM -0800, Andrew Vasquez wrote:
> > +static int
> > +qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
> > +{
> > +       scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
> > +
> > +       if (!ha->host)
> > +               return 1;
> > +       if (time > ha->loop_reset_delay * HZ)
> > +               return 1;
> > +
> > +       return atomic_read(&ha->loop_state) == LOOP_READY;
> > +}
> > 
> > is the *first* instance where the firmware/driver has attained a
> > steady link state within the topology.  The 'found all the devices
> > there are to find' case may or may not fall within this window...
> 
> Ah, fair point, I didn't *quite* understand the distinction between the
> various flags; can you suggest a better condition to test?

I don't really think there's a 'better' condition to test for given
there's isn't a state at which a driver:

- knows how to define 'all devices'
- is in control of ports beyond its single interconnect (as is
  the case of a fabric) from the HBA to the switch port.

My only point is that when the LOOP_READY state is attained for the
first time, we'll have only discovered devices (ports) present at
precisely that point in time -- i.e. two seconds (one second, 10
miliseconds) later (perhaps due to some hiccup on the fabric) an RSCN
could occur, an SNS rescan performed, and some new target-capable
device is discovered...

Anyway, just something we need to keep in mind going forward... It's
also another reason why lun-discovery is triggered indirectly during
an fc_remote_port_add()...

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2006-11-22 19:19 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-11-13 15:26 [RFC] Asynchronous scanning for FC/SAS version 3 Matthew Wilcox
2006-11-15 13:55 ` James Smart
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox