diff options
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); |