提交 8a9d2e80 编写于 作者: J James Smart 提交者: James Bottomley

[SCSI] lpfc 8.3.31: Correct handling of SLI4-port XRI resource-provisioning profile change

Signed-off-by: NAlex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: NJames Smart <james.smart@emulex.com>
Signed-off-by: NJames Bottomley <JBottomley@Parallels.com>
上级 587a37f6
......@@ -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 *);
......@@ -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
......
......@@ -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);
......@@ -2766,36 +2766,6 @@ lpfc_offline(struct lpfc_hba *phba)
lpfc_destroy_vport_work_array(phba, vports);
}
/**
* 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.
......@@ -2803,11 +2773,8 @@ lpfc_scsi_buf_update(struct lpfc_hba *phba)
* 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 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
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 @@ lpfc_init_iocb_list(struct lpfc_hba *phba, int iocb_count)
}
/**
* 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;
}
......
......@@ -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;
}
/**
......
此差异已折叠。
......@@ -493,14 +493,12 @@ struct lpfc_sli4_hba {
uint16_t next_rpi;
uint16_t scsi_xri_max;
uint16_t scsi_xri_cnt;
uint16_t els_xri_cnt;
uint16_t scsi_xri_start;
struct list_head lpfc_free_sgl_list;
struct list_head lpfc_sgl_list;
struct lpfc_sglq **lpfc_els_sgl_array;
struct list_head lpfc_abts_els_sgl_list;
struct lpfc_scsi_buf **lpfc_scsi_psb_array;
struct list_head lpfc_abts_scsi_buf_list;
uint32_t total_sglq_bufs;
struct lpfc_sglq **lpfc_sglq_active_list;
struct list_head lpfc_rpi_hdr_list;
unsigned long *rpi_bmask;
......@@ -509,7 +507,6 @@ struct lpfc_sli4_hba {
struct list_head lpfc_rpi_blk_list;
unsigned long *xri_bmask;
uint16_t *xri_ids;
uint16_t xri_count;
struct list_head lpfc_xri_blk_list;
unsigned long *vfi_bmask;
uint16_t *vfi_ids;
......@@ -614,11 +611,7 @@ int lpfc_sli4_post_sgl(struct lpfc_hba *, dma_addr_t, dma_addr_t, uint16_t);
int lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *);
uint16_t lpfc_sli4_next_xritag(struct lpfc_hba *);
int lpfc_sli4_post_async_mbox(struct lpfc_hba *);
int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba);
int lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba);
int lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *, struct list_head *, int);
int lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *, struct list_head *,
int);
struct lpfc_cq_event *__lpfc_sli4_cq_event_alloc(struct lpfc_hba *);
struct lpfc_cq_event *lpfc_sli4_cq_event_alloc(struct lpfc_hba *);
void __lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册