Skip to contentSkip to conversation

Asynchronous scanning for FC/SAS

RFC New Matthew Wilcox 1 participant 1 message Oct 20, 2006

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

RFC 1/1 Asynchronous scanning for FC/SAS

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.

Also 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.

Other changes relative to scsi-misc:
- Added missing "none" case to scsi_scan_target()
- Refactor scsi_prep_async_scan/scsi_finish_async_scan so the async_scan_data is now passed into them rather than being allocated and freed by them.
- Make the above two functions static.

Relative to earlier versions of this patch:
- Add documentation for scsi_target_discovery()
- Handle errors from scsi_prep_async_scan() properly (including sync mode)
- Embed the async_scan_data in the target_discovery_data since they're both tiny structs.

Todo:
- I'd like a better name than scsi_target_discovery().
- Find out why it still doesn't actually help qla2xxx.
- 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.

Documentation/scsi/scsi_mid_low_api.txt +14 -0
index 75a535a..f7e019e 100644
@@ -388,6 +388,7 @@ Summary:
    scsi_remove_host - detach and remove all SCSI devices owned by host
    scsi_report_bus_reset - report scsi _bus_ reset observed
    scsi_scan_host - scan SCSI bus
+   scsi_target_discovery - register host as doing target discovery
    scsi_track_queue_full - track successive QUEUE_FULL events 
    scsi_unblock_requests - allow further commands to be queued to given host
    scsi_unregister - [calls scsi_host_put()]
@@ -718,6 +719,19 @@ void scsi_scan_host(struct Scsi_Host *sh
 
 
 /**
+ * scsi_target_discovery - register host as performing target discovery
+ * @shost: the host which is discovering targets
+ * @timeout: how long to wait (in jiffies)
+ * @finished: callback to determine if all targets have been discovered
+ * 
+ * Might block: yes
+ * Defined in: drivers/scsi/scsi_scan.c
+ */
+void scsi_target_discovery(struct Scsi_Host *shost, unsigned long timeout,
+                           int (*finished)(struct Scsi_Host *, unsigned long))
+
+
+/**
  * scsi_track_queue_full - track successive QUEUE_FULL events on given
  *                      device to determine if and when there is a need
  *                      to adjust the queue depth on the device.
drivers/scsi/Kconfig +17 -0
index 9540eb8..c312444 100644
@@ -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
 
drivers/scsi/aic94xx/aic94xx_init.c +14 -5
index 99743ca..8000d88 100644
@@ -546,6 +546,19 @@ static int asd_unregister_sas_ha(struct 
 	return err;
 }
 
+static int asd_finished_discovery(struct Scsi_Host *shost,
+						unsigned long elapsed_jiffies)
+{
+	/* give the phy enabling interrupt event time to come in (1s
+	 * is empirically about all it takes) */
+	if (elapsed_jiffies < 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 +690,7 @@ 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_target_discovery(shost, 30 * HZ, asd_finished_discovery);
 
 	return 0;
 Err_en_phys:
drivers/scsi/lpfc/lpfc_init.c +18 -29

71 lines not on this page · raw message

drivers/scsi/qla2xxx/qla_os.c +14 -18
index 3f20d76..74726c2 100644
@@ -1353,6 +1353,17 @@ qla24xx_disable_intrs(scsi_qla_host_t *h
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
+static int qla2x00_scan_finished(struct Scsi_Host *shost, unsigned long x)
+{
+	scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+
+	qla2x00_check_fabric_devices(ha);
+
+	if (ha->device_flags & (DFLG_NO_CABLE | DFLG_FABRIC_DEVICES))
+		return 1;
+	return !(ha->device_flags & SWITCH_FOUND);
+}
+
 /*
  * PCI driver interface
  */
@@ -1363,8 +1374,7 @@ qla2x00_probe_one(struct pci_dev *pdev, 
 	device_reg_t __iomem *reg;
 	struct Scsi_Host *host;
 	scsi_qla_host_t *ha;
-	unsigned long	flags = 0;
-	unsigned long	wait_switch = 0;
+	unsigned long flags;
 	char pci_info[20];
 	char fw_str[30];
 	fc_port_t *fcport;
@@ -1614,22 +1624,6 @@ 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);
 	ha->flags.init_done = 1;
 	num_hosts++;
@@ -1638,6 +1632,8 @@ qla2x00_probe_one(struct pci_dev *pdev, 
 	if (ret)
 		goto probe_failed;
 
+	scsi_target_discovery(host, ha->loop_reset_delay * HZ,
+				qla2x00_scan_finished);
 	qla2x00_alloc_sysfs_attr(ha);
 
 	qla2x00_init_host_attr(ha);
drivers/scsi/scsi_scan.c +106 -20

203 lines not on this page · raw message

include/scsi/scsi_host.h +3 -0
index ba5b3eb..88be61e 100644
@@ -649,6 +649,9 @@ extern void scsi_host_put(struct Scsi_Ho
 extern struct Scsi_Host *scsi_host_lookup(unsigned short);
 extern const char *scsi_host_state_name(enum scsi_host_state);
 
+void scsi_target_discovery(struct Scsi_Host *shost, unsigned long timeout,
+			   int (*finished)(struct Scsi_Host *, unsigned long));
+
 extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
 
 static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock)