]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/lpfc/lpfc_init.c
[SCSI] lpfc 8.1.2: Fixed system panic in lpfc_sli_brdreset during dynamic add of...
[linux-2.6-omap-h63xx.git] / drivers / scsi / lpfc / lpfc_init.c
index 0856ff7d3b33d587b99e4bb72107cd34f90e2f47..369487e8f45051f7c7538f7f04d6c5add33eb2bb 100644 (file)
@@ -126,34 +126,26 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
                return -ERESTART;
        }
 
-       /* The HBA's current state is provided by the ProgType and rr fields.
-        * Read and check the value of these fields before continuing to config
-        * this port.
+       /*
+        * The value of rr must be 1 since the driver set the cv field to 1.
+        * This setting requires the FW to set all revision fields.
         */
-       if (mb->un.varRdRev.rr == 0 || mb->un.varRdRev.un.b.ProgType != 2) {
-               /* Old firmware */
+       if (mb->un.varRdRev.rr == 0) {
                vp->rev.rBit = 0;
-               lpfc_printf_log(phba,
-                               KERN_ERR,
-                               LOG_INIT,
-                               "%d:0440 Adapter failed to init, mbxCmd x%x "
-                               "READ_REV detected outdated firmware"
-                               "Data: x%x\n",
-                               phba->brd_no,
-                               mb->mbxCommand, 0);
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "%d:0440 Adapter failed to init, READ_REV has "
+                               "missing revision information.\n",
+                               phba->brd_no);
                mempool_free(pmb, phba->mbox_mem_pool);
                return -ERESTART;
-       } else {
-               vp->rev.rBit = 1;
-               vp->rev.sli1FwRev = mb->un.varRdRev.sli1FwRev;
-               memcpy(vp->rev.sli1FwName,
-                       (char*)mb->un.varRdRev.sli1FwName, 16);
-               vp->rev.sli2FwRev = mb->un.varRdRev.sli2FwRev;
-               memcpy(vp->rev.sli2FwName,
-                                       (char *)mb->un.varRdRev.sli2FwName, 16);
        }
 
        /* Save information as VPD data */
+       vp->rev.rBit = 1;
+       vp->rev.sli1FwRev = mb->un.varRdRev.sli1FwRev;
+       memcpy(vp->rev.sli1FwName, (char*) mb->un.varRdRev.sli1FwName, 16);
+       vp->rev.sli2FwRev = mb->un.varRdRev.sli2FwRev;
+       memcpy(vp->rev.sli2FwName, (char *) mb->un.varRdRev.sli2FwName, 16);
        vp->rev.biuRev = mb->un.varRdRev.biuRev;
        vp->rev.smRev = mb->un.varRdRev.smRev;
        vp->rev.smFwRev = mb->un.varRdRev.un.smFwRev;
@@ -378,6 +370,10 @@ lpfc_config_port_post(struct lpfc_hba * phba)
        if (psli->num_rings > 3)
                status |= HC_R3INT_ENA;
 
+       if ((phba->cfg_poll & ENABLE_FCP_RING_POLLING) &&
+           (phba->cfg_poll & DISABLE_FCP_RING_INT))
+               status &= ~(HC_R0INT_ENA << LPFC_FCP_RING);
+
        writel(status, phba->HCregaddr);
        readl(phba->HCregaddr); /* flush */
        spin_unlock_irq(phba->host->host_lock);
@@ -537,12 +533,6 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
 
                lpfc_offline(phba);
 
-               /*
-                * Restart all traffic to this host.  Since the fc_transport
-                * block functions (future) were not called in lpfc_offline,
-                * don't call them here.
-                */
-               scsi_unblock_requests(phba->host);
        }
 }
 
@@ -577,6 +567,8 @@ lpfc_handle_latt(struct lpfc_hba * phba)
 
        rc = -EIO;
 
