diff options
author | Sumit Saxena <sumit.saxena@avagotech.com> | 2016-01-28 10:34:30 -0500 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2016-02-23 21:27:02 -0500 |
commit | 308ec459bc1975d9856cfeb3d1cd6461794a3976 (patch) | |
tree | 375d7a68f08adf3420da7f0158b033489f239e50 | |
parent | f9a9dee6a1fd8570884a0ab6f19c6b5cca05bd49 (diff) |
megaraid_sas: Dual queue depth support
1. For iMR controllers, firmware will report two queue depths:
- Controller-wide queue depth
- LDIO queue depth (240)
Controller-wide queue depth will be greater among the two. Using this
new feature, iMR can provide larger Queue depth(QD) for JBOD and limited
QD for Virtual Disk(VD).
2. megaraid_sas driver will throttle read/write LDIOs based on "LDIO
Queue Depth".
3. Dual queue depth can be enabled/disabled via module parameter. It is
enabled by default if the firmware supports it. Only specific firmware
builds will enable the feature.
4. Added sysfs parameter "ldio_outstanding" which permits querying the
number of outstanding LDIO requests at runtime.
Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.h | 9 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_base.c | 20 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_fusion.c | 88 |
3 files changed, 107 insertions, 10 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 3b1ed2d86efe..2a2f49134491 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h | |||
@@ -1353,6 +1353,12 @@ enum DCMD_TIMEOUT_ACTION { | |||
1353 | KILL_ADAPTER = 1, | 1353 | KILL_ADAPTER = 1, |
1354 | IGNORE_TIMEOUT = 2, | 1354 | IGNORE_TIMEOUT = 2, |
1355 | }; | 1355 | }; |
1356 | |||
1357 | enum FW_BOOT_CONTEXT { | ||
1358 | PROBE_CONTEXT = 0, | ||
1359 | OCR_CONTEXT = 1, | ||
1360 | }; | ||
1361 | |||
1356 | /* Frame Type */ | 1362 | /* Frame Type */ |
1357 | #define IO_FRAME 0 | 1363 | #define IO_FRAME 0 |
1358 | #define PTHRU_FRAME 1 | 1364 | #define PTHRU_FRAME 1 |
@@ -2038,6 +2044,8 @@ struct megasas_instance { | |||
2038 | u16 max_fw_cmds; | 2044 | u16 max_fw_cmds; |
2039 | u16 max_mfi_cmds; | 2045 | u16 max_mfi_cmds; |
2040 | u16 max_scsi_cmds; | 2046 | u16 max_scsi_cmds; |
2047 | u16 ldio_threshold; | ||
2048 | u16 cur_can_queue; | ||
2041 | u32 max_sectors_per_req; | 2049 | u32 max_sectors_per_req; |
2042 | struct megasas_aen_event *ev; | 2050 | struct megasas_aen_event *ev; |
2043 | 2051 | ||
@@ -2068,6 +2076,7 @@ struct megasas_instance { | |||
2068 | u32 fw_support_ieee; | 2076 | u32 fw_support_ieee; |
2069 | 2077 | ||
2070 | atomic_t fw_outstanding; | 2078 | atomic_t fw_outstanding; |
2079 | atomic_t ldio_outstanding; | ||
2071 | atomic_t fw_reset_no_pci_access; | 2080 | atomic_t fw_reset_no_pci_access; |
2072 | 2081 | ||
2073 | struct megasas_instance_template *instancet; | 2082 | struct megasas_instance_template *instancet; |
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index edf8911bdb12..961c024d11ca 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c | |||
@@ -96,6 +96,10 @@ int rdpq_enable = 1; | |||
96 | module_param(rdpq_enable, int, S_IRUGO); | 96 | module_param(rdpq_enable, int, S_IRUGO); |
97 | MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disable Default: disable(0)"); | 97 | MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disable Default: disable(0)"); |
98 | 98 | ||
99 | unsigned int dual_qdepth_disable; | ||
100 | module_param(dual_qdepth_disable, int, S_IRUGO); | ||
101 | MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0"); | ||
102 | |||
99 | MODULE_LICENSE("GPL"); | 103 | MODULE_LICENSE("GPL"); |
100 | MODULE_VERSION(MEGASAS_VERSION); | 104 | MODULE_VERSION(MEGASAS_VERSION); |
101 | MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com"); | 105 | MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com"); |
@@ -1976,7 +1980,7 @@ megasas_check_and_restore_queue_depth(struct megasas_instance *instance) | |||
1976 | spin_lock_irqsave(instance->host->host_lock, flags); | 1980 | spin_lock_irqsave(instance->host->host_lock, flags); |
1977 | instance->flag &= ~MEGASAS_FW_BUSY; | 1981 | instance->flag &= ~MEGASAS_FW_BUSY; |
1978 | 1982 | ||
1979 | instance->host->can_queue = instance->max_scsi_cmds; | 1983 | instance->host->can_queue = instance->cur_can_queue; |
1980 | spin_unlock_irqrestore(instance->host->host_lock, flags); | 1984 | spin_unlock_irqrestore(instance->host->host_lock, flags); |
1981 | } | 1985 | } |
1982 | } | 1986 | } |
@@ -2941,6 +2945,16 @@ megasas_page_size_show(struct device *cdev, | |||
2941 | return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1); | 2945 | return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1); |
2942 | } | 2946 | } |
2943 | 2947 | ||
2948 | static ssize_t | ||
2949 | megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr, | ||
2950 | char *buf) | ||
2951 | { | ||
2952 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2953 | struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata; | ||
2954 | |||
2955 | return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->ldio_outstanding)); | ||
2956 | } | ||
2957 | |||
2944 | static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR, | 2958 | static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR, |
2945 | megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store); | 2959 | megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store); |
2946 | static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO, | 2960 | static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO, |
@@ -2949,12 +2963,15 @@ static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR, | |||
2949 | megasas_fw_crash_state_show, megasas_fw_crash_state_store); | 2963 | megasas_fw_crash_state_show, megasas_fw_crash_state_store); |
2950 | static DEVICE_ATTR(page_size, S_IRUGO, | 2964 | static DEVICE_ATTR(page_size, S_IRUGO, |
2951 | megasas_page_size_show, NULL); | 2965 | megasas_page_size_show, NULL); |
2966 | static DEVICE_ATTR(ldio_outstanding, S_IRUGO, | ||
2967 | megasas_ldio_outstanding_show, NULL); | ||
2952 | 2968 | ||
2953 | struct device_attribute *megaraid_host_attrs[] = { | 2969 | struct device_attribute *megaraid_host_attrs[] = { |
2954 | &dev_attr_fw_crash_buffer_size, | 2970 | &dev_attr_fw_crash_buffer_size, |
2955 | &dev_attr_fw_crash_buffer, | 2971 | &dev_attr_fw_crash_buffer, |
2956 | &dev_attr_fw_crash_state, | 2972 | &dev_attr_fw_crash_state, |
2957 | &dev_attr_page_size, | 2973 | &dev_attr_page_size, |
2974 | &dev_attr_ldio_outstanding, | ||
2958 | NULL, | 2975 | NULL, |
2959 | }; | 2976 | }; |
2960 | 2977 | ||
@@ -4749,6 +4766,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance) | |||
4749 | sema_init(&instance->ioctl_sem, (MEGASAS_MFI_IOCTL_CMDS)); | 4766 | sema_init(&instance->ioctl_sem, (MEGASAS_MFI_IOCTL_CMDS)); |
4750 | } | 4767 | } |
4751 | 4768 | ||
4769 | instance->cur_can_queue = instance->max_scsi_cmds; | ||
4752 | /* | 4770 | /* |
4753 | * Create a pool of commands | 4771 | * Create a pool of commands |
4754 | */ | 4772 | */ |
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index f5538303a9bc..6b8547cf9de4 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c | |||
@@ -92,6 +92,7 @@ void megasas_start_timer(struct megasas_instance *instance, | |||
92 | void *fn, unsigned long interval); | 92 | void *fn, unsigned long interval); |
93 | extern struct megasas_mgmt_info megasas_mgmt_info; | 93 | extern struct megasas_mgmt_info megasas_mgmt_info; |
94 | extern int resetwaittime; | 94 | extern int resetwaittime; |
95 | extern unsigned int dual_qdepth_disable; | ||
95 | static void megasas_free_rdpq_fusion(struct megasas_instance *instance); | 96 | static void megasas_free_rdpq_fusion(struct megasas_instance *instance); |
96 | static void megasas_free_reply_fusion(struct megasas_instance *instance); | 97 | static void megasas_free_reply_fusion(struct megasas_instance *instance); |
97 | 98 | ||
@@ -208,6 +209,67 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance, | |||
208 | } | 209 | } |
209 | 210 | ||
210 | /** | 211 | /** |
212 | * megasas_fusion_update_can_queue - Do all Adapter Queue depth related calculations here | ||
213 | * @instance: Adapter soft state | ||
214 | * fw_boot_context: Whether this function called during probe or after OCR | ||
215 | * | ||
216 | * This function is only for fusion controllers. | ||
217 | * Update host can queue, if firmware downgrade max supported firmware commands. | ||
218 | * Firmware upgrade case will be skiped because underlying firmware has | ||
219 | * more resource than exposed to the OS. | ||
220 | * | ||
221 | */ | ||
222 | static void | ||
223 | megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_context) | ||
224 | { | ||
225 | u16 cur_max_fw_cmds = 0; | ||
226 | u16 ldio_threshold = 0; | ||
227 | struct megasas_register_set __iomem *reg_set; | ||
228 | |||
229 | reg_set = instance->reg_set; | ||
230 | |||
231 | cur_max_fw_cmds = readl(&instance->reg_set->outbound_scratch_pad_3) & 0x00FFFF; | ||
232 | |||
233 | if (dual_qdepth_disable || !cur_max_fw_cmds) | ||
234 | cur_max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF; | ||
235 | else | ||
236 | ldio_threshold = | ||
237 | (instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF) - MEGASAS_FUSION_IOCTL_CMDS; | ||
238 | |||
239 | dev_info(&instance->pdev->dev, | ||
240 | "Current firmware maximum commands: %d\t LDIO threshold: %d\n", | ||
241 | cur_max_fw_cmds, ldio_threshold); | ||
242 | |||
243 | if (fw_boot_context == OCR_CONTEXT) { | ||
244 | cur_max_fw_cmds = cur_max_fw_cmds - 1; | ||
245 | if (cur_max_fw_cmds <= instance->max_fw_cmds) { | ||
246 | instance->cur_can_queue = | ||
247 | cur_max_fw_cmds - (MEGASAS_FUSION_INTERNAL_CMDS + | ||
248 | MEGASAS_FUSION_IOCTL_CMDS); | ||
249 | instance->host->can_queue = instance->cur_can_queue; | ||
250 | instance->ldio_threshold = ldio_threshold; | ||
251 | } | ||
252 | } else { | ||
253 | instance->max_fw_cmds = cur_max_fw_cmds; | ||
254 | instance->ldio_threshold = ldio_threshold; | ||
255 | |||
256 | if (!instance->is_rdpq) | ||
257 | instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024); | ||
258 | |||
259 | /* | ||
260 | * Reduce the max supported cmds by 1. This is to ensure that the | ||
261 | * reply_q_sz (1 more than the max cmd that driver may send) | ||
262 | * does not exceed max cmds that the FW can support | ||
263 | */ | ||
264 | instance->max_fw_cmds = instance->max_fw_cmds-1; | ||
265 | |||
266 | instance->max_scsi_cmds = instance->max_fw_cmds - | ||
267 | (MEGASAS_FUSION_INTERNAL_CMDS + | ||
268 | MEGASAS_FUSION_IOCTL_CMDS); | ||
269 | instance->cur_can_queue = instance->max_scsi_cmds; | ||
270 | } | ||
271 | } | ||
272 | /** | ||
211 | * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool | 273 | * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool |
212 | * @instance: Adapter soft state | 274 | * @instance: Adapter soft state |
213 | */ | 275 | */ |
@@ -738,6 +800,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) | |||
738 | drv_ops->mfi_capabilities.support_ext_io_size = 1; | 800 | drv_ops->mfi_capabilities.support_ext_io_size = 1; |
739 | 801 | ||
740 | drv_ops->mfi_capabilities.support_fp_rlbypass = 1; | 802 | drv_ops->mfi_capabilities.support_fp_rlbypass = 1; |
803 | if (!dual_qdepth_disable) | ||
804 | drv_ops->mfi_capabilities.support_ext_queue_depth = 1; | ||
741 | 805 | ||
742 | /* Convert capability to LE32 */ | 806 | /* Convert capability to LE32 */ |
743 | cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities); | 807 | cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities); |
@@ -1153,15 +1217,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) | |||
1153 | 1217 | ||
1154 | reg_set = instance->reg_set; | 1218 | reg_set = instance->reg_set; |
1155 | 1219 | ||
1156 | /* | 1220 | megasas_fusion_update_can_queue(instance, PROBE_CONTEXT); |
1157 | * Get various operational parameters from status register | ||
1158 | */ | ||
1159 | instance->max_fw_cmds = | ||
1160 | instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF; | ||
1161 | dev_info(&instance->pdev->dev, | ||
1162 | "firmware support max fw cmd\t: (%d)\n", instance->max_fw_cmds); | ||
1163 | if (!instance->is_rdpq) | ||
1164 | instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024); | ||
1165 | 1221 | ||
1166 | /* | 1222 | /* |
1167 | * Reduce the max supported cmds by 1. This is to ensure that the | 1223 | * Reduce the max supported cmds by 1. This is to ensure that the |
@@ -2119,6 +2175,14 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, | |||
2119 | 2175 | ||
2120 | fusion = instance->ctrl_context; | 2176 | fusion = instance->ctrl_context; |
2121 | 2177 | ||
2178 | if ((megasas_cmd_type(scmd) == READ_WRITE_LDIO) && | ||
2179 | instance->ldio_threshold && | ||
2180 | (atomic_inc_return(&instance->ldio_outstanding) > | ||
2181 | instance->ldio_threshold)) { | ||
2182 | atomic_dec(&instance->ldio_outstanding); | ||
2183 | return SCSI_MLQUEUE_DEVICE_BUSY; | ||
2184 | } | ||
2185 | |||
2122 | cmd = megasas_get_cmd_fusion(instance, scmd->request->tag); | 2186 | cmd = megasas_get_cmd_fusion(instance, scmd->request->tag); |
2123 | 2187 | ||
2124 | index = cmd->index; | 2188 | index = cmd->index; |
@@ -2249,6 +2313,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) | |||
2249 | map_cmd_status(cmd_fusion, status, extStatus); | 2313 | map_cmd_status(cmd_fusion, status, extStatus); |
2250 | scsi_io_req->RaidContext.status = 0; | 2314 | scsi_io_req->RaidContext.status = 0; |
2251 | scsi_io_req->RaidContext.exStatus = 0; | 2315 | scsi_io_req->RaidContext.exStatus = 0; |
2316 | if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO) | ||
2317 | atomic_dec(&instance->ldio_outstanding); | ||
2252 | megasas_return_cmd_fusion(instance, cmd_fusion); | 2318 | megasas_return_cmd_fusion(instance, cmd_fusion); |
2253 | scsi_dma_unmap(scmd_local); | 2319 | scsi_dma_unmap(scmd_local); |
2254 | scmd_local->scsi_done(scmd_local); | 2320 | scmd_local->scsi_done(scmd_local); |
@@ -3367,6 +3433,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) | |||
3367 | scmd_local->result = | 3433 | scmd_local->result = |
3368 | megasas_check_mpio_paths(instance, | 3434 | megasas_check_mpio_paths(instance, |
3369 | scmd_local); | 3435 | scmd_local); |
3436 | if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO) | ||
3437 | atomic_dec(&instance->ldio_outstanding); | ||
3370 | megasas_return_cmd_fusion(instance, cmd_fusion); | 3438 | megasas_return_cmd_fusion(instance, cmd_fusion); |
3371 | scsi_dma_unmap(scmd_local); | 3439 | scsi_dma_unmap(scmd_local); |
3372 | scmd_local->scsi_done(scmd_local); | 3440 | scmd_local->scsi_done(scmd_local); |
@@ -3459,6 +3527,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) | |||
3459 | } | 3527 | } |
3460 | 3528 | ||
3461 | megasas_reset_reply_desc(instance); | 3529 | megasas_reset_reply_desc(instance); |
3530 | megasas_fusion_update_can_queue(instance, OCR_CONTEXT); | ||
3531 | |||
3462 | if (megasas_ioc_init_fusion(instance)) { | 3532 | if (megasas_ioc_init_fusion(instance)) { |
3463 | dev_warn(&instance->pdev->dev, | 3533 | dev_warn(&instance->pdev->dev, |
3464 | "megasas_ioc_init_fusion() failed!" | 3534 | "megasas_ioc_init_fusion() failed!" |