diff options
author | James Smart <james.smart@emulex.com> | 2012-05-09 21:16:12 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-05-17 10:29:22 +0100 |
commit | 8a9d2e8003040d2e1cd24ac5e83bb30b68f7f488 (patch) | |
tree | a0fb34a954b174681a7af4706dee3823db4260ce /drivers/scsi/lpfc | |
parent | 587a37f6e007e97e4f88f10a51f5d0bc62eb6e0a (diff) |
[SCSI] lpfc 8.3.31: Correct handling of SLI4-port XRI resource-provisioning profile change
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')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 7 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 10 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 367 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 296 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 607 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 9 |
6 files changed, 594 insertions, 702 deletions
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 330dd7192a7f..620fa45866dc 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -460,6 +460,7 @@ int lpfc_hba_init_link_fc_topology(struct lpfc_hba *, uint32_t, uint32_t); int lpfc_issue_reg_vfi(struct lpfc_vport *); int lpfc_issue_unreg_vfi(struct lpfc_vport *); int lpfc_selective_reset(struct lpfc_hba *); -int lpfc_sli4_read_config(struct lpfc_hba *phba); -int lpfc_scsi_buf_update(struct lpfc_hba *phba); -void lpfc_sli4_node_prep(struct lpfc_hba *phba); +int lpfc_sli4_read_config(struct lpfc_hba *); +void lpfc_sli4_node_prep(struct lpfc_hba *); +int lpfc_sli4_xri_sgl_update(struct lpfc_hba *); +void lpfc_free_sgl_list(struct lpfc_hba *, struct list_head *); diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 91f09761bd32..24344c1fab5a 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -228,19 +228,15 @@ struct lpfc_sli4_flags { #define lpfc_idx_rsrc_rdy_MASK 0x00000001 #define lpfc_idx_rsrc_rdy_WORD word0 #define LPFC_IDX_RSRC_RDY 1 -#define lpfc_xri_rsrc_rdy_SHIFT 1 -#define lpfc_xri_rsrc_rdy_MASK 0x00000001 -#define lpfc_xri_rsrc_rdy_WORD word0 -#define LPFC_XRI_RSRC_RDY 1 -#define lpfc_rpi_rsrc_rdy_SHIFT 2 +#define lpfc_rpi_rsrc_rdy_SHIFT 1 #define lpfc_rpi_rsrc_rdy_MASK 0x00000001 #define lpfc_rpi_rsrc_rdy_WORD word0 #define LPFC_RPI_RSRC_RDY 1 -#define lpfc_vpi_rsrc_rdy_SHIFT 3 +#define lpfc_vpi_rsrc_rdy_SHIFT 2 #define lpfc_vpi_rsrc_rdy_MASK 0x00000001 #define lpfc_vpi_rsrc_rdy_WORD word0 #define LPFC_VPI_RSRC_RDY 1 -#define lpfc_vfi_rsrc_rdy_SHIFT 4 +#define lpfc_vfi_rsrc_rdy_SHIFT 3 #define lpfc_vfi_rsrc_rdy_MASK 0x00000001 #define lpfc_vfi_rsrc_rdy_WORD word0 #define LPFC_VFI_RSRC_RDY 1 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 5538cd068611..411ed48d79da 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -64,8 +64,8 @@ static int lpfc_sli4_queue_verify(struct lpfc_hba *); static int lpfc_create_bootstrap_mbox(struct lpfc_hba *); static int lpfc_setup_endian_order(struct lpfc_hba *); static void lpfc_destroy_bootstrap_mbox(struct lpfc_hba *); -static void lpfc_free_sgl_list(struct lpfc_hba *); -static int lpfc_init_sgl_list(struct lpfc_hba *); +static void lpfc_free_els_sgl_list(struct lpfc_hba *); +static void lpfc_init_sgl_list(struct lpfc_hba *); static int lpfc_init_active_sgl_array(struct lpfc_hba *); static void lpfc_free_active_sgl(struct lpfc_hba *); static int lpfc_hba_down_post_s3(struct lpfc_hba *phba); @@ -2767,47 +2767,14 @@ lpfc_offline(struct lpfc_hba *phba) } /** - * lpfc_scsi_buf_update - Update the scsi_buffers that are already allocated. - * @phba: pointer to lpfc hba data structure. - * - * This routine goes through all the scsi buffers in the system and updates the - * Physical XRIs assigned to the SCSI buffer because these may change after any - * firmware reset - * - * Return codes - * 0 - successful (for now, it always returns 0) - **/ -int -lpfc_scsi_buf_update(struct lpfc_hba *phba) -{ - struct lpfc_scsi_buf *sb, *sb_next; - - spin_lock_irq(&phba->hbalock); - spin_lock(&phba->scsi_buf_list_lock); - list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) { - sb->cur_iocbq.sli4_xritag = - phba->sli4_hba.xri_ids[sb->cur_iocbq.sli4_lxritag]; - set_bit(sb->cur_iocbq.sli4_lxritag, phba->sli4_hba.xri_bmask); - phba->sli4_hba.max_cfg_param.xri_used++; - phba->sli4_hba.xri_count++; - } - spin_unlock(&phba->scsi_buf_list_lock); - spin_unlock_irq(&phba->hbalock); - return 0; -} - -/** * lpfc_scsi_free - Free all the SCSI buffers and IOCBs from driver lists * @phba: pointer to lpfc hba data structure. * * This routine is to free all the SCSI buffers and IOCBs from the driver * list back to kernel. It is called from lpfc_pci_remove_one to free * the internal resources before the device is removed from the system. - * - * Return codes - * 0 - successful (for now, it always returns 0) **/ -static int +static void lpfc_scsi_free(struct lpfc_hba *phba) { struct lpfc_scsi_buf *sb, *sb_next; @@ -2833,7 +2800,178 @@ lpfc_scsi_free(struct lpfc_hba *phba) } spin_unlock_irq(&phba->hbalock); +} + +/** + * lpfc_sli4_xri_sgl_update - update xri-sgl sizing and mapping + * @phba: pointer to lpfc hba data structure. + * + * This routine first calculates the sizes of the current els and allocated + * scsi sgl lists, and then goes through all sgls to updates the physical + * XRIs assigned due to port function reset. During port initialization, the + * current els and allocated scsi sgl lists are 0s. + * + * Return codes + * 0 - successful (for now, it always returns 0) + **/ +int +lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba) +{ + struct lpfc_sglq *sglq_entry = NULL, *sglq_entry_next = NULL; + struct lpfc_scsi_buf *psb = NULL, *psb_next = NULL; + uint16_t i, lxri, xri_cnt, els_xri_cnt, scsi_xri_cnt; + LIST_HEAD(els_sgl_list); + LIST_HEAD(scsi_sgl_list); + int rc; + + /* + * update on pci function's els xri-sgl list + */ + els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); + if (els_xri_cnt > phba->sli4_hba.els_xri_cnt) { + /* els xri-sgl expanded */ + xri_cnt = els_xri_cnt - phba->sli4_hba.els_xri_cnt; + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3157 ELS xri-sgl count increased from " + "%d to %d\n", phba->sli4_hba.els_xri_cnt, + els_xri_cnt); + /* allocate the additional els sgls */ + for (i = 0; i < xri_cnt; i++) { + sglq_entry = kzalloc(sizeof(struct lpfc_sglq), + GFP_KERNEL); + if (sglq_entry == NULL) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2562 Failure to allocate an " + "ELS sgl entry:%d\n", i); + rc = -ENOMEM; + goto out_free_mem; + } + sglq_entry->buff_type = GEN_BUFF_TYPE; + sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, + &sglq_entry->phys); + if (sglq_entry->virt == NULL) { + kfree(sglq_entry); + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2563 Failure to allocate an " + "ELS mbuf:%d\n", i); + rc = -ENOMEM; + goto out_free_mem; + } + sglq_entry->sgl = sglq_entry->virt; + memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE); + sglq_entry->state = SGL_FREED; + list_add_tail(&sglq_entry->list, &els_sgl_list); + } + spin_lock(&phba->hbalock); + list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list); + spin_unlock(&phba->hbalock); + } else if (els_xri_cnt < phba->sli4_hba.els_xri_cnt) { + /* els xri-sgl shrinked */ + xri_cnt = phba->sli4_hba.els_xri_cnt - els_xri_cnt; + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3158 ELS xri-sgl count decreased from " + "%d to %d\n", phba->sli4_hba.els_xri_cnt, + els_xri_cnt); + spin_lock_irq(&phba->hbalock); + list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &els_sgl_list); + spin_unlock_irq(&phba->hbalock); + /* release extra els sgls from list */ + for (i = 0; i < xri_cnt; i++) { + list_remove_head(&els_sgl_list, + sglq_entry, struct lpfc_sglq, list); + if (sglq_entry) { + lpfc_mbuf_free(phba, sglq_entry->virt, + sglq_entry->phys); + kfree(sglq_entry); + } + } + spin_lock_irq(&phba->hbalock); + list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list); + spin_unlock_irq(&phba->hbalock); + } else + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3163 ELS xri-sgl count unchanged: %d\n", + els_xri_cnt); + phba->sli4_hba.els_xri_cnt = els_xri_cnt; + + /* update xris to els sgls on the list */ + sglq_entry = NULL; + sglq_entry_next = NULL; + list_for_each_entry_safe(sglq_entry, sglq_entry_next, + &phba->sli4_hba.lpfc_sgl_list, list) { + lxri = lpfc_sli4_next_xritag(phba); + if (lxri == NO_XRI) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2400 Failed to allocate xri for " + "ELS sgl\n"); + rc = -ENOMEM; + goto out_free_mem; + } + sglq_entry->sli4_lxritag = lxri; + sglq_entry->sli4_xritag = phba->sli4_hba.xri_ids[lxri]; + } + + /* + * update on pci function's allocated scsi xri-sgl list + */ + phba->total_scsi_bufs = 0; + + /* maximum number of xris available for scsi buffers */ + phba->sli4_hba.scsi_xri_max = phba->sli4_hba.max_cfg_param.max_xri - + els_xri_cnt; + + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2401 Current allocated SCSI xri-sgl count:%d, " + "maximum SCSI xri count:%d\n", + phba->sli4_hba.scsi_xri_cnt, + phba->sli4_hba.scsi_xri_max); + + spin_lock_irq(&phba->scsi_buf_list_lock); + list_splice_init(&phba->lpfc_scsi_buf_list, &scsi_sgl_list); + spin_unlock_irq(&phba->scsi_buf_list_lock); + + if (phba->sli4_hba.scsi_xri_cnt > phba->sli4_hba.scsi_xri_max) { + /* max scsi xri shrinked below the allocated scsi buffers */ + scsi_xri_cnt = phba->sli4_hba.scsi_xri_cnt - + phba->sli4_hba.scsi_xri_max; + /* release the extra allocated scsi buffers */ + for (i = 0; i < scsi_xri_cnt; i++) { + list_remove_head(&scsi_sgl_list, psb, + struct lpfc_scsi_buf, list); + pci_pool_free(phba->lpfc_scsi_dma_buf_pool, psb->data, + psb->dma_handle); + kfree(psb); + } + spin_lock_irq(&phba->scsi_buf_list_lock); + phba->sli4_hba.scsi_xri_cnt -= scsi_xri_cnt; + spin_unlock_irq(&phba->scsi_buf_list_lock); + } + + /* update xris associated to remaining allocated scsi buffers */ + psb = NULL; + psb_next = NULL; + list_for_each_entry_safe(psb, psb_next, &scsi_sgl_list, list) { + lxri = lpfc_sli4_next_xritag(phba); + if (lxri == NO_XRI) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2560 Failed to allocate xri for " + "scsi buffer\n"); + rc = -ENOMEM; + goto out_free_mem; + } + psb->cur_iocbq.sli4_lxritag = lxri; + psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri]; + } + spin_lock(&phba->scsi_buf_list_lock); + list_splice_init(&scsi_sgl_list, &phba->lpfc_scsi_buf_list); + spin_unlock(&phba->scsi_buf_list_lock); + return 0; + +out_free_mem: + lpfc_free_els_sgl_list(phba); + lpfc_scsi_free(phba); + return rc; } /** @@ -4636,18 +4774,15 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) if (rc) goto out_free_bsmbx; - /* Initialize and populate the iocb list per host */ - rc = lpfc_init_sgl_list(phba); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1400 Failed to initialize sgl list.\n"); - goto out_destroy_cq_event_pool; - } + /* Initialize sgl lists per host */ + lpfc_init_sgl_list(phba); + + /* Allocate and initialize active sgl array */ rc = lpfc_init_active_sgl_array(phba); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "1430 Failed to initialize sgl list.\n"); - goto out_free_sgl_list; + goto out_destroy_cq_event_pool; } rc = lpfc_sli4_init_rpi_hdrs(phba); if (rc) { @@ -4722,8 +4857,6 @@ out_remove_rpi_hdrs: lpfc_sli4_remove_rpi_hdrs(phba); out_free_active_sgl: lpfc_free_active_sgl(phba); -out_free_sgl_list: - lpfc_free_sgl_list(phba); out_destroy_cq_event_pool: lpfc_sli4_cq_event_pool_destroy(phba); out_free_bsmbx: @@ -4760,10 +4893,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) /* Free the ELS sgl list */ lpfc_free_active_sgl(phba); - lpfc_free_sgl_list(phba); - - /* Free the SCSI sgl management array */ - kfree(phba->sli4_hba.lpfc_scsi_psb_array); + lpfc_free_els_sgl_list(phba); /* Free the completion queue EQ event pool */ lpfc_sli4_cq_event_release_all(phba); @@ -4990,29 +5120,42 @@ out_free_iocbq: } /** - * lpfc_free_sgl_list - Free sgl list. + * lpfc_free_sgl_list - Free a given sgl list. * @phba: pointer to lpfc hba data structure. + * @sglq_list: pointer to the head of sgl list. * - * This routine is invoked to free the driver's sgl list and memory. + * This routine is invoked to free a give sgl list and memory. **/ -static void -lpfc_free_sgl_list(struct lpfc_hba *phba) +void +lpfc_free_sgl_list(struct lpfc_hba *phba, struct list_head *sglq_list) { struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; + + list_for_each_entry_safe(sglq_entry, sglq_next, sglq_list, list) { + list_del(&sglq_entry->list); + lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys); + kfree(sglq_entry); + } +} + +/** + * lpfc_free_els_sgl_list - Free els sgl list. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to free the driver's els sgl list and memory. + **/ +static void +lpfc_free_els_sgl_list(struct lpfc_hba *phba) +{ LIST_HEAD(sglq_list); + /* Retrieve all els sgls from driver list */ spin_lock_irq(&phba->hbalock); list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &sglq_list); spin_unlock_irq(&phba->hbalock); - list_for_each_entry_safe(sglq_entry, sglq_next, - &sglq_list, list) { - list_del(&sglq_entry->list); - lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys); - kfree(sglq_entry); - phba->sli4_hba.total_sglq_bufs--; - } - kfree(phba->sli4_hba.lpfc_els_sgl_array); + /* Now free the sgl list */ + lpfc_free_sgl_list(phba, &sglq_list); } /** @@ -5057,99 +5200,19 @@ lpfc_free_active_sgl(struct lpfc_hba *phba) * This routine is invoked to allocate and initizlize the driver's sgl * list and set up the sgl xritag tag array accordingly. * - * Return codes - * 0 - successful - * other values - error **/ -static int +static void lpfc_init_sgl_list(struct lpfc_hba *phba) { - struct lpfc_sglq *sglq_entry = NULL; - int i; - int els_xri_cnt; - - els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2400 ELS XRI count %d.\n", - els_xri_cnt); /* Initialize and populate the sglq list per host/VF. */ INIT_LIST_HEAD(&phba->sli4_hba.lpfc_sgl_list); INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_els_sgl_list); - /* Sanity check on XRI management */ - if (phba->sli4_hba.max_cfg_param.max_xri <= els_xri_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2562 No room left for SCSI XRI allocation: " - "max_xri=%d, els_xri=%d\n", - phba->sli4_hba.max_cfg_param.max_xri, - els_xri_cnt); - return -ENOMEM; - } - - /* Allocate memory for the ELS XRI management array */ - phba->sli4_hba.lpfc_els_sgl_array = - kzalloc((sizeof(struct lpfc_sglq *) * els_xri_cnt), - GFP_KERNEL); + /* els xri-sgl book keeping */ + phba->sli4_hba.els_xri_cnt = 0; - if (!phba->sli4_hba.lpfc_els_sgl_array) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2401 Failed to allocate memory for ELS " - "XRI management array of size %d.\n", - els_xri_cnt); - return -ENOMEM; - } - - /* Keep the SCSI XRI into the XRI management array */ - phba->sli4_hba.scsi_xri_max = - phba->sli4_hba.max_cfg_param.max_xri - els_xri_cnt; + /* scsi xri-buffer book keeping */ phba->sli4_hba.scsi_xri_cnt = 0; - phba->sli4_hba.lpfc_scsi_psb_array = - kzalloc((sizeof(struct lpfc_scsi_buf *) * - phba->sli4_hba.scsi_xri_max), GFP_KERNEL); - - if (!phba->sli4_hba.lpfc_scsi_psb_array) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2563 Failed to allocate memory for SCSI " - "XRI management array of size %d.\n", - phba->sli4_hba.scsi_xri_max); - kfree(phba->sli4_hba.lpfc_els_sgl_array); - return -ENOMEM; - } - - for (i = 0; i < els_xri_cnt; i++) { - sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL); - if (sglq_entry == NULL) { - printk(KERN_ERR "%s: only allocated %d sgls of " - "expected %d count. Unloading driver.\n", - __func__, i, els_xri_cnt); - goto out_free_mem; - } - - sglq_entry->buff_type = GEN_BUFF_TYPE; - sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, &sglq_entry->phys); - if (sglq_entry->virt == NULL) { - kfree(sglq_entry); - printk(KERN_ERR "%s: failed to allocate mbuf.\n" - "Unloading driver.\n", __func__); - goto out_free_mem; - } - sglq_entry->sgl = sglq_entry->virt; - memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE); - - /* The list order is used by later block SGL registraton */ - spin_lock_irq(&phba->hbalock); - sglq_entry->state = SGL_FREED; - list_add_tail(&sglq_entry->list, &phba->sli4_hba.lpfc_sgl_list); - phba->sli4_hba.lpfc_els_sgl_array[i] = sglq_entry; - phba->sli4_hba.total_sglq_bufs++; - spin_unlock_irq(&phba->hbalock); - } - return 0; - -out_free_mem: - kfree(phba->sli4_hba.lpfc_scsi_psb_array); - lpfc_free_sgl_list(phba); - return -ENOMEM; } /** @@ -7320,9 +7383,11 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) phba->sli4_hba.u.if_type2.ERR2regaddr); lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2890 Port error detected during port " - "reset(%d): port status reg 0x%x, " + "reset(%d): wait_tmo:%d ms, " + "port status reg 0x%x, " "error 1=0x%x, error 2=0x%x\n", - num_resets, reg_data.word0, + num_resets, rdy_chk*10, + reg_data.word0, phba->work_status[0], phba->work_status[1]); rc = -ENODEV; @@ -9118,8 +9183,12 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba) return 50; else if (max_xri <= 1024) return 100; - else + else if (max_xri <= 1536) return 150; + else if (max_xri <= 2048) + return 200; + else + return 250; } else return 0; } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 88f3a83dbd2e..bf0048a7a302 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -718,72 +718,162 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, } /** - * lpfc_sli4_repost_scsi_sgl_list - Repsot the Scsi buffers sgl pages as block + * lpfc_sli4_post_scsi_sgl_list - Psot blocks of scsi buffer sgls from a list * @phba: pointer to lpfc hba data structure. + * @post_sblist: pointer to the scsi buffer list. * - * This routine walks the list of scsi buffers that have been allocated and - * repost them to the HBA by using SGL block post. This is needed after a - * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine - * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list - * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers. + * This routine walks a list of scsi buffers that was passed in. It attempts + * to construct blocks of scsi buffer sgls which contains contiguous xris and + * uses the non-embedded SGL block post mailbox commands to post to the port. + * For single SCSI buffer sgl with non-contiguous xri, if any, it shall use + * embedded SGL post mailbox command for posting. The @post_sblist passed in + * must be local list, thus no lock is needed when manipulate the list. * - * Returns: 0 = success, non-zero failure. + * Returns: 0 = failure, non-zero number of successfully posted buffers. **/ int -lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) +lpfc_sli4_post_scsi_sgl_list(struct lpfc_hba *phba, + struct list_head *post_sblist, int sb_count) { - struct lpfc_scsi_buf *psb; - int index, status, bcnt = 0, rcnt = 0, rc = 0; - LIST_HEAD(sblist); - - for (index = 0; index < phba->sli4_hba.scsi_xri_cnt; index++) { - psb = phba->sli4_hba.lpfc_scsi_psb_array[index]; - if (psb) { - /* Remove from SCSI buffer list */ - list_del(&psb->list); - /* Add it to a local SCSI buffer list */ - list_add_tail(&psb->list, &sblist); - if (++rcnt == LPFC_NEMBED_MBOX_SGL_CNT) { - bcnt = rcnt; - rcnt = 0; + struct lpfc_scsi_buf *psb, *psb_next; + int status; + int post_cnt = 0, block_cnt = 0, num_posting = 0, num_posted = 0; + dma_addr_t pdma_phys_bpl1; + int last_xritag = NO_XRI; + LIST_HEAD(prep_sblist); + LIST_HEAD(blck_sblist); + LIST_HEAD(scsi_sblist); + + /* sanity check */ + if (sb_count <= 0) + return -EINVAL; + + list_for_each_entry_safe(psb, psb_next, post_sblist, list) { + list_del_init(&psb->list); + block_cnt++; + if ((last_xritag != NO_XRI) && + (psb->cur_iocbq.sli4_xritag != last_xritag + 1)) { + /* a hole in xri block, form a sgl posting block */ + list_splice_init(&prep_sblist, &blck_sblist); + post_cnt = block_cnt - 1; + /* prepare list for next posting block */ + list_add_tail(&psb->list, &prep_sblist); + block_cnt = 1; + } else { + /* prepare list for next posting block */ + list_add_tail(&psb->list, &prep_sblist); + /* enough sgls for non-embed sgl mbox command */ + if (block_cnt == LPFC_NEMBED_MBOX_SGL_CNT) { + list_splice_init(&prep_sblist, &blck_sblist); + post_cnt = block_cnt; + block_cnt = 0; } - } else - /* A hole present in the XRI array, need to skip */ - bcnt = rcnt; + } + num_posting++; + last_xritag = psb->cur_iocbq.sli4_xritag; - if (index == phba->sli4_hba.scsi_xri_cnt - 1) - /* End of XRI array for SCSI buffer, complete */ - bcnt = rcnt; + /* end of repost sgl list condition for SCSI buffers */ + if (num_posting == sb_count) { + if (post_cnt == 0) { + /* last sgl posting block */ + list_splice_init(&prep_sblist, &blck_sblist); + post_cnt = block_cnt; + } else if (block_cnt == 1) { + /* last single sgl with non-contiguous xri */ + 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; + status = lpfc_sli4_post_sgl(phba, + psb->dma_phys_bpl, + pdma_phys_bpl1, + psb->cur_iocbq.sli4_xritag); + if (status) { + /* failure, put on abort scsi list */ + psb->exch_busy = 1; + } else { + /* success, put on SCSI buffer list */ + psb->exch_busy = 0; + psb->status = IOSTAT_SUCCESS; + num_posted++; + } + /* success, put on SCSI buffer sgl list */ + list_add_tail(&psb->list, &scsi_sblist); + } + } - /* Continue until collect up to a nembed page worth of sgls */ - if (bcnt == 0) + /* continue until a nembed page worth of sgls */ + if (post_cnt == 0) continue; - /* Now, post the SCSI buffer list sgls as a block */ - if (!phba->sli4_hba.extents_in_use) - status = lpfc_sli4_post_scsi_sgl_block(phba, - &sblist, - bcnt); - else - status = lpfc_sli4_post_scsi_sgl_blk_ext(phba, - &sblist, - bcnt); - /* Reset SCSI buffer count for next round of posting */ - bcnt = 0; - while (!list_empty(&sblist)) { - list_remove_head(&sblist, psb, struct lpfc_scsi_buf, - list); + + /* post block of SCSI buffer list sgls */ + status = lpfc_sli4_post_scsi_sgl_block(phba, &blck_sblist, + post_cnt); + + /* don't reset xirtag due to hole in xri block */ + if (block_cnt == 0) + last_xritag = NO_XRI; + + /* reset SCSI buffer post count for next round of posting */ + post_cnt = 0; + + /* put posted SCSI buffer-sgl posted on SCSI buffer sgl list */ + while (!list_empty(&blck_sblist)) { + list_remove_head(&blck_sblist, psb, + struct lpfc_scsi_buf, list); if (status) { - /* Put this back on the abort scsi list */ + /* failure, put on abort scsi list */ psb->exch_busy = 1; - rc++; } else { + /* success, put on SCSI buffer list */ psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; + num_posted++; } - /* Put it back into the SCSI buffer list */ - lpfc_release_scsi_buf_s4(phba, psb); + list_add_tail(&psb->list, &scsi_sblist); } } + /* Push SCSI buffers with sgl posted to the availble list */ + while (!list_empty(&scsi_sblist)) { + list_remove_head(&scsi_sblist, psb, + struct lpfc_scsi_buf, list); + lpfc_release_scsi_buf_s4(phba, psb); + } + return num_posted; +} + +/** + * lpfc_sli4_repost_scsi_sgl_list - Repsot all the allocated scsi buffer sgls + * @phba: pointer to lpfc hba data structure. + * + * This routine walks the list of scsi 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. The lpfc_hba_down_post_s4 routine + * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list + * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers. + * + * Returns: 0 = success, non-zero failure. + **/ +int +lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) +{ + LIST_HEAD(post_sblist); + int num_posted, rc = 0; + + /* get all SCSI buffers need to repost to a local list */ + spin_lock(&phba->scsi_buf_list_lock); + list_splice_init(&phba->lpfc_scsi_buf_list, &post_sblist); + spin_unlock(&phba->scsi_buf_list_lock); + + /* post the list of scsi buffer sgls to port if available */ + if (!list_empty(&post_sblist)) { + num_posted = lpfc_sli4_post_scsi_sgl_list(phba, &post_sblist, + phba->sli4_hba.scsi_xri_cnt); + /* failed to post any scsi buffer, return error */ + if (num_posted == 0) + rc = -EIO; + } return rc; } @@ -792,12 +882,13 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) * @vport: The virtual port for which this call being executed. * @num_to_allocate: The requested number of buffers to allocate. * - * This routine allocates a scsi buffer for device with SLI-4 interface spec, + * This routine allocates scsi buffers for device with SLI-4 interface spec, * the scsi buffer contains all the necessary information needed to initiate - * a SCSI I/O. + * a SCSI I/O. After allocating up to @num_to_allocate SCSI buffers and put + * them on a list, it post them to the port by using SGL block post. * * Return codes: - * int - number of scsi buffers that were allocated. + * int - number of scsi buffers that were allocated and posted. * 0 = failure, less than num_to_alloc is a partial failure. **/ static int @@ -810,22 +901,21 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) dma_addr_t pdma_phys_fcp_cmd; dma_addr_t pdma_phys_fcp_rsp; dma_addr_t pdma_phys_bpl, pdma_phys_bpl1; - uint16_t iotag, last_xritag = NO_XRI, lxri = 0; - int status = 0, index; - int bcnt; - int non_sequential_xri = 0; - LIST_HEAD(sblist); + uint16_t iotag, lxri = 0; + int bcnt, num_posted; + LIST_HEAD(prep_sblist); + LIST_HEAD(post_sblist); + LIST_HEAD(scsi_sblist); for (bcnt = 0; bcnt < num_to_alloc; bcnt++) { psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); if (!psb) break; - /* - * Get memory from the pci pool to map the virt space to pci bus - * space for an I/O. The DMA buffer includes space for the - * struct fcp_cmnd, struct fcp_rsp and the number of bde's - * necessary to support the sg_tablesize. + * Get memory from the pci pool to map the virt space to + * pci bus space for an I/O. The DMA buffer includes space + * for the struct fcp_cmnd, struct fcp_rsp and the number + * of bde's necessary to support the sg_tablesize. */ psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool, GFP_KERNEL, &psb->dma_handle); @@ -833,8 +923,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) kfree(psb); break; } - - /* Initialize virtual ptrs to dma_buf region. */ memset(psb->data, 0, phba->cfg_sg_dma_buf_size); /* Allocate iotag for psb->cur_iocbq. */ @@ -855,16 +943,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) } psb->cur_iocbq.sli4_lxritag = lxri; psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri]; - if (last_xritag != NO_XRI - && psb->cur_iocbq.sli4_xritag != (last_xritag+1)) { - non_sequential_xri = 1; - } else - list_add_tail(&psb->list, &sblist); - last_xritag = psb->cur_iocbq.sli4_xritag; - - index = phba->sli4_hba.scsi_xri_cnt++; psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP; - psb->fcp_bpl = psb->data; psb->fcp_cmnd = (psb->data + phba->cfg_sg_dma_buf_size) - (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp)); @@ -880,9 +959,9 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd); /* - * The first two bdes are the FCP_CMD and FCP_RSP. The balance - * are sg list bdes. Initialize the first two and leave the - * rest for queuecommand. + * The first two bdes are the FCP_CMD and FCP_RSP. + * The balance are sg list bdes. Initialize the + * first two and leave the rest for queuecommand. */ sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd)); sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd)); @@ -917,62 +996,31 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) iocb->ulpBdeCount = 1; iocb->ulpLe = 1; iocb->ulpClass = CLASS3; - psb->cur_iocbq.context1 = psb; + psb->cur_iocbq.context1 = psb; if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) pdma_phys_bpl1 = pdma_phys_bpl + SGL_PAGE_SIZE; else pdma_phys_bpl1 = 0; psb->dma_phys_bpl = pdma_phys_bpl; - phba->sli4_hba.lpfc_scsi_psb_array[index] = psb; - if (non_sequential_xri) { - status = lpfc_sli4_post_sgl(phba, pdma_phys_bpl, - pdma_phys_bpl1, - psb->cur_iocbq.sli4_xritag); - if (status) { - /* Put this back on the abort scsi list */ - psb->exch_busy = 1; - } else { - psb->exch_busy = 0; - psb->status = IOSTAT_SUCCESS; - } - /* Put it back into the SCSI buffer list */ - lpfc_release_scsi_buf_s4(phba, psb); - break; - } - } - if (bcnt) { - if (!phba->sli4_hba.extents_in_use) - status = lpfc_sli4_post_scsi_sgl_block(phba, - &sblist, - bcnt); - else - status = lpfc_sli4_post_scsi_sgl_blk_ext(phba, - &sblist, - bcnt); - - if (status) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "3021 SCSI SGL post error %d\n", - status); - bcnt = 0; - } - /* Reset SCSI buffer count for next round of posting */ - while (!list_empty(&sblist)) { - list_remove_head(&sblist, psb, struct lpfc_scsi_buf, - list); - if (status) { - /* Put this back on the abort scsi list */ - psb->exch_busy = 1; - } else { - psb->exch_busy = 0; - psb->status = IOSTAT_SUCCESS; - } - /* Put it back into the SCSI buffer list */ - lpfc_release_scsi_buf_s4(phba, psb); - } + + /* add the scsi buffer to a post list */ + list_add_tail(&psb->list, &post_sblist); + spin_lock_irq(&phba->scsi_buf_list_lock); + phba->sli4_hba.scsi_xri_cnt++; + spin_unlock_irq(&phba->scsi_buf_list_lock); } + lpfc_printf_log(phba, KERN_INFO, LOG_BG, + "3021 Allocate %d out of %d requested new SCSI " + "buffers\n", bcnt, num_to_alloc); + + /* post the list of scsi buffer sgls to port if available */ + if (!list_empty(&post_sblist)) + num_posted = lpfc_sli4_post_scsi_sgl_list(phba, + &post_sblist, bcnt); + else + num_posted = 0; - return bcnt + non_sequential_xri; + return num_posted; } /** diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index dbaf5b963bff..b887c9c5372a 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -67,6 +67,8 @@ 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 IOCB_t * lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) @@ -4967,7 +4969,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; } @@ -5051,7 +5058,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; @@ -5060,7 +5067,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 @@ -5075,7 +5082,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; @@ -5091,7 +5098,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; @@ -5149,17 +5156,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 = |