diff options
author | James Smart <james.smart@emulex.com> | 2010-11-20 23:14:19 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-12-21 13:23:58 -0500 |
commit | 63e801ce685d151c5faca8f491adc2ad2e732259 (patch) | |
tree | 6cf3db58849160580e4a5c1ce32e4ee14ed6902d /drivers/scsi/lpfc | |
parent | 98db519573e805f9f7e988fb5661da951fcb16b1 (diff) |
[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: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 31 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 9 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 6 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_logmsg.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 61 |
6 files changed, 99 insertions, 14 deletions
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 7260c3af555a..c216f4eb0e37 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c | |||
@@ -2162,7 +2162,7 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job) | |||
2162 | goto loopback_test_exit; | 2162 | goto loopback_test_exit; |
2163 | } | 2163 | } |
2164 | 2164 | ||
2165 | if (size >= BUF_SZ_4K) { | 2165 | if (full_size >= BUF_SZ_4K) { |
2166 | /* | 2166 | /* |
2167 | * Allocate memory for ioctl data. If buffer is bigger than 64k, | 2167 | * Allocate memory for ioctl data. If buffer is bigger than 64k, |
2168 | * then we allocate 64k and re-use that buffer over and over to | 2168 | * 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 | * problem with GET_FCPTARGETMAPPING... | 2171 | * problem with GET_FCPTARGETMAPPING... |
2172 | */ | 2172 | */ |
2173 | if (size <= (64 * 1024)) | 2173 | if (size <= (64 * 1024)) |
2174 | total_mem = size; | 2174 | total_mem = full_size; |
2175 | else | 2175 | else |
2176 | total_mem = 64 * 1024; | 2176 | total_mem = 64 * 1024; |
2177 | } else | 2177 | } else |
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 884f4d321799..196a7bf905a1 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -6201,7 +6201,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
6201 | cmd, did, vport->port_state); | 6201 | cmd, did, vport->port_state); |
6202 | 6202 | ||
6203 | /* Unsupported ELS command, reject */ | 6203 | /* Unsupported ELS command, reject */ |
6204 | rjt_err = LSRJT_INVALID_CMD; | 6204 | rjt_err = LSRJT_CMD_UNSUPPORTED; |
6205 | 6205 | ||
6206 | /* Unknown ELS command <elsCmd> received from NPORT <did> */ | 6206 | /* Unknown ELS command <elsCmd> received from NPORT <did> */ |
6207 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | 6207 | 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 | } | 6408 | } |
6409 | 6409 | ||
6410 | if (vport->cfg_fdmi_on) { | 6410 | if (vport->cfg_fdmi_on) { |
6411 | ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool, | 6411 | /* If this is the first time, allocate an ndlp and initialize |
6412 | GFP_KERNEL); | 6412 | * it. Otherwise, make sure the node is enabled and then do the |
6413 | * login. | ||
6414 | */ | ||
6415 | ndlp_fdmi = lpfc_findnode_did(vport, FDMI_DID); | ||
6416 | if (!ndlp_fdmi) { | ||
6417 | ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool, | ||
6418 | GFP_KERNEL); | ||
6419 | if (ndlp_fdmi) { | ||
6420 | lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID); | ||
6421 | ndlp_fdmi->nlp_type |= NLP_FABRIC; | ||
6422 | } else | ||
6423 | return; | ||
6424 | } | ||
6425 | if (!NLP_CHK_NODE_ACT(ndlp_fdmi)) | ||
6426 | ndlp_fdmi = lpfc_enable_node(vport, | ||
6427 | ndlp_fdmi, | ||
6428 | NLP_STE_NPR_NODE); | ||
6429 | |||
6413 | if (ndlp_fdmi) { | 6430 | if (ndlp_fdmi) { |
6414 | lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID); | ||
6415 | ndlp_fdmi->nlp_type |= NLP_FABRIC; | ||
6416 | lpfc_nlp_set_state(vport, ndlp_fdmi, | 6431 | lpfc_nlp_set_state(vport, ndlp_fdmi, |
6417 | NLP_STE_PLOGI_ISSUE); | 6432 | NLP_STE_PLOGI_ISSUE); |
6418 | lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, | 6433 | lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, 0); |
6419 | 0); | ||
6420 | } | 6434 | } |
6421 | } | 6435 | } |
6422 | return; | ||
6423 | } | 6436 | } |
6424 | 6437 | ||
6425 | /** | 6438 | /** |
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index a5d1695dac3d..57ab799da2e2 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -4059,6 +4059,11 @@ lpfc_unreg_hba_rpis(struct lpfc_hba *phba) | |||
4059 | int i; | 4059 | int i; |
4060 | 4060 | ||
4061 | vports = lpfc_create_vport_work_array(phba); | 4061 | vports = lpfc_create_vport_work_array(phba); |
4062 | if (!vports) { | ||
4063 | lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, | ||
4064 | "2884 Vport array allocation failed \n"); | ||
4065 | return; | ||
4066 | } | ||
4062 | for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { | 4067 | for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { |
4063 | shost = lpfc_shost_from_vport(vports[i]); | 4068 | shost = lpfc_shost_from_vport(vports[i]); |
4064 | spin_lock_irq(shost->host_lock); | 4069 | spin_lock_irq(shost->host_lock); |
@@ -5254,6 +5259,10 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) | |||
5254 | 5259 | ||
5255 | vports = lpfc_create_vport_work_array(phba); | 5260 | vports = lpfc_create_vport_work_array(phba); |
5256 | 5261 | ||
5262 | /* If driver cannot allocate memory, indicate fcf is in use */ | ||
5263 | if (!vports) | ||
5264 | return 1; | ||
5265 | |||
5257 | for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { | 5266 | for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { |
5258 | shost = lpfc_shost_from_vport(vports[i]); | 5267 | shost = lpfc_shost_from_vport(vports[i]); |
5259 | spin_lock_irq(shost->host_lock); | 5268 | spin_lock_irq(shost->host_lock); |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b3065791f303..ec8e8e819236 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -3247,10 +3247,12 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport) | |||
3247 | if (!ndlp) | 3247 | if (!ndlp) |
3248 | return 0; | 3248 | return 0; |
3249 | } | 3249 | } |
3250 | if (phba->pport->port_state < LPFC_FLOGI) | 3250 | if ((phba->pport->port_state < LPFC_FLOGI) && |
3251 | (phba->pport->port_state != LPFC_VPORT_FAILED)) | ||
3251 | return NULL; | 3252 | return NULL; |
3252 | /* If virtual link is not yet instantiated ignore CVL */ | 3253 | /* If virtual link is not yet instantiated ignore CVL */ |
3253 | if ((vport != phba->pport) && (vport->port_state < LPFC_FDISC)) | 3254 | if ((vport != phba->pport) && (vport->port_state < LPFC_FDISC) |
3255 | && (vport->port_state != LPFC_VPORT_FAILED)) | ||
3254 | return NULL; | 3256 | return NULL; |
3255 | shost = lpfc_shost_from_vport(vport); | 3257 | shost = lpfc_shost_from_vport(vport); |
3256 | if (!shost) | 3258 | if (!shost) |
diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h index bb59e9273126..e3b790e59156 100644 --- a/drivers/scsi/lpfc/lpfc_logmsg.h +++ b/drivers/scsi/lpfc/lpfc_logmsg.h | |||
@@ -33,7 +33,7 @@ | |||
33 | #define LOG_FCP_ERROR 0x00001000 /* log errors, not underruns */ | 33 | #define LOG_FCP_ERROR 0x00001000 /* log errors, not underruns */ |
34 | #define LOG_LIBDFC 0x00002000 /* Libdfc events */ | 34 | #define LOG_LIBDFC 0x00002000 /* Libdfc events */ |
35 | #define LOG_VPORT 0x00004000 /* NPIV events */ | 35 | #define LOG_VPORT 0x00004000 /* NPIV events */ |
36 | #define LOF_SECURITY 0x00008000 /* Security events */ | 36 | #define LOG_SECURITY 0x00008000 /* Security events */ |
37 | #define LOG_EVENT 0x00010000 /* CT,TEMP,DUMP, logging */ | 37 | #define LOG_EVENT 0x00010000 /* CT,TEMP,DUMP, logging */ |
38 | #define LOG_FIP 0x00020000 /* FIP events */ | 38 | #define LOG_FIP 0x00020000 /* FIP events */ |
39 | #define LOG_ALL_MSG 0xffffffff /* LOG all messages */ | 39 | #define LOG_ALL_MSG 0xffffffff /* LOG all messages */ |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 554efa6623f4..06b1655b4d59 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -5863,6 +5863,8 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, | |||
5863 | IOCB_t *icmd; | 5863 | IOCB_t *icmd; |
5864 | int numBdes = 0; | 5864 | int numBdes = 0; |
5865 | int i = 0; | 5865 | int i = 0; |
5866 | uint32_t offset = 0; /* accumulated offset in the sg request list */ | ||
5867 | int inbound = 0; /* number of sg reply entries inbound from firmware */ | ||
5866 | 5868 | ||
5867 | if (!piocbq || !sglq) | 5869 | if (!piocbq || !sglq) |
5868 | return xritag; | 5870 | return xritag; |
@@ -5897,6 +5899,20 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, | |||
5897 | */ | 5899 | */ |
5898 | bde.tus.w = le32_to_cpu(bpl->tus.w); | 5900 | bde.tus.w = le32_to_cpu(bpl->tus.w); |
5899 | sgl->sge_len = cpu_to_le32(bde.tus.f.bdeSize); | 5901 | sgl->sge_len = cpu_to_le32(bde.tus.f.bdeSize); |
5902 | /* The offsets in the sgl need to be accumulated | ||
5903 | * separately for the request and reply lists. | ||
5904 | * The request is always first, the reply follows. | ||
5905 | */ | ||
5906 | if (piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) { | ||
5907 | /* add up the reply sg entries */ | ||
5908 | if (bpl->tus.f.bdeFlags == BUFF_TYPE_BDE_64I) | ||
5909 | inbound++; | ||
5910 | /* first inbound? reset the offset */ | ||
5911 | if (inbound == 1) | ||
5912 | offset = 0; | ||
5913 | bf_set(lpfc_sli4_sge_offset, sgl, offset); | ||
5914 | offset += bde.tus.f.bdeSize; | ||
5915 | } | ||
5900 | bpl++; | 5916 | bpl++; |
5901 | sgl++; | 5917 | sgl++; |
5902 | } | 5918 | } |
@@ -6140,6 +6156,18 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, | |||
6140 | bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0); | 6156 | bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0); |
6141 | break; | 6157 | break; |
6142 | case CMD_GEN_REQUEST64_CR: | 6158 | case CMD_GEN_REQUEST64_CR: |
6159 | /* For this command calculate the xmit length of the | ||
6160 | * request bde. | ||
6161 | */ | ||
6162 | xmit_len = 0; | ||
6163 | numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize / | ||
6164 | sizeof(struct ulp_bde64); | ||
6165 | for (i = 0; i < numBdes; i++) { | ||
6166 | if (bpl[i].tus.f.bdeFlags != BUFF_TYPE_BDE_64) | ||
6167 | break; | ||
6168 | bde.tus.w = le32_to_cpu(bpl[i].tus.w); | ||
6169 | xmit_len += bde.tus.f.bdeSize; | ||
6170 | } | ||
6143 | /* word3 iocb=IO_TAG wqe=request_payload_len */ | 6171 | /* word3 iocb=IO_TAG wqe=request_payload_len */ |
6144 | wqe->gen_req.request_payload_len = xmit_len; | 6172 | wqe->gen_req.request_payload_len = xmit_len; |
6145 | /* word4 iocb=parameter wqe=relative_offset memcpy */ | 6173 | /* word4 iocb=parameter wqe=relative_offset memcpy */ |
@@ -12854,6 +12882,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) | |||
12854 | struct lpfc_nodelist *act_mbx_ndlp = NULL; | 12882 | struct lpfc_nodelist *act_mbx_ndlp = NULL; |
12855 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 12883 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
12856 | LIST_HEAD(mbox_cmd_list); | 12884 | LIST_HEAD(mbox_cmd_list); |
12885 | uint8_t restart_loop; | ||
12857 | 12886 | ||
12858 | /* Clean up internally queued mailbox commands with the vport */ | 12887 | /* Clean up internally queued mailbox commands with the vport */ |
12859 | spin_lock_irq(&phba->hbalock); | 12888 | spin_lock_irq(&phba->hbalock); |
@@ -12882,6 +12911,38 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) | |||
12882 | mb->mbox_flag |= LPFC_MBX_IMED_UNREG; | 12911 | mb->mbox_flag |= LPFC_MBX_IMED_UNREG; |
12883 | } | 12912 | } |
12884 | } | 12913 | } |
12914 | /* Cleanup any mailbox completions which are not yet processed */ | ||
12915 | do { | ||
12916 | restart_loop = 0; | ||
12917 | list_for_each_entry(mb, &phba->sli.mboxq_cmpl, list) { | ||
12918 | /* | ||
12919 | * If this mailox is already processed or it is | ||
12920 | * for another vport ignore it. | ||
12921 | */ | ||
12922 | if ((mb->vport != vport) || | ||
12923 | (mb->mbox_flag & LPFC_MBX_IMED_UNREG)) | ||
12924 | continue; | ||
12925 | |||
12926 | if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) && | ||
12927 | (mb->u.mb.mbxCommand != MBX_REG_VPI)) | ||
12928 | continue; | ||
12929 | |||
12930 | mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | ||
12931 | if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) { | ||
12932 | ndlp = (struct lpfc_nodelist *)mb->context2; | ||
12933 | /* Unregister the RPI when mailbox complete */ | ||
12934 | mb->mbox_flag |= LPFC_MBX_IMED_UNREG; | ||
12935 | restart_loop = 1; | ||
12936 | spin_unlock_irq(&phba->hbalock); | ||
12937 | spin_lock(shost->host_lock); | ||
12938 | ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; | ||
12939 | spin_unlock(shost->host_lock); | ||
12940 | spin_lock_irq(&phba->hbalock); | ||
12941 | break; | ||
12942 | } | ||
12943 | } | ||
12944 | } while (restart_loop); | ||
12945 | |||
12885 | spin_unlock_irq(&phba->hbalock); | 12946 | spin_unlock_irq(&phba->hbalock); |
12886 | 12947 | ||
12887 | /* Release the cleaned-up mailbox commands */ | 12948 | /* Release the cleaned-up mailbox commands */ |