Commit 0bd4ca25 authored by James.Smart@Emulex.Com's avatar James.Smart@Emulex.Com Committed by James Bottomley

[SCSI] lpfc: Fix eh_ return codes for commands

Return FAILED from eh_ routines if command(s) is(are) not completed

There were scenarios where we may have returned from the error
handlers prior to all affected commands being flushed to the midlayer.
Add changes to ensure this doesn't happen.
Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 4a0dfcde
......@@ -143,6 +143,7 @@ LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
int lpfc_mem_alloc(struct lpfc_hba *);
void lpfc_mem_free(struct lpfc_hba *);
struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
int lpfc_sli_hba_setup(struct lpfc_hba *);
......
......@@ -224,13 +224,12 @@ lpfc_gen_req(struct lpfc_hba *phba, struct lpfc_dmabuf *bmp,
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
IOCB_t *icmd;
struct lpfc_iocbq *geniocb = NULL;
struct lpfc_iocbq *geniocb;
/* Allocate buffer for command iocb */
spin_lock_irq(phba->host->host_lock);
list_remove_head(lpfc_iocb_list, geniocb, struct lpfc_iocbq, list);
geniocb = lpfc_sli_get_iocbq(phba);
spin_unlock_irq(phba->host->host_lock);
if (geniocb == NULL)
......
......@@ -102,9 +102,8 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba,
uint16_t cmdSize,
uint8_t retry, struct lpfc_nodelist * ndlp, uint32_t elscmd)
{
struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
struct lpfc_sli_ring *pring;
struct lpfc_iocbq *elsiocb = NULL;
struct lpfc_iocbq *elsiocb;
struct lpfc_dmabuf *pcmd, *prsp, *pbuflist;
struct ulp_bde64 *bpl;
IOCB_t *icmd;
......@@ -114,10 +113,9 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba,
if (phba->hba_state < LPFC_LINK_UP)
return NULL;
/* Allocate buffer for command iocb */
spin_lock_irq(phba->host->host_lock);
list_remove_head(lpfc_iocb_list, elsiocb, struct lpfc_iocbq, list);
elsiocb = lpfc_sli_get_iocbq(phba);
spin_unlock_irq(phba->host->host_lock);
if (elsiocb == NULL)
......
......@@ -870,8 +870,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
int type)
{
IOCB_t *icmd;
struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
struct lpfc_iocbq *iocb = NULL;
struct lpfc_iocbq *iocb;
struct lpfc_dmabuf *mp1, *mp2;
cnt += pring->missbufcnt;
......@@ -880,7 +879,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
while (cnt > 0) {
/* Allocate buffer for command iocb */
spin_lock_irq(phba->host->host_lock);
list_remove_head(lpfc_iocb_list, iocb, struct lpfc_iocbq, list);
iocb = lpfc_sli_get_iocbq(phba);
spin_unlock_irq(phba->host->host_lock);
if (iocb == NULL) {
pring->missbufcnt = cnt;
......
This diff is collapsed.
......@@ -65,6 +65,16 @@ typedef enum _lpfc_iocb_type {
LPFC_ABORT_IOCB
} lpfc_iocb_type;
struct lpfc_iocbq *
lpfc_sli_get_iocbq(struct lpfc_hba * phba)
{
struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
struct lpfc_iocbq * iocbq = NULL;
list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list);
return iocbq;
}
void
lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
{
......@@ -1055,7 +1065,6 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
struct lpfc_iocbq *next_iocb;
struct lpfc_iocbq *cmdiocbp;
struct lpfc_iocbq *saveq;
struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
uint8_t iocb_cmd_type;
lpfc_iocb_type type;
......@@ -1097,7 +1106,6 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
}
rmb();
lpfc_iocb_list = &phba->lpfc_iocb_list;
while (pring->rspidx != portRspPut) {
/*
* Build a completion list and call the appropriate handler.
......@@ -1113,8 +1121,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
* received.
*/
entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx);
list_remove_head(lpfc_iocb_list, rspiocbp, struct lpfc_iocbq,
list);
rspiocbp = lpfc_sli_get_iocbq(phba);
if (rspiocbp == NULL) {
printk(KERN_ERR "%s: out of buffers! Failing "
"completion.\n", __FUNCTION__);
......@@ -2407,13 +2414,12 @@ lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba,
struct lpfc_sli_ring * pring,
struct lpfc_iocbq * cmdiocb)
{
struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
struct lpfc_iocbq *abtsiocbp = NULL;
struct lpfc_iocbq *abtsiocbp;
IOCB_t *icmd = NULL;
IOCB_t *iabt = NULL;
/* issue ABTS for this IOCB based on iotag */
list_remove_head(lpfc_iocb_list, abtsiocbp, struct lpfc_iocbq, list);
abtsiocbp = lpfc_sli_get_iocbq(phba);
if (abtsiocbp == NULL)
return 0;
......@@ -2454,28 +2460,37 @@ lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba,
}
static int
lpfc_sli_validate_iocb_cmd(struct lpfc_scsi_buf *lpfc_cmd, uint16_t tgt_id,
uint64_t lun_id, struct lpfc_iocbq *iocb,
uint32_t ctx, lpfc_ctx_cmd ctx_cmd)
lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, uint16_t tgt_id,
uint64_t lun_id, uint32_t ctx,
lpfc_ctx_cmd ctx_cmd)
{
struct lpfc_scsi_buf *lpfc_cmd;
struct scsi_cmnd *cmnd;
int rc = 1;
if (lpfc_cmd == NULL)
if (!(iocbq->iocb_flag & LPFC_IO_FCP))
return rc;
lpfc_cmd = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq);
cmnd = lpfc_cmd->pCmd;
if (cmnd == NULL)
return rc;
switch (ctx_cmd) {
case LPFC_CTX_LUN:
if ((lpfc_cmd->pCmd->device->id == tgt_id) &&
(lpfc_cmd->pCmd->device->lun == lun_id))
if ((cmnd->device->id == tgt_id) &&
(cmnd->device->lun == lun_id))
rc = 0;
break;
case LPFC_CTX_TGT:
if (lpfc_cmd->pCmd->device->id == tgt_id)
if (cmnd->device->id == tgt_id)
rc = 0;
break;
case LPFC_CTX_CTX:
if (iocb->iocb.ulpContext == ctx)
if (iocbq->iocb.ulpContext == ctx)
rc = 0;
break;
case LPFC_CTX_HOST:
rc = 0;
break;
......@@ -2492,30 +2507,17 @@ int
lpfc_sli_sum_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd ctx_cmd)
{
struct lpfc_iocbq *iocb, *next_iocb;
IOCB_t *cmd = NULL;
struct lpfc_scsi_buf *lpfc_cmd;
int sum = 0, ret_val = 0;
struct lpfc_iocbq *iocbq;
int sum, i;
/* Next check the txcmplq */
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
cmd = &iocb->iocb;
/* Must be a FCP command */
if ((cmd->ulpCommand != CMD_FCP_ICMND64_CR) &&
(cmd->ulpCommand != CMD_FCP_IWRITE64_CR) &&
(cmd->ulpCommand != CMD_FCP_IREAD64_CR)) {
continue;
}
for (i = 1, sum = 0; i <= phba->sli.last_iotag; i++) {
iocbq = phba->sli.iocbq_lookup[i];
/* context1 MUST be a struct lpfc_scsi_buf */
lpfc_cmd = (struct lpfc_scsi_buf *) (iocb->context1);
ret_val = lpfc_sli_validate_iocb_cmd(lpfc_cmd, tgt_id, lun_id,
NULL, 0, ctx_cmd);
if (ret_val != 0)
continue;
sum++;
if (lpfc_sli_validate_fcp_iocb (iocbq, tgt_id, lun_id,
0, ctx_cmd) == 0)
sum++;
}
return sum;
}
......@@ -2534,38 +2536,27 @@ lpfc_sli_abort_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
uint16_t tgt_id, uint64_t lun_id, uint32_t ctx,
lpfc_ctx_cmd abort_cmd)
{
struct lpfc_iocbq *iocb, *next_iocb;
struct lpfc_iocbq *abtsiocb = NULL;
struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
struct lpfc_iocbq *iocbq;
struct lpfc_iocbq *abtsiocb;
IOCB_t *cmd = NULL;
struct lpfc_scsi_buf *lpfc_cmd;
int errcnt = 0, ret_val = 0;
int i;
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
cmd = &iocb->iocb;
/* Must be a FCP command */
if ((cmd->ulpCommand != CMD_FCP_ICMND64_CR) &&
(cmd->ulpCommand != CMD_FCP_IWRITE64_CR) &&
(cmd->ulpCommand != CMD_FCP_IREAD64_CR)) {
continue;
}
for (i = 1; i <= phba->sli.last_iotag; i++) {
iocbq = phba->sli.iocbq_lookup[i];
/* context1 MUST be a struct lpfc_scsi_buf */
lpfc_cmd = (struct lpfc_scsi_buf *) (iocb->context1);
ret_val = lpfc_sli_validate_iocb_cmd(lpfc_cmd, tgt_id, lun_id,
iocb, ctx, abort_cmd);
if (ret_val != 0)
if (lpfc_sli_validate_fcp_iocb (iocbq, tgt_id, lun_id,
0, abort_cmd) != 0)
continue;
/* issue ABTS for this IOCB based on iotag */
list_remove_head(lpfc_iocb_list, abtsiocb, struct lpfc_iocbq,
list);
abtsiocb = lpfc_sli_get_iocbq(phba);
if (abtsiocb == NULL) {
errcnt++;
continue;
}
cmd = &iocbq->iocb;
abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS;
abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext;
abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag;
......
......@@ -41,6 +41,7 @@ struct lpfc_iocbq {
uint8_t iocb_flag;
#define LPFC_IO_LIBDFC 1 /* libdfc iocb */
#define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */
#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */
uint8_t abort_count;
uint8_t rsvd2;
......
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