scsi: lpfc: Fix RQ empty firmware trap

When nvme target deferred receive logic waits for exchange resources,
the corresponding receive buffer is not replenished with the hardware.
This can result in a lack of asynchronous receive buffer resources in
the hardware, resulting in a "2885 Port Status Event: ... error
1=0x52004a01 ..." message.

Correct by replenishing the buffer whenenver the deferred logic kicks
in.  Update corresponding debug messages and statistics as well.

[mkp: applied by hand]

Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <james.smart@broadcom.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
James Smart 2018-01-30 15:58:52 -08:00 committed by Martin K. Petersen
parent 91455b8509
commit 411de511c6
5 changed files with 51 additions and 15 deletions

View File

@ -259,6 +259,12 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
atomic_read(&tgtp->xmt_abort_rsp), atomic_read(&tgtp->xmt_abort_rsp),
atomic_read(&tgtp->xmt_abort_rsp_error)); atomic_read(&tgtp->xmt_abort_rsp_error));
len += snprintf(buf + len, PAGE_SIZE - len,
"DELAY: ctx %08x fod %08x wqfull %08x\n",
atomic_read(&tgtp->defer_ctx),
atomic_read(&tgtp->defer_fod),
atomic_read(&tgtp->defer_wqfull));
/* Calculate outstanding IOs */ /* Calculate outstanding IOs */
tot = atomic_read(&tgtp->rcv_fcp_cmd_drop); tot = atomic_read(&tgtp->rcv_fcp_cmd_drop);
tot += atomic_read(&tgtp->xmt_fcp_release); tot += atomic_read(&tgtp->xmt_fcp_release);

View File