+       /* Cleanup any outstanding ELS commands */
+       lpfc_els_flush_cmd(phba);
 
        psli->slistat.link_event++;
        lpfc_read_la(phba, pmb, mp);
@@ -771,82 +763,139 @@ static void
 lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
 {
        lpfc_vpd_t *vp;
-       uint32_t id;
-       char str[16];
+       uint16_t dev_id = phba->pcidev->device;
+       uint16_t dev_subid = phba->pcidev->subsystem_device;
+       uint8_t hdrtype = phba->pcidev->hdr_type;
+       char *model_str = "";
 
        vp = &phba->vpd;
-       pci_read_config_dword(phba->pcidev, PCI_VENDOR_ID, &id);
 
-       switch ((id >> 16) & 0xffff) {
+       switch (dev_id) {
        case PCI_DEVICE_ID_FIREFLY:
-               strcpy(str, "LP6000 1");
+               model_str = "LP6000 1Gb PCI";
                break;
        case PCI_DEVICE_ID_SUPERFLY:
                if (vp->rev.biuRev >= 1 && vp->rev.biuRev <= 3)
-                       strcpy(str, "LP7000 1");
+                       model_str = "LP7000 1Gb PCI";
                else
-                       strcpy(str, "LP7000E 1");
+                       model_str = "LP7000E 1Gb PCI";
                break;
        case PCI_DEVICE_ID_DRAGONFLY:
-               strcpy(str, "LP8000 1");
+               model_str = "LP8000 1Gb PCI";
                break;
        case PCI_DEVICE_ID_CENTAUR:
                if (FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID)
-                       strcpy(str, "LP9002 2");
+                       model_str = "LP9002 2Gb PCI";
                else
-                       strcpy(str, "LP9000 1");
+                       model_str = "LP9000 1Gb PCI";
                break;
        case PCI_DEVICE_ID_RFLY:
-               strcpy(str, "LP952 2");
+               model_str = "LP952 2Gb PCI";
                break;
        case PCI_DEVICE_ID_PEGASUS:
-               strcpy(str, "LP9802 2");
+               model_str = "LP9802 2Gb PCI-X";
                break;
        case PCI_DEVICE_ID_THOR:
-               strcpy(str, "LP10000 2");
+               if (hdrtype == 0x80)
+                       model_str = "LP10000DC 2Gb 2-port PCI-X";
+               else
+                       model_str = "LP10000 2Gb PCI-X";
                break;
        case PCI_DEVICE_ID_VIPER:
-               strcpy(str, "LPX1000 10");
+               model_str = "LPX1000 10Gb PCI-X";
                break;
        case PCI_DEVICE_ID_PFLY:
-               strcpy(str, "LP982 2");
+               model_str = "LP982 2Gb PCI-X";
                break;
        case PCI_DEVICE_ID_TFLY:
-               strcpy(str, "LP1050 2");
+               if (hdrtype == 0x80)
+                       model_str = "LP1050DC 2Gb 2-port PCI-X";
+               else
+                       model_str = "LP1050 2Gb PCI-X";
                break;
        case PCI_DEVICE_ID_HELIOS:
-               strcpy(str, "LP11000 4");
+               if (hdrtype == 0x80)
+                       model_str = "LP11002 4Gb 2-port PCI-X2";
+               else
+                       model_str = "LP11000 4Gb PCI-X2";
+               break;
+       case PCI_DEVICE_ID_HELIOS_SCSP:
+               model_str = "LP11000-SP 4Gb PCI-X2";
+               break;
+       case PCI_DEVICE_ID_HELIOS_DCSP:
+               model_str = "LP11002-SP 4Gb 2-port PCI-X2";
+               break;
+       case PCI_DEVICE_ID_NEPTUNE:
+               if (hdrtype == 0x80)
+                       model_str = "LPe1002 4Gb 2-port";
+               else
+                       model_str = "LPe1000 4Gb PCIe";
+               break;
+       case PCI_DEVICE_ID_NEPTUNE_SCSP:
+               model_str = "LPe1000-SP 4Gb PCIe";
+               break;
+       case PCI_DEVICE_ID_NEPTUNE_DCSP:
+               model_str = "LPe1002-SP 4Gb 2-port PCIe";
                break;
        case PCI_DEVICE_ID_BMID:
-               strcpy(str, "LP1150 4");
+               model_str = "LP1150 4Gb PCI-X2";
                break;
        case PCI_DEVICE_ID_BSMB:
-               strcpy(str, "LP111 4");
+               model_str = "LP111 4Gb PCI-X2";
                break;
        case PCI_DEVICE_ID_ZEPHYR:
-               strcpy(str, "LP11000e 4");
+               if (hdrtype == 0x80)
+                       model_str = "LPe11002 4Gb 2-port PCIe";
+               else
+                       model_str = "LPe11000 4Gb PCIe";
+               break;
+       case PCI_DEVICE_ID_ZEPHYR_SCSP:
+               model_str = "LPe11000-SP 4Gb PCIe";
+               break;
+       case PCI_DEVICE_ID_ZEPHYR_DCSP:
+               model_str = "LPe11002-SP 4Gb 2-port PCIe";
                break;
        case PCI_DEVICE_ID_ZMID:
-               strcpy(str, "LP1150e 4");
+               model_str = "LPe1150 4Gb PCIe";
                break;
        case PCI_DEVICE_ID_ZSMB:
-               strcpy(str, "LP111e 4");
+               model_str = "LPe111 4Gb PCIe";
                break;
        case PCI_DEVICE_ID_LP101:
-               strcpy(str, "LP101 2");
+               model_str = "LP101 2Gb PCI-X";
                break;
        case PCI_DEVICE_ID_LP10000S:
-               strcpy(str, "LP10000-S 2");
+               model_str = "LP10000-S 2Gb PCI";
+               break;
+       case PCI_DEVICE_ID_LP11000S:
+       case PCI_DEVICE_ID_LPE11000S:
+               switch (dev_subid) {
+               case PCI_SUBSYSTEM_ID_LP11000S:
+                       model_str = "LP11002-S 4Gb PCI-X2";
+                       break;
+               case PCI_SUBSYSTEM_ID_LP11002S:
+                       model_str = "LP11000-S 4Gb 2-port PCI-X2";
+                       break;
+               case PCI_SUBSYSTEM_ID_LPE11000S:
+                       model_str = "LPe11002-S 4Gb PCIe";
+                       break;
+               case PCI_SUBSYSTEM_ID_LPE11002S:
+                       model_str = "LPe11002-S 4Gb 2-port PCIe";
+                       break;
+               case PCI_SUBSYSTEM_ID_LPE11010S:
+                       model_str = "LPe11010-S 4Gb 10-port PCIe";
+                       break;
+               default:
+                       break;
+               }
                break;
        default:
-               memset(str, 0, 16);
                break;
        }
        if (mdp)
-               sscanf(str, "%s", mdp);
+               sscanf(model_str, "%s", mdp);
        if (descp)
-               sprintf(descp, "Emulex LightPulse %s Gigabit PCI Fibre "
-                       "Channel Adapter", str);
+               sprintf(descp, "Emulex %s Fibre Channel Adapter", model_str);
 }
 
 /**************************************************/
@@ -862,8 +911,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
                 int type)
 {
        IOCB_t *icmd;
-       struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
-       struct lpfc_iocbq *iocb = NULL;
+       struct lpfc_iocbq *iocb;
        struct lpfc_dmabuf *mp1, *mp2;
 
        cnt += pring->missbufcnt;
@@ -872,13 +920,12 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
        while (cnt > 0) {
                /* Allocate buffer for  command iocb */
                spin_lock_irq(phba->host->host_lock);
-               list_remove_head(lpfc_iocb_list, iocb, struct lpfc_iocbq, list);
+               iocb = lpfc_sli_get_iocbq(phba);
                spin_unlock_irq(phba->host->host_lock);
                if (iocb == NULL) {
                        pring->missbufcnt = cnt;
                        return cnt;
                }
-               memset(iocb, 0, sizeof (struct lpfc_iocbq));
                icmd = &iocb->iocb;
 
                /* 2 buffers can be posted per command */
@@ -888,10 +935,9 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
                    mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
                                                &mp1->phys);
                if (mp1 == 0 || mp1->virt == 0) {
-                       if (mp1)
-                               kfree(mp1);
+                       kfree(mp1);
                        spin_lock_irq(phba->host->host_lock);
-                       list_add_tail(&iocb->list, lpfc_iocb_list);
+                       lpfc_sli_release_iocbq(phba, iocb);
                        spin_unlock_irq(phba->host->host_lock);
                        pring->missbufcnt = cnt;
                        return cnt;
@@ -905,12 +951,11 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
                                mp2->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
                                                            &mp2->phys);
                        if (mp2 == 0 || mp2->virt == 0) {
-                               if (mp2)
-                                       kfree(mp2);
+                               kfree(mp2);
                                lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
                                kfree(mp1);
                                spin_lock_irq(phba->host->host_lock);
-                               list_add_tail(&iocb->list, lpfc_iocb_list);
+                               lpfc_sli_release_iocbq(phba, iocb);
                                spin_unlock_irq(phba->host->host_lock);
                                pring->missbufcnt = cnt;
                                return cnt;
@@ -947,7 +992,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
                                kfree(mp2);
                                cnt++;
                        }
-                       list_add_tail(&iocb->list, lpfc_iocb_list);
+                       lpfc_sli_release_iocbq(phba, iocb);
                        pring->missbufcnt = cnt;
                        spin_unlock_irq(phba->host->host_lock);
                        return cnt;
@@ -1192,6 +1237,7 @@ lpfc_stop_timer(struct lpfc_hba * phba)
                }
        }
 
+       del_timer_sync(&phba->fcp_poll_timer);
        del_timer_sync(&phba->fc_estabtmo);
        del_timer_sync(&phba->fc_disctmo);
        del_timer_sync(&phba->fc_fdmitmo);
@@ -1226,12 +1272,6 @@ lpfc_online(struct lpfc_hba * phba)
        phba->fc_flag &= ~FC_OFFLINE_MODE;
        spin_unlock_irq(phba->host->host_lock);
 
-       /*
-        * Restart all traffic to this host.  Since the fc_transport block
-        * functions (future) were not called in lpfc_offline, don't call them
-        * here.
-        */
-       scsi_unblock_requests(phba->host);
        return 0;
 }
 
@@ -1249,13 +1289,6 @@ lpfc_offline(struct lpfc_hba * phba)
        if (phba->fc_flag & FC_OFFLINE_MODE)
                return 0;
 
-       /*
-        * Don't call the fc_transport block api (future).  The device is
-        * going offline and causing a timer to fire in the midlayer is
-        * unproductive.  Just block all new requests until the driver
-        * comes back online.
-        */
-       scsi_block_requests(phba->host);
        psli = &phba->sli;
        pring = &psli->ring[psli->fcp_ring];
 
@@ -1333,6 +1366,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        unsigned long bar0map_len, bar2map_len;
        int error = -ENODEV, retval;
        int i;
