summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2007-04-25 15:53:22 +0200
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-05-06 16:33:16 +0200
commit47a8617c7df6cc8b8617a3deb5a36bbae1997d13 (patch)
treeba592dbafd7f3144e3ed0a210cefe7ed89b96058
parent[SCSI] lpfc 8.1.12 : Don't process ERATT interrupts when issuing KILL_BOARD m... (diff)
downloadlinux-47a8617c7df6cc8b8617a3deb5a36bbae1997d13.tar.xz
linux-47a8617c7df6cc8b8617a3deb5a36bbae1997d13.zip
[SCSI] lpfc 8.1.12 : Add support for async scanning
Add support for async scanning Notes: This is the async scan patch to our driver from Matthew Wilcox. The async scan logic is still subject to errors in insmod/rmmod, as the async scan threads don't get shutdown when the module unloads underneath them. See http://marc.info/?l=linux-scsi&m=117551999925582&w=2 Signed-off-by: James Smart <James.Smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c305
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c2
3 files changed, 160 insertions, 150 deletions
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 9f70b5bc0950..e4454bc37782 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -200,6 +200,9 @@ void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
/* 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 5e9a839111d2..7cb92c7531ba 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -418,33 +418,6 @@ lpfc_config_port_post(struct lpfc_hba * phba)
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 */
@@ -1362,6 +1335,156 @@ 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);
+ pci_disable_msi(phba->pcidev);
+
+ lpfc_cleanup(phba);
+ 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)
@@ -1552,13 +1675,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
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;
if (phba->cfg_use_msi) {
error = pci_enable_msi(phba->pcidev);
@@ -1574,73 +1690,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
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:
@@ -1648,11 +1706,6 @@ out_free_irq:
phba->work_hba_events = 0;
free_irq(phba->pcidev->irq, phba);
pci_disable_msi(phba->pcidev);
-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:
@@ -1690,56 +1743,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);
- pci_disable_msi(phba->pcidev);
-
- lpfc_cleanup(phba);
- 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 cc0f845d8b38..f09f3d211438 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -1351,6 +1351,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,