@ -753,12 +753,16 @@ lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp)
drqe.address_hi = putPaddrHigh(rqb_entry->dbuf.phys); drqe.address_hi = putPaddrHigh(rqb_entry->dbuf.phys);
rc = lpfc_sli4_rq_put(rqb_entry->hrq, rqb_entry->drq, &hrqe, &drqe); rc = lpfc_sli4_rq_put(rqb_entry->hrq, rqb_entry->drq, &hrqe, &drqe);
if (rc < 0) { if (rc < 0) {
(rqbp->rqb_free_buffer)(phba, rqb_entry);
lpfc_printf_log(phba, KERN_ERR, LOG_INIT, lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"6409 Cannot post to RQ %d: %x %x\n", "6409 Cannot post to HRQ %d: %x %x %x "
"DRQ %x %x\n",
rqb_entry->hrq->queue_id, rqb_entry->hrq->queue_id,
rqb_entry->hrq->host_index, rqb_entry->hrq->host_index,
rqb_entry->hrq->hba_index); rqb_entry->hrq->hba_index,
(rqbp->rqb_free_buffer)(phba, rqb_entry); rqb_entry->hrq->entry_count,
rqb_entry->drq->host_index,
rqb_entry->drq->hba_index);
} else { } else {
list_add_tail(&rqb_entry->hbuf.list, &rqbp->rqb_buffer_list); list_add_tail(&rqb_entry->hbuf.list, &rqbp->rqb_buffer_list);
rqbp->buffer_count++; rqbp->buffer_count++;

View File

@ -270,8 +270,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
"NVMET RCV BUSY: xri x%x sz %d " "NVMET RCV BUSY: xri x%x sz %d "
"from %06x\n", "from %06x\n",
oxid, size, sid); oxid, size, sid);
/* defer repost rcv buffer till .defer_rcv callback */
ctxp->flag &= ~LPFC_NVMET_DEFER_RCV_REPOST;
atomic_inc(&tgtp->rcv_fcp_cmd_out); atomic_inc(&tgtp->rcv_fcp_cmd_out);
return; return;
} }
@ -837,6 +835,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
list_add_tail(&nvmewqeq->list, &wq->wqfull_list); list_add_tail(&nvmewqeq->list, &wq->wqfull_list);
wq->q_flag |= HBA_NVMET_WQFULL; wq->q_flag |= HBA_NVMET_WQFULL;
spin_unlock_irqrestore(&pring->ring_lock, iflags); spin_unlock_irqrestore(&pring->ring_lock, iflags);
atomic_inc(&lpfc_nvmep->defer_wqfull);
return 0; return 0;
} }
@ -975,11 +974,9 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport,
tgtp = phba->targetport->private; tgtp = phba->targetport->private;
atomic_inc(&tgtp->rcv_fcp_cmd_defer); atomic_inc(&tgtp->rcv_fcp_cmd_defer);
if (ctxp->flag & LPFC_NVMET_DEFER_RCV_REPOST)
lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */ /* Free the nvmebuf since a new buffer already replaced it */
else
nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf); nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
ctxp->flag &= ~LPFC_NVMET_DEFER_RCV_REPOST;
} }
static struct nvmet_fc_target_template lpfc_tgttemplate = { static struct nvmet_fc_target_template lpfc_tgttemplate = {
@ -1309,6 +1306,9 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba)
atomic_set(&tgtp->xmt_abort_sol, 0); atomic_set(&tgtp->xmt_abort_sol, 0);
atomic_set(&tgtp->xmt_abort_rsp, 0); atomic_set(&tgtp->xmt_abort_rsp, 0);
atomic_set(&tgtp->xmt_abort_rsp_error, 0); atomic_set(&tgtp->xmt_abort_rsp_error, 0);
atomic_set(&tgtp->defer_ctx, 0);
atomic_set(&tgtp->defer_fod, 0);
atomic_set(&tgtp->defer_wqfull, 0);
} }
return error; return error;
} }
@ -1810,6 +1810,8 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
lpfc_nvmeio_data(phba, "NVMET FCP RCV: xri x%x sz %d CPU %02x\n", lpfc_nvmeio_data(phba, "NVMET FCP RCV: xri x%x sz %d CPU %02x\n",
oxid, size, smp_processor_id()); oxid, size, smp_processor_id());
tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
if (!ctx_buf) { if (!ctx_buf) {
/* Queue this NVME IO to process later */ /* Queue this NVME IO to process later */
spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag); spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag);
@ -1825,10 +1827,11 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
lpfc_post_rq_buffer( lpfc_post_rq_buffer(
phba, phba->sli4_hba.nvmet_mrq_hdr[qno], phba, phba->sli4_hba.nvmet_mrq_hdr[qno],
phba->sli4_hba.nvmet_mrq_data[qno], 1, qno); phba->sli4_hba.nvmet_mrq_data[qno], 1, qno);
atomic_inc(&tgtp->defer_ctx);
return; return;
} }
tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
payload = (uint32_t *)(nvmebuf->dbuf.virt); payload = (uint32_t *)(nvmebuf->dbuf.virt);
sid = sli4_sid_from_fc_hdr(fc_hdr); sid = sli4_sid_from_fc_hdr(fc_hdr);
@ -1892,12 +1895,20 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
/* Processing of FCP command is deferred */ /* Processing of FCP command is deferred */
if (rc == -EOVERFLOW) { if (rc == -EOVERFLOW) {
/*
* Post a brand new DMA buffer to RQ and defer
* freeing rcv buffer till .defer_rcv callback
*/
qno = nvmebuf->idx;
lpfc_post_rq_buffer(
phba, phba->sli4_hba.nvmet_mrq_hdr[qno],
phba->sli4_hba.nvmet_mrq_data[qno], 1, qno);
lpfc_nvmeio_data(phba, lpfc_nvmeio_data(phba,
"NVMET RCV BUSY: xri x%x sz %d from %06x\n", "NVMET RCV BUSY: xri x%x sz %d from %06x\n",
oxid, size, sid); oxid, size, sid);
/* defer reposting rcv buffer till .defer_rcv callback */
ctxp->flag |= LPFC_NVMET_DEFER_RCV_REPOST;
atomic_inc(&tgtp->rcv_fcp_cmd_out); atomic_inc(&tgtp->rcv_fcp_cmd_out);
atomic_inc(&tgtp->defer_fod);
return; return;
} }
ctxp->rqb_buffer = nvmebuf; ctxp->rqb_buffer = nvmebuf;

View File

