diff options
author | bo yang <bo.yang@lsi.com> | 2007-11-07 12:09:50 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-11 19:22:43 -0500 |
commit | 31ea7088974c2405e19d72f17c2afb103ef19e02 (patch) | |
tree | 6956005710481785d7c7aa04f2e72a87e5db4496 /drivers/scsi/megaraid | |
parent | 1e6c38cec08f88b0df88a34e80f15492cace74e9 (diff) |
[SCSI] megaraid_sas: add hibernation support
Adding hibernation support. suspend, resume routine implemented.
Signed-off-by: Bo Yang <bo.yang@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/megaraid')
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.c | 302 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.h | 1 |
2 files changed, 233 insertions, 70 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 3ad379fcd18f..9aee2544798c 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c | |||
@@ -1804,6 +1804,81 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) | |||
1804 | } | 1804 | } |
1805 | 1805 | ||
1806 | /** | 1806 | /** |
1807 | * megasas_issue_init_mfi - Initializes the FW | ||
1808 | * @instance: Adapter soft state | ||
1809 | * | ||
1810 | * Issues the INIT MFI cmd | ||
1811 | */ | ||
1812 | static int | ||
1813 | megasas_issue_init_mfi(struct megasas_instance *instance) | ||
1814 | { | ||
1815 | u32 context; | ||
1816 | |||
1817 | struct megasas_cmd *cmd; | ||
1818 | |||
1819 | struct megasas_init_frame *init_frame; | ||
1820 | struct megasas_init_queue_info *initq_info; | ||
1821 | dma_addr_t init_frame_h; | ||
1822 | dma_addr_t initq_info_h; | ||
1823 | |||
1824 | /* | ||
1825 | * Prepare a init frame. Note the init frame points to queue info | ||
1826 | * structure. Each frame has SGL allocated after first 64 bytes. For | ||
1827 | * this frame - since we don't need any SGL - we use SGL's space as | ||
1828 | * queue info structure | ||
1829 | * | ||
1830 | * We will not get a NULL command below. We just created the pool. | ||
1831 | */ | ||
1832 | cmd = megasas_get_cmd(instance); | ||
1833 | |||
1834 | init_frame = (struct megasas_init_frame *)cmd->frame; | ||
1835 | initq_info = (struct megasas_init_queue_info *) | ||
1836 | ((unsigned long)init_frame + 64); | ||
1837 | |||
1838 | init_frame_h = cmd->frame_phys_addr; | ||
1839 | initq_info_h = init_frame_h + 64; | ||
1840 | |||
1841 | context = init_frame->context; | ||
1842 | memset(init_frame, 0, MEGAMFI_FRAME_SIZE); | ||
1843 | memset(initq_info, 0, sizeof(struct megasas_init_queue_info)); | ||
1844 | init_frame->context = context; | ||
1845 | |||
1846 | initq_info->reply_queue_entries = instance->max_fw_cmds + 1; | ||
1847 | initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h; | ||
1848 | |||
1849 | initq_info->producer_index_phys_addr_lo = instance->producer_h; | ||
1850 | initq_info->consumer_index_phys_addr_lo = instance->consumer_h; | ||
1851 | |||
1852 | init_frame->cmd = MFI_CMD_INIT; | ||
1853 | init_frame->cmd_status = 0xFF; | ||
1854 | init_frame->queue_info_new_phys_addr_lo = initq_info_h; | ||
1855 | |||
1856 | init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info); | ||
1857 | |||
1858 | /* | ||
1859 | * disable the intr before firing the init frame to FW | ||
1860 | */ | ||
1861 | instance->instancet->disable_intr(instance->reg_set); | ||
1862 | |||
1863 | /* | ||
1864 | * Issue the init frame in polled mode | ||
1865 | */ | ||
1866 | |||
1867 | if (megasas_issue_polled(instance, cmd)) { | ||
1868 | printk(KERN_ERR "megasas: Failed to init firmware\n"); | ||
1869 | megasas_return_cmd(instance, cmd); | ||
1870 | goto fail_fw_init; | ||
1871 | } | ||
1872 | |||
1873 | megasas_return_cmd(instance, cmd); | ||
1874 | |||
1875 | return 0; | ||
1876 | |||
1877 | fail_fw_init: | ||
1878 | return -EINVAL; | ||
1879 | } | ||
1880 | |||
1881 | /** | ||
1807 | * megasas_init_mfi - Initializes the FW | 1882 | * megasas_init_mfi - Initializes the FW |
1808 | * @instance: Adapter soft state | 1883 | * @instance: Adapter soft state |
1809 | * | 1884 | * |
@@ -1816,15 +1891,7 @@ static int megasas_init_mfi(struct megasas_instance *instance) | |||
1816 | u32 max_sectors_1; | 1891 | u32 max_sectors_1; |
1817 | u32 max_sectors_2; | 1892 | u32 max_sectors_2; |
1818 | struct megasas_register_set __iomem *reg_set; | 1893 | struct megasas_register_set __iomem *reg_set; |
1819 | |||
1820 | struct megasas_cmd *cmd; | ||
1821 | struct megasas_ctrl_info *ctrl_info; | 1894 | struct megasas_ctrl_info *ctrl_info; |
1822 | |||
1823 | struct megasas_init_frame *init_frame; | ||
1824 | struct megasas_init_queue_info *initq_info; | ||
1825 | dma_addr_t init_frame_h; | ||
1826 | dma_addr_t initq_info_h; | ||
1827 | |||
1828 | /* | 1895 | /* |
1829 | * Map the message registers | 1896 | * Map the message registers |
1830 | */ | 1897 | */ |
@@ -1901,52 +1968,8 @@ static int megasas_init_mfi(struct megasas_instance *instance) | |||
1901 | goto fail_reply_queue; | 1968 | goto fail_reply_queue; |
1902 | } | 1969 | } |
1903 | 1970 | ||
1904 | /* | 1971 | if (megasas_issue_init_mfi(instance)) |
1905 | * Prepare a init frame. Note the init frame points to queue info | ||
1906 | * structure. Each frame has SGL allocated after first 64 bytes. For | ||
1907 | * this frame - since we don't need any SGL - we use SGL's space as | ||
1908 | * queue info structure | ||
1909 | * | ||
1910 | * We will not get a NULL command below. We just created the pool. | ||
1911 | */ | ||
1912 | cmd = megasas_get_cmd(instance); | ||
1913 | |||
1914 | init_frame = (struct megasas_init_frame *)cmd->frame; | ||
1915 | initq_info = (struct megasas_init_queue_info *) | ||
1916 | ((unsigned long)init_frame + 64); | ||
1917 | |||
1918 | init_frame_h = cmd->frame_phys_addr; | ||
1919 | initq_info_h = init_frame_h + 64; | ||
1920 | |||
1921 | memset(init_frame, 0, MEGAMFI_FRAME_SIZE); | ||
1922 | memset(initq_info, 0, sizeof(struct megasas_init_queue_info)); | ||
1923 | |||
1924 | initq_info->reply_queue_entries = instance->max_fw_cmds + 1; | ||
1925 | initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h; | ||
1926 | |||
1927 | initq_info->producer_index_phys_addr_lo = instance->producer_h; | ||
1928 | initq_info->consumer_index_phys_addr_lo = instance->consumer_h; | ||
1929 | |||
1930 | init_frame->cmd = MFI_CMD_INIT; | ||
1931 | init_frame->cmd_status = 0xFF; | ||
1932 | init_frame->queue_info_new_phys_addr_lo = initq_info_h; | ||
1933 | |||
1934 | init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info); | ||
1935 | |||
1936 | /* | ||
1937 | * disable the intr before firing the init frame to FW | ||
1938 | */ | ||
1939 | instance->instancet->disable_intr(instance->reg_set); | ||
1940 | |||
1941 | /* | ||
1942 | * Issue the init frame in polled mode | ||
1943 | */ | ||
1944 | if (megasas_issue_polled(instance, cmd)) { | ||
1945 | printk(KERN_DEBUG "megasas: Failed to init firmware\n"); | ||
1946 | goto fail_fw_init; | 1972 | goto fail_fw_init; |
1947 | } | ||
1948 | |||
1949 | megasas_return_cmd(instance, cmd); | ||
1950 | 1973 | ||
1951 | ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL); | 1974 | ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL); |
1952 | 1975 | ||
@@ -1982,7 +2005,6 @@ static int megasas_init_mfi(struct megasas_instance *instance) | |||
1982 | return 0; | 2005 | return 0; |
1983 | 2006 | ||
1984 | fail_fw_init: | 2007 | fail_fw_init: |
1985 | megasas_return_cmd(instance, cmd); | ||
1986 | 2008 | ||
1987 | pci_free_consistent(instance->pdev, reply_q_sz, | 2009 | pci_free_consistent(instance->pdev, reply_q_sz, |
1988 | instance->reply_queue, instance->reply_queue_h); | 2010 | instance->reply_queue, instance->reply_queue_h); |
@@ -2264,6 +2286,28 @@ static int megasas_io_attach(struct megasas_instance *instance) | |||
2264 | return 0; | 2286 | return 0; |
2265 | } | 2287 | } |
2266 | 2288 | ||
2289 | static int | ||
2290 | megasas_set_dma_mask(struct pci_dev *pdev) | ||
2291 | { | ||
2292 | /* | ||
2293 | * All our contollers are capable of performing 64-bit DMA | ||
2294 | */ | ||
2295 | if (IS_DMA64) { | ||
2296 | if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) { | ||
2297 | |||
2298 | if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) | ||
2299 | goto fail_set_dma_mask; | ||
2300 | } | ||
2301 | } else { | ||
2302 | if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) | ||
2303 | goto fail_set_dma_mask; | ||
2304 | } | ||
2305 | return 0; | ||
2306 | |||
2307 | fail_set_dma_mask: | ||
2308 | return 1; | ||
2309 | } | ||
2310 | |||
2267 | /** | 2311 | /** |
2268 | * megasas_probe_one - PCI hotplug entry point | 2312 | * megasas_probe_one - PCI hotplug entry point |
2269 | * @pdev: PCI device structure | 2313 | * @pdev: PCI device structure |
@@ -2297,19 +2341,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
2297 | 2341 | ||
2298 | pci_set_master(pdev); | 2342 | pci_set_master(pdev); |
2299 | 2343 | ||
2300 | /* | 2344 | if (megasas_set_dma_mask(pdev)) |
2301 | * All our contollers are capable of performing 64-bit DMA | 2345 | goto fail_set_dma_mask; |
2302 | */ | ||
2303 | if (IS_DMA64) { | ||
2304 | if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) { | ||
2305 | |||
2306 | if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) | ||
2307 | goto fail_set_dma_mask; | ||
2308 | } | ||
2309 | } else { | ||
2310 | if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) | ||
2311 | goto fail_set_dma_mask; | ||
2312 | } | ||
2313 | 2346 | ||
2314 | host = scsi_host_alloc(&megasas_template, | 2347 | host = scsi_host_alloc(&megasas_template, |
2315 | sizeof(struct megasas_instance)); | 2348 | sizeof(struct megasas_instance)); |
@@ -2491,8 +2524,10 @@ static void megasas_flush_cache(struct megasas_instance *instance) | |||
2491 | /** | 2524 | /** |
2492 | * megasas_shutdown_controller - Instructs FW to shutdown the controller | 2525 | * megasas_shutdown_controller - Instructs FW to shutdown the controller |
2493 | * @instance: Adapter soft state | 2526 | * @instance: Adapter soft state |
2527 | * @opcode: Shutdown/Hibernate | ||
2494 | */ | 2528 | */ |
2495 | static void megasas_shutdown_controller(struct megasas_instance *instance) | 2529 | static void megasas_shutdown_controller(struct megasas_instance *instance, |
2530 | u32 opcode) | ||
2496 | { | 2531 | { |
2497 | struct megasas_cmd *cmd; | 2532 | struct megasas_cmd *cmd; |
2498 | struct megasas_dcmd_frame *dcmd; | 2533 | struct megasas_dcmd_frame *dcmd; |
@@ -2515,7 +2550,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance) | |||
2515 | dcmd->flags = MFI_FRAME_DIR_NONE; | 2550 | dcmd->flags = MFI_FRAME_DIR_NONE; |
2516 | dcmd->timeout = 0; | 2551 | dcmd->timeout = 0; |
2517 | dcmd->data_xfer_len = 0; | 2552 | dcmd->data_xfer_len = 0; |
2518 | dcmd->opcode = MR_DCMD_CTRL_SHUTDOWN; | 2553 | dcmd->opcode = opcode; |
2519 | 2554 | ||
2520 | megasas_issue_blocked_cmd(instance, cmd); | 2555 | megasas_issue_blocked_cmd(instance, cmd); |
2521 | 2556 | ||
@@ -2525,6 +2560,131 @@ static void megasas_shutdown_controller(struct megasas_instance *instance) | |||
2525 | } | 2560 | } |
2526 | 2561 | ||
2527 | /** | 2562 | /** |
2563 | * megasas_suspend - driver suspend entry point | ||
2564 | * @pdev: PCI device structure | ||
2565 | * @state: PCI power state to suspend routine | ||
2566 | */ | ||
2567 | static int __devinit | ||
2568 | megasas_suspend(struct pci_dev *pdev, pm_message_t state) | ||
2569 | { | ||
2570 | struct Scsi_Host *host; | ||
2571 | struct megasas_instance *instance; | ||
2572 | |||
2573 | instance = pci_get_drvdata(pdev); | ||
2574 | host = instance->host; | ||
2575 | |||
2576 | megasas_flush_cache(instance); | ||
2577 | megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN); | ||
2578 | tasklet_kill(&instance->isr_tasklet); | ||
2579 | |||
2580 | pci_set_drvdata(instance->pdev, instance); | ||
2581 | instance->instancet->disable_intr(instance->reg_set); | ||
2582 | free_irq(instance->pdev->irq, instance); | ||
2583 | |||
2584 | pci_save_state(pdev); | ||
2585 | pci_disable_device(pdev); | ||
2586 | |||
2587 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
2588 | |||
2589 | return 0; | ||
2590 | } | ||
2591 | |||
2592 | /** | ||
2593 | * megasas_resume- driver resume entry point | ||
2594 | * @pdev: PCI device structure | ||
2595 | */ | ||
2596 | static int __devinit | ||
2597 | megasas_resume(struct pci_dev *pdev) | ||
2598 | { | ||
2599 | int rval; | ||
2600 | struct Scsi_Host *host; | ||
2601 | struct megasas_instance *instance; | ||
2602 | |||
2603 | instance = pci_get_drvdata(pdev); | ||
2604 | host = instance->host; | ||
2605 | pci_set_power_state(pdev, PCI_D0); | ||
2606 | pci_enable_wake(pdev, PCI_D0, 0); | ||
2607 | pci_restore_state(pdev); | ||
2608 | |||
2609 | /* | ||
2610 | * PCI prepping: enable device set bus mastering and dma mask | ||
2611 | */ | ||
2612 | rval = pci_enable_device(pdev); | ||
2613 | |||
2614 | if (rval) { | ||
2615 | printk(KERN_ERR "megasas: Enable device failed\n"); | ||
2616 | return rval; | ||
2617 | } | ||
2618 | |||
2619 | pci_set_master(pdev); | ||
2620 | |||
2621 | if (megasas_set_dma_mask(pdev)) | ||
2622 | goto fail_set_dma_mask; | ||
2623 | |||
2624 | /* | ||
2625 | * Initialize MFI Firmware | ||
2626 | */ | ||
2627 | |||
2628 | *instance->producer = 0; | ||
2629 | *instance->consumer = 0; | ||
2630 | |||
2631 | atomic_set(&instance->fw_outstanding, 0); | ||
2632 | |||
2633 | /* | ||
2634 | * We expect the FW state to be READY | ||
2635 | */ | ||
2636 | if (megasas_transition_to_ready(instance)) | ||
2637 | goto fail_ready_state; | ||
2638 | |||
2639 | if (megasas_issue_init_mfi(instance)) | ||
2640 | goto fail_init_mfi; | ||
2641 | |||
2642 | tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc, | ||
2643 | (unsigned long)instance); | ||
2644 | |||
2645 | /* | ||
2646 | * Register IRQ | ||
2647 | */ | ||
2648 | if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED, | ||
2649 | "megasas", instance)) { | ||
2650 | printk(KERN_ERR "megasas: Failed to register IRQ\n"); | ||
2651 | goto fail_irq; | ||
2652 | } | ||
2653 | |||
2654 | instance->instancet->enable_intr(instance->reg_set); | ||
2655 | |||
2656 | /* | ||
2657 | * Initiate AEN (Asynchronous Event Notification) | ||
2658 | */ | ||
2659 | if (megasas_start_aen(instance)) | ||
2660 | printk(KERN_ERR "megasas: Start AEN failed\n"); | ||
2661 | |||
2662 | return 0; | ||
2663 | |||
2664 | fail_irq: | ||
2665 | fail_init_mfi: | ||
2666 | if (instance->evt_detail) | ||
2667 | pci_free_consistent(pdev, sizeof(struct megasas_evt_detail), | ||
2668 | instance->evt_detail, | ||
2669 | instance->evt_detail_h); | ||
2670 | |||
2671 | if (instance->producer) | ||
2672 | pci_free_consistent(pdev, sizeof(u32), instance->producer, | ||
2673 | instance->producer_h); | ||
2674 | if (instance->consumer) | ||
2675 | pci_free_consistent(pdev, sizeof(u32), instance->consumer, | ||
2676 | instance->consumer_h); | ||
2677 | scsi_host_put(host); | ||
2678 | |||
2679 | fail_set_dma_mask: | ||
2680 | fail_ready_state: | ||
2681 | |||
2682 | pci_disable_device(pdev); | ||
2683 | |||
2684 | return -ENODEV; | ||
2685 | } | ||
2686 | |||
2687 | /** | ||
2528 | * megasas_detach_one - PCI hot"un"plug entry point | 2688 | * megasas_detach_one - PCI hot"un"plug entry point |
2529 | * @pdev: PCI device structure | 2689 | * @pdev: PCI device structure |
2530 | */ | 2690 | */ |
@@ -2539,7 +2699,7 @@ static void megasas_detach_one(struct pci_dev *pdev) | |||
2539 | 2699 | ||
2540 | scsi_remove_host(instance->host); | 2700 | scsi_remove_host(instance->host); |
2541 | megasas_flush_cache(instance); | 2701 | megasas_flush_cache(instance); |
2542 | megasas_shutdown_controller(instance); | 2702 | megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); |
2543 | tasklet_kill(&instance->isr_tasklet); | 2703 | tasklet_kill(&instance->isr_tasklet); |
2544 | 2704 | ||
2545 | /* | 2705 | /* |
@@ -2978,6 +3138,8 @@ static struct pci_driver megasas_pci_driver = { | |||
2978 | .id_table = megasas_pci_table, | 3138 | .id_table = megasas_pci_table, |
2979 | .probe = megasas_probe_one, | 3139 | .probe = megasas_probe_one, |
2980 | .remove = __devexit_p(megasas_detach_one), | 3140 | .remove = __devexit_p(megasas_detach_one), |
3141 | .suspend = megasas_suspend, | ||
3142 | .resume = megasas_resume, | ||
2981 | .shutdown = megasas_shutdown, | 3143 | .shutdown = megasas_shutdown, |
2982 | }; | 3144 | }; |
2983 | 3145 | ||
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 08c74c991781..f4ab30094621 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h | |||
@@ -117,6 +117,7 @@ | |||
117 | #define MR_FLUSH_DISK_CACHE 0x02 | 117 | #define MR_FLUSH_DISK_CACHE 0x02 |
118 | 118 | ||
119 | #define MR_DCMD_CTRL_SHUTDOWN 0x01050000 | 119 | #define MR_DCMD_CTRL_SHUTDOWN 0x01050000 |
120 | #define MR_DCMD_HIBERNATE_SHUTDOWN 0x01060000 | ||
120 | #define MR_ENABLE_DRIVE_SPINDOWN 0x01 | 121 | #define MR_ENABLE_DRIVE_SPINDOWN 0x01 |
121 | 122 | ||
122 | #define MR_DCMD_CTRL_EVENT_GET_INFO 0x01040100 | 123 | #define MR_DCMD_CTRL_EVENT_GET_INFO 0x01040100 |