diff options
author | James Smart <James.Smart@Emulex.Com> | 2007-06-17 20:56:37 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-06-17 23:06:27 -0400 |
commit | ed957684294618602b48f1950b0c9bbcb036583f (patch) | |
tree | 4e88dbb2e55013f973ad94099e2963dd507ea719 /drivers/scsi/lpfc/lpfc_els.c | |
parent | 2e0fef85e098f6794956b8b80b111179fbb4cbb7 (diff) |
[SCSI] lpfc: NPIV: add SLI-3 interface
NPIV support is only available via new adapter interface extensions,
termed SLI-3. This interface changes some of the basic behaviors such
as command and response ring element sizes and data structures, as
well as a change in buffer posting. Note: the new firmware extensions
are found only on our mid-range and enterprise 4Gig adapters - so NPIV
support is available only on these newer adapters. The latest firmware
can be downloaded from the Emulex support page.
Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_els.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 273 |
1 files changed, 146 insertions, 127 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 0af33bead302..d48247b3b654 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -45,9 +45,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) | |||
45 | { | 45 | { |
46 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 46 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
47 | struct lpfc_hba *phba = vport->phba; | 47 | struct lpfc_hba *phba = vport->phba; |
48 | LPFC_MBOXQ_t *mbox; | ||
49 | uint32_t ha_copy; | 48 | uint32_t ha_copy; |
50 | int rc; | ||
51 | 49 | ||
52 | if (vport->port_state >= LPFC_VPORT_READY || | 50 | if (vport->port_state >= LPFC_VPORT_READY || |
53 | phba->link_state == LPFC_LINK_DOWN) | 51 | phba->link_state == LPFC_LINK_DOWN) |
@@ -76,20 +74,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) | |||
76 | spin_unlock_irq(shost->host_lock); | 74 | spin_unlock_irq(shost->host_lock); |
77 | 75 | ||
78 | if (phba->link_state != LPFC_CLEAR_LA) { | 76 | if (phba->link_state != LPFC_CLEAR_LA) { |
79 | if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) { | 77 | lpfc_issue_clear_la(phba, vport); |
80 | phba->link_state = LPFC_CLEAR_LA; | ||
81 | lpfc_clear_la(phba, mbox); | ||
82 | mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; | ||
83 | mbox->vport = vport; | ||
84 | printk(KERN_ERR "%s (%d): do clear_la\n", | ||
85 | __FUNCTION__, __LINE__); | ||
86 | rc = lpfc_sli_issue_mbox(phba, mbox, | ||
87 | (MBX_NOWAIT | MBX_STOP_IOCB)); | ||
88 | if (rc == MBX_NOT_FINISHED) { | ||
89 | mempool_free(mbox, phba->mbox_mem_pool); | ||
90 | phba->link_state = LPFC_HBA_ERROR; | ||
91 | } | ||
92 | } | ||
93 | } | 78 | } |
94 | 79 | ||
95 | return 1; | 80 | return 1; |
@@ -153,8 +138,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, | |||
153 | /* Allocate buffer for Buffer ptr list */ | 138 | /* Allocate buffer for Buffer ptr list */ |
154 | pbuflist = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); | 139 | pbuflist = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); |
155 | if (pbuflist) | 140 | if (pbuflist) |
156 | pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI, | 141 | pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI, |
157 | &pbuflist->phys); | 142 | &pbuflist->phys); |
158 | if (pbuflist == 0 || pbuflist->virt == 0) { | 143 | if (pbuflist == 0 || pbuflist->virt == 0) { |
159 | lpfc_sli_release_iocbq(phba, elsiocb); | 144 | lpfc_sli_release_iocbq(phba, elsiocb); |
160 | lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); | 145 | lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); |
@@ -289,6 +274,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
289 | vport->port_state = LPFC_FABRIC_CFG_LINK; | 274 | vport->port_state = LPFC_FABRIC_CFG_LINK; |
290 | lpfc_config_link(phba, mbox); | 275 | lpfc_config_link(phba, mbox); |
291 | mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | 276 | mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; |
277 | mbox->vport = vport; | ||
292 | 278 | ||
293 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB); | 279 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB); |
294 | if (rc == MBX_NOT_FINISHED) | 280 | if (rc == MBX_NOT_FINISHED) |
@@ -364,6 +350,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
364 | lpfc_config_link(phba, mbox); | 350 | lpfc_config_link(phba, mbox); |
365 | 351 | ||
366 | mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | 352 | mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; |
353 | mbox->vport = vport; | ||
367 | rc = lpfc_sli_issue_mbox(phba, mbox, | 354 | rc = lpfc_sli_issue_mbox(phba, mbox, |
368 | MBX_NOWAIT | MBX_STOP_IOCB); | 355 | MBX_NOWAIT | MBX_STOP_IOCB); |
369 | if (rc == MBX_NOT_FINISHED) { | 356 | if (rc == MBX_NOT_FINISHED) { |
@@ -714,8 +701,10 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
714 | 701 | ||
715 | irsp = &rspiocb->iocb; | 702 | irsp = &rspiocb->iocb; |
716 | ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); | 703 | ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); |
717 | if (!ndlp) | 704 | |
705 | if (!ndlp) { | ||
718 | goto out; | 706 | goto out; |
707 | } | ||
719 | 708 | ||
720 | /* Since ndlp can be freed in the disc state machine, note if this node | 709 | /* Since ndlp can be freed in the disc state machine, note if this node |
721 | * is being used during discovery. | 710 | * is being used during discovery. |
@@ -1110,9 +1099,8 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
1110 | /* If we get here, there is nothing left to wait for */ | 1099 | /* If we get here, there is nothing left to wait for */ |
1111 | if (vport->port_state < LPFC_VPORT_READY && | 1100 | if (vport->port_state < LPFC_VPORT_READY && |
1112 | phba->link_state != LPFC_CLEAR_LA) { | 1101 | phba->link_state != LPFC_CLEAR_LA) { |
1113 | if (vport->port_type == LPFC_PHYSICAL_PORT) { | 1102 | if (vport->port_type == LPFC_PHYSICAL_PORT) |
1114 | lpfc_issue_clear_la(phba, vport); | 1103 | lpfc_issue_clear_la(phba, vport); |
1115 | } | ||
1116 | } else { | 1104 | } else { |
1117 | lpfc_rscn_disc(vport); | 1105 | lpfc_rscn_disc(vport); |
1118 | } | 1106 | } |
@@ -1420,6 +1408,27 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) | |||
1420 | return 0; | 1408 | return 0; |
1421 | } | 1409 | } |
1422 | 1410 | ||
1411 | static void | ||
1412 | lpfc_end_rscn(struct lpfc_vport *vport) | ||
1413 | { | ||
1414 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
1415 | |||
1416 | if (vport->fc_flag & FC_RSCN_MODE) { | ||
1417 | /* | ||
1418 | * Check to see if more RSCNs came in while we were | ||
1419 | * processing this one. | ||
1420 | */ | ||
1421 | if (vport->fc_rscn_id_cnt || | ||
1422 | (vport->fc_flag & FC_RSCN_DISCOVERY) != 0) | ||
1423 | lpfc_els_handle_rscn(vport); | ||
1424 | else { | ||
1425 | spin_lock_irq(shost->host_lock); | ||
1426 | vport->fc_flag &= ~FC_RSCN_MODE; | ||
1427 | spin_unlock_irq(shost->host_lock); | ||
1428 | } | ||
1429 | } | ||
1430 | } | ||
1431 | |||
1423 | void | 1432 | void |
1424 | lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) | 1433 | lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) |
1425 | { | 1434 | { |
@@ -1449,24 +1458,7 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) | |||
1449 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | 1458 | vport->fc_flag &= ~FC_NDISC_ACTIVE; |
1450 | spin_unlock_irq(shost->host_lock); | 1459 | spin_unlock_irq(shost->host_lock); |
1451 | lpfc_can_disctmo(vport); | 1460 | lpfc_can_disctmo(vport); |
1452 | if (vport->fc_flag & FC_RSCN_MODE) { | 1461 | lpfc_end_rscn(vport); |
1453 | /* | ||
1454 | * Check to see if more RSCNs | ||
1455 | * came in while we were | ||
1456 | * processing this one. | ||
1457 | */ | ||
1458 | if (!vport->fc_rscn_id_cnt && | ||
1459 | !(vport->fc_flag & | ||
1460 | FC_RSCN_DISCOVERY)) { | ||
1461 | spin_lock_irq(shost->host_lock); | ||
1462 | vport->fc_flag &= ~FC_RSCN_MODE; | ||
1463 | spin_unlock_irq( | ||
1464 | shost->host_lock); | ||
1465 | } | ||
1466 | else { | ||
1467 | lpfc_els_handle_rscn(vport); | ||
1468 | } | ||
1469 | } | ||
1470 | } | 1462 | } |
1471 | } | 1463 | } |
1472 | } | 1464 | } |
@@ -1689,6 +1681,9 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
1689 | retry = 0; | 1681 | retry = 0; |
1690 | } | 1682 | } |
1691 | 1683 | ||
1684 | if ((vport->load_flag & FC_UNLOADING) != 0) | ||
1685 | retry = 0; | ||
1686 | |||
1692 | if (retry) { | 1687 | if (retry) { |
1693 | 1688 | ||
1694 | /* Retry ELS command <elsCmd> to remote NPORT <did> */ | 1689 | /* Retry ELS command <elsCmd> to remote NPORT <did> */ |
@@ -2141,9 +2136,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, | |||
2141 | 2136 | ||
2142 | cmdsize = sizeof (uint32_t) + sizeof (PRLI); | 2137 | cmdsize = sizeof (uint32_t) + sizeof (PRLI); |
2143 | elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, | 2138 | elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, |
2144 | ndlp->nlp_DID, | 2139 | ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK))); |
2145 | (ELS_CMD_ACC | | ||
2146 | (ELS_CMD_PRLI & ~ELS_RSP_MASK))); | ||
2147 | if (!elsiocb) | 2140 | if (!elsiocb) |
2148 | return 1; | 2141 | return 1; |
2149 | 2142 | ||
@@ -2361,8 +2354,12 @@ lpfc_els_flush_rscn(struct lpfc_vport *vport) | |||
2361 | 2354 | ||
2362 | for (i = 0; i < vport->fc_rscn_id_cnt; i++) { | 2355 | for (i = 0; i < vport->fc_rscn_id_cnt; i++) { |
2363 | mp = vport->fc_rscn_id_list[i]; | 2356 | mp = vport->fc_rscn_id_list[i]; |
2364 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 2357 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) |
2365 | kfree(mp); | 2358 | lpfc_sli_hbqbuf_free(phba, mp->virt, mp->phys); |
2359 | else { | ||
2360 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
2361 | kfree(mp); | ||
2362 | } | ||
2366 | vport->fc_rscn_id_list[i] = NULL; | 2363 | vport->fc_rscn_id_list[i] = NULL; |
2367 | } | 2364 | } |
2368 | spin_lock_irq(shost->host_lock); | 2365 | spin_lock_irq(shost->host_lock); |
@@ -2486,9 +2483,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
2486 | cmd &= ELS_CMD_MASK; | 2483 | cmd &= ELS_CMD_MASK; |
2487 | 2484 | ||
2488 | /* RSCN received */ | 2485 | /* RSCN received */ |
2489 | lpfc_printf_log(phba, | 2486 | lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, |
2490 | KERN_INFO, | ||
2491 | LOG_DISCOVERY, | ||
2492 | "%d:0214 RSCN received Data: x%x x%x x%x x%x\n", | 2487 | "%d:0214 RSCN received Data: x%x x%x x%x x%x\n", |
2493 | phba->brd_no, vport->fc_flag, payload_len, *lp, | 2488 | phba->brd_no, vport->fc_flag, payload_len, *lp, |
2494 | vport->fc_rscn_id_cnt); | 2489 | vport->fc_rscn_id_cnt); |
@@ -2581,9 +2576,7 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) | |||
2581 | lpfc_set_disctmo(vport); | 2576 | lpfc_set_disctmo(vport); |
2582 | 2577 | ||
2583 | /* RSCN processed */ | 2578 | /* RSCN processed */ |
2584 | lpfc_printf_log(phba, | 2579 | lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, |
2585 | KERN_INFO, | ||
2586 | LOG_DISCOVERY, | ||
2587 | "%d:0215 RSCN processed Data: x%x x%x x%x x%x\n", | 2580 | "%d:0215 RSCN processed Data: x%x x%x x%x x%x\n", |
2588 | phba->brd_no, | 2581 | phba->brd_no, |
2589 | vport->fc_flag, 0, vport->fc_rscn_id_cnt, | 2582 | vport->fc_flag, 0, vport->fc_rscn_id_cnt, |
@@ -2683,6 +2676,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
2683 | phba->cfg_link_speed); | 2676 | phba->cfg_link_speed); |
2684 | mbox->mb.un.varInitLnk.lipsr_AL_PA = 0; | 2677 | mbox->mb.un.varInitLnk.lipsr_AL_PA = 0; |
2685 | mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | 2678 | mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; |
2679 | mbox->vport = vport; | ||
2686 | rc = lpfc_sli_issue_mbox | 2680 | rc = lpfc_sli_issue_mbox |
2687 | (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); | 2681 | (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); |
2688 | lpfc_set_loopback_flag(phba); | 2682 | lpfc_set_loopback_flag(phba); |
@@ -2837,10 +2831,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
2837 | 2831 | ||
2838 | elsiocb->iocb_cmpl = lpfc_cmpl_els_acc; | 2832 | elsiocb->iocb_cmpl = lpfc_cmpl_els_acc; |
2839 | phba->fc_stat.elsXmitACC++; | 2833 | phba->fc_stat.elsXmitACC++; |
2840 | 2834 | if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) | |
2841 | if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { | ||
2842 | lpfc_els_free_iocb(phba, elsiocb); | 2835 | lpfc_els_free_iocb(phba, elsiocb); |
2843 | } | ||
2844 | return; | 2836 | return; |
2845 | } | 2837 | } |
2846 | 2838 | ||
@@ -3015,9 +3007,7 @@ lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
3015 | fp = (FARP *) lp; | 3007 | fp = (FARP *) lp; |
3016 | 3008 | ||
3017 | /* FARP-REQ received from DID <did> */ | 3009 | /* FARP-REQ received from DID <did> */ |
3018 | lpfc_printf_log(phba, | 3010 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, |
3019 | KERN_INFO, | ||
3020 | LOG_ELS, | ||
3021 | "%d:0601 FARP-REQ received from DID x%x\n", | 3011 | "%d:0601 FARP-REQ received from DID x%x\n", |
3022 | phba->brd_no, did); | 3012 | phba->brd_no, did); |
3023 | 3013 | ||
@@ -3077,12 +3067,9 @@ lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
3077 | 3067 | ||
3078 | cmd = *lp++; | 3068 | cmd = *lp++; |
3079 | /* FARP-RSP received from DID <did> */ | 3069 | /* FARP-RSP received from DID <did> */ |
3080 | lpfc_printf_log(phba, | 3070 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, |
3081 | KERN_INFO, | ||
3082 | LOG_ELS, | ||
3083 | "%d:0600 FARP-RSP received from DID x%x\n", | 3071 | "%d:0600 FARP-RSP received from DID x%x\n", |
3084 | phba->brd_no, did); | 3072 | phba->brd_no, did); |
3085 | |||
3086 | /* ACCEPT the Farp resp request */ | 3073 | /* ACCEPT the Farp resp request */ |
3087 | lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); | 3074 | lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); |
3088 | 3075 | ||
@@ -3102,8 +3089,9 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
3102 | struct lpfc_hba *phba = vport->phba; | 3089 | struct lpfc_hba *phba = vport->phba; |
3103 | 3090 | ||
3104 | /* FAN received */ | 3091 | /* FAN received */ |
3105 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0265 FAN received\n", | 3092 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, |
3106 | phba->brd_no); | 3093 | "%d:0265 FAN received\n", |
3094 | phba->brd_no); | ||
3107 | 3095 | ||
3108 | icmd = &cmdiocb->iocb; | 3096 | icmd = &cmdiocb->iocb; |
3109 | did = icmd->un.elsreq64.remoteID; | 3097 | did = icmd->un.elsreq64.remoteID; |
@@ -3332,79 +3320,40 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) | |||
3332 | return; | 3320 | return; |
3333 | } | 3321 | } |
3334 | 3322 | ||
3335 | void | 3323 | static void |
3336 | lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | 3324 | lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, |
3337 | struct lpfc_iocbq *elsiocb) | 3325 | struct lpfc_vport *vport, struct lpfc_dmabuf *mp, |
3326 | struct lpfc_iocbq *elsiocb) | ||
3338 | { | 3327 | { |
3339 | struct lpfc_sli *psli; | ||
3340 | struct lpfc_nodelist *ndlp; | 3328 | struct lpfc_nodelist *ndlp; |
3341 | struct lpfc_dmabuf *mp = NULL; | ||
3342 | uint32_t *lp; | ||
3343 | IOCB_t *icmd; | ||
3344 | struct ls_rjt stat; | 3329 | struct ls_rjt stat; |
3330 | uint32_t *lp; | ||
3345 | uint32_t cmd, did, newnode, rjt_err = 0; | 3331 | uint32_t cmd, did, newnode, rjt_err = 0; |
3346 | uint32_t drop_cmd = 0; /* by default do NOT drop received cmd */ | 3332 | IOCB_t *icmd = &elsiocb->iocb; |
3347 | struct lpfc_vport *vport = NULL; | ||
3348 | |||
3349 | psli = &phba->sli; | ||
3350 | icmd = &elsiocb->iocb; | ||
3351 | 3333 | ||
3352 | if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && | 3334 | if (!vport || !mp) |
3353 | ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { | ||
3354 | phba->fc_stat.NoRcvBuf++; | ||
3355 | /* Not enough posted buffers; Try posting more buffers */ | ||
3356 | lpfc_post_buffer(phba, pring, 0, 1); | ||
3357 | return; | ||
3358 | } | ||
3359 | |||
3360 | /* If there are no BDEs associated with this IOCB, | ||
3361 | * there is nothing to do. | ||
3362 | */ | ||
3363 | if (icmd->ulpBdeCount == 0) | ||
3364 | return; | ||
3365 | |||
3366 | /* type of ELS cmd is first 32bit word in packet */ | ||
3367 | mp = lpfc_sli_ringpostbuf_get(phba, pring, | ||
3368 | getPaddr(icmd->un.cont64[0].addrHigh, | ||
3369 | icmd->un.cont64[0].addrLow)); | ||
3370 | if (mp == 0) { | ||
3371 | drop_cmd = 1; | ||
3372 | goto dropit; | 3335 | goto dropit; |
3373 | } | ||
3374 | |||
3375 | vport = phba->pport; | ||
3376 | 3336 | ||
3377 | newnode = 0; | 3337 | newnode = 0; |
3378 | lp = (uint32_t *) mp->virt; | 3338 | lp = (uint32_t *) mp->virt; |
3379 | cmd = *lp++; | 3339 | cmd = *lp++; |
3380 | lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], 1, 1); | 3340 | if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0) |
3341 | lpfc_post_buffer(phba, pring, 1, 1); | ||
3381 | 3342 | ||
3382 | if (icmd->ulpStatus) { | 3343 | if (icmd->ulpStatus) |
3383 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
3384 | kfree(mp); | ||
3385 | drop_cmd = 1; | ||
3386 | goto dropit; | 3344 | goto dropit; |
3387 | } | ||
3388 | 3345 | ||
3389 | /* Check to see if link went down during discovery */ | 3346 | /* Check to see if link went down during discovery */ |
3390 | if (lpfc_els_chk_latt(vport)) { | 3347 | if (lpfc_els_chk_latt(vport)) |
3391 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
3392 | kfree(mp); | ||
3393 | drop_cmd = 1; | ||
3394 | goto dropit; | 3348 | goto dropit; |
3395 | } | ||
3396 | 3349 | ||
3397 | did = icmd->un.rcvels.remoteID; | 3350 | did = icmd->un.rcvels.remoteID; |
3398 | ndlp = lpfc_findnode_did(vport, did); | 3351 | ndlp = lpfc_findnode_did(vport, did); |
3399 | if (!ndlp) { | 3352 | if (!ndlp) { |
3400 | /* Cannot find existing Fabric ndlp, so allocate a new one */ | 3353 | /* Cannot find existing Fabric ndlp, so allocate a new one */ |
3401 | ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); | 3354 | ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); |
3402 | if (!ndlp) { | 3355 | if (!ndlp) |
3403 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
3404 | kfree(mp); | ||
3405 | drop_cmd = 1; | ||
3406 | goto dropit; | 3356 | goto dropit; |
3407 | } | ||
3408 | 3357 | ||
3409 | lpfc_nlp_init(vport, ndlp, did); | 3358 | lpfc_nlp_init(vport, ndlp, did); |
3410 | newnode = 1; | 3359 | newnode = 1; |
@@ -3428,7 +3377,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3428 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | 3377 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, |
3429 | "%d:0112 ELS command x%x received from NPORT x%x " | 3378 | "%d:0112 ELS command x%x received from NPORT x%x " |
3430 | "Data: x%x\n", phba->brd_no, cmd, did, | 3379 | "Data: x%x\n", phba->brd_no, cmd, did, |
3431 | vport->port_state); | 3380 | vport->port_state); |
3432 | 3381 | ||
3433 | switch (cmd) { | 3382 | switch (cmd) { |
3434 | case ELS_CMD_PLOGI: | 3383 | case ELS_CMD_PLOGI: |
@@ -3537,8 +3486,9 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3537 | 3486 | ||
3538 | /* Unknown ELS command <elsCmd> received from NPORT <did> */ | 3487 | /* Unknown ELS command <elsCmd> received from NPORT <did> */ |
3539 | lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | 3488 | lpfc_printf_log(phba, KERN_ERR, LOG_ELS, |
3540 | "%d:0115 Unknown ELS command x%x received from " | 3489 | "%d:0115 Unknown ELS command x%x " |
3541 | "NPORT x%x\n", phba->brd_no, cmd, did); | 3490 | "received from NPORT x%x\n", |
3491 | phba->brd_no, cmd, did); | ||
3542 | if (newnode) | 3492 | if (newnode) |
3543 | lpfc_drop_node(vport, ndlp); | 3493 | lpfc_drop_node(vport, ndlp); |
3544 | break; | 3494 | break; |
@@ -3553,20 +3503,89 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3553 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp); | 3503 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp); |
3554 | } | 3504 | } |
3555 | 3505 | ||
3506 | return; | ||
3507 | |||
3508 | dropit: | ||
3509 | lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | ||
3510 | "%d:0111 Dropping received ELS cmd " | ||
3511 | "Data: x%x x%x x%x\n", | ||
3512 | phba->brd_no, | ||
3513 | icmd->ulpStatus, icmd->un.ulpWord[4], | ||
3514 | icmd->ulpTimeout); | ||
3515 | phba->fc_stat.elsRcvDrop++; | ||
3516 | } | ||
3517 | |||
3518 | |||
3519 | void | ||
3520 | lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | ||
3521 | struct lpfc_iocbq *elsiocb) | ||
3522 | { | ||
3523 | struct lpfc_vport *vport = phba->pport; | ||
3524 | struct lpfc_dmabuf *mp = NULL; | ||
3525 | IOCB_t *icmd = &elsiocb->iocb; | ||
3526 | struct hbq_dmabuf *sp = NULL; | ||
3527 | dma_addr_t paddr; | ||
3528 | |||
3529 | if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && | ||
3530 | ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { | ||
3531 | phba->fc_stat.NoRcvBuf++; | ||
3532 | /* Not enough posted buffers; Try posting more buffers */ | ||
3533 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) | ||
3534 | lpfc_sli_hbqbuf_fill_hbq(phba); | ||
3535 | else | ||
3536 | lpfc_post_buffer(phba, pring, 0, 1); | ||
3537 | return; | ||
3538 | } | ||
3539 | |||
3540 | /* If there are no BDEs associated with this IOCB, | ||
3541 | * there is nothing to do. | ||
3542 | */ | ||
3543 | if (icmd->ulpBdeCount == 0) | ||
3544 | return; | ||
3545 | |||
3546 | /* type of ELS cmd is first 32bit word in packet */ | ||
3547 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { | ||
3548 | paddr = getPaddr(icmd->un.cont64[0].addrHigh, | ||
3549 | icmd->un.cont64[0].addrLow); | ||
3550 | sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[3]); | ||
3551 | if (sp) | ||
3552 | phba->hbq_buff_count--; | ||
3553 | mp = sp ? &sp->dbuf : NULL; | ||
3554 | } else { | ||
3555 | paddr = getPaddr(icmd->un.cont64[0].addrHigh, | ||
3556 | icmd->un.cont64[0].addrLow); | ||
3557 | mp = lpfc_sli_ringpostbuf_get(phba, pring, paddr); | ||
3558 | } | ||
3559 | |||
3560 | lpfc_els_unsol_buffer(phba, pring, vport, mp, elsiocb); | ||
3561 | |||
3556 | lpfc_nlp_put(elsiocb->context1); | 3562 | lpfc_nlp_put(elsiocb->context1); |
3557 | elsiocb->context1 = NULL; | 3563 | elsiocb->context1 = NULL; |
3558 | if (elsiocb->context2) { | 3564 | if (elsiocb->context2) { |
3559 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 3565 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) |
3560 | kfree(mp); | 3566 | lpfc_sli_free_hbq(phba, sp); |
3567 | else { | ||
3568 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
3569 | kfree(mp); | ||
3570 | } | ||
3561 | } | 3571 | } |
3562 | dropit: | 3572 | |
3563 | /* check if need to drop received ELS cmd */ | 3573 | /* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */ |
3564 | if (drop_cmd == 1) { | 3574 | if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) != 0 && |
3565 | lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | 3575 | icmd->ulpBdeCount == 2) { |
3566 | "%d:0111 Dropping received ELS cmd " | 3576 | sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[15]); |
3567 | "Data: x%x x%x x%x\n", phba->brd_no, | 3577 | if (sp) |
3568 | icmd->ulpStatus, icmd->un.ulpWord[4], | 3578 | phba->hbq_buff_count--; |
3569 | icmd->ulpTimeout); | 3579 | mp = sp ? &sp->dbuf : NULL; |
3570 | phba->fc_stat.elsRcvDrop++; | 3580 | lpfc_els_unsol_buffer(phba, pring, vport, mp, elsiocb); |
3581 | /* free mp if we are done with it */ | ||
3582 | if (elsiocb->context2) { | ||
3583 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) | ||
3584 | lpfc_sli_free_hbq(phba, sp); | ||
3585 | else { | ||
3586 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
3587 | kfree(mp); | ||
3588 | } | ||
3589 | } | ||
3571 | } | 3590 | } |
3572 | } | 3591 | } |