diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_sli.c')
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 3295 |
1 files changed, 2174 insertions, 1121 deletions
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 23a27592388..32ada050557 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2011 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -67,6 +67,12 @@ static void lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *, struct hbq_dmabuf *); static int lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *, struct lpfc_queue *, struct lpfc_cqe *); +static int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *, struct list_head *, + int); +static void lpfc_sli4_hba_handle_eqe(struct lpfc_hba *, struct lpfc_eqe *, + uint32_t); +static bool lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba); +static bool lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba); static IOCB_t * lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) @@ -92,6 +98,7 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) union lpfc_wqe *temp_wqe; struct lpfc_register doorbell; uint32_t host_index; + uint32_t idx; /* sanity check on queue memory */ if (unlikely(!q)) @@ -99,8 +106,12 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) temp_wqe = q->qe[q->host_index].wqe; /* If the host has not yet processed the next entry then we are done */ - if (((q->host_index + 1) % q->entry_count) == q->hba_index) + idx = ((q->host_index + 1) % q->entry_count); + if (idx == q->hba_index) { + q->WQ_overflow++; return -ENOMEM; + } + q->WQ_posted++; /* set consumption flag every once in a while */ if (!((q->host_index + 1) % q->entry_repost)) bf_set(wqe_wqec, &wqe->generic.wqe_com, 1); @@ -110,15 +121,22 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) /* Update the host index before invoking device */ host_index = q->host_index; - q->host_index = ((q->host_index + 1) % q->entry_count); + + q->host_index = idx; /* Ring Doorbell */ doorbell.word0 = 0; - bf_set(lpfc_wq_doorbell_num_posted, &doorbell, 1); - bf_set(lpfc_wq_doorbell_index, &doorbell, host_index); - bf_set(lpfc_wq_doorbell_id, &doorbell, q->queue_id); - writel(doorbell.word0, q->phba->sli4_hba.WQDBregaddr); - readl(q->phba->sli4_hba.WQDBregaddr); /* Flush */ + if (q->db_format == LPFC_DB_LIST_FORMAT) { + bf_set(lpfc_wq_db_list_fm_num_posted, &doorbell, 1); + bf_set(lpfc_wq_db_list_fm_index, &doorbell, host_index); + bf_set(lpfc_wq_db_list_fm_id, &doorbell, q->queue_id); + } else if (q->db_format == LPFC_DB_RING_FORMAT) { + bf_set(lpfc_wq_db_ring_fm_num_posted, &doorbell, 1); + bf_set(lpfc_wq_db_ring_fm_id, &doorbell, q->queue_id); + } else { + return -EINVAL; + } + writel(doorbell.word0, q->db_regaddr); return 0; } @@ -192,7 +210,6 @@ lpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe) bf_set(lpfc_mq_doorbell_num_posted, &doorbell, 1); bf_set(lpfc_mq_doorbell_id, &doorbell, q->queue_id); writel(doorbell.word0, q->phba->sli4_hba.MQDBregaddr); - readl(q->phba->sli4_hba.MQDBregaddr); /* Flush */ return 0; } @@ -232,6 +249,7 @@ static struct lpfc_eqe * lpfc_sli4_eq_get(struct lpfc_queue *q) { struct lpfc_eqe *eqe; + uint32_t idx; /* sanity check on queue memory */ if (unlikely(!q)) @@ -242,14 +260,44 @@ lpfc_sli4_eq_get(struct lpfc_queue *q) if (!bf_get_le32(lpfc_eqe_valid, eqe)) return NULL; /* If the host has not yet processed the next entry then we are done */ - if (((q->hba_index + 1) % q->entry_count) == q->host_index) + idx = ((q->hba_index + 1) % q->entry_count); + if (idx == q->host_index) return NULL; - q->hba_index = ((q->hba_index + 1) % q->entry_count); + q->hba_index = idx; + + /* + * insert barrier for instruction interlock : data from the hardware + * must have the valid bit checked before it can be copied and acted + * upon. Given what was seen in lpfc_sli4_cq_get() of speculative + * instructions allowing action on content before valid bit checked, + * add barrier here as well. May not be needed as "content" is a + * single 32-bit entity here (vs multi word structure for cq's). + */ + mb(); return eqe; } /** + * lpfc_sli4_eq_clr_intr - Turn off interrupts from this EQ + * @q: The Event Queue to disable interrupts + * + **/ +static inline void +lpfc_sli4_eq_clr_intr(struct lpfc_queue *q) +{ + struct lpfc_register doorbell; + + doorbell.word0 = 0; + bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1); + bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT); + bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell, + (q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT)); + bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id); + writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr); +} + +/** * lpfc_sli4_eq_release - Indicates the host has finished processing an EQ * @q: The Event Queue that the host has completed processing for. * @arm: Indicates whether the host wants to arms this CQ. @@ -293,7 +341,9 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm) } bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released); bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT); - bf_set(lpfc_eqcq_doorbell_eqid, &doorbell, q->queue_id); + bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell, + (q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT)); + bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id); writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr); /* PCI read to flush PCI pipeline on re-arming for INTx mode */ if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM)) @@ -314,6 +364,7 @@ static struct lpfc_cqe * lpfc_sli4_cq_get(struct lpfc_queue *q) { struct lpfc_cqe *cqe; + uint32_t idx; /* sanity check on queue memory */ if (unlikely(!q)) @@ -323,11 +374,23 @@ lpfc_sli4_cq_get(struct lpfc_queue *q) if (!bf_get_le32(lpfc_cqe_valid, q->qe[q->hba_index].cqe)) return NULL; /* If the host has not yet processed the next entry then we are done */ - if (((q->hba_index + 1) % q->entry_count) == q->host_index) + idx = ((q->hba_index + 1) % q->entry_count); + if (idx == q->host_index) return NULL; cqe = q->qe[q->hba_index].cqe; - q->hba_index = ((q->hba_index + 1) % q->entry_count); + q->hba_index = idx; + + /* + * insert barrier for instruction interlock : data from the hardware + * must have the valid bit checked before it can be copied and acted + * upon. Speculative instructions were allowing a bcopy at the start + * of lpfc_sli4_fp_handle_wcqe(), which is called immediately + * after our return, to copy data before the valid bit check above + * was done. As such, some of the copied data was stale. The barrier + * ensures the check is before any data is copied. + */ + mb(); return cqe; } @@ -372,7 +435,9 @@ lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm) bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1); bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released); bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_COMPLETION); - bf_set(lpfc_eqcq_doorbell_cqid, &doorbell, q->queue_id); + bf_set(lpfc_eqcq_doorbell_cqid_hi, &doorbell, + (q->queue_id >> LPFC_CQID_HI_FIELD_SHIFT)); + bf_set(lpfc_eqcq_doorbell_cqid_lo, &doorbell, q->queue_id); writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr); return released; } @@ -396,11 +461,12 @@ lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, struct lpfc_rqe *temp_hrqe; struct lpfc_rqe *temp_drqe; struct lpfc_register doorbell; - int put_index = hq->host_index; + int put_index; /* sanity check on queue memory */ if (unlikely(!hq) || unlikely(!dq)) return -ENOMEM; + put_index = hq->host_index; temp_hrqe = hq->qe[hq->host_index].rqe; temp_drqe = dq->qe[dq->host_index].rqe; @@ -421,10 +487,20 @@ lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, /* Ring The Header Receive Queue Doorbell */ if (!(hq->host_index % hq->entry_repost)) { doorbell.word0 = 0; - bf_set(lpfc_rq_doorbell_num_posted, &doorbell, - hq->entry_repost); - bf_set(lpfc_rq_doorbell_id, &doorbell, hq->queue_id); - writel(doorbell.word0, hq->phba->sli4_hba.RQDBregaddr); + if (hq->db_format == LPFC_DB_RING_FORMAT) { + bf_set(lpfc_rq_db_ring_fm_num_posted, &doorbell, + hq->entry_repost); + bf_set(lpfc_rq_db_ring_fm_id, &doorbell, hq->queue_id); + } else if (hq->db_format == LPFC_DB_LIST_FORMAT) { + bf_set(lpfc_rq_db_list_fm_num_posted, &doorbell, + hq->entry_repost); + bf_set(lpfc_rq_db_list_fm_index, &doorbell, + hq->host_index); + bf_set(lpfc_rq_db_list_fm_id, &doorbell, hq->queue_id); + } else { + return -EINVAL; + } + writel(doorbell.word0, hq->db_regaddr); } return put_index; } @@ -466,8 +542,8 @@ lpfc_sli4_rq_release(struct lpfc_queue *hq, struct lpfc_queue *dq) static inline IOCB_t * lpfc_cmd_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { - return (IOCB_t *) (((char *) pring->cmdringaddr) + - pring->cmdidx * phba->iocb_cmd_size); + return (IOCB_t *) (((char *) pring->sli.sli3.cmdringaddr) + + pring->sli.sli3.cmdidx * phba->iocb_cmd_size); } /** @@ -483,8 +559,8 @@ lpfc_cmd_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) static inline IOCB_t * lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { - return (IOCB_t *) (((char *) pring->rspringaddr) + - pring->rspidx * phba->iocb_rsp_size); + return (IOCB_t *) (((char *) pring->sli.sli3.rspringaddr) + + pring->sli.sli3.rspidx * phba->iocb_rsp_size); } /** @@ -496,7 +572,7 @@ lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) * allocation is successful, it returns pointer to the newly * allocated iocb object else it returns NULL. **/ -static struct lpfc_iocbq * +struct lpfc_iocbq * __lpfc_sli_get_iocbq(struct lpfc_hba *phba) { struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; @@ -554,81 +630,6 @@ __lpfc_get_active_sglq(struct lpfc_hba *phba, uint16_t xritag) } /** - * __lpfc_set_rrq_active - set RRQ active bit in the ndlp's xri_bitmap. - * @phba: Pointer to HBA context object. - * @ndlp: nodelist pointer for this target. - * @xritag: xri used in this exchange. - * @rxid: Remote Exchange ID. - * @send_rrq: Flag used to determine if we should send rrq els cmd. - * - * This function is called with hbalock held. - * The active bit is set in the ndlp's active rrq xri_bitmap. Allocates an - * rrq struct and adds it to the active_rrq_list. - * - * returns 0 for rrq slot for this xri - * < 0 Were not able to get rrq mem or invalid parameter. - **/ -static int -__lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, - uint16_t xritag, uint16_t rxid, uint16_t send_rrq) -{ - struct lpfc_node_rrq *rrq; - int empty; - uint32_t did = 0; - - - if (!ndlp) - return -EINVAL; - - if (!phba->cfg_enable_rrq) - return -EINVAL; - - if (phba->pport->load_flag & FC_UNLOADING) { - phba->hba_flag &= ~HBA_RRQ_ACTIVE; - goto out; - } - did = ndlp->nlp_DID; - - /* - * set the active bit even if there is no mem available. - */ - if (NLP_CHK_FREE_REQ(ndlp)) - goto out; - - if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING)) - goto out; - - if (test_and_set_bit(xritag, ndlp->active_rrqs.xri_bitmap)) - goto out; - - rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL); - if (rrq) { - rrq->send_rrq = send_rrq; - rrq->xritag = xritag; - rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1); - rrq->ndlp = ndlp; - rrq->nlp_DID = ndlp->nlp_DID; - rrq->vport = ndlp->vport; - rrq->rxid = rxid; - empty = list_empty(&phba->active_rrq_list); - rrq->send_rrq = send_rrq; - list_add_tail(&rrq->list, &phba->active_rrq_list); - if (!(phba->hba_flag & HBA_RRQ_ACTIVE)) { - phba->hba_flag |= HBA_RRQ_ACTIVE; - if (empty) - lpfc_worker_wake_up(phba); - } - return 0; - } -out: - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2921 Can't set rrq active xri:0x%x rxid:0x%x" - " DID:0x%x Send:%d\n", - xritag, rxid, did, send_rrq); - return -EINVAL; -} - -/** * lpfc_clr_rrq_active - Clears RRQ active bit in xri_bitmap. * @phba: Pointer to HBA context object. * @xritag: xri used in this exchange. @@ -655,7 +656,7 @@ lpfc_clr_rrq_active(struct lpfc_hba *phba, if (!ndlp) goto out; - if (test_and_clear_bit(xritag, ndlp->active_rrqs.xri_bitmap)) { + if (test_and_clear_bit(xritag, ndlp->active_rrqs_xri_bitmap)) { rrq->send_rrq = 0; rrq->xritag = 0; rrq->rrq_stop_time = 0; @@ -689,7 +690,7 @@ lpfc_handle_rrq_active(struct lpfc_hba *phba) spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag &= ~HBA_RRQ_ACTIVE; - next_time = jiffies + HZ * (phba->fc_ratov + 1); + next_time = jiffies + msecs_to_jiffies(1000 * (phba->fc_ratov + 1)); list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) { if (time_after(jiffies, rrq->rrq_stop_time)) @@ -698,7 +699,8 @@ lpfc_handle_rrq_active(struct lpfc_hba *phba) next_time = rrq->rrq_stop_time; } spin_unlock_irqrestore(&phba->hbalock, iflags); - if (!list_empty(&phba->active_rrq_list)) + if ((!list_empty(&phba->active_rrq_list)) && + (!(phba->pport->load_flag & FC_UNLOADING))) mod_timer(&phba->rrq_tmr, next_time); list_for_each_entry_safe(rrq, nextrrq, &send_rrq, list) { list_del(&rrq->list); @@ -804,7 +806,7 @@ lpfc_cleanup_wt_rrqs(struct lpfc_hba *phba) return; spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag &= ~HBA_RRQ_ACTIVE; - next_time = jiffies + HZ * (phba->fc_ratov * 2); + next_time = jiffies + msecs_to_jiffies(1000 * (phba->fc_ratov * 2)); list_splice_init(&phba->active_rrq_list, &rrq_list); spin_unlock_irqrestore(&phba->hbalock, iflags); @@ -812,7 +814,9 @@ lpfc_cleanup_wt_rrqs(struct lpfc_hba *phba) list_del(&rrq->list); lpfc_clr_rrq_active(phba, rrq->xritag, rrq); } - if (!list_empty(&phba->active_rrq_list)) + if ((!list_empty(&phba->active_rrq_list)) && + (!(phba->pport->load_flag & FC_UNLOADING))) + mod_timer(&phba->rrq_tmr, next_time); } @@ -833,7 +837,9 @@ lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, { if (!ndlp) return 0; - if (test_bit(xritag, ndlp->active_rrqs.xri_bitmap)) + if (!ndlp->active_rrqs_xri_bitmap) + return 0; + if (test_bit(xritag, ndlp->active_rrqs_xri_bitmap)) return 1; else return 0; @@ -856,15 +862,74 @@ lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, **/ int lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, - uint16_t xritag, uint16_t rxid, uint16_t send_rrq) + uint16_t xritag, uint16_t rxid, uint16_t send_rrq) { - int ret; unsigned long iflags; + struct lpfc_node_rrq *rrq; + int empty; + + if (!ndlp) + return -EINVAL; + + if (!phba->cfg_enable_rrq) + return -EINVAL; + + spin_lock_irqsave(&phba->hbalock, iflags); + if (phba->pport->load_flag & FC_UNLOADING) { + phba->hba_flag &= ~HBA_RRQ_ACTIVE; + goto out; + } + + /* + * set the active bit even if there is no mem available. + */ + if (NLP_CHK_FREE_REQ(ndlp)) + goto out; + + if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING)) + goto out; + + if (!ndlp->active_rrqs_xri_bitmap) + goto out; + + if (test_and_set_bit(xritag, ndlp->active_rrqs_xri_bitmap)) + goto out; + spin_unlock_irqrestore(&phba->hbalock, iflags); + rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL); + if (!rrq) { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3155 Unable to allocate RRQ xri:0x%x rxid:0x%x" + " DID:0x%x Send:%d\n", + xritag, rxid, ndlp->nlp_DID, send_rrq); + return -EINVAL; + } + if (phba->cfg_enable_rrq == 1) + rrq->send_rrq = send_rrq; + else + rrq->send_rrq = 0; + rrq->xritag = xritag; + rrq->rrq_stop_time = jiffies + + msecs_to_jiffies(1000 * (phba->fc_ratov + 1)); + rrq->ndlp = ndlp; + rrq->nlp_DID = ndlp->nlp_DID; + rrq->vport = ndlp->vport; + rrq->rxid = rxid; spin_lock_irqsave(&phba->hbalock, iflags); - ret = __lpfc_set_rrq_active(phba, ndlp, xritag, rxid, send_rrq); + empty = list_empty(&phba->active_rrq_list); + list_add_tail(&rrq->list, &phba->active_rrq_list); + phba->hba_flag |= HBA_RRQ_ACTIVE; + if (empty) + lpfc_worker_wake_up(phba); spin_unlock_irqrestore(&phba->hbalock, iflags); - return ret; + return 0; +out: + spin_unlock_irqrestore(&phba->hbalock, iflags); + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2921 Can't set rrq active xri:0x%x rxid:0x%x" + " DID:0x%x Send:%d\n", + xritag, rxid, ndlp->nlp_DID, send_rrq); + return -EINVAL; } /** @@ -893,6 +958,8 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) } else if ((piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) && !(piocbq->iocb_flag & LPFC_IO_LIBDFC)) ndlp = piocbq->context_un.ndlp; + else if (piocbq->iocb_flag & LPFC_IO_LIBDFC) + ndlp = piocbq->context_un.ndlp; else ndlp = piocbq->context1; @@ -901,7 +968,7 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) while (!found) { if (!sglq) return NULL; - if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_xritag)) { + if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_lxritag)) { /* This xri has an rrq outstanding for this DID. * put it back in the list and get another xri. */ @@ -975,6 +1042,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) else sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_lxritag); + if (sglq) { if ((iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) && (sglq->state != SGL_XRI_ABORTED)) { @@ -991,7 +1059,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) &phba->sli4_hba.lpfc_sgl_list); /* Check if TXQ queue needs to be serviced */ - if (pring->txq_cnt) + if (!list_empty(&pring->txq)) lpfc_worker_wake_up(phba); } } @@ -1022,6 +1090,7 @@ __lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) { size_t start_clean = offsetof(struct lpfc_iocbq, iocb); + /* * Clean all volatile data fields, preserve iotag and node struct. */ @@ -1088,7 +1157,6 @@ lpfc_sli_cancel_iocbs(struct lpfc_hba *phba, struct list_head *iocblist, while (!list_empty(iocblist)) { list_remove_head(iocblist, piocb, struct lpfc_iocbq, list); - if (!piocb->iocb_cmpl) lpfc_sli_release_iocbq(phba, piocb); else { @@ -1275,19 +1343,18 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb) { list_add_tail(&piocb->list, &pring->txcmplq); - piocb->iocb_flag |= LPFC_IO_ON_Q; - pring->txcmplq_cnt++; - if (pring->txcmplq_cnt > pring->txcmplq_max) - pring->txcmplq_max = pring->txcmplq_cnt; + piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ; if ((unlikely(pring->ringno == LPFC_ELS_RING)) && (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && - (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) { + (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN) && + (!(piocb->vport->load_flag & FC_UNLOADING))) { if (!piocb->vport) BUG(); else mod_timer(&piocb->vport->els_tmofunc, - jiffies + HZ * (phba->fc_ratov << 1)); + jiffies + + msecs_to_jiffies(1000 * (phba->fc_ratov << 1))); } @@ -1310,8 +1377,6 @@ lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) struct lpfc_iocbq *cmd_iocb; list_remove_head((&pring->txq), cmd_iocb, struct lpfc_iocbq, list); - if (cmd_iocb != NULL) - pring->txq_cnt--; return cmd_iocb; } @@ -1333,21 +1398,23 @@ static IOCB_t * lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno]; - uint32_t max_cmd_idx = pring->numCiocb; - if ((pring->next_cmdidx == pring->cmdidx) && - (++pring->next_cmdidx >= max_cmd_idx)) - pring->next_cmdidx = 0; + uint32_t max_cmd_idx = pring->sli.sli3.numCiocb; + if ((pring->sli.sli3.next_cmdidx == pring->sli.sli3.cmdidx) && + (++pring->sli.sli3.next_cmdidx >= max_cmd_idx)) + pring->sli.sli3.next_cmdidx = 0; - if (unlikely(pring->local_getidx == pring->next_cmdidx)) { + if (unlikely(pring->sli.sli3.local_getidx == + pring->sli.sli3.next_cmdidx)) { - pring->local_getidx = le32_to_cpu(pgp->cmdGetInx); + pring->sli.sli3.local_getidx = le32_to_cpu(pgp->cmdGetInx); - if (unlikely(pring->local_getidx >= max_cmd_idx)) { + if (unlikely(pring->sli.sli3.local_getidx >= max_cmd_idx)) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0315 Ring %d issue: portCmdGet %d " "is bigger than cmd ring %d\n", pring->ringno, - pring->local_getidx, max_cmd_idx); + pring->sli.sli3.local_getidx, + max_cmd_idx); phba->link_state = LPFC_HBA_ERROR; /* @@ -1362,7 +1429,7 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) return NULL; } - if (pring->local_getidx == pring->next_cmdidx) + if (pring->sli.sli3.local_getidx == pring->sli.sli3.next_cmdidx) return NULL; } @@ -1497,8 +1564,8 @@ lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * Let the HBA know what IOCB slot will be the next one the * driver will put a command into. */ - pring->cmdidx = pring->next_cmdidx; - writel(pring->cmdidx, &phba->host_gp[pring->ringno].cmdPutInx); + pring->sli.sli3.cmdidx = pring->sli.sli3.next_cmdidx; + writel(pring->sli.sli3.cmdidx, &phba->host_gp[pring->ringno].cmdPutInx); } /** @@ -1578,8 +1645,9 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) * (c) link attention events can be processed (fcp ring only) * (d) IOCB processing is not blocked by the outstanding mbox command. */ - if (pring->txq_cnt && - lpfc_is_link_up(phba) && + + if (lpfc_is_link_up(phba) && + (!list_empty(&pring->txq)) && (pring->ringno != phba->sli.fcp_ring || phba->sli.sli_flag & LPFC_PROCESS_LA)) { @@ -2069,6 +2137,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) case MBX_READ_EVENT_LOG: case MBX_SECURITY_MGMT: case MBX_AUTH_PORT: + case MBX_ACCESS_VDATA: ret = mbxCommand; break; default: @@ -2286,7 +2355,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) /* Mailbox cmd <cmd> Cmpl <cmpl> */ lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, "(%d):0307 Mailbox cmd x%x (x%x/x%x) Cmpl x%p " - "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x\n", + "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x " + "x%x x%x x%x\n", pmb->vport ? pmb->vport->vpi : 0, pmbox->mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, pmb), @@ -2300,7 +2370,10 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) pmbox->un.varWords[4], pmbox->un.varWords[5], pmbox->un.varWords[6], - pmbox->un.varWords[7]); + pmbox->un.varWords[7], + pmbox->un.varWords[8], + pmbox->un.varWords[9], + pmbox->un.varWords[10]); if (pmb->mbox_cmpl) pmb->mbox_cmpl(phba,pmb); @@ -2574,9 +2647,8 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, if (iotag != 0 && iotag <= phba->sli.last_iotag) { cmd_iocb = phba->sli.iocbq_lookup[iotag]; list_del_init(&cmd_iocb->list); - if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) { - pring->txcmplq_cnt--; - cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q; + if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) { + cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; } return cmd_iocb; } @@ -2609,14 +2681,13 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba, if (iotag != 0 && iotag <= phba->sli.last_iotag) { cmd_iocb = phba->sli.iocbq_lookup[iotag]; - list_del_init(&cmd_iocb->list); - if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) { - cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q; - pring->txcmplq_cnt--; + if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) { + /* remove from txcmpl queue list */ + list_del_init(&cmd_iocb->list); + cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; + return cmd_iocb; } - return cmd_iocb; } - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0372 iotag x%x is out off range: max iotag (x%x)\n", iotag, phba->sli.last_iotag); @@ -2799,7 +2870,7 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) "0312 Ring %d handler: portRspPut %d " "is bigger than rsp ring %d\n", pring->ringno, le32_to_cpu(pgp->rspPutInx), - pring->numRiocb); + pring->sli.sli3.numRiocb); phba->link_state = LPFC_HBA_ERROR; @@ -2828,10 +2899,26 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) void lpfc_poll_eratt(unsigned long ptr) { struct lpfc_hba *phba; - uint32_t eratt = 0; + uint32_t eratt = 0, rem; + uint64_t sli_intr, cnt; phba = (struct lpfc_hba *)ptr; + /* Here we will also keep track of interrupts per sec of the hba */ + sli_intr = phba->sli.slistat.sli_intr; + + if (phba->sli.slistat.sli_prev_intr > sli_intr) + cnt = (((uint64_t)(-1) - phba->sli.slistat.sli_prev_intr) + + sli_intr); + else + cnt = (sli_intr - phba->sli.slistat.sli_prev_intr); + + /* 64-bit integer division not supporte on 32-bit x86 - use do_div */ + rem = do_div(cnt, LPFC_ERATT_POLL_INTERVAL); + phba->sli.slistat.sli_ips = cnt; + + phba->sli.slistat.sli_prev_intr = sli_intr; + /* Check chip HA register for error event */ eratt = lpfc_sli_check_eratt(phba); @@ -2840,8 +2927,9 @@ void lpfc_poll_eratt(unsigned long ptr) lpfc_worker_wake_up(phba); else /* Restart the timer for next eratt poll */ - mod_timer(&phba->eratt_poll, jiffies + - HZ * LPFC_ERATT_POLL_INTERVAL); + mod_timer(&phba->eratt_poll, + jiffies + + msecs_to_jiffies(1000 * LPFC_ERATT_POLL_INTERVAL)); return; } @@ -2886,7 +2974,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, * The next available response entry should never exceed the maximum * entries. If it does, treat it as an adapter hardware error. */ - portRspMax = pring->numRiocb; + portRspMax = pring->sli.sli3.numRiocb; portRspPut = le32_to_cpu(pgp->rspPutInx); if (unlikely(portRspPut >= portRspMax)) { lpfc_sli_rsp_pointers_error(phba, pring); @@ -2900,7 +2988,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, phba->fcp_ring_in_use = 1; rmb(); - while (pring->rspidx != portRspPut) { + while (pring->sli.sli3.rspidx != portRspPut) { /* * Fetch an entry off the ring and copy it into a local data * structure. The copy involves a byte-swap since the @@ -2909,8 +2997,8 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, entry = lpfc_resp_iocb(phba, pring); phba->last_completion_time = jiffies; - if (++pring->rspidx >= portRspMax) - pring->rspidx = 0; + if (++pring->sli.sli3.rspidx >= portRspMax) + pring->sli.sli3.rspidx = 0; lpfc_sli_pcimem_bcopy((uint32_t *) entry, (uint32_t *) &rspiocbq.iocb, @@ -2928,7 +3016,8 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, * queuedepths of the SCSI device. */ if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) { + ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == + IOERR_NO_RESOURCES)) { spin_unlock_irqrestore(&phba->hbalock, iflag); phba->lpfc_rampdown_queue_depth(phba); spin_lock_irqsave(&phba->hbalock, iflag); @@ -3011,9 +3100,10 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, * been updated, sync the pgp->rspPutInx and fetch the new port * response put pointer. */ - writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); + writel(pring->sli.sli3.rspidx, + &phba->host_gp[pring->ringno].rspGetInx); - if (pring->rspidx == portRspPut) + if (pring->sli.sli3.rspidx == portRspPut) portRspPut = le32_to_cpu(pgp->rspPutInx); } @@ -3028,7 +3118,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, pring->stats.iocb_cmd_empty++; /* Force update of the local copy of cmdGetInx */ - pring->local_getidx = le32_to_cpu(pgp->cmdGetInx); + pring->sli.sli3.local_getidx = le32_to_cpu(pgp->cmdGetInx); lpfc_sli_resume_iocb(phba, pring); if ((pring->lpfc_sli_cmd_available)) @@ -3099,7 +3189,8 @@ lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * queuedepths of the SCSI device. */ if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) { + ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == + IOERR_NO_RESOURCES)) { spin_unlock_irqrestore(&phba->hbalock, iflag); phba->lpfc_rampdown_queue_depth(phba); spin_lock_irqsave(&phba->hbalock, iflag); @@ -3202,7 +3293,7 @@ lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (free_saveq) { list_for_each_entry_safe(rspiocbp, next_iocb, &saveq->list, list) { - list_del(&rspiocbp->list); + list_del_init(&rspiocbp->list); __lpfc_sli_release_iocbq(phba, rspiocbp); } __lpfc_sli_release_iocbq(phba, saveq); @@ -3260,7 +3351,7 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, * The next available response entry should never exceed the maximum * entries. If it does, treat it as an adapter hardware error. */ - portRspMax = pring->numRiocb; + portRspMax = pring->sli.sli3.numRiocb; portRspPut = le32_to_cpu(pgp->rspPutInx); if (portRspPut >= portRspMax) { /* @@ -3282,7 +3373,7 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, } rmb(); - while (pring->rspidx != portRspPut) { + while (pring->sli.sli3.rspidx != portRspPut) { /* * Build a completion list and call the appropriate handler. * The process is to get the next available response iocb, get @@ -3310,8 +3401,8 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, phba->iocb_rsp_size); irsp = &rspiocbp->iocb; - if (++pring->rspidx >= portRspMax) - pring->rspidx = 0; + if (++pring->sli.sli3.rspidx >= portRspMax) + pring->sli.sli3.rspidx = 0; if (pring->ringno == LPFC_ELS_RING) { lpfc_debugfs_slow_ring_trc(phba, @@ -3321,7 +3412,8 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, *(((uint32_t *) irsp) + 7)); } - writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); + writel(pring->sli.sli3.rspidx, + &phba->host_gp[pring->ringno].rspGetInx); spin_unlock_irqrestore(&phba->hbalock, iflag); /* Handle the response IOCB */ @@ -3333,10 +3425,10 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, * the pgp->rspPutInx in the MAILBOX_tand fetch the new port * response put pointer. */ - if (pring->rspidx == portRspPut) { + if (pring->sli.sli3.rspidx == portRspPut) { portRspPut = le32_to_cpu(pgp->rspPutInx); } - } /* while (pring->rspidx != portRspPut) */ + } /* while (pring->sli.sli3.rspidx != portRspPut) */ if ((rspiocbp != NULL) && (mask & HA_R0RE_REQ)) { /* At least one response entry has been freed */ @@ -3351,7 +3443,7 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, pring->stats.iocb_cmd_empty++; /* Force update of the local copy of cmdGetInx */ - pring->local_getidx = le32_to_cpu(pgp->cmdGetInx); + pring->sli.sli3.local_getidx = le32_to_cpu(pgp->cmdGetInx); lpfc_sli_resume_iocb(phba, pring); if ((pring->lpfc_sli_cmd_available)) @@ -3440,15 +3532,27 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) /* Error everything on txq and txcmplq * First do the txq. */ - spin_lock_irq(&phba->hbalock); - list_splice_init(&pring->txq, &completions); - pring->txq_cnt = 0; + if (phba->sli_rev >= LPFC_SLI_REV4) { + spin_lock_irq(&pring->ring_lock); + list_splice_init(&pring->txq, &completions); + pring->txq_cnt = 0; + spin_unlock_irq(&pring->ring_lock); - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + spin_lock_irq(&phba->hbalock); + /* Next issue ABTS for everything on the txcmplq */ + list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) + lpfc_sli_issue_abort_iotag(phba, pring, iocb); + spin_unlock_irq(&phba->hbalock); + } else { + spin_lock_irq(&phba->hbalock); + list_splice_init(&pring->txq, &completions); + pring->txq_cnt = 0; - spin_unlock_irq(&phba->hbalock); + /* Next issue ABTS for everything on the txcmplq */ + list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) + lpfc_sli_issue_abort_iotag(phba, pring, iocb); + spin_unlock_irq(&phba->hbalock); + } /* Cancel all the IOCBs from the completions list */ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, @@ -3456,6 +3560,36 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) } /** + * lpfc_sli_abort_fcp_rings - Abort all iocbs in all FCP rings + * @phba: Pointer to HBA context object. + * @pring: Pointer to driver SLI ring object. + * + * This function aborts all iocbs in FCP rings and frees all the iocb + * objects in txq. This function issues an abort iocb for all the iocb commands + * in txcmplq. The iocbs in the txcmplq is not guaranteed to complete before + * the return of this function. The caller is not required to hold any locks. + **/ +void +lpfc_sli_abort_fcp_rings(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; + uint32_t i; + + /* Look on all the FCP Rings for the iotag */ + if (phba->sli_rev >= LPFC_SLI_REV4) { + for (i = 0; i < phba->cfg_fcp_io_channel; i++) { + pring = &psli->ring[i + MAX_SLI3_CONFIGURED_RINGS]; + lpfc_sli_abort_iocb_ring(phba, pring); + } + } else { + pring = &psli->ring[psli->fcp_ring]; + lpfc_sli_abort_iocb_ring(phba, pring); + } +} + + +/** * lpfc_sli_flush_fcp_rings - flush all iocbs in the fcp ring * @phba: Pointer to HBA context object. * @@ -3472,27 +3606,55 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) LIST_HEAD(txcmplq); struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; - - /* Currently, only one fcp ring */ - pring = &psli->ring[psli->fcp_ring]; + uint32_t i; spin_lock_irq(&phba->hbalock); - /* Retrieve everything on txq */ - list_splice_init(&pring->txq, &txq); - pring->txq_cnt = 0; - - /* Retrieve everything on the txcmplq */ - list_splice_init(&pring->txcmplq, &txcmplq); - pring->txcmplq_cnt = 0; + /* Indicate the I/O queues are flushed */ + phba->hba_flag |= HBA_FCP_IOQ_FLUSH; spin_unlock_irq(&phba->hbalock); - /* Flush the txq */ - lpfc_sli_cancel_iocbs(phba, &txq, IOSTAT_LOCAL_REJECT, - IOERR_SLI_DOWN); + /* Look on all the FCP Rings for the iotag */ + if (phba->sli_rev >= LPFC_SLI_REV4) { + for (i = 0; i < phba->cfg_fcp_io_channel; i++) { + pring = &psli->ring[i + MAX_SLI3_CONFIGURED_RINGS]; + + spin_lock_irq(&pring->ring_lock); + /* Retrieve everything on txq */ + list_splice_init(&pring->txq, &txq); + /* Retrieve everything on the txcmplq */ + list_splice_init(&pring->txcmplq, &txcmplq); + pring->txq_cnt = 0; + pring->txcmplq_cnt = 0; + spin_unlock_irq(&pring->ring_lock); + + /* Flush the txq */ + lpfc_sli_cancel_iocbs(phba, &txq, + IOSTAT_LOCAL_REJECT, + IOERR_SLI_DOWN); + /* Flush the txcmpq */ + lpfc_sli_cancel_iocbs(phba, &txcmplq, + IOSTAT_LOCAL_REJECT, + IOERR_SLI_DOWN); + } + } else { + pring = &psli->ring[psli->fcp_ring]; - /* Flush the txcmpq */ - lpfc_sli_cancel_iocbs(phba, &txcmplq, IOSTAT_LOCAL_REJECT, - IOERR_SLI_DOWN); + spin_lock_irq(&phba->hbalock); + /* Retrieve everything on txq */ + list_splice_init(&pring->txq, &txq); + /* Retrieve everything on the txcmplq */ + list_splice_init(&pring->txcmplq, &txcmplq); + pring->txq_cnt = 0; + pring->txcmplq_cnt = 0; + spin_unlock_irq(&phba->hbalock); + + /* Flush the txq */ + lpfc_sli_cancel_iocbs(phba, &txq, IOSTAT_LOCAL_REJECT, + IOERR_SLI_DOWN); + /* Flush the txcmpq */ + lpfc_sli_cancel_iocbs(phba, &txcmplq, IOSTAT_LOCAL_REJECT, + IOERR_SLI_DOWN); + } } /** @@ -3869,10 +4031,10 @@ lpfc_sli_brdreset(struct lpfc_hba *phba) for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; pring->flag = 0; - pring->rspidx = 0; - pring->next_cmdidx = 0; - pring->local_getidx = 0; - pring->cmdidx = 0; + pring->sli.sli3.rspidx = 0; + pring->sli.sli3.next_cmdidx = 0; + pring->sli.sli3.local_getidx = 0; + pring->sli.sli3.cmdidx = 0; pring->missbufcnt = 0; } @@ -3895,11 +4057,13 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; uint16_t cfg_value; + int rc = 0; /* Reset HBA */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0295 Reset HBA Data: x%x x%x\n", - phba->pport->port_state, psli->sli_flag); + "0295 Reset HBA Data: x%x x%x x%x\n", + phba->pport->port_state, psli->sli_flag, + phba->hba_flag); /* perform board reset */ phba->fc_eventTag = 0; @@ -3912,6 +4076,12 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) phba->fcf.fcf_flag = 0; spin_unlock_irq(&phba->hbalock); + /* SLI4 INTF 2: if FW dump is being taken skip INIT_PORT */ + if (phba->hba_flag & HBA_FW_DUMP_OP) { + phba->hba_flag &= ~HBA_FW_DUMP_OP; + return rc; + } + /* Now physically reset the device */ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0389 Performing PCI function reset!\n"); @@ -3921,14 +4091,14 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) pci_write_config_word(phba->pcidev, PCI_COMMAND, (cfg_value & ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); - /* Perform FCoE PCI function reset */ + /* Perform FCoE PCI function reset before freeing queue memory */ + rc = lpfc_pci_function_reset(phba); lpfc_sli4_queue_destroy(phba); - lpfc_pci_function_reset(phba); /* Restore PCI cmd register */ pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value); - return 0; + return rc; } /** @@ -4020,6 +4190,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; uint32_t hba_aer_enabled; + int rc; /* Restart HBA */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, @@ -4029,7 +4200,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) /* Take PCIe device Advanced Error Reporting (AER) state */ hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED; - lpfc_sli4_brdreset(phba); + rc = lpfc_sli4_brdreset(phba); spin_lock_irq(&phba->hbalock); phba->pport->stopped = 0; @@ -4046,7 +4217,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) lpfc_hba_down_post(phba); - return 0; + return rc; } /** @@ -4504,7 +4675,8 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) } else { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "2708 This device does not support " - "Advanced Error Reporting (AER)\n"); + "Advanced Error Reporting (AER): %d\n", + rc); phba->cfg_aer_support = 0; } } @@ -4747,7 +4919,7 @@ lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, * is attached to. * * Return codes - * 0 - sucessful + * 0 - successful * otherwise - failed to retrieve physical port name **/ static int @@ -4895,24 +5067,30 @@ out_free_mboxq: static void lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) { - uint8_t fcp_eqidx; + int fcp_eqidx; lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM); lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM); fcp_eqidx = 0; if (phba->sli4_hba.fcp_cq) { - do + do { lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[fcp_eqidx], LPFC_QUEUE_REARM); - while (++fcp_eqidx < phba->cfg_fcp_eq_count); + } while (++fcp_eqidx < phba->cfg_fcp_io_channel); } - lpfc_sli4_eq_release(phba->sli4_hba.sp_eq, LPFC_QUEUE_REARM); - if (phba->sli4_hba.fp_eq) { - for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; + + if (phba->cfg_fof) + lpfc_sli4_cq_release(phba->sli4_hba.oas_cq, LPFC_QUEUE_REARM); + + if (phba->sli4_hba.hba_eq) { + for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_io_channel; fcp_eqidx++) - lpfc_sli4_eq_release(phba->sli4_hba.fp_eq[fcp_eqidx], + lpfc_sli4_eq_release(phba->sli4_hba.hba_eq[fcp_eqidx], LPFC_QUEUE_REARM); } + + if (phba->cfg_fof) + lpfc_sli4_eq_release(phba->sli4_hba.fof_eq, LPFC_QUEUE_REARM); } /** @@ -4985,7 +5163,12 @@ lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type, &rsrc_info->u.rsp); *extnt_size = bf_get(lpfc_mbx_get_rsrc_extent_info_size, &rsrc_info->u.rsp); - err_exit: + + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3162 Retrieved extents type-%d from port: count:%d, " + "size:%d\n", type, *extnt_count, *extnt_size); + +err_exit: mempool_free(mbox, phba->mbox_mem_pool); return rc; } @@ -5069,7 +5252,7 @@ lpfc_sli4_chk_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type) * 0: if successful **/ static int -lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt, +lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t extnt_cnt, uint16_t type, bool *emb, LPFC_MBOXQ_t *mbox) { int rc = 0; @@ -5078,7 +5261,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt, uint32_t alloc_len, mbox_tmo; /* Calculate the total requested length of the dma memory */ - req_len = *extnt_cnt * sizeof(uint16_t); + req_len = extnt_cnt * sizeof(uint16_t); /* * Calculate the size of an embedded mailbox. The uint32_t @@ -5093,7 +5276,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt, */ *emb = LPFC_SLI4_MBX_EMBED; if (req_len > emb_len) { - req_len = *extnt_cnt * sizeof(uint16_t) + + req_len = extnt_cnt * sizeof(uint16_t) + sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); *emb = LPFC_SLI4_MBX_NEMBED; @@ -5109,7 +5292,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt, "size (x%x)\n", alloc_len, req_len); return -ENOMEM; } - rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, *extnt_cnt, type, *emb); + rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, extnt_cnt, type, *emb); if (unlikely(rc)) return -EIO; @@ -5167,17 +5350,15 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) return -ENOMEM; } - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT, - "2903 Available Resource Extents " - "for resource type 0x%x: Count: 0x%x, " - "Size 0x%x\n", type, rsrc_cnt, - rsrc_size); + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT | LOG_SLI, + "2903 Post resource extents type-0x%x: " + "count:%d, size %d\n", type, rsrc_cnt, rsrc_size); mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) return -ENOMEM; - rc = lpfc_sli4_cfg_post_extnts(phba, &rsrc_cnt, type, &emb, mbox); + rc = lpfc_sli4_cfg_post_extnts(phba, rsrc_cnt, type, &emb, mbox); if (unlikely(rc)) { rc = -EIO; goto err_exit; @@ -5268,6 +5449,7 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) rc = -ENOMEM; goto err_exit; } + phba->sli4_hba.max_cfg_param.xri_used = 0; phba->sli4_hba.xri_ids = kzalloc(rsrc_id_cnt * sizeof(uint16_t), GFP_KERNEL); @@ -5434,11 +5616,11 @@ lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type) list_del_init(&rsrc_blk->list); kfree(rsrc_blk); } + phba->sli4_hba.max_cfg_param.vpi_used = 0; break; case LPFC_RSC_TYPE_FCOE_XRI: kfree(phba->sli4_hba.xri_bmask); kfree(phba->sli4_hba.xri_ids); - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); list_for_each_entry_safe(rsrc_blk, rsrc_blk_next, &phba->sli4_hba.lpfc_xri_blk_list, list) { list_del_init(&rsrc_blk->list); @@ -5576,6 +5758,13 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) } /* RPIs. */ count = phba->sli4_hba.max_cfg_param.max_rpi; + if (count <= 0) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "3279 Invalid provisioning of " + "rpi:%d\n", count); + rc = -EINVAL; + goto err_exit; + } base = phba->sli4_hba.max_cfg_param.rpi_base; longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; phba->sli4_hba.rpi_bmask = kzalloc(longs * @@ -5598,6 +5787,13 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) /* VPIs. */ count = phba->sli4_hba.max_cfg_param.max_vpi; + if (count <= 0) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "3280 Invalid provisioning of " + "vpi:%d\n", count); + rc = -EINVAL; + goto free_rpi_ids; + } base = phba->sli4_hba.max_cfg_param.vpi_base; longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; phba->vpi_bmask = kzalloc(longs * @@ -5620,6 +5816,13 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) /* XRIs. */ count = phba->sli4_hba.max_cfg_param.max_xri; + if (count <= 0) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "3281 Invalid provisioning of " + "xri:%d\n", count); + rc = -EINVAL; + goto free_vpi_ids; + } base = phba->sli4_hba.max_cfg_param.xri_base; longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; phba->sli4_hba.xri_bmask = kzalloc(longs * @@ -5629,6 +5832,7 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) rc = -ENOMEM; goto free_vpi_ids; } + phba->sli4_hba.max_cfg_param.xri_used = 0; phba->sli4_hba.xri_ids = kzalloc(count * sizeof(uint16_t), GFP_KERNEL); @@ -5642,6 +5846,13 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) /* VFIs. */ count = phba->sli4_hba.max_cfg_param.max_vfi; + if (count <= 0) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "3282 Invalid provisioning of " + "vfi:%d\n", count); + rc = -EINVAL; + goto free_xri_ids; + } base = phba->sli4_hba.max_cfg_param.vfi_base; longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; phba->sli4_hba.vfi_bmask = kzalloc(longs * @@ -5706,11 +5917,11 @@ lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba) lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_VFI); } else { kfree(phba->vpi_bmask); + phba->sli4_hba.max_cfg_param.vpi_used = 0; kfree(phba->vpi_ids); bf_set(lpfc_vpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); kfree(phba->sli4_hba.xri_bmask); kfree(phba->sli4_hba.xri_ids); - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); kfree(phba->sli4_hba.vfi_bmask); kfree(phba->sli4_hba.vfi_ids); bf_set(lpfc_vfi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); @@ -5869,6 +6080,148 @@ lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type, } /** + * lpfc_sli4_repost_els_sgl_list - Repsot the els buffers sgl pages as block + * @phba: pointer to lpfc hba data structure. + * + * This routine walks the list of els buffers that have been allocated and + * repost them to the port by using SGL block post. This is needed after a + * pci_function_reset/warm_start or start. It attempts to construct blocks + * of els buffer sgls which contains contiguous xris and uses the non-embedded + * SGL block post mailbox commands to post them to the port. For single els + * buffer sgl with non-contiguous xri, if any, it shall use embedded SGL post + * mailbox command for posting. + * + * Returns: 0 = success, non-zero failure. + **/ +static int +lpfc_sli4_repost_els_sgl_list(struct lpfc_hba *phba) +{ + struct lpfc_sglq *sglq_entry = NULL; + struct lpfc_sglq *sglq_entry_next = NULL; + struct lpfc_sglq *sglq_entry_first = NULL; + int status, total_cnt, post_cnt = 0, num_posted = 0, block_cnt = 0; + int last_xritag = NO_XRI; + LIST_HEAD(prep_sgl_list); + LIST_HEAD(blck_sgl_list); + LIST_HEAD(allc_sgl_list); + LIST_HEAD(post_sgl_list); + LIST_HEAD(free_sgl_list); + + spin_lock_irq(&phba->hbalock); + list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &allc_sgl_list); + spin_unlock_irq(&phba->hbalock); + + total_cnt = phba->sli4_hba.els_xri_cnt; + list_for_each_entry_safe(sglq_entry, sglq_entry_next, + &allc_sgl_list, list) { + list_del_init(&sglq_entry->list); + block_cnt++; + if ((last_xritag != NO_XRI) && + (sglq_entry->sli4_xritag != last_xritag + 1)) { + /* a hole in xri block, form a sgl posting block */ + list_splice_init(&prep_sgl_list, &blck_sgl_list); + post_cnt = block_cnt - 1; + /* prepare list for next posting block */ + list_add_tail(&sglq_entry->list, &prep_sgl_list); + block_cnt = 1; + } else { + /* prepare list for next posting block */ + list_add_tail(&sglq_entry->list, &prep_sgl_list); + /* enough sgls for non-embed sgl mbox command */ + if (block_cnt == LPFC_NEMBED_MBOX_SGL_CNT) { + list_splice_init(&prep_sgl_list, + &blck_sgl_list); + post_cnt = block_cnt; + block_cnt = 0; + } + } + num_posted++; + + /* keep track of last sgl's xritag */ + last_xritag = sglq_entry->sli4_xritag; + + /* end of repost sgl list condition for els buffers */ + if (num_posted == phba->sli4_hba.els_xri_cnt) { + if (post_cnt == 0) { + list_splice_init(&prep_sgl_list, + &blck_sgl_list); + post_cnt = block_cnt; + } else if (block_cnt == 1) { + status = lpfc_sli4_post_sgl(phba, + sglq_entry->phys, 0, + sglq_entry->sli4_xritag); + if (!status) { + /* successful, put sgl to posted list */ + list_add_tail(&sglq_entry->list, + &post_sgl_list); + } else { + /* Failure, put sgl to free list */ + lpfc_printf_log(phba, KERN_WARNING, + LOG_SLI, + "3159 Failed to post els " + "sgl, xritag:x%x\n", + sglq_entry->sli4_xritag); + list_add_tail(&sglq_entry->list, + &free_sgl_list); + total_cnt--; + } + } + } + + /* continue until a nembed page worth of sgls */ + if (post_cnt == 0) + continue; + + /* post the els buffer list sgls as a block */ + status = lpfc_sli4_post_els_sgl_list(phba, &blck_sgl_list, + post_cnt); + + if (!status) { + /* success, put sgl list to posted sgl list */ + list_splice_init(&blck_sgl_list, &post_sgl_list); + } else { + /* Failure, put sgl list to free sgl list */ + sglq_entry_first = list_first_entry(&blck_sgl_list, + struct lpfc_sglq, + list); + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "3160 Failed to post els sgl-list, " + "xritag:x%x-x%x\n", + sglq_entry_first->sli4_xritag, + (sglq_entry_first->sli4_xritag + + post_cnt - 1)); + list_splice_init(&blck_sgl_list, &free_sgl_list); + total_cnt -= post_cnt; + } + + /* don't reset xirtag due to hole in xri block */ + if (block_cnt == 0) + last_xritag = NO_XRI; + + /* reset els sgl post count for next round of posting */ + post_cnt = 0; + } + /* update the number of XRIs posted for ELS */ + phba->sli4_hba.els_xri_cnt = total_cnt; + + /* free the els sgls failed to post */ + lpfc_free_sgl_list(phba, &free_sgl_list); + + /* push els sgls posted to the availble list */ + if (!list_empty(&post_sgl_list)) { + spin_lock_irq(&phba->hbalock); + list_splice_init(&post_sgl_list, + &phba->sli4_hba.lpfc_sgl_list); + spin_unlock_irq(&phba->hbalock); + } else { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "3161 Failure to post els sgl to port.\n"); + return -EIO; + } + return 0; +} + +/** * lpfc_sli4_hba_setup - SLI4 device intialization PCI function * @phba: Pointer to HBA context object. * @@ -5926,6 +6279,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) kfree(vpd); goto out_free_mbox; } + mqe = &mboxq->u.mqe; phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev); if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev)) @@ -5939,6 +6293,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) else phba->hba_flag &= ~HBA_FIP_SUPPORT; + phba->hba_flag &= ~HBA_FCP_IOQ_FLUSH; + if (phba->sli_rev != LPFC_SLI_REV4) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "0376 READ_REV Error. SLI Level %d " @@ -6010,6 +6366,16 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) phba->vpd.rev.fcphHigh, phba->vpd.rev.fcphLow, phba->vpd.rev.feaLevelHigh, phba->vpd.rev.feaLevelLow); + /* Reset the DFT_LUN_Q_DEPTH to (max xri >> 3) */ + rc = (phba->sli4_hba.max_cfg_param.max_xri >> 3); + if (phba->pport->cfg_lun_queue_depth > rc) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "3362 LUN queue depth changed from %d to %d\n", + phba->pport->cfg_lun_queue_depth, rc); + phba->pport->cfg_lun_queue_depth = rc; + } + + /* * Discover the port's supported feature set and match it against the * hosts requests. @@ -6079,8 +6445,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) "rc = x%x\n", rc); goto out_free_mbox; } - /* update physical xri mappings in the scsi buffers */ - lpfc_scsi_buf_update(phba); /* Read the port's service parameters. */ rc = lpfc_read_sparam(phba, mboxq, vport->vpi); @@ -6121,28 +6485,26 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn); fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn); - /* Register SGL pool to the device using non-embedded mailbox command */ - if (!phba->sli4_hba.extents_in_use) { - rc = lpfc_sli4_post_els_sgl_list(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0582 Error %d during els sgl post " - "operation\n", rc); - rc = -ENODEV; - goto out_free_mbox; - } - } else { - rc = lpfc_sli4_post_els_sgl_list_ext(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "2560 Error %d during els sgl post " - "operation\n", rc); - rc = -ENODEV; - goto out_free_mbox; - } + /* update host els and scsi xri-sgl sizes and mappings */ + rc = lpfc_sli4_xri_sgl_update(phba); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "1400 Failed to update xri-sgl size and " + "mapping: %d\n", rc); + goto out_free_mbox; } - /* Register SCSI SGL pool to the device */ + /* register the els sgl pool to the port */ + rc = lpfc_sli4_repost_els_sgl_list(phba); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "0582 Error %d during els sgl post " + "operation\n", rc); + rc = -ENODEV; + goto out_free_mbox; + } + + /* register the allocated scsi sgl pool to the port */ rc = lpfc_sli4_repost_scsi_sgl_list(phba); if (unlikely(rc)) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, @@ -6163,6 +6525,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = -ENODEV; goto out_free_mbox; } + lpfc_sli4_node_prep(phba); /* Create all the SLI4 queues */ rc = lpfc_sli4_queue_create(phba); @@ -6200,16 +6563,17 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Start the ELS watchdog timer */ mod_timer(&vport->els_tmofunc, - jiffies + HZ * (phba->fc_ratov * 2)); + jiffies + msecs_to_jiffies(1000 * (phba->fc_ratov * 2))); /* Start heart beat timer */ mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_INTERVAL); + jiffies + msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL)); phba->hb_outstanding = 0; phba->last_completion_time = jiffies; /* Start error attention (ERATT) polling timer */ - mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); + mod_timer(&phba->eratt_poll, + jiffies + msecs_to_jiffies(1000 * LPFC_ERATT_POLL_INTERVAL)); /* Enable PCIe device Advanced Error Reporting (AER) if configured */ if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) { @@ -6318,6 +6682,108 @@ lpfc_mbox_timeout(unsigned long ptr) return; } +/** + * lpfc_sli4_mbox_completions_pending - check to see if any mailbox completions + * are pending + * @phba: Pointer to HBA context object. + * + * This function checks if any mailbox completions are present on the mailbox + * completion queue. + **/ +bool +lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba) +{ + + uint32_t idx; + struct lpfc_queue *mcq; + struct lpfc_mcqe *mcqe; + bool pending_completions = false; + + if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4)) + return false; + + /* Check for completions on mailbox completion queue */ + + mcq = phba->sli4_hba.mbx_cq; + idx = mcq->hba_index; + while (bf_get_le32(lpfc_cqe_valid, mcq->qe[idx].cqe)) { + mcqe = (struct lpfc_mcqe *)mcq->qe[idx].cqe; + if (bf_get_le32(lpfc_trailer_completed, mcqe) && + (!bf_get_le32(lpfc_trailer_async, mcqe))) { + pending_completions = true; + break; + } + idx = (idx + 1) % mcq->entry_count; + if (mcq->hba_index == idx) + break; + } + return pending_completions; + +} + +/** + * lpfc_sli4_process_missed_mbox_completions - process mbox completions + * that were missed. + * @phba: Pointer to HBA context object. + * + * For sli4, it is possible to miss an interrupt. As such mbox completions + * maybe missed causing erroneous mailbox timeouts to occur. This function + * checks to see if mbox completions are on the mailbox completion queue + * and will process all the completions associated with the eq for the + * mailbox completion queue. + **/ +bool +lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba) +{ + + uint32_t eqidx; + struct lpfc_queue *fpeq = NULL; + struct lpfc_eqe *eqe; + bool mbox_pending; + + if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4)) + return false; + + /* Find the eq associated with the mcq */ + + if (phba->sli4_hba.hba_eq) + for (eqidx = 0; eqidx < phba->cfg_fcp_io_channel; eqidx++) + if (phba->sli4_hba.hba_eq[eqidx]->queue_id == + phba->sli4_hba.mbx_cq->assoc_qid) { + fpeq = phba->sli4_hba.hba_eq[eqidx]; + break; + } + if (!fpeq) + return false; + + /* Turn off interrupts from this EQ */ + + lpfc_sli4_eq_clr_intr(fpeq); + + /* Check to see if a mbox completion is pending */ + + mbox_pending = lpfc_sli4_mbox_completions_pending(phba); + + /* + * If a mbox completion is pending, process all the events on EQ + * associated with the mbox completion queue (this could include + * mailbox commands, async events, els commands, receive queue data + * and fcp commands) + */ + + if (mbox_pending) + while ((eqe = lpfc_sli4_eq_get(fpeq))) { + lpfc_sli4_hba_handle_eqe(phba, eqe, eqidx); + fpeq->EQ_processed++; + } + + /* Always clear and re-arm the EQ */ + + lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM); + + return mbox_pending; + +} /** * lpfc_mbox_timeout_handler - Worker thread function to handle mailbox timeout @@ -6333,7 +6799,10 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) LPFC_MBOXQ_t *pmbox = phba->sli.mbox_active; MAILBOX_t *mb = &pmbox->u.mb; struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; + + /* If the mailbox completed, process the completion and return */ + if (lpfc_sli4_process_missed_mbox_completions(phba)) + return; /* Check the pmbox pointer first. There is a race condition * between the mbox timeout handler getting executed in the @@ -6371,8 +6840,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) psli->sli_flag &= ~LPFC_SLI_ACTIVE; spin_unlock_irq(&phba->hbalock); - pring = &psli->ring[psli->fcp_ring]; - lpfc_sli_abort_iocb_ring(phba, pring); + lpfc_sli_abort_fcp_rings(phba); lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "0345 Resetting board due to mailbox timeout\n"); @@ -6411,7 +6879,7 @@ static int lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) { - MAILBOX_t *mb; + MAILBOX_t *mbx; struct lpfc_sli *psli = &phba->sli; uint32_t status, evtctr; uint32_t ha_copy, hc_copy; @@ -6465,7 +6933,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, psli = &phba->sli; - mb = &pmbox->u.mb; + mbx = &pmbox->u.mb; status = MBX_SUCCESS; if (phba->link_state == LPFC_HBA_ERROR) { @@ -6480,7 +6948,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, goto out_not_finished; } - if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT) { + if (mbx->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT) { if (lpfc_readl(phba->HCregaddr, &hc_copy) || !(hc_copy & HC_MBINT_ENA)) { spin_unlock_irqrestore(&phba->hbalock, drvr_flag); @@ -6534,7 +7002,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, "(%d):0308 Mbox cmd issue - BUSY Data: " "x%x x%x x%x x%x\n", pmbox->vport ? pmbox->vport->vpi : 0xffffff, - mb->mbxCommand, phba->pport->port_state, + mbx->mbxCommand, phba->pport->port_state, psli->sli_flag, flag); psli->slistat.mbox_busy++; @@ -6544,15 +7012,15 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, lpfc_debugfs_disc_trc(pmbox->vport, LPFC_DISC_TRC_MBOX_VPORT, "MBOX Bsy vport: cmd:x%x mb:x%x x%x", - (uint32_t)mb->mbxCommand, - mb->un.varWords[0], mb->un.varWords[1]); + (uint32_t)mbx->mbxCommand, + mbx->un.varWords[0], mbx->un.varWords[1]); } else { lpfc_debugfs_disc_trc(phba->pport, LPFC_DISC_TRC_MBOX, "MBOX Bsy: cmd:x%x mb:x%x x%x", - (uint32_t)mb->mbxCommand, - mb->un.varWords[0], mb->un.varWords[1]); + (uint32_t)mbx->mbxCommand, + mbx->un.varWords[0], mbx->un.varWords[1]); } return MBX_BUSY; @@ -6563,7 +7031,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, /* If we are not polling, we MUST be in SLI2 mode */ if (flag != MBX_POLL) { if (!(psli->sli_flag & LPFC_SLI_ACTIVE) && - (mb->mbxCommand != MBX_KILL_BOARD)) { + (mbx->mbxCommand != MBX_KILL_BOARD)) { psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command <mbxCommand> cannot issue */ @@ -6576,8 +7044,9 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, goto out_not_finished; } /* timeout active mbox command */ - mod_timer(&psli->mbox_tmo, (jiffies + - (HZ * lpfc_mbox_tmo_val(phba, pmbox)))); + timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, pmbox) * + 1000); + mod_timer(&psli->mbox_tmo, jiffies + timeout); } /* Mailbox cmd <cmd> issue */ @@ -6585,23 +7054,23 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, "(%d):0309 Mailbox cmd x%x issue Data: x%x x%x " "x%x\n", pmbox->vport ? pmbox->vport->vpi : 0, - mb->mbxCommand, phba->pport->port_state, + mbx->mbxCommand, phba->pport->port_state, psli->sli_flag, flag); - if (mb->mbxCommand != MBX_HEARTBEAT) { + if (mbx->mbxCommand != MBX_HEARTBEAT) { if (pmbox->vport) { lpfc_debugfs_disc_trc(pmbox->vport, LPFC_DISC_TRC_MBOX_VPORT, "MBOX Send vport: cmd:x%x mb:x%x x%x", - (uint32_t)mb->mbxCommand, - mb->un.varWords[0], mb->un.varWords[1]); + (uint32_t)mbx->mbxCommand, + mbx->un.varWords[0], mbx->un.varWords[1]); } else { lpfc_debugfs_disc_trc(phba->pport, LPFC_DISC_TRC_MBOX, "MBOX Send: cmd:x%x mb:x%x x%x", - (uint32_t)mb->mbxCommand, - mb->un.varWords[0], mb->un.varWords[1]); + (uint32_t)mbx->mbxCommand, + mbx->un.varWords[0], mbx->un.varWords[1]); } } @@ -6609,12 +7078,12 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, evtctr = psli->slistat.mbox_event; /* next set own bit for the adapter and copy over command word */ - mb->mbxOwner = OWN_CHIP; + mbx->mbxOwner = OWN_CHIP; if (psli->sli_flag & LPFC_SLI_ACTIVE) { /* Populate mbox extension offset word. */ if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) { - *(((uint32_t *)mb) + pmbox->mbox_offset_word) + *(((uint32_t *)mbx) + pmbox->mbox_offset_word) = (uint8_t *)phba->mbox_ext - (uint8_t *)phba->mbox; } @@ -6626,11 +7095,11 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, pmbox->in_ext_byte_len); } /* Copy command data to host SLIM area */ - lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); + lpfc_sli_pcimem_bcopy(mbx, phba->mbox, MAILBOX_CMD_SIZE); } else { /* Populate mbox extension offset word. */ if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) - *(((uint32_t *)mb) + pmbox->mbox_offset_word) + *(((uint32_t *)mbx) + pmbox->mbox_offset_word) = MAILBOX_HBA_EXT_OFFSET; /* Copy the mailbox extension data */ @@ -6640,24 +7109,24 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, pmbox->context2, pmbox->in_ext_byte_len); } - if (mb->mbxCommand == MBX_CONFIG_PORT) { + if (mbx->mbxCommand == MBX_CONFIG_PORT) { /* copy command data into host mbox for cmpl */ - lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); + lpfc_sli_pcimem_bcopy(mbx, phba->mbox, MAILBOX_CMD_SIZE); } /* First copy mbox command data to HBA SLIM, skip past first word */ to_slim = phba->MBslimaddr + sizeof (uint32_t); - lpfc_memcpy_to_slim(to_slim, &mb->un.varWords[0], + lpfc_memcpy_to_slim(to_slim, &mbx->un.varWords[0], MAILBOX_CMD_SIZE - sizeof (uint32_t)); /* Next copy over first word, with mbxOwner set */ - ldata = *((uint32_t *)mb); + ldata = *((uint32_t *)mbx); to_slim = phba->MBslimaddr; writel(ldata, to_slim); readl(to_slim); /* flush */ - if (mb->mbxCommand == MBX_CONFIG_PORT) { + if (mbx->mbxCommand == MBX_CONFIG_PORT) { /* switch over to host mailbox */ psli->sli_flag |= LPFC_SLI_ACTIVE; } @@ -6732,7 +7201,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, /* First copy command data */ word0 = *((uint32_t *)phba->mbox); word0 = le32_to_cpu(word0); - if (mb->mbxCommand == MBX_CONFIG_PORT) { + if (mbx->mbxCommand == MBX_CONFIG_PORT) { MAILBOX_t *slimmb; uint32_t slimword0; /* Check real SLIM for any errors */ @@ -6759,7 +7228,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, if (psli->sli_flag & LPFC_SLI_ACTIVE) { /* copy results back to user */ - lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE); + lpfc_sli_pcimem_bcopy(phba->mbox, mbx, MAILBOX_CMD_SIZE); /* Copy the mailbox extension data */ if (pmbox->out_ext_byte_len && pmbox->context2) { lpfc_sli_pcimem_bcopy(phba->mbox_ext, @@ -6768,7 +7237,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, } } else { /* First copy command data */ - lpfc_memcpy_from_slim(mb, phba->MBslimaddr, + lpfc_memcpy_from_slim(mbx, phba->MBslimaddr, MAILBOX_CMD_SIZE); /* Copy the mailbox extension data */ if (pmbox->out_ext_byte_len && pmbox->context2) { @@ -6783,7 +7252,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, readl(phba->HAregaddr); /* flush */ psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - status = mb->mbxStatus; + status = mbx->mbxStatus; } spin_unlock_irqrestore(&phba->hbalock, drvr_flag); @@ -6828,6 +7297,10 @@ lpfc_sli4_async_mbox_block(struct lpfc_hba *phba) 1000) + jiffies; spin_unlock_irq(&phba->hbalock); + /* Make sure the mailbox is really active */ + if (timeout) + lpfc_sli4_process_missed_mbox_completions(phba); + /* Wait for the outstnading mailbox command to complete */ while (phba->sli.mbox_active) { /* Check active mailbox complete status every 2ms */ @@ -6884,6 +7357,40 @@ lpfc_sli4_async_mbox_unblock(struct lpfc_hba *phba) } /** + * lpfc_sli4_wait_bmbx_ready - Wait for bootstrap mailbox register ready + * @phba: Pointer to HBA context object. + * @mboxq: Pointer to mailbox object. + * + * The function waits for the bootstrap mailbox register ready bit from + * port for twice the regular mailbox command timeout value. + * + * 0 - no timeout on waiting for bootstrap mailbox register ready. + * MBXERR_ERROR - wait for bootstrap mailbox register timed out. + **/ +static int +lpfc_sli4_wait_bmbx_ready(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +{ + uint32_t db_ready; + unsigned long timeout; + struct lpfc_register bmbx_reg; + + timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq) + * 1000) + jiffies; + + do { + bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr); + db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg); + if (!db_ready) + msleep(2); + + if (time_after(jiffies, timeout)) + return MBXERR_ERROR; + } while (!db_ready); + + return 0; +} + +/** * lpfc_sli4_post_sync_mbox - Post an SLI4 mailbox to the bootstrap mailbox * @phba: Pointer to HBA context object. * @mboxq: Pointer to mailbox object. @@ -6904,15 +7411,12 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { int rc = MBX_SUCCESS; unsigned long iflag; - uint32_t db_ready; uint32_t mcqe_status; uint32_t mbx_cmnd; - unsigned long timeout; struct lpfc_sli *psli = &phba->sli; struct lpfc_mqe *mb = &mboxq->u.mqe; struct lpfc_bmbx_create *mbox_rgn; struct dma_address *dma_address; - struct lpfc_register bmbx_reg; /* * Only one mailbox can be active to the bootstrap mailbox region @@ -6936,6 +7440,11 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) phba->sli.mbox_active = mboxq; spin_unlock_irqrestore(&phba->hbalock, iflag); + /* wait for bootstrap mbox register for readyness */ + rc = lpfc_sli4_wait_bmbx_ready(phba, mboxq); + if (rc) + goto exit; + /* * Initialize the bootstrap memory region to avoid stale data areas * in the mailbox post. Then copy the caller's mailbox contents to @@ -6950,35 +7459,18 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) dma_address = &phba->sli4_hba.bmbx.dma_address; writel(dma_address->addr_hi, phba->sli4_hba.BMBXregaddr); - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq) - * 1000) + jiffies; - do { - bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr); - db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg); - if (!db_ready) - msleep(2); - - if (time_after(jiffies, timeout)) { - rc = MBXERR_ERROR; - goto exit; - } - } while (!db_ready); + /* wait for bootstrap mbox register for hi-address write done */ + rc = lpfc_sli4_wait_bmbx_ready(phba, mboxq); + if (rc) + goto exit; /* Post the low mailbox dma address to the port. */ writel(dma_address->addr_lo, phba->sli4_hba.BMBXregaddr); - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq) - * 1000) + jiffies; - do { - bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr); - db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg); - if (!db_ready) - msleep(2); - if (time_after(jiffies, timeout)) { - rc = MBXERR_ERROR; - goto exit; - } - } while (!db_ready); + /* wait for bootstrap mbox register for low address write done */ + rc = lpfc_sli4_wait_bmbx_ready(phba, mboxq); + if (rc) + goto exit; /* * Read the CQ to ensure the mailbox has completed. @@ -7075,14 +7567,19 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, if (rc != MBX_SUCCESS) lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, "(%d):2541 Mailbox command x%x " - "(x%x/x%x) cannot issue Data: " - "x%x x%x\n", + "(x%x/x%x) failure: " + "mqe_sta: x%x mcqe_sta: x%x/x%x " + "Data: x%x x%x\n,", mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, mboxq), lpfc_sli_config_mbox_opcode_get(phba, mboxq), + bf_get(lpfc_mqe_status, &mboxq->u.mqe), + bf_get(lpfc_mcqe_status, &mboxq->mcqe), + bf_get(lpfc_mcqe_ext_status, + &mboxq->mcqe), psli->sli_flag, flag); return rc; } else if (flag == MBX_POLL) { @@ -7101,18 +7598,22 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, /* Successfully blocked, now issue sync mbox cmd */ rc = lpfc_sli4_post_sync_mbox(phba, mboxq); if (rc != MBX_SUCCESS) - lpfc_printf_log(phba, KERN_ERR, + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, - "(%d):2597 Mailbox command " - "x%x (x%x/x%x) cannot issue " - "Data: x%x x%x\n", - mboxq->vport ? - mboxq->vport->vpi : 0, + "(%d):2597 Sync Mailbox command " + "x%x (x%x/x%x) failure: " + "mqe_sta: x%x mcqe_sta: x%x/x%x " + "Data: x%x x%x\n,", + mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, mboxq), lpfc_sli_config_mbox_opcode_get(phba, mboxq), + bf_get(lpfc_mqe_status, &mboxq->u.mqe), + bf_get(lpfc_mcqe_status, &mboxq->mcqe), + bf_get(lpfc_mcqe_ext_status, + &mboxq->mcqe), psli->sli_flag, flag); /* Unblock the async mailbox posting afterward */ lpfc_sli4_async_mbox_unblock(phba); @@ -7222,7 +7723,7 @@ lpfc_sli4_post_async_mbox(struct lpfc_hba *phba) /* Start timer for the mbox_tmo and log some mailbox post messages */ mod_timer(&psli->mbox_tmo, (jiffies + - (HZ * lpfc_mbox_tmo_val(phba, mboxq)))); + msecs_to_jiffies(1000 * lpfc_mbox_tmo_val(phba, mboxq)))); lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, "(%d):0355 Mailbox cmd x%x (x%x/x%x) issue Data: " @@ -7267,11 +7768,13 @@ lpfc_sli4_post_async_mbox(struct lpfc_hba *phba) out_not_finished: spin_lock_irqsave(&phba->hbalock, iflags); - mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED; - __lpfc_mbox_cmpl_put(phba, mboxq); - /* Release the token */ - psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - phba->sli.mbox_active = NULL; + if (phba->sli.mbox_active) { + mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED; + __lpfc_mbox_cmpl_put(phba, mboxq); + /* Release the token */ + psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + phba->sli.mbox_active = NULL; + } spin_unlock_irqrestore(&phba->hbalock, iflags); return MBX_NOT_FINISHED; @@ -7351,7 +7854,6 @@ __lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, { /* Insert the caller's iocb in the txq tail for later processing. */ list_add_tail(&piocb->list, &pring->txq); - pring->txq_cnt++; } /** @@ -7555,6 +8057,8 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, sgl = (struct sli4_sge *)sglq->sgl; icmd = &piocbq->iocb; + if (icmd->ulpCommand == CMD_XMIT_BLS_RSP64_CX) + return sglq->sli4_xritag; if (icmd->un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) { numBdes = icmd->un.genreq64.bdl.bdeSize / sizeof(struct ulp_bde64); @@ -7634,14 +8138,25 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, * * Return: index into SLI4 fast-path FCP queue index. **/ -static uint32_t +static inline uint32_t lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba) { - ++phba->fcp_qidx; - if (phba->fcp_qidx >= phba->cfg_fcp_wq_count) - phba->fcp_qidx = 0; - - return phba->fcp_qidx; + struct lpfc_vector_map_info *cpup; + int chann, cpu; + + if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_CPU + && phba->cfg_fcp_io_channel > 1) { + cpu = smp_processor_id(); + if (cpu < phba->sli4_hba.num_present_cpu) { + cpup = phba->sli4_hba.cpu_map; + cpup += cpu; + return cpup->channel_id; + } + chann = cpu; + } + chann = atomic_add_return(1, &phba->fcp_qidx); + chann = (chann % phba->cfg_fcp_io_channel); + return chann; } /** @@ -7693,6 +8208,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, abort_tag = (uint32_t) iocbq->iotag; xritag = iocbq->sli4_xritag; wqe->generic.wqe_com.word7 = 0; /* The ct field has moved so reset */ + wqe->generic.wqe_com.word10 = 0; /* words0-2 bpl convert bde */ if (iocbq->iocb.un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) { numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize / @@ -7723,7 +8239,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, switch (iocbq->iocb.ulpCommand) { case CMD_ELS_REQUEST64_CR: - ndlp = (struct lpfc_nodelist *)iocbq->context1; + if (iocbq->iocb_flag & LPFC_IO_LIBDFC) + ndlp = iocbq->context_un.ndlp; + else + ndlp = (struct lpfc_nodelist *)iocbq->context1; if (!iocbq->iocb.ulpLe) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2007 Only Limited Edition cmd Format" @@ -7756,14 +8275,20 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { if (pcmd && (*pcmd == ELS_CMD_FLOGI || *pcmd == ELS_CMD_SCR || + *pcmd == ELS_CMD_FDISC || + *pcmd == ELS_CMD_LOGO || *pcmd == ELS_CMD_PLOGI)) { bf_set(els_req64_sp, &wqe->els_req, 1); bf_set(els_req64_sid, &wqe->els_req, iocbq->vport->fc_myDID); + if ((*pcmd == ELS_CMD_FLOGI) && + !(phba->fc_topology == + LPFC_TOPOLOGY_LOOP)) + bf_set(els_req64_sid, &wqe->els_req, 0); bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, - phba->vpi_ids[phba->pport->vpi]); - } else if (iocbq->context1) { + phba->vpi_ids[iocbq->vport->vpi]); + } else if (pcmd && iocbq->context1) { bf_set(wqe_ct, &wqe->els_req.wqe_com, 0); bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); @@ -7777,6 +8302,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_qosd, &wqe->els_req.wqe_com, 1); bf_set(wqe_lenloc, &wqe->els_req.wqe_com, LPFC_WQE_LENLOC_NONE); bf_set(wqe_ebde_cnt, &wqe->els_req.wqe_com, 0); + wqe->els_req.max_response_payload_len = total_len - xmit_len; break; case CMD_XMIT_SEQUENCE64_CX: bf_set(wqe_ctxt_tag, &wqe->xmit_sequence.wqe_com, @@ -7821,8 +8347,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, command_type = FCP_COMMAND_DATA_OUT; /* word3 iocb=iotag wqe=payload_offset_len */ /* Add the FCP_CMD and FCP_RSP sizes to get the offset */ - wqe->fcp_iwrite.payload_offset_len = - xmit_len + sizeof(struct fcp_rsp); + bf_set(payload_offset_len, &wqe->fcp_iwrite, + xmit_len + sizeof(struct fcp_rsp)); + bf_set(cmd_buff_len, &wqe->fcp_iwrite, + 0); /* word4 iocb=parameter wqe=total_xfer_length memcpy */ /* word5 iocb=initial_xfer_len wqe=initial_xfer_len memcpy */ bf_set(wqe_erp, &wqe->fcp_iwrite.wqe_com, @@ -7830,18 +8358,28 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_lnk, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpXS); /* Always open the exchange */ bf_set(wqe_xc, &wqe->fcp_iwrite.wqe_com, 0); - bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1); bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE); bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_LENLOC_WORD4); bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0); bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU); + bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1); + if (iocbq->iocb_flag & LPFC_IO_OAS) { + bf_set(wqe_oas, &wqe->fcp_iwrite.wqe_com, 1); + if (phba->cfg_XLanePriority) { + bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1); + bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com, + (phba->cfg_XLanePriority << 1)); + } + } break; case CMD_FCP_IREAD64_CR: /* word3 iocb=iotag wqe=payload_offset_len */ /* Add the FCP_CMD and FCP_RSP sizes to get the offset */ - wqe->fcp_iread.payload_offset_len = - xmit_len + sizeof(struct fcp_rsp); + bf_set(payload_offset_len, &wqe->fcp_iread, + xmit_len + sizeof(struct fcp_rsp)); + bf_set(cmd_buff_len, &wqe->fcp_iread, + 0); /* word4 iocb=parameter wqe=total_xfer_length memcpy */ /* word5 iocb=initial_xfer_len wqe=initial_xfer_len memcpy */ bf_set(wqe_erp, &wqe->fcp_iread.wqe_com, @@ -7849,16 +8387,29 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_lnk, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpXS); /* Always open the exchange */ bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0); - bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1); bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ); bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, LPFC_WQE_LENLOC_WORD4); bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0); bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU); + bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1); + if (iocbq->iocb_flag & LPFC_IO_OAS) { + bf_set(wqe_oas, &wqe->fcp_iread.wqe_com, 1); + if (phba->cfg_XLanePriority) { + bf_set(wqe_ccpe, &wqe->fcp_iread.wqe_com, 1); + bf_set(wqe_ccp, &wqe->fcp_iread.wqe_com, + (phba->cfg_XLanePriority << 1)); + } + } break; case CMD_FCP_ICMND64_CR: + /* word3 iocb=iotag wqe=payload_offset_len */ + /* Add the FCP_CMD and FCP_RSP sizes to get the offset */ + bf_set(payload_offset_len, &wqe->fcp_icmd, + xmit_len + sizeof(struct fcp_rsp)); + bf_set(cmd_buff_len, &wqe->fcp_icmd, + 0); /* word3 iocb=IO_TAG wqe=reserved */ - wqe->fcp_icmd.rsrvd3 = 0; bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0); /* Always open the exchange */ bf_set(wqe_xc, &wqe->fcp_icmd.wqe_com, 0); @@ -7868,6 +8419,16 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, LPFC_WQE_LENLOC_NONE); bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0); + bf_set(wqe_erp, &wqe->fcp_icmd.wqe_com, + iocbq->iocb.ulpFCP2Rcvy); + if (iocbq->iocb_flag & LPFC_IO_OAS) { + bf_set(wqe_oas, &wqe->fcp_icmd.wqe_com, 1); + if (phba->cfg_XLanePriority) { + bf_set(wqe_ccpe, &wqe->fcp_icmd.wqe_com, 1); + bf_set(wqe_ccp, &wqe->fcp_icmd.wqe_com, + (phba->cfg_XLanePriority << 1)); + } + } break; case CMD_GEN_REQUEST64_CR: /* For this command calculate the xmit length of the @@ -7902,6 +8463,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_qosd, &wqe->gen_req.wqe_com, 1); bf_set(wqe_lenloc, &wqe->gen_req.wqe_com, LPFC_WQE_LENLOC_NONE); bf_set(wqe_ebde_cnt, &wqe->gen_req.wqe_com, 0); + wqe->gen_req.max_response_payload_len = total_len - xmit_len; command_type = OTHER_COMMAND; break; case CMD_XMIT_ELS_RSP64_CX: @@ -7909,11 +8471,25 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, /* words0-2 BDE memcpy */ /* word3 iocb=iotag32 wqe=response_payload_len */ wqe->xmit_els_rsp.response_payload_len = xmit_len; - /* word4 iocb=did wge=rsvd. */ - wqe->xmit_els_rsp.rsvd4 = 0; + /* word4 */ + wqe->xmit_els_rsp.word4 = 0; /* word5 iocb=rsvd wge=did */ bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest, - iocbq->iocb.un.elsreq64.remoteID); + iocbq->iocb.un.xseq64.xmit_els_remoteID); + + if_type = bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf); + if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { + if (iocbq->vport->fc_flag & FC_PT2PT) { + bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1); + bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, + iocbq->vport->fc_myDID); + if (iocbq->vport->fc_myDID == Fabric_DID) { + bf_set(wqe_els_did, + &wqe->xmit_els_rsp.wqe_dest, 0); + } + } + } bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com, ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); bf_set(wqe_pu, &wqe->xmit_els_rsp.wqe_com, iocbq->iocb.ulpPU); @@ -7933,11 +8509,11 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, pcmd = (uint32_t *) (((struct lpfc_dmabuf *) iocbq->context2)->virt); if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - bf_set(els_req64_sp, &wqe->els_req, 1); - bf_set(els_req64_sid, &wqe->els_req, + bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1); + bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, iocbq->vport->fc_myDID); - bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); - bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, + bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com, 1); + bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, phba->vpi_ids[phba->pport->vpi]); } command_type = OTHER_COMMAND; @@ -7982,6 +8558,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, xritag = 0; break; case CMD_XMIT_BLS_RSP64_CX: + ndlp = (struct lpfc_nodelist *)iocbq->context1; /* As BLS ABTS RSP WQE is very different from other WQEs, * we re-construct this WQE here based on information in * iocbq from scratch. @@ -8008,8 +8585,15 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, } bf_set(xmit_bls_rsp64_seqcnthi, &wqe->xmit_bls_rsp, 0xffff); bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1); + + /* Use CT=VPI */ + bf_set(wqe_els_did, &wqe->xmit_bls_rsp.wqe_dest, + ndlp->nlp_DID); + bf_set(xmit_bls_rsp64_temprpi, &wqe->xmit_bls_rsp, + iocbq->iocb.ulpContext); + bf_set(wqe_ct, &wqe->xmit_bls_rsp.wqe_com, 1); bf_set(wqe_ctxt_tag, &wqe->xmit_bls_rsp.wqe_com, - iocbq->iocb.ulpContext); + phba->vpi_ids[phba->pport->vpi]); bf_set(wqe_qosd, &wqe->xmit_bls_rsp.wqe_com, 1); bf_set(wqe_lenloc, &wqe->xmit_bls_rsp.wqe_com, LPFC_WQE_LENLOC_NONE); @@ -8039,6 +8623,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, break; } + if (iocbq->iocb_flag & LPFC_IO_DIF_PASS) + bf_set(wqe_dif, &wqe->generic.wqe_com, LPFC_WQE_DIF_PASSTHRU); + else if (iocbq->iocb_flag & LPFC_IO_DIF_STRIP) + bf_set(wqe_dif, &wqe->generic.wqe_com, LPFC_WQE_DIF_STRIP); + else if (iocbq->iocb_flag & LPFC_IO_DIF_INSERT) + bf_set(wqe_dif, &wqe->generic.wqe_com, LPFC_WQE_DIF_INSERT); + iocbq->iocb_flag &= ~(LPFC_IO_DIF_PASS | LPFC_IO_DIF_STRIP | + LPFC_IO_DIF_INSERT); bf_set(wqe_xri_tag, &wqe->generic.wqe_com, xritag); bf_set(wqe_reqtag, &wqe->generic.wqe_com, iocbq->iotag); wqe->generic.wqe_com.abort_tag = abort_tag; @@ -8069,15 +8661,15 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, { struct lpfc_sglq *sglq; union lpfc_wqe wqe; + struct lpfc_queue *wq; struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number]; if (piocb->sli4_xritag == NO_XRI) { if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN || - piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN || - piocb->iocb.ulpCommand == CMD_XMIT_BLS_RSP64_CX) + piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN) sglq = NULL; else { - if (pring->txq_cnt) { + if (!list_empty(&pring->txq)) { if (!(flag & SLI_IOCB_RET_IOCB)) { __lpfc_sli_ringtx_put(phba, pring, piocb); @@ -8106,7 +8698,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, * This is a continuation of a commandi,(CX) so this * sglq is on the active list */ - sglq = __lpfc_get_active_sglq(phba, piocb->sli4_xritag); + sglq = __lpfc_get_active_sglq(phba, piocb->sli4_lxritag); if (!sglq) return IOCB_ERROR; } @@ -8122,21 +8714,17 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, return IOCB_ERROR; if ((piocb->iocb_flag & LPFC_IO_FCP) || - (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) { - /* - * For FCP command IOCB, get a new WQ index to distribute - * WQE across the WQsr. On the other hand, for abort IOCB, - * it carries the same WQ index to the original command - * IOCB. - */ - if (piocb->iocb_flag & LPFC_IO_FCP) - piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba); - if (unlikely(!phba->sli4_hba.fcp_wq)) - return IOCB_ERROR; - if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx], - &wqe)) + (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) { + if (!phba->cfg_fof || (!(piocb->iocb_flag & LPFC_IO_OAS))) { + wq = phba->sli4_hba.fcp_wq[piocb->fcp_wqidx]; + } else { + wq = phba->sli4_hba.oas_wq; + } + if (lpfc_sli4_wq_put(wq, &wqe)) return IOCB_ERROR; } else { + if (unlikely(!phba->sli4_hba.els_wq)) + return IOCB_ERROR; if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe)) return IOCB_ERROR; } @@ -8213,13 +8801,76 @@ int lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, struct lpfc_iocbq *piocb, uint32_t flag) { + struct lpfc_fcp_eq_hdl *fcp_eq_hdl; + struct lpfc_sli_ring *pring; + struct lpfc_queue *fpeq; + struct lpfc_eqe *eqe; unsigned long iflags; - int rc; + int rc, idx; - spin_lock_irqsave(&phba->hbalock, iflags); - rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag); - spin_unlock_irqrestore(&phba->hbalock, iflags); + if (phba->sli_rev == LPFC_SLI_REV4) { + if (piocb->iocb_flag & LPFC_IO_FCP) { + if (!phba->cfg_fof || (!(piocb->iocb_flag & + LPFC_IO_OAS))) { + if (unlikely(!phba->sli4_hba.fcp_wq)) + return IOCB_ERROR; + idx = lpfc_sli4_scmd_to_wqidx_distr(phba); + piocb->fcp_wqidx = idx; + ring_number = MAX_SLI3_CONFIGURED_RINGS + idx; + } else { + if (unlikely(!phba->sli4_hba.oas_wq)) + return IOCB_ERROR; + idx = 0; + piocb->fcp_wqidx = 0; + ring_number = LPFC_FCP_OAS_RING; + } + pring = &phba->sli.ring[ring_number]; + spin_lock_irqsave(&pring->ring_lock, iflags); + rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, + flag); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + + if (lpfc_fcp_look_ahead) { + fcp_eq_hdl = &phba->sli4_hba.fcp_eq_hdl[idx]; + + if (atomic_dec_and_test(&fcp_eq_hdl-> + fcp_eq_in_use)) { + + /* Get associated EQ with this index */ + fpeq = phba->sli4_hba.hba_eq[idx]; + /* Turn off interrupts from this EQ */ + lpfc_sli4_eq_clr_intr(fpeq); + + /* + * Process all the events on FCP EQ + */ + while ((eqe = lpfc_sli4_eq_get(fpeq))) { + lpfc_sli4_hba_handle_eqe(phba, + eqe, idx); + fpeq->EQ_processed++; + } + + /* Always clear and re-arm the EQ */ + lpfc_sli4_eq_release(fpeq, + LPFC_QUEUE_REARM); + } + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); + } + } else { + pring = &phba->sli.ring[ring_number]; + spin_lock_irqsave(&pring->ring_lock, iflags); + rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, + flag); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + + } + } else { + /* For now, SLI2/3 will still use hbalock */ + spin_lock_irqsave(&phba->hbalock, iflags); + rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag); + spin_unlock_irqrestore(&phba->hbalock, iflags); + } return rc; } @@ -8246,18 +8897,18 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) /* Take some away from the FCP ring */ pring = &psli->ring[psli->fcp_ring]; - pring->numCiocb -= SLI2_IOCB_CMD_R1XTRA_ENTRIES; - pring->numRiocb -= SLI2_IOCB_RSP_R1XTRA_ENTRIES; - pring->numCiocb -= SLI2_IOCB_CMD_R3XTRA_ENTRIES; - pring->numRiocb -= SLI2_IOCB_RSP_R3XTRA_ENTRIES; + pring->sli.sli3.numCiocb -= SLI2_IOCB_CMD_R1XTRA_ENTRIES; + pring->sli.sli3.numRiocb -= SLI2_IOCB_RSP_R1XTRA_ENTRIES; + pring->sli.sli3.numCiocb -= SLI2_IOCB_CMD_R3XTRA_ENTRIES; + pring->sli.sli3.numRiocb -= SLI2_IOCB_RSP_R3XTRA_ENTRIES; /* and give them to the extra ring */ pring = &psli->ring[psli->extra_ring]; - pring->numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES; - pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES; - pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES; - pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES; + pring->sli.sli3.numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES; + pring->sli.sli3.numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES; + pring->sli.sli3.numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES; + pring->sli.sli3.numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES; /* Setup default profile for this ring */ pring->iotag_max = 4096; @@ -8269,56 +8920,6 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) return 0; } -/* lpfc_sli_abts_recover_port - Recover a port that failed an ABTS. - * @vport: pointer to virtual port object. - * @ndlp: nodelist pointer for the impacted rport. - * - * The driver calls this routine in response to a XRI ABORT CQE - * event from the port. In this event, the driver is required to - * recover its login to the rport even though its login may be valid - * from the driver's perspective. The failed ABTS notice from the - * port indicates the rport is not responding. - */ -static void -lpfc_sli_abts_recover_port(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp) -{ - struct Scsi_Host *shost; - struct lpfc_hba *phba; - unsigned long flags = 0; - - shost = lpfc_shost_from_vport(vport); - phba = vport->phba; - if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) { - lpfc_printf_log(phba, KERN_INFO, - LOG_SLI, "3093 No rport recovery needed. " - "rport in state 0x%x\n", - ndlp->nlp_state); - return; - } - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "3094 Start rport recovery on shost id 0x%x " - "fc_id 0x%06x vpi 0x%x rpi 0x%x state 0x%x " - "flags 0x%x\n", - shost->host_no, ndlp->nlp_DID, - vport->vpi, ndlp->nlp_rpi, ndlp->nlp_state, - ndlp->nlp_flag); - /* - * The rport is not responding. Don't attempt ADISC recovery. - * Remove the FCP-2 flag to force a PLOGI. - */ - spin_lock_irqsave(shost->host_lock, flags); - ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - spin_unlock_irqrestore(shost->host_lock, flags); - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RECOVERY); - lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irqsave(shost->host_lock, flags); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irqrestore(shost->host_lock, flags); - lpfc_disc_start(vport); -} - /* lpfc_sli_abts_err_handler - handle a failed ABTS request from an SLI3 port. * @phba: Pointer to HBA context object. * @iocbq: Pointer to iocb object. @@ -8383,20 +8984,32 @@ lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri) { struct lpfc_vport *vport; + uint32_t ext_status = 0; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "3115 Node Context not found, driver " "ignoring abts err event\n"); + return; + } + vport = ndlp->vport; lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "3116 Port generated FCP XRI ABORT event on " - "vpi %d rpi %d xri x%x status 0x%x\n", - ndlp->vport->vpi, ndlp->nlp_rpi, + "vpi %d rpi %d xri x%x status 0x%x parameter x%x\n", + ndlp->vport->vpi, phba->sli4_hba.rpi_ids[ndlp->nlp_rpi], bf_get(lpfc_wcqe_xa_xri, axri), - bf_get(lpfc_wcqe_xa_status, axri)); + bf_get(lpfc_wcqe_xa_status, axri), + axri->parameter); - if (bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) + /* + * Catch the ABTS protocol failure case. Older OCe FW releases returned + * LOCAL_REJECT and 0 for a failed ABTS exchange and later OCe and + * LPe FW releases returned LOCAL_REJECT and SEQUENCE_TIMEOUT. + */ + ext_status = axri->parameter & IOERR_PARAM_MASK; + if ((bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) && + ((ext_status == IOERR_SEQUENCE_TIMEOUT) || (ext_status == 0))) lpfc_sli_abts_recover_port(vport, ndlp); } @@ -8492,7 +9105,9 @@ lpfc_sli_setup(struct lpfc_hba *phba) struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; - psli->num_rings = MAX_CONFIGURED_RINGS; + psli->num_rings = MAX_SLI3_CONFIGURED_RINGS; + if (phba->sli_rev == LPFC_SLI_REV4) + psli->num_rings += phba->cfg_fcp_io_channel; psli->sli_flag = 0; psli->fcp_ring = LPFC_FCP_RING; psli->next_ring = LPFC_FCP_NEXT_RING; @@ -8507,16 +9122,20 @@ lpfc_sli_setup(struct lpfc_hba *phba) switch (i) { case LPFC_FCP_RING: /* ring 0 - FCP */ /* numCiocb and numRiocb are used in config_port */ - pring->numCiocb = SLI2_IOCB_CMD_R0_ENTRIES; - pring->numRiocb = SLI2_IOCB_RSP_R0_ENTRIES; - pring->numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES; - pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES; - pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES; - pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES; - pring->sizeCiocb = (phba->sli_rev == 3) ? + pring->sli.sli3.numCiocb = SLI2_IOCB_CMD_R0_ENTRIES; + pring->sli.sli3.numRiocb = SLI2_IOCB_RSP_R0_ENTRIES; + pring->sli.sli3.numCiocb += + SLI2_IOCB_CMD_R1XTRA_ENTRIES; + pring->sli.sli3.numRiocb += + SLI2_IOCB_RSP_R1XTRA_ENTRIES; + pring->sli.sli3.numCiocb += + SLI2_IOCB_CMD_R3XTRA_ENTRIES; + pring->sli.sli3.numRiocb += + SLI2_IOCB_RSP_R3XTRA_ENTRIES; + pring->sli.sli3.sizeCiocb = (phba->sli_rev == 3) ? SLI3_IOCB_CMD_SIZE : SLI2_IOCB_CMD_SIZE; - pring->sizeRiocb = (phba->sli_rev == 3) ? + pring->sli.sli3.sizeRiocb = (phba->sli_rev == 3) ? SLI3_IOCB_RSP_SIZE : SLI2_IOCB_RSP_SIZE; pring->iotag_ctr = 0; @@ -8527,12 +9146,12 @@ lpfc_sli_setup(struct lpfc_hba *phba) break; case LPFC_EXTRA_RING: /* ring 1 - EXTRA */ /* numCiocb and numRiocb are used in config_port */ - pring->numCiocb = SLI2_IOCB_CMD_R1_ENTRIES; - pring->numRiocb = SLI2_IOCB_RSP_R1_ENTRIES; - pring->sizeCiocb = (phba->sli_rev == 3) ? + pring->sli.sli3.numCiocb = SLI2_IOCB_CMD_R1_ENTRIES; + pring->sli.sli3.numRiocb = SLI2_IOCB_RSP_R1_ENTRIES; + pring->sli.sli3.sizeCiocb = (phba->sli_rev == 3) ? SLI3_IOCB_CMD_SIZE : SLI2_IOCB_CMD_SIZE; - pring->sizeRiocb = (phba->sli_rev == 3) ? + pring->sli.sli3.sizeRiocb = (phba->sli_rev == 3) ? SLI3_IOCB_RSP_SIZE : SLI2_IOCB_RSP_SIZE; pring->iotag_max = phba->cfg_hba_queue_depth; @@ -8540,12 +9159,12 @@ lpfc_sli_setup(struct lpfc_hba *phba) break; case LPFC_ELS_RING: /* ring 2 - ELS / CT */ /* numCiocb and numRiocb are used in config_port */ - pring->numCiocb = SLI2_IOCB_CMD_R2_ENTRIES; - pring->numRiocb = SLI2_IOCB_RSP_R2_ENTRIES; - pring->sizeCiocb = (phba->sli_rev == 3) ? + pring->sli.sli3.numCiocb = SLI2_IOCB_CMD_R2_ENTRIES; + pring->sli.sli3.numRiocb = SLI2_IOCB_RSP_R2_ENTRIES; + pring->sli.sli3.sizeCiocb = (phba->sli_rev == 3) ? SLI3_IOCB_CMD_SIZE : SLI2_IOCB_CMD_SIZE; - pring->sizeRiocb = (phba->sli_rev == 3) ? + pring->sli.sli3.sizeRiocb = (phba->sli_rev == 3) ? SLI3_IOCB_RSP_SIZE : SLI2_IOCB_RSP_SIZE; pring->fast_iotag = 0; @@ -8578,16 +9197,11 @@ lpfc_sli_setup(struct lpfc_hba *phba) pring->prt[3].type = FC_TYPE_CT; pring->prt[3].lpfc_sli_rcv_unsol_event = lpfc_ct_unsol_event; - /* abort unsolicited sequence */ - pring->prt[4].profile = 0; /* Mask 4 */ - pring->prt[4].rctl = FC_RCTL_BA_ABTS; - pring->prt[4].type = FC_TYPE_BLS; - pring->prt[4].lpfc_sli_rcv_unsol_event = - lpfc_sli4_ct_abort_unsol_event; break; } - totiocbsize += (pring->numCiocb * pring->sizeCiocb) + - (pring->numRiocb * pring->sizeRiocb); + totiocbsize += (pring->sli.sli3.numCiocb * + pring->sli.sli3.sizeCiocb) + + (pring->sli.sli3.numRiocb * pring->sli.sli3.sizeRiocb); } if (totiocbsize > MAX_SLIM_IOCB_SIZE) { /* Too many cmd / rsp ring entries in SLI2 SLIM */ @@ -8628,14 +9242,16 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba) for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; pring->ringno = i; - pring->next_cmdidx = 0; - pring->local_getidx = 0; - pring->cmdidx = 0; + pring->sli.sli3.next_cmdidx = 0; + pring->sli.sli3.local_getidx = 0; + pring->sli.sli3.cmdidx = 0; + pring->flag = 0; INIT_LIST_HEAD(&pring->txq); INIT_LIST_HEAD(&pring->txcmplq); INIT_LIST_HEAD(&pring->iocb_continueq); INIT_LIST_HEAD(&pring->iocb_continue_saveq); INIT_LIST_HEAD(&pring->postbufq); + spin_lock_init(&pring->ring_lock); } spin_unlock_irq(&phba->hbalock); return 1; @@ -8736,7 +9352,6 @@ lpfc_sli_host_down(struct lpfc_vport *vport) if (iocb->vport != vport) continue; list_move_tail(&iocb->list, &completions); - pring->txq_cnt--; } /* Next issue ABTS for everything on the txcmplq */ @@ -8784,7 +9399,7 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) int i; /* Shutdown the mailbox command sub-system */ - lpfc_sli_mbox_sys_shutdown(phba); + lpfc_sli_mbox_sys_shutdown(phba, LPFC_MBX_WAIT); lpfc_hba_down_prep(phba); @@ -8805,8 +9420,6 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) * given to the FW yet. */ list_splice_init(&pring->txq, &completions); - pring->txq_cnt = 0; - } spin_unlock_irqrestore(&phba->hbalock, flags); @@ -9134,6 +9747,7 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, IOCB_t *icmd = NULL; IOCB_t *iabt = NULL; int retval; + unsigned long iflags; /* * There are certain command types we don't want to abort. And we @@ -9186,7 +9800,17 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, iabt->un.acxri.abortIoTag, iabt->un.acxri.abortContextTag, abtsiocbp->iotag); - retval = __lpfc_sli_issue_iocb(phba, pring->ringno, abtsiocbp, 0); + + if (phba->sli_rev == LPFC_SLI_REV4) { + /* Note: both hbalock and ring_lock need to be set here */ + spin_lock_irqsave(&pring->ring_lock, iflags); + retval = __lpfc_sli_issue_iocb(phba, pring->ringno, + abtsiocbp, 0); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + } else { + retval = __lpfc_sli_issue_iocb(phba, pring->ringno, + abtsiocbp, 0); + } if (retval) __lpfc_sli_release_iocbq(phba, abtsiocbp); @@ -9257,43 +9881,6 @@ abort_iotag_exit: } /** - * lpfc_sli_iocb_ring_abort - Unconditionally abort all iocbs on an iocb ring - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * This function aborts all iocbs in the given ring and frees all the iocb - * objects in txq. This function issues abort iocbs unconditionally for all - * the iocb commands in txcmplq. The iocbs in the txcmplq is not guaranteed - * to complete before the return of this function. The caller is not required - * to hold any locks. - **/ -static void -lpfc_sli_iocb_ring_abort(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ - LIST_HEAD(completions); - struct lpfc_iocbq *iocb, *next_iocb; - - if (pring->ringno == LPFC_ELS_RING) - lpfc_fabric_abort_hba(phba); - - spin_lock_irq(&phba->hbalock); - - /* Take off all the iocbs on txq for cancelling */ - list_splice_init(&pring->txq, &completions); - pring->txq_cnt = 0; - - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_abort_iotag_issue(phba, pring, iocb); - - spin_unlock_irq(&phba->hbalock); - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); -} - -/** * lpfc_sli_hba_iocb_abort - Abort all iocbs to an hba. * @phba: pointer to lpfc HBA data structure. * @@ -9308,7 +9895,7 @@ lpfc_sli_hba_iocb_abort(struct lpfc_hba *phba) for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; - lpfc_sli_iocb_ring_abort(phba, pring); + lpfc_sli_abort_iocb_ring(phba, pring); } } @@ -9430,7 +10017,7 @@ lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3096 ABORT_XRI_CN completing on xri x%x " + "3096 ABORT_XRI_CN completing on rpi x%x " "original iotag x%x, abort cmd iotag x%x " "status 0x%x, reason 0x%x\n", cmdiocb->iocb.un.acxri.abortContextTag, @@ -9480,6 +10067,13 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, abort_cmd) != 0) continue; + /* + * If the iocbq is already being aborted, don't take a second + * action, but do count it. + */ + if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED) + continue; + /* issue ABTS for this IOCB based on iotag */ abtsiocb = lpfc_sli_get_iocbq(phba); if (abtsiocb == NULL) { @@ -9487,6 +10081,9 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, continue; } + /* indicate the IO is being aborted by the driver. */ + iocbq->iocb_flag |= LPFC_DRIVER_ABORTED; + cmd = &iocbq->iocb; abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS; abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext; @@ -9496,7 +10093,7 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag; abtsiocb->iocb.ulpLe = 1; abtsiocb->iocb.ulpClass = cmd->ulpClass; - abtsiocb->vport = phba->pport; + abtsiocb->vport = vport; /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abtsiocb->fcp_wqidx = iocbq->fcp_wqidx; @@ -9523,6 +10120,124 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, } /** + * lpfc_sli_abort_taskmgmt - issue abort for all commands on a host/target/LUN + * @vport: Pointer to virtual port. + * @pring: Pointer to driver SLI ring object. + * @tgt_id: SCSI ID of the target. + * @lun_id: LUN ID of the scsi device. + * @taskmgmt_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST. + * + * This function sends an abort command for every SCSI command + * associated with the given virtual port pending on the ring + * filtered by lpfc_sli_validate_fcp_iocb function. + * When taskmgmt_cmd == LPFC_CTX_LUN, the function sends abort only to the + * FCP iocbs associated with lun specified by tgt_id and lun_id + * parameters + * When taskmgmt_cmd == LPFC_CTX_TGT, the function sends abort only to the + * FCP iocbs associated with SCSI target specified by tgt_id parameter. + * When taskmgmt_cmd == LPFC_CTX_HOST, the function sends abort to all + * FCP iocbs associated with virtual port. + * This function returns number of iocbs it aborted . + * This function is called with no locks held right after a taskmgmt + * command is sent. + **/ +int +lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, + uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd cmd) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *abtsiocbq; + struct lpfc_iocbq *iocbq; + IOCB_t *icmd; + int sum, i, ret_val; + unsigned long iflags; + struct lpfc_sli_ring *pring_s4; + uint32_t ring_number; + + spin_lock_irq(&phba->hbalock); + + /* all I/Os are in process of being flushed */ + if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) { + spin_unlock_irq(&phba->hbalock); + return 0; + } + sum = 0; + + for (i = 1; i <= phba->sli.last_iotag; i++) { + iocbq = phba->sli.iocbq_lookup[i]; + + if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id, + cmd) != 0) + continue; + + /* + * If the iocbq is already being aborted, don't take a second + * action, but do count it. + */ + if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED) + continue; + + /* issue ABTS for this IOCB based on iotag */ + abtsiocbq = __lpfc_sli_get_iocbq(phba); + if (abtsiocbq == NULL) + continue; + + icmd = &iocbq->iocb; + abtsiocbq->iocb.un.acxri.abortType = ABORT_TYPE_ABTS; + abtsiocbq->iocb.un.acxri.abortContextTag = icmd->ulpContext; + if (phba->sli_rev == LPFC_SLI_REV4) + abtsiocbq->iocb.un.acxri.abortIoTag = + iocbq->sli4_xritag; + else + abtsiocbq->iocb.un.acxri.abortIoTag = icmd->ulpIoTag; + abtsiocbq->iocb.ulpLe = 1; + abtsiocbq->iocb.ulpClass = icmd->ulpClass; + abtsiocbq->vport = vport; + + /* ABTS WQE must go to the same WQ as the WQE to be aborted */ + abtsiocbq->fcp_wqidx = iocbq->fcp_wqidx; + if (iocbq->iocb_flag & LPFC_IO_FCP) + abtsiocbq->iocb_flag |= LPFC_USE_FCPWQIDX; + + if (lpfc_is_link_up(phba)) + abtsiocbq->iocb.ulpCommand = CMD_ABORT_XRI_CN; + else + abtsiocbq->iocb.ulpCommand = CMD_CLOSE_XRI_CN; + + /* Setup callback routine and issue the command. */ + abtsiocbq->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; + + /* + * Indicate the IO is being aborted by the driver and set + * the caller's flag into the aborted IO. + */ + iocbq->iocb_flag |= LPFC_DRIVER_ABORTED; + + if (phba->sli_rev == LPFC_SLI_REV4) { + ring_number = MAX_SLI3_CONFIGURED_RINGS + + iocbq->fcp_wqidx; + pring_s4 = &phba->sli.ring[ring_number]; + /* Note: both hbalock and ring_lock must be set here */ + spin_lock_irqsave(&pring_s4->ring_lock, iflags); + ret_val = __lpfc_sli_issue_iocb(phba, pring_s4->ringno, + abtsiocbq, 0); + spin_unlock_irqrestore(&pring_s4->ring_lock, iflags); + } else { + ret_val = __lpfc_sli_issue_iocb(phba, pring->ringno, + abtsiocbq, 0); + } + + + if (ret_val == IOCB_ERROR) + __lpfc_sli_release_iocbq(phba, abtsiocbq); + else + sum++; + } + spin_unlock_irq(&phba->hbalock); + return sum; +} + +/** * lpfc_sli_wake_iocb_wait - lpfc_sli_issue_iocb_wait's completion handler * @phba: Pointer to HBA context object. * @cmdiocbq: Pointer to command iocb. @@ -9549,6 +10264,24 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd; spin_lock_irqsave(&phba->hbalock, iflags); + if (cmdiocbq->iocb_flag & LPFC_IO_WAKE_TMO) { + + /* + * A time out has occurred for the iocb. If a time out + * completion handler has been supplied, call it. Otherwise, + * just free the iocbq. + */ + + spin_unlock_irqrestore(&phba->hbalock, iflags); + cmdiocbq->iocb_cmpl = cmdiocbq->wait_iocb_cmpl; + cmdiocbq->wait_iocb_cmpl = NULL; + if (cmdiocbq->iocb_cmpl) + (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, NULL); + else + lpfc_sli_release_iocbq(phba, cmdiocbq); + return; + } + cmdiocbq->iocb_flag |= LPFC_IO_WAKE; if (cmdiocbq->context2 && rspiocbq) memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, @@ -9604,10 +10337,16 @@ lpfc_chk_iocb_flg(struct lpfc_hba *phba, * @timeout: Timeout in number of seconds. * * This function issues the iocb to firmware and waits for the - * iocb to complete. If the iocb command is not - * completed within timeout seconds, it returns IOCB_TIMEDOUT. - * Caller should not free the iocb resources if this function - * returns IOCB_TIMEDOUT. + * iocb to complete. The iocb_cmpl field of the shall be used + * to handle iocbs which time out. If the field is NULL, the + * function shall free the iocbq structure. If more clean up is + * needed, the caller is expected to provide a completion function + * that will provide the needed clean up. If the iocb command is + * not completed within timeout seconds, the function will either + * free the iocbq structure (if iocb_cmpl == NULL) or execute the + * completion function set in the iocb_cmpl field and then return + * a status of IOCB_TIMEDOUT. The caller should not free the iocb + * resources if this function returns IOCB_TIMEDOUT. * The function waits for the iocb completion using an * non-interruptible wait. * This function will sleep while waiting for iocb completion. @@ -9636,7 +10375,13 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, long timeleft, timeout_req = 0; int retval = IOCB_SUCCESS; uint32_t creg_val; + struct lpfc_iocbq *iocb; + int txq_cnt = 0; + int txcmplq_cnt = 0; struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; + unsigned long iflags; + bool iocb_completed = true; + /* * If the caller has provided a response iocbq buffer, then context2 * is NULL or its an error. @@ -9647,9 +10392,10 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, piocb->context2 = prspiocbq; } + piocb->wait_iocb_cmpl = piocb->iocb_cmpl; piocb->iocb_cmpl = lpfc_sli_wake_iocb_wait; piocb->context_un.wait_queue = &done_q; - piocb->iocb_flag &= ~LPFC_IO_WAKE; + piocb->iocb_flag &= ~(LPFC_IO_WAKE | LPFC_IO_WAKE_TMO); if (phba->cfg_poll & DISABLE_FCP_RING_INT) { if (lpfc_readl(phba->HCregaddr, &creg_val)) @@ -9662,14 +10408,30 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, SLI_IOCB_RET_IOCB); if (retval == IOCB_SUCCESS) { - timeout_req = timeout * HZ; + timeout_req = msecs_to_jiffies(timeout * 1000); timeleft = wait_event_timeout(done_q, lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE), timeout_req); + spin_lock_irqsave(&phba->hbalock, iflags); + if (!(piocb->iocb_flag & LPFC_IO_WAKE)) { - if (piocb->iocb_flag & LPFC_IO_WAKE) { + /* + * IOCB timed out. Inform the wake iocb wait + * completion function and set local status + */ + + iocb_completed = false; + piocb->iocb_flag |= LPFC_IO_WAKE_TMO; + } + spin_unlock_irqrestore(&phba->hbalock, iflags); + if (iocb_completed) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "0331 IOCB wake signaled\n"); + /* Note: we are not indicating if the IOCB has a success + * status or not - that's for the caller to check. + * IOCB_SUCCESS means just that the command was sent and + * completed. Not that it completed successfully. + * */ } else if (timeleft == 0) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0338 IOCB wait timeout error - no " @@ -9683,9 +10445,17 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, retval = IOCB_TIMEDOUT; } } else if (retval == IOCB_BUSY) { - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2818 Max IOCBs %d txq cnt %d txcmplq cnt %d\n", - phba->iocb_cnt, pring->txq_cnt, pring->txcmplq_cnt); + if (phba->cfg_log_verbose & LOG_SLI) { + list_for_each_entry(iocb, &pring->txq, list) { + txq_cnt++; + } + list_for_each_entry(iocb, &pring->txcmplq, list) { + txcmplq_cnt++; + } + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2818 Max IOCBs %d txq cnt %d txcmplq cnt %d\n", + phba->iocb_cnt, txq_cnt, txcmplq_cnt); + } return retval; } else { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, @@ -9741,12 +10511,13 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, uint32_t timeout) { DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q); + MAILBOX_t *mb = NULL; int retval; unsigned long flag; - /* The caller must leave context1 empty. */ + /* The caller might set context1 for extended buffer */ if (pmboxq->context1) - return MBX_NOT_FINISHED; + mb = (MAILBOX_t *)pmboxq->context1; pmboxq->mbox_flag &= ~LPFC_MBX_WAKE; /* setup wake call as IOCB callback */ @@ -9759,22 +10530,25 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, if (retval == MBX_BUSY || retval == MBX_SUCCESS) { wait_event_interruptible_timeout(done_q, pmboxq->mbox_flag & LPFC_MBX_WAKE, - timeout * HZ); + msecs_to_jiffies(timeout * 1000)); spin_lock_irqsave(&phba->hbalock, flag); - pmboxq->context1 = NULL; + /* restore the possible extended buffer for free resource */ + pmboxq->context1 = (uint8_t *)mb; /* * if LPFC_MBX_WAKE flag is set the mailbox is completed * else do not free the resources. */ if (pmboxq->mbox_flag & LPFC_MBX_WAKE) { retval = MBX_SUCCESS; - lpfc_sli4_swap_str(phba, pmboxq); } else { retval = MBX_TIMEOUT; pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; } spin_unlock_irqrestore(&phba->hbalock, flag); + } else { + /* restore the possible extended buffer for free resource */ + pmboxq->context1 = (uint8_t *)mb; } return retval; @@ -9796,18 +10570,23 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, * sub-system flush routine to gracefully bring down mailbox sub-system. **/ void -lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba) +lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action) { struct lpfc_sli *psli = &phba->sli; unsigned long timeout; + if (mbx_action == LPFC_MBX_NO_WAIT) { + /* delay 100ms for port state */ + msleep(100); + lpfc_sli_mbox_sys_flush(phba); + return; + } timeout = msecs_to_jiffies(LPFC_MBOX_TMO * 1000) + jiffies; + spin_lock_irq(&phba->hbalock); psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK; - spin_unlock_irq(&phba->hbalock); if (psli->sli_flag & LPFC_SLI_ACTIVE) { - spin_lock_irq(&phba->hbalock); /* Determine how long we might wait for the active mailbox * command to be gracefully completed by firmware. */ @@ -9826,7 +10605,9 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba) */ break; } - } + } else + spin_unlock_irq(&phba->hbalock); + lpfc_sli_mbox_sys_flush(phba); } @@ -10652,13 +11433,18 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbOut, struct lpfc_wcqe_complete *wcqe) { + int numBdes, i; unsigned long iflags; + uint32_t status, max_response; + struct lpfc_dmabuf *dmabuf; + struct ulp_bde64 *bpl, bde; size_t offset = offsetof(struct lpfc_iocbq, iocb); memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset, sizeof(struct lpfc_iocbq) - offset); /* Map WCQE parameters into irspiocb parameters */ - pIocbIn->iocb.ulpStatus = bf_get(lpfc_wcqe_c_status, wcqe); + status = bf_get(lpfc_wcqe_c_status, wcqe); + pIocbIn->iocb.ulpStatus = (status & LPFC_IOCB_STATUS_MASK); if (pIocbOut->iocb_flag & LPFC_IO_FCP) if (pIocbIn->iocb.ulpStatus == IOSTAT_FCP_RSP_ERROR) pIocbIn->iocb.un.fcpi.fcpi_parm = @@ -10668,7 +11454,74 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba, pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; else { pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; - pIocbIn->iocb.un.genreq64.bdl.bdeSize = wcqe->total_data_placed; + switch (pIocbOut->iocb.ulpCommand) { + case CMD_ELS_REQUEST64_CR: + dmabuf = (struct lpfc_dmabuf *)pIocbOut->context3; + bpl = (struct ulp_bde64 *)dmabuf->virt; + bde.tus.w = le32_to_cpu(bpl[1].tus.w); + max_response = bde.tus.f.bdeSize; + break; + case CMD_GEN_REQUEST64_CR: + max_response = 0; + if (!pIocbOut->context3) + break; + numBdes = pIocbOut->iocb.un.genreq64.bdl.bdeSize/ + sizeof(struct ulp_bde64); + dmabuf = (struct lpfc_dmabuf *)pIocbOut->context3; + bpl = (struct ulp_bde64 *)dmabuf->virt; + for (i = 0; i < numBdes; i++) { + bde.tus.w = le32_to_cpu(bpl[i].tus.w); + if (bde.tus.f.bdeFlags != BUFF_TYPE_BDE_64) + max_response += bde.tus.f.bdeSize; + } + break; + default: + max_response = wcqe->total_data_placed; + break; + } + if (max_response < wcqe->total_data_placed) + pIocbIn->iocb.un.genreq64.bdl.bdeSize = max_response; + else + pIocbIn->iocb.un.genreq64.bdl.bdeSize = + wcqe->total_data_placed; + } + + /* Convert BG errors for completion status */ + if (status == CQE_STATUS_DI_ERROR) { + pIocbIn->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; + + if (bf_get(lpfc_wcqe_c_bg_edir, wcqe)) + pIocbIn->iocb.un.ulpWord[4] = IOERR_RX_DMA_FAILED; + else + pIocbIn->iocb.un.ulpWord[4] = IOERR_TX_DMA_FAILED; + + pIocbIn->iocb.unsli3.sli3_bg.bgstat = 0; + if (bf_get(lpfc_wcqe_c_bg_ge, wcqe)) /* Guard Check failed */ + pIocbIn->iocb.unsli3.sli3_bg.bgstat |= + BGS_GUARD_ERR_MASK; + if (bf_get(lpfc_wcqe_c_bg_ae, wcqe)) /* App Tag Check failed */ + pIocbIn->iocb.unsli3.sli3_bg.bgstat |= + BGS_APPTAG_ERR_MASK; + if (bf_get(lpfc_wcqe_c_bg_re, wcqe)) /* Ref Tag Check failed */ + pIocbIn->iocb.unsli3.sli3_bg.bgstat |= + BGS_REFTAG_ERR_MASK; + + /* Check to see if there was any good data before the error */ + if (bf_get(lpfc_wcqe_c_bg_tdpv, wcqe)) { + pIocbIn->iocb.unsli3.sli3_bg.bgstat |= + BGS_HI_WATER_MARK_PRESENT_MASK; + pIocbIn->iocb.unsli3.sli3_bg.bghm = + wcqe->total_data_placed; + } + + /* + * Set ALL the error bits to indicate we don't know what + * type of error it is. + */ + if (!pIocbIn->iocb.unsli3.sli3_bg.bgstat) + pIocbIn->iocb.unsli3.sli3_bg.bgstat |= + (BGS_REFTAG_ERR_MASK | BGS_APPTAG_ERR_MASK | + BGS_GUARD_ERR_MASK); } /* Pick up HBA exchange busy condition */ @@ -10700,12 +11553,12 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, unsigned long iflags; wcqe = &irspiocbq->cq_event.cqe.wcqe_cmpl; - spin_lock_irqsave(&phba->hbalock, iflags); + spin_lock_irqsave(&pring->ring_lock, iflags); pring->stats.iocb_event++; /* Look up the ELS command IOCB and create pseudo response IOCB */ cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, bf_get(lpfc_wcqe_c_request_tag, wcqe)); - spin_unlock_irqrestore(&phba->hbalock, iflags); + spin_unlock_irqrestore(&pring->ring_lock, iflags); if (unlikely(!cmdiocbq)) { lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, @@ -10907,6 +11760,7 @@ lpfc_sli4_sp_handle_mcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe) /** * lpfc_sli4_sp_handle_els_wcqe - Handle els work-queue completion event * @phba: Pointer to HBA context object. + * @cq: Pointer to associated CQ * @wcqe: Pointer to work-queue completion queue entry. * * This routine handles an ELS work-queue completion event. @@ -10914,22 +11768,31 @@ lpfc_sli4_sp_handle_mcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe) * Return: true if work posted to worker thread, otherwise false. **/ static bool -lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, +lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, struct lpfc_wcqe_complete *wcqe) { struct lpfc_iocbq *irspiocbq; unsigned long iflags; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING]; + struct lpfc_sli_ring *pring = cq->pring; + int txq_cnt = 0; + int txcmplq_cnt = 0; + int fcp_txcmplq_cnt = 0; /* Get an irspiocbq for later ELS response processing use */ irspiocbq = lpfc_sli_get_iocbq(phba); if (!irspiocbq) { + if (!list_empty(&pring->txq)) + txq_cnt++; + if (!list_empty(&pring->txcmplq)) + txcmplq_cnt++; + if (!list_empty(&phba->sli.ring[LPFC_FCP_RING].txcmplq)) + fcp_txcmplq_cnt++; lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d " "fcp_txcmplq_cnt=%d, els_txcmplq_cnt=%d\n", - pring->txq_cnt, phba->iocb_cnt, - phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt, - phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt); + txq_cnt, phba->iocb_cnt, + fcp_txcmplq_cnt, + txcmplq_cnt); return false; } @@ -11064,14 +11927,17 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) case FC_STATUS_RQ_BUF_LEN_EXCEEDED: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2537 Receive Frame Truncated!!\n"); + hrq->RQ_buf_trunc++; case FC_STATUS_RQ_SUCCESS: lpfc_sli4_rq_release(hrq, drq); spin_lock_irqsave(&phba->hbalock, iflags); dma_buf = lpfc_sli_hbqbuf_get(&phba->hbqs[0].hbq_buffer_list); if (!dma_buf) { + hrq->RQ_no_buf_found++; spin_unlock_irqrestore(&phba->hbalock, iflags); goto out; } + hrq->RQ_rcv_buf++; memcpy(&dma_buf->cq_event.cqe.rcqe_cmpl, rcqe, sizeof(*rcqe)); /* save off the frame for the word thread to process */ list_add_tail(&dma_buf->cq_event.list, @@ -11083,6 +11949,7 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) break; case FC_STATUS_INSUFF_BUF_NEED_BUF: case FC_STATUS_INSUFF_BUF_FRM_DISC: + hrq->RQ_no_posted_buf++; /* Post more buffers if possible */ spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag |= HBA_POST_RECEIVE_BUFFER; @@ -11120,7 +11987,7 @@ lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, case CQE_CODE_COMPL_WQE: /* Process the WQ/RQ complete event */ phba->last_completion_time = jiffies; - workposted = lpfc_sli4_sp_handle_els_wcqe(phba, + workposted = lpfc_sli4_sp_handle_els_wcqe(phba, cq, (struct lpfc_wcqe_complete *)&cqevt); break; case CQE_CODE_RELEASE_WQE: @@ -11164,31 +12031,18 @@ lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, * **/ static void -lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) +lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, + struct lpfc_queue *speq) { - struct lpfc_queue *cq = NULL, *childq, *speq; + struct lpfc_queue *cq = NULL, *childq; struct lpfc_cqe *cqe; bool workposted = false; int ecount = 0; uint16_t cqid; - if (bf_get_le32(lpfc_eqe_major_code, eqe) != 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0359 Not a valid slow-path completion " - "event: majorcode=x%x, minorcode=x%x\n", - bf_get_le32(lpfc_eqe_major_code, eqe), - bf_get_le32(lpfc_eqe_minor_code, eqe)); - return; - } - /* Get the reference to the corresponding CQ */ cqid = bf_get_le32(lpfc_eqe_resource_id, eqe); - /* Search for completion queue pointer matching this cqid */ - speq = phba->sli4_hba.sp_eq; - /* sanity check on queue memory */ - if (unlikely(!speq)) - return; list_for_each_entry(childq, &speq->child_list, list) { if (childq->queue_id == cqid) { cq = childq; @@ -11210,6 +12064,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) workposted |= lpfc_sli4_sp_handle_mcqe(phba, cqe); if (!(++ecount % cq->entry_repost)) lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); + cq->CQ_mbox++; } break; case LPFC_WCQ: @@ -11223,6 +12078,10 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) if (!(++ecount % cq->entry_repost)) lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); } + + /* Track the max number of CQEs processed in 1 EQ */ + if (ecount > cq->CQ_max_cqe) + cq->CQ_max_cqe = ecount; break; default: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -11247,34 +12106,33 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) /** * lpfc_sli4_fp_handle_fcp_wcqe - Process fast-path work queue completion entry - * @eqe: Pointer to fast-path completion queue entry. + * @phba: Pointer to HBA context object. + * @cq: Pointer to associated CQ + * @wcqe: Pointer to work-queue completion queue entry. * * This routine process a fast-path work queue completion entry from fast-path * event queue for FCP command response completion. **/ static void -lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, +lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, struct lpfc_wcqe_complete *wcqe) { - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING]; + struct lpfc_sli_ring *pring = cq->pring; struct lpfc_iocbq *cmdiocbq; struct lpfc_iocbq irspiocbq; unsigned long iflags; - spin_lock_irqsave(&phba->hbalock, iflags); - pring->stats.iocb_event++; - spin_unlock_irqrestore(&phba->hbalock, iflags); - /* Check for response status */ if (unlikely(bf_get(lpfc_wcqe_c_status, wcqe))) { /* If resource errors reported from HBA, reduce queue * depth of the SCSI device. */ - if ((bf_get(lpfc_wcqe_c_status, wcqe) == - IOSTAT_LOCAL_REJECT) && - (wcqe->parameter == IOERR_NO_RESOURCES)) { + if (((bf_get(lpfc_wcqe_c_status, wcqe) == + IOSTAT_LOCAL_REJECT)) && + ((wcqe->parameter & IOERR_PARAM_MASK) == + IOERR_NO_RESOURCES)) phba->lpfc_rampdown_queue_depth(phba); - } + /* Log the error status */ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0373 FCP complete error: status=x%x, " @@ -11287,10 +12145,11 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, } /* Look up the FCP command IOCB and create pseudo response IOCB */ - spin_lock_irqsave(&phba->hbalock, iflags); + spin_lock_irqsave(&pring->ring_lock, iflags); + pring->stats.iocb_event++; cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, bf_get(lpfc_wcqe_c_request_tag, wcqe)); - spin_unlock_irqrestore(&phba->hbalock, iflags); + spin_unlock_irqrestore(&pring->ring_lock, iflags); if (unlikely(!cmdiocbq)) { lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0374 FCP complete with no corresponding " @@ -11374,17 +12233,20 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, /* Check and process for different type of WCQE and dispatch */ switch (bf_get(lpfc_wcqe_c_code, &wcqe)) { case CQE_CODE_COMPL_WQE: + cq->CQ_wq++; /* Process the WQ complete event */ phba->last_completion_time = jiffies; - lpfc_sli4_fp_handle_fcp_wcqe(phba, + lpfc_sli4_fp_handle_fcp_wcqe(phba, cq, (struct lpfc_wcqe_complete *)&wcqe); break; case CQE_CODE_RELEASE_WQE: + cq->CQ_release_wqe++; /* Process the WQ release event */ lpfc_sli4_fp_handle_rel_wcqe(phba, cq, (struct lpfc_wcqe_release *)&wcqe); break; case CQE_CODE_XRI_ABORTED: + cq->CQ_xri_aborted++; /* Process the WQ XRI abort event */ phba->last_completion_time = jiffies; workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq, @@ -11400,7 +12262,7 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, } /** - * lpfc_sli4_fp_handle_eqe - Process a fast-path event queue entry + * lpfc_sli4_hba_handle_eqe - Process a fast-path event queue entry * @phba: Pointer to HBA context object. * @eqe: Pointer to fast-path event queue entry. * @@ -11412,8 +12274,8 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, * completion queue, and then return. **/ static void -lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, - uint32_t fcp_cqidx) +lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, + uint32_t qidx) { struct lpfc_queue *cq; struct lpfc_cqe *cqe; @@ -11423,30 +12285,38 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0366 Not a valid fast-path completion " + "0366 Not a valid completion " "event: majorcode=x%x, minorcode=x%x\n", bf_get_le32(lpfc_eqe_major_code, eqe), bf_get_le32(lpfc_eqe_minor_code, eqe)); return; } + /* Get the reference to the corresponding CQ */ + cqid = bf_get_le32(lpfc_eqe_resource_id, eqe); + + /* Check if this is a Slow path event */ + if (unlikely(cqid != phba->sli4_hba.fcp_cq_map[qidx])) { + lpfc_sli4_sp_handle_eqe(phba, eqe, + phba->sli4_hba.hba_eq[qidx]); + return; + } + if (unlikely(!phba->sli4_hba.fcp_cq)) { lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "3146 Fast-path completion queues " "does not exist\n"); return; } - cq = phba->sli4_hba.fcp_cq[fcp_cqidx]; + cq = phba->sli4_hba.fcp_cq[qidx]; if (unlikely(!cq)) { if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0367 Fast-path completion queue " - "(%d) does not exist\n", fcp_cqidx); + "(%d) does not exist\n", qidx); return; } - /* Get the reference to the corresponding CQ */ - cqid = bf_get_le32(lpfc_eqe_resource_id, eqe); if (unlikely(cqid != cq->queue_id)) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0368 Miss-matched fast-path completion " @@ -11462,6 +12332,10 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); } + /* Track the max number of CQEs processed in 1 EQ */ + if (ecount > cq->CQ_max_cqe) + cq->CQ_max_cqe = ecount; + /* Catch the no cq entry condition */ if (unlikely(ecount == 0)) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -11489,87 +12363,177 @@ lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq) lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM); } + +/** + * lpfc_sli4_fof_handle_eqe - Process a Flash Optimized Fabric event queue + * entry + * @phba: Pointer to HBA context object. + * @eqe: Pointer to fast-path event queue entry. + * + * This routine process a event queue entry from the Flash Optimized Fabric + * event queue. It will check the MajorCode and MinorCode to determine this + * is for a completion event on a completion queue, if not, an error shall be + * logged and just return. Otherwise, it will get to the corresponding + * completion queue and process all the entries on the completion queue, rearm + * the completion queue, and then return. + **/ +static void +lpfc_sli4_fof_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) +{ + struct lpfc_queue *cq; + struct lpfc_cqe *cqe; + bool workposted = false; + uint16_t cqid; + int ecount = 0; + + if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "9147 Not a valid completion " + "event: majorcode=x%x, minorcode=x%x\n", + bf_get_le32(lpfc_eqe_major_code, eqe), + bf_get_le32(lpfc_eqe_minor_code, eqe)); + return; + } + + /* Get the reference to the corresponding CQ */ + cqid = bf_get_le32(lpfc_eqe_resource_id, eqe); + + /* Next check for OAS */ + cq = phba->sli4_hba.oas_cq; + if (unlikely(!cq)) { + if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "9148 OAS completion queue " + "does not exist\n"); + return; + } + + if (unlikely(cqid != cq->queue_id)) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "9149 Miss-matched fast-path compl " + "queue id: eqcqid=%d, fcpcqid=%d\n", + cqid, cq->queue_id); + return; + } + + /* Process all the entries to the OAS CQ */ + while ((cqe = lpfc_sli4_cq_get(cq))) { + workposted |= lpfc_sli4_fp_handle_wcqe(phba, cq, cqe); + if (!(++ecount % cq->entry_repost)) + lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); + } + + /* Track the max number of CQEs processed in 1 EQ */ + if (ecount > cq->CQ_max_cqe) + cq->CQ_max_cqe = ecount; + + /* Catch the no cq entry condition */ + if (unlikely(ecount == 0)) + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "9153 No entry from fast-path completion " + "queue fcpcqid=%d\n", cq->queue_id); + + /* In any case, flash and re-arm the CQ */ + lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM); + + /* wake up worker thread if there are works to be done */ + if (workposted) + lpfc_worker_wake_up(phba); +} + /** - * lpfc_sli4_sp_intr_handler - Slow-path interrupt handler to SLI-4 device + * lpfc_sli4_fof_intr_handler - HBA interrupt handler to SLI-4 device * @irq: Interrupt number. * @dev_id: The device context pointer. * * This function is directly called from the PCI layer as an interrupt * service routine when device with SLI-4 interface spec is enabled with - * MSI-X multi-message interrupt mode and there are slow-path events in - * the HBA. However, when the device is enabled with either MSI or Pin-IRQ - * interrupt mode, this function is called as part of the device-level - * interrupt handler. When the PCI slot is in error recovery or the HBA is - * undergoing initialization, the interrupt handler will not process the - * interrupt. The link attention and ELS ring attention events are handled - * by the worker thread. The interrupt handler signals the worker thread - * and returns for these events. This function is called without any lock - * held. It gets the hbalock to access and update SLI data structures. + * MSI-X multi-message interrupt mode and there is a Flash Optimized Fabric + * IOCB ring event in the HBA. However, when the device is enabled with either + * MSI or Pin-IRQ interrupt mode, this function is called as part of the + * device-level interrupt handler. When the PCI slot is in error recovery + * or the HBA is undergoing initialization, the interrupt handler will not + * process the interrupt. The Flash Optimized Fabric ring event are handled in + * the intrrupt context. This function is called without any lock held. + * It gets the hbalock to access and update SLI data structures. Note that, + * the EQ to CQ are one-to-one map such that the EQ index is + * equal to that of CQ index. * * This function returns IRQ_HANDLED when interrupt is handled else it * returns IRQ_NONE. **/ irqreturn_t -lpfc_sli4_sp_intr_handler(int irq, void *dev_id) +lpfc_sli4_fof_intr_handler(int irq, void *dev_id) { struct lpfc_hba *phba; - struct lpfc_queue *speq; + struct lpfc_fcp_eq_hdl *fcp_eq_hdl; + struct lpfc_queue *eq; struct lpfc_eqe *eqe; unsigned long iflag; int ecount = 0; + uint32_t eqidx; - /* - * Get the driver's phba structure from the dev_id - */ - phba = (struct lpfc_hba *)dev_id; + /* Get the driver's phba structure from the dev_id */ + fcp_eq_hdl = (struct lpfc_fcp_eq_hdl *)dev_id; + phba = fcp_eq_hdl->phba; + eqidx = fcp_eq_hdl->idx; if (unlikely(!phba)) return IRQ_NONE; /* Get to the EQ struct associated with this vector */ - speq = phba->sli4_hba.sp_eq; - if (unlikely(!speq)) + eq = phba->sli4_hba.fof_eq; + if (unlikely(!eq)) return IRQ_NONE; /* Check device state for handling interrupt */ if (unlikely(lpfc_intr_state_check(phba))) { + eq->EQ_badstate++; /* Check again for link_state with lock held */ spin_lock_irqsave(&phba->hbalock, iflag); if (phba->link_state < LPFC_LINK_DOWN) /* Flush, clear interrupt, and rearm the EQ */ - lpfc_sli4_eq_flush(phba, speq); + lpfc_sli4_eq_flush(phba, eq); spin_unlock_irqrestore(&phba->hbalock, iflag); return IRQ_NONE; } /* - * Process all the event on FCP slow-path EQ + * Process all the event on FCP fast-path EQ */ - while ((eqe = lpfc_sli4_eq_get(speq))) { - lpfc_sli4_sp_handle_eqe(phba, eqe); - if (!(++ecount % speq->entry_repost)) - lpfc_sli4_eq_release(speq, LPFC_QUEUE_NOARM); + while ((eqe = lpfc_sli4_eq_get(eq))) { + lpfc_sli4_fof_handle_eqe(phba, eqe); + if (!(++ecount % eq->entry_repost)) + lpfc_sli4_eq_release(eq, LPFC_QUEUE_NOARM); + eq->EQ_processed++; } - /* Always clear and re-arm the slow-path EQ */ - lpfc_sli4_eq_release(speq, LPFC_QUEUE_REARM); + /* Track the max number of EQEs processed in 1 intr */ + if (ecount > eq->EQ_max_eqe) + eq->EQ_max_eqe = ecount; + - /* Catch the no cq entry condition */ if (unlikely(ecount == 0)) { + eq->EQ_no_entry++; + if (phba->intr_type == MSIX) /* MSI-X treated interrupt served as no EQ share INT */ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0357 MSI-X interrupt with no EQE\n"); - else + "9145 MSI-X interrupt with no EQE\n"); + else { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "9146 ISR interrupt with no EQE\n"); /* Non MSI-X treated on interrupt as EQ share INT */ return IRQ_NONE; + } } - + /* Always clear and re-arm the fast-path EQ */ + lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM); return IRQ_HANDLED; -} /* lpfc_sli4_sp_intr_handler */ +} /** - * lpfc_sli4_fp_intr_handler - Fast-path interrupt handler to SLI-4 device + * lpfc_sli4_hba_intr_handler - HBA interrupt handler to SLI-4 device * @irq: Interrupt number. * @dev_id: The device context pointer. * @@ -11586,11 +12550,16 @@ lpfc_sli4_sp_intr_handler(int irq, void *dev_id) * the FCP EQ to FCP CQ are one-to-one map such that the FCP EQ index is * equal to that of FCP CQ index. * + * The link attention and ELS ring attention events are handled + * by the worker thread. The interrupt handler signals the worker thread + * and returns for these events. This function is called without any lock + * held. It gets the hbalock to access and update SLI data structures. + * * This function returns IRQ_HANDLED when interrupt is handled else it * returns IRQ_NONE. **/ irqreturn_t -lpfc_sli4_fp_intr_handler(int irq, void *dev_id) +lpfc_sli4_hba_intr_handler(int irq, void *dev_id) { struct lpfc_hba *phba; struct lpfc_fcp_eq_hdl *fcp_eq_hdl; @@ -11598,7 +12567,7 @@ lpfc_sli4_fp_intr_handler(int irq, void *dev_id) struct lpfc_eqe *eqe; unsigned long iflag; int ecount = 0; - uint32_t fcp_eqidx; + int fcp_eqidx; /* Get the driver's phba structure from the dev_id */ fcp_eq_hdl = (struct lpfc_fcp_eq_hdl *)dev_id; @@ -11607,22 +12576,34 @@ lpfc_sli4_fp_intr_handler(int irq, void *dev_id) if (unlikely(!phba)) return IRQ_NONE; - if (unlikely(!phba->sli4_hba.fp_eq)) + if (unlikely(!phba->sli4_hba.hba_eq)) return IRQ_NONE; /* Get to the EQ struct associated with this vector */ - fpeq = phba->sli4_hba.fp_eq[fcp_eqidx]; + fpeq = phba->sli4_hba.hba_eq[fcp_eqidx]; if (unlikely(!fpeq)) return IRQ_NONE; + if (lpfc_fcp_look_ahead) { + if (atomic_dec_and_test(&fcp_eq_hdl->fcp_eq_in_use)) + lpfc_sli4_eq_clr_intr(fpeq); + else { + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); + return IRQ_NONE; + } + } + /* Check device state for handling interrupt */ if (unlikely(lpfc_intr_state_check(phba))) { + fpeq->EQ_badstate++; /* Check again for link_state with lock held */ spin_lock_irqsave(&phba->hbalock, iflag); if (phba->link_state < LPFC_LINK_DOWN) /* Flush, clear interrupt, and rearm the EQ */ lpfc_sli4_eq_flush(phba, fpeq); spin_unlock_irqrestore(&phba->hbalock, iflag); + if (lpfc_fcp_look_ahead) + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); return IRQ_NONE; } @@ -11630,15 +12611,27 @@ lpfc_sli4_fp_intr_handler(int irq, void *dev_id) * Process all the event on FCP fast-path EQ */ while ((eqe = lpfc_sli4_eq_get(fpeq))) { - lpfc_sli4_fp_handle_eqe(phba, eqe, fcp_eqidx); + lpfc_sli4_hba_handle_eqe(phba, eqe, fcp_eqidx); if (!(++ecount % fpeq->entry_repost)) lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_NOARM); + fpeq->EQ_processed++; } + /* Track the max number of EQEs processed in 1 intr */ + if (ecount > fpeq->EQ_max_eqe) + fpeq->EQ_max_eqe = ecount; + /* Always clear and re-arm the fast-path EQ */ lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM); if (unlikely(ecount == 0)) { + fpeq->EQ_no_entry++; + + if (lpfc_fcp_look_ahead) { + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); + return IRQ_NONE; + } + if (phba->intr_type == MSIX) /* MSI-X treated interrupt served as no EQ share INT */ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, @@ -11648,6 +12641,8 @@ lpfc_sli4_fp_intr_handler(int irq, void *dev_id) return IRQ_NONE; } + if (lpfc_fcp_look_ahead) + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); return IRQ_HANDLED; } /* lpfc_sli4_fp_intr_handler */ @@ -11672,9 +12667,9 @@ irqreturn_t lpfc_sli4_intr_handler(int irq, void *dev_id) { struct lpfc_hba *phba; - irqreturn_t sp_irq_rc, fp_irq_rc; - bool fp_handled = false; - uint32_t fcp_eqidx; + irqreturn_t hba_irq_rc; + bool hba_handled = false; + int fcp_eqidx; /* Get the driver's phba structure from the dev_id */ phba = (struct lpfc_hba *)dev_id; @@ -11683,21 +12678,23 @@ lpfc_sli4_intr_handler(int irq, void *dev_id) return IRQ_NONE; /* - * Invokes slow-path host attention interrupt handling as appropriate. - */ - sp_irq_rc = lpfc_sli4_sp_intr_handler(irq, dev_id); - - /* * Invoke fast-path host attention interrupt handling as appropriate. */ - for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) { - fp_irq_rc = lpfc_sli4_fp_intr_handler(irq, + for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_io_channel; fcp_eqidx++) { + hba_irq_rc = lpfc_sli4_hba_intr_handler(irq, &phba->sli4_hba.fcp_eq_hdl[fcp_eqidx]); - if (fp_irq_rc == IRQ_HANDLED) - fp_handled |= true; + if (hba_irq_rc == IRQ_HANDLED) + hba_handled |= true; + } + + if (phba->cfg_fof) { + hba_irq_rc = lpfc_sli4_fof_intr_handler(irq, + &phba->sli4_hba.fcp_eq_hdl[0]); + if (hba_irq_rc == IRQ_HANDLED) + hba_handled |= true; } - return (fp_handled == true) ? IRQ_HANDLED : sp_irq_rc; + return (hba_handled == true) ? IRQ_HANDLED : IRQ_NONE; } /* lpfc_sli4_intr_handler */ /** @@ -11801,6 +12798,120 @@ out_fail: } /** + * lpfc_dual_chute_pci_bar_map - Map pci base address register to host memory + * @phba: HBA structure that indicates port to create a queue on. + * @pci_barset: PCI BAR set flag. + * + * This function shall perform iomap of the specified PCI BAR address to host + * memory address if not already done so and return it. The returned host + * memory address can be NULL. + */ +static void __iomem * +lpfc_dual_chute_pci_bar_map(struct lpfc_hba *phba, uint16_t pci_barset) +{ + struct pci_dev *pdev; + + if (!phba->pcidev) + return NULL; + else + pdev = phba->pcidev; + + switch (pci_barset) { + case WQ_PCI_BAR_0_AND_1: + return phba->pci_bar0_memmap_p; + case WQ_PCI_BAR_2_AND_3: + return phba->pci_bar2_memmap_p; + case WQ_PCI_BAR_4_AND_5: + return phba->pci_bar4_memmap_p; + default: + break; + } + return NULL; +} + +/** + * lpfc_modify_fcp_eq_delay - Modify Delay Multiplier on FCP EQs + * @phba: HBA structure that indicates port to create a queue on. + * @startq: The starting FCP EQ to modify + * + * This function sends an MODIFY_EQ_DELAY mailbox command to the HBA. + * + * The @phba struct is used to send mailbox command to HBA. The @startq + * is used to get the starting FCP EQ to change. + * This function is asynchronous and will wait for the mailbox + * command to finish before continuing. + * + * On success this function will return a zero. If unable to allocate enough + * memory this function will return -ENOMEM. If the queue create mailbox command + * fails this function will return -ENXIO. + **/ +uint32_t +lpfc_modify_fcp_eq_delay(struct lpfc_hba *phba, uint16_t startq) +{ + struct lpfc_mbx_modify_eq_delay *eq_delay; + LPFC_MBOXQ_t *mbox; + struct lpfc_queue *eq; + int cnt, rc, length, status = 0; + uint32_t shdr_status, shdr_add_status; + uint32_t result; + int fcp_eqidx; + union lpfc_sli4_cfg_shdr *shdr; + uint16_t dmult; + + if (startq >= phba->cfg_fcp_io_channel) + return 0; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_modify_eq_delay) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_MODIFY_EQ_DELAY, + length, LPFC_SLI4_MBX_EMBED); + eq_delay = &mbox->u.mqe.un.eq_delay; + + /* Calculate delay multiper from maximum interrupt per second */ + result = phba->cfg_fcp_imax / phba->cfg_fcp_io_channel; + if (result > LPFC_DMULT_CONST) + dmult = 0; + else + dmult = LPFC_DMULT_CONST/result - 1; + + cnt = 0; + for (fcp_eqidx = startq; fcp_eqidx < phba->cfg_fcp_io_channel; + fcp_eqidx++) { + eq = phba->sli4_hba.hba_eq[fcp_eqidx]; + if (!eq) + continue; + eq_delay->u.request.eq[cnt].eq_id = eq->queue_id; + eq_delay->u.request.eq[cnt].phase = 0; + eq_delay->u.request.eq[cnt].delay_multi = dmult; + cnt++; + if (cnt >= LPFC_MAX_EQ_DELAY) + break; + } + eq_delay->u.request.num_eq = cnt; + + mbox->vport = phba->pport; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->context1 = NULL; + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + shdr = (union lpfc_sli4_cfg_shdr *) &eq_delay->header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2512 MODIFY_EQ_DELAY mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + status = -ENXIO; + } + mempool_free(mbox, phba->mbox_mem_pool); + return status; +} + +/** * lpfc_eq_create - Create an Event Queue on the HBA * @phba: HBA structure that indicates port to create a queue on. * @eq: The queue structure to use to create the event queue. @@ -11821,7 +12932,7 @@ out_fail: * fails this function will return -ENXIO. **/ uint32_t -lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax) +lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) { struct lpfc_mbx_eq_create *eq_create; LPFC_MBOXQ_t *mbox; @@ -11853,7 +12964,10 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax) LPFC_EQE_SIZE); bf_set(lpfc_eq_context_valid, &eq_create->u.request.context, 1); /* Calculate delay multiper from maximum interrupt per second */ - dmult = LPFC_DMULT_CONST/imax - 1; + if (imax > LPFC_DMULT_CONST) + dmult = 0; + else + dmult = LPFC_DMULT_CONST/imax - 1; bf_set(lpfc_eq_context_delay_multi, &eq_create->u.request.context, dmult); switch (eq->entry_count) { @@ -11987,8 +13101,10 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0361 Unsupported CQ count. (%d)\n", cq->entry_count); - if (cq->entry_count < 256) - return -EINVAL; + if (cq->entry_count < 256) { + status = -EINVAL; + goto out; + } /* otherwise default to smallest count (drop through) */ case 256: bf_set(lpfc_cq_context_count, &cq_create->u.request.context, @@ -12179,8 +13295,10 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0362 Unsupported MQ count. (%d)\n", mq->entry_count); - if (mq->entry_count < 16) - return -EINVAL; + if (mq->entry_count < 16) { + status = -EINVAL; + goto out; + } /* otherwise default to smallest count (drop through) */ case 16: bf_set(lpfc_mq_context_ring_size, @@ -12288,6 +13406,9 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, union lpfc_sli4_cfg_shdr *shdr; uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; struct dma_address *page; + void __iomem *bar_memmap_p; + uint32_t db_offset; + uint16_t pci_barset; /* sanity check on queue memory */ if (!wq || !cq) @@ -12309,9 +13430,44 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, wq->page_count); bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request, cq->queue_id); + + /* wqv is the earliest version supported, NOT the latest */ bf_set(lpfc_mbox_hdr_version, &shdr->request, phba->sli4_hba.pc_sli4_params.wqv); - if (phba->sli4_hba.pc_sli4_params.wqv == LPFC_Q_CREATE_VERSION_1) { + + switch (phba->sli4_hba.pc_sli4_params.wqv) { + case LPFC_Q_CREATE_VERSION_0: + switch (wq->entry_size) { + default: + case 64: + /* Nothing to do, version 0 ONLY supports 64 byte */ + page = wq_create->u.request.page; + break; + case 128: + if (!(phba->sli4_hba.pc_sli4_params.wqsize & + LPFC_WQ_SZ128_SUPPORT)) { + status = -ERANGE; + goto out; + } + /* If we get here the HBA MUST also support V1 and + * we MUST use it + */ + bf_set(lpfc_mbox_hdr_version, &shdr->request, + LPFC_Q_CREATE_VERSION_1); + + bf_set(lpfc_mbx_wq_create_wqe_count, + &wq_create->u.request_1, wq->entry_count); + bf_set(lpfc_mbx_wq_create_wqe_size, + &wq_create->u.request_1, + LPFC_WQ_WQE_SIZE_128); + bf_set(lpfc_mbx_wq_create_page_size, + &wq_create->u.request_1, + (PAGE_SIZE/SLI4_PAGE_SIZE)); + page = wq_create->u.request_1.page; + break; + } + break; + case LPFC_Q_CREATE_VERSION_1: bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1, wq->entry_count); switch (wq->entry_size) { @@ -12322,6 +13478,11 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, LPFC_WQ_WQE_SIZE_64); break; case 128: + if (!(phba->sli4_hba.pc_sli4_params.wqsize & + LPFC_WQ_SZ128_SUPPORT)) { + status = -ERANGE; + goto out; + } bf_set(lpfc_mbx_wq_create_wqe_size, &wq_create->u.request_1, LPFC_WQ_WQE_SIZE_128); @@ -12330,14 +13491,21 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1, (PAGE_SIZE/SLI4_PAGE_SIZE)); page = wq_create->u.request_1.page; - } else { - page = wq_create->u.request.page; + break; + default: + status = -ERANGE; + goto out; } + list_for_each_entry(dmabuf, &wq->page_list, list) { memset(dmabuf->virt, 0, hw_page_size); page[dmabuf->buffer_tag].addr_lo = putPaddrLow(dmabuf->phys); page[dmabuf->buffer_tag].addr_hi = putPaddrHigh(dmabuf->phys); } + + if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) + bf_set(lpfc_mbx_wq_create_dua, &wq_create->u.request, 1); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); /* The IOCTL status is embedded in the mailbox subheader. */ shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); @@ -12355,6 +13523,48 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, status = -ENXIO; goto out; } + if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) { + wq->db_format = bf_get(lpfc_mbx_wq_create_db_format, + &wq_create->u.response); + if ((wq->db_format != LPFC_DB_LIST_FORMAT) && + (wq->db_format != LPFC_DB_RING_FORMAT)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3265 WQ[%d] doorbell format not " + "supported: x%x\n", wq->queue_id, + wq->db_format); + status = -EINVAL; + goto out; + } + pci_barset = bf_get(lpfc_mbx_wq_create_bar_set, + &wq_create->u.response); + bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset); + if (!bar_memmap_p) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3263 WQ[%d] failed to memmap pci " + "barset:x%x\n", wq->queue_id, + pci_barset); + status = -ENOMEM; + goto out; + } + db_offset = wq_create->u.response.doorbell_offset; + if ((db_offset != LPFC_ULP0_WQ_DOORBELL) && + (db_offset != LPFC_ULP1_WQ_DOORBELL)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3252 WQ[%d] doorbell offset not " + "supported: x%x\n", wq->queue_id, + db_offset); + status = -EINVAL; + goto out; + } + wq->db_regaddr = bar_memmap_p + db_offset; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "3264 WQ[%d]: barset:x%x, offset:x%x, " + "format:x%x\n", wq->queue_id, pci_barset, + db_offset, wq->db_format); + } else { + wq->db_format = LPFC_DB_LIST_FORMAT; + wq->db_regaddr = phba->sli4_hba.WQDBregaddr; + } wq->type = LPFC_WQ; wq->assoc_qid = cq->queue_id; wq->subtype = subtype; @@ -12431,6 +13641,9 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + void __iomem *bar_memmap_p; + uint32_t db_offset; + uint16_t pci_barset; /* sanity check on queue memory */ if (!hrq || !drq || !cq) @@ -12469,8 +13682,10 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2535 Unsupported RQ count. (%d)\n", hrq->entry_count); - if (hrq->entry_count < 512) - return -EINVAL; + if (hrq->entry_count < 512) { + status = -EINVAL; + goto out; + } /* otherwise default to smallest count (drop through) */ case 512: bf_set(lpfc_rq_context_rqe_count, @@ -12507,6 +13722,9 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, rq_create->u.request.page[dmabuf->buffer_tag].addr_hi = putPaddrHigh(dmabuf->phys); } + if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) + bf_set(lpfc_mbx_rq_create_dua, &rq_create->u.request, 1); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); /* The IOCTL status is embedded in the mailbox subheader. */ shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); @@ -12524,6 +13742,51 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, status = -ENXIO; goto out; } + + if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) { + hrq->db_format = bf_get(lpfc_mbx_rq_create_db_format, + &rq_create->u.response); + if ((hrq->db_format != LPFC_DB_LIST_FORMAT) && + (hrq->db_format != LPFC_DB_RING_FORMAT)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3262 RQ [%d] doorbell format not " + "supported: x%x\n", hrq->queue_id, + hrq->db_format); + status = -EINVAL; + goto out; + } + + pci_barset = bf_get(lpfc_mbx_rq_create_bar_set, + &rq_create->u.response); + bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset); + if (!bar_memmap_p) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3269 RQ[%d] failed to memmap pci " + "barset:x%x\n", hrq->queue_id, + pci_barset); + status = -ENOMEM; + goto out; + } + + db_offset = rq_create->u.response.doorbell_offset; + if ((db_offset != LPFC_ULP0_RQ_DOORBELL) && + (db_offset != LPFC_ULP1_RQ_DOORBELL)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3270 RQ[%d] doorbell offset not " + "supported: x%x\n", hrq->queue_id, + db_offset); + status = -EINVAL; + goto out; + } + hrq->db_regaddr = bar_memmap_p + db_offset; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "3266 RQ[qid:%d]: barset:x%x, offset:x%x, " + "format:x%x\n", hrq->queue_id, pci_barset, + db_offset, hrq->db_format); + } else { + hrq->db_format = LPFC_DB_RING_FORMAT; + hrq->db_regaddr = phba->sli4_hba.RQDBregaddr; + } hrq->type = LPFC_HRQ; hrq->assoc_qid = cq->queue_id; hrq->subtype = subtype; @@ -12550,8 +13813,10 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2536 Unsupported RQ count. (%d)\n", drq->entry_count); - if (drq->entry_count < 512) - return -EINVAL; + if (drq->entry_count < 512) { + status = -EINVAL; + goto out; + } /* otherwise default to smallest count (drop through) */ case 512: bf_set(lpfc_rq_context_rqe_count, @@ -12587,6 +13852,8 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, rq_create->u.request.page[dmabuf->buffer_tag].addr_hi = putPaddrHigh(dmabuf->phys); } + if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) + bf_set(lpfc_mbx_rq_create_dua, &rq_create->u.request, 1); rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); /* The IOCTL status is embedded in the mailbox subheader. */ shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr; @@ -13021,9 +14288,7 @@ lpfc_sli4_alloc_xri(struct lpfc_hba *phba) } else { set_bit(xri, phba->sli4_hba.xri_bmask); phba->sli4_hba.max_cfg_param.xri_used++; - phba->sli4_hba.xri_count++; } - spin_unlock_irq(&phba->hbalock); return xri; } @@ -13039,7 +14304,6 @@ void __lpfc_sli4_free_xri(struct lpfc_hba *phba, int xri) { if (test_and_clear_bit(xri, phba->sli4_hba.xri_bmask)) { - phba->sli4_hba.xri_count--; phba->sli4_hba.max_cfg_param.xri_used--; } } @@ -13075,46 +14339,45 @@ lpfc_sli4_next_xritag(struct lpfc_hba *phba) uint16_t xri_index; xri_index = lpfc_sli4_alloc_xri(phba); - if (xri_index != NO_XRI) - return xri_index; - - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2004 Failed to allocate XRI.last XRITAG is %d" - " Max XRI is %d, Used XRI is %d\n", - xri_index, - phba->sli4_hba.max_cfg_param.max_xri, - phba->sli4_hba.max_cfg_param.xri_used); - return NO_XRI; + if (xri_index == NO_XRI) + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "2004 Failed to allocate XRI.last XRITAG is %d" + " Max XRI is %d, Used XRI is %d\n", + xri_index, + phba->sli4_hba.max_cfg_param.max_xri, + phba->sli4_hba.max_cfg_param.xri_used); + return xri_index; } /** * lpfc_sli4_post_els_sgl_list - post a block of ELS sgls to the port. * @phba: pointer to lpfc hba data structure. + * @post_sgl_list: pointer to els sgl entry list. + * @count: number of els sgl entries on the list. * * This routine is invoked to post a block of driver's sgl pages to the * HBA using non-embedded mailbox command. No Lock is held. This routine * is only called when the driver is loading and after all IO has been * stopped. **/ -int -lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) +static int +lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba, + struct list_head *post_sgl_list, + int post_cnt) { - struct lpfc_sglq *sglq_entry; + struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; struct lpfc_mbx_post_uembed_sgl_page1 *sgl; struct sgl_page_pairs *sgl_pg_pairs; void *viraddr; LPFC_MBOXQ_t *mbox; uint32_t reqlen, alloclen, pg_pairs; uint32_t mbox_tmo; - uint16_t xritag_start = 0, lxri = 0; - int els_xri_cnt, rc = 0; + uint16_t xritag_start = 0; + int rc = 0; uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; - /* The number of sgls to be posted */ - els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); - - reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) + + reqlen = phba->sli4_hba.els_xri_cnt * sizeof(struct sgl_page_pairs) + sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); if (reqlen > SLI4_PAGE_SIZE) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -13144,25 +14407,8 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; sgl_pg_pairs = &sgl->sgl_pg_pairs; - for (pg_pairs = 0; pg_pairs < els_xri_cnt; pg_pairs++) { - sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[pg_pairs]; - - /* - * Assign the sglq a physical xri only if the driver has not - * initialized those resources. A port reset only needs - * the sglq's posted. - */ - if (bf_get(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags) != - LPFC_XRI_RSRC_RDY) { - lxri = lpfc_sli4_next_xritag(phba); - if (lxri == NO_XRI) { - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - sglq_entry->sli4_lxritag = lxri; - sglq_entry->sli4_xritag = phba->sli4_hba.xri_ids[lxri]; - } - + pg_pairs = 0; + list_for_each_entry_safe(sglq_entry, sglq_next, post_sgl_list, list) { /* Set up the sge entry */ sgl_pg_pairs->sgl_pg0_addr_lo = cpu_to_le32(putPaddrLow(sglq_entry->phys)); @@ -13177,11 +14423,12 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) if (pg_pairs == 0) xritag_start = sglq_entry->sli4_xritag; sgl_pg_pairs++; + pg_pairs++; } /* Complete initialization and perform endian conversion. */ bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start); - bf_set(lpfc_post_sgl_pages_xricnt, sgl, els_xri_cnt); + bf_set(lpfc_post_sgl_pages_xricnt, sgl, phba->sli4_hba.els_xri_cnt); sgl->word0 = cpu_to_le32(sgl->word0); if (!phba->sli4_hba.intr_enable) rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); @@ -13201,181 +14448,6 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) shdr_status, shdr_add_status, rc); rc = -ENXIO; } - - if (rc == 0) - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, - LPFC_XRI_RSRC_RDY); - return rc; -} - -/** - * lpfc_sli4_post_els_sgl_list_ext - post a block of ELS sgls to the port. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to post a block of driver's sgl pages to the - * HBA using non-embedded mailbox command. No Lock is held. This routine - * is only called when the driver is loading and after all IO has been - * stopped. - **/ -int -lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba) -{ - struct lpfc_sglq *sglq_entry; - struct lpfc_mbx_post_uembed_sgl_page1 *sgl; - struct sgl_page_pairs *sgl_pg_pairs; - void *viraddr; - LPFC_MBOXQ_t *mbox; - uint32_t reqlen, alloclen, index; - uint32_t mbox_tmo; - uint16_t rsrc_start, rsrc_size, els_xri_cnt; - uint16_t xritag_start = 0, lxri = 0; - struct lpfc_rsrc_blks *rsrc_blk; - int cnt, ttl_cnt, rc = 0; - int loop_cnt; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - - /* The number of sgls to be posted */ - els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); - - reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - if (reqlen > SLI4_PAGE_SIZE) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2989 Block sgl registration required DMA " - "size (%d) great than a page\n", reqlen); - return -ENOMEM; - } - - cnt = 0; - ttl_cnt = 0; - list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list, - list) { - rsrc_start = rsrc_blk->rsrc_start; - rsrc_size = rsrc_blk->rsrc_size; - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3014 Working ELS Extent start %d, cnt %d\n", - rsrc_start, rsrc_size); - - loop_cnt = min(els_xri_cnt, rsrc_size); - if (ttl_cnt + loop_cnt >= els_xri_cnt) { - loop_cnt = els_xri_cnt - ttl_cnt; - ttl_cnt = els_xri_cnt; - } - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - /* - * Allocate DMA memory and set up the non-embedded mailbox - * command. - */ - alloclen = lpfc_sli4_config(phba, mbox, - LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, - reqlen, LPFC_SLI4_MBX_NEMBED); - if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2987 Allocated DMA memory size (%d) " - "is less than the requested DMA memory " - "size (%d)\n", alloclen, reqlen); - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - - /* Set up the SGL pages in the non-embedded DMA pages */ - viraddr = mbox->sge_array->addr[0]; - sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; - sgl_pg_pairs = &sgl->sgl_pg_pairs; - - /* - * The starting resource may not begin at zero. Control - * the loop variants via the block resource parameters, - * but handle the sge pointers with a zero-based index - * that doesn't get reset per loop pass. - */ - for (index = rsrc_start; - index < rsrc_start + loop_cnt; - index++) { - sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[cnt]; - - /* - * Assign the sglq a physical xri only if the driver - * has not initialized those resources. A port reset - * only needs the sglq's posted. - */ - if (bf_get(lpfc_xri_rsrc_rdy, - &phba->sli4_hba.sli4_flags) != - LPFC_XRI_RSRC_RDY) { - lxri = lpfc_sli4_next_xritag(phba); - if (lxri == NO_XRI) { - lpfc_sli4_mbox_cmd_free(phba, mbox); - rc = -ENOMEM; - goto err_exit; - } - sglq_entry->sli4_lxritag = lxri; - sglq_entry->sli4_xritag = - phba->sli4_hba.xri_ids[lxri]; - } - - /* Set up the sge entry */ - sgl_pg_pairs->sgl_pg0_addr_lo = - cpu_to_le32(putPaddrLow(sglq_entry->phys)); - sgl_pg_pairs->sgl_pg0_addr_hi = - cpu_to_le32(putPaddrHigh(sglq_entry->phys)); - sgl_pg_pairs->sgl_pg1_addr_lo = - cpu_to_le32(putPaddrLow(0)); - sgl_pg_pairs->sgl_pg1_addr_hi = - cpu_to_le32(putPaddrHigh(0)); - - /* Track the starting physical XRI for the mailbox. */ - if (index == rsrc_start) - xritag_start = sglq_entry->sli4_xritag; - sgl_pg_pairs++; - cnt++; - } - - /* Complete initialization and perform endian conversion. */ - rsrc_blk->rsrc_used += loop_cnt; - bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start); - bf_set(lpfc_post_sgl_pages_xricnt, sgl, loop_cnt); - sgl->word0 = cpu_to_le32(sgl->word0); - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3015 Post ELS Extent SGL, start %d, " - "cnt %d, used %d\n", - xritag_start, loop_cnt, rsrc_blk->rsrc_used); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, - &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &shdr->response); - if (rc != MBX_TIMEOUT) - lpfc_sli4_mbox_cmd_free(phba, mbox); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2988 POST_SGL_BLOCK mailbox " - "command failed status x%x " - "add_status x%x mbx status x%x\n", - shdr_status, shdr_add_status, rc); - rc = -ENXIO; - goto err_exit; - } - if (ttl_cnt >= els_xri_cnt) - break; - } - - err_exit: - if (rc == 0) - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, - LPFC_XRI_RSRC_RDY); return rc; } @@ -13391,8 +14463,9 @@ lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba) * **/ int -lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist, - int cnt) +lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, + struct list_head *sblist, + int count) { struct lpfc_scsi_buf *psb; struct lpfc_mbx_post_uembed_sgl_page1 *sgl; @@ -13408,7 +14481,7 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist, union lpfc_sli4_cfg_shdr *shdr; /* Calculate the requested length of the dma memory */ - reqlen = cnt * sizeof(struct sgl_page_pairs) + + reqlen = count * sizeof(struct sgl_page_pairs) + sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); if (reqlen > SLI4_PAGE_SIZE) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -13492,169 +14565,6 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist, } /** - * lpfc_sli4_post_scsi_sgl_blk_ext - post a block of scsi sgls to the port. - * @phba: pointer to lpfc hba data structure. - * @sblist: pointer to scsi buffer list. - * @count: number of scsi buffers on the list. - * - * This routine is invoked to post a block of @count scsi sgl pages from a - * SCSI buffer list @sblist to the HBA using non-embedded mailbox command. - * No Lock is held. - * - **/ -int -lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *phba, struct list_head *sblist, - int cnt) -{ - struct lpfc_scsi_buf *psb = NULL; - struct lpfc_mbx_post_uembed_sgl_page1 *sgl; - struct sgl_page_pairs *sgl_pg_pairs; - void *viraddr; - LPFC_MBOXQ_t *mbox; - uint32_t reqlen, alloclen, pg_pairs; - uint32_t mbox_tmo; - uint16_t xri_start = 0, scsi_xri_start; - uint16_t rsrc_range; - int rc = 0, avail_cnt; - uint32_t shdr_status, shdr_add_status; - dma_addr_t pdma_phys_bpl1; - union lpfc_sli4_cfg_shdr *shdr; - struct lpfc_rsrc_blks *rsrc_blk; - uint32_t xri_cnt = 0; - - /* Calculate the total requested length of the dma memory */ - reqlen = cnt * sizeof(struct sgl_page_pairs) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - if (reqlen > SLI4_PAGE_SIZE) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2932 Block sgl registration required DMA " - "size (%d) great than a page\n", reqlen); - return -ENOMEM; - } - - /* - * The use of extents requires the driver to post the sgl headers - * in multiple postings to meet the contiguous resource assignment. - */ - psb = list_prepare_entry(psb, sblist, list); - scsi_xri_start = phba->sli4_hba.scsi_xri_start; - list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list, - list) { - rsrc_range = rsrc_blk->rsrc_start + rsrc_blk->rsrc_size; - if (rsrc_range < scsi_xri_start) - continue; - else if (rsrc_blk->rsrc_used >= rsrc_blk->rsrc_size) - continue; - else - avail_cnt = rsrc_blk->rsrc_size - rsrc_blk->rsrc_used; - - reqlen = (avail_cnt * sizeof(struct sgl_page_pairs)) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - /* - * Allocate DMA memory and set up the non-embedded mailbox - * command. The mbox is used to post an SGL page per loop - * but the DMA memory has a use-once semantic so the mailbox - * is used and freed per loop pass. - */ - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2933 Failed to allocate mbox cmd " - "memory\n"); - return -ENOMEM; - } - alloclen = lpfc_sli4_config(phba, mbox, - LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, - reqlen, - LPFC_SLI4_MBX_NEMBED); - if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2934 Allocated DMA memory size (%d) " - "is less than the requested DMA memory " - "size (%d)\n", alloclen, reqlen); - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - - /* Get the first SGE entry from the non-embedded DMA memory */ - viraddr = mbox->sge_array->addr[0]; - - /* Set up the SGL pages in the non-embedded DMA pages */ - sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; - sgl_pg_pairs = &sgl->sgl_pg_pairs; - - /* pg_pairs tracks posted SGEs per loop iteration. */ - pg_pairs = 0; - list_for_each_entry_continue(psb, sblist, list) { - /* Set up the sge entry */ - sgl_pg_pairs->sgl_pg0_addr_lo = - cpu_to_le32(putPaddrLow(psb->dma_phys_bpl)); - sgl_pg_pairs->sgl_pg0_addr_hi = - cpu_to_le32(putPaddrHigh(psb->dma_phys_bpl)); - if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) - pdma_phys_bpl1 = psb->dma_phys_bpl + - SGL_PAGE_SIZE; - else - pdma_phys_bpl1 = 0; - sgl_pg_pairs->sgl_pg1_addr_lo = - cpu_to_le32(putPaddrLow(pdma_phys_bpl1)); - sgl_pg_pairs->sgl_pg1_addr_hi = - cpu_to_le32(putPaddrHigh(pdma_phys_bpl1)); - /* Keep the first xri for this extent. */ - if (pg_pairs == 0) - xri_start = psb->cur_iocbq.sli4_xritag; - sgl_pg_pairs++; - pg_pairs++; - xri_cnt++; - - /* - * Track two exit conditions - the loop has constructed - * all of the caller's SGE pairs or all available - * resource IDs in this extent are consumed. - */ - if ((xri_cnt == cnt) || (pg_pairs >= avail_cnt)) - break; - } - rsrc_blk->rsrc_used += pg_pairs; - bf_set(lpfc_post_sgl_pages_xri, sgl, xri_start); - bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs); - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3016 Post SCSI Extent SGL, start %d, cnt %d " - "blk use %d\n", - xri_start, pg_pairs, rsrc_blk->rsrc_used); - /* Perform endian conversion if necessary */ - sgl->word0 = cpu_to_le32(sgl->word0); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &shdr->response); - if (rc != MBX_TIMEOUT) - lpfc_sli4_mbox_cmd_free(phba, mbox); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2935 POST_SGL_BLOCK mailbox command " - "failed status x%x add_status x%x " - "mbx status x%x\n", - shdr_status, shdr_add_status, rc); - return -ENXIO; - } - - /* Post only what is requested. */ - if (xri_cnt >= cnt) - break; - } - return rc; -} - -/** * lpfc_fc_frame_check - Check that this frame is a valid frame to handle * @phba: pointer to lpfc_hba struct that the frame was received on * @fc_hdr: A pointer to the FC Header data (In Big Endian Format) @@ -13722,13 +14632,14 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr) } lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "2538 Received frame rctl:%s type:%s " - "Frame Data:%08x %08x %08x %08x %08x %08x\n", - rctl_names[fc_hdr->fh_r_ctl], - type_names[fc_hdr->fh_type], + "2538 Received frame rctl:%s (x%x), type:%s (x%x), " + "frame Data:%08x %08x %08x %08x %08x %08x %08x\n", + rctl_names[fc_hdr->fh_r_ctl], fc_hdr->fh_r_ctl, + type_names[fc_hdr->fh_type], fc_hdr->fh_type, be32_to_cpu(header[0]), be32_to_cpu(header[1]), be32_to_cpu(header[2]), be32_to_cpu(header[3]), - be32_to_cpu(header[4]), be32_to_cpu(header[5])); + be32_to_cpu(header[4]), be32_to_cpu(header[5]), + be32_to_cpu(header[6])); return 0; drop: lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, @@ -13778,8 +14689,13 @@ lpfc_fc_frame_to_vport(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr, uint32_t did = (fc_hdr->fh_d_id[0] << 16 | fc_hdr->fh_d_id[1] << 8 | fc_hdr->fh_d_id[2]); + if (did == Fabric_DID) return phba->pport; + if ((phba->pport->fc_flag & FC_PT2PT) && + !(phba->link_state == LPFC_HBA_READY)) + return phba->pport; + vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { @@ -14026,6 +14942,40 @@ lpfc_sli4_abort_partial_seq(struct lpfc_vport *vport, } /** + * lpfc_sli4_abort_ulp_seq - Abort assembled unsol sequence from ulp + * @vport: pointer to a vitural port + * @dmabuf: pointer to a dmabuf that describes the FC sequence + * + * This function tries to abort from the assembed sequence from upper level + * protocol, described by the information from basic abbort @dmabuf. It + * checks to see whether such pending context exists at upper level protocol. + * If so, it shall clean up the pending context. + * + * Return + * true -- if there is matching pending context of the sequence cleaned + * at ulp; + * false -- if there is no matching pending context of the sequence present + * at ulp. + **/ +static bool +lpfc_sli4_abort_ulp_seq(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf) +{ + struct lpfc_hba *phba = vport->phba; + int handled; + + /* Accepting abort at ulp with SLI4 only */ + if (phba->sli_rev < LPFC_SLI_REV4) + return false; + + /* Register all caring upper level protocols to attend abort */ + handled = lpfc_ct_handle_unsol_abort(phba, dmabuf); + if (handled) + return true; + + return false; +} + +/** * lpfc_sli4_seq_abort_rsp_cmpl - BLS ABORT RSP seq abort iocb complete handler * @phba: Pointer to HBA context object. * @cmd_iocbq: pointer to the command iocbq structure. @@ -14040,8 +14990,21 @@ lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmd_iocbq, struct lpfc_iocbq *rsp_iocbq) { - if (cmd_iocbq) + struct lpfc_nodelist *ndlp; + + if (cmd_iocbq) { + ndlp = (struct lpfc_nodelist *)cmd_iocbq->context1; + lpfc_nlp_put(ndlp); + lpfc_nlp_not_used(ndlp); lpfc_sli_release_iocbq(phba, cmd_iocbq); + } + + /* Failure means BLS ABORT RSP did not get delivered to remote node*/ + if (rsp_iocbq && rsp_iocbq->iocb.ulpStatus) + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "3154 BLS ABORT RSP failed, data: x%x/x%x\n", + rsp_iocbq->iocb.ulpStatus, + rsp_iocbq->iocb.un.ulpWord[4]); } /** @@ -14065,7 +15028,6 @@ lpfc_sli4_xri_inrange(struct lpfc_hba *phba, return NO_XRI; } - /** * lpfc_sli4_seq_abort_rsp - bls rsp to sequence abort * @phba: Pointer to HBA context object. @@ -14075,12 +15037,13 @@ lpfc_sli4_xri_inrange(struct lpfc_hba *phba, * event after aborting the sequence handling. **/ static void -lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, - struct fc_frame_header *fc_hdr) +lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, + struct fc_frame_header *fc_hdr, bool aborted) { + struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *ctiocb = NULL; struct lpfc_nodelist *ndlp; - uint16_t oxid, rxid; + uint16_t oxid, rxid, xri, lxri; uint32_t sid, fctl; IOCB_t *icmd; int rc; @@ -14092,15 +15055,28 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, oxid = be16_to_cpu(fc_hdr->fh_ox_id); rxid = be16_to_cpu(fc_hdr->fh_rx_id); - ndlp = lpfc_findnode_did(phba->pport, sid); + ndlp = lpfc_findnode_did(vport, sid); if (!ndlp) { - lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, - "1268 Find ndlp returned NULL for oxid:x%x " - "SID:x%x\n", oxid, sid); - return; + ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); + if (!ndlp) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, + "1268 Failed to allocate ndlp for " + "oxid:x%x SID:x%x\n", oxid, sid); + return; + } + lpfc_nlp_init(vport, ndlp, sid); + /* Put ndlp onto pport node list */ + lpfc_enqueue_node(vport, ndlp); + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + /* re-setup ndlp without removing from node list */ + ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); + if (!ndlp) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, + "3275 Failed to active ndlp found " + "for oxid:x%x SID:x%x\n", oxid, sid); + return; + } } - if (lpfc_sli4_xri_inrange(phba, rxid)) - lpfc_set_rrq_active(phba, ndlp, rxid, oxid, 0); /* Allocate buffer for rsp iocb */ ctiocb = lpfc_sli_get_iocbq(phba); @@ -14123,7 +15099,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, icmd->ulpLe = 1; icmd->ulpClass = CLASS3; icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; - ctiocb->context1 = ndlp; + ctiocb->context1 = lpfc_nlp_get(ndlp); ctiocb->iocb_cmpl = NULL; ctiocb->vport = phba->pport; @@ -14131,14 +15107,35 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, ctiocb->sli4_lxritag = NO_XRI; ctiocb->sli4_xritag = NO_XRI; - /* If the oxid maps to the FCP XRI range or if it is out of range, - * send a BLS_RJT. The driver no longer has that exchange. - * Override the IOCB for a BA_RJT. + if (fctl & FC_FC_EX_CTX) + /* Exchange responder sent the abort so we + * own the oxid. + */ + xri = oxid; + else + xri = rxid; + lxri = lpfc_sli4_xri_inrange(phba, xri); + if (lxri != NO_XRI) + lpfc_set_rrq_active(phba, ndlp, lxri, + (xri == oxid) ? rxid : oxid, 0); + /* For BA_ABTS from exchange responder, if the logical xri with + * the oxid maps to the FCP XRI range, the port no longer has + * that exchange context, send a BLS_RJT. Override the IOCB for + * a BA_RJT. + */ + if ((fctl & FC_FC_EX_CTX) && + (lxri > lpfc_sli4_get_els_iocb_cnt(phba))) { + icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT; + bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0); + bf_set(lpfc_rsn_expln, &icmd->un.bls_rsp, FC_BA_RJT_INV_XID); + bf_set(lpfc_rsn_code, &icmd->un.bls_rsp, FC_BA_RJT_UNABLE); + } + + /* If BA_ABTS failed to abort a partially assembled receive sequence, + * the driver no longer has that exchange, send a BLS_RJT. Override + * the IOCB for a BA_RJT. */ - if (oxid > (phba->sli4_hba.max_cfg_param.max_xri + - phba->sli4_hba.max_cfg_param.xri_base) || - oxid > (lpfc_sli4_get_els_iocb_cnt(phba) + - phba->sli4_hba.max_cfg_param.xri_base)) { + if (aborted == false) { icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT; bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0); bf_set(lpfc_rsn_expln, &icmd->un.bls_rsp, FC_BA_RJT_INV_XID); @@ -14151,29 +15148,30 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, * field and RX_ID from ABTS for RX_ID field. */ bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_RSP); - bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, rxid); } else { /* ABTS sent by initiator to CT exchange, construction * of BA_ACC will need to allocate a new XRI as for the - * XRI_TAG and RX_ID fields. + * XRI_TAG field. */ bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_INT); - bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, NO_XRI); } + bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, rxid); bf_set(lpfc_abts_oxid, &icmd->un.bls_rsp, oxid); /* Xmit CT abts response on exchange <xid> */ - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "1200 Send BLS cmd x%x on oxid x%x Data: x%x\n", - icmd->un.xseq64.w5.hcsw.Rctl, oxid, phba->link_state); + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "1200 Send BLS cmd x%x on oxid x%x Data: x%x\n", + icmd->un.xseq64.w5.hcsw.Rctl, oxid, phba->link_state); rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); if (rc == IOCB_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, - "2925 Failed to issue CT ABTS RSP x%x on " - "xri x%x, Data x%x\n", - icmd->un.xseq64.w5.hcsw.Rctl, oxid, - phba->link_state); + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "2925 Failed to issue CT ABTS RSP x%x on " + "xri x%x, Data x%x\n", + icmd->un.xseq64.w5.hcsw.Rctl, oxid, + phba->link_state); + lpfc_nlp_put(ndlp); + ctiocb->context1 = NULL; lpfc_sli_release_iocbq(phba, ctiocb); } } @@ -14198,32 +15196,25 @@ lpfc_sli4_handle_unsol_abort(struct lpfc_vport *vport, struct lpfc_hba *phba = vport->phba; struct fc_frame_header fc_hdr; uint32_t fctl; - bool abts_par; + bool aborted; /* Make a copy of fc_hdr before the dmabuf being released */ memcpy(&fc_hdr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header)); fctl = sli4_fctl_from_fc_hdr(&fc_hdr); if (fctl & FC_FC_EX_CTX) { - /* - * ABTS sent by responder to exchange, just free the buffer - */ - lpfc_in_buf_free(phba, &dmabuf->dbuf); + /* ABTS by responder to exchange, no cleanup needed */ + aborted = true; } else { - /* - * ABTS sent by initiator to exchange, need to do cleanup - */ - /* Try to abort partially assembled seq */ - abts_par = lpfc_sli4_abort_partial_seq(vport, dmabuf); - - /* Send abort to ULP if partially seq abort failed */ - if (abts_par == false) - lpfc_sli4_send_seq_to_ulp(vport, dmabuf); - else - lpfc_in_buf_free(phba, &dmabuf->dbuf); + /* ABTS by initiator to exchange, need to do cleanup */ + aborted = lpfc_sli4_abort_partial_seq(vport, dmabuf); + if (aborted == false) + aborted = lpfc_sli4_abort_ulp_seq(vport, dmabuf); } - /* Send basic accept (BA_ACC) to the abort requester */ - lpfc_sli4_seq_abort_rsp(phba, &fc_hdr); + lpfc_in_buf_free(phba, &dmabuf->dbuf); + + /* Respond with BA_ACC or BA_RJT accordingly */ + lpfc_sli4_seq_abort_rsp(vport, &fc_hdr, aborted); } /** @@ -14310,7 +15301,15 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) /* Initialize the first IOCB. */ first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0; first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS; - first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX; + + /* Check FC Header to see what TYPE of frame we are rcv'ing */ + if (sli4_type_from_fc_hdr(fc_hdr) == FC_TYPE_ELS) { + first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_ELS64_CX; + first_iocbq->iocb.un.rcvels.parmRo = + sli4_did_from_fc_hdr(fc_hdr); + first_iocbq->iocb.ulpPU = PARM_NPIV_DID; + } else + first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX; first_iocbq->iocb.ulpContext = NO_XRI; first_iocbq->iocb.unsli3.rcvsli3.ox_id = be16_to_cpu(fc_hdr->fh_ox_id); @@ -14318,14 +15317,20 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) first_iocbq->iocb.unsli3.rcvsli3.vpi = vport->phba->vpi_ids[vport->vpi]; /* put the first buffer into the first IOCBq */ + tot_len = bf_get(lpfc_rcqe_length, + &seq_dmabuf->cq_event.cqe.rcqe_cmpl); + first_iocbq->context2 = &seq_dmabuf->dbuf; first_iocbq->context3 = NULL; first_iocbq->iocb.ulpBdeCount = 1; - first_iocbq->iocb.un.cont64[0].tus.f.bdeSize = + if (tot_len > LPFC_DATA_BUF_SIZE) + first_iocbq->iocb.un.cont64[0].tus.f.bdeSize = LPFC_DATA_BUF_SIZE; + else + first_iocbq->iocb.un.cont64[0].tus.f.bdeSize = tot_len; + first_iocbq->iocb.un.rcvels.remoteID = sid; - tot_len = bf_get(lpfc_rcqe_length, - &seq_dmabuf->cq_event.cqe.rcqe_cmpl); + first_iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len; } iocbq = first_iocbq; @@ -14341,14 +15346,17 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) if (!iocbq->context3) { iocbq->context3 = d_buf; iocbq->iocb.ulpBdeCount++; - pbde = (struct ulp_bde64 *) - &iocbq->iocb.unsli3.sli3Words[4]; - pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE; - /* We need to get the size out of the right CQE */ hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); len = bf_get(lpfc_rcqe_length, &hbq_buf->cq_event.cqe.rcqe_cmpl); + pbde = (struct ulp_bde64 *) + &iocbq->iocb.unsli3.sli3Words[4]; + if (len > LPFC_DATA_BUF_SIZE) + pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE; + else + pbde->tus.f.bdeSize = len; + iocbq->iocb.unsli3.rcvsli3.acc_len += len; tot_len += len; } else { @@ -14363,16 +15371,19 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) lpfc_in_buf_free(vport->phba, d_buf); continue; } + /* We need to get the size out of the right CQE */ + hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); + len = bf_get(lpfc_rcqe_length, + &hbq_buf->cq_event.cqe.rcqe_cmpl); iocbq->context2 = d_buf; iocbq->context3 = NULL; iocbq->iocb.ulpBdeCount = 1; - iocbq->iocb.un.cont64[0].tus.f.bdeSize = + if (len > LPFC_DATA_BUF_SIZE) + iocbq->iocb.un.cont64[0].tus.f.bdeSize = LPFC_DATA_BUF_SIZE; + else + iocbq->iocb.un.cont64[0].tus.f.bdeSize = len; - /* We need to get the size out of the right CQE */ - hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); - len = bf_get(lpfc_rcqe_length, - &hbq_buf->cq_event.cqe.rcqe_cmpl); tot_len += len; iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len; @@ -14440,6 +15451,7 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr; struct lpfc_vport *vport; uint32_t fcfi; + uint32_t did; /* Process each received buffer */ fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; @@ -14455,12 +15467,32 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, else fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->cq_event.cqe.rcqe_cmpl); + vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi); - if (!vport || !(vport->vpi_state & LPFC_VPI_REGISTERED)) { + if (!vport) { /* throw out the frame */ lpfc_in_buf_free(phba, &dmabuf->dbuf); return; } + + /* d_id this frame is directed to */ + did = sli4_did_from_fc_hdr(fc_hdr); + + /* vport is registered unless we rcv a FLOGI directed to Fabric_DID */ + if (!(vport->vpi_state & LPFC_VPI_REGISTERED) && + (did != Fabric_DID)) { + /* + * Throw out the frame if we are not pt2pt. + * The pt2pt protocol allows for discovery frames + * to be received without a registered VPI. + */ + if (!(vport->fc_flag & FC_PT2PT) || + (phba->link_state == LPFC_HBA_READY)) { + lpfc_in_buf_free(phba, &dmabuf->dbuf); + return; + } + } + /* Handle the basic abort sequence (BA_ABTS) event */ if (fc_hdr->fh_r_ctl == FC_RCTL_BA_ABTS) { lpfc_sli4_handle_unsol_abort(vport, dmabuf); @@ -14633,6 +15665,7 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) uint16_t max_rpi, rpi_limit; uint16_t rpi_remaining, lrpi = 0; struct lpfc_rpi_hdr *rpi_hdr; + unsigned long iflag; max_rpi = phba->sli4_hba.max_cfg_param.max_rpi; rpi_limit = phba->sli4_hba.next_rpi; @@ -14641,7 +15674,7 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) * Fetch the next logical rpi. Because this index is logical, * the driver starts at 0 each time. */ - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflag); rpi = find_next_zero_bit(phba->sli4_hba.rpi_bmask, rpi_limit, 0); if (rpi >= rpi_limit) rpi = LPFC_RPI_ALLOC_ERROR; @@ -14657,7 +15690,7 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) */ if ((rpi == LPFC_RPI_ALLOC_ERROR) && (phba->sli4_hba.rpi_count >= max_rpi)) { - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflag); return rpi; } @@ -14666,7 +15699,7 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) * extents. */ if (!phba->sli4_hba.rpi_hdrs_in_use) { - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflag); return rpi; } @@ -14677,7 +15710,7 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) * how many are supported max by the device. */ rpi_remaining = phba->sli4_hba.next_rpi - phba->sli4_hba.rpi_count; - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflag); if (rpi_remaining < LPFC_RPI_LOW_WATER_MARK) { rpi_hdr = lpfc_sli4_create_rpi_hdr(phba); if (!rpi_hdr) { @@ -14748,7 +15781,8 @@ lpfc_sli4_remove_rpis(struct lpfc_hba *phba) * provided rpi via a bitmask. **/ int -lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp) +lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp, + void (*cmpl)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *arg) { LPFC_MBOXQ_t *mboxq; struct lpfc_hba *phba = ndlp->phba; @@ -14761,6 +15795,13 @@ lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp) /* Post all rpi memory regions to the port. */ lpfc_resume_rpi(mboxq, ndlp); + if (cmpl) { + mboxq->mbox_cmpl = cmpl; + mboxq->context1 = arg; + mboxq->context2 = ndlp; + } else + mboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mboxq->vport = ndlp->vport; rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -14982,6 +16023,7 @@ lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index) LPFC_MBOXQ_t *mboxq; phba->fcoe_eventtag_at_fcf_scan = phba->fcoe_eventtag; + phba->fcoe_cvl_eventtag_attn = phba->fcoe_cvl_eventtag; mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -15143,11 +16185,18 @@ lpfc_check_next_fcf_pri_level(struct lpfc_hba *phba) LPFC_SLI4_FCF_TBL_INDX_MAX); lpfc_printf_log(phba, KERN_INFO, LOG_FIP, "3060 Last IDX %d\n", last_index); - if (list_empty(&phba->fcf.fcf_pri_list)) { + + /* Verify the priority list has 2 or more entries */ + spin_lock_irq(&phba->hbalock); + if (list_empty(&phba->fcf.fcf_pri_list) || + list_is_singular(&phba->fcf.fcf_pri_list)) { + spin_unlock_irq(&phba->hbalock); lpfc_printf_log(phba, KERN_ERR, LOG_FIP, "3061 Last IDX %d\n", last_index); return 0; /* Empty rr list */ } + spin_unlock_irq(&phba->hbalock); + next_fcf_pri = 0; /* * Clear the rr_bmask and set all of the bits that are at this @@ -15177,7 +16226,7 @@ lpfc_check_next_fcf_pri_level(struct lpfc_hba *phba) /* * if next_fcf_pri was not set above and the list is not empty then * we have failed flogis on all of them. So reset flogi failed - * and start at the begining. + * and start at the beginning. */ if (!next_fcf_pri && !list_empty(&phba->fcf.fcf_pri_list)) { list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) { @@ -15218,10 +16267,13 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba) { uint16_t next_fcf_index; +initial_priority: /* Search start from next bit of currently registered FCF index */ + next_fcf_index = phba->fcf.current_rec.fcf_indx; + next_priority: - next_fcf_index = (phba->fcf.current_rec.fcf_indx + 1) % - LPFC_SLI4_FCF_TBL_INDX_MAX; + /* Determine the next fcf index to check */ + next_fcf_index = (next_fcf_index + 1) % LPFC_SLI4_FCF_TBL_INDX_MAX; next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask, LPFC_SLI4_FCF_TBL_INDX_MAX, next_fcf_index); @@ -15248,7 +16300,7 @@ next_priority: * at that level and continue the selection process. */ if (lpfc_check_next_fcf_pri_level(phba)) - goto next_priority; + goto initial_priority; lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, "2844 No roundrobin failover FCF available\n"); if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) @@ -15318,7 +16370,7 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index) void lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index) { - struct lpfc_fcf_pri *fcf_pri; + struct lpfc_fcf_pri *fcf_pri, *fcf_pri_next; if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { lpfc_printf_log(phba, KERN_ERR, LOG_FIP, "2762 FCF (x%x) reached driver's book " @@ -15328,7 +16380,8 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index) } /* Clear the eligible FCF record index bmask */ spin_lock_irq(&phba->hbalock); - list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) { + list_for_each_entry_safe(fcf_pri, fcf_pri_next, &phba->fcf.fcf_pri_list, + list) { if (fcf_pri->fcf_rec.fcf_index == fcf_index) { list_del_init(&fcf_pri->list); break; @@ -15898,41 +16951,41 @@ lpfc_drain_txq(struct lpfc_hba *phba) { LIST_HEAD(completions); struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - struct lpfc_iocbq *piocbq = 0; + struct lpfc_iocbq *piocbq = NULL; unsigned long iflags = 0; char *fail_msg = NULL; struct lpfc_sglq *sglq; union lpfc_wqe wqe; + int txq_cnt = 0; - spin_lock_irqsave(&phba->hbalock, iflags); - if (pring->txq_cnt > pring->txq_max) - pring->txq_max = pring->txq_cnt; + spin_lock_irqsave(&pring->ring_lock, iflags); + list_for_each_entry(piocbq, &pring->txq, list) { + txq_cnt++; + } - spin_unlock_irqrestore(&phba->hbalock, iflags); + if (txq_cnt > pring->txq_max) + pring->txq_max = txq_cnt; - while (pring->txq_cnt) { - spin_lock_irqsave(&phba->hbalock, iflags); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + + while (!list_empty(&pring->txq)) { + spin_lock_irqsave(&pring->ring_lock, iflags); piocbq = lpfc_sli_ringtx_get(phba, pring); + if (!piocbq) { + spin_unlock_irqrestore(&pring->ring_lock, iflags); + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2823 txq empty and txq_cnt is %d\n ", + txq_cnt); + break; + } sglq = __lpfc_sli_get_sglq(phba, piocbq); if (!sglq) { __lpfc_sli_ringtx_put(phba, pring, piocbq); - spin_unlock_irqrestore(&phba->hbalock, iflags); + spin_unlock_irqrestore(&pring->ring_lock, iflags); break; - } else { - if (!piocbq) { - /* The txq_cnt out of sync. This should - * never happen - */ - sglq = __lpfc_clear_active_sglq(phba, - sglq->sli4_lxritag); - spin_unlock_irqrestore(&phba->hbalock, iflags); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2823 txq empty and txq_cnt is %d\n ", - pring->txq_cnt); - break; - } } + txq_cnt--; /* The xri and iocb resources secured, * attempt to issue request @@ -15957,12 +17010,12 @@ lpfc_drain_txq(struct lpfc_hba *phba) piocbq->iotag, piocbq->sli4_xritag); list_add_tail(&piocbq->list, &completions); } - spin_unlock_irqrestore(&phba->hbalock, iflags); + spin_unlock_irqrestore(&pring->ring_lock, iflags); } /* Cancel all the IOCBs that cannot be issued */ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); - return pring->txq_cnt; + return txq_cnt; } |
