diff options
author | bo yang <bo.yang@lsi.com> | 2007-11-09 04:40:16 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-11 19:22:44 -0500 |
commit | ad84db2e2e1817bb8a29e7c9108eb66bf023d99f (patch) | |
tree | 3dad9cd19c3bc2c9c6e98612c050a9e8343c3f65 /drivers/scsi/megaraid/megaraid_sas.c | |
parent | 7343eb6570ae3b299e7b5185b139d8335ef60e9b (diff) |
[SCSI] megaraid_sas: support for poll_mode_io (reduced interrupt)
Added module parameter "poll_mode_io" to support for "polling"
(reduced interrupt operation). In this mode, IO completion interrupts
are delayed. At the end of initiating IOs, the driver schedules for
cmd completion if there are pending cmds. A timer-based interrupt has
also been added to prevent IO completion from being delayed
indefinitely in the case that no new IOs are initiated. Some
formatting issues in resume, suspend comment block also corrected
Signed-off-by: Bo Yang <bo.yang@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/megaraid/megaraid_sas.c')
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.c | 152 |
1 files changed, 146 insertions, 6 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 08c3d4315eb8..499f994f503d 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c | |||
@@ -47,6 +47,14 @@ | |||
47 | #include <scsi/scsi_host.h> | 47 | #include <scsi/scsi_host.h> |
48 | #include "megaraid_sas.h" | 48 | #include "megaraid_sas.h" |
49 | 49 | ||
50 | /* | ||
51 | * poll_mode_io:1- schedule complete completion from q cmd | ||
52 | */ | ||
53 | static unsigned int poll_mode_io; | ||
54 | module_param_named(poll_mode_io, poll_mode_io, int, 0); | ||
55 | MODULE_PARM_DESC(poll_mode_io, | ||
56 | "Complete cmds from IO path, (default=0)"); | ||
57 | |||
50 | MODULE_LICENSE("GPL"); | 58 | MODULE_LICENSE("GPL"); |
51 | MODULE_VERSION(MEGASAS_VERSION); | 59 | MODULE_VERSION(MEGASAS_VERSION); |
52 | MODULE_AUTHOR("megaraidlinux@lsi.com"); | 60 | MODULE_AUTHOR("megaraidlinux@lsi.com"); |
@@ -860,6 +868,12 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) | |||
860 | atomic_inc(&instance->fw_outstanding); | 868 | atomic_inc(&instance->fw_outstanding); |
861 | 869 | ||
862 | instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set); | 870 | instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set); |
871 | /* | ||
872 | * Check if we have pend cmds to be completed | ||
873 | */ | ||
874 | if (poll_mode_io && atomic_read(&instance->fw_outstanding)) | ||
875 | tasklet_schedule(&instance->isr_tasklet); | ||
876 | |||
863 | 877 | ||
864 | return 0; | 878 | return 0; |
865 | 879 | ||
@@ -1892,6 +1906,47 @@ fail_fw_init: | |||
1892 | } | 1906 | } |
1893 | 1907 | ||
1894 | /** | 1908 | /** |
1909 | * megasas_start_timer - Initializes a timer object | ||
1910 | * @instance: Adapter soft state | ||
1911 | * @timer: timer object to be initialized | ||
1912 | * @fn: timer function | ||
1913 | * @interval: time interval between timer function call | ||
1914 | */ | ||
1915 | static inline void | ||
1916 | megasas_start_timer(struct megasas_instance *instance, | ||
1917 | struct timer_list *timer, | ||
1918 | void *fn, unsigned long interval) | ||
1919 | { | ||
1920 | init_timer(timer); | ||
1921 | timer->expires = jiffies + interval; | ||
1922 | timer->data = (unsigned long)instance; | ||
1923 | timer->function = fn; | ||
1924 | add_timer(timer); | ||
1925 | } | ||
1926 | |||
1927 | /** | ||
1928 | * megasas_io_completion_timer - Timer fn | ||
1929 | * @instance_addr: Address of adapter soft state | ||
1930 | * | ||
1931 | * Schedules tasklet for cmd completion | ||
1932 | * if poll_mode_io is set | ||
1933 | */ | ||
1934 | static void | ||
1935 | megasas_io_completion_timer(unsigned long instance_addr) | ||
1936 | { | ||
1937 | struct megasas_instance *instance = | ||
1938 | (struct megasas_instance *)instance_addr; | ||
1939 | |||
1940 | if (atomic_read(&instance->fw_outstanding)) | ||
1941 | tasklet_schedule(&instance->isr_tasklet); | ||
1942 | |||
1943 | /* Restart timer */ | ||
1944 | if (poll_mode_io) | ||
1945 | mod_timer(&instance->io_completion_timer, | ||
1946 | jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL); | ||
1947 | } | ||
1948 | |||
1949 | /** | ||
1895 | * megasas_init_mfi - Initializes the FW | 1950 | * megasas_init_mfi - Initializes the FW |
1896 | * @instance: Adapter soft state | 1951 | * @instance: Adapter soft state |
1897 | * | 1952 | * |
@@ -2017,8 +2072,14 @@ static int megasas_init_mfi(struct megasas_instance *instance) | |||
2017 | * Setup tasklet for cmd completion | 2072 | * Setup tasklet for cmd completion |
2018 | */ | 2073 | */ |
2019 | 2074 | ||
2020 | tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc, | 2075 | tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc, |
2021 | (unsigned long)instance); | 2076 | (unsigned long)instance); |
2077 | |||
2078 | /* Initialize the cmd completion timer */ | ||
2079 | if (poll_mode_io) | ||
2080 | megasas_start_timer(instance, &instance->io_completion_timer, | ||
2081 | megasas_io_completion_timer, | ||
2082 | MEGASAS_COMPLETION_TIMER_INTERVAL); | ||
2022 | return 0; | 2083 | return 0; |
2023 | 2084 | ||
2024 | fail_fw_init: | 2085 | fail_fw_init: |
@@ -2578,8 +2639,8 @@ static void megasas_shutdown_controller(struct megasas_instance *instance, | |||
2578 | } | 2639 | } |
2579 | 2640 | ||
2580 | /** | 2641 | /** |
2581 | * megasas_suspend - driver suspend entry point | 2642 | * megasas_suspend - driver suspend entry point |
2582 | * @pdev: PCI device structure | 2643 | * @pdev: PCI device structure |
2583 | * @state: PCI power state to suspend routine | 2644 | * @state: PCI power state to suspend routine |
2584 | */ | 2645 | */ |
2585 | static int __devinit | 2646 | static int __devinit |
@@ -2591,6 +2652,9 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state) | |||
2591 | instance = pci_get_drvdata(pdev); | 2652 | instance = pci_get_drvdata(pdev); |
2592 | host = instance->host; | 2653 | host = instance->host; |
2593 | 2654 | ||
2655 | if (poll_mode_io) | ||
2656 | del_timer_sync(&instance->io_completion_timer); | ||
2657 | |||
2594 | megasas_flush_cache(instance); | 2658 | megasas_flush_cache(instance); |
2595 | megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN); | 2659 | megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN); |
2596 | tasklet_kill(&instance->isr_tasklet); | 2660 | tasklet_kill(&instance->isr_tasklet); |
@@ -2677,6 +2741,11 @@ megasas_resume(struct pci_dev *pdev) | |||
2677 | if (megasas_start_aen(instance)) | 2741 | if (megasas_start_aen(instance)) |
2678 | printk(KERN_ERR "megasas: Start AEN failed\n"); | 2742 | printk(KERN_ERR "megasas: Start AEN failed\n"); |
2679 | 2743 | ||
2744 | /* Initialize the cmd completion timer */ | ||
2745 | if (poll_mode_io) | ||
2746 | megasas_start_timer(instance, &instance->io_completion_timer, | ||
2747 | megasas_io_completion_timer, | ||
2748 | MEGASAS_COMPLETION_TIMER_INTERVAL); | ||
2680 | return 0; | 2749 | return 0; |
2681 | 2750 | ||
2682 | fail_irq: | 2751 | fail_irq: |
@@ -2715,6 +2784,9 @@ static void megasas_detach_one(struct pci_dev *pdev) | |||
2715 | instance = pci_get_drvdata(pdev); | 2784 | instance = pci_get_drvdata(pdev); |
2716 | host = instance->host; | 2785 | host = instance->host; |
2717 | 2786 | ||
2787 | if (poll_mode_io) | ||
2788 | del_timer_sync(&instance->io_completion_timer); | ||
2789 | |||
2718 | scsi_remove_host(instance->host); | 2790 | scsi_remove_host(instance->host); |
2719 | megasas_flush_cache(instance); | 2791 | megasas_flush_cache(instance); |
2720 | megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); | 2792 | megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); |
@@ -3188,7 +3260,7 @@ static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date, | |||
3188 | static ssize_t | 3260 | static ssize_t |
3189 | megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf) | 3261 | megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf) |
3190 | { | 3262 | { |
3191 | return sprintf(buf,"%u",megasas_dbg_lvl); | 3263 | return sprintf(buf, "%u\n", megasas_dbg_lvl); |
3192 | } | 3264 | } |
3193 | 3265 | ||
3194 | static ssize_t | 3266 | static ssize_t |
@@ -3203,7 +3275,65 @@ megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t coun | |||
3203 | } | 3275 | } |
3204 | 3276 | ||
3205 | static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl, | 3277 | static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl, |
3206 | megasas_sysfs_set_dbg_lvl); | 3278 | megasas_sysfs_set_dbg_lvl); |
3279 | |||
3280 | static ssize_t | ||
3281 | megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf) | ||
3282 | { | ||
3283 | return sprintf(buf, "%u\n", poll_mode_io); | ||
3284 | } | ||
3285 | |||
3286 | static ssize_t | ||
3287 | megasas_sysfs_set_poll_mode_io(struct device_driver *dd, | ||
3288 | const char *buf, size_t count) | ||
3289 | { | ||
3290 | int retval = count; | ||
3291 | int tmp = poll_mode_io; | ||
3292 | int i; | ||
3293 | struct megasas_instance *instance; | ||
3294 | |||
3295 | if (sscanf(buf, "%u", &poll_mode_io) < 1) { | ||
3296 | printk(KERN_ERR "megasas: could not set poll_mode_io\n"); | ||
3297 | retval = -EINVAL; | ||
3298 | } | ||
3299 | |||
3300 | /* | ||
3301 | * Check if poll_mode_io is already set or is same as previous value | ||
3302 | */ | ||
3303 | if ((tmp && poll_mode_io) || (tmp == poll_mode_io)) | ||
3304 | goto out; | ||
3305 | |||
3306 | if (poll_mode_io) { | ||
3307 | /* | ||
3308 | * Start timers for all adapters | ||
3309 | */ | ||
3310 | for (i = 0; i < megasas_mgmt_info.max_index; i++) { | ||
3311 | instance = megasas_mgmt_info.instance[i]; | ||
3312 | if (instance) { | ||
3313 | megasas_start_timer(instance, | ||
3314 | &instance->io_completion_timer, | ||
3315 | megasas_io_completion_timer, | ||
3316 | MEGASAS_COMPLETION_TIMER_INTERVAL); | ||
3317 | } | ||
3318 | } | ||
3319 | } else { | ||
3320 | /* | ||
3321 | * Delete timers for all adapters | ||
3322 | */ | ||
3323 | for (i = 0; i < megasas_mgmt_info.max_index; i++) { | ||
3324 | instance = megasas_mgmt_info.instance[i]; | ||
3325 | if (instance) | ||
3326 | del_timer_sync(&instance->io_completion_timer); | ||
3327 | } | ||
3328 | } | ||
3329 | |||
3330 | out: | ||
3331 | return retval; | ||
3332 | } | ||
3333 | |||
3334 | static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO, | ||
3335 | megasas_sysfs_show_poll_mode_io, | ||
3336 | megasas_sysfs_set_poll_mode_io); | ||
3207 | 3337 | ||
3208 | /** | 3338 | /** |
3209 | * megasas_init - Driver load entry point | 3339 | * megasas_init - Driver load entry point |
@@ -3254,8 +3384,16 @@ static int __init megasas_init(void) | |||
3254 | &driver_attr_dbg_lvl); | 3384 | &driver_attr_dbg_lvl); |
3255 | if (rval) | 3385 | if (rval) |
3256 | goto err_dcf_dbg_lvl; | 3386 | goto err_dcf_dbg_lvl; |
3387 | rval = driver_create_file(&megasas_pci_driver.driver, | ||
3388 | &driver_attr_poll_mode_io); | ||
3389 | if (rval) | ||
3390 | goto err_dcf_poll_mode_io; | ||
3257 | 3391 | ||
3258 | return rval; | 3392 | return rval; |
3393 | |||
3394 | err_dcf_poll_mode_io: | ||
3395 | driver_remove_file(&megasas_pci_driver.driver, | ||
3396 | &driver_attr_dbg_lvl); | ||
3259 | err_dcf_dbg_lvl: | 3397 | err_dcf_dbg_lvl: |
3260 | driver_remove_file(&megasas_pci_driver.driver, | 3398 | driver_remove_file(&megasas_pci_driver.driver, |
3261 | &driver_attr_release_date); | 3399 | &driver_attr_release_date); |
@@ -3274,6 +3412,8 @@ err_pcidrv: | |||
3274 | static void __exit megasas_exit(void) | 3412 | static void __exit megasas_exit(void) |
3275 | { | 3413 | { |
3276 | driver_remove_file(&megasas_pci_driver.driver, | 3414 | driver_remove_file(&megasas_pci_driver.driver, |
3415 | &driver_attr_poll_mode_io); | ||
3416 | driver_remove_file(&megasas_pci_driver.driver, | ||
3277 | &driver_attr_dbg_lvl); | 3417 | &driver_attr_dbg_lvl); |
3278 | driver_remove_file(&megasas_pci_driver.driver, | 3418 | driver_remove_file(&megasas_pci_driver.driver, |
3279 | &driver_attr_release_date); | 3419 | &driver_attr_release_date); |