diff options
author | James Smart <james.smart@emulex.com> | 2011-05-24 11:44:12 -0400 |
---|---|---|
committer | James Bottomley <jbottomley@parallels.com> | 2011-05-26 22:49:38 -0500 |
commit | 6d368e532168cb621731b3936945cd910cb25bd0 (patch) | |
tree | 6d49d2dea91c6637ab4cf38b61ec3a0eecc0bdfb /drivers/scsi/lpfc/lpfc_sli.c | |
parent | 52d5244096017bbd11164479116baceaede342b0 (diff) |
[SCSI] lpfc 8.3.24: Add resource extent support
This patch adds support for hardware that returns resource ids via
extents rather than contiguous ranges.
[jejb: checkpatch.pl fixes]
Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <jbottomley@parallels.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_sli.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 1523 |
1 files changed, 1417 insertions, 106 deletions
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index fcfa8c8cfb6..98999bbd8cb 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -459,7 +459,6 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba) struct lpfc_iocbq * iocbq = NULL; list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list); - if (iocbq) phba->iocb_cnt++; if (phba->iocb_cnt > phba->iocb_max) @@ -482,13 +481,10 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba) static struct lpfc_sglq * __lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xritag) { - uint16_t adj_xri; struct lpfc_sglq *sglq; - adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base; - if (adj_xri > phba->sli4_hba.max_cfg_param.max_xri) - return NULL; - sglq = phba->sli4_hba.lpfc_sglq_active_list[adj_xri]; - phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = NULL; + + sglq = phba->sli4_hba.lpfc_sglq_active_list[xritag]; + phba->sli4_hba.lpfc_sglq_active_list[xritag] = NULL; return sglq; } @@ -507,12 +503,9 @@ __lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xritag) struct lpfc_sglq * __lpfc_get_active_sglq(struct lpfc_hba *phba, uint16_t xritag) { - uint16_t adj_xri; struct lpfc_sglq *sglq; - adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base; - if (adj_xri > phba->sli4_hba.max_cfg_param.max_xri) - return NULL; - sglq = phba->sli4_hba.lpfc_sglq_active_list[adj_xri]; + + sglq = phba->sli4_hba.lpfc_sglq_active_list[xritag]; return sglq; } @@ -535,7 +528,6 @@ static 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 adj_xri; struct lpfc_node_rrq *rrq; int empty; uint32_t did = 0; @@ -556,21 +548,19 @@ __lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, /* * set the active bit even if there is no mem available. */ - adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base; - if (NLP_CHK_FREE_REQ(ndlp)) goto out; if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING)) goto out; - if (test_and_set_bit(adj_xri, ndlp->active_rrqs.xri_bitmap)) + 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->xritag = phba->sli4_hba.xri_ids[xritag]; rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1); rrq->ndlp = ndlp; rrq->nlp_DID = ndlp->nlp_DID; @@ -606,7 +596,6 @@ lpfc_clr_rrq_active(struct lpfc_hba *phba, uint16_t xritag, struct lpfc_node_rrq *rrq) { - uint16_t adj_xri; struct lpfc_nodelist *ndlp = NULL; if ((rrq->vport) && NLP_CHK_NODE_ACT(rrq->ndlp)) @@ -622,8 +611,7 @@ lpfc_clr_rrq_active(struct lpfc_hba *phba, if (!ndlp) goto out; - adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base; - if (test_and_clear_bit(adj_xri, 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; @@ -799,12 +787,9 @@ int lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint16_t xritag) { - uint16_t adj_xri; - - adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base; if (!ndlp) return 0; - if (test_bit(adj_xri, ndlp->active_rrqs.xri_bitmap)) + if (test_bit(xritag, ndlp->active_rrqs.xri_bitmap)) return 1; else return 0; @@ -844,7 +829,7 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, * @piocb: Pointer to the iocbq. * * This function is called with hbalock held. This function - * Gets a new driver sglq object from the sglq list. If the + * gets a new driver sglq object from the sglq list. If the * list is not empty then it is successful, it returns pointer to the newly * allocated sglq object else it returns NULL. **/ @@ -854,7 +839,6 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) struct list_head *lpfc_sgl_list = &phba->sli4_hba.lpfc_sgl_list; struct lpfc_sglq *sglq = NULL; struct lpfc_sglq *start_sglq = NULL; - uint16_t adj_xri; struct lpfc_scsi_buf *lpfc_cmd; struct lpfc_nodelist *ndlp; int found = 0; @@ -873,8 +857,6 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) while (!found) { if (!sglq) return NULL; - adj_xri = sglq->sli4_xritag - - phba->sli4_hba.max_cfg_param.xri_base; if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_xritag)) { /* This xri has an rrq outstanding for this DID. * put it back in the list and get another xri. @@ -891,7 +873,7 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) } sglq->ndlp = ndlp; found = 1; - phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = sglq; + phba->sli4_hba.lpfc_sglq_active_list[sglq->sli4_lxritag] = sglq; sglq->state = SGL_ALLOCATED; } return sglq; @@ -947,7 +929,8 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) if (iocbq->sli4_xritag == NO_XRI) sglq = NULL; else - sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag); + sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_lxritag); + if (sglq) { if ((iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) && (sglq->state != SGL_XRI_ABORTED)) { @@ -974,6 +957,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) * Clean all volatile data fields, preserve iotag and node struct. */ memset((char *)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean); + iocbq->sli4_lxritag = NO_XRI; iocbq->sli4_xritag = NO_XRI; list_add_tail(&iocbq->list, &phba->lpfc_iocb_list); } @@ -2116,7 +2100,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) pmb->u.mb.mbxCommand == MBX_REG_LOGIN64 && !pmb->u.mb.mbxStatus) { rpi = pmb->u.mb.un.varWords[0]; - vpi = pmb->u.mb.un.varRegLogin.vpi - phba->vpi_base; + vpi = pmb->u.mb.un.varRegLogin.vpi; lpfc_unreg_login(phba, vpi, rpi, pmb); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); @@ -4323,6 +4307,7 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) continue; } else if (rc) break; + phba->link_state = LPFC_INIT_MBX_CMDS; lpfc_config_port(phba, pmb); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); @@ -4426,7 +4411,8 @@ int lpfc_sli_hba_setup(struct lpfc_hba *phba) { uint32_t rc; - int mode = 3; + int mode = 3, i; + int longs; switch (lpfc_sli_mode) { case 2: @@ -4496,6 +4482,35 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) if (rc) goto lpfc_sli_hba_setup_error; + /* Initialize VPIs. */ + if (phba->sli_rev == LPFC_SLI_REV3) { + /* + * The VPI bitmask and physical ID array are allocated + * and initialized once only - at driver load. A port + * reset doesn't need to reinitialize this memory. + */ + if ((phba->vpi_bmask == NULL) && (phba->vpi_ids == NULL)) { + longs = (phba->max_vpi + BITS_PER_LONG) / BITS_PER_LONG; + phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), + GFP_KERNEL); + if (!phba->vpi_bmask) { + rc = -ENOMEM; + goto lpfc_sli_hba_setup_error; + } + + phba->vpi_ids = kzalloc( + (phba->max_vpi+1) * sizeof(uint16_t), + GFP_KERNEL); + if (!phba->vpi_ids) { + kfree(phba->vpi_bmask); + rc = -ENOMEM; + goto lpfc_sli_hba_setup_error; + } + for (i = 0; i < phba->max_vpi; i++) + phba->vpi_ids[i] = i; + } + } + /* Init HBQs */ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { rc = lpfc_sli_hbq_setup(phba); @@ -4694,6 +4709,803 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) } /** + * lpfc_sli4_get_avail_extnt_rsrc - Get available resource extent count. + * @phba: Pointer to HBA context object. + * @type: The resource extent type. + * + * This function allocates all SLI4 resource identifiers. + **/ +static int +lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type, + uint16_t *extnt_count, uint16_t *extnt_size) +{ + int rc = 0; + uint32_t length; + uint32_t mbox_tmo; + struct lpfc_mbx_get_rsrc_extent_info *rsrc_info; + LPFC_MBOXQ_t *mbox; + + mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + + /* Find out how many extents are available for this resource type */ + length = (sizeof(struct lpfc_mbx_get_rsrc_extent_info) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_GET_RSRC_EXTENT_INFO, + length, LPFC_SLI4_MBX_EMBED); + + /* Send an extents count of 0 - the GET doesn't use it. */ + rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, 0, type, + LPFC_SLI4_MBX_EMBED); + if (unlikely(rc)) { + rc = -EIO; + goto err_exit; + } + + if (!phba->sli4_hba.intr_enable) + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + else { + mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); + rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); + } + if (unlikely(rc)) { + rc = -EIO; + goto err_exit; + } + + rsrc_info = &mbox->u.mqe.un.rsrc_extent_info; + if (bf_get(lpfc_mbox_hdr_status, + &rsrc_info->header.cfg_shdr.response)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, + "2930 Failed to get resource extents " + "Status 0x%x Add'l Status 0x%x\n", + bf_get(lpfc_mbox_hdr_status, + &rsrc_info->header.cfg_shdr.response), + bf_get(lpfc_mbox_hdr_add_status, + &rsrc_info->header.cfg_shdr.response)); + rc = -EIO; + goto err_exit; + } + + *extnt_count = bf_get(lpfc_mbx_get_rsrc_extent_info_cnt, + &rsrc_info->u.rsp); + *extnt_size = bf_get(lpfc_mbx_get_rsrc_extent_info_size, + &rsrc_info->u.rsp); + err_exit: + mempool_free(mbox, phba->mbox_mem_pool); + return rc; +} + +/** + * lpfc_sli4_chk_avail_extnt_rsrc - Check for available SLI4 resource extents. + * @phba: Pointer to HBA context object. + * @type: The extent type to check. + * + * This function reads the current available extents from the port and checks + * if the extent count or extent size has changed since the last access. + * Callers use this routine post port reset to understand if there is a + * extent reprovisioning requirement. + * + * Returns: + * -Error: error indicates problem. + * 1: Extent count or size has changed. + * 0: No changes. + **/ +static int +lpfc_sli4_chk_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type) +{ + uint16_t curr_ext_cnt, rsrc_ext_cnt; + uint16_t size_diff, rsrc_ext_size; + int rc = 0; + struct lpfc_rsrc_blks *rsrc_entry; + struct list_head *rsrc_blk_list = NULL; + + size_diff = 0; + curr_ext_cnt = 0; + rc = lpfc_sli4_get_avail_extnt_rsrc(phba, type, + &rsrc_ext_cnt, + &rsrc_ext_size); + if (unlikely(rc)) + return -EIO; + + switch (type) { + case LPFC_RSC_TYPE_FCOE_RPI: + rsrc_blk_list = &phba->sli4_hba.lpfc_rpi_blk_list; + break; + case LPFC_RSC_TYPE_FCOE_VPI: + rsrc_blk_list = &phba->lpfc_vpi_blk_list; + break; + case LPFC_RSC_TYPE_FCOE_XRI: + rsrc_blk_list = &phba->sli4_hba.lpfc_xri_blk_list; + break; + case LPFC_RSC_TYPE_FCOE_VFI: + rsrc_blk_list = &phba->sli4_hba.lpfc_vfi_blk_list; + break; + default: + break; + } + + list_for_each_entry(rsrc_entry, rsrc_blk_list, list) { + curr_ext_cnt++; + if (rsrc_entry->rsrc_size != rsrc_ext_size) + size_diff++; + } + + if (curr_ext_cnt != rsrc_ext_cnt || size_diff != 0) + rc = 1; + + return rc; +} + +/** + * lpfc_sli4_cfg_post_extnts - + * @phba: Pointer to HBA context object. + * @extnt_cnt - number of available extents. + * @type - the extent type (rpi, xri, vfi, vpi). + * @emb - buffer to hold either MBX_EMBED or MBX_NEMBED operation. + * @mbox - pointer to the caller's allocated mailbox structure. + * + * This function executes the extents allocation request. It also + * takes care of the amount of memory needed to allocate or get the + * allocated extents. It is the caller's responsibility to evaluate + * the response. + * + * Returns: + * -Error: Error value describes the condition found. + * 0: if successful + **/ +static int +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; + uint32_t req_len; + uint32_t emb_len; + uint32_t alloc_len, mbox_tmo; + + /* Calculate the total requested length of the dma memory */ + req_len = *extnt_cnt * sizeof(uint16_t); + + /* + * Calculate the size of an embedded mailbox. The uint32_t + * accounts for extents-specific word. + */ + emb_len = sizeof(MAILBOX_t) - sizeof(struct mbox_header) - + sizeof(uint32_t); + + /* + * Presume the allocation and response will fit into an embedded + * mailbox. If not true, reconfigure to a non-embedded mailbox. + */ + *emb = LPFC_SLI4_MBX_EMBED; + if (req_len > emb_len) { + req_len = *extnt_cnt * sizeof(uint16_t) + + sizeof(union lpfc_sli4_cfg_shdr) + + sizeof(uint32_t); + *emb = LPFC_SLI4_MBX_NEMBED; + } + + alloc_len = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_ALLOC_RSRC_EXTENT, + req_len, *emb); + if (alloc_len < req_len) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "9000 Allocated DMA memory size (x%x) is " + "less than the requested DMA memory " + "size (x%x)\n", alloc_len, req_len); + return -ENOMEM; + } + rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, *extnt_cnt, type, *emb); + if (unlikely(rc)) + return -EIO; + + if (!phba->sli4_hba.intr_enable) + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + else { + mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); + rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); + } + + if (unlikely(rc)) + rc = -EIO; + return rc; +} + +/** + * lpfc_sli4_alloc_extent - Allocate an SLI4 resource extent. + * @phba: Pointer to HBA context object. + * @type: The resource extent type to allocate. + * + * This function allocates the number of elements for the specified + * resource type. + **/ +static int +lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) +{ + bool emb = false; + uint16_t rsrc_id_cnt, rsrc_cnt, rsrc_size; + uint16_t rsrc_id, rsrc_start, j, k; + uint16_t *ids; + int i, rc; + unsigned long longs; + unsigned long *bmask; + struct lpfc_rsrc_blks *rsrc_blks; + LPFC_MBOXQ_t *mbox; + uint32_t length; + struct lpfc_id_range *id_array = NULL; + void *virtaddr = NULL; + struct lpfc_mbx_nembed_rsrc_extent *n_rsrc; + struct lpfc_mbx_alloc_rsrc_extents *rsrc_ext; + struct list_head *ext_blk_list; + + rc = lpfc_sli4_get_avail_extnt_rsrc(phba, type, + &rsrc_cnt, + &rsrc_size); + if (unlikely(rc)) + return -EIO; + + if ((rsrc_cnt == 0) || (rsrc_size == 0)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, + "3009 No available Resource Extents " + "for resource type 0x%x: Count: 0x%x, " + "Size 0x%x\n", type, rsrc_cnt, + rsrc_size); + 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); + + 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); + if (unlikely(rc)) { + rc = -EIO; + goto err_exit; + } + + /* + * Figure out where the response is located. Then get local pointers + * to the response data. The port does not guarantee to respond to + * all extents counts request so update the local variable with the + * allocated count from the port. + */ + if (emb == LPFC_SLI4_MBX_EMBED) { + rsrc_ext = &mbox->u.mqe.un.alloc_rsrc_extents; + id_array = &rsrc_ext->u.rsp.id[0]; + rsrc_cnt = bf_get(lpfc_mbx_rsrc_cnt, &rsrc_ext->u.rsp); + } else { + virtaddr = mbox->sge_array->addr[0]; + n_rsrc = (struct lpfc_mbx_nembed_rsrc_extent *) virtaddr; + rsrc_cnt = bf_get(lpfc_mbx_rsrc_cnt, n_rsrc); + id_array = &n_rsrc->id; + } + + longs = ((rsrc_cnt * rsrc_size) + BITS_PER_LONG - 1) / BITS_PER_LONG; + rsrc_id_cnt = rsrc_cnt * rsrc_size; + + /* + * Based on the resource size and count, correct the base and max + * resource values. + */ + length = sizeof(struct lpfc_rsrc_blks); + switch (type) { + case LPFC_RSC_TYPE_FCOE_RPI: + phba->sli4_hba.rpi_bmask = kzalloc(longs * + sizeof(unsigned long), + GFP_KERNEL); + if (unlikely(!phba->sli4_hba.rpi_bmask)) { + rc = -ENOMEM; + goto err_exit; + } + phba->sli4_hba.rpi_ids = kzalloc(rsrc_id_cnt * + sizeof(uint16_t), + GFP_KERNEL); + if (unlikely(!phba->sli4_hba.rpi_ids)) { + kfree(phba->sli4_hba.rpi_bmask); + rc = -ENOMEM; + goto err_exit; + } + + /* + * The next_rpi was initialized with the maximum available + * count but the port may allocate a smaller number. Catch + * that case and update the next_rpi. + */ + phba->sli4_hba.next_rpi = rsrc_id_cnt; + + /* Initialize local ptrs for common extent processing later. */ + bmask = phba->sli4_hba.rpi_bmask; + ids = phba->sli4_hba.rpi_ids; + ext_blk_list = &phba->sli4_hba.lpfc_rpi_blk_list; + break; + case LPFC_RSC_TYPE_FCOE_VPI: + phba->vpi_bmask = kzalloc(longs * + sizeof(unsigned long), + GFP_KERNEL); + if (unlikely(!phba->vpi_bmask)) { + rc = -ENOMEM; + goto err_exit; + } + phba->vpi_ids = kzalloc(rsrc_id_cnt * + sizeof(uint16_t), + GFP_KERNEL); + if (unlikely(!phba->vpi_ids)) { + kfree(phba->vpi_bmask); + rc = -ENOMEM; + goto err_exit; + } + + /* Initialize local ptrs for common extent processing later. */ + bmask = phba->vpi_bmask; + ids = phba->vpi_ids; + ext_blk_list = &phba->lpfc_vpi_blk_list; + break; + case LPFC_RSC_TYPE_FCOE_XRI: + phba->sli4_hba.xri_bmask = kzalloc(longs * + sizeof(unsigned long), + GFP_KERNEL); + if (unlikely(!phba->sli4_hba.xri_bmask)) { + rc = -ENOMEM; + goto err_exit; + } + phba->sli4_hba.xri_ids = kzalloc(rsrc_id_cnt * + sizeof(uint16_t), + GFP_KERNEL); + if (unlikely(!phba->sli4_hba.xri_ids)) { + kfree(phba->sli4_hba.xri_bmask); + rc = -ENOMEM; + goto err_exit; + } + + /* Initialize local ptrs for common extent processing later. */ + bmask = phba->sli4_hba.xri_bmask; + ids = phba->sli4_hba.xri_ids; + ext_blk_list = &phba->sli4_hba.lpfc_xri_blk_list; + break; + case LPFC_RSC_TYPE_FCOE_VFI: + phba->sli4_hba.vfi_bmask = kzalloc(longs * + sizeof(unsigned long), + GFP_KERNEL); + if (unlikely(!phba->sli4_hba.vfi_bmask)) { + rc = -ENOMEM; + goto err_exit; + } + phba->sli4_hba.vfi_ids = kzalloc(rsrc_id_cnt * + sizeof(uint16_t), + GFP_KERNEL); + if (unlikely(!phba->sli4_hba.vfi_ids)) { + kfree(phba->sli4_hba.vfi_bmask); + rc = -ENOMEM; + goto err_exit; + } + + /* Initialize local ptrs for common extent processing later. */ + bmask = phba->sli4_hba.vfi_bmask; + ids = phba->sli4_hba.vfi_ids; + ext_blk_list = &phba->sli4_hba.lpfc_vfi_blk_list; + break; + default: + /* Unsupported Opcode. Fail call. */ + id_array = NULL; + bmask = NULL; + ids = NULL; + ext_blk_list = NULL; + goto err_exit; + } + + /* + * Complete initializing the extent configuration with the + * allocated ids assigned to this function. The bitmask serves + * as an index into the array and manages the available ids. The + * array just stores the ids communicated to the port via the wqes. + */ + for (i = 0, j = 0, k = 0; i < rsrc_cnt; i++) { + if ((i % 2) == 0) + rsrc_id = bf_get(lpfc_mbx_rsrc_id_word4_0, + &id_array[k]); + else + rsrc_id = bf_get(lpfc_mbx_rsrc_id_word4_1, + &id_array[k]); + + rsrc_blks = kzalloc(length, GFP_KERNEL); + if (unlikely(!rsrc_blks)) { + rc = -ENOMEM; + kfree(bmask); + kfree(ids); + goto err_exit; + } + rsrc_blks->rsrc_start = rsrc_id; + rsrc_blks->rsrc_size = rsrc_size; + list_add_tail(&rsrc_blks->list, ext_blk_list); + rsrc_start = rsrc_id; + if ((type == LPFC_RSC_TYPE_FCOE_XRI) && (j == 0)) + phba->sli4_hba.scsi_xri_start = rsrc_start + + lpfc_sli4_get_els_iocb_cnt(phba); + + while (rsrc_id < (rsrc_start + rsrc_size)) { + ids[j] = rsrc_id; + rsrc_id++; + j++; + } + /* Entire word processed. Get next word.*/ + if ((i % 2) == 1) + k++; + } + err_exit: + lpfc_sli4_mbox_cmd_free(phba, mbox); + return rc; +} + +/** + * lpfc_sli4_dealloc_extent - Deallocate an SLI4 resource extent. + * @phba: Pointer to HBA context object. + * @type: the extent's type. + * + * This function deallocates all extents of a particular resource type. + * SLI4 does not allow for deallocating a particular extent range. It + * is the caller's responsibility to release all kernel memory resources. + **/ +static int +lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type) +{ + int rc; + uint32_t length, mbox_tmo = 0; + LPFC_MBOXQ_t *mbox; + struct lpfc_mbx_dealloc_rsrc_extents *dealloc_rsrc; + struct lpfc_rsrc_blks *rsrc_blk, *rsrc_blk_next; + + mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + + /* + * This function sends an embedded mailbox because it only sends the + * the resource type. All extents of this type are released by the + * port. + */ + length = (sizeof(struct lpfc_mbx_dealloc_rsrc_extents) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_DEALLOC_RSRC_EXTENT, + length, LPFC_SLI4_MBX_EMBED); + + /* Send an extents count of 0 - the dealloc doesn't use it. */ + rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, 0, type, + LPFC_SLI4_MBX_EMBED); + if (unlikely(rc)) { + rc = -EIO; + goto out_free_mbox; + } + if (!phba->sli4_hba.intr_enable) + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + else { + mbox_tmo = lpfc_mbox_tmo_val(phba, mbox_tmo); + rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); + } + if (unlikely(rc)) { + rc = -EIO; + goto out_free_mbox; + } + + dealloc_rsrc = &mbox->u.mqe.un.dealloc_rsrc_extents; + if (bf_get(lpfc_mbox_hdr_status, + &dealloc_rsrc->header.cfg_shdr.response)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, + "2919 Failed to release resource extents " + "for type %d - Status 0x%x Add'l Status 0x%x. " + "Resource memory not released.\n", + type, + bf_get(lpfc_mbox_hdr_status, + &dealloc_rsrc->header.cfg_shdr.response), + bf_get(lpfc_mbox_hdr_add_status, + &dealloc_rsrc->header.cfg_shdr.response)); + rc = -EIO; + goto out_free_mbox; + } + + /* Release kernel memory resources for the specific type. */ + switch (type) { + case LPFC_RSC_TYPE_FCOE_VPI: + kfree(phba->vpi_bmask); + kfree(phba->vpi_ids); + bf_set(lpfc_vpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); + list_for_each_entry_safe(rsrc_blk, rsrc_blk_next, + &phba->lpfc_vpi_blk_list, list) { + list_del_init(&rsrc_blk->list); + kfree(rsrc_blk); + } + 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); + kfree(rsrc_blk); + } + break; + case LPFC_RSC_TYPE_FCOE_VFI: + kfree(phba->sli4_hba.vfi_bmask); + kfree(phba->sli4_hba.vfi_ids); + bf_set(lpfc_vfi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); + list_for_each_entry_safe(rsrc_blk, rsrc_blk_next, + &phba->sli4_hba.lpfc_vfi_blk_list, list) { + list_del_init(&rsrc_blk->list); + kfree(rsrc_blk); + } + break; + case LPFC_RSC_TYPE_FCOE_RPI: + /* RPI bitmask and physical id array are cleaned up earlier. */ + list_for_each_entry_safe(rsrc_blk, rsrc_blk_next, + &phba->sli4_hba.lpfc_rpi_blk_list, list) { + list_del_init(&rsrc_blk->list); + kfree(rsrc_blk); + } + break; + default: + break; + } + + bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); + + out_free_mbox: + mempool_free(mbox, phba->mbox_mem_pool); + return rc; +} + +/** + * lpfc_sli4_alloc_resource_identifiers - Allocate all SLI4 resource extents. + * @phba: Pointer to HBA context object. + * + * This function allocates all SLI4 resource identifiers. + **/ +int +lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) +{ + int i, rc, error = 0; + uint16_t count, base; + unsigned long longs; + + if (phba->sli4_hba.extents_in_use) { + /* + * The port supports resource extents. The XRI, VPI, VFI, RPI + * resource extent count must be read and allocated before + * provisioning the resource id arrays. + */ + if (bf_get(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags) == + LPFC_IDX_RSRC_RDY) { + /* + * Extent-based resources are set - the driver could + * be in a port reset. Figure out if any corrective + * actions need to be taken. + */ + rc = lpfc_sli4_chk_avail_extnt_rsrc(phba, + LPFC_RSC_TYPE_FCOE_VFI); + if (rc != 0) + error++; + rc = lpfc_sli4_chk_avail_extnt_rsrc(phba, + LPFC_RSC_TYPE_FCOE_VPI); + if (rc != 0) + error++; + rc = lpfc_sli4_chk_avail_extnt_rsrc(phba, + LPFC_RSC_TYPE_FCOE_XRI); + if (rc != 0) + error++; + rc = lpfc_sli4_chk_avail_extnt_rsrc(phba, + LPFC_RSC_TYPE_FCOE_RPI); + if (rc != 0) + error++; + + /* + * It's possible that the number of resources + * provided to this port instance changed between + * resets. Detect this condition and reallocate + * resources. Otherwise, there is no action. + */ + if (error) { + lpfc_printf_log(phba, KERN_INFO, + LOG_MBOX | LOG_INIT, + "2931 Detected extent resource " + "change. Reallocating all " + "extents.\n"); + rc = lpfc_sli4_dealloc_extent(phba, + LPFC_RSC_TYPE_FCOE_VFI); + rc = lpfc_sli4_dealloc_extent(phba, + LPFC_RSC_TYPE_FCOE_VPI); + rc = lpfc_sli4_dealloc_extent(phba, + LPFC_RSC_TYPE_FCOE_XRI); + rc = lpfc_sli4_dealloc_extent(phba, + LPFC_RSC_TYPE_FCOE_RPI); + } else + return 0; + } + + rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_VFI); + if (unlikely(rc)) + goto err_exit; + + rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_VPI); + if (unlikely(rc)) + goto err_exit; + + rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_RPI); + if (unlikely(rc)) + goto err_exit; + + rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_XRI); + if (unlikely(rc)) + goto err_exit; + bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags, + LPFC_IDX_RSRC_RDY); + return rc; + } else { + /* + * The port does not support resource extents. The XRI, VPI, + * VFI, RPI resource ids were determined from READ_CONFIG. + * Just allocate the bitmasks and provision the resource id + * arrays. If a port reset is active, the resources don't + * need any action - just exit. + */ + if (bf_get(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags) == + LPFC_IDX_RSRC_RDY) + return 0; + + /* RPIs. */ + count = phba->sli4_hba.max_cfg_param.max_rpi; + 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 * + sizeof(unsigned long), + GFP_KERNEL); + if (unlikely(!phba->sli4_hba.rpi_bmask)) { + rc = -ENOMEM; + goto err_exit; + } + phba->sli4_hba.rpi_ids = kzalloc(count * + sizeof(uint16_t), + GFP_KERNEL); + if (unlikely(!phba->sli4_hba.rpi_ids)) { + rc = -ENOMEM; + goto free_rpi_bmask; + } + + for (i = 0; i < count; i++) + phba->sli4_hba.rpi_ids[i] = base + i; + + /* VPIs. */ + count = phba->sli4_hba.max_cfg_param.max_vpi; + base = phba->sli4_hba.max_cfg_param.vpi_base; + longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; + phba->vpi_bmask = kzalloc(longs * + sizeof(unsigned long), + GFP_KERNEL); + if (unlikely(!phba->vpi_bmask)) { + rc = -ENOMEM; + goto free_rpi_ids; + } + phba->vpi_ids = kzalloc(count * + sizeof(uint16_t), + GFP_KERNEL); + if (unlikely(!phba->vpi_ids)) { + rc = -ENOMEM; + goto free_vpi_bmask; + } + + for (i = 0; i < count; i++) + phba->vpi_ids[i] = base + i; + + /* XRIs. */ + count = phba->sli4_hba.max_cfg_param.max_xri; + 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 * + sizeof(unsigned long), + GFP_KERNEL); + if (unlikely(!phba->sli4_hba.xri_bmask)) { + rc = -ENOMEM; + goto free_vpi_ids; + } + phba->sli4_hba.xri_ids = kzalloc(count * + sizeof(uint16_t), + GFP_KERNEL); + if (unlikely(!phba->sli4_hba.xri_ids)) { + rc = -ENOMEM; + goto free_xri_bmask; + } + + for (i = 0; i < count; i++) + phba->sli4_hba.xri_ids[i] = base + i; + + /* VFIs. */ + count = phba->sli4_hba.max_cfg_param.max_vfi; + 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 * + sizeof(unsigned long), + GFP_KERNEL); + if (unlikely(!phba->sli4_hba.vfi_bmask)) { + rc = -ENOMEM; + goto free_xri_ids; + } + phba->sli4_hba.vfi_ids = kzalloc(count * + sizeof(uint16_t), + GFP_KERNEL); + if (unlikely(!phba->sli4_hba.vfi_ids)) { + rc = -ENOMEM; + goto free_vfi_bmask; + } + + for (i = 0; i < count; i++) + phba->sli4_hba.vfi_ids[i] = base + i; + + /* + * Mark all resources ready. An HBA reset doesn't need + * to reset the initialization. + */ + bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags, + LPFC_IDX_RSRC_RDY); + return 0; + } + + free_vfi_bmask: + kfree(phba->sli4_hba.vfi_bmask); + free_xri_ids: + kfree(phba->sli4_hba.xri_ids); + free_xri_bmask: + kfree(phba->sli4_hba.xri_bmask); + free_vpi_ids: + kfree(phba->vpi_ids); + free_vpi_bmask: + kfree(phba->vpi_bmask); + free_rpi_ids: + kfree(phba->sli4_hba.rpi_ids); + free_rpi_bmask: + kfree(phba->sli4_hba.rpi_bmask); + err_exit: + return rc; +} + +/** + * lpfc_sli4_dealloc_resource_identifiers - Deallocate all SLI4 resource extents. + * @phba: Pointer to HBA context object. + * + * This function allocates the number of elements for the specified + * resource type. + **/ +int +lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba) +{ + if (phba->sli4_hba.extents_in_use) { + lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_VPI); + lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_RPI); + lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_XRI); + lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_VFI); + } else { + kfree(phba->vpi_bmask); + 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); + bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); + } + + return 0; +} + +/** * lpfc_sli4_hba_setup - SLI4 device intialization PCI function * @phba: Pointer to HBA context object. * @@ -4715,10 +5527,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) struct lpfc_vport *vport = phba->pport; struct lpfc_dmabuf *mp; - /* - * TODO: Why does this routine execute these task in a different - * order from probe? - */ /* Perform a PCI function reset to start from clean */ rc = lpfc_pci_function_reset(phba); if (unlikely(rc)) @@ -4880,6 +5688,18 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) phba->sli3_options |= (LPFC_SLI3_NPIV_ENABLED | LPFC_SLI3_HBQ_ENABLED); spin_unlock_irq(&phba->hbalock); + /* + * Allocate all resources (xri,rpi,vpi,vfi) now. Subsequent + * calls depends on these resources to complete port setup. + */ + rc = lpfc_sli4_alloc_resource_identifiers(phba); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "2920 Failed to alloc Resource IDs " + "rc = x%x\n", rc); + goto out_free_mbox; + } + /* Read the port's service parameters. */ rc = lpfc_read_sparam(phba, mboxq, vport->vpi); if (rc) { @@ -4920,19 +5740,30 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn); /* Register SGL pool to the device using non-embedded mailbox command */ - rc = lpfc_sli4_post_sgl_list(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0582 Error %d during sgl post operation\n", - rc); - rc = -ENODEV; - goto out_free_mbox; + 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; + } } /* Register SCSI SGL pool to the device */ rc = lpfc_sli4_repost_scsi_sgl_list(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "0383 Error %d during scsi sgl post " "operation\n", rc); /* Some Scsi buffers were moved to the abort scsi list */ @@ -6479,7 +7310,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, els_id = ((iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK) >> LPFC_FIP_ELS_ID_SHIFT); } - bf_set(wqe_temp_rpi, &wqe->els_req.wqe_com, ndlp->nlp_rpi); + bf_set(wqe_temp_rpi, &wqe->els_req.wqe_com, + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); bf_set(wqe_els_id, &wqe->els_req.wqe_com, els_id); bf_set(wqe_dbde, &wqe->els_req.wqe_com, 1); bf_set(wqe_iod, &wqe->els_req.wqe_com, LPFC_WQE_IOD_READ); @@ -6628,14 +7460,15 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, iocbq->iocb.ulpContext); if (!iocbq->iocb.ulpCt_h && iocbq->iocb.ulpCt_l) bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, - iocbq->vport->vpi + phba->vpi_base); + phba->vpi_ids[iocbq->vport->vpi]); bf_set(wqe_dbde, &wqe->xmit_els_rsp.wqe_com, 1); bf_set(wqe_iod, &wqe->xmit_els_rsp.wqe_com, LPFC_WQE_IOD_WRITE); bf_set(wqe_qosd, &wqe->xmit_els_rsp.wqe_com, 1); bf_set(wqe_lenloc, &wqe->xmit_els_rsp.wqe_com, LPFC_WQE_LENLOC_WORD3); bf_set(wqe_ebde_cnt, &wqe->xmit_els_rsp.wqe_com, 0); - bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp, ndlp->nlp_rpi); + bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp, + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); command_type = OTHER_COMMAND; break; case CMD_CLOSE_XRI_CN: @@ -6734,6 +7567,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, return IOCB_ERROR; break; } + 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; @@ -6781,7 +7615,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, return IOCB_BUSY; } } else { - sglq = __lpfc_sli_get_sglq(phba, piocb); + sglq = __lpfc_sli_get_sglq(phba, piocb); if (!sglq) { if (!(flag & SLI_IOCB_RET_IOCB)) { __lpfc_sli_ringtx_put(phba, @@ -6794,11 +7628,11 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, } } } else if (piocb->iocb_flag & LPFC_IO_FCP) { - sglq = NULL; /* These IO's already have an XRI and - * a mapped sgl. - */ + /* These IO's already have an XRI and a mapped sgl. */ + sglq = NULL; } else { - /* This is a continuation of a commandi,(CX) so this + /* + * 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); @@ -6807,8 +7641,8 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, } if (sglq) { + piocb->sli4_lxritag = sglq->sli4_lxritag; piocb->sli4_xritag = sglq->sli4_xritag; - if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocb, sglq)) return IOCB_ERROR; } @@ -11456,6 +12290,7 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox; int rc; uint32_t shdr_status, shdr_add_status; + uint32_t mbox_tmo; union lpfc_sli4_cfg_shdr *shdr; if (xritag == NO_XRI) { @@ -11489,8 +12324,10 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba, cpu_to_le32(putPaddrHigh(pdma_phys_addr1)); if (!phba->sli4_hba.intr_enable) rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else - rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); + else { + mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); + rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); + } /* The IOCTL status is embedded in the mailbox subheader. */ shdr = (union lpfc_sli4_cfg_shdr *) &post_sgl_pages->header.cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); @@ -11508,6 +12345,76 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba, } /** + * lpfc_sli4_init_rpi_hdrs - Post the rpi header memory region to the port + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to post rpi header templates to the + * port for those SLI4 ports that do not support extents. This routine + * posts a PAGE_SIZE memory region to the port to hold up to + * PAGE_SIZE modulo 64 rpi context headers. This is an initialization routine + * and should be called only when interrupts are disabled. + * + * Return codes + * 0 - successful + * -ERROR - otherwise. + */ +uint16_t +lpfc_sli4_alloc_xri(struct lpfc_hba *phba) +{ + unsigned long xri; + + /* + * Fetch the next logical xri. Because this index is logical, + * the driver starts at 0 each time. + */ + spin_lock_irq(&phba->hbalock); + xri = find_next_zero_bit(phba->sli4_hba.xri_bmask, + phba->sli4_hba.max_cfg_param.max_xri, 0); + if (xri >= phba->sli4_hba.max_cfg_param.max_xri) { + spin_unlock_irq(&phba->hbalock); + return NO_XRI; + } 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; +} + +/** + * lpfc_sli4_free_xri - Release an xri for reuse. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to release an xri to the pool of + * available rpis maintained by the driver. + **/ +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--; + } +} + +/** + * lpfc_sli4_free_xri - Release an xri for reuse. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to release an xri to the pool of + * available rpis maintained by the driver. + **/ +void +lpfc_sli4_free_xri(struct lpfc_hba *phba, int xri) +{ + spin_lock_irq(&phba->hbalock); + __lpfc_sli4_free_xri(phba, xri); + spin_unlock_irq(&phba->hbalock); +} + +/** * lpfc_sli4_next_xritag - Get an xritag for the io * @phba: Pointer to HBA context object. * @@ -11520,30 +12427,23 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba, uint16_t lpfc_sli4_next_xritag(struct lpfc_hba *phba) { - uint16_t xritag; + uint16_t xri_index; - spin_lock_irq(&phba->hbalock); - xritag = phba->sli4_hba.next_xri; - if ((xritag != (uint16_t) -1) && xritag < - (phba->sli4_hba.max_cfg_param.max_xri - + phba->sli4_hba.max_cfg_param.xri_base)) { - phba->sli4_hba.next_xri++; - phba->sli4_hba.max_cfg_param.xri_used++; - spin_unlock_irq(&phba->hbalock); - return xritag; - } - spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + 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", - phba->sli4_hba.next_xri, + xri_index, phba->sli4_hba.max_cfg_param.max_xri, phba->sli4_hba.max_cfg_param.xri_used); - return -1; + return NO_XRI; } /** - * lpfc_sli4_post_sgl_list - post a block of sgl list to the firmware. + * lpfc_sli4_post_els_sgl_list - 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 @@ -11552,7 +12452,7 @@ lpfc_sli4_next_xritag(struct lpfc_hba *phba) * stopped. **/ int -lpfc_sli4_post_sgl_list(struct lpfc_hba *phba) +lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) { struct lpfc_sglq *sglq_entry; struct lpfc_mbx_post_uembed_sgl_page1 *sgl; @@ -11561,7 +12461,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba) LPFC_MBOXQ_t *mbox; uint32_t reqlen, alloclen, pg_pairs; uint32_t mbox_tmo; - uint16_t xritag_start = 0; + uint16_t xritag_start = 0, lxri = 0; int els_xri_cnt, rc = 0; uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; @@ -11578,11 +12478,8 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba) return -ENOMEM; } mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2560 Failed to allocate mbox cmd memory\n"); + 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, @@ -11597,15 +12494,30 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba) 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 */ + viraddr = mbox->sge_array->addr[0]; 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]; + } + /* Set up the sge entry */ sgl_pg_pairs->sgl_pg0_addr_lo = cpu_to_le32(putPaddrLow(sglq_entry->phys)); @@ -11615,16 +12527,17 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba) cpu_to_le32(putPaddrLow(0)); sgl_pg_pairs->sgl_pg1_addr_hi = cpu_to_le32(putPaddrHigh(0)); + /* Keep the first xritag on the list */ if (pg_pairs == 0) xritag_start = sglq_entry->sli4_xritag; sgl_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); - /* 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 { @@ -11643,6 +12556,181 @@ lpfc_sli4_post_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, MBX_SLI4_CONFIG); + 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; } @@ -11703,6 +12791,7 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist, 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]; @@ -11758,6 +12847,169 @@ 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, MBX_SLI4_CONFIG); + 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) @@ -12147,6 +13399,28 @@ lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba, } /** + * lpfc_sli4_xri_inrange - check xri is in range of xris owned by driver. + * @phba: Pointer to HBA context object. + * @xri: xri id in transaction. + * + * This function validates the xri maps to the known range of XRIs allocated an + * used by the driver. + **/ +static uint16_t +lpfc_sli4_xri_inrange(struct lpfc_hba *phba, + uint16_t xri) +{ + int i; + + for (i = 0; i < phba->sli4_hba.max_cfg_param.max_xri; i++) { + if (xri == phba->sli4_hba.xri_ids[i]) + return i; + } + return NO_XRI; +} + + +/** * lpfc_sli4_seq_abort_rsp - bls rsp to sequence abort * @phba: Pointer to HBA context object. * @fc_hdr: pointer to a FC frame header. @@ -12179,9 +13453,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, "SID:x%x\n", oxid, sid); return; } - if (rxid >= phba->sli4_hba.max_cfg_param.xri_base - && rxid <= (phba->sli4_hba.max_cfg_param.max_xri - + phba->sli4_hba.max_cfg_param.xri_base)) + if (lpfc_sli4_xri_inrange(phba, rxid)) lpfc_set_rrq_active(phba, ndlp, rxid, oxid, 0); /* Allocate buffer for rsp iocb */ @@ -12204,12 +13476,13 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, icmd->ulpBdeCount = 0; icmd->ulpLe = 1; icmd->ulpClass = CLASS3; - icmd->ulpContext = ndlp->nlp_rpi; + icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; ctiocb->context1 = ndlp; ctiocb->iocb_cmpl = NULL; ctiocb->vport = phba->pport; ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_rsp_cmpl; + 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, @@ -12390,8 +13663,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS; first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX; first_iocbq->iocb.ulpContext = be16_to_cpu(fc_hdr->fh_ox_id); - first_iocbq->iocb.unsli3.rcvsli3.vpi = - vport->vpi + vport->phba->vpi_base; + /* iocbq is prepped for internal consumption. Logical vpi. */ + first_iocbq->iocb.unsli3.rcvsli3.vpi = vport->vpi; /* put the first buffer into the first IOCBq */ first_iocbq->context2 = &seq_dmabuf->dbuf; first_iocbq->context3 = NULL; @@ -12471,7 +13744,7 @@ lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *vport, &phba->sli.ring[LPFC_ELS_RING], iocbq, fc_hdr->fh_r_ctl, fc_hdr->fh_type)) - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2540 Ring %d handler: unexpected Rctl " "x%x Type x%x received\n", LPFC_ELS_RING, @@ -12568,9 +13841,24 @@ lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *phba) { struct lpfc_rpi_hdr *rpi_page; uint32_t rc = 0; + uint16_t lrpi = 0; + + /* SLI4 ports that support extents do not require RPI headers. */ + if (!phba->sli4_hba.rpi_hdrs_in_use) + goto exit; + if (phba->sli4_hba.extents_in_use) + return -EIO; - /* Post all rpi memory regions to the port. */ list_for_each_entry(rpi_page, &phba->sli4_hba.lpfc_rpi_hdr_list, list) { + /* + * Assign the rpi headers a physical rpi only if the driver + * has not initialized those resources. A port reset only + * needs the headers posted. + */ + if (bf_get(lpfc_rpi_rsrc_rdy, &phba->sli4_hba.sli4_flags) != + LPFC_RPI_RSRC_RDY) + rpi_page->start_rpi = phba->sli4_hba.rpi_ids[lrpi]; + rc = lpfc_sli4_post_rpi_hdr(phba, rpi_page); if (rc != MBX_SUCCESS) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -12581,6 +13869,9 @@ lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *phba) } } + exit: + bf_set(lpfc_rpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, + LPFC_RPI_RSRC_RDY); return rc; } @@ -12604,10 +13895,15 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page) LPFC_MBOXQ_t *mboxq; struct lpfc_mbx_post_hdr_tmpl *hdr_tmpl; uint32_t rc = 0; - uint32_t mbox_tmo; uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; + /* SLI4 ports that support extents do not require RPI headers. */ + if (!phba->sli4_hba.rpi_hdrs_in_use) + return rc; + if (phba->sli4_hba.extents_in_use) + return -EIO; + /* The port is notified of the header region via a mailbox command. */ mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { @@ -12619,16 +13915,19 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page) /* Post all rpi memory regions to the port. */ hdr_tmpl = &mboxq->u.mqe.un.hdr_tmpl; - mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE, LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE, sizeof(struct lpfc_mbx_post_hdr_tmpl) - sizeof(struct lpfc_sli4_cfg_mhdr), LPFC_SLI4_MBX_EMBED); - bf_set(lpfc_mbx_post_hdr_tmpl_page_cnt, - hdr_tmpl, rpi_page->page_count); + + + /* Post the physical rpi to the port for this rpi header. */ bf_set(lpfc_mbx_post_hdr_tmpl_rpi_offset, hdr_tmpl, rpi_page->start_rpi); + bf_set(lpfc_mbx_post_hdr_tmpl_page_cnt, + hdr_tmpl, rpi_page->page_count); + hdr_tmpl->rpi_paddr_lo = putPaddrLow(rpi_page->dmabuf->phys); hdr_tmpl->rpi_paddr_hi = putPaddrHigh(rpi_page->dmabuf->phys); rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); @@ -12663,22 +13962,21 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page) int lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) { - int rpi; - uint16_t max_rpi, rpi_base, rpi_limit; - uint16_t rpi_remaining; + unsigned long rpi; + uint16_t max_rpi, rpi_limit; + uint16_t rpi_remaining, lrpi = 0; struct lpfc_rpi_hdr *rpi_hdr; max_rpi = phba->sli4_hba.max_cfg_param.max_rpi; - rpi_base = phba->sli4_hba.max_cfg_param.rpi_base; rpi_limit = phba->sli4_hba.next_rpi; /* - * The valid rpi range is not guaranteed to be zero-based. Start - * the search at the rpi_base as reported by the port. + * Fetch the next logical rpi. Because this index is logical, + * the driver starts at 0 each time. */ spin_lock_irq(&phba->hbalock); - rpi = find_next_zero_bit(phba->sli4_hba.rpi_bmask, rpi_limit, rpi_base); - if (rpi >= rpi_limit || rpi < rpi_base) + rpi = find_next_zero_bit(phba->sli4_hba.rpi_bmask, rpi_limit, 0); + if (rpi >= rpi_limit) rpi = LPFC_RPI_ALLOC_ERROR; else { set_bit(rpi, phba->sli4_hba.rpi_bmask); @@ -12688,7 +13986,7 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) /* * Don't try to allocate more rpi header regions if the device limit - * on available rpis max has been exhausted. + * has been exhausted. */ if ((rpi == LPFC_RPI_ALLOC_ERROR) && (phba->sli4_hba.rpi_count >= max_rpi)) { @@ -12697,13 +13995,21 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) } /* + * RPI header postings are not required for SLI4 ports capable of + * extents. + */ + if (!phba->sli4_hba.rpi_hdrs_in_use) { + spin_unlock_irq(&phba->hbalock); + return rpi; + } + + /* * If the driver is running low on rpi resources, allocate another * page now. Note that the next_rpi value is used because * it represents how many are actually in use whereas max_rpi notes * how many are supported max by the device. */ - rpi_remaining = phba->sli4_hba.next_rpi - rpi_base - - phba->sli4_hba.rpi_count; + rpi_remaining = phba->sli4_hba.next_rpi - phba->sli4_hba.rpi_count; spin_unlock_irq(&phba->hbalock); if (rpi_remaining < LPFC_RPI_LOW_WATER_MARK) { rpi_hdr = lpfc_sli4_create_rpi_hdr(phba); @@ -12712,6 +14018,8 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) "2002 Error Could not grow rpi " "count\n"); } else { + lrpi = rpi_hdr->start_rpi; + rpi_hdr->start_rpi = phba->sli4_hba.rpi_ids[lrpi]; lpfc_sli4_post_rpi_hdr(phba, rpi_hdr); } } @@ -12761,6 +14069,8 @@ void lpfc_sli4_remove_rpis(struct lpfc_hba *phba) { kfree(phba->sli4_hba.rpi_bmask); + kfree(phba->sli4_hba.rpi_ids); + bf_set(lpfc_rpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); } /** @@ -13744,7 +15054,7 @@ lpfc_drain_txq(struct lpfc_hba *phba) * never happen */ sglq = __lpfc_clear_active_sglq(phba, - sglq->sli4_xritag); + 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 ", @@ -13756,6 +15066,7 @@ lpfc_drain_txq(struct lpfc_hba *phba) /* The xri and iocb resources secured, * attempt to issue request */ + piocbq->sli4_lxritag = sglq->sli4_lxritag; piocbq->sli4_xritag = sglq->sli4_xritag; if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq)) fail_msg = "to convert bpl to sgl"; |