Commit 341af102 authored by James Smart's avatar James Smart Committed by James Bottomley

[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: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 2cec8029
...@@ -99,7 +99,7 @@ int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *, ...@@ -99,7 +99,7 @@ int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *,
void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *); void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
struct serv_parm *, uint32_t); struct serv_parm *, uint32_t, int);
int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
void lpfc_more_plogi(struct lpfc_vport *); void lpfc_more_plogi(struct lpfc_vport *);
void lpfc_more_adisc(struct lpfc_vport *); void lpfc_more_adisc(struct lpfc_vport *);
......
...@@ -4385,7 +4385,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, ...@@ -4385,7 +4385,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
did = Fabric_DID; did = Fabric_DID;
if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) { if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) {
/* For a FLOGI we accept, then if our portname is greater /* For a FLOGI we accept, then if our portname is greater
* then the remote portname we initiate Nport login. * then the remote portname we initiate Nport login.
*/ */
......
...@@ -1465,17 +1465,13 @@ typedef struct { /* FireFly BIU registers */ ...@@ -1465,17 +1465,13 @@ typedef struct { /* FireFly BIU registers */
#define CMD_IOCB_LOGENTRY_CN 0x94 #define CMD_IOCB_LOGENTRY_CN 0x94
#define CMD_IOCB_LOGENTRY_ASYNC_CN 0x96 #define CMD_IOCB_LOGENTRY_ASYNC_CN 0x96
/* Unhandled Data Security SLI Commands */ /* Data Security SLI Commands */
#define DSSCMD_IWRITE64_CR 0xD8 #define DSSCMD_IWRITE64_CR 0xF8
#define DSSCMD_IWRITE64_CX 0xD9 #define DSSCMD_IWRITE64_CX 0xF9
#define DSSCMD_IREAD64_CR 0xDA #define DSSCMD_IREAD64_CR 0xFA
#define DSSCMD_IREAD64_CX 0xDB #define DSSCMD_IREAD64_CX 0xFB
#define DSSCMD_INVALIDATE_DEK 0xDC
#define DSSCMD_SET_KEK 0xDD #define CMD_MAX_IOCB_CMD 0xFB
#define DSSCMD_GET_KEK_ID 0xDE
#define DSSCMD_GEN_XFER 0xDF
#define CMD_MAX_IOCB_CMD 0xE6
#define CMD_IOCB_MASK 0xff #define CMD_IOCB_MASK 0xff
#define MAX_MSG_DATA 28 /* max msg data in CMD_ADAPTER_MSG #define MAX_MSG_DATA 28 /* max msg data in CMD_ADAPTER_MSG
......
...@@ -62,7 +62,7 @@ lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -62,7 +62,7 @@ lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
int int
lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct serv_parm * sp, uint32_t class) struct serv_parm *sp, uint32_t class, int flogi)
{ {
volatile struct serv_parm *hsp = &vport->fc_sparam; volatile struct serv_parm *hsp = &vport->fc_sparam;
uint16_t hsp_value, ssp_value = 0; uint16_t hsp_value, ssp_value = 0;
...@@ -75,49 +75,56 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -75,49 +75,56 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
* correcting the byte values. * correcting the byte values.
*/ */
if (sp->cls1.classValid) { if (sp->cls1.classValid) {
hsp_value = (hsp->cls1.rcvDataSizeMsb << 8) | if (!flogi) {
hsp->cls1.rcvDataSizeLsb; hsp_value = ((hsp->cls1.rcvDataSizeMsb << 8) |
ssp_value = (sp->cls1.rcvDataSizeMsb << 8) | hsp->cls1.rcvDataSizeLsb);
sp->cls1.rcvDataSizeLsb; ssp_value = ((sp->cls1.rcvDataSizeMsb << 8) |
sp->cls1.rcvDataSizeLsb);
if (!ssp_value) if (!ssp_value)
goto bad_service_param; goto bad_service_param;
if (ssp_value > hsp_value) { if (ssp_value > hsp_value) {
sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb; sp->cls1.rcvDataSizeLsb =
sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb; hsp->cls1.rcvDataSizeLsb;
sp->cls1.rcvDataSizeMsb =
hsp->cls1.rcvDataSizeMsb;
} }
} else if (class == CLASS1) {
goto bad_service_param;
} }
} else if (class == CLASS1)
goto bad_service_param;
if (sp->cls2.classValid) { if (sp->cls2.classValid) {
hsp_value = (hsp->cls2.rcvDataSizeMsb << 8) | if (!flogi) {
hsp->cls2.rcvDataSizeLsb; hsp_value = ((hsp->cls2.rcvDataSizeMsb << 8) |
ssp_value = (sp->cls2.rcvDataSizeMsb << 8) | hsp->cls2.rcvDataSizeLsb);
sp->cls2.rcvDataSizeLsb; ssp_value = ((sp->cls2.rcvDataSizeMsb << 8) |
sp->cls2.rcvDataSizeLsb);
if (!ssp_value) if (!ssp_value)
goto bad_service_param; goto bad_service_param;
if (ssp_value > hsp_value) { if (ssp_value > hsp_value) {
sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb; sp->cls2.rcvDataSizeLsb =
sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb; hsp->cls2.rcvDataSizeLsb;
sp->cls2.rcvDataSizeMsb =
hsp->cls2.rcvDataSizeMsb;
} }
} else if (class == CLASS2) {
goto bad_service_param;
} }
} else if (class == CLASS2)
goto bad_service_param;
if (sp->cls3.classValid) { if (sp->cls3.classValid) {
hsp_value = (hsp->cls3.rcvDataSizeMsb << 8) | if (!flogi) {
hsp->cls3.rcvDataSizeLsb; hsp_value = ((hsp->cls3.rcvDataSizeMsb << 8) |
ssp_value = (sp->cls3.rcvDataSizeMsb << 8) | hsp->cls3.rcvDataSizeLsb);
sp->cls3.rcvDataSizeLsb; ssp_value = ((sp->cls3.rcvDataSizeMsb << 8) |
sp->cls3.rcvDataSizeLsb);
if (!ssp_value) if (!ssp_value)
goto bad_service_param; goto bad_service_param;
if (ssp_value > hsp_value) { if (ssp_value > hsp_value) {
sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb; sp->cls3.rcvDataSizeLsb =
sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb; hsp->cls3.rcvDataSizeLsb;
sp->cls3.rcvDataSizeMsb =
hsp->cls3.rcvDataSizeMsb;
} }
} else if (class == CLASS3) {
goto bad_service_param;
} }
} else if (class == CLASS3)
goto bad_service_param;
/* /*
* Preserve the upper four bits of the MSB from the PLOGI response. * 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,7 +302,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
NULL); NULL);
return 0; return 0;
} }
if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) { if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0) == 0)) {
/* Reject this request because invalid parameters */ /* Reject this request because invalid parameters */
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
...@@ -831,7 +838,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, ...@@ -831,7 +838,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
"0142 PLOGI RSP: Invalid WWN.\n"); "0142 PLOGI RSP: Invalid WWN.\n");
goto out; goto out;
} }
if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3)) if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0))
goto out; goto out;
/* PLOGI chkparm OK */ /* PLOGI chkparm OK */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
......
...@@ -626,6 +626,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, ...@@ -626,6 +626,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
&phba->sli4_hba.lpfc_abts_scsi_buf_list, list) { &phba->sli4_hba.lpfc_abts_scsi_buf_list, list) {
if (psb->cur_iocbq.sli4_xritag == xri) { if (psb->cur_iocbq.sli4_xritag == xri) {
list_del(&psb->list); list_del(&psb->list);
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS; psb->status = IOSTAT_SUCCESS;
spin_unlock_irqrestore( spin_unlock_irqrestore(
&phba->sli4_hba.abts_scsi_buf_list_lock, &phba->sli4_hba.abts_scsi_buf_list_lock,
...@@ -688,11 +689,12 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) ...@@ -688,11 +689,12 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
list); list);
if (status) { if (status) {
/* Put this back on the abort scsi list */ /* Put this back on the abort scsi list */
psb->status = IOSTAT_LOCAL_REJECT; psb->exch_busy = 1;
psb->result = IOERR_ABORT_REQUESTED;
rc++; rc++;
} else } else {
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS; psb->status = IOSTAT_SUCCESS;
}
/* Put it back into the SCSI buffer list */ /* Put it back into the SCSI buffer list */
lpfc_release_scsi_buf_s4(phba, psb); lpfc_release_scsi_buf_s4(phba, psb);
} }
...@@ -839,11 +841,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) ...@@ -839,11 +841,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
psb->cur_iocbq.sli4_xritag); psb->cur_iocbq.sli4_xritag);
if (status) { if (status) {
/* Put this back on the abort scsi list */ /* Put this back on the abort scsi list */
psb->status = IOSTAT_LOCAL_REJECT; psb->exch_busy = 1;
psb->result = IOERR_ABORT_REQUESTED;
rc++; rc++;
} else } else {
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS; psb->status = IOSTAT_SUCCESS;
}
/* Put it back into the SCSI buffer list */ /* Put it back into the SCSI buffer list */
lpfc_release_scsi_buf_s4(phba, psb); lpfc_release_scsi_buf_s4(phba, psb);
break; break;
...@@ -857,11 +860,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) ...@@ -857,11 +860,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
list); list);
if (status) { if (status) {
/* Put this back on the abort scsi list */ /* Put this back on the abort scsi list */
psb->status = IOSTAT_LOCAL_REJECT; psb->exch_busy = 1;
psb->result = IOERR_ABORT_REQUESTED;
rc++; rc++;
} else } else {
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS; psb->status = IOSTAT_SUCCESS;
}
/* Put it back into the SCSI buffer list */ /* Put it back into the SCSI buffer list */
lpfc_release_scsi_buf_s4(phba, psb); lpfc_release_scsi_buf_s4(phba, psb);
} }
...@@ -951,8 +955,7 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) ...@@ -951,8 +955,7 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
{ {
unsigned long iflag = 0; unsigned long iflag = 0;
if (psb->status == IOSTAT_LOCAL_REJECT if (psb->exch_busy) {
&& psb->result == IOERR_ABORT_REQUESTED) {
spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock, spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock,
iflag); iflag);
psb->pCmd = NULL; psb->pCmd = NULL;
...@@ -2221,6 +2224,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, ...@@ -2221,6 +2224,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
lpfc_cmd->status = pIocbOut->iocb.ulpStatus; lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
/* pick up SLI4 exhange busy status from HBA */
lpfc_cmd->exch_busy = pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY;
if (pnode && NLP_CHK_NODE_ACT(pnode)) if (pnode && NLP_CHK_NODE_ACT(pnode))
atomic_dec(&pnode->cmd_pending); atomic_dec(&pnode->cmd_pending);
...@@ -2990,6 +2996,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) ...@@ -2990,6 +2996,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
/* ABTS WQE must go to the same WQ as the WQE to be aborted */ /* ABTS WQE must go to the same WQ as the WQE to be aborted */
abtsiocb->fcp_wqidx = iocb->fcp_wqidx; abtsiocb->fcp_wqidx = iocb->fcp_wqidx;
abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX;
if (lpfc_is_link_up(phba)) if (lpfc_is_link_up(phba))
icmd->ulpCommand = CMD_ABORT_XRI_CN; icmd->ulpCommand = CMD_ABORT_XRI_CN;
......
...@@ -118,6 +118,7 @@ struct lpfc_scsi_buf { ...@@ -118,6 +118,7 @@ struct lpfc_scsi_buf {
uint32_t timeout; uint32_t timeout;
uint16_t exch_busy; /* SLI4 hba reported XB on complete WCQE */
uint16_t status; /* From IOCB Word 7- ulpStatus */ uint16_t status; /* From IOCB Word 7- ulpStatus */
uint32_t result; /* From IOCB Word 4. */ uint32_t result; /* From IOCB Word 4. */
......
...@@ -580,10 +580,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) ...@@ -580,10 +580,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
else else
sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag); sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag);
if (sglq) { if (sglq) {
if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED if (iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) {
&& ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT)
&& (iocbq->iocb.un.ulpWord[4]
== IOERR_ABORT_REQUESTED))) {
spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock,
iflag); iflag);
list_add(&sglq->list, list_add(&sglq->list,
...@@ -764,10 +761,6 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) ...@@ -764,10 +761,6 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
case DSSCMD_IWRITE64_CX: case DSSCMD_IWRITE64_CX:
case DSSCMD_IREAD64_CR: case DSSCMD_IREAD64_CR:
case DSSCMD_IREAD64_CX: case DSSCMD_IREAD64_CX:
case DSSCMD_INVALIDATE_DEK:
case DSSCMD_SET_KEK:
case DSSCMD_GET_KEK_ID:
case DSSCMD_GEN_XFER:
type = LPFC_SOL_IOCB; type = LPFC_SOL_IOCB;
break; break;
case CMD_ABORT_XRI_CN: case CMD_ABORT_XRI_CN:
...@@ -2228,9 +2221,15 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ...@@ -2228,9 +2221,15 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
* All other are passed to the completion callback. * All other are passed to the completion callback.
*/ */
if (pring->ringno == LPFC_ELS_RING) { if (pring->ringno == LPFC_ELS_RING) {
if (cmdiocbp->iocb_flag & LPFC_DRIVER_ABORTED) { if ((phba->sli_rev < LPFC_SLI_REV4) &&
(cmdiocbp->iocb_flag &
LPFC_DRIVER_ABORTED)) {
spin_lock_irqsave(&phba->hbalock,
iflag);
cmdiocbp->iocb_flag &= cmdiocbp->iocb_flag &=
~LPFC_DRIVER_ABORTED; ~LPFC_DRIVER_ABORTED;
spin_unlock_irqrestore(&phba->hbalock,
iflag);
saveq->iocb.ulpStatus = saveq->iocb.ulpStatus =
IOSTAT_LOCAL_REJECT; IOSTAT_LOCAL_REJECT;
saveq->iocb.un.ulpWord[4] = saveq->iocb.un.ulpWord[4] =
...@@ -2240,7 +2239,47 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ...@@ -2240,7 +2239,47 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
* of DMAing payload, so don't free data * of DMAing payload, so don't free data
* buffer till after a hbeat. * buffer till after a hbeat.
*/ */
spin_lock_irqsave(&phba->hbalock,
iflag);
saveq->iocb_flag |= LPFC_DELAY_MEM_FREE;
spin_unlock_irqrestore(&phba->hbalock,
iflag);
}
if ((phba->sli_rev == LPFC_SLI_REV4) &&
(saveq->iocb_flag & LPFC_EXCHANGE_BUSY)) {
/* Set cmdiocb flag for the exchange
* busy so sgl (xri) will not be
* released until the abort xri is
* received from hba, clear the
* LPFC_DRIVER_ABORTED bit in case
* it was driver initiated abort.
*/
spin_lock_irqsave(&phba->hbalock,
iflag);
cmdiocbp->iocb_flag &=
~LPFC_DRIVER_ABORTED;
cmdiocbp->iocb_flag |=
LPFC_EXCHANGE_BUSY;
spin_unlock_irqrestore(&phba->hbalock,
iflag);
cmdiocbp->iocb.ulpStatus =
IOSTAT_LOCAL_REJECT;
cmdiocbp->iocb.un.ulpWord[4] =
IOERR_ABORT_REQUESTED;
/*
* For SLI4, irsiocb contains NO_XRI
* in sli_xritag, it shall not affect
* releasing sgl (xri) process.
*/
saveq->iocb.ulpStatus =
IOSTAT_LOCAL_REJECT;
saveq->iocb.un.ulpWord[4] =
IOERR_SLI_ABORTED;
spin_lock_irqsave(&phba->hbalock,
iflag);
saveq->iocb_flag |= LPFC_DELAY_MEM_FREE; saveq->iocb_flag |= LPFC_DELAY_MEM_FREE;
spin_unlock_irqrestore(&phba->hbalock,
iflag);
} }
} }
(cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
...@@ -5987,12 +6026,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, ...@@ -5987,12 +6026,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
else else
bf_set(abort_cmd_ia, &wqe->abort_cmd, 0); bf_set(abort_cmd_ia, &wqe->abort_cmd, 0);
bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG);
abort_tag = iocbq->iocb.un.acxri.abortIoTag;
wqe->words[5] = 0; wqe->words[5] = 0;
bf_set(lpfc_wqe_gen_ct, &wqe->generic, bf_set(lpfc_wqe_gen_ct, &wqe->generic,
((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
abort_tag = iocbq->iocb.un.acxri.abortIoTag; abort_tag = iocbq->iocb.un.acxri.abortIoTag;
wqe->generic.abort_tag = abort_tag;
/* /*
* The abort handler will send us CMD_ABORT_XRI_CN or * The abort handler will send us CMD_ABORT_XRI_CN or
* CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX * 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,15 +6158,15 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe)) if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe))
return IOCB_ERROR; return IOCB_ERROR;
if (piocb->iocb_flag & LPFC_IO_FCP) { if ((piocb->iocb_flag & LPFC_IO_FCP) ||
(piocb->iocb_flag & LPFC_USE_FCPWQIDX)) {
/* /*
* For FCP command IOCB, get a new WQ index to distribute * For FCP command IOCB, get a new WQ index to distribute
* WQE across the WQsr. On the other hand, for abort IOCB, * WQE across the WQsr. On the other hand, for abort IOCB,
* it carries the same WQ index to the original command * it carries the same WQ index to the original command
* IOCB. * IOCB.
*/ */
if ((piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && if (piocb->iocb_flag & LPFC_IO_FCP)
(piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN))
piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba); piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba);
if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx], if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx],
&wqe)) &wqe))
...@@ -7004,7 +7041,14 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ...@@ -7004,7 +7041,14 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
abort_iocb->iocb.ulpContext != abort_context || abort_iocb->iocb.ulpContext != abort_context ||
(abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) == 0) (abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) == 0)
spin_unlock_irq(&phba->hbalock); spin_unlock_irq(&phba->hbalock);
else { else if (phba->sli_rev < LPFC_SLI_REV4) {
/*
* leave the SLI4 aborted command on the txcmplq
* list and the command complete WCQE's XB bit
* will tell whether the SGL (XRI) can be released
* immediately or to the aborted SGL list for the
* following abort XRI from the HBA.
*/
list_del_init(&abort_iocb->list); list_del_init(&abort_iocb->list);
pring->txcmplq_cnt--; pring->txcmplq_cnt--;
spin_unlock_irq(&phba->hbalock); spin_unlock_irq(&phba->hbalock);
...@@ -7013,11 +7057,13 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ...@@ -7013,11 +7057,13 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* payload, so don't free data buffer till after * payload, so don't free data buffer till after
* a hbeat. * a hbeat.
*/ */
spin_lock_irq(&phba->hbalock);
abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE; abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE;
abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;
spin_unlock_irq(&phba->hbalock);
abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED; abort_iocb->iocb.un.ulpWord[4] = IOERR_ABORT_REQUESTED;
(abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb); (abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb);
} }
} }
...@@ -7106,7 +7152,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ...@@ -7106,7 +7152,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
return 0; return 0;
/* This signals the response to set the correct status /* This signals the response to set the correct status
* before calling the completion handler. * before calling the completion handler
*/ */
cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED; cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED;
...@@ -7124,6 +7170,8 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ...@@ -7124,6 +7170,8 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/* ABTS WQE must go to the same WQ as the WQE to be aborted */ /* ABTS WQE must go to the same WQ as the WQE to be aborted */
abtsiocbp->fcp_wqidx = cmdiocb->fcp_wqidx; abtsiocbp->fcp_wqidx = cmdiocb->fcp_wqidx;
if (cmdiocb->iocb_flag & LPFC_IO_FCP)
abtsiocbp->iocb_flag |= LPFC_USE_FCPWQIDX;
if (phba->link_state >= LPFC_LINK_UP) if (phba->link_state >= LPFC_LINK_UP)
iabt->ulpCommand = CMD_ABORT_XRI_CN; iabt->ulpCommand = CMD_ABORT_XRI_CN;
...@@ -7330,6 +7378,8 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, ...@@ -7330,6 +7378,8 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
/* ABTS WQE must go to the same WQ as the WQE to be aborted */ /* ABTS WQE must go to the same WQ as the WQE to be aborted */
abtsiocb->fcp_wqidx = iocbq->fcp_wqidx; abtsiocb->fcp_wqidx = iocbq->fcp_wqidx;
if (iocbq->iocb_flag & LPFC_IO_FCP)
abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX;
if (lpfc_is_link_up(phba)) if (lpfc_is_link_up(phba))
abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN; abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN;
...@@ -8359,11 +8409,24 @@ void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba) ...@@ -8359,11 +8409,24 @@ void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba)
} }
} }
/**
* lpfc_sli4_iocb_param_transfer - Transfer pIocbOut and cmpl status to pIocbIn
* @phba: pointer to lpfc hba data structure
* @pIocbIn: pointer to the rspiocbq
* @pIocbOut: pointer to the cmdiocbq
* @wcqe: pointer to the complete wcqe
*
* This routine transfers the fields of a command iocbq to a response iocbq
* by copying all the IOCB fields from command iocbq and transferring the
* completion status information from the complete wcqe.
**/
static void static void
lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn, lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba,
struct lpfc_iocbq *pIocbIn,
struct lpfc_iocbq *pIocbOut, struct lpfc_iocbq *pIocbOut,
struct lpfc_wcqe_complete *wcqe) struct lpfc_wcqe_complete *wcqe)
{ {
unsigned long iflags;
size_t offset = offsetof(struct lpfc_iocbq, iocb); size_t offset = offsetof(struct lpfc_iocbq, iocb);
memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset, memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset,
...@@ -8379,6 +8442,13 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn, ...@@ -8379,6 +8442,13 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn,
pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
else else
pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
/* Pick up HBA exchange busy condition */
if (bf_get(lpfc_wcqe_c_xb, wcqe)) {
spin_lock_irqsave(&phba->hbalock, iflags);
pIocbIn->iocb_flag |= LPFC_EXCHANGE_BUSY;
spin_unlock_irqrestore(&phba->hbalock, iflags);
}
} }
/** /**
...@@ -8419,7 +8489,7 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, ...@@ -8419,7 +8489,7 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba,
} }
/* Fake the irspiocbq and copy necessary response information */ /* Fake the irspiocbq and copy necessary response information */
lpfc_sli4_iocb_param_transfer(irspiocbq, cmdiocbq, wcqe); lpfc_sli4_iocb_param_transfer(phba, irspiocbq, cmdiocbq, wcqe);
return irspiocbq; return irspiocbq;
} }
...@@ -8976,7 +9046,7 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, ...@@ -8976,7 +9046,7 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba,
} }
/* Fake the irspiocb and copy necessary response information */ /* Fake the irspiocb and copy necessary response information */
lpfc_sli4_iocb_param_transfer(&irspiocbq, cmdiocbq, wcqe); lpfc_sli4_iocb_param_transfer(phba, &irspiocbq, cmdiocbq, wcqe);
/* Pass the cmd_iocb and the rsp state to the upper layer */ /* Pass the cmd_iocb and the rsp state to the upper layer */
(cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq); (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq);
......
...@@ -53,17 +53,19 @@ struct lpfc_iocbq { ...@@ -53,17 +53,19 @@ struct lpfc_iocbq {
IOCB_t iocb; /* IOCB cmd */ IOCB_t iocb; /* IOCB cmd */
uint8_t retry; /* retry counter for IOCB cmd - if needed */ uint8_t retry; /* retry counter for IOCB cmd - if needed */
uint8_t iocb_flag; uint16_t iocb_flag;
#define LPFC_IO_LIBDFC 1 /* libdfc iocb */ #define LPFC_IO_LIBDFC 1 /* libdfc iocb */
#define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */ #define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */
#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ #define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */
#define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ #define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */
#define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */ #define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */
#define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */ #define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */
#define LPFC_FIP_ELS_ID_MASK 0xc0 /* ELS_ID range 0-3 */ #define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */
#define LPFC_FIP_ELS_ID_SHIFT 6 #define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */
#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */
#define LPFC_FIP_ELS_ID_SHIFT 14
uint8_t abort_count;
uint8_t rsvd2; uint8_t rsvd2;
uint32_t drvrTimeout; /* driver timeout in seconds */ uint32_t drvrTimeout; /* driver timeout in seconds */
uint32_t fcp_wqidx; /* index to FCP work queue */ uint32_t fcp_wqidx; /* index to FCP work queue */
......
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