Commit e8711085 authored by Andrew Vasquez's avatar Andrew Vasquez Committed by James Bottomley

[SCSI] qla2xxx: Cleanse memory allocation logic during probe.

- Drop loop-till-allocated structure of code within
  qla2x00_mem_alloc().
- Properly unwind deallcations of memory during failures.
- Drop qla2x00_allocate_sp_pool() and qla2x00_free_sp_pool()
  functions as their implementations can easily be collapsed into
  the callers.
- Defer DMA pool allocation of SFP data until requested.
Signed-off-by: default avatarAndrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 0afb467b
...@@ -428,6 +428,19 @@ qla2x00_sysfs_read_sfp(struct kobject *kobj, ...@@ -428,6 +428,19 @@ qla2x00_sysfs_read_sfp(struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2) if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2)
return 0; return 0;
if (ha->sfp_data)
goto do_read;
ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
&ha->sfp_data_dma);
if (!ha->sfp_data) {
qla_printk(KERN_WARNING, ha,
"Unable to allocate memory for SFP read-data.\n");
return 0;
}
do_read:
memset(ha->sfp_data, 0, SFP_BLOCK_SIZE);
addr = 0xa0; addr = 0xa0;
for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE; for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE;
iter++, offset += SFP_BLOCK_SIZE) { iter++, offset += SFP_BLOCK_SIZE) {
......
...@@ -204,10 +204,8 @@ static int qla2x00_do_dpc(void *data); ...@@ -204,10 +204,8 @@ static int qla2x00_do_dpc(void *data);
static void qla2x00_rst_aen(scsi_qla_host_t *); static void qla2x00_rst_aen(scsi_qla_host_t *);
static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *); static int qla2x00_mem_alloc(scsi_qla_host_t *);
static void qla2x00_mem_free(scsi_qla_host_t *ha); static void qla2x00_mem_free(scsi_qla_host_t *ha);
static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *); static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
...@@ -2032,196 +2030,109 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer) ...@@ -2032,196 +2030,109 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
* *
* Returns: * Returns:
* 0 = success. * 0 = success.
* 1 = failure. * !0 = failure.
*/ */
static uint8_t static int
qla2x00_mem_alloc(scsi_qla_host_t *ha) qla2x00_mem_alloc(scsi_qla_host_t *ha)
{ {
char name[16]; char name[16];
uint8_t status = 1;
int retry= 10;
do {
/*
* This will loop only once if everything goes well, else some
* number of retries will be performed to get around a kernel
* bug where available mem is not allocated until after a
* little delay and a retry.
*/
ha->request_ring = dma_alloc_coherent(&ha->pdev->dev, ha->request_ring = dma_alloc_coherent(&ha->pdev->dev,
(ha->request_q_length + 1) * sizeof(request_t), (ha->request_q_length + 1) * sizeof(request_t), &ha->request_dma,
&ha->request_dma, GFP_KERNEL); GFP_KERNEL);
if (ha->request_ring == NULL) { if (!ha->request_ring)
qla_printk(KERN_WARNING, ha, goto fail;
"Memory Allocation failed - request_ring\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
}
ha->response_ring = dma_alloc_coherent(&ha->pdev->dev, ha->response_ring = dma_alloc_coherent(&ha->pdev->dev,
(ha->response_q_length + 1) * sizeof(response_t), (ha->response_q_length + 1) * sizeof(response_t),
&ha->response_dma, GFP_KERNEL); &ha->response_dma, GFP_KERNEL);
if (ha->response_ring == NULL) { if (!ha->response_ring)
qla_printk(KERN_WARNING, ha, goto fail_free_request_ring;
"Memory Allocation failed - response_ring\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
}
ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE,
&ha->gid_list_dma, GFP_KERNEL); &ha->gid_list_dma, GFP_KERNEL);
if (ha->gid_list == NULL) { if (!ha->gid_list)
qla_printk(KERN_WARNING, ha, goto fail_free_response_ring;
"Memory Allocation failed - gid_list\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
}
/* get consistent memory allocated for init control block */
ha->init_cb = dma_alloc_coherent(&ha->pdev->dev,
ha->init_cb_size, &ha->init_cb_dma, GFP_KERNEL);
if (ha->init_cb == NULL) {
qla_printk(KERN_WARNING, ha,
"Memory Allocation failed - init_cb\n");
qla2x00_mem_free(ha);
msleep(100);
continue; ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, ha->init_cb_size,
} &ha->init_cb_dma, GFP_KERNEL);
memset(ha->init_cb, 0, ha->init_cb_size); if (!ha->init_cb)
goto fail_free_gid_list;
snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME, snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME,
ha->host_no); ha->host_no);
ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev, ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
DMA_POOL_SIZE, 8, 0); DMA_POOL_SIZE, 8, 0);
if (ha->s_dma_pool == NULL) { if (!ha->s_dma_pool)
qla_printk(KERN_WARNING, ha, goto fail_free_init_cb;
"Memory Allocation failed - s_dma_pool\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
}
if (qla2x00_allocate_sp_pool(ha)) { ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep);
qla_printk(KERN_WARNING, ha, if (!ha->srb_mempool)
"Memory Allocation failed - " goto fail_free_s_dma_pool;
"qla2x00_allocate_sp_pool()\n");
qla2x00_mem_free(ha);
msleep(100);
continue; /* Get memory for cached NVRAM */
} ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL);
if (!ha->nvram)
goto fail_free_srb_mempool;
/* Allocate memory for SNS commands */ /* Allocate memory for SNS commands */
if (IS_QLA2100(ha) || IS_QLA2200(ha)) { if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
/* Get consistent memory allocated for SNS commands */ /* Get consistent memory allocated for SNS commands */
ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev, ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev,
sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, GFP_KERNEL);
GFP_KERNEL); if (!ha->sns_cmd)
if (ha->sns_cmd == NULL) { goto fail_free_nvram;
/* error */
qla_printk(KERN_WARNING, ha,
"Memory Allocation failed - sns_cmd\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
}
memset(ha->sns_cmd, 0, sizeof(struct sns_cmd_pkt));
} else { } else {
/* Get consistent memory allocated for MS IOCB */ /* Get consistent memory allocated for MS IOCB */
ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
&ha->ms_iocb_dma); &ha->ms_iocb_dma);
if (ha->ms_iocb == NULL) { if (!ha->ms_iocb)
/* error */ goto fail_free_nvram;
qla_printk(KERN_WARNING, ha,
"Memory Allocation failed - ms_iocb\n");
qla2x00_mem_free(ha);
msleep(100);
continue; /* Get consistent memory allocated for CT SNS commands */
}
memset(ha->ms_iocb, 0, sizeof(ms_iocb_entry_t));
/*
* Get consistent memory allocated for CT SNS
* commands
*/
ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev, ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev,
sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL);
GFP_KERNEL); if (!ha->ct_sns)
if (ha->ct_sns == NULL) { goto fail_free_ms_iocb;
/* error */
qla_printk(KERN_WARNING, ha,
"Memory Allocation failed - ct_sns\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
}
memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt));
if (IS_FWI2_CAPABLE(ha)) {
/*
* Get consistent memory allocated for SFP
* block.
*/
ha->sfp_data = dma_pool_alloc(ha->s_dma_pool,
GFP_KERNEL, &ha->sfp_data_dma);
if (ha->sfp_data == NULL) {
qla_printk(KERN_WARNING, ha,
"Memory Allocation failed - "
"sfp_data\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
}
memset(ha->sfp_data, 0, SFP_BLOCK_SIZE);
}
}
/* Get memory for cached NVRAM */
ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL);
if (ha->nvram == NULL) {
/* error */
qla_printk(KERN_WARNING, ha,
"Memory Allocation failed - nvram cache\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
} }
/* Done all allocations without any error. */ return 0;
status = 0;
} while (retry-- && status != 0);
if (status) {
printk(KERN_WARNING
"%s(): **** FAILED ****\n", __func__);
}
return(status); fail_free_ms_iocb:
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
ha->ms_iocb = NULL;
ha->ms_iocb_dma = 0;
fail_free_nvram:
kfree(ha->nvram);
ha->nvram = NULL;
fail_free_srb_mempool:
mempool_destroy(ha->srb_mempool);
ha->srb_mempool = NULL;
fail_free_s_dma_pool:
dma_pool_destroy(ha->s_dma_pool);
ha->s_dma_pool = NULL;
fail_free_init_cb:
dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb,
ha->init_cb_dma);
ha->init_cb = NULL;
ha->init_cb_dma = 0;
fail_free_gid_list:
dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
ha->gid_list_dma);
ha->gid_list = NULL;
ha->gid_list_dma = 0;
fail_free_response_ring:
dma_free_coherent(&ha->pdev->dev, (ha->response_q_length + 1) *
sizeof(response_t), ha->response_ring, ha->response_dma);
ha->response_ring = NULL;
ha->response_dma = 0;
fail_free_request_ring:
dma_free_coherent(&ha->pdev->dev, (ha->request_q_length + 1) *
sizeof(request_t), ha->request_ring, ha->request_dma);
ha->request_ring = NULL;
ha->request_dma = 0;
fail:
return -ENOMEM;
} }
/* /*
...@@ -2237,14 +2148,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha) ...@@ -2237,14 +2148,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
struct list_head *fcpl, *fcptemp; struct list_head *fcpl, *fcptemp;
fc_port_t *fcport; fc_port_t *fcport;
if (ha == NULL) { if (ha->srb_mempool)
/* error */ mempool_destroy(ha->srb_mempool);
DEBUG2(printk("%s(): ERROR invalid ha pointer.\n", __func__));
return;
}
/* free sp pool */
qla2x00_free_sp_pool(ha);
if (ha->fce) if (ha->fce)
dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce, dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
...@@ -2292,6 +2197,7 @@ qla2x00_mem_free(scsi_qla_host_t *ha) ...@@ -2292,6 +2197,7 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
(ha->request_q_length + 1) * sizeof(request_t), (ha->request_q_length + 1) * sizeof(request_t),
ha->request_ring, ha->request_dma); ha->request_ring, ha->request_dma);
ha->srb_mempool = NULL;
ha->eft = NULL; ha->eft = NULL;
ha->eft_dma = 0; ha->eft_dma = 0;
ha->sns_cmd = NULL; ha->sns_cmd = NULL;
...@@ -2330,44 +2236,6 @@ qla2x00_mem_free(scsi_qla_host_t *ha) ...@@ -2330,44 +2236,6 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
kfree(ha->nvram); kfree(ha->nvram);
} }
/*
* qla2x00_allocate_sp_pool
* This routine is called during initialization to allocate
* memory for local srb_t.
*
* Input:
* ha = adapter block pointer.
*
* Context:
* Kernel context.
*/
static int
qla2x00_allocate_sp_pool(scsi_qla_host_t *ha)
{
int rval;
rval = QLA_SUCCESS;
ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep);
if (ha->srb_mempool == NULL) {
qla_printk(KERN_INFO, ha, "Unable to allocate SRB mempool.\n");
rval = QLA_FUNCTION_FAILED;
}
return (rval);
}
/*
* This routine frees all adapter allocated memory.
*
*/
static void
qla2x00_free_sp_pool( scsi_qla_host_t *ha)
{
if (ha->srb_mempool) {
mempool_destroy(ha->srb_mempool);
ha->srb_mempool = NULL;
}
}
/************************************************************************** /**************************************************************************
* qla2x00_do_dpc * qla2x00_do_dpc
* This kernel thread is a task that is schedule by the interrupt handler * This kernel thread is a task that is schedule by the interrupt handler
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment