]> Pileus Git - ~andy/linux/commitdiff
[SCSI] Lpfc 8.3.28: FC and SCSI Discovery Fixes
authorJames Smart <james.smart@emulex.com>
Tue, 13 Dec 2011 18:22:17 +0000 (13:22 -0500)
committerJames Bottomley <JBottomley@Parallels.com>
Thu, 15 Dec 2011 06:57:44 +0000 (10:57 +0400)
FC and SCSI Discovery Fixes:

- Clear the virtual fabrics bit (word 1 bit 30) when sending the FLOGI
  and FDISC. (CR 124339)
- Return a MLQUEUE_DEVICE_BUSY if the driver detects that an I/O is being
  retried too quickly (CR 124668)
- Remove NDLP reference put in lpfc_cmpl_els_logo_acc for all but fabric
  nodes (CR 123924)
- Only retry FDISCs every second and stop retrying after devloss number
  of retries (CR 13939)
- Check to see if vports are unloading before adding them to the vport
  work array. (CR 124996)
- Fixed illegal state transition during driver unload (CR 124191)
- Added missing protection on setting/clearing of vport->fc_flag bit (CR 126002)
- Set NPIV flag in lpfc_mbx_process_link_up for all ports sli3 and
  above. (CR 126094)
- Clear FCP command bytes that are not used. (CR 126209)

Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_scsi.h
drivers/scsi/lpfc/lpfc_vport.c

index 46876941bac6499fcb980b393aaa765ed066891d..0b662db232848ddfe22bac96f3df1c624e4cce0b 100644 (file)
@@ -1075,6 +1075,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        /* Setup CSPs accordingly for Fabric */
        sp->cmn.e_d_tov = 0;
        sp->cmn.w2.r_a_tov = 0;
+       sp->cmn.virtual_fabric_support = 0;
        sp->cls1.classValid = 0;
        sp->cls2.seqDelivery = 1;
        sp->cls3.seqDelivery = 1;
@@ -3066,17 +3067,22 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        if (did == FDMI_DID)
                retry = 1;
 
-       if (((cmd == ELS_CMD_FLOGI) || (cmd == ELS_CMD_FDISC)) &&
+       if ((cmd == ELS_CMD_FLOGI) &&
            (phba->fc_topology != LPFC_TOPOLOGY_LOOP) &&
            !lpfc_error_lost_link(irsp)) {
                /* FLOGI retry policy */
                retry = 1;
-               /* retry forever */
+               /* retry FLOGI forever */
                maxretry = 0;
                if (cmdiocb->retry >= 100)
                        delay = 5000;
                else if (cmdiocb->retry >= 32)
                        delay = 1000;
+       } else if ((cmd == ELS_CMD_FDISC) && !lpfc_error_lost_link(irsp)) {
+               /* retry FDISCs every second up to devloss */
+               retry = 1;
+               maxretry = vport->cfg_devloss_tmo;
+               delay = 1000;
        }
 
        cmdiocb->retry++;
@@ -3389,11 +3395,17 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
        /*
         * The driver received a LOGO from the rport and has ACK'd it.
-        * At this point, the driver is done so release the IOCB and
-        * remove the ndlp reference.
+        * At this point, the driver is done so release the IOCB
         */
        lpfc_els_free_iocb(phba, cmdiocb);
-       lpfc_nlp_put(ndlp);
+
+       /*
+        * Remove the ndlp reference if it's a fabric node that has
+        * sent us an unsolicted LOGO.
+        */
+       if (ndlp->nlp_type & NLP_FABRIC)
+               lpfc_nlp_put(ndlp);
+
        return;
 }
 
@@ -7231,6 +7243,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        /* Setup CSPs accordingly for Fabric */
        sp->cmn.e_d_tov = 0;
        sp->cmn.w2.r_a_tov = 0;
+       sp->cmn.virtual_fabric_support = 0;
        sp->cls1.classValid = 0;
        sp->cls2.seqDelivery = 1;
        sp->cls3.seqDelivery = 1;
index 99c76677e39425b8228b8db497dd49f0f31382e9..d96498581ebe989568ab217cc38ee026689d13a8 100644 (file)
@@ -2646,9 +2646,14 @@ lpfc_init_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 {
        struct lpfc_vport *vport = mboxq->vport;
 
-       /* VFI not supported on interface type 0, just do the flogi */
-       if (mboxq->u.mb.mbxStatus && (bf_get(lpfc_sli_intf_if_type,
-           &phba->sli4_hba.sli_intf) != LPFC_SLI_INTF_IF_TYPE_0)) {
+       /*
+        * VFI not supported on interface type 0, just do the flogi
+        * Also continue if the VFI is in use - just use the same one.
+        */
+       if (mboxq->u.mb.mbxStatus &&
+           (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+                       LPFC_SLI_INTF_IF_TYPE_0) &&
+           mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) {
                lpfc_printf_vlog(vport, KERN_ERR,
                                LOG_MBOX,
                                "2891 Init VFI mailbox failed 0x%x\n",
@@ -2922,6 +2927,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
 {
        struct lpfc_vport *vport = phba->pport;
        LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox = NULL;
+       struct Scsi_Host *shost;
        int i;
        struct lpfc_dmabuf *mp;
        int rc;
@@ -2945,6 +2951,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
        phba->fc_topology = bf_get(lpfc_mbx_read_top_topology, la);
        phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
 
+       shost = lpfc_shost_from_vport(vport);
        if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
                phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
 
@@ -2956,8 +2963,11 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
                                "1309 Link Up Event npiv not supported in loop "
                                "topology\n");
                                /* Get Loop Map information */
-               if (bf_get(lpfc_mbx_read_top_il, la))
+               if (bf_get(lpfc_mbx_read_top_il, la)) {
+                       spin_lock_irq(shost->host_lock);
                        vport->fc_flag |= FC_LBIT;
+                       spin_unlock_irq(shost->host_lock);
+               }
 
                vport->fc_myDID = bf_get(lpfc_mbx_read_top_alpa_granted, la);
                i = la->lilpBde64.tus.f.bdeSize;
@@ -3002,11 +3012,13 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
        } else {
                if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
                        if (phba->max_vpi && phba->cfg_enable_npiv &&
-                          (phba->sli_rev == 3))
+                          (phba->sli_rev >= LPFC_SLI_REV3))
                                phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
                }
                vport->fc_myDID = phba->fc_pref_DID;
+               spin_lock_irq(shost->host_lock);
                vport->fc_flag |= FC_LBIT;
+               spin_unlock_irq(shost->host_lock);
        }
        spin_unlock_irq(&phba->hbalock);
 
@@ -3593,6 +3605,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        MAILBOX_t *mb = &pmb->u.mb;
        struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
        struct lpfc_nodelist *ndlp;
+       struct Scsi_Host *shost;
 
        ndlp = (struct lpfc_nodelist *) pmb->context2;
        pmb->context1 = NULL;
@@ -3638,8 +3651,12 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                 * vport discovery */
                if (!(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG))
                        lpfc_start_fdiscs(phba);
-               else
+               else {
+                       shost = lpfc_shost_from_vport(vport);
+                       spin_lock_irq(shost->host_lock);
                        vport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG ;
+                       spin_unlock_irq(shost->host_lock);
+               }
                lpfc_do_scr_ns_plogi(phba, vport);
        }
 
index 2dd464b0f29ef3b67cea85b7cd17e9d4065c10b0..73fc5318641b36f4840f845b6a1b5aff8f14828f 100644 (file)
@@ -349,6 +349,12 @@ struct csp {
  * Word 1 Bit 31 in FLOGI response is clean address bit
  */
 #define clean_address_bit request_multiple_Nport /* Word 1, bit 31 */
+/*
+ * Word 1 Bit 30 in common service parameter is overloaded.
+ * Word 1 Bit 30 in FLOGI request is Virtual Fabrics
+ * Word 1 Bit 30 in PLOGI request is random offset
+ */
+#define virtual_fabric_support randomOffset /* Word 1, bit 30 */
 #ifdef __BIG_ENDIAN_BITFIELD
        uint16_t request_multiple_Nport:1;      /* FC Word 1, bit 31 */
        uint16_t randomOffset:1;        /* FC Word 1, bit 30 */
index 447da2a546ae5998685a25958c300beb4f678b0a..43c4c56f9e6855ddb541c91f807b0403da43148c 100644 (file)
@@ -1830,6 +1830,8 @@ struct lpfc_mbx_init_vfi {
 #define lpfc_init_vfi_hop_count_MASK   0x000000FF
 #define lpfc_init_vfi_hop_count_WORD   word4
 };
+#define MBX_VFI_IN_USE                 0x9F02
+
 
 struct lpfc_mbx_reg_vfi {
        uint32_t word1;
index 2ddd02f7c60336130e90f8a0eb5f0ba230484451..e8bb0055994316a790db82111163295efa5ba7be 100644 (file)
@@ -782,6 +782,14 @@ lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        return NLP_STE_FREED_NODE;
 }
 
+static uint32_t
+lpfc_device_recov_unused_node(struct lpfc_vport *vport,
+                       struct lpfc_nodelist *ndlp,
+                          void *arg, uint32_t evt)
+{
+       return ndlp->nlp_state;
+}
+
 static uint32_t
 lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                           void *arg, uint32_t evt)
