]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/scsi/lpfc/lpfc_init.c
PCI: add pci_try_set_mwi
[mirror_ubuntu-artful-kernel.git] / drivers / scsi / lpfc / lpfc_init.c
index 4df0a77ab12e432043a6a864eec1d4ef8b78504a..955b2e48d04192579615d6030311e43688b2aae9 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -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                                                */
@@ -930,6 +903,24 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
                m = (typeof(m)){"LPe11000-S", max_speed,
                        "PCIe"};
                break;
+       case PCI_DEVICE_ID_SAT:
+               m = (typeof(m)){"LPe12000", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_MID:
+               m = (typeof(m)){"LPe1250", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_SMB:
+               m = (typeof(m)){"LPe121", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_DCSP:
+               m = (typeof(m)){"LPe12002-SP", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_SCSP:
+               m = (typeof(m)){"LPe12000-SP", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_S:
+               m = (typeof(m)){"LPe12000-S", max_speed, "PCIe"};
+               break;
        default:
                m = (typeof(m)){ NULL };
                break;
@@ -1185,63 +1176,11 @@ lpfc_cleanup(struct lpfc_hba * phba)
 
        /* clean up phba - lpfc specific */
        lpfc_can_disctmo(phba);
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpunmap_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpmap_list,
-                                nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
-                               nlp_listp) {
-               lpfc_drop_node(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+               lpfc_nlp_put(ndlp);
 
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_reglogin_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_prli_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
+       INIT_LIST_HEAD(&phba->fc_nodes);
 
-       INIT_LIST_HEAD(&phba->fc_nlpmap_list);
-       INIT_LIST_HEAD(&phba->fc_nlpunmap_list);
-       INIT_LIST_HEAD(&phba->fc_unused_list);
-       INIT_LIST_HEAD(&phba->fc_plogi_list);
-       INIT_LIST_HEAD(&phba->fc_adisc_list);
-       INIT_LIST_HEAD(&phba->fc_reglogin_list);
-       INIT_LIST_HEAD(&phba->fc_prli_list);
-       INIT_LIST_HEAD(&phba->fc_npr_list);
-
-       phba->fc_map_cnt   = 0;
-       phba->fc_unmap_cnt = 0;
-       phba->fc_plogi_cnt = 0;
-       phba->fc_adisc_cnt = 0;
-       phba->fc_reglogin_cnt = 0;
-       phba->fc_prli_cnt  = 0;
-       phba->fc_npr_cnt   = 0;
-       phba->fc_unused_cnt= 0;
        return;
 }
 
@@ -1336,8 +1275,6 @@ void
 lpfc_offline_prep(struct lpfc_hba * phba)
 {
        struct lpfc_nodelist  *ndlp, *next_ndlp;
-       struct list_head *listp, *node_list[7];
-       int i;
 
        if (phba->fc_flag & FC_OFFLINE_MODE)
                return;
@@ -1347,21 +1284,9 @@ lpfc_offline_prep(struct lpfc_hba * phba)
        lpfc_linkdown(phba);
 
        /* Issue an unreg_login to all nodes */
-       node_list[0] = &phba->fc_npr_list;  /* MUST do this list first */
-       node_list[1] = &phba->fc_nlpmap_list;
-       node_list[2] = &phba->fc_nlpunmap_list;
-       node_list[3] = &phba->fc_prli_list;
-       node_list[4] = &phba->fc_reglogin_list;
-       node_list[5] = &phba->fc_adisc_list;
-       node_list[6] = &phba->fc_plogi_list;
-       for (i = 0; i < 7; i++) {
-               listp = node_list[i];
-               if (list_empty(listp))
-                       continue;
-
-               list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp)
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+               if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
                        lpfc_unreg_rpi(phba, ndlp);
-       }
 
        lpfc_sli_flush_mbox_queue(phba);
 }
@@ -1428,6 +1353,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)
@@ -1500,22 +1575,10 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        host->max_lun = phba->cfg_max_luns;
        host->this_id = -1;
 
-       /* Initialize all internally managed lists. */
-       INIT_LIST_HEAD(&phba->fc_nlpmap_list);
-       INIT_LIST_HEAD(&phba->fc_nlpunmap_list);
-       INIT_LIST_HEAD(&phba->fc_unused_list);
-       INIT_LIST_HEAD(&phba->fc_plogi_list);
-       INIT_LIST_HEAD(&phba->fc_adisc_list);
-       INIT_LIST_HEAD(&phba->fc_reglogin_list);
-       INIT_LIST_HEAD(&phba->fc_prli_list);
-       INIT_LIST_HEAD(&phba->fc_npr_list);
-
+       INIT_LIST_HEAD(&phba->fc_nodes);
 
        pci_set_master(pdev);
-       retval = pci_set_mwi(pdev);
-       if (retval)
-               dev_printk(KERN_WARNING, &pdev->dev,
-                          "Warning: pci_set_mwi returned %d\n", retval);
+       pci_try_set_mwi(pdev);
 
        if (pci_set_dma_mask(phba->pcidev, DMA_64BIT_MASK) != 0)
                if (pci_set_dma_mask(phba->pcidev, DMA_32BIT_MASK) != 0)
@@ -1627,13 +1690,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);
@@ -1649,73 +1705,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);
+       scsi_scan_host(host);
 
-       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;
-
-       spin_lock_irq(phba->host->host_lock);
-       phba->fc_flag &= ~FC_LOADING;
-       spin_unlock_irq(phba->host->host_lock);
        return 0;
 
 out_free_irq:
@@ -1723,11 +1721,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:
@@ -1765,56 +1758,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);
 }
@@ -1959,6 +1904,18 @@ static struct pci_device_id lpfc_id_table[] = {
                PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LPE11000S,
                PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_MID,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SMB,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_DCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_S,
+               PCI_ANY_ID, PCI_ANY_ID, },
        { 0 }
 };