[SCSI] mpt2sas: Create a pool of chain buffer instead of dedicated per IOs
Create a pool of chain buffers, instead of dedicated per IO: This enahancment is to address memory allocation failure when asking for more than 2300 IOs per host. There is just not enough contiquious DMA physical memory to make one single allocation to hold both message frames and chain buffers when asking for more than 2300 request. In order to address this problem we will have to allocate memory for each chain buffer in a seperate individual memory allocation, placing each chain element of 128 bytes onto a pool of available chains, which can be shared amoung all request. Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
parent
6cb8ef573f
commit
35f805b52c
@ -65,7 +65,6 @@
|
|||||||
static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS];
|
static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS];
|
||||||
|
|
||||||
#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
|
#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
|
||||||
#define MPT2SAS_MAX_REQUEST_QUEUE 600 /* maximum controller queue depth */
|
|
||||||
|
|
||||||
static int max_queue_depth = -1;
|
static int max_queue_depth = -1;
|
||||||
module_param(max_queue_depth, int, 0);
|
module_param(max_queue_depth, int, 0);
|
||||||
@ -1497,6 +1496,7 @@ mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid)
|
|||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
|
struct chain_tracker *chain_req, *next;
|
||||||
|
|
||||||
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
|
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
|
||||||
if (smid >= ioc->hi_priority_smid) {
|
if (smid >= ioc->hi_priority_smid) {
|
||||||
@ -1519,6 +1519,14 @@ mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid)
|
|||||||
|
|
||||||
/* scsiio queue */
|
/* scsiio queue */
|
||||||
i = smid - 1;
|
i = smid - 1;
|
||||||
|
if (!list_empty(&ioc->scsi_lookup[i].chain_list)) {
|
||||||
|
list_for_each_entry_safe(chain_req, next,
|
||||||
|
&ioc->scsi_lookup[i].chain_list, tracker_list) {
|
||||||
|
list_del_init(&chain_req->tracker_list);
|
||||||
|
list_add_tail(&chain_req->tracker_list,
|
||||||
|
&ioc->free_chain_list);
|
||||||
|
}
|
||||||
|
}
|
||||||
ioc->scsi_lookup[i].cb_idx = 0xFF;
|
ioc->scsi_lookup[i].cb_idx = 0xFF;
|
||||||
ioc->scsi_lookup[i].scmd = NULL;
|
ioc->scsi_lookup[i].scmd = NULL;
|
||||||
list_add_tail(&ioc->scsi_lookup[i].tracker_list,
|
list_add_tail(&ioc->scsi_lookup[i].tracker_list,
|
||||||
@ -1968,6 +1976,8 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
|
|||||||
static void
|
static void
|
||||||
_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
|
_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
|
dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
|
||||||
__func__));
|
__func__));
|
||||||
|
|
||||||
@ -2032,6 +2042,20 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
|
|||||||
}
|
}
|
||||||
kfree(ioc->hpr_lookup);
|
kfree(ioc->hpr_lookup);
|
||||||
kfree(ioc->internal_lookup);
|
kfree(ioc->internal_lookup);
|
||||||
|
if (ioc->chain_lookup) {
|
||||||
|
for (i = 0; i < ioc->chain_depth; i++) {
|
||||||
|
if (ioc->chain_lookup[i].chain_buffer)
|
||||||
|
pci_pool_free(ioc->chain_dma_pool,
|
||||||
|
ioc->chain_lookup[i].chain_buffer,
|
||||||
|
ioc->chain_lookup[i].chain_buffer_dma);
|
||||||
|
}
|
||||||
|
if (ioc->chain_dma_pool)
|
||||||
|
pci_pool_destroy(ioc->chain_dma_pool);
|
||||||
|
}
|
||||||
|
if (ioc->chain_lookup) {
|
||||||
|
free_pages((ulong)ioc->chain_lookup, ioc->chain_pages);
|
||||||
|
ioc->chain_lookup = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2053,6 +2077,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|||||||
u32 sz, total_sz;
|
u32 sz, total_sz;
|
||||||
u32 retry_sz;
|
u32 retry_sz;
|
||||||
u16 max_request_credit;
|
u16 max_request_credit;
|
||||||
|
int i;
|
||||||
|
|
||||||
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
|
||||||
__func__));
|
__func__));
|
||||||
@ -2070,14 +2095,11 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* command line tunables for max controller queue depth */
|
/* command line tunables for max controller queue depth */
|
||||||
if (max_queue_depth != -1) {
|
if (max_queue_depth != -1)
|
||||||
max_request_credit = (max_queue_depth < facts->RequestCredit)
|
max_request_credit = (max_queue_depth < facts->RequestCredit)
|
||||||
? max_queue_depth : facts->RequestCredit;
|
? max_queue_depth : facts->RequestCredit;
|
||||||
} else {
|
else
|
||||||
max_request_credit = (facts->RequestCredit >
|
max_request_credit = facts->RequestCredit;
|
||||||
MPT2SAS_MAX_REQUEST_QUEUE) ? MPT2SAS_MAX_REQUEST_QUEUE :
|
|
||||||
facts->RequestCredit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ioc->hba_queue_depth = max_request_credit;
|
ioc->hba_queue_depth = max_request_credit;
|
||||||
ioc->hi_priority_depth = facts->HighPriorityCredit;
|
ioc->hi_priority_depth = facts->HighPriorityCredit;
|
||||||
@ -2183,7 +2205,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|||||||
* "frame for smid=0
|
* "frame for smid=0
|
||||||
*/
|
*/
|
||||||
ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth;
|
ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth;
|
||||||
sz = ((ioc->scsiio_depth + 1 + ioc->chain_depth) * ioc->request_sz);
|
sz = ((ioc->scsiio_depth + 1) * ioc->request_sz);
|
||||||
|
|
||||||
/* hi-priority queue */
|
/* hi-priority queue */
|
||||||
sz += (ioc->hi_priority_depth * ioc->request_sz);
|
sz += (ioc->hi_priority_depth * ioc->request_sz);
|
||||||
@ -2224,19 +2246,11 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|||||||
ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth *
|
ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth *
|
||||||
ioc->request_sz);
|
ioc->request_sz);
|
||||||
|
|
||||||
ioc->chain = ioc->internal + (ioc->internal_depth *
|
|
||||||
ioc->request_sz);
|
|
||||||
ioc->chain_dma = ioc->internal_dma + (ioc->internal_depth *
|
|
||||||
ioc->request_sz);
|
|
||||||
|
|
||||||
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): "
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): "
|
||||||
"depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
|
"depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
|
||||||
ioc->request, ioc->hba_queue_depth, ioc->request_sz,
|
ioc->request, ioc->hba_queue_depth, ioc->request_sz,
|
||||||
(ioc->hba_queue_depth * ioc->request_sz)/1024));
|
(ioc->hba_queue_depth * ioc->request_sz)/1024));
|
||||||
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool(0x%p): depth"
|
|
||||||
"(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->chain,
|
|
||||||
ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth *
|
|
||||||
ioc->request_sz))/1024));
|
|
||||||
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n",
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n",
|
||||||
ioc->name, (unsigned long long) ioc->request_dma));
|
ioc->name, (unsigned long long) ioc->request_dma));
|
||||||
total_sz += sz;
|
total_sz += sz;
|
||||||
@ -2255,6 +2269,38 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|||||||
"depth(%d)\n", ioc->name, ioc->request,
|
"depth(%d)\n", ioc->name, ioc->request,
|
||||||
ioc->scsiio_depth));
|
ioc->scsiio_depth));
|
||||||
|
|
||||||
|
/* loop till the allocation succeeds */
|
||||||
|
do {
|
||||||
|
sz = ioc->chain_depth * sizeof(struct chain_tracker);
|
||||||
|
ioc->chain_pages = get_order(sz);
|
||||||
|
ioc->chain_lookup = (struct chain_tracker *)__get_free_pages(
|
||||||
|
GFP_KERNEL, ioc->chain_pages);
|
||||||
|
if (ioc->chain_lookup == NULL)
|
||||||
|
ioc->chain_depth -= 100;
|
||||||
|
} while (ioc->chain_lookup == NULL);
|
||||||
|
ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev,
|
||||||
|
ioc->request_sz, 16, 0);
|
||||||
|
if (!ioc->chain_dma_pool) {
|
||||||
|
printk(MPT2SAS_ERR_FMT "chain_dma_pool: pci_pool_create "
|
||||||
|
"failed\n", ioc->name);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (i = 0; i < ioc->chain_depth; i++) {
|
||||||
|
ioc->chain_lookup[i].chain_buffer = pci_pool_alloc(
|
||||||
|
ioc->chain_dma_pool , GFP_KERNEL,
|
||||||
|
&ioc->chain_lookup[i].chain_buffer_dma);
|
||||||
|
if (!ioc->chain_lookup[i].chain_buffer) {
|
||||||
|
ioc->chain_depth = i;
|
||||||
|
goto chain_done;
|
||||||
|
}
|
||||||
|
total_sz += ioc->request_sz;
|
||||||
|
}
|
||||||
|
chain_done:
|
||||||
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool depth"
|
||||||
|
"(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
|
||||||
|
ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth *
|
||||||
|
ioc->request_sz))/1024));
|
||||||
|
|
||||||
/* initialize hi-priority queue smid's */
|
/* initialize hi-priority queue smid's */
|
||||||
ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth,
|
ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth,
|
||||||
sizeof(struct request_tracker), GFP_KERNEL);
|
sizeof(struct request_tracker), GFP_KERNEL);
|
||||||
@ -2404,7 +2450,6 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
_base_release_memory_pools(ioc);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3587,6 +3632,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|||||||
INIT_LIST_HEAD(&ioc->free_list);
|
INIT_LIST_HEAD(&ioc->free_list);
|
||||||
smid = 1;
|
smid = 1;
|
||||||
for (i = 0; i < ioc->scsiio_depth; i++, smid++) {
|
for (i = 0; i < ioc->scsiio_depth; i++, smid++) {
|
||||||
|
INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list);
|
||||||
ioc->scsi_lookup[i].cb_idx = 0xFF;
|
ioc->scsi_lookup[i].cb_idx = 0xFF;
|
||||||
ioc->scsi_lookup[i].smid = smid;
|
ioc->scsi_lookup[i].smid = smid;
|
||||||
ioc->scsi_lookup[i].scmd = NULL;
|
ioc->scsi_lookup[i].scmd = NULL;
|
||||||
@ -3613,6 +3659,13 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|||||||
list_add_tail(&ioc->internal_lookup[i].tracker_list,
|
list_add_tail(&ioc->internal_lookup[i].tracker_list,
|
||||||
&ioc->internal_free_list);
|
&ioc->internal_free_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* chain pool */
|
||||||
|
INIT_LIST_HEAD(&ioc->free_chain_list);
|
||||||
|
for (i = 0; i < ioc->chain_depth; i++)
|
||||||
|
list_add_tail(&ioc->chain_lookup[i].tracker_list,
|
||||||
|
&ioc->free_chain_list);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
|
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
|
||||||
|
|
||||||
/* initialize Reply Free Queue */
|
/* initialize Reply Free Queue */
|
||||||
|
@ -418,6 +418,18 @@ enum reset_type {
|
|||||||
SOFT_RESET,
|
SOFT_RESET,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct chain_tracker - firmware chain tracker
|
||||||
|
* @chain_buffer: chain buffer
|
||||||
|
* @chain_buffer_dma: physical address
|
||||||
|
* @tracker_list: list of free request (ioc->free_chain_list)
|
||||||
|
*/
|
||||||
|
struct chain_tracker {
|
||||||
|
void *chain_buffer;
|
||||||
|
dma_addr_t chain_buffer_dma;
|
||||||
|
struct list_head tracker_list;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct request_tracker - firmware request tracker
|
* struct request_tracker - firmware request tracker
|
||||||
* @smid: system message id
|
* @smid: system message id
|
||||||
@ -430,6 +442,7 @@ struct request_tracker {
|
|||||||
u16 smid;
|
u16 smid;
|
||||||
struct scsi_cmnd *scmd;
|
struct scsi_cmnd *scmd;
|
||||||
u8 cb_idx;
|
u8 cb_idx;
|
||||||
|
struct list_head chain_list;
|
||||||
struct list_head tracker_list;
|
struct list_head tracker_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -704,8 +717,10 @@ struct MPT2SAS_ADAPTER {
|
|||||||
wait_queue_head_t reset_wq;
|
wait_queue_head_t reset_wq;
|
||||||
|
|
||||||
/* chain */
|
/* chain */
|
||||||
u8 *chain;
|
struct chain_tracker *chain_lookup;
|
||||||
dma_addr_t chain_dma;
|
struct list_head free_chain_list;
|
||||||
|
struct dma_pool *chain_dma_pool;
|
||||||
|
ulong chain_pages;
|
||||||
u16 max_sges_in_main_message;
|
u16 max_sges_in_main_message;
|
||||||
u16 max_sges_in_chain_message;
|
u16 max_sges_in_chain_message;
|
||||||
u16 chains_needed_per_io;
|
u16 chains_needed_per_io;
|
||||||
|
@ -931,31 +931,32 @@ _scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
|
* _scsih_get_chain_buffer_tracker - obtain chain tracker
|
||||||
* @ioc: per adapter object
|
* @ioc: per adapter object
|
||||||
* @smid: system request message index
|
* @smid: smid associated to an IO request
|
||||||
*
|
*
|
||||||
* Returns phys pointer to chain buffer.
|
* Returns chain tracker(from ioc->free_chain_list)
|
||||||
*/
|
*/
|
||||||
static dma_addr_t
|
static struct chain_tracker *
|
||||||
_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
|
_scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid)
|
||||||
{
|
{
|
||||||
return ioc->chain_dma + ((smid - 1) * (ioc->request_sz *
|
struct chain_tracker *chain_req;
|
||||||
ioc->chains_needed_per_io));
|
unsigned long flags;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
|
||||||
* _scsih_get_chain_buffer - obtain block of chains assigned to a mf request
|
if (list_empty(&ioc->free_chain_list)) {
|
||||||
* @ioc: per adapter object
|
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
|
||||||
* @smid: system request message index
|
printk(MPT2SAS_WARN_FMT "chain buffers not available\n",
|
||||||
*
|
ioc->name);
|
||||||
* Returns virt pointer to chain buffer.
|
return NULL;
|
||||||
*/
|
}
|
||||||
static void *
|
chain_req = list_entry(ioc->free_chain_list.next,
|
||||||
_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
|
struct chain_tracker, tracker_list);
|
||||||
{
|
list_del_init(&chain_req->tracker_list);
|
||||||
return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz *
|
list_add_tail(&chain_req->tracker_list,
|
||||||
ioc->chains_needed_per_io)));
|
&ioc->scsi_lookup[smid - 1].chain_list);
|
||||||
|
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
|
||||||
|
return chain_req;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -986,6 +987,7 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
|
|||||||
u32 sgl_flags;
|
u32 sgl_flags;
|
||||||
u32 sgl_flags_last_element;
|
u32 sgl_flags_last_element;
|
||||||
u32 sgl_flags_end_buffer;
|
u32 sgl_flags_end_buffer;
|
||||||
|
struct chain_tracker *chain_req;
|
||||||
|
|
||||||
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
|
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
|
||||||
|
|
||||||
@ -1033,8 +1035,11 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
|
|||||||
|
|
||||||
/* initializing the chain flags and pointers */
|
/* initializing the chain flags and pointers */
|
||||||
chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
|
chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
|
||||||
chain = _scsih_get_chain_buffer(ioc, smid);
|
chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
|
||||||
chain_dma = _scsih_get_chain_buffer_dma(ioc, smid);
|
if (!chain_req)
|
||||||
|
return -1;
|
||||||
|
chain = chain_req->chain_buffer;
|
||||||
|
chain_dma = chain_req->chain_buffer_dma;
|
||||||
do {
|
do {
|
||||||
sges_in_segment = (sges_left <=
|
sges_in_segment = (sges_left <=
|
||||||
ioc->max_sges_in_chain_message) ? sges_left :
|
ioc->max_sges_in_chain_message) ? sges_left :
|
||||||
@ -1070,8 +1075,11 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
|
|||||||
sges_in_segment--;
|
sges_in_segment--;
|
||||||
}
|
}
|
||||||
|
|
||||||
chain_dma += ioc->request_sz;
|
chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
|
||||||
chain += ioc->request_sz;
|
if (!chain_req)
|
||||||
|
return -1;
|
||||||
|
chain = chain_req->chain_buffer;
|
||||||
|
chain_dma = chain_req->chain_buffer_dma;
|
||||||
} while (1);
|
} while (1);
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user