diff options
author | James Smart <james.smart@emulex.com> | 2010-01-26 23:07:37 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-02-08 19:37:53 -0500 |
commit | 341af10239c4c87192bf762f53c7bcb1f3a1e767 (patch) | |
tree | 41f7dfa01fc753e7873239daf9155765d153d776 /drivers/scsi/lpfc | |
parent | 2cec802980727f1daa46d8c31b411e083d49d7a2 (diff) |
[SCSI] lpfc 8.3.8: BugFixes: SLI relates changes
Fix hardware/SLI relates issues:
- Handle XB bit so that ELS XRIs are not prematurely released.
- Handle XB bit so that FCP XRIs are not prematurely released.
- Define new security SLI Commands.
- Remove unused security SLI commands
- Skip receive data size parameter check on received FLOGI.
- Added LPFC_USE_FCPWQIDX flag to iocb to force SLI layer
to submit abort WQE on same WQ as the command WQE.
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_crtn.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 18 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 83 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 29 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 112 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 10 |
8 files changed, 170 insertions, 87 deletions
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 650494d622c1..14ee7d4f71ba 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -99,7 +99,7 @@ int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *, | |||
99 | 99 | ||
100 | void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *); | 100 | void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *); |
101 | int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, | 101 | int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, |
102 | struct serv_parm *, uint32_t); | 102 | struct serv_parm *, uint32_t, int); |
103 | int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); | 103 | int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); |
104 | void lpfc_more_plogi(struct lpfc_vport *); | 104 | void lpfc_more_plogi(struct lpfc_vport *); |
105 | void lpfc_more_adisc(struct lpfc_vport *); | 105 | void lpfc_more_adisc(struct lpfc_vport *); |
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 2cc39684ce97..32e3c8df22c5 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -4385,7 +4385,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
4385 | 4385 | ||
4386 | did = Fabric_DID; | 4386 | did = Fabric_DID; |
4387 | 4387 | ||
4388 | if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) { | 4388 | if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) { |
4389 | /* For a FLOGI we accept, then if our portname is greater | 4389 | /* For a FLOGI we accept, then if our portname is greater |
4390 | * then the remote portname we initiate Nport login. | 4390 | * then the remote portname we initiate Nport login. |
4391 | */ | 4391 | */ |
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index c9faa1d8c3c8..44c258730b07 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h | |||
@@ -1465,17 +1465,13 @@ typedef struct { /* FireFly BIU registers */ | |||
1465 | #define CMD_IOCB_LOGENTRY_CN 0x94 | 1465 | #define CMD_IOCB_LOGENTRY_CN 0x94 |
1466 | #define CMD_IOCB_LOGENTRY_ASYNC_CN 0x96 | 1466 | #define CMD_IOCB_LOGENTRY_ASYNC_CN 0x96 |
1467 | 1467 | ||
1468 | /* Unhandled Data Security SLI Commands */ | 1468 | /* Data Security SLI Commands */ |
1469 | #define DSSCMD_IWRITE64_CR 0xD8 | 1469 | #define DSSCMD_IWRITE64_CR 0xF8 |
1470 | #define DSSCMD_IWRITE64_CX 0xD9 | 1470 | #define DSSCMD_IWRITE64_CX 0xF9 |
1471 | #define DSSCMD_IREAD64_CR 0xDA | 1471 | #define DSSCMD_IREAD64_CR 0xFA |
1472 | #define DSSCMD_IREAD64_CX 0xDB | 1472 | #define DSSCMD_IREAD64_CX 0xFB |
1473 | #define DSSCMD_INVALIDATE_DEK 0xDC | 1473 | |
1474 | #define DSSCMD_SET_KEK 0xDD | 1474 | #define CMD_MAX_IOCB_CMD 0xFB |
1475 | #define DSSCMD_GET_KEK_ID 0xDE | ||
1476 | #define DSSCMD_GEN_XFER 0xDF | ||
1477 | |||
1478 | #define CMD_MAX_IOCB_CMD 0xE6 | ||
1479 | #define CMD_IOCB_MASK 0xff | 1475 | #define CMD_IOCB_MASK 0xff |
1480 | 1476 | ||
1481 | #define MAX_MSG_DATA 28 /* max msg data in CMD_ADAPTER_MSG | 1477 | #define MAX_MSG_DATA 28 /* max msg data in CMD_ADAPTER_MSG |
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 2ed6af194932..293234a5a944 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c | |||
@@ -62,7 +62,7 @@ lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
62 | 62 | ||
63 | int | 63 | int |
64 | lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | 64 | lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, |
65 | struct serv_parm * sp, uint32_t class) | 65 | struct serv_parm *sp, uint32_t class, int flogi) |
66 | { | 66 | { |
67 | volatile struct serv_parm *hsp = &vport->fc_sparam; | 67 | volatile struct serv_parm *hsp = &vport->fc_sparam; |
68 | uint16_t hsp_value, ssp_value = 0; | 68 | uint16_t hsp_value, ssp_value = 0; |
@@ -75,49 +75,56 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
75 | * correcting the byte values. | 75 | * correcting the byte values. |
76 | */ | 76 | */ |
77 | if (sp->cls1.classValid) { | 77 | if (sp->cls1.classValid) { |
78 | hsp_value = (hsp->cls1.rcvDataSizeMsb << 8) | | 78 | if (!flogi) { |
79 | hsp->cls1.rcvDataSizeLsb; | 79 | hsp_value = ((hsp->cls1.rcvDataSizeMsb << 8) | |
80 | ssp_value = (sp->cls1.rcvDataSizeMsb << 8) | | 80 | hsp->cls1.rcvDataSizeLsb); |
81 | sp->cls1.rcvDataSizeLsb; | 81 | ssp_value = ((sp->cls1.rcvDataSizeMsb << 8) | |
82 | if (!ssp_value) | 82 | sp->cls1.rcvDataSizeLsb); |
83 | goto bad_service_param; | 83 | if (!ssp_value) |
84 | if (ssp_value > hsp_value) { | 84 | goto bad_service_param; |
85 | sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb; | 85 | if (ssp_value > hsp_value) { |
86 | sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb; | 86 | sp->cls1.rcvDataSizeLsb = |
87 | hsp->cls1.rcvDataSizeLsb; | ||
88 | sp->cls1.rcvDataSizeMsb = | ||
89 | hsp->cls1.rcvDataSizeMsb; | ||
90 | } | ||
87 | } | 91 | } |
88 | } else if (class == CLASS1) { | 92 | } else if (class == CLASS1) |
89 | goto bad_service_param; | 93 | goto bad_service_param; |
90 | } | ||
91 | |||
92 | if (sp->cls2.classValid) { | 94 | if (sp->cls2.classValid) { |
93 | hsp_value = (hsp->cls2.rcvDataSizeMsb << 8) | | 95 | if (!flogi) { |
94 | hsp->cls2.rcvDataSizeLsb; | 96 | hsp_value = ((hsp->cls2.rcvDataSizeMsb << 8) | |
95 | ssp_value = (sp->cls2.rcvDataSizeMsb << 8) | | 97 | hsp->cls2.rcvDataSizeLsb); |
96 | sp->cls2.rcvDataSizeLsb; | 98 | ssp_value = ((sp->cls2.rcvDataSizeMsb << 8) | |
97 | if (!ssp_value) | 99 | sp->cls2.rcvDataSizeLsb); |
98 | goto bad_service_param; | 100 | if (!ssp_value) |
99 | if (ssp_value > hsp_value) { | 101 | goto bad_service_param; |
100 | sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb; | 102 | if (ssp_value > hsp_value) { |
101 | sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb; | 103 | sp->cls2.rcvDataSizeLsb = |
104 | hsp->cls2.rcvDataSizeLsb; | ||
105 | sp->cls2.rcvDataSizeMsb = | ||
106 | hsp->cls2.rcvDataSizeMsb; | ||
107 | } | ||
102 | } | 108 | } |
103 | } else if (class == CLASS2) { | 109 | } else if (class == CLASS2) |
104 | goto bad_service_param; | 110 | goto bad_service_param; |
105 | } | ||
106 | |||
107 | if (sp->cls3.classValid) { | 111 | if (sp->cls3.classValid) { |
108 | hsp_value = (hsp->cls3.rcvDataSizeMsb << 8) | | 112 | if (!flogi) { |
109 | hsp->cls3.rcvDataSizeLsb; | 113 | hsp_value = ((hsp->cls3.rcvDataSizeMsb << 8) | |
110 | ssp_value = (sp->cls3.rcvDataSizeMsb << 8) | | 114 | hsp->cls3.rcvDataSizeLsb); |
111 | sp->cls3.rcvDataSizeLsb; | 115 | ssp_value = ((sp->cls3.rcvDataSizeMsb << 8) | |
112 | if (!ssp_value) | 116 | sp->cls3.rcvDataSizeLsb); |
113 | goto bad_service_param; | 117 | if (!ssp_value) |
114 | if (ssp_value > hsp_value) { | 118 | goto bad_service_param; |
115 | sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb; | 119 | if (ssp_value > hsp_value) { |
116 | sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb; | 120 | sp->cls3.rcvDataSizeLsb = |
121 | hsp->cls3.rcvDataSizeLsb; | ||
122 | sp->cls3.rcvDataSizeMsb = | ||
123 | hsp->cls3.rcvDataSizeMsb; | ||
124 | } | ||
117 | } | 125 | } |
118 | } else if (class == CLASS3) { | 126 | } else if (class == CLASS3) |
119 | goto bad_service_param; | 127 | goto bad_service_param; |
120 | } | ||
121 | 128 | ||
122 | /* | 129 | /* |
123 | * Preserve the upper four bits of the MSB from the PLOGI response. | 130 | * Preserve the upper four bits of the MSB from the PLOGI response. |
@@ -295,7 +302,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
295 | NULL); | 302 | NULL); |
296 | return 0; | 303 | return 0; |
297 | } | 304 | } |
298 | if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) { | 305 | if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0) == 0)) { |
299 | /* Reject this request because invalid parameters */ | 306 | /* Reject this request because invalid parameters */ |
300 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | 307 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; |
301 | stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; | 308 | stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; |
@@ -831,7 +838,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, | |||
831 | "0142 PLOGI RSP: Invalid WWN.\n"); | 838 | "0142 PLOGI RSP: Invalid WWN.\n"); |
832 | goto out; | 839 | goto out; |
833 | } | 840 | } |
834 | if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3)) | 841 | if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0)) |
835 | goto out; | 842 | goto out; |
836 | /* PLOGI chkparm OK */ | 843 | /* PLOGI chkparm OK */ |
837 | lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, | 844 | lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, |
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index a246410ce9df..d5cc6b8d32f2 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
@@ -626,6 +626,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, | |||
626 | &phba->sli4_hba.lpfc_abts_scsi_buf_list, list) { | 626 | &phba->sli4_hba.lpfc_abts_scsi_buf_list, list) { |
627 | if (psb->cur_iocbq.sli4_xritag == xri) { | 627 | if (psb->cur_iocbq.sli4_xritag == xri) { |
628 | list_del(&psb->list); | 628 | list_del(&psb->list); |
629 | psb->exch_busy = 0; | ||
629 | psb->status = IOSTAT_SUCCESS; | 630 | psb->status = IOSTAT_SUCCESS; |
630 | spin_unlock_irqrestore( | 631 | spin_unlock_irqrestore( |
631 | &phba->sli4_hba.abts_scsi_buf_list_lock, | 632 | &phba->sli4_hba.abts_scsi_buf_list_lock, |
@@ -688,11 +689,12 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) | |||
688 | list); | 689 | list); |
689 | if (status) { | 690 | if (status) { |
690 | /* Put this back on the abort scsi list */ | 691 | /* Put this back on the abort scsi list */ |
691 | psb->status = IOSTAT_LOCAL_REJECT; | 692 | psb->exch_busy = 1; |
692 | psb->result = IOERR_ABORT_REQUESTED; | ||
693 | rc++; | 693 | rc++; |
694 | } else | 694 | } else { |
695 | psb->exch_busy = 0; | ||
695 | psb->status = IOSTAT_SUCCESS; | 696 | psb->status = IOSTAT_SUCCESS; |
697 | } | ||
696 | /* Put it back into the SCSI buffer list */ | 698 | /* Put it back into the SCSI buffer list */ |
697 | lpfc_release_scsi_buf_s4(phba, psb); | 699 | lpfc_release_scsi_buf_s4(phba, psb); |
698 | } | 700 | } |
@@ -839,11 +841,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) | |||
839 | psb->cur_iocbq.sli4_xritag); | 841 | psb->cur_iocbq.sli4_xritag); |
840 | if (status) { | 842 | if (status) { |
841 | /* Put this back on the abort scsi list */ | 843 | /* Put this back on the abort scsi list */ |
842 | psb->status = IOSTAT_LOCAL_REJECT; | 844 | psb->exch_busy = 1; |
843 | psb->result = IOERR_ABORT_REQUESTED; | ||
844 | rc++; | 845 | rc++; |
845 | } else | 846 | } else { |
847 | psb->exch_busy = 0; | ||
846 | psb->status = IOSTAT_SUCCESS; | 848 | psb->status = IOSTAT_SUCCESS; |
849 | } | ||
847 | /* Put it back into the SCSI buffer list */ | 850 | /* Put it back into the SCSI buffer list */ |
848 | lpfc_release_scsi_buf_s4(phba, psb); | 851 | lpfc_release_scsi_buf_s4(phba, psb); |
849 | break; | 852 | break; |
@@ -857,11 +860,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) | |||
857 | list); | 860 | list); |
858 | if (status) { | 861 | if (status) { |
859 | /* Put this back on the abort scsi list */ | 862 | /* Put this back on the abort scsi list */ |
860 | psb->status = IOSTAT_LOCAL_REJECT; | 863 | psb->exch_busy = 1; |
861 | psb->result = IOERR_ABORT_REQUESTED; | ||
862 | rc++; | 864 | rc++; |
863 | } else | 865 | } else { |
866 | psb->exch_busy = 0; | ||
864 | psb->status = IOSTAT_SUCCESS; | 867 | psb->status = IOSTAT_SUCCESS; |
868 | } | ||
865 | /* Put it back into the SCSI buffer list */ | 869 | /* Put it back into the SCSI buffer list */ |
866 | lpfc_release_scsi_buf_s4(phba, psb); | 870 | lpfc_release_scsi_buf_s4(phba, psb); |
867 | } | 871 | } |
@@ -951,8 +955,7 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) | |||
951 | { | 955 | { |
952 | unsigned long iflag = 0; | 956 | unsigned long iflag = 0; |
953 | 957 | ||
954 | if (psb->status == IOSTAT_LOCAL_REJECT | 958 | if (psb->exch_busy) { |
955 | && psb->result == IOERR_ABORT_REQUESTED) { | ||
956 | spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock, | 959 | spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock, |
957 | iflag); | 960 | iflag); |
958 | psb->pCmd = NULL; | 961 | psb->pCmd = NULL; |
@@ -2221,6 +2224,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | |||
2221 | 2224 | ||
2222 | lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; | 2225 | lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; |
2223 | lpfc_cmd->status = pIocbOut->iocb.ulpStatus; | 2226 | lpfc_cmd->status = pIocbOut->iocb.ulpStatus; |
2227 | /* pick up SLI4 exhange busy status from HBA */ | ||
2228 | lpfc_cmd->exch_busy = pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY; | ||
2229 | |||
2224 | if (pnode && NLP_CHK_NODE_ACT(pnode)) | 2230 | if (pnode && NLP_CHK_NODE_ACT(pnode)) |
2225 | atomic_dec(&pnode->cmd_pending); | 2231 | atomic_dec(&pnode->cmd_pending); |
2226 | 2232 | ||
@@ -2990,6 +2996,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) | |||
2990 | 2996 | ||
2991 | /* ABTS WQE must go to the same WQ as the WQE to be aborted */ | 2997 | /* ABTS WQE must go to the same WQ as the WQE to be aborted */ |
2992 | abtsiocb->fcp_wqidx = iocb->fcp_wqidx; | 2998 | abtsiocb->fcp_wqidx = iocb->fcp_wqidx; |
2999 | abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; | ||
2993 | 3000 | ||
2994 | if (lpfc_is_link_up(phba)) | 3001 | if (lpfc_is_link_up(phba)) |
2995 | icmd->ulpCommand = CMD_ABORT_XRI_CN; | 3002 | icmd->ulpCommand = CMD_ABORT_XRI_CN; |
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 65dfc8bd5b49..5932273870a5 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h | |||
@@ -118,6 +118,7 @@ struct lpfc_scsi_buf { | |||
118 | 118 | ||
119 | uint32_t timeout; | 119 | uint32_t timeout; |
120 | 120 | ||
121 | uint16_t exch_busy; /* SLI4 hba reported XB on complete WCQE */ | ||
121 | uint16_t status; /* From IOCB Word 7- ulpStatus */ | 122 | uint16_t status; /* From IOCB Word 7- ulpStatus */ |
122 | uint32_t result; /* From IOCB Word 4. */ | 123 | uint32_t result; /* From IOCB Word 4. */ |
123 | 124 | ||
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 589549b2bf0e..dc7c5c1231df 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -580,10 +580,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) | |||
580 | else | 580 | else |
581 | sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag); | 581 | sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag); |
582 | if (sglq) { | 582 | if (sglq) { |
583 | if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED | 583 | if (iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) { |
584 | && ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT) | ||
585 | && (iocbq->iocb.un.ulpWord[4] | ||
586 | == IOERR_ABORT_REQUESTED))) { | ||
587 | spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, | 584 | spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, |
588 | iflag); | 585 | iflag); |
589 | list_add(&sglq->list, | 586 | list_add(&sglq->list, |
@@ -764,10 +761,6 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) | |||
764 | case DSSCMD_IWRITE64_CX: | 761 | case DSSCMD_IWRITE64_CX: |
765 | case DSSCMD_IREAD64_CR: | 762 | case DSSCMD_IREAD64_CR: |
766 | case DSSCMD_IREAD64_CX: | 763 | case DSSCMD_IREAD64_CX: |
767 | case DSSCMD_INVALIDATE_DEK: | ||
768 | case DSSCMD_SET_KEK: | ||
769 | case DSSCMD_GET_KEK_ID: | ||
770 | case DSSCMD_GEN_XFER: | ||
771 | type = LPFC_SOL_IOCB; | 764 | type = LPFC_SOL_IOCB; |
772 | break; | 765 | break; |
773 | case CMD_ABORT_XRI_CN: | 766 | case CMD_ABORT_XRI_CN: |
@@ -2228,9 +2221,15 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
2228 | * All other are passed to the completion callback. | 2221 | * All other are passed to the completion callback. |
2229 | */ | 2222 | */ |
2230 | if (pring->ringno == LPFC_ELS_RING) { | 2223 | if (pring->ringno == LPFC_ELS_RING) { |
2231 | if (cmdiocbp->iocb_flag & LPFC_DRIVER_ABORTED) { | 2224 | if ((phba->sli_rev < LPFC_SLI_REV4) && |
2225 | (cmdiocbp->iocb_flag & | ||
2226 | LPFC_DRIVER_ABORTED)) { | ||
2227 | spin_lock_irqsave(&phba->hbalock, | ||
2228 | iflag); | ||
2232 | cmdiocbp->iocb_flag &= | 2229 | cmdiocbp->iocb_flag &= |
2233 | ~LPFC_DRIVER_ABORTED; | 2230 | ~LPFC_DRIVER_ABORTED; |
2231 | spin_unlock_irqrestore(&phba->hbalock, | ||
2232 | iflag); | ||
2234 | saveq->iocb.ulpStatus = | 2233 | saveq->iocb.ulpStatus = |
2235 | IOSTAT_LOCAL_REJECT; | 2234 | IOSTAT_LOCAL_REJECT; |
2236 | saveq->iocb.un.ulpWord[4] = | 2235 | saveq->iocb.un.ulpWord[4] = |
@@ -2240,7 +2239,47 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
2240 | * of DMAing payload, so don't free data | 2239 | * of DMAing payload, so don't free data |
2241 | * buffer till after a hbeat. | 2240 | * buffer till after a hbeat. |
2242 | */ | 2241 | */ |
2242 | spin_lock_irqsave(&phba->hbalock, | ||
2243 | iflag); | ||
2243 | saveq->iocb_flag |= LPFC_DELAY_MEM_FREE; | 2244 | saveq->iocb_flag |= LPFC_DELAY_MEM_FREE; |
2245 | spin_unlock_irqrestore(&phba->hbalock, | ||
2246 | iflag); | ||
2247 | } | ||
2248 | if ((phba->sli_rev == LPFC_SLI_REV4) && | ||
2249 | (saveq->iocb_flag & LPFC_EXCHANGE_BUSY)) { | ||
2250 | /* Set cmdiocb flag for the exchange | ||
2251 | * busy so sgl (xri) will not be | ||
2252 | * released until the abort xri is | ||
2253 | * received from hba, clear the | ||
2254 | * LPFC_DRIVER_ABORTED bit in case | ||
2255 | * it was driver initiated abort. | ||
2256 | */ | ||
2257 | spin_lock_irqsave(&phba->hbalock, | ||
2258 | iflag); | ||
2259 | cmdiocbp->iocb_flag &= | ||
2260 | ~LPFC_DRIVER_ABORTED; | ||
2261 | cmdiocbp->iocb_flag |= | ||
2262 | LPFC_EXCHANGE_BUSY; | ||
2263 | spin_unlock_irqrestore(&phba->hbalock, | ||
2264 | iflag); | ||
2265 | cmdiocbp->iocb.ulpStatus = | ||
2266 | IOSTAT_LOCAL_REJECT; | ||
2267 | cmdiocbp->iocb.un.ulpWord[4] = | ||
2268 | IOERR_ABORT_REQUESTED; | ||
2269 | /* | ||
2270 | * For SLI4, irsiocb contains NO_XRI | ||
2271 | * in sli_xritag, it shall not affect | ||
2272 | * releasing sgl (xri) process. | ||
2273 | */ | ||
2274 | saveq->iocb.ulpStatus = | ||
2275 | IOSTAT_LOCAL_REJECT; | ||
2276 | saveq->iocb.un.ulpWord[4] = | ||
2277 | IOERR_SLI_ABORTED; | ||
2278 | spin_lock_irqsave(&phba->hbalock, | ||
2279 | iflag); | ||
2280 | saveq->iocb_flag |= LPFC_DELAY_MEM_FREE; | ||
2281 | spin_unlock_irqrestore(&phba->hbalock, | ||
2282 | iflag); | ||
2244 | } | 2283 | } |
2245 | } | 2284 | } |
2246 | (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); | 2285 | (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); |
@@ -5987,12 +6026,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, | |||
5987 | else | 6026 | else |
5988 | bf_set(abort_cmd_ia, &wqe->abort_cmd, 0); | 6027 | bf_set(abort_cmd_ia, &wqe->abort_cmd, 0); |
5989 | bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); | 6028 | bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); |
5990 | abort_tag = iocbq->iocb.un.acxri.abortIoTag; | ||
5991 | wqe->words[5] = 0; | 6029 | wqe->words[5] = 0; |
5992 | bf_set(lpfc_wqe_gen_ct, &wqe->generic, | 6030 | bf_set(lpfc_wqe_gen_ct, &wqe->generic, |
5993 | ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); | 6031 | ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); |
5994 | abort_tag = iocbq->iocb.un.acxri.abortIoTag; | 6032 | abort_tag = iocbq->iocb.un.acxri.abortIoTag; |
5995 | wqe->generic.abort_tag = abort_tag; | ||
5996 | /* | 6033 | /* |
5997 | * The abort handler will send us CMD_ABORT_XRI_CN or | 6034 | * The abort handler will send us CMD_ABORT_XRI_CN or |
5998 | * CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX | 6035 | * CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX |
@@ -6121,15 +6158,15 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, | |||
6121 | if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe)) | 6158 | if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe)) |
6122 | return IOCB_ERROR; | 6159 | return IOCB_ERROR; |
6123 | 6160 | ||
6124 | if (piocb->iocb_flag & LPFC_IO_FCP) { | 6161 | if ((piocb->iocb_flag & LPFC_IO_FCP) || |
6162 | (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) { | ||
6125 | /* | 6163 | /* |
6126 | * For FCP command IOCB, get a new WQ index to distribute | 6164 | * For FCP command IOCB, get a new WQ index to distribute |
6127 | * WQE across the WQsr. On the other hand, for abort IOCB, | 6165 | * WQE across the WQsr. On the other hand, for abort IOCB, |
6128 | * it carries the same WQ index to the original command | 6166 | * it carries the same WQ index to the original command |
6129 | * IOCB. | 6167 | * IOCB. |
6130 | */ | 6168 | */ |
6131 | if ((piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && | 6169 | if (piocb->iocb_flag & LPFC_IO_FCP) |
6132 | (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) | ||
6133 | piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba); | 6170 | piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba); |
6134 | if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx], | 6171 | if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx], |
6135 | &wqe)) | 6172 | &wqe)) |
@@ -7004,7 +7041,14 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
7004 | abort_iocb->iocb.ulpContext != abort_context || | 7041 | abort_iocb->iocb.ulpContext != abort_context || |
7005 | (abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) == 0) | 7042 | (abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) == 0) |
7006 | spin_unlock_irq(&phba->hbalock); | 7043 | spin_unlock_irq(&phba->hbalock); |
7007 | else { | 7044 | else if (phba->sli_rev < LPFC_SLI_REV4) { |
7045 | /* | ||
7046 | * leave the SLI4 aborted command on the txcmplq | ||
7047 | * list and the command complete WCQE's XB bit | ||
7048 | * will tell whether the SGL (XRI) can be released | ||
7049 | * immediately or to the aborted SGL list for the | ||
7050 | * following abort XRI from the HBA. | ||
7051 | */ | ||
7008 | list_del_init(&abort_iocb->list); | 7052 | list_del_init(&abort_iocb->list); |
7009 | pring->txcmplq_cnt--; | 7053 | pring->txcmplq_cnt--; |
7010 | spin_unlock_irq(&phba->hbalock); | 7054 | spin_unlock_irq(&phba->hbalock); |
@@ -7013,11 +7057,13 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
7013 | * payload, so don't free data buffer till after | 7057 | * payload, so don't free data buffer till after |
7014 | * a hbeat. | 7058 | * a hbeat. |
7015 | */ | 7059 | */ |
7060 | spin_lock_irq(&phba->hbalock); | ||
7016 | abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE; | 7061 | abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE; |
7017 | |||
7018 | abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; | 7062 | abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; |
7063 | spin_unlock_irq(&phba->hbalock); | ||
7064 | |||
7019 | abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; | 7065 | abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; |
7020 | abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED; | 7066 | abort_iocb->iocb.un.ulpWord[4] = IOERR_ABORT_REQUESTED; |
7021 | (abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb); | 7067 | (abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb); |
7022 | } | 7068 | } |
7023 | } | 7069 | } |
@@ -7106,7 +7152,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
7106 | return 0; | 7152 | return 0; |
7107 | 7153 | ||
7108 | /* This signals the response to set the correct status | 7154 | /* This signals the response to set the correct status |
7109 | * before calling the completion handler. | 7155 | * before calling the completion handler |
7110 | */ | 7156 | */ |
7111 | cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED; | 7157 | cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED; |
7112 | 7158 | ||
@@ -7124,6 +7170,8 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
7124 | 7170 | ||
7125 | /* ABTS WQE must go to the same WQ as the WQE to be aborted */ | 7171 | /* ABTS WQE must go to the same WQ as the WQE to be aborted */ |
7126 | abtsiocbp->fcp_wqidx = cmdiocb->fcp_wqidx; | 7172 | abtsiocbp->fcp_wqidx = cmdiocb->fcp_wqidx; |
7173 | if (cmdiocb->iocb_flag & LPFC_IO_FCP) | ||
7174 | abtsiocbp->iocb_flag |= LPFC_USE_FCPWQIDX; | ||
7127 | 7175 | ||
7128 | if (phba->link_state >= LPFC_LINK_UP) | 7176 | if (phba->link_state >= LPFC_LINK_UP) |
7129 | iabt->ulpCommand = CMD_ABORT_XRI_CN; | 7177 | iabt->ulpCommand = CMD_ABORT_XRI_CN; |
@@ -7330,6 +7378,8 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, | |||
7330 | 7378 | ||
7331 | /* ABTS WQE must go to the same WQ as the WQE to be aborted */ | 7379 | /* ABTS WQE must go to the same WQ as the WQE to be aborted */ |
7332 | abtsiocb->fcp_wqidx = iocbq->fcp_wqidx; | 7380 | abtsiocb->fcp_wqidx = iocbq->fcp_wqidx; |
7381 | if (iocbq->iocb_flag & LPFC_IO_FCP) | ||
7382 | abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; | ||
7333 | 7383 | ||
7334 | if (lpfc_is_link_up(phba)) | 7384 | if (lpfc_is_link_up(phba)) |
7335 | abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN; | 7385 | abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN; |
@@ -8359,11 +8409,24 @@ void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba) | |||
8359 | } | 8409 | } |
8360 | } | 8410 | } |
8361 | 8411 | ||
8412 | /** | ||
8413 | * lpfc_sli4_iocb_param_transfer - Transfer pIocbOut and cmpl status to pIocbIn | ||
8414 | * @phba: pointer to lpfc hba data structure | ||
8415 | * @pIocbIn: pointer to the rspiocbq | ||
8416 | * @pIocbOut: pointer to the cmdiocbq | ||
8417 | * @wcqe: pointer to the complete wcqe | ||
8418 | * | ||
8419 | * This routine transfers the fields of a command iocbq to a response iocbq | ||
8420 | * by copying all the IOCB fields from command iocbq and transferring the | ||
8421 | * completion status information from the complete wcqe. | ||
8422 | **/ | ||
8362 | static void | 8423 | static void |
8363 | lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn, | 8424 | lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba, |
8425 | struct lpfc_iocbq *pIocbIn, | ||
8364 | struct lpfc_iocbq *pIocbOut, | 8426 | struct lpfc_iocbq *pIocbOut, |
8365 | struct lpfc_wcqe_complete *wcqe) | 8427 | struct lpfc_wcqe_complete *wcqe) |
8366 | { | 8428 | { |
8429 | unsigned long iflags; | ||
8367 | size_t offset = offsetof(struct lpfc_iocbq, iocb); | 8430 | size_t offset = offsetof(struct lpfc_iocbq, iocb); |
8368 | 8431 | ||
8369 | memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset, | 8432 | memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset, |
@@ -8379,6 +8442,13 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn, | |||
8379 | pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; | 8442 | pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; |
8380 | else | 8443 | else |
8381 | pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; | 8444 | pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; |
8445 | |||
8446 | /* Pick up HBA exchange busy condition */ | ||
8447 | if (bf_get(lpfc_wcqe_c_xb, wcqe)) { | ||
8448 | spin_lock_irqsave(&phba->hbalock, iflags); | ||
8449 | pIocbIn->iocb_flag |= LPFC_EXCHANGE_BUSY; | ||
8450 | spin_unlock_irqrestore(&phba->hbalock, iflags); | ||
8451 | } | ||
8382 | } | 8452 | } |
8383 | 8453 | ||
8384 | /** | 8454 | /** |
@@ -8419,7 +8489,7 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, | |||
8419 | } | 8489 | } |
8420 | 8490 | ||
8421 | /* Fake the irspiocbq and copy necessary response information */ | 8491 | /* Fake the irspiocbq and copy necessary response information */ |
8422 | lpfc_sli4_iocb_param_transfer(irspiocbq, cmdiocbq, wcqe); | 8492 | lpfc_sli4_iocb_param_transfer(phba, irspiocbq, cmdiocbq, wcqe); |
8423 | 8493 | ||
8424 | return irspiocbq; | 8494 | return irspiocbq; |
8425 | } | 8495 | } |
@@ -8976,7 +9046,7 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, | |||
8976 | } | 9046 | } |
8977 | 9047 | ||
8978 | /* Fake the irspiocb and copy necessary response information */ | 9048 | /* Fake the irspiocb and copy necessary response information */ |
8979 | lpfc_sli4_iocb_param_transfer(&irspiocbq, cmdiocbq, wcqe); | 9049 | lpfc_sli4_iocb_param_transfer(phba, &irspiocbq, cmdiocbq, wcqe); |
8980 | 9050 | ||
8981 | /* Pass the cmd_iocb and the rsp state to the upper layer */ | 9051 | /* Pass the cmd_iocb and the rsp state to the upper layer */ |
8982 | (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq); | 9052 | (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq); |
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index ba38de3c28f1..dfcf5437d1f5 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h | |||
@@ -53,17 +53,19 @@ struct lpfc_iocbq { | |||
53 | 53 | ||
54 | IOCB_t iocb; /* IOCB cmd */ | 54 | IOCB_t iocb; /* IOCB cmd */ |
55 | uint8_t retry; /* retry counter for IOCB cmd - if needed */ | 55 | uint8_t retry; /* retry counter for IOCB cmd - if needed */ |
56 | uint8_t iocb_flag; | 56 | uint16_t iocb_flag; |
57 | #define LPFC_IO_LIBDFC 1 /* libdfc iocb */ | 57 | #define LPFC_IO_LIBDFC 1 /* libdfc iocb */ |
58 | #define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */ | 58 | #define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */ |
59 | #define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ | 59 | #define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ |
60 | #define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ | 60 | #define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ |
61 | #define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */ | 61 | #define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */ |
62 | #define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */ | 62 | #define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */ |
63 | #define LPFC_FIP_ELS_ID_MASK 0xc0 /* ELS_ID range 0-3 */ | 63 | #define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */ |
64 | #define LPFC_FIP_ELS_ID_SHIFT 6 | 64 | #define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */ |
65 | |||
66 | #define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */ | ||
67 | #define LPFC_FIP_ELS_ID_SHIFT 14 | ||
65 | 68 | ||
66 | uint8_t abort_count; | ||
67 | uint8_t rsvd2; | 69 | uint8_t rsvd2; |
68 | uint32_t drvrTimeout; /* driver timeout in seconds */ | 70 | uint32_t drvrTimeout; /* driver timeout in seconds */ |
69 | uint32_t fcp_wqidx; /* index to FCP work queue */ | 71 | uint32_t fcp_wqidx; /* index to FCP work queue */ |