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