@@ -2147,7 +2155,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
        lpfc_disc_illegal,              /* CMPL_ADISC      */
        lpfc_disc_illegal,              /* CMPL_REG_LOGIN  */
        lpfc_device_rm_unused_node,     /* DEVICE_RM       */
-       lpfc_disc_illegal,              /* DEVICE_RECOVERY */
+       lpfc_device_recov_unused_node,  /* DEVICE_RECOVERY */
 
        lpfc_rcv_plogi_plogi_issue,     /* RCV_PLOGI   PLOGI_ISSUE    */
        lpfc_rcv_prli_plogi_issue,      /* RCV_PRLI        */
index f1af3f9dead41f574c71bed3866f6e2cb3ae7628..c60f5d0b38696c022326c76e937f57e1d72a6626 100644 (file)
@@ -2913,8 +2913,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
        int_to_scsilun(lpfc_cmd->pCmd->device->lun,
                        &lpfc_cmd->fcp_cmnd->fcp_lun);
 
-       memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, 16);
-
+       memset(&fcp_cmnd->fcpCdb[0], 0, LPFC_FCP_CDB_LEN);
+       memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
        if (scsi_populate_tag_msg(scsi_cmnd, tag)) {
                switch (tag[0]) {
                case HEAD_OF_QUEUE_TAG:
@@ -3238,6 +3238,15 @@ lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
                cmnd->result = err;
                goto out_fail_command;
        }
+       /*
+        * Do not let the mid-layer retry I/O too fast. If an I/O is retried
+        * without waiting a bit then indicate that the device is busy.
+        */
+       if (cmnd->retries &&
+           time_before(jiffies, (cmnd->jiffies_at_alloc +
+                                 msecs_to_jiffies(LPFC_RETRY_PAUSE *
+                                                  cmnd->retries))))
+               return SCSI_MLQUEUE_DEVICE_BUSY;
        ndlp = rdata->pnode;
 
        if ((scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) &&
index ce645b20a6ad3eda03f03c5ccc1059406476d1f2..9075a08cf78155af9ee0a635453bbd6ff9512f31 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/byteorder.h>
 
 struct lpfc_hba;
+#define LPFC_FCP_CDB_LEN 16
 
 #define list_remove_head(list, entry, type, member)            \
        do {                                                    \
@@ -102,7 +103,7 @@ struct fcp_cmnd {
 #define  WRITE_DATA      0x01  /* Bit 0 */
 #define  READ_DATA       0x02  /* Bit 1 */
 
-       uint8_t fcpCdb[16];     /* SRB cdb field is copied here */
+       uint8_t fcpCdb[LPFC_FCP_CDB_LEN]; /* SRB cdb field is copied here */
        uint32_t fcpDl;         /* Total transfer length */
 
 };
@@ -153,5 +154,5 @@ struct lpfc_scsi_buf {
 
 #define LPFC_SCSI_DMA_EXT_SIZE 264
 #define LPFC_BPL_SIZE          1024
-
+#define LPFC_RETRY_PAUSE       300
 #define MDAC_DIRECT_CMD                  0x22
index cff6ca67415ccfc2e118e86cb4f33bd8ab53fd99..0fe188e66000da063c01feec76b557a075545258 100644 (file)
@@ -774,10 +774,10 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
                return NULL;
        spin_lock_irq(&phba->hbalock);
        list_for_each_entry(port_iterator, &phba->port_list, listentry) {
+               if (port_iterator->load_flag & FC_UNLOADING)
+                       continue;
                if (!scsi_host_get(lpfc_shost_from_vport(port_iterator))) {
-                       if (!(port_iterator->load_flag & FC_UNLOADING))
-                               lpfc_printf_vlog(port_iterator, KERN_ERR,
-                                        LOG_VPORT,
+                       lpfc_printf_vlog(port_iterator, KERN_ERR, LOG_VPORT,
                                         "1801 Create vport work array FAILED: "
                                         "cannot do scsi_host_get\n");
                        continue;