Asynchronous scanning for FC/SAS
Subsystems (4)
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
@@ -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
@@ -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
@@ -546,6 +546,19 @@ static int asd_unregister_sas_ha(structreturn 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
@@ -1353,6 +1353,17 @@ qla24xx_disable_intrs(scsi_qla_host_t *hspin_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
@@ -649,6 +649,9 @@ extern void scsi_host_put(struct Scsi_Hoextern 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)