]> git.karo-electronics.de Git - linux-beck.git/commitdiff
[SCSI] lpfc 8.3.19: Fix critical errors and crashes
authorJames Smart <james.smart@emulex.com>
Sun, 21 Nov 2010 04:14:19 +0000 (23:14 -0500)
committerJames Bottomley <James.Bottomley@suse.de>
Tue, 21 Dec 2010 18:23:58 +0000 (12:23 -0600)
Fix critical errors and crashes

- Replace LOF_SECURITY with LOG_SECURITY
- When calculating diag test memory size, use full size with header.
- Return LS_RJT with status=UNSUPPORTED on unrecognized ELS's
- Correct NULL pointer dereference when lpfc_create_vport_work_array()
  returns NULL.
- Added code to handle CVL when port is in LPFC_VPORT_FAILED state.
- In lpfc_do_scr_ns_plogi, check the nodelist for FDMI_DID and reuse
  the resource.
- Check for generic request 64 and calculate the sgl offset for the request
  and reply sgls, also calculate the xmit length using only the request bde.

Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/lpfc/lpfc_bsg.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_logmsg.h
drivers/scsi/lpfc/lpfc_sli.c

index 7260c3af555a0723924553fb362cb88aee742cd5..c216f4eb0e375d7958f73a08219eded012db9c9b 100644 (file)
@@ -2162,7 +2162,7 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job)
                goto loopback_test_exit;
        }
 
-       if (size >= BUF_SZ_4K) {
+       if (full_size >= BUF_SZ_4K) {
                /*
                 * Allocate memory for ioctl data. If buffer is bigger than 64k,
                 * then we allocate 64k and re-use that buffer over and over to
@@ -2171,7 +2171,7 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job)
                 * problem with GET_FCPTARGETMAPPING...
                 */
                if (size <= (64 * 1024))
-                       total_mem = size;
+                       total_mem = full_size;
                else
                        total_mem = 64 * 1024;
        } else
index 884f4d321799cffda5bb5ea56295d4166fb0b32c..196a7bf905a135c90714836b02e3be8f1c95da5c 100644 (file)
@@ -6201,7 +6201,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        cmd, did, vport->port_state);
 
                /* Unsupported ELS command, reject */
-               rjt_err = LSRJT_INVALID_CMD;
+               rjt_err = LSRJT_CMD_UNSUPPORTED;
 
                /* Unknown ELS command <elsCmd> received from NPORT <did> */
                lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
@@ -6408,18 +6408,31 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
        }
 
        if (vport->cfg_fdmi_on) {
-               ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
-                                         GFP_KERNEL);
+               /* If this is the first time, allocate an ndlp and initialize
+                * it. Otherwise, make sure the node is enabled and then do the
+                * login.
+                */
+               ndlp_fdmi = lpfc_findnode_did(vport, FDMI_DID);
+               if (!ndlp_fdmi) {
+                       ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
+                                                 GFP_KERNEL);
+                       if (ndlp_fdmi) {
+                               lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
+                               ndlp_fdmi->nlp_type |= NLP_FABRIC;
+                       } else
+                               return;
+               }
+               if (!NLP_CHK_NODE_ACT(ndlp_fdmi))
+                       ndlp_fdmi = lpfc_enable_node(vport,
+                                                    ndlp_fdmi,
+                                                    NLP_STE_NPR_NODE);
+
                if (ndlp_fdmi) {
-                       lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
-                       ndlp_fdmi->nlp_type |= NLP_FABRIC;
                        lpfc_nlp_set_state(vport, ndlp_fdmi,
-                               NLP_STE_PLOGI_ISSUE);
-                       lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID,
-                                            0);
+                                          NLP_STE_PLOGI_ISSUE);
+                       lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, 0);
                }
        }
-       return;
 }
 
 /**
index a5d1695dac3dcd73b1e5cae6651c46c602d57d20..57ab799da2e20663ea95c3bf4470f6f34165e696 100644 (file)
@@ -4059,6 +4059,11 @@ lpfc_unreg_hba_rpis(struct lpfc_hba *phba)
        int i;
 
        vports = lpfc_create_vport_work_array(phba);
+       if (!vports) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+                       "2884 Vport array allocation failed \n");
+               return;
+       }
        for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                shost = lpfc_shost_from_vport(vports[i]);
                spin_lock_irq(shost->host_lock);
@@ -5254,6 +5259,10 @@ lpfc_fcf_inuse(struct lpfc_hba *phba)
 
        vports = lpfc_create_vport_work_array(phba);
 
+       /* If driver cannot allocate memory, indicate fcf is in use */
+       if (!vports)
+               return 1;
+
        for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                shost = lpfc_shost_from_vport(vports[i]);
                spin_lock_irq(shost->host_lock);
index b3065791f30333b9667dcb0f9d3d222facb76fc0..ec8e8e81923627375acb0235d5062e3066b5424d 100644 (file)
@@ -3247,10 +3247,12 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport)
                if (!ndlp)
                        return 0;
        }