@ -72,7 +72,6 @@ struct lpfc_nvmet_tgtport {
atomic_t xmt_fcp_rsp_aborted; atomic_t xmt_fcp_rsp_aborted;
atomic_t xmt_fcp_rsp_drop; atomic_t xmt_fcp_rsp_drop;
/* Stats counters - lpfc_nvmet_xmt_fcp_abort */ /* Stats counters - lpfc_nvmet_xmt_fcp_abort */
atomic_t xmt_fcp_xri_abort_cqe; atomic_t xmt_fcp_xri_abort_cqe;
atomic_t xmt_fcp_abort; atomic_t xmt_fcp_abort;
@ -81,6 +80,11 @@ struct lpfc_nvmet_tgtport {
atomic_t xmt_abort_unsol; atomic_t xmt_abort_unsol;
atomic_t xmt_abort_rsp; atomic_t xmt_abort_rsp;
atomic_t xmt_abort_rsp_error; atomic_t xmt_abort_rsp_error;
/* Stats counters - defer IO */
atomic_t defer_ctx;
atomic_t defer_fod;
atomic_t defer_wqfull;
}; };
struct lpfc_nvmet_ctx_info { struct lpfc_nvmet_ctx_info {
@ -131,7 +135,6 @@ struct lpfc_nvmet_rcv_ctx {
#define LPFC_NVMET_XBUSY 0x4 /* XB bit set on IO cmpl */ #define LPFC_NVMET_XBUSY 0x4 /* XB bit set on IO cmpl */
#define LPFC_NVMET_CTX_RLS 0x8 /* ctx free requested */ #define LPFC_NVMET_CTX_RLS 0x8 /* ctx free requested */
#define LPFC_NVMET_ABTS_RCV 0x10 /* ABTS received on exchange */ #define LPFC_NVMET_ABTS_RCV 0x10 /* ABTS received on exchange */
#define LPFC_NVMET_DEFER_RCV_REPOST 0x20 /* repost to RQ on defer rcv */
#define LPFC_NVMET_DEFER_WQFULL 0x40 /* Waiting on a free WQE */ #define LPFC_NVMET_DEFER_WQFULL 0x40 /* Waiting on a free WQE */
struct rqb_dmabuf *rqb_buffer; struct rqb_dmabuf *rqb_buffer;
struct lpfc_nvmet_ctxbuf *ctxbuf; struct lpfc_nvmet_ctxbuf *ctxbuf;

View File

@ -6535,9 +6535,11 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
struct lpfc_rqe hrqe; struct lpfc_rqe hrqe;
struct lpfc_rqe drqe; struct lpfc_rqe drqe;
struct lpfc_rqb *rqbp; struct lpfc_rqb *rqbp;
unsigned long flags;
struct rqb_dmabuf *rqb_buffer; struct rqb_dmabuf *rqb_buffer;
LIST_HEAD(rqb_buf_list); LIST_HEAD(rqb_buf_list);
spin_lock_irqsave(&phba->hbalock, flags);
rqbp = hrq->rqbp; rqbp = hrq->rqbp;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
/* IF RQ is already full, don't bother */ /* IF RQ is already full, don't bother */
@ -6561,6 +6563,15 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
drqe.address_hi = putPaddrHigh(rqb_buffer->dbuf.phys); drqe.address_hi = putPaddrHigh(rqb_buffer->dbuf.phys);
rc = lpfc_sli4_rq_put(hrq, drq, &hrqe, &drqe); rc = lpfc_sli4_rq_put(hrq, drq, &hrqe, &drqe);
if (rc < 0) { if (rc < 0) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"6421 Cannot post to HRQ %d: %x %x %x "
"DRQ %x %x\n",
hrq->queue_id,
hrq->host_index,
hrq->hba_index,
hrq->entry_count,
drq->host_index,
drq->hba_index);
rqbp->rqb_free_buffer(phba, rqb_buffer); rqbp->rqb_free_buffer(phba, rqb_buffer);
} else { } else {
list_add_tail(&rqb_buffer->hbuf.list, list_add_tail(&rqb_buffer->hbuf.list,
@ -6568,6 +6579,7 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
rqbp->buffer_count++; rqbp->buffer_count++;
} }
} }
spin_unlock_irqrestore(&phba->hbalock, flags);
return 1; return 1;
} }