summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_sli.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_sli.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c162
1 files changed, 159 insertions, 3 deletions
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 5b28ea1d72c5..247c24f438f5 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -4714,10 +4714,15 @@ 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.
+ * @extnt_count: buffer to hold port available extent count.
+ * @extnt_size: buffer to hold element count per extent.
*
- * This function allocates all SLI4 resource identifiers.
+ * This function calls the port and retrievs the number of available
+ * extents and their size for a particular extent type.
+ *
+ * Returns: 0 if successful. Nonzero otherwise.
**/
-static int
+int
lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type,
uint16_t *extnt_count, uint16_t *extnt_size)
{
@@ -4894,7 +4899,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt,
req_len, *emb);
if (alloc_len < req_len) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "9000 Allocated DMA memory size (x%x) is "
+ "2982 Allocated DMA memory size (x%x) is "
"less than the requested DMA memory "
"size (x%x)\n", alloc_len, req_len);
return -ENOMEM;
@@ -5508,6 +5513,154 @@ lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba)
}
/**
+ * lpfc_sli4_get_allocated_extnts - Get the port's allocated extents.
+ * @phba: Pointer to HBA context object.
+ * @type: The resource extent type.
+ * @extnt_count: buffer to hold port extent count response
+ * @extnt_size: buffer to hold port extent size response.
+ *
+ * This function calls the port to read the host allocated extents
+ * for a particular type.
+ **/
+int
+lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type,
+ uint16_t *extnt_cnt, uint16_t *extnt_size)
+{
+ bool emb;
+ int rc = 0;
+ uint16_t curr_blks = 0;
+ uint32_t req_len, emb_len;
+ uint32_t alloc_len, mbox_tmo;
+ struct list_head *blk_list_head;
+ struct lpfc_rsrc_blks *rsrc_blk;
+ LPFC_MBOXQ_t *mbox;
+ void *virtaddr = NULL;
+ struct lpfc_mbx_nembed_rsrc_extent *n_rsrc;
+ struct lpfc_mbx_alloc_rsrc_extents *rsrc_ext;
+ union lpfc_sli4_cfg_shdr *shdr;
+
+ switch (type) {
+ case LPFC_RSC_TYPE_FCOE_VPI:
+ blk_list_head = &phba->lpfc_vpi_blk_list;
+ break;
+ case LPFC_RSC_TYPE_FCOE_XRI:
+ blk_list_head = &phba->sli4_hba.lpfc_xri_blk_list;
+ break;
+ case LPFC_RSC_TYPE_FCOE_VFI:
+ blk_list_head = &phba->sli4_hba.lpfc_vfi_blk_list;
+ break;
+ case LPFC_RSC_TYPE_FCOE_RPI:
+ blk_list_head = &phba->sli4_hba.lpfc_rpi_blk_list;
+ break;
+ default:
+ return -EIO;
+ }
+
+ /* Count the number of extents currently allocatd for this type. */
+ list_for_each_entry(rsrc_blk, blk_list_head, list) {
+ if (curr_blks == 0) {
+ /*
+ * The GET_ALLOCATED mailbox does not return the size,
+ * just the count. The size should be just the size
+ * stored in the current allocated block and all sizes
+ * for an extent type are the same so set the return
+ * value now.
+ */
+ *extnt_size = rsrc_blk->rsrc_size;
+ }
+ curr_blks++;
+ }
+
+ /* Calculate the total requested length of the dma memory. */
+ req_len = curr_blks * 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;
+ req_len = emb_len;
+ if (req_len > emb_len) {
+ req_len = curr_blks * sizeof(uint16_t) +
+ sizeof(union lpfc_sli4_cfg_shdr) +
+ sizeof(uint32_t);
+ emb = LPFC_SLI4_MBX_NEMBED;
+ }
+
+ mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ return -ENOMEM;
+ memset(mbox, 0, sizeof(LPFC_MBOXQ_t));
+
+ alloc_len = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+ LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT,
+ req_len, emb);
+ if (alloc_len < req_len) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2983 Allocated DMA memory size (x%x) is "
+ "less than the requested DMA memory "
+ "size (x%x)\n", alloc_len, req_len);
+ rc = -ENOMEM;
+ goto err_exit;
+ }
+ rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, curr_blks, type, emb);
+ 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;
+ }
+
+ /*
+ * 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;
+ shdr = &rsrc_ext->header.cfg_shdr;
+ *extnt_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;
+ shdr = &n_rsrc->cfg_shdr;
+ *extnt_cnt = bf_get(lpfc_mbx_rsrc_cnt, n_rsrc);
+ }
+
+ if (bf_get(lpfc_mbox_hdr_status, &shdr->response)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT,
+ "2984 Failed to read allocated resources "
+ "for type %d - Status 0x%x Add'l Status 0x%x.\n",
+ type,
+ bf_get(lpfc_mbox_hdr_status, &shdr->response),
+ bf_get(lpfc_mbox_hdr_add_status, &shdr->response));
+ rc = -EIO;
+ goto err_exit;
+ }
+ err_exit:
+ lpfc_sli4_mbox_cmd_free(phba, mbox);
+ return rc;
+}
+
+/**
* lpfc_sli4_hba_setup - SLI4 device intialization PCI function
* @phba: Pointer to HBA context object.
*
@@ -6637,6 +6790,9 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
unsigned long iflags;
int rc;
+ /* dump from issue mailbox command if setup */
+ lpfc_idiag_mbxacc_dump_issue_mbox(phba, &mboxq->u.mb);
+
rc = lpfc_mbox_dev_check(phba);
if (unlikely(rc)) {
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,