-       if (phba->pport->port_state < LPFC_FLOGI)
+       if ((phba->pport->port_state < LPFC_FLOGI) &&
+               (phba->pport->port_state != LPFC_VPORT_FAILED))
                return NULL;
        /* If virtual link is not yet instantiated ignore CVL */
-       if ((vport != phba->pport) && (vport->port_state < LPFC_FDISC))
+       if ((vport != phba->pport) && (vport->port_state < LPFC_FDISC)
+               && (vport->port_state != LPFC_VPORT_FAILED))
                return NULL;
        shost = lpfc_shost_from_vport(vport);
        if (!shost)
index bb59e927312674b4ff6fea061ca6549120290507..e3b790e5915624794284b5c2e420caee58fe6114 100644 (file)
@@ -33,7 +33,7 @@
 #define LOG_FCP_ERROR  0x00001000      /* log errors, not underruns */
 #define LOG_LIBDFC     0x00002000      /* Libdfc events */
 #define LOG_VPORT      0x00004000      /* NPIV events */
-#define LOF_SECURITY   0x00008000      /* Security events */
+#define LOG_SECURITY   0x00008000      /* Security events */
 #define LOG_EVENT      0x00010000      /* CT,TEMP,DUMP, logging */
 #define LOG_FIP                0x00020000      /* FIP events */
 #define LOG_ALL_MSG    0xffffffff      /* LOG all messages */
index 554efa6623f4edab7154e3f1ad23e5be845260c6..06b1655b4d594fbb50b9353d88845aef590001ab 100644 (file)
@@ -5863,6 +5863,8 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
        IOCB_t *icmd;
        int numBdes = 0;
        int i = 0;
+       uint32_t offset = 0; /* accumulated offset in the sg request list */
+       int inbound = 0; /* number of sg reply entries inbound from firmware */
 
        if (!piocbq || !sglq)
                return xritag;
@@ -5897,6 +5899,20 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
                         */
                        bde.tus.w = le32_to_cpu(bpl->tus.w);
                        sgl->sge_len = cpu_to_le32(bde.tus.f.bdeSize);
+                       /* The offsets in the sgl need to be accumulated
+                        * separately for the request and reply lists.
+                        * The request is always first, the reply follows.
+                        */
+                       if (piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) {
+                               /* add up the reply sg entries */
+                               if (bpl->tus.f.bdeFlags == BUFF_TYPE_BDE_64I)
+                                       inbound++;
+                               /* first inbound? reset the offset */
+                               if (inbound == 1)
+                                       offset = 0;
+                               bf_set(lpfc_sli4_sge_offset, sgl, offset);
+                               offset += bde.tus.f.bdeSize;
+                       }
                        bpl++;
                        sgl++;
                }
@@ -6140,6 +6156,18 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0);
        break;
        case CMD_GEN_REQUEST64_CR:
+               /* For this command calculate the xmit length of the
+                * request bde.
+                */
+               xmit_len = 0;
+               numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize /
+                       sizeof(struct ulp_bde64);
+               for (i = 0; i < numBdes; i++) {
+                       if (bpl[i].tus.f.bdeFlags != BUFF_TYPE_BDE_64)
+                               break;
+                       bde.tus.w = le32_to_cpu(bpl[i].tus.w);
+                       xmit_len += bde.tus.f.bdeSize;
+               }
                /* word3 iocb=IO_TAG wqe=request_payload_len */
                wqe->gen_req.request_payload_len = xmit_len;
                /* word4 iocb=parameter wqe=relative_offset memcpy */
@@ -12854,6 +12882,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
        struct lpfc_nodelist *act_mbx_ndlp = NULL;
        struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
        LIST_HEAD(mbox_cmd_list);
+       uint8_t restart_loop;
 
        /* Clean up internally queued mailbox commands with the vport */
        spin_lock_irq(&phba->hbalock);
@@ -12882,6 +12911,38 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
                        mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
                }
        }
+       /* Cleanup any mailbox completions which are not yet processed */
+       do {
+               restart_loop = 0;
+               list_for_each_entry(mb, &phba->sli.mboxq_cmpl, list) {
+                       /*
+                        * If this mailox is already processed or it is
+                        * for another vport ignore it.
+                        */
+                       if ((mb->vport != vport) ||
+                               (mb->mbox_flag & LPFC_MBX_IMED_UNREG))
+                               continue;
+
+                       if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) &&
+                               (mb->u.mb.mbxCommand != MBX_REG_VPI))
+                               continue;
+
+                       mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+                       if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
+                               ndlp = (struct lpfc_nodelist *)mb->context2;
+                               /* Unregister the RPI when mailbox complete */
+                               mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
+                               restart_loop = 1;
+                               spin_unlock_irq(&phba->hbalock);
+                               spin_lock(shost->host_lock);
+                               ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
+                               spin_unlock(shost->host_lock);
+                               spin_lock_irq(&phba->hbalock);
+                               break;
+                       }
+               }
+       } while (restart_loop);
+
        spin_unlock_irq(&phba->hbalock);
 
        /* Release the cleaned-up mailbox commands */