diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_els.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 160 |
1 files changed, 124 insertions, 36 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 630bd28fb997..a8f30bdaff69 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -221,7 +221,11 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, | |||
221 | /* For ELS_REQUEST64_CR, use the VPI by default */ | 221 | /* For ELS_REQUEST64_CR, use the VPI by default */ |
222 | icmd->ulpContext = vport->vpi; | 222 | icmd->ulpContext = vport->vpi; |
223 | icmd->ulpCt_h = 0; | 223 | icmd->ulpCt_h = 0; |
224 | icmd->ulpCt_l = 1; | 224 | /* The CT field must be 0=INVALID_RPI for the ECHO cmd */ |
225 | if (elscmd == ELS_CMD_ECHO) | ||
226 | icmd->ulpCt_l = 0; /* context = invalid RPI */ | ||
227 | else | ||
228 | icmd->ulpCt_l = 1; /* context = VPI */ | ||
225 | } | 229 | } |
226 | 230 | ||
227 | bpl = (struct ulp_bde64 *) pbuflist->virt; | 231 | bpl = (struct ulp_bde64 *) pbuflist->virt; |
@@ -271,7 +275,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, | |||
271 | return elsiocb; | 275 | return elsiocb; |
272 | 276 | ||
273 | els_iocb_free_pbuf_exit: | 277 | els_iocb_free_pbuf_exit: |
274 | lpfc_mbuf_free(phba, prsp->virt, prsp->phys); | 278 | if (expectRsp) |
279 | lpfc_mbuf_free(phba, prsp->virt, prsp->phys); | ||
275 | kfree(pbuflist); | 280 | kfree(pbuflist); |
276 | 281 | ||
277 | els_iocb_free_prsp_exit: | 282 | els_iocb_free_prsp_exit: |
@@ -2468,6 +2473,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
2468 | case IOSTAT_LOCAL_REJECT: | 2473 | case IOSTAT_LOCAL_REJECT: |
2469 | switch ((irsp->un.ulpWord[4] & 0xff)) { | 2474 | switch ((irsp->un.ulpWord[4] & 0xff)) { |
2470 | case IOERR_LOOP_OPEN_FAILURE: | 2475 | case IOERR_LOOP_OPEN_FAILURE: |
2476 | if (cmd == ELS_CMD_FLOGI) { | ||
2477 | if (PCI_DEVICE_ID_HORNET == | ||
2478 | phba->pcidev->device) { | ||
2479 | phba->fc_topology = TOPOLOGY_LOOP; | ||
2480 | phba->pport->fc_myDID = 0; | ||
2481 | phba->alpa_map[0] = 0; | ||
2482 | phba->alpa_map[1] = 0; | ||
2483 | } | ||
2484 | } | ||
2471 | if (cmd == ELS_CMD_PLOGI && cmdiocb->retry == 0) | 2485 | if (cmd == ELS_CMD_PLOGI && cmdiocb->retry == 0) |
2472 | delay = 1000; | 2486 | delay = 1000; |
2473 | retry = 1; | 2487 | retry = 1; |
@@ -3823,27 +3837,21 @@ lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did) | |||
3823 | while (payload_len) { | 3837 | while (payload_len) { |
3824 | rscn_did.un.word = be32_to_cpu(*lp++); | 3838 | rscn_did.un.word = be32_to_cpu(*lp++); |
3825 | payload_len -= sizeof(uint32_t); | 3839 | payload_len -= sizeof(uint32_t); |
3826 | switch (rscn_did.un.b.resv) { | 3840 | switch (rscn_did.un.b.resv & RSCN_ADDRESS_FORMAT_MASK) { |
3827 | case 0: /* Single N_Port ID effected */ | 3841 | case RSCN_ADDRESS_FORMAT_PORT: |
3828 | if (ns_did.un.word == rscn_did.un.word) | 3842 | if (ns_did.un.word == rscn_did.un.word) |
3829 | goto return_did_out; | 3843 | goto return_did_out; |
3830 | break; | 3844 | break; |
3831 | case 1: /* Whole N_Port Area effected */ | 3845 | case RSCN_ADDRESS_FORMAT_AREA: |
3832 | if ((ns_did.un.b.domain == rscn_did.un.b.domain) | 3846 | if ((ns_did.un.b.domain == rscn_did.un.b.domain) |
3833 | && (ns_did.un.b.area == rscn_did.un.b.area)) | 3847 | && (ns_did.un.b.area == rscn_did.un.b.area)) |
3834 | goto return_did_out; | 3848 | goto return_did_out; |
3835 | break; | 3849 | break; |
3836 | case 2: /* Whole N_Port Domain effected */ | 3850 | case RSCN_ADDRESS_FORMAT_DOMAIN: |
3837 | if (ns_did.un.b.domain == rscn_did.un.b.domain) | 3851 | if (ns_did.un.b.domain == rscn_did.un.b.domain) |
3838 | goto return_did_out; | 3852 | goto return_did_out; |
3839 | break; | 3853 | break; |
3840 | default: | 3854 | case RSCN_ADDRESS_FORMAT_FABRIC: |
3841 | /* Unknown Identifier in RSCN node */ | ||
3842 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, | ||
3843 | "0217 Unknown Identifier in " | ||
3844 | "RSCN payload Data: x%x\n", | ||
3845 | rscn_did.un.word); | ||
3846 | case 3: /* Whole Fabric effected */ | ||
3847 | goto return_did_out; | 3855 | goto return_did_out; |
3848 | } | 3856 | } |
3849 | } | 3857 | } |
@@ -3887,6 +3895,49 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport) | |||
3887 | } | 3895 | } |
3888 | 3896 | ||
3889 | /** | 3897 | /** |
3898 | * lpfc_send_rscn_event: Send an RSCN event to management application. | ||
3899 | * @vport: pointer to a host virtual N_Port data structure. | ||
3900 | * @cmdiocb: pointer to lpfc command iocb data structure. | ||
3901 | * | ||
3902 | * lpfc_send_rscn_event sends an RSCN netlink event to management | ||
3903 | * applications. | ||
3904 | */ | ||
3905 | static void | ||
3906 | lpfc_send_rscn_event(struct lpfc_vport *vport, | ||
3907 | struct lpfc_iocbq *cmdiocb) | ||
3908 | { | ||
3909 | struct lpfc_dmabuf *pcmd; | ||
3910 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
3911 | uint32_t *payload_ptr; | ||
3912 | uint32_t payload_len; | ||
3913 | struct lpfc_rscn_event_header *rscn_event_data; | ||
3914 | |||
3915 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
3916 | payload_ptr = (uint32_t *) pcmd->virt; | ||
3917 | payload_len = be32_to_cpu(*payload_ptr & ~ELS_CMD_MASK); | ||
3918 | |||
3919 | rscn_event_data = kmalloc(sizeof(struct lpfc_rscn_event_header) + | ||
3920 | payload_len, GFP_KERNEL); | ||
3921 | if (!rscn_event_data) { | ||
3922 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | ||
3923 | "0147 Failed to allocate memory for RSCN event\n"); | ||
3924 | return; | ||
3925 | } | ||
3926 | rscn_event_data->event_type = FC_REG_RSCN_EVENT; | ||
3927 | rscn_event_data->payload_length = payload_len; | ||
3928 | memcpy(rscn_event_data->rscn_payload, payload_ptr, | ||
3929 | payload_len); | ||
3930 | |||
3931 | fc_host_post_vendor_event(shost, | ||
3932 | fc_get_event_number(), | ||
3933 | sizeof(struct lpfc_els_event_header) + payload_len, | ||
3934 | (char *)rscn_event_data, | ||
3935 | LPFC_NL_VENDOR_ID); | ||
3936 | |||
3937 | kfree(rscn_event_data); | ||
3938 | } | ||
3939 | |||
3940 | /** | ||
3890 | * lpfc_els_rcv_rscn: Process an unsolicited rscn iocb. | 3941 | * lpfc_els_rcv_rscn: Process an unsolicited rscn iocb. |
3891 | * @vport: pointer to a host virtual N_Port data structure. | 3942 | * @vport: pointer to a host virtual N_Port data structure. |
3892 | * @cmdiocb: pointer to lpfc command iocb data structure. | 3943 | * @cmdiocb: pointer to lpfc command iocb data structure. |
@@ -3933,6 +3984,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
3933 | "0214 RSCN received Data: x%x x%x x%x x%x\n", | 3984 | "0214 RSCN received Data: x%x x%x x%x x%x\n", |
3934 | vport->fc_flag, payload_len, *lp, | 3985 | vport->fc_flag, payload_len, *lp, |
3935 | vport->fc_rscn_id_cnt); | 3986 | vport->fc_rscn_id_cnt); |
3987 | |||
3988 | /* Send an RSCN event to the management application */ | ||
3989 | lpfc_send_rscn_event(vport, cmdiocb); | ||
3990 | |||
3936 | for (i = 0; i < payload_len/sizeof(uint32_t); i++) | 3991 | for (i = 0; i < payload_len/sizeof(uint32_t); i++) |
3937 | fc_host_post_event(shost, fc_get_event_number(), | 3992 | fc_host_post_event(shost, fc_get_event_number(), |
3938 | FCH_EVT_RSCN, lp[i]); | 3993 | FCH_EVT_RSCN, lp[i]); |
@@ -4884,10 +4939,6 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) | |||
4884 | uint32_t timeout; | 4939 | uint32_t timeout; |
4885 | uint32_t remote_ID = 0xffffffff; | 4940 | uint32_t remote_ID = 0xffffffff; |
4886 | 4941 | ||
4887 | /* If the timer is already canceled do nothing */ | ||
4888 | if ((vport->work_port_events & WORKER_ELS_TMO) == 0) { | ||
4889 | return; | ||
4890 | } | ||
4891 | spin_lock_irq(&phba->hbalock); | 4942 | spin_lock_irq(&phba->hbalock); |
4892 | timeout = (uint32_t)(phba->fc_ratov << 1); | 4943 | timeout = (uint32_t)(phba->fc_ratov << 1); |
4893 | 4944 | ||
@@ -5128,7 +5179,7 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba, | |||
5128 | fc_get_event_number(), | 5179 | fc_get_event_number(), |
5129 | sizeof(lsrjt_event), | 5180 | sizeof(lsrjt_event), |
5130 | (char *)&lsrjt_event, | 5181 | (char *)&lsrjt_event, |
5131 | SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); | 5182 | LPFC_NL_VENDOR_ID); |
5132 | return; | 5183 | return; |
5133 | } | 5184 | } |
5134 | if ((rspiocbp->iocb.ulpStatus == IOSTAT_NPORT_BSY) || | 5185 | if ((rspiocbp->iocb.ulpStatus == IOSTAT_NPORT_BSY) || |
@@ -5146,7 +5197,7 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba, | |||
5146 | fc_get_event_number(), | 5197 | fc_get_event_number(), |
5147 | sizeof(fabric_event), | 5198 | sizeof(fabric_event), |
5148 | (char *)&fabric_event, | 5199 | (char *)&fabric_event, |
5149 | SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); | 5200 | LPFC_NL_VENDOR_ID); |
5150 | return; | 5201 | return; |
5151 | } | 5202 | } |
5152 | 5203 | ||
@@ -5164,32 +5215,68 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba, | |||
5164 | static void | 5215 | static void |
5165 | lpfc_send_els_event(struct lpfc_vport *vport, | 5216 | lpfc_send_els_event(struct lpfc_vport *vport, |
5166 | struct lpfc_nodelist *ndlp, | 5217 | struct lpfc_nodelist *ndlp, |
5167 | uint32_t cmd) | 5218 | uint32_t *payload) |
5168 | { | 5219 | { |
5169 | struct lpfc_els_event_header els_data; | 5220 | struct lpfc_els_event_header *els_data = NULL; |
5221 | struct lpfc_logo_event *logo_data = NULL; | ||
5170 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 5222 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
5171 | 5223 | ||
5172 | els_data.event_type = FC_REG_ELS_EVENT; | 5224 | if (*payload == ELS_CMD_LOGO) { |
5173 | switch (cmd) { | 5225 | logo_data = kmalloc(sizeof(struct lpfc_logo_event), GFP_KERNEL); |
5226 | if (!logo_data) { | ||
5227 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | ||
5228 | "0148 Failed to allocate memory " | ||
5229 | "for LOGO event\n"); | ||
5230 | return; | ||
5231 | } | ||
5232 | els_data = &logo_data->header; | ||
5233 | } else { | ||
5234 | els_data = kmalloc(sizeof(struct lpfc_els_event_header), | ||
5235 | GFP_KERNEL); | ||
5236 | if (!els_data) { | ||
5237 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | ||
5238 | "0149 Failed to allocate memory " | ||
5239 | "for ELS event\n"); | ||
5240 | return; | ||
5241 | } | ||
5242 | } | ||
5243 | els_data->event_type = FC_REG_ELS_EVENT; | ||
5244 | switch (*payload) { | ||
5174 | case ELS_CMD_PLOGI: | 5245 | case ELS_CMD_PLOGI: |
5175 | els_data.subcategory = LPFC_EVENT_PLOGI_RCV; | 5246 | els_data->subcategory = LPFC_EVENT_PLOGI_RCV; |
5176 | break; | 5247 | break; |
5177 | case ELS_CMD_PRLO: | 5248 | case ELS_CMD_PRLO: |
5178 | els_data.subcategory = LPFC_EVENT_PRLO_RCV; | 5249 | els_data->subcategory = LPFC_EVENT_PRLO_RCV; |
5179 | break; | 5250 | break; |
5180 | case ELS_CMD_ADISC: | 5251 | case ELS_CMD_ADISC: |
5181 | els_data.subcategory = LPFC_EVENT_ADISC_RCV; | 5252 | els_data->subcategory = LPFC_EVENT_ADISC_RCV; |
5253 | break; | ||
5254 | case ELS_CMD_LOGO: | ||
5255 | els_data->subcategory = LPFC_EVENT_LOGO_RCV; | ||
5256 | /* Copy the WWPN in the LOGO payload */ | ||
5257 | memcpy(logo_data->logo_wwpn, &payload[2], | ||
5258 | sizeof(struct lpfc_name)); | ||
5182 | break; | 5259 | break; |
5183 | default: | 5260 | default: |
5184 | return; | 5261 | return; |
5185 | } | 5262 | } |
5186 | memcpy(els_data.wwpn, &ndlp->nlp_portname, sizeof(struct lpfc_name)); | 5263 | memcpy(els_data->wwpn, &ndlp->nlp_portname, sizeof(struct lpfc_name)); |
5187 | memcpy(els_data.wwnn, &ndlp->nlp_nodename, sizeof(struct lpfc_name)); | 5264 | memcpy(els_data->wwnn, &ndlp->nlp_nodename, sizeof(struct lpfc_name)); |
5188 | fc_host_post_vendor_event(shost, | 5265 | if (*payload == ELS_CMD_LOGO) { |
5189 | fc_get_event_number(), | 5266 | fc_host_post_vendor_event(shost, |
5190 | sizeof(els_data), | 5267 | fc_get_event_number(), |
5191 | (char *)&els_data, | 5268 | sizeof(struct lpfc_logo_event), |
5192 | SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); | 5269 | (char *)logo_data, |
5270 | LPFC_NL_VENDOR_ID); | ||
5271 | kfree(logo_data); | ||
5272 | } else { | ||
5273 | fc_host_post_vendor_event(shost, | ||
5274 | fc_get_event_number(), | ||
5275 | sizeof(struct lpfc_els_event_header), | ||
5276 | (char *)els_data, | ||
5277 | LPFC_NL_VENDOR_ID); | ||
5278 | kfree(els_data); | ||
5279 | } | ||
5193 | 5280 | ||
5194 | return; | 5281 | return; |
5195 | } | 5282 | } |
@@ -5296,7 +5383,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
5296 | phba->fc_stat.elsRcvPLOGI++; | 5383 | phba->fc_stat.elsRcvPLOGI++; |
5297 | ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp); | 5384 | ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp); |
5298 | 5385 | ||
5299 | lpfc_send_els_event(vport, ndlp, cmd); | 5386 | lpfc_send_els_event(vport, ndlp, payload); |
5300 | if (vport->port_state < LPFC_DISC_AUTH) { | 5387 | if (vport->port_state < LPFC_DISC_AUTH) { |
5301 | if (!(phba->pport->fc_flag & FC_PT2PT) || | 5388 | if (!(phba->pport->fc_flag & FC_PT2PT) || |
5302 | (phba->pport->fc_flag & FC_PT2PT_PLOGI)) { | 5389 | (phba->pport->fc_flag & FC_PT2PT_PLOGI)) { |
@@ -5334,6 +5421,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
5334 | did, vport->port_state, ndlp->nlp_flag); | 5421 | did, vport->port_state, ndlp->nlp_flag); |
5335 | 5422 | ||
5336 | phba->fc_stat.elsRcvLOGO++; | 5423 | phba->fc_stat.elsRcvLOGO++; |
5424 | lpfc_send_els_event(vport, ndlp, payload); | ||
5337 | if (vport->port_state < LPFC_DISC_AUTH) { | 5425 | if (vport->port_state < LPFC_DISC_AUTH) { |
5338 | rjt_err = LSRJT_UNABLE_TPC; | 5426 | rjt_err = LSRJT_UNABLE_TPC; |
5339 | break; | 5427 | break; |
@@ -5346,7 +5434,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
5346 | did, vport->port_state, ndlp->nlp_flag); | 5434 | did, vport->port_state, ndlp->nlp_flag); |
5347 | 5435 | ||
5348 | phba->fc_stat.elsRcvPRLO++; | 5436 | phba->fc_stat.elsRcvPRLO++; |
5349 | lpfc_send_els_event(vport, ndlp, cmd); | 5437 | lpfc_send_els_event(vport, ndlp, payload); |
5350 | if (vport->port_state < LPFC_DISC_AUTH) { | 5438 | if (vport->port_state < LPFC_DISC_AUTH) { |
5351 | rjt_err = LSRJT_UNABLE_TPC; | 5439 | rjt_err = LSRJT_UNABLE_TPC; |
5352 | break; | 5440 | break; |
@@ -5364,7 +5452,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
5364 | "RCV ADISC: did:x%x/ste:x%x flg:x%x", | 5452 | "RCV ADISC: did:x%x/ste:x%x flg:x%x", |
5365 | did, vport->port_state, ndlp->nlp_flag); | 5453 | did, vport->port_state, ndlp->nlp_flag); |
5366 | 5454 | ||
5367 | lpfc_send_els_event(vport, ndlp, cmd); | 5455 | lpfc_send_els_event(vport, ndlp, payload); |
5368 | phba->fc_stat.elsRcvADISC++; | 5456 | phba->fc_stat.elsRcvADISC++; |
5369 | if (vport->port_state < LPFC_DISC_AUTH) { | 5457 | if (vport->port_state < LPFC_DISC_AUTH) { |
5370 | rjt_err = LSRJT_UNABLE_TPC; | 5458 | rjt_err = LSRJT_UNABLE_TPC; |