Commit 63e801ce authored by James Smart's avatar James Smart Committed by James Bottomley

[SCSI] lpfc 8.3.19: Fix critical errors and crashes

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: default avatarAlex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 98db5195
...@@ -2162,7 +2162,7 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job) ...@@ -2162,7 +2162,7 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job)
goto loopback_test_exit; 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, * Allocate memory for ioctl data. If buffer is bigger than 64k,
* then we allocate 64k and re-use that buffer over and over to * 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) ...@@ -2171,7 +2171,7 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job)
* problem with GET_FCPTARGETMAPPING... * problem with GET_FCPTARGETMAPPING...
*/ */
if (size <= (64 * 1024)) if (size <= (64 * 1024))
total_mem = size; total_mem = full_size;
else else
total_mem = 64 * 1024; total_mem = 64 * 1024;
} else } else
......
...@@ -6201,7 +6201,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ...@@ -6201,7 +6201,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
cmd, did, vport->port_state); cmd, did, vport->port_state);
/* Unsupported ELS command, reject */ /* Unsupported ELS command, reject */
rjt_err = LSRJT_INVALID_CMD; rjt_err = LSRJT_CMD_UNSUPPORTED;
/* Unknown ELS command <elsCmd> received from NPORT <did> */ /* Unknown ELS command <elsCmd> received from NPORT <did> */
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, 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) ...@@ -6408,18 +6408,31 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
} }
if (vport->cfg_fdmi_on) { if (vport->cfg_fdmi_on) {
ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool, /* If this is the first time, allocate an ndlp and initialize
GFP_KERNEL); * 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) { if (ndlp_fdmi) {
lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
ndlp_fdmi->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp_fdmi, lpfc_nlp_set_state(vport, ndlp_fdmi,
NLP_STE_PLOGI_ISSUE); NLP_STE_PLOGI_ISSUE);
lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, 0);
0);
} }
} }
return;
} }
/** /**
......
...@@ -4059,6 +4059,11 @@ lpfc_unreg_hba_rpis(struct lpfc_hba *phba) ...@@ -4059,6 +4059,11 @@ lpfc_unreg_hba_rpis(struct lpfc_hba *phba)
int i; int i;
vports = lpfc_create_vport_work_array(phba); 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++) { for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
shost = lpfc_shost_from_vport(vports[i]); shost = lpfc_shost_from_vport(vports[i]);
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
...@@ -5254,6 +5259,10 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) ...@@ -5254,6 +5259,10 @@ lpfc_fcf_inuse(struct lpfc_hba *phba)
vports = lpfc_create_vport_work_array(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++) { for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
shost = lpfc_shost_from_vport(vports[i]); shost = lpfc_shost_from_vport(vports[i]);
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
......
...@@ -3247,10 +3247,12 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport) ...@@ -3247,10 +3247,12 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport)
if (!ndlp) if (!ndlp)
return 0; 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; return NULL;
/* If virtual link is not yet instantiated ignore CVL */ /* 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; return NULL;
shost = lpfc_shost_from_vport(vport); shost = lpfc_shost_from_vport(vport);
if (!shost) if (!shost)
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#define LOG_FCP_ERROR 0x00001000 /* log errors, not underruns */ #define LOG_FCP_ERROR 0x00001000 /* log errors, not underruns */
#define LOG_LIBDFC 0x00002000 /* Libdfc events */ #define LOG_LIBDFC 0x00002000 /* Libdfc events */
#define LOG_VPORT 0x00004000 /* NPIV 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_EVENT 0x00010000 /* CT,TEMP,DUMP, logging */
#define LOG_FIP 0x00020000 /* FIP events */ #define LOG_FIP 0x00020000 /* FIP events */
#define LOG_ALL_MSG 0xffffffff /* LOG all messages */ #define LOG_ALL_MSG 0xffffffff /* LOG all messages */
......
...@@ -5863,6 +5863,8 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, ...@@ -5863,6 +5863,8 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
IOCB_t *icmd; IOCB_t *icmd;
int numBdes = 0; int numBdes = 0;
int i = 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) if (!piocbq || !sglq)
return xritag; return xritag;
...@@ -5897,6 +5899,20 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, ...@@ -5897,6 +5899,20 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
*/ */
bde.tus.w = le32_to_cpu(bpl->tus.w); bde.tus.w = le32_to_cpu(bpl->tus.w);
sgl->sge_len = cpu_to_le32(bde.tus.f.bdeSize); 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++; bpl++;
sgl++; sgl++;
} }
...@@ -6140,6 +6156,18 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, ...@@ -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); bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0);
break; break;
case CMD_GEN_REQUEST64_CR: 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 */ /* word3 iocb=IO_TAG wqe=request_payload_len */
wqe->gen_req.request_payload_len = xmit_len; wqe->gen_req.request_payload_len = xmit_len;
/* word4 iocb=parameter wqe=relative_offset memcpy */ /* word4 iocb=parameter wqe=relative_offset memcpy */
...@@ -12854,6 +12882,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) ...@@ -12854,6 +12882,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
struct lpfc_nodelist *act_mbx_ndlp = NULL; struct lpfc_nodelist *act_mbx_ndlp = NULL;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
LIST_HEAD(mbox_cmd_list); LIST_HEAD(mbox_cmd_list);
uint8_t restart_loop;
/* Clean up internally queued mailbox commands with the vport */ /* Clean up internally queued mailbox commands with the vport */
spin_lock_irq(&phba->hbalock); spin_lock_irq(&phba->hbalock);
...@@ -12882,6 +12911,38 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) ...@@ -12882,6 +12911,38 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
mb->mbox_flag |= LPFC_MBX_IMED_UNREG; 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); spin_unlock_irq(&phba->hbalock);
/* Release the cleaned-up mailbox commands */ /* Release the cleaned-up mailbox commands */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment