aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authornagalakshmi.nandigama@lsi.com <nagalakshmi.nandigama@lsi.com>2011-11-30 21:23:08 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2012-01-25 20:24:41 -0500
commit73669debb5f508962ffcc8b632ffb2971c606e5c (patch)
tree86f1de490a8b2fa3ed2e4278bf33600661e7b199 /drivers/scsi
parentde3f88ba084473ce5365632f0209c3e95aeb55e9 (diff)
SCSI: mpt2sas : Fix for memory allocation error for large host credits
commit aff132d95ffe14eca96cab90597cdd010b457af7 upstream. The amount of memory required for tracking chain buffers is rather large, and when the host credit count is big, memory allocation failure occurs inside __get_free_pages. The fix is to limit the number of chains to 100,000. In addition, the number of host credits is limited to 30,000 IOs. However this limitation can be overridden this using the command line option max_queue_depth. The algorithm for calculating the reply_post_queue_depth is changed so that it is equal to (reply_free_queue_depth + 16), previously it was (reply_free_queue_depth * 2). Signed-off-by: Nagalakshmi Nandigama <nagalakshmi.nandigama@lsi.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c83
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c4
2 files changed, 29 insertions, 58 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 39e81cd567a..10f16a306e5 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -66,6 +66,8 @@ static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS];
66 66
67#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */ 67#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
68 68
69#define MAX_HBA_QUEUE_DEPTH 30000
70#define MAX_CHAIN_DEPTH 100000
69static int max_queue_depth = -1; 71static int max_queue_depth = -1;
70module_param(max_queue_depth, int, 0); 72module_param(max_queue_depth, int, 0);
71MODULE_PARM_DESC(max_queue_depth, " max controller queue depth "); 73MODULE_PARM_DESC(max_queue_depth, " max controller queue depth ");
@@ -2098,8 +2100,6 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
2098 } 2100 }
2099 if (ioc->chain_dma_pool) 2101 if (ioc->chain_dma_pool)
2100 pci_pool_destroy(ioc->chain_dma_pool); 2102 pci_pool_destroy(ioc->chain_dma_pool);
2101 }
2102 if (ioc->chain_lookup) {
2103 free_pages((ulong)ioc->chain_lookup, ioc->chain_pages); 2103 free_pages((ulong)ioc->chain_lookup, ioc->chain_pages);
2104 ioc->chain_lookup = NULL; 2104 ioc->chain_lookup = NULL;
2105 } 2105 }
@@ -2117,9 +2117,7 @@ static int
2117_base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) 2117_base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
2118{ 2118{
2119 struct mpt2sas_facts *facts; 2119 struct mpt2sas_facts *facts;
2120 u32 queue_size, queue_diff;
2121 u16 max_sge_elements; 2120 u16 max_sge_elements;
2122 u16 num_of_reply_frames;
2123 u16 chains_needed_per_io; 2121 u16 chains_needed_per_io;
2124 u32 sz, total_sz; 2122 u32 sz, total_sz;
2125 u32 retry_sz; 2123 u32 retry_sz;
@@ -2146,7 +2144,8 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
2146 max_request_credit = (max_queue_depth < facts->RequestCredit) 2144 max_request_credit = (max_queue_depth < facts->RequestCredit)
2147 ? max_queue_depth : facts->RequestCredit; 2145 ? max_queue_depth : facts->RequestCredit;
2148 else 2146 else
2149 max_request_credit = facts->RequestCredit; 2147 max_request_credit = min_t(u16, facts->RequestCredit,
2148 MAX_HBA_QUEUE_DEPTH);
2150 2149
2151 ioc->hba_queue_depth = max_request_credit; 2150 ioc->hba_queue_depth = max_request_credit;
2152 ioc->hi_priority_depth = facts->HighPriorityCredit; 2151 ioc->hi_priority_depth = facts->HighPriorityCredit;
@@ -2187,50 +2186,25 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
2187 } 2186 }
2188 ioc->chains_needed_per_io = chains_needed_per_io; 2187 ioc->chains_needed_per_io = chains_needed_per_io;
2189 2188
2190 /* reply free queue sizing - taking into account for events */ 2189 /* reply free queue sizing - taking into account for 64 FW events */
2191 num_of_reply_frames = ioc->hba_queue_depth + 32; 2190 ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
2192
2193 /* number of replies frames can't be a multiple of 16 */
2194 /* decrease number of reply frames by 1 */
2195 if (!(num_of_reply_frames % 16))
2196 num_of_reply_frames--;
2197
2198 /* calculate number of reply free queue entries
2199 * (must be multiple of 16)
2200 */
2201
2202 /* (we know reply_free_queue_depth is not a multiple of 16) */
2203 queue_size = num_of_reply_frames;
2204 queue_size += 16 - (queue_size % 16);
2205 ioc->reply_free_queue_depth = queue_size;
2206
2207 /* reply descriptor post queue sizing */
2208 /* this size should be the number of request frames + number of reply
2209 * frames
2210 */
2211
2212 queue_size = ioc->hba_queue_depth + num_of_reply_frames + 1;
2213 /* round up to 16 byte boundary */
2214 if (queue_size % 16)
2215 queue_size += 16 - (queue_size % 16);
2216
2217 /* check against IOC maximum reply post queue depth */
2218 if (queue_size > facts->MaxReplyDescriptorPostQueueDepth) {
2219 queue_diff = queue_size -
2220 facts->MaxReplyDescriptorPostQueueDepth;
2221 2191
2222 /* round queue_diff up to multiple of 16 */ 2192 /* align the reply post queue on the next 16 count boundary */
2223 if (queue_diff % 16) 2193 if (!ioc->reply_free_queue_depth % 16)
2224 queue_diff += 16 - (queue_diff % 16); 2194 ioc->reply_post_queue_depth = ioc->reply_free_queue_depth + 16;
2225 2195 else
2226 /* adjust hba_queue_depth, reply_free_queue_depth, 2196 ioc->reply_post_queue_depth = ioc->reply_free_queue_depth +
2227 * and queue_size 2197 32 - (ioc->reply_free_queue_depth % 16);
2228 */ 2198 if (ioc->reply_post_queue_depth >
2229 ioc->hba_queue_depth -= (queue_diff / 2); 2199 facts->MaxReplyDescriptorPostQueueDepth) {
2230 ioc->reply_free_queue_depth -= (queue_diff / 2); 2200 ioc->reply_post_queue_depth = min_t(u16,
2231 queue_size = facts->MaxReplyDescriptorPostQueueDepth; 2201 (facts->MaxReplyDescriptorPostQueueDepth -
2202 (facts->MaxReplyDescriptorPostQueueDepth % 16)),
2203 (ioc->hba_queue_depth - (ioc->hba_queue_depth % 16)));
2204 ioc->reply_free_queue_depth = ioc->reply_post_queue_depth - 16;
2205 ioc->hba_queue_depth = ioc->reply_free_queue_depth - 64;
2232 } 2206 }
2233 ioc->reply_post_queue_depth = queue_size; 2207
2234 2208
2235 dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: " 2209 dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: "
2236 "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), " 2210 "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), "
@@ -2316,15 +2290,12 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
2316 "depth(%d)\n", ioc->name, ioc->request, 2290 "depth(%d)\n", ioc->name, ioc->request,
2317 ioc->scsiio_depth)); 2291 ioc->scsiio_depth));
2318 2292
2319 /* loop till the allocation succeeds */ 2293 ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH);
2320 do { 2294 sz = ioc->chain_depth * sizeof(struct chain_tracker);
2321 sz = ioc->chain_depth * sizeof(struct chain_tracker); 2295 ioc->chain_pages = get_order(sz);
2322 ioc->chain_pages = get_order(sz); 2296
2323 ioc->chain_lookup = (struct chain_tracker *)__get_free_pages( 2297 ioc->chain_lookup = (struct chain_tracker *)__get_free_pages(
2324 GFP_KERNEL, ioc->chain_pages); 2298 GFP_KERNEL, ioc->chain_pages);
2325 if (ioc->chain_lookup == NULL)
2326 ioc->chain_depth -= 100;
2327 } while (ioc->chain_lookup == NULL);
2328 ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev, 2299 ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev,
2329 ioc->request_sz, 16, 0); 2300 ioc->request_sz, 16, 0);
2330 if (!ioc->chain_dma_pool) { 2301 if (!ioc->chain_dma_pool) {
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 2a4719ae688..aa51195a731 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -974,8 +974,8 @@ _scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid)
974 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); 974 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
975 if (list_empty(&ioc->free_chain_list)) { 975 if (list_empty(&ioc->free_chain_list)) {
976 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); 976 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
977 printk(MPT2SAS_WARN_FMT "chain buffers not available\n", 977 dfailprintk(ioc, printk(MPT2SAS_WARN_FMT "chain buffers not "
978 ioc->name); 978 "available\n", ioc->name));
979 return NULL; 979 return NULL;
980 } 980 }
981 chain_req = list_entry(ioc->free_chain_list.next, 981 chain_req = list_entry(ioc->free_chain_list.next,