+       uint16_t iotag;
 
        if (pci_enable_device(pdev))
                goto out;
@@ -1359,7 +1393,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
                goto out_put_host;
 
        host->unique_id = phba->brd_no;
-
+       init_MUTEX(&phba->hba_can_block);
        INIT_LIST_HEAD(&phba->ctrspbuflist);
        INIT_LIST_HEAD(&phba->rnidrspbuflist);
        INIT_LIST_HEAD(&phba->freebufList);
@@ -1383,6 +1417,10 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        psli->mbox_tmo.function = lpfc_mbox_timeout;
        psli->mbox_tmo.data = (unsigned long)phba;
 
+       init_timer(&phba->fcp_poll_timer);
+       phba->fcp_poll_timer.function = lpfc_poll_timeout;
+       phba->fcp_poll_timer.data = (unsigned long)phba;
+
        /*
         * Get all the module params for configuring this host and then
         * establish the host parameters.
@@ -1424,9 +1462,23 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        phba->pci_bar2_map = pci_resource_start(phba->pcidev, 2);
        bar2map_len        = pci_resource_len(phba->pcidev, 2);
 
-       /* Map HBA SLIM and Control Registers to a kernel virtual address. */
+       /* Map HBA SLIM to a kernel virtual address. */
        phba->slim_memmap_p      = ioremap(phba->pci_bar0_map, bar0map_len);
+       if (!phba->slim_memmap_p) {
+               error = -ENODEV;
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "ioremap failed for SLIM memory.\n");
+               goto out_idr_remove;
+       }
+
+       /* Map HBA Control Registers to a kernel virtual address. */
        phba->ctrl_regs_memmap_p = ioremap(phba->pci_bar2_map, bar2map_len);
+       if (!phba->ctrl_regs_memmap_p) {
+               error = -ENODEV;
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "ioremap failed for HBA control registers.\n");
+               goto out_iounmap_slim;
+       }
 
        /* Allocate memory for SLI-2 structures */
        phba->slim2p = dma_alloc_coherent(&phba->pcidev->dev, SLI2_SLIM_SIZE,
@@ -1434,6 +1486,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        if (!phba->slim2p)
                goto out_iounmap;
 
+       memset(phba->slim2p, 0, SLI2_SLIM_SIZE);
 
        /* Initialize the SLI Layer to run with lpfc HBAs. */
        lpfc_sli_setup(phba);
@@ -1456,6 +1509,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
                }
 
                memset(iocbq_entry, 0, sizeof(struct lpfc_iocbq));
+               iotag = lpfc_sli_next_iotag(phba, iocbq_entry);
+               if (iotag == 0) {
+                       kfree (iocbq_entry);
+                       printk(KERN_ERR "%s: failed to allocate IOTAG. "
+                              "Unloading driver.\n",
+                               __FUNCTION__);
+                       error = -ENOMEM;
+                       goto out_free_iocbq;
+               }
                spin_lock_irq(phba->host->host_lock);
                list_add(&iocbq_entry->list, &phba->lpfc_iocb_list);
                phba->total_iocbq_bufs++;
@@ -1487,6 +1549,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        host->max_cmd_len = 16;
 
        /* Initialize the list of scsi buffers used by driver for scsi IO. */
+       spin_lock_init(&phba->scsi_buf_list_lock);
        INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list);
 
        host->transportt = lpfc_transport_template;
@@ -1518,6 +1581,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        if (error)
                goto out_free_irq;
 
+       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()
@@ -1588,6 +1657,7 @@ out_free_slim:
                                                        phba->slim2p_mapping);
 out_iounmap:
        iounmap(phba->ctrl_regs_memmap_p);
+out_iounmap_slim:
        iounmap(phba->slim_memmap_p);
 out_idr_remove:
        idr_remove(&lpfc_hba_index, phba->brd_no);
@@ -1677,14 +1747,28 @@ static struct pci_device_id lpfc_id_table[] = {
                PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PFLY,
                PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_SCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_DCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS,
                PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_SCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_DCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BMID,
                PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BSMB,
                PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR,
                PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_SCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_DCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZMID,
                PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZSMB,
@@ -1695,6 +1779,10 @@ static struct pci_device_id lpfc_id_table[] = {
                PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP10000S,
                PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP11000S,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LPE11000S,
+               PCI_ANY_ID, PCI_ANY_ID, },
        { 0 }
 };