diff options
Diffstat (limited to 'drivers')
| -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 |
