aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/megaraid
diff options
context:
space:
mode:
authorbo yang <bo.yang@lsi.com>2007-11-07 12:09:50 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-11 19:22:43 -0500
commit31ea7088974c2405e19d72f17c2afb103ef19e02 (patch)
tree6956005710481785d7c7aa04f2e72a87e5db4496 /drivers/scsi/megaraid
parent1e6c38cec08f88b0df88a34e80f15492cace74e9 (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.c302
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h1
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 */
1812static int
1813megasas_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
1877fail_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
2289static int
2290megasas_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
2307fail_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 */
2495static void megasas_shutdown_controller(struct megasas_instance *instance) 2529static 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 */
2567static int __devinit
2568megasas_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 */
2596static int __devinit
2597megasas_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
2664fail_irq:
2665fail_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
2679fail_set_dma_mask:
2680fail_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