[SCSI] lpfc 8.3.5: fix VPI registration, error clean up and add support for vlink...
[linux-2.6.git] / drivers / scsi / lpfc / lpfc_init.c
index d654c0e..a7b5566 100644 (file)
@@ -1669,6 +1669,10 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
                oneConnect = 1;
                m = (typeof(m)) {"OCe10100-F", max_speed, "PCIe"};
                break;
+       case PCI_DEVICE_ID_TS_BE3:
+               oneConnect = 1;
+               m = (typeof(m)) {"OCeXXXXX-F", max_speed, "PCIe"};
+               break;
        default:
                m = (typeof(m)){ NULL };
                break;
@@ -2699,6 +2703,63 @@ lpfc_sli_remove_dflt_fcf(struct lpfc_hba *phba)
 }
 
 /**
+ * lpfc_sli4_fw_cfg_check - Read the firmware config and verify FCoE support
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This function uses the QUERY_FW_CFG mailbox command to determine if the
+ * firmware loaded supports FCoE. A return of zero indicates that the mailbox
+ * was successful and the firmware supports FCoE. Any other return indicates
+ * a error. It is assumed that this function will be called before interrupts
+ * are enabled.
+ **/
+static int
+lpfc_sli4_fw_cfg_check(struct lpfc_hba *phba)
+{
+       int rc = 0;
+       LPFC_MBOXQ_t *mboxq;
+       struct lpfc_mbx_query_fw_cfg *query_fw_cfg;
+       uint32_t length;
+       uint32_t shdr_status, shdr_add_status;
+
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2621 Failed to allocate mbox for "
+                               "query firmware config cmd\n");
+               return -ENOMEM;
+       }
+       query_fw_cfg = &mboxq->u.mqe.un.query_fw_cfg;
+       length = (sizeof(struct lpfc_mbx_query_fw_cfg) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_QUERY_FW_CFG,
+                        length, LPFC_SLI4_MBX_EMBED);
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr_status = bf_get(lpfc_mbox_hdr_status,
+                            &query_fw_cfg->header.cfg_shdr.response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+                                &query_fw_cfg->header.cfg_shdr.response);
+       if (shdr_status || shdr_add_status || rc != MBX_SUCCESS) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2622 Query Firmware Config failed "
+                               "mbx status x%x, status x%x add_status x%x\n",
+                               rc, shdr_status, shdr_add_status);
+               return -EINVAL;
+       }
+       if (!bf_get(lpfc_function_mode_fcoe_i, query_fw_cfg)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2623 FCoE Function not supported by firmware. "
+                               "Function mode = %08x\n",
+                               query_fw_cfg->function_mode);
+               return -EINVAL;
+       }
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mboxq, phba->mbox_mem_pool);
+       return 0;
+}
+
+/**
  * lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code
  * @phba: pointer to lpfc hba data structure.
  * @acqe_link: pointer to the async link completion queue entry.
@@ -2918,6 +2979,9 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
 {
        uint8_t event_type = bf_get(lpfc_acqe_fcoe_event_type, acqe_fcoe);
        int rc;
+       struct lpfc_vport *vport;
+       struct lpfc_nodelist *ndlp;
+       struct Scsi_Host  *shost;
 
        phba->fc_eventTag = acqe_fcoe->event_tag;
        phba->fcoe_eventtag = acqe_fcoe->event_tag;
@@ -2925,7 +2989,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
        case LPFC_FCOE_EVENT_TYPE_NEW_FCF:
                lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
                        "2546 New FCF found index 0x%x tag 0x%x\n",
-                       acqe_fcoe->fcf_index,
+                       acqe_fcoe->index,
                        acqe_fcoe->event_tag);
                /*
                 * If the current FCF is in discovered state, or
@@ -2958,10 +3022,10 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
        case LPFC_FCOE_EVENT_TYPE_FCF_DEAD:
                lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
                        "2549 FCF disconnected fron network index 0x%x"
-                       " tag 0x%x\n", acqe_fcoe->fcf_index,
+                       " tag 0x%x\n", acqe_fcoe->index,
                        acqe_fcoe->event_tag);
                /* If the event is not for currently used fcf do nothing */
