|
@@ -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
|
|
|
|
- && ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT)
|
|
|
|
- && (iocbq->iocb.un.ulpWord[4]
|
|
|
|
- == IOERR_ABORT_REQUESTED))) {
|
|
|
|
|
|
+ if (iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) {
|
|
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)
|
|
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,
|
|
* 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,
|
|
* 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;
|
|
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;
|
|
|
|
+ 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,
|
|
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,
|
|
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) &&
|
|
|
|
- (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN))
|
|
|
|
|
|
+ if (piocb->iocb_flag & LPFC_IO_FCP)
|
|
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,
|
|
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,
|
|
* 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,
|
|
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,
|
|
|
|
|
|
/* 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,
|
|
|
|
|
|
/* 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)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * 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,
|
|
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,
|
|
}
|
|
}
|
|
|
|
|
|
/* 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,
|
|
}
|
|
}
|
|
|
|
|
|
/* 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);
|