diff options
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.c | 87 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.h | 19 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_scsih.c | 56 |
3 files changed, 119 insertions, 43 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 0e30827d44e7..c8f39f8c6fed 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c | |||
@@ -65,7 +65,6 @@ | |||
65 | static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS]; | 65 | 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 | #define MPT2SAS_MAX_REQUEST_QUEUE 600 /* maximum controller queue depth */ | ||
69 | 68 | ||
70 | static int max_queue_depth = -1; | 69 | static int max_queue_depth = -1; |
71 | module_param(max_queue_depth, int, 0); | 70 | module_param(max_queue_depth, int, 0); |
@@ -1497,6 +1496,7 @@ mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid) | |||
1497 | { | 1496 | { |
1498 | unsigned long flags; | 1497 | unsigned long flags; |
1499 | int i; | 1498 | int i; |
1499 | struct chain_tracker *chain_req, *next; | ||
1500 | 1500 | ||
1501 | spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); | 1501 | spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); |
1502 | if (smid >= ioc->hi_priority_smid) { | 1502 | if (smid >= ioc->hi_priority_smid) { |
@@ -1519,6 +1519,14 @@ mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid) | |||
1519 | 1519 | ||
1520 | /* scsiio queue */ | 1520 | /* scsiio queue */ |
1521 | i = smid - 1; | 1521 | i = smid - 1; |
1522 | if (!list_empty(&ioc->scsi_lookup[i].chain_list)) { | ||
1523 | list_for_each_entry_safe(chain_req, next, | ||
1524 | &ioc->scsi_lookup[i].chain_list, tracker_list) { | ||
1525 | list_del_init(&chain_req->tracker_list); | ||
1526 | list_add_tail(&chain_req->tracker_list, | ||
1527 | &ioc->free_chain_list); | ||
1528 | } | ||
1529 | } | ||
1522 | ioc->scsi_lookup[i].cb_idx = 0xFF; | 1530 | ioc->scsi_lookup[i].cb_idx = 0xFF; |
1523 | ioc->scsi_lookup[i].scmd = NULL; | 1531 | ioc->scsi_lookup[i].scmd = NULL; |
1524 | list_add_tail(&ioc->scsi_lookup[i].tracker_list, | 1532 | list_add_tail(&ioc->scsi_lookup[i].tracker_list, |
@@ -1968,6 +1976,8 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc) | |||
1968 | static void | 1976 | static void |
1969 | _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) | 1977 | _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) |
1970 | { | 1978 | { |
1979 | int i; | ||
1980 | |||
1971 | dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, | 1981 | dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, |
1972 | __func__)); | 1982 | __func__)); |
1973 | 1983 | ||
@@ -2032,6 +2042,20 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) | |||
2032 | } | 2042 | } |
2033 | kfree(ioc->hpr_lookup); | 2043 | kfree(ioc->hpr_lookup); |
2034 | kfree(ioc->internal_lookup); | 2044 | kfree(ioc->internal_lookup); |
2045 | if (ioc->chain_lookup) { | ||
2046 | for (i = 0; i < ioc->chain_depth; i++) { | ||
2047 | if (ioc->chain_lookup[i].chain_buffer) | ||
2048 | pci_pool_free(ioc->chain_dma_pool, | ||
2049 | ioc->chain_lookup[i].chain_buffer, | ||
2050 | ioc->chain_lookup[i].chain_buffer_dma); | ||
2051 | } | ||
2052 | if (ioc->chain_dma_pool) | ||
2053 | pci_pool_destroy(ioc->chain_dma_pool); | ||
2054 | } | ||
2055 | if (ioc->chain_lookup) { | ||
2056 | free_pages((ulong)ioc->chain_lookup, ioc->chain_pages); | ||
2057 | ioc->chain_lookup = NULL; | ||
2058 | } | ||
2035 | } | 2059 | } |
2036 | 2060 | ||
2037 | 2061 | ||
@@ -2053,6 +2077,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
2053 | u32 sz, total_sz; | 2077 | u32 sz, total_sz; |
2054 | u32 retry_sz; | 2078 | u32 retry_sz; |
2055 | u16 max_request_credit; | 2079 | u16 max_request_credit; |
2080 | int i; | ||
2056 | 2081 | ||
2057 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, | 2082 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, |
2058 | __func__)); | 2083 | __func__)); |
@@ -2070,14 +2095,11 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
2070 | } | 2095 | } |
2071 | 2096 | ||
2072 | /* command line tunables for max controller queue depth */ | 2097 | /* command line tunables for max controller queue depth */ |
2073 | if (max_queue_depth != -1) { | 2098 | if (max_queue_depth != -1) |
2074 | max_request_credit = (max_queue_depth < facts->RequestCredit) | 2099 | max_request_credit = (max_queue_depth < facts->RequestCredit) |
2075 | ? max_queue_depth : facts->RequestCredit; | 2100 | ? max_queue_depth : facts->RequestCredit; |
2076 | } else { | 2101 | else |
2077 | max_request_credit = (facts->RequestCredit > | 2102 | max_request_credit = facts->RequestCredit; |
2078 | MPT2SAS_MAX_REQUEST_QUEUE) ? MPT2SAS_MAX_REQUEST_QUEUE : | ||
2079 | facts->RequestCredit; | ||
2080 | } | ||
2081 | 2103 | ||
2082 | ioc->hba_queue_depth = max_request_credit; | 2104 | ioc->hba_queue_depth = max_request_credit; |
2083 | ioc->hi_priority_depth = facts->HighPriorityCredit; | 2105 | ioc->hi_priority_depth = facts->HighPriorityCredit; |
@@ -2183,7 +2205,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
2183 | * "frame for smid=0 | 2205 | * "frame for smid=0 |
2184 | */ | 2206 | */ |
2185 | ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth; | 2207 | ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth; |
2186 | sz = ((ioc->scsiio_depth + 1 + ioc->chain_depth) * ioc->request_sz); | 2208 | sz = ((ioc->scsiio_depth + 1) * ioc->request_sz); |
2187 | 2209 | ||
2188 | /* hi-priority queue */ | 2210 | /* hi-priority queue */ |
2189 | sz += (ioc->hi_priority_depth * ioc->request_sz); | 2211 | sz += (ioc->hi_priority_depth * ioc->request_sz); |
@@ -2224,19 +2246,11 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
2224 | ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth * | 2246 | ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth * |
2225 | ioc->request_sz); | 2247 | ioc->request_sz); |
2226 | 2248 | ||
2227 | ioc->chain = ioc->internal + (ioc->internal_depth * | ||
2228 | ioc->request_sz); | ||
2229 | ioc->chain_dma = ioc->internal_dma + (ioc->internal_depth * | ||
2230 | ioc->request_sz); | ||
2231 | 2249 | ||
2232 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): " | 2250 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): " |
2233 | "depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, | 2251 | "depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, |
2234 | ioc->request, ioc->hba_queue_depth, ioc->request_sz, | 2252 | ioc->request, ioc->hba_queue_depth, ioc->request_sz, |
2235 | (ioc->hba_queue_depth * ioc->request_sz)/1024)); | 2253 | (ioc->hba_queue_depth * ioc->request_sz)/1024)); |
2236 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool(0x%p): depth" | ||
2237 | "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->chain, | ||
2238 | ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth * | ||
2239 | ioc->request_sz))/1024)); | ||
2240 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n", | 2254 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n", |
2241 | ioc->name, (unsigned long long) ioc->request_dma)); | 2255 | ioc->name, (unsigned long long) ioc->request_dma)); |
2242 | total_sz += sz; | 2256 | total_sz += sz; |
@@ -2255,6 +2269,38 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
2255 | "depth(%d)\n", ioc->name, ioc->request, | 2269 | "depth(%d)\n", ioc->name, ioc->request, |
2256 | ioc->scsiio_depth)); | 2270 | ioc->scsiio_depth)); |
2257 | 2271 | ||
2272 | /* loop till the allocation succeeds */ | ||
2273 | do { | ||
2274 | sz = ioc->chain_depth * sizeof(struct chain_tracker); | ||
2275 | ioc->chain_pages = get_order(sz); | ||
2276 | ioc->chain_lookup = (struct chain_tracker *)__get_free_pages( | ||
2277 | GFP_KERNEL, ioc->chain_pages); | ||
2278 | if (ioc->chain_lookup == NULL) | ||
2279 | ioc->chain_depth -= 100; | ||
2280 | } while (ioc->chain_lookup == NULL); | ||
2281 | ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev, | ||
2282 | ioc->request_sz, 16, 0); | ||
2283 | if (!ioc->chain_dma_pool) { | ||
2284 | printk(MPT2SAS_ERR_FMT "chain_dma_pool: pci_pool_create " | ||
2285 | "failed\n", ioc->name); | ||
2286 | goto out; | ||
2287 | } | ||
2288 | for (i = 0; i < ioc->chain_depth; i++) { | ||
2289 | ioc->chain_lookup[i].chain_buffer = pci_pool_alloc( | ||
2290 | ioc->chain_dma_pool , GFP_KERNEL, | ||
2291 | &ioc->chain_lookup[i].chain_buffer_dma); | ||
2292 | if (!ioc->chain_lookup[i].chain_buffer) { | ||
2293 | ioc->chain_depth = i; | ||
2294 | goto chain_done; | ||
2295 | } | ||
2296 | total_sz += ioc->request_sz; | ||
2297 | } | ||
2298 | chain_done: | ||
2299 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool depth" | ||
2300 | "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, | ||
2301 | ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth * | ||
2302 | ioc->request_sz))/1024)); | ||
2303 | |||
2258 | /* initialize hi-priority queue smid's */ | 2304 | /* initialize hi-priority queue smid's */ |
2259 | ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth, | 2305 | ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth, |
2260 | sizeof(struct request_tracker), GFP_KERNEL); | 2306 | sizeof(struct request_tracker), GFP_KERNEL); |
@@ -2404,7 +2450,6 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
2404 | return 0; | 2450 | return 0; |
2405 | 2451 | ||
2406 | out: | 2452 | out: |
2407 | _base_release_memory_pools(ioc); | ||
2408 | return -ENOMEM; | 2453 | return -ENOMEM; |
2409 | } | 2454 | } |
2410 | 2455 | ||
@@ -3587,6 +3632,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
3587 | INIT_LIST_HEAD(&ioc->free_list); | 3632 | INIT_LIST_HEAD(&ioc->free_list); |
3588 | smid = 1; | 3633 | smid = 1; |
3589 | for (i = 0; i < ioc->scsiio_depth; i++, smid++) { | 3634 | for (i = 0; i < ioc->scsiio_depth; i++, smid++) { |
3635 | INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list); | ||
3590 | ioc->scsi_lookup[i].cb_idx = 0xFF; | 3636 | ioc->scsi_lookup[i].cb_idx = 0xFF; |
3591 | ioc->scsi_lookup[i].smid = smid; | 3637 | ioc->scsi_lookup[i].smid = smid; |
3592 | ioc->scsi_lookup[i].scmd = NULL; | 3638 | ioc->scsi_lookup[i].scmd = NULL; |
@@ -3613,6 +3659,13 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
3613 | list_add_tail(&ioc->internal_lookup[i].tracker_list, | 3659 | list_add_tail(&ioc->internal_lookup[i].tracker_list, |
3614 | &ioc->internal_free_list); | 3660 | &ioc->internal_free_list); |
3615 | } | 3661 | } |
3662 | |||
3663 | /* chain pool */ | ||
3664 | INIT_LIST_HEAD(&ioc->free_chain_list); | ||
3665 | for (i = 0; i < ioc->chain_depth; i++) | ||
3666 | list_add_tail(&ioc->chain_lookup[i].tracker_list, | ||
3667 | &ioc->free_chain_list); | ||
3668 | |||
3616 | spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); | 3669 | spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); |
3617 | 3670 | ||
3618 | /* initialize Reply Free Queue */ | 3671 | /* initialize Reply Free Queue */ |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 63f7a196f42d..edf1a028db6c 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h | |||
@@ -419,6 +419,18 @@ enum reset_type { | |||
419 | }; | 419 | }; |
420 | 420 | ||
421 | /** | 421 | /** |
422 | * struct chain_tracker - firmware chain tracker | ||
423 | * @chain_buffer: chain buffer | ||
424 | * @chain_buffer_dma: physical address | ||
425 | * @tracker_list: list of free request (ioc->free_chain_list) | ||
426 | */ | ||
427 | struct chain_tracker { | ||
428 | void *chain_buffer; | ||
429 | dma_addr_t chain_buffer_dma; | ||
430 | struct list_head tracker_list; | ||
431 | }; | ||
432 | |||
433 | /** | ||
422 | * struct request_tracker - firmware request tracker | 434 | * struct request_tracker - firmware request tracker |
423 | * @smid: system message id | 435 | * @smid: system message id |
424 | * @scmd: scsi request pointer | 436 | * @scmd: scsi request pointer |
@@ -430,6 +442,7 @@ struct request_tracker { | |||
430 | u16 smid; | 442 | u16 smid; |
431 | struct scsi_cmnd *scmd; | 443 | struct scsi_cmnd *scmd; |
432 | u8 cb_idx; | 444 | u8 cb_idx; |
445 | struct list_head chain_list; | ||
433 | struct list_head tracker_list; | 446 | struct list_head tracker_list; |
434 | }; | 447 | }; |
435 | 448 | ||
@@ -704,8 +717,10 @@ struct MPT2SAS_ADAPTER { | |||
704 | wait_queue_head_t reset_wq; | 717 | wait_queue_head_t reset_wq; |
705 | 718 | ||
706 | /* chain */ | 719 | /* chain */ |
707 | u8 *chain; | 720 | struct chain_tracker *chain_lookup; |
708 | dma_addr_t chain_dma; | 721 | struct list_head free_chain_list; |
722 | struct dma_pool *chain_dma_pool; | ||
723 | ulong chain_pages; | ||
709 | u16 max_sges_in_main_message; | 724 | u16 max_sges_in_main_message; |
710 | u16 max_sges_in_chain_message; | 725 | u16 max_sges_in_chain_message; |
711 | u16 chains_needed_per_io; | 726 | u16 chains_needed_per_io; |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 5af5781d9464..3e9c78aa4ccb 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c | |||
@@ -931,31 +931,32 @@ _scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id, | |||
931 | } | 931 | } |
932 | 932 | ||
933 | /** | 933 | /** |
934 | * _scsih_get_chain_buffer_dma - obtain block of chains (dma address) | 934 | * _scsih_get_chain_buffer_tracker - obtain chain tracker |
935 | * @ioc: per adapter object | 935 | * @ioc: per adapter object |
936 | * @smid: system request message index | 936 | * @smid: smid associated to an IO request |
937 | * | 937 | * |
938 | * Returns phys pointer to chain buffer. | 938 | * Returns chain tracker(from ioc->free_chain_list) |
939 | */ | 939 | */ |
940 | static dma_addr_t | 940 | static struct chain_tracker * |
941 | _scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) | 941 | _scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid) |
942 | { | 942 | { |
943 | return ioc->chain_dma + ((smid - 1) * (ioc->request_sz * | 943 | struct chain_tracker *chain_req; |
944 | ioc->chains_needed_per_io)); | 944 | unsigned long flags; |
945 | } | ||
946 | 945 | ||
947 | /** | 946 | spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); |
948 | * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request | 947 | if (list_empty(&ioc->free_chain_list)) { |
949 | * @ioc: per adapter object | 948 | spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); |
950 | * @smid: system request message index | 949 | printk(MPT2SAS_WARN_FMT "chain buffers not available\n", |
951 | * | 950 | ioc->name); |
952 | * Returns virt pointer to chain buffer. | 951 | return NULL; |
953 | */ | 952 | } |
954 | static void * | 953 | chain_req = list_entry(ioc->free_chain_list.next, |
955 | _scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid) | 954 | struct chain_tracker, tracker_list); |
956 | { | 955 | list_del_init(&chain_req->tracker_list); |
957 | return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz * | 956 | list_add_tail(&chain_req->tracker_list, |
958 | ioc->chains_needed_per_io))); | 957 | &ioc->scsi_lookup[smid - 1].chain_list); |
958 | spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); | ||
959 | return chain_req; | ||
959 | } | 960 | } |
960 | 961 | ||
961 | /** | 962 | /** |
@@ -986,6 +987,7 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, | |||
986 | u32 sgl_flags; | 987 | u32 sgl_flags; |
987 | u32 sgl_flags_last_element; | 988 | u32 sgl_flags_last_element; |
988 | u32 sgl_flags_end_buffer; | 989 | u32 sgl_flags_end_buffer; |
990 | struct chain_tracker *chain_req; | ||
989 | 991 | ||
990 | mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); | 992 | mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); |
991 | 993 | ||
@@ -1033,8 +1035,11 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, | |||
1033 | 1035 | ||
1034 | /* initializing the chain flags and pointers */ | 1036 | /* initializing the chain flags and pointers */ |
1035 | chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT; | 1037 | chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT; |
1036 | chain = _scsih_get_chain_buffer(ioc, smid); | 1038 | chain_req = _scsih_get_chain_buffer_tracker(ioc, smid); |
1037 | chain_dma = _scsih_get_chain_buffer_dma(ioc, smid); | 1039 | if (!chain_req) |
1040 | return -1; | ||
1041 | chain = chain_req->chain_buffer; | ||
1042 | chain_dma = chain_req->chain_buffer_dma; | ||
1038 | do { | 1043 | do { |
1039 | sges_in_segment = (sges_left <= | 1044 | sges_in_segment = (sges_left <= |
1040 | ioc->max_sges_in_chain_message) ? sges_left : | 1045 | ioc->max_sges_in_chain_message) ? sges_left : |
@@ -1070,8 +1075,11 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, | |||
1070 | sges_in_segment--; | 1075 | sges_in_segment--; |
1071 | } | 1076 | } |
1072 | 1077 | ||
1073 | chain_dma += ioc->request_sz; | 1078 | chain_req = _scsih_get_chain_buffer_tracker(ioc, smid); |
1074 | chain += ioc->request_sz; | 1079 | if (!chain_req) |
1080 | return -1; | ||
1081 | chain = chain_req->chain_buffer; | ||
1082 | chain_dma = chain_req->chain_buffer_dma; | ||
1075 | } while (1); | 1083 | } while (1); |
1076 | 1084 | ||
1077 | 1085 | ||