-               if (phba->fcf.fcf_indx != acqe_fcoe->fcf_index)
+               if (phba->fcf.fcf_indx != acqe_fcoe->index)
                        break;
                /*
                 * Currently, driver support only one FCF - so treat this as
@@ -2971,7 +3035,28 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
                /* Unregister FCF if no devices connected to it */
                lpfc_unregister_unused_fcf(phba);
                break;
-
+       case LPFC_FCOE_EVENT_TYPE_CVL:
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+                       "2718 Clear Virtual Link Received for VPI 0x%x"
+                       " tag 0x%x\n", acqe_fcoe->index, acqe_fcoe->event_tag);
+               vport = lpfc_find_vport_by_vpid(phba,
+                               acqe_fcoe->index /*- phba->vpi_base*/);
+               if (!vport)
+                       break;
+               ndlp = lpfc_findnode_did(vport, Fabric_DID);
+               if (!ndlp)
+                       break;
+               shost = lpfc_shost_from_vport(vport);
+               lpfc_linkdown_port(vport);
+               if (vport->port_type != LPFC_NPIV_PORT) {
+                       mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+                       spin_lock_irq(shost->host_lock);
+                       ndlp->nlp_flag |= NLP_DELAY_TMO;
+                       spin_unlock_irq(shost->host_lock);
+                       ndlp->nlp_last_elscmd = ELS_CMD_FLOGI;
+                       vport->port_state = LPFC_FLOGI;
+               }
+               break;
        default:
                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                        "0288 Unknown FCoE event type 0x%x event tag "
@@ -3463,6 +3548,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        if (unlikely(rc))
                goto out_free_bsmbx;
 
+       rc = lpfc_sli4_fw_cfg_check(phba);
+       if (unlikely(rc))
+               goto out_free_bsmbx;
+
        /* Set up the hba's configuration parameters. */
        rc = lpfc_sli4_read_config(phba);
        if (unlikely(rc))
@@ -6687,6 +6776,7 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid)
 {
        struct lpfc_hba   *phba;
        struct lpfc_vport *vport = NULL;
+       struct Scsi_Host  *shost = NULL;
        int error;
        uint32_t cfg_mode, intr_mode;
 
@@ -6765,6 +6855,7 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid)
                goto out_destroy_shost;
        }
 
+       shost = lpfc_shost_from_vport(vport); /* save shost for error cleanup */
        /* Now, trying to enable interrupt and bring up the device */
        cfg_mode = phba->cfg_use_msi;
        while (true) {
@@ -6831,6 +6922,8 @@ out_unset_pci_mem_s3:
        lpfc_sli_pci_mem_unset(phba);
 out_disable_pci_dev:
        lpfc_disable_pci_dev(phba);
+       if (shost)
+               scsi_host_put(shost);
 out_free_phba:
        lpfc_hba_free(phba);
        return error;
@@ -7214,6 +7307,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
 {
        struct lpfc_hba   *phba;
        struct lpfc_vport *vport = NULL;
+       struct Scsi_Host  *shost = NULL;
        int error;
        uint32_t cfg_mode, intr_mode;
        int mcnt;
@@ -7294,6 +7388,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
                goto out_destroy_shost;
        }
 
+       shost = lpfc_shost_from_vport(vport); /* save shost for error cleanup */
        /* Now, trying to enable interrupt and bring up the device */
        cfg_mode = phba->cfg_use_msi;
        while (true) {
@@ -7362,6 +7457,8 @@ out_unset_pci_mem_s4:
        lpfc_sli4_pci_mem_unset(phba);
 out_disable_pci_dev:
        lpfc_disable_pci_dev(phba);
+       if (shost)
+               scsi_host_put(shost);
 out_free_phba:
        lpfc_hba_free(phba);
        return error;
@@ -7936,6 +8033,8 @@ static struct pci_device_id lpfc_id_table[] = {
                PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK,
                PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TS_BE3,
+               PCI_ANY_ID, PCI_ANY_ID, },
        { 0 }
 };