18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Linux MegaRAID device driver 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 2003-2004 LSI Logic Corporation. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * FILE : megaraid_mbox.c 98c2ecf20Sopenharmony_ci * Version : v2.20.5.1 (Nov 16 2006) 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Authors: 128c2ecf20Sopenharmony_ci * Atul Mukker <Atul.Mukker@lsi.com> 138c2ecf20Sopenharmony_ci * Sreenivas Bagalkote <Sreenivas.Bagalkote@lsi.com> 148c2ecf20Sopenharmony_ci * Manoj Jose <Manoj.Jose@lsi.com> 158c2ecf20Sopenharmony_ci * Seokmann Ju 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * List of supported controllers 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * OEM Product Name VID DID SSVID SSID 208c2ecf20Sopenharmony_ci * --- ------------ --- --- ---- ---- 218c2ecf20Sopenharmony_ci * Dell PERC3/QC 101E 1960 1028 0471 228c2ecf20Sopenharmony_ci * Dell PERC3/DC 101E 1960 1028 0493 238c2ecf20Sopenharmony_ci * Dell PERC3/SC 101E 1960 1028 0475 248c2ecf20Sopenharmony_ci * Dell PERC3/Di 1028 1960 1028 0123 258c2ecf20Sopenharmony_ci * Dell PERC4/SC 1000 1960 1028 0520 268c2ecf20Sopenharmony_ci * Dell PERC4/DC 1000 1960 1028 0518 278c2ecf20Sopenharmony_ci * Dell PERC4/QC 1000 0407 1028 0531 288c2ecf20Sopenharmony_ci * Dell PERC4/Di 1028 000F 1028 014A 298c2ecf20Sopenharmony_ci * Dell PERC 4e/Si 1028 0013 1028 016c 308c2ecf20Sopenharmony_ci * Dell PERC 4e/Di 1028 0013 1028 016d 318c2ecf20Sopenharmony_ci * Dell PERC 4e/Di 1028 0013 1028 016e 328c2ecf20Sopenharmony_ci * Dell PERC 4e/Di 1028 0013 1028 016f 338c2ecf20Sopenharmony_ci * Dell PERC 4e/Di 1028 0013 1028 0170 348c2ecf20Sopenharmony_ci * Dell PERC 4e/DC 1000 0408 1028 0002 358c2ecf20Sopenharmony_ci * Dell PERC 4e/SC 1000 0408 1028 0001 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * LSI MegaRAID SCSI 320-0 1000 1960 1000 A520 388c2ecf20Sopenharmony_ci * LSI MegaRAID SCSI 320-1 1000 1960 1000 0520 398c2ecf20Sopenharmony_ci * LSI MegaRAID SCSI 320-2 1000 1960 1000 0518 408c2ecf20Sopenharmony_ci * LSI MegaRAID SCSI 320-0X 1000 0407 1000 0530 418c2ecf20Sopenharmony_ci * LSI MegaRAID SCSI 320-2X 1000 0407 1000 0532 428c2ecf20Sopenharmony_ci * LSI MegaRAID SCSI 320-4X 1000 0407 1000 0531 438c2ecf20Sopenharmony_ci * LSI MegaRAID SCSI 320-1E 1000 0408 1000 0001 448c2ecf20Sopenharmony_ci * LSI MegaRAID SCSI 320-2E 1000 0408 1000 0002 458c2ecf20Sopenharmony_ci * LSI MegaRAID SATA 150-4 1000 1960 1000 4523 468c2ecf20Sopenharmony_ci * LSI MegaRAID SATA 150-6 1000 1960 1000 0523 478c2ecf20Sopenharmony_ci * LSI MegaRAID SATA 300-4X 1000 0409 1000 3004 488c2ecf20Sopenharmony_ci * LSI MegaRAID SATA 300-8X 1000 0409 1000 3008 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * INTEL RAID Controller SRCU42X 1000 0407 8086 0532 518c2ecf20Sopenharmony_ci * INTEL RAID Controller SRCS16 1000 1960 8086 0523 528c2ecf20Sopenharmony_ci * INTEL RAID Controller SRCU42E 1000 0408 8086 0002 538c2ecf20Sopenharmony_ci * INTEL RAID Controller SRCZCRX 1000 0407 8086 0530 548c2ecf20Sopenharmony_ci * INTEL RAID Controller SRCS28X 1000 0409 8086 3008 558c2ecf20Sopenharmony_ci * INTEL RAID Controller SROMBU42E 1000 0408 8086 3431 568c2ecf20Sopenharmony_ci * INTEL RAID Controller SROMBU42E 1000 0408 8086 3499 578c2ecf20Sopenharmony_ci * INTEL RAID Controller SRCU51L 1000 1960 8086 0520 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * FSC MegaRAID PCI Express ROMB 1000 0408 1734 1065 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * ACER MegaRAID ROMB-2E 1000 0408 1025 004D 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * NEC MegaRAID PCI Express ROMB 1000 0408 1033 8287 648c2ecf20Sopenharmony_ci * 658c2ecf20Sopenharmony_ci * For history of changes, see Documentation/scsi/ChangeLog.megaraid 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#include <linux/slab.h> 698c2ecf20Sopenharmony_ci#include <linux/module.h> 708c2ecf20Sopenharmony_ci#include "megaraid_mbox.h" 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic int megaraid_init(void); 738c2ecf20Sopenharmony_cistatic void megaraid_exit(void); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int megaraid_probe_one(struct pci_dev*, const struct pci_device_id *); 768c2ecf20Sopenharmony_cistatic void megaraid_detach_one(struct pci_dev *); 778c2ecf20Sopenharmony_cistatic void megaraid_mbox_shutdown(struct pci_dev *); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int megaraid_io_attach(adapter_t *); 808c2ecf20Sopenharmony_cistatic void megaraid_io_detach(adapter_t *); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int megaraid_init_mbox(adapter_t *); 838c2ecf20Sopenharmony_cistatic void megaraid_fini_mbox(adapter_t *); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int megaraid_alloc_cmd_packets(adapter_t *); 868c2ecf20Sopenharmony_cistatic void megaraid_free_cmd_packets(adapter_t *); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int megaraid_mbox_setup_dma_pools(adapter_t *); 898c2ecf20Sopenharmony_cistatic void megaraid_mbox_teardown_dma_pools(adapter_t *); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int megaraid_sysfs_alloc_resources(adapter_t *); 928c2ecf20Sopenharmony_cistatic void megaraid_sysfs_free_resources(adapter_t *); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int megaraid_abort_handler(struct scsi_cmnd *); 958c2ecf20Sopenharmony_cistatic int megaraid_reset_handler(struct scsi_cmnd *); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int mbox_post_sync_cmd(adapter_t *, uint8_t []); 988c2ecf20Sopenharmony_cistatic int mbox_post_sync_cmd_fast(adapter_t *, uint8_t []); 998c2ecf20Sopenharmony_cistatic int megaraid_busywait_mbox(mraid_device_t *); 1008c2ecf20Sopenharmony_cistatic int megaraid_mbox_product_info(adapter_t *); 1018c2ecf20Sopenharmony_cistatic int megaraid_mbox_extended_cdb(adapter_t *); 1028c2ecf20Sopenharmony_cistatic int megaraid_mbox_support_ha(adapter_t *, uint16_t *); 1038c2ecf20Sopenharmony_cistatic int megaraid_mbox_support_random_del(adapter_t *); 1048c2ecf20Sopenharmony_cistatic int megaraid_mbox_get_max_sg(adapter_t *); 1058c2ecf20Sopenharmony_cistatic void megaraid_mbox_enum_raid_scsi(adapter_t *); 1068c2ecf20Sopenharmony_cistatic void megaraid_mbox_flush_cache(adapter_t *); 1078c2ecf20Sopenharmony_cistatic int megaraid_mbox_fire_sync_cmd(adapter_t *); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void megaraid_mbox_display_scb(adapter_t *, scb_t *); 1108c2ecf20Sopenharmony_cistatic void megaraid_mbox_setup_device_map(adapter_t *); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int megaraid_queue_command(struct Scsi_Host *, struct scsi_cmnd *); 1138c2ecf20Sopenharmony_cistatic scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *); 1148c2ecf20Sopenharmony_cistatic void megaraid_mbox_runpendq(adapter_t *, scb_t *); 1158c2ecf20Sopenharmony_cistatic void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *, 1168c2ecf20Sopenharmony_ci struct scsi_cmnd *); 1178c2ecf20Sopenharmony_cistatic void megaraid_mbox_prepare_epthru(adapter_t *, scb_t *, 1188c2ecf20Sopenharmony_ci struct scsi_cmnd *); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic irqreturn_t megaraid_isr(int, void *); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic void megaraid_mbox_dpc(unsigned long); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic ssize_t megaraid_sysfs_show_app_hndl(struct device *, struct device_attribute *attr, char *); 1258c2ecf20Sopenharmony_cistatic ssize_t megaraid_sysfs_show_ldnum(struct device *, struct device_attribute *attr, char *); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int megaraid_cmm_register(adapter_t *); 1288c2ecf20Sopenharmony_cistatic int megaraid_cmm_unregister(adapter_t *); 1298c2ecf20Sopenharmony_cistatic int megaraid_mbox_mm_handler(unsigned long, uioc_t *, uint32_t); 1308c2ecf20Sopenharmony_cistatic int megaraid_mbox_mm_command(adapter_t *, uioc_t *); 1318c2ecf20Sopenharmony_cistatic void megaraid_mbox_mm_done(adapter_t *, scb_t *); 1328c2ecf20Sopenharmony_cistatic int gather_hbainfo(adapter_t *, mraid_hba_info_t *); 1338c2ecf20Sopenharmony_cistatic int wait_till_fw_empty(adapter_t *); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ciMODULE_AUTHOR("megaraidlinux@lsi.com"); 1388c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LSI Logic MegaRAID Mailbox Driver"); 1398c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1408c2ecf20Sopenharmony_ciMODULE_VERSION(MEGARAID_VERSION); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* 1438c2ecf20Sopenharmony_ci * ### modules parameters for driver ### 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* 1478c2ecf20Sopenharmony_ci * Set to enable driver to expose unconfigured disk to kernel 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_cistatic int megaraid_expose_unconf_disks = 0; 1508c2ecf20Sopenharmony_cimodule_param_named(unconf_disks, megaraid_expose_unconf_disks, int, 0); 1518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(unconf_disks, 1528c2ecf20Sopenharmony_ci "Set to expose unconfigured disks to kernel (default=0)"); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* 1558c2ecf20Sopenharmony_ci * driver wait time if the adapter's mailbox is busy 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_cistatic unsigned int max_mbox_busy_wait = MBOX_BUSY_WAIT; 1588c2ecf20Sopenharmony_cimodule_param_named(busy_wait, max_mbox_busy_wait, int, 0); 1598c2ecf20Sopenharmony_ciMODULE_PARM_DESC(busy_wait, 1608c2ecf20Sopenharmony_ci "Max wait for mailbox in microseconds if busy (default=10)"); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* 1638c2ecf20Sopenharmony_ci * number of sectors per IO command 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_cistatic unsigned int megaraid_max_sectors = MBOX_MAX_SECTORS; 1668c2ecf20Sopenharmony_cimodule_param_named(max_sectors, megaraid_max_sectors, int, 0); 1678c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_sectors, 1688c2ecf20Sopenharmony_ci "Maximum number of sectors per IO command (default=128)"); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* 1718c2ecf20Sopenharmony_ci * number of commands per logical unit 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_cistatic unsigned int megaraid_cmd_per_lun = MBOX_DEF_CMD_PER_LUN; 1748c2ecf20Sopenharmony_cimodule_param_named(cmd_per_lun, megaraid_cmd_per_lun, int, 0); 1758c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cmd_per_lun, 1768c2ecf20Sopenharmony_ci "Maximum number of commands per logical unit (default=64)"); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* 1808c2ecf20Sopenharmony_ci * Fast driver load option, skip scanning for physical devices during load. 1818c2ecf20Sopenharmony_ci * This would result in non-disk devices being skipped during driver load 1828c2ecf20Sopenharmony_ci * time. These can be later added though, using /proc/scsi/scsi 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_cistatic unsigned int megaraid_fast_load = 0; 1858c2ecf20Sopenharmony_cimodule_param_named(fast_load, megaraid_fast_load, int, 0); 1868c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fast_load, 1878c2ecf20Sopenharmony_ci "Faster loading of the driver, skips physical devices! (default=0)"); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* 1918c2ecf20Sopenharmony_ci * mraid_debug level - threshold for amount of information to be displayed by 1928c2ecf20Sopenharmony_ci * the driver. This level can be changed through modules parameters, ioctl or 1938c2ecf20Sopenharmony_ci * sysfs/proc interface. By default, print the announcement messages only. 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_ciint mraid_debug_level = CL_ANN; 1968c2ecf20Sopenharmony_cimodule_param_named(debug_level, mraid_debug_level, int, 0); 1978c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug_level, "Debug level for driver (default=0)"); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* 2008c2ecf20Sopenharmony_ci * PCI table for all supported controllers. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_cistatic struct pci_device_id pci_id_table_g[] = { 2038c2ecf20Sopenharmony_ci { 2048c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2058c2ecf20Sopenharmony_ci PCI_DEVICE_ID_PERC4_DI_DISCOVERY, 2068c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2078c2ecf20Sopenharmony_ci PCI_SUBSYS_ID_PERC4_DI_DISCOVERY, 2088c2ecf20Sopenharmony_ci }, 2098c2ecf20Sopenharmony_ci { 2108c2ecf20Sopenharmony_ci PCI_VENDOR_ID_LSI_LOGIC, 2118c2ecf20Sopenharmony_ci PCI_DEVICE_ID_PERC4_SC, 2128c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2138c2ecf20Sopenharmony_ci PCI_SUBSYS_ID_PERC4_SC, 2148c2ecf20Sopenharmony_ci }, 2158c2ecf20Sopenharmony_ci { 2168c2ecf20Sopenharmony_ci PCI_VENDOR_ID_LSI_LOGIC, 2178c2ecf20Sopenharmony_ci PCI_DEVICE_ID_PERC4_DC, 2188c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2198c2ecf20Sopenharmony_ci PCI_SUBSYS_ID_PERC4_DC, 2208c2ecf20Sopenharmony_ci }, 2218c2ecf20Sopenharmony_ci { 2228c2ecf20Sopenharmony_ci PCI_VENDOR_ID_LSI_LOGIC, 2238c2ecf20Sopenharmony_ci PCI_DEVICE_ID_VERDE, 2248c2ecf20Sopenharmony_ci PCI_ANY_ID, 2258c2ecf20Sopenharmony_ci PCI_ANY_ID, 2268c2ecf20Sopenharmony_ci }, 2278c2ecf20Sopenharmony_ci { 2288c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2298c2ecf20Sopenharmony_ci PCI_DEVICE_ID_PERC4_DI_EVERGLADES, 2308c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2318c2ecf20Sopenharmony_ci PCI_SUBSYS_ID_PERC4_DI_EVERGLADES, 2328c2ecf20Sopenharmony_ci }, 2338c2ecf20Sopenharmony_ci { 2348c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2358c2ecf20Sopenharmony_ci PCI_DEVICE_ID_PERC4E_SI_BIGBEND, 2368c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2378c2ecf20Sopenharmony_ci PCI_SUBSYS_ID_PERC4E_SI_BIGBEND, 2388c2ecf20Sopenharmony_ci }, 2398c2ecf20Sopenharmony_ci { 2408c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2418c2ecf20Sopenharmony_ci PCI_DEVICE_ID_PERC4E_DI_KOBUK, 2428c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2438c2ecf20Sopenharmony_ci PCI_SUBSYS_ID_PERC4E_DI_KOBUK, 2448c2ecf20Sopenharmony_ci }, 2458c2ecf20Sopenharmony_ci { 2468c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2478c2ecf20Sopenharmony_ci PCI_DEVICE_ID_PERC4E_DI_CORVETTE, 2488c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2498c2ecf20Sopenharmony_ci PCI_SUBSYS_ID_PERC4E_DI_CORVETTE, 2508c2ecf20Sopenharmony_ci }, 2518c2ecf20Sopenharmony_ci { 2528c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2538c2ecf20Sopenharmony_ci PCI_DEVICE_ID_PERC4E_DI_EXPEDITION, 2548c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2558c2ecf20Sopenharmony_ci PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION, 2568c2ecf20Sopenharmony_ci }, 2578c2ecf20Sopenharmony_ci { 2588c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2598c2ecf20Sopenharmony_ci PCI_DEVICE_ID_PERC4E_DI_GUADALUPE, 2608c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DELL, 2618c2ecf20Sopenharmony_ci PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE, 2628c2ecf20Sopenharmony_ci }, 2638c2ecf20Sopenharmony_ci { 2648c2ecf20Sopenharmony_ci PCI_VENDOR_ID_LSI_LOGIC, 2658c2ecf20Sopenharmony_ci PCI_DEVICE_ID_DOBSON, 2668c2ecf20Sopenharmony_ci PCI_ANY_ID, 2678c2ecf20Sopenharmony_ci PCI_ANY_ID, 2688c2ecf20Sopenharmony_ci }, 2698c2ecf20Sopenharmony_ci { 2708c2ecf20Sopenharmony_ci PCI_VENDOR_ID_AMI, 2718c2ecf20Sopenharmony_ci PCI_DEVICE_ID_AMI_MEGARAID3, 2728c2ecf20Sopenharmony_ci PCI_ANY_ID, 2738c2ecf20Sopenharmony_ci PCI_ANY_ID, 2748c2ecf20Sopenharmony_ci }, 2758c2ecf20Sopenharmony_ci { 2768c2ecf20Sopenharmony_ci PCI_VENDOR_ID_LSI_LOGIC, 2778c2ecf20Sopenharmony_ci PCI_DEVICE_ID_AMI_MEGARAID3, 2788c2ecf20Sopenharmony_ci PCI_ANY_ID, 2798c2ecf20Sopenharmony_ci PCI_ANY_ID, 2808c2ecf20Sopenharmony_ci }, 2818c2ecf20Sopenharmony_ci { 2828c2ecf20Sopenharmony_ci PCI_VENDOR_ID_LSI_LOGIC, 2838c2ecf20Sopenharmony_ci PCI_DEVICE_ID_LINDSAY, 2848c2ecf20Sopenharmony_ci PCI_ANY_ID, 2858c2ecf20Sopenharmony_ci PCI_ANY_ID, 2868c2ecf20Sopenharmony_ci }, 2878c2ecf20Sopenharmony_ci {0} /* Terminating entry */ 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pci_id_table_g); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic struct pci_driver megaraid_pci_driver = { 2938c2ecf20Sopenharmony_ci .name = "megaraid", 2948c2ecf20Sopenharmony_ci .id_table = pci_id_table_g, 2958c2ecf20Sopenharmony_ci .probe = megaraid_probe_one, 2968c2ecf20Sopenharmony_ci .remove = megaraid_detach_one, 2978c2ecf20Sopenharmony_ci .shutdown = megaraid_mbox_shutdown, 2988c2ecf20Sopenharmony_ci}; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci// definitions for the device attributes for exporting logical drive number 3038c2ecf20Sopenharmony_ci// for a scsi address (Host, Channel, Id, Lun) 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic DEVICE_ATTR(megaraid_mbox_app_hndl, S_IRUSR, megaraid_sysfs_show_app_hndl, 3068c2ecf20Sopenharmony_ci NULL); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci// Host template initializer for megaraid mbox sysfs device attributes 3098c2ecf20Sopenharmony_cistatic struct device_attribute *megaraid_shost_attrs[] = { 3108c2ecf20Sopenharmony_ci &dev_attr_megaraid_mbox_app_hndl, 3118c2ecf20Sopenharmony_ci NULL, 3128c2ecf20Sopenharmony_ci}; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic DEVICE_ATTR(megaraid_mbox_ld, S_IRUSR, megaraid_sysfs_show_ldnum, NULL); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci// Host template initializer for megaraid mbox sysfs device attributes 3188c2ecf20Sopenharmony_cistatic struct device_attribute *megaraid_sdev_attrs[] = { 3198c2ecf20Sopenharmony_ci &dev_attr_megaraid_mbox_ld, 3208c2ecf20Sopenharmony_ci NULL, 3218c2ecf20Sopenharmony_ci}; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/* 3248c2ecf20Sopenharmony_ci * Scsi host template for megaraid unified driver 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_cistatic struct scsi_host_template megaraid_template_g = { 3278c2ecf20Sopenharmony_ci .module = THIS_MODULE, 3288c2ecf20Sopenharmony_ci .name = "LSI Logic MegaRAID driver", 3298c2ecf20Sopenharmony_ci .proc_name = "megaraid", 3308c2ecf20Sopenharmony_ci .queuecommand = megaraid_queue_command, 3318c2ecf20Sopenharmony_ci .eh_abort_handler = megaraid_abort_handler, 3328c2ecf20Sopenharmony_ci .eh_host_reset_handler = megaraid_reset_handler, 3338c2ecf20Sopenharmony_ci .change_queue_depth = scsi_change_queue_depth, 3348c2ecf20Sopenharmony_ci .no_write_same = 1, 3358c2ecf20Sopenharmony_ci .sdev_attrs = megaraid_sdev_attrs, 3368c2ecf20Sopenharmony_ci .shost_attrs = megaraid_shost_attrs, 3378c2ecf20Sopenharmony_ci}; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/** 3418c2ecf20Sopenharmony_ci * megaraid_init - module load hook 3428c2ecf20Sopenharmony_ci * 3438c2ecf20Sopenharmony_ci * We register ourselves as hotplug enabled module and let PCI subsystem 3448c2ecf20Sopenharmony_ci * discover our adapters. 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_cistatic int __init 3478c2ecf20Sopenharmony_cimegaraid_init(void) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci int rval; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci // Announce the driver version 3528c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_INFO "megaraid: %s %s\n", MEGARAID_VERSION, 3538c2ecf20Sopenharmony_ci MEGARAID_EXT_VERSION)); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci // check validity of module parameters 3568c2ecf20Sopenharmony_ci if (megaraid_cmd_per_lun > MBOX_MAX_SCSI_CMDS) { 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 3598c2ecf20Sopenharmony_ci "megaraid mailbox: max commands per lun reset to %d\n", 3608c2ecf20Sopenharmony_ci MBOX_MAX_SCSI_CMDS)); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci megaraid_cmd_per_lun = MBOX_MAX_SCSI_CMDS; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci // register as a PCI hot-plug driver module 3678c2ecf20Sopenharmony_ci rval = pci_register_driver(&megaraid_pci_driver); 3688c2ecf20Sopenharmony_ci if (rval < 0) { 3698c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 3708c2ecf20Sopenharmony_ci "megaraid: could not register hotplug support.\n")); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return rval; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci/** 3788c2ecf20Sopenharmony_ci * megaraid_exit - driver unload entry point 3798c2ecf20Sopenharmony_ci * 3808c2ecf20Sopenharmony_ci * We simply unwrap the megaraid_init routine here. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_cistatic void __exit 3838c2ecf20Sopenharmony_cimegaraid_exit(void) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n")); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci // unregister as PCI hotplug driver 3888c2ecf20Sopenharmony_ci pci_unregister_driver(&megaraid_pci_driver); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci return; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci/** 3958c2ecf20Sopenharmony_ci * megaraid_probe_one - PCI hotplug entry point 3968c2ecf20Sopenharmony_ci * @pdev : handle to this controller's PCI configuration space 3978c2ecf20Sopenharmony_ci * @id : pci device id of the class of controllers 3988c2ecf20Sopenharmony_ci * 3998c2ecf20Sopenharmony_ci * This routine should be called whenever a new adapter is detected by the 4008c2ecf20Sopenharmony_ci * PCI hotplug susbsystem. 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_cistatic int 4038c2ecf20Sopenharmony_cimegaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci adapter_t *adapter; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci // detected a new controller 4098c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_INFO 4108c2ecf20Sopenharmony_ci "megaraid: probe new device %#4.04x:%#4.04x:%#4.04x:%#4.04x: ", 4118c2ecf20Sopenharmony_ci pdev->vendor, pdev->device, pdev->subsystem_vendor, 4128c2ecf20Sopenharmony_ci pdev->subsystem_device)); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci con_log(CL_ANN, ("bus %d:slot %d:func %d\n", pdev->bus->number, 4158c2ecf20Sopenharmony_ci PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn))); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) { 4188c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 4198c2ecf20Sopenharmony_ci "megaraid: pci_enable_device failed\n")); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return -ENODEV; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci // Enable bus-mastering on this controller 4258c2ecf20Sopenharmony_ci pci_set_master(pdev); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci // Allocate the per driver initialization structure 4288c2ecf20Sopenharmony_ci adapter = kzalloc(sizeof(adapter_t), GFP_KERNEL); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (adapter == NULL) { 4318c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 4328c2ecf20Sopenharmony_ci "megaraid: out of memory, %s %d.\n", __func__, __LINE__)); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci goto out_probe_one; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci // set up PCI related soft state and other pre-known parameters 4398c2ecf20Sopenharmony_ci adapter->unique_id = pdev->bus->number << 8 | pdev->devfn; 4408c2ecf20Sopenharmony_ci adapter->irq = pdev->irq; 4418c2ecf20Sopenharmony_ci adapter->pdev = pdev; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci atomic_set(&adapter->being_detached, 0); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci // Setup the default DMA mask. This would be changed later on 4468c2ecf20Sopenharmony_ci // depending on hardware capabilities 4478c2ecf20Sopenharmony_ci if (dma_set_mask(&adapter->pdev->dev, DMA_BIT_MASK(32))) { 4488c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 4498c2ecf20Sopenharmony_ci "megaraid: dma_set_mask failed:%d\n", __LINE__)); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci goto out_free_adapter; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci // Initialize the synchronization lock for kernel and LLD 4568c2ecf20Sopenharmony_ci spin_lock_init(&adapter->lock); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci // Initialize the command queues: the list of free SCBs and the list 4598c2ecf20Sopenharmony_ci // of pending SCBs. 4608c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->kscb_pool); 4618c2ecf20Sopenharmony_ci spin_lock_init(SCSI_FREE_LIST_LOCK(adapter)); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->pend_list); 4648c2ecf20Sopenharmony_ci spin_lock_init(PENDING_LIST_LOCK(adapter)); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->completed_list); 4678c2ecf20Sopenharmony_ci spin_lock_init(COMPLETED_LIST_LOCK(adapter)); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci // Start the mailbox based controller 4718c2ecf20Sopenharmony_ci if (megaraid_init_mbox(adapter) != 0) { 4728c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 4738c2ecf20Sopenharmony_ci "megaraid: mailbox adapter did not initialize\n")); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci goto out_free_adapter; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci // Register with LSI Common Management Module 4798c2ecf20Sopenharmony_ci if (megaraid_cmm_register(adapter) != 0) { 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 4828c2ecf20Sopenharmony_ci "megaraid: could not register with management module\n")); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci goto out_fini_mbox; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci // setup adapter handle in PCI soft state 4888c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, adapter); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci // attach with scsi mid-layer 4918c2ecf20Sopenharmony_ci if (megaraid_io_attach(adapter) != 0) { 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING "megaraid: io attach failed\n")); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci goto out_cmm_unreg; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci return 0; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ciout_cmm_unreg: 5018c2ecf20Sopenharmony_ci megaraid_cmm_unregister(adapter); 5028c2ecf20Sopenharmony_ciout_fini_mbox: 5038c2ecf20Sopenharmony_ci megaraid_fini_mbox(adapter); 5048c2ecf20Sopenharmony_ciout_free_adapter: 5058c2ecf20Sopenharmony_ci kfree(adapter); 5068c2ecf20Sopenharmony_ciout_probe_one: 5078c2ecf20Sopenharmony_ci pci_disable_device(pdev); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return -ENODEV; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci/** 5148c2ecf20Sopenharmony_ci * megaraid_detach_one - release framework resources and call LLD release routine 5158c2ecf20Sopenharmony_ci * @pdev : handle for our PCI configuration space 5168c2ecf20Sopenharmony_ci * 5178c2ecf20Sopenharmony_ci * This routine is called during driver unload. We free all the allocated 5188c2ecf20Sopenharmony_ci * resources and call the corresponding LLD so that it can also release all 5198c2ecf20Sopenharmony_ci * its resources. 5208c2ecf20Sopenharmony_ci * 5218c2ecf20Sopenharmony_ci * This routine is also called from the PCI hotplug system. 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_cistatic void 5248c2ecf20Sopenharmony_cimegaraid_detach_one(struct pci_dev *pdev) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci adapter_t *adapter; 5278c2ecf20Sopenharmony_ci struct Scsi_Host *host; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci // Start a rollback on this adapter 5318c2ecf20Sopenharmony_ci adapter = pci_get_drvdata(pdev); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (!adapter) { 5348c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_CRIT 5358c2ecf20Sopenharmony_ci "megaraid: Invalid detach on %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", 5368c2ecf20Sopenharmony_ci pdev->vendor, pdev->device, pdev->subsystem_vendor, 5378c2ecf20Sopenharmony_ci pdev->subsystem_device)); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci else { 5428c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 5438c2ecf20Sopenharmony_ci "megaraid: detaching device %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", 5448c2ecf20Sopenharmony_ci pdev->vendor, pdev->device, pdev->subsystem_vendor, 5458c2ecf20Sopenharmony_ci pdev->subsystem_device)); 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci host = adapter->host; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci // do not allow any more requests from the management module for this 5528c2ecf20Sopenharmony_ci // adapter. 5538c2ecf20Sopenharmony_ci // FIXME: How do we account for the request which might still be 5548c2ecf20Sopenharmony_ci // pending with us? 5558c2ecf20Sopenharmony_ci atomic_set(&adapter->being_detached, 1); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci // detach from the IO sub-system 5588c2ecf20Sopenharmony_ci megaraid_io_detach(adapter); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci // Unregister from common management module 5618c2ecf20Sopenharmony_ci // 5628c2ecf20Sopenharmony_ci // FIXME: this must return success or failure for conditions if there 5638c2ecf20Sopenharmony_ci // is a command pending with LLD or not. 5648c2ecf20Sopenharmony_ci megaraid_cmm_unregister(adapter); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci // finalize the mailbox based controller and release all resources 5678c2ecf20Sopenharmony_ci megaraid_fini_mbox(adapter); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci kfree(adapter); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci scsi_host_put(host); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci pci_disable_device(pdev); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci return; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci/** 5808c2ecf20Sopenharmony_ci * megaraid_mbox_shutdown - PCI shutdown for megaraid HBA 5818c2ecf20Sopenharmony_ci * @pdev : generic driver model device 5828c2ecf20Sopenharmony_ci * 5838c2ecf20Sopenharmony_ci * Shutdown notification, perform flush cache. 5848c2ecf20Sopenharmony_ci */ 5858c2ecf20Sopenharmony_cistatic void 5868c2ecf20Sopenharmony_cimegaraid_mbox_shutdown(struct pci_dev *pdev) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci adapter_t *adapter = pci_get_drvdata(pdev); 5898c2ecf20Sopenharmony_ci static int counter; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if (!adapter) { 5928c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 5938c2ecf20Sopenharmony_ci "megaraid: null device in shutdown\n")); 5948c2ecf20Sopenharmony_ci return; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci // flush caches now 5988c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_INFO "megaraid: flushing adapter %d...", 5998c2ecf20Sopenharmony_ci counter++)); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci megaraid_mbox_flush_cache(adapter); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci con_log(CL_ANN, ("done\n")); 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci/** 6088c2ecf20Sopenharmony_ci * megaraid_io_attach - attach a device with the IO subsystem 6098c2ecf20Sopenharmony_ci * @adapter : controller's soft state 6108c2ecf20Sopenharmony_ci * 6118c2ecf20Sopenharmony_ci * Attach this device with the IO subsystem. 6128c2ecf20Sopenharmony_ci */ 6138c2ecf20Sopenharmony_cistatic int 6148c2ecf20Sopenharmony_cimegaraid_io_attach(adapter_t *adapter) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct Scsi_Host *host; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci // Initialize SCSI Host structure 6198c2ecf20Sopenharmony_ci host = scsi_host_alloc(&megaraid_template_g, 8); 6208c2ecf20Sopenharmony_ci if (!host) { 6218c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 6228c2ecf20Sopenharmony_ci "megaraid mbox: scsi_register failed\n")); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci return -1; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci SCSIHOST2ADAP(host) = (caddr_t)adapter; 6288c2ecf20Sopenharmony_ci adapter->host = host; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci host->irq = adapter->irq; 6318c2ecf20Sopenharmony_ci host->unique_id = adapter->unique_id; 6328c2ecf20Sopenharmony_ci host->can_queue = adapter->max_cmds; 6338c2ecf20Sopenharmony_ci host->this_id = adapter->init_id; 6348c2ecf20Sopenharmony_ci host->sg_tablesize = adapter->sglen; 6358c2ecf20Sopenharmony_ci host->max_sectors = adapter->max_sectors; 6368c2ecf20Sopenharmony_ci host->cmd_per_lun = adapter->cmd_per_lun; 6378c2ecf20Sopenharmony_ci host->max_channel = adapter->max_channel; 6388c2ecf20Sopenharmony_ci host->max_id = adapter->max_target; 6398c2ecf20Sopenharmony_ci host->max_lun = adapter->max_lun; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci // notify mid-layer about the new controller 6438c2ecf20Sopenharmony_ci if (scsi_add_host(host, &adapter->pdev->dev)) { 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 6468c2ecf20Sopenharmony_ci "megaraid mbox: scsi_add_host failed\n")); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci scsi_host_put(host); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci return -1; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci scsi_scan_host(host); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return 0; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci/** 6608c2ecf20Sopenharmony_ci * megaraid_io_detach - detach a device from the IO subsystem 6618c2ecf20Sopenharmony_ci * @adapter : controller's soft state 6628c2ecf20Sopenharmony_ci * 6638c2ecf20Sopenharmony_ci * Detach this device from the IO subsystem. 6648c2ecf20Sopenharmony_ci */ 6658c2ecf20Sopenharmony_cistatic void 6668c2ecf20Sopenharmony_cimegaraid_io_detach(adapter_t *adapter) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci struct Scsi_Host *host; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci con_log(CL_DLEVEL1, (KERN_INFO "megaraid: io detach\n")); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci host = adapter->host; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci scsi_remove_host(host); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci return; 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci/* 6818c2ecf20Sopenharmony_ci * START: Mailbox Low Level Driver 6828c2ecf20Sopenharmony_ci * 6838c2ecf20Sopenharmony_ci * This is section specific to the single mailbox based controllers 6848c2ecf20Sopenharmony_ci */ 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci/** 6878c2ecf20Sopenharmony_ci * megaraid_init_mbox - initialize controller 6888c2ecf20Sopenharmony_ci * @adapter : our soft state 6898c2ecf20Sopenharmony_ci * 6908c2ecf20Sopenharmony_ci * - Allocate 16-byte aligned mailbox memory for firmware handshake 6918c2ecf20Sopenharmony_ci * - Allocate controller's memory resources 6928c2ecf20Sopenharmony_ci * - Find out all initialization data 6938c2ecf20Sopenharmony_ci * - Allocate memory required for all the commands 6948c2ecf20Sopenharmony_ci * - Use internal library of FW routines, build up complete soft state 6958c2ecf20Sopenharmony_ci */ 6968c2ecf20Sopenharmony_cistatic int 6978c2ecf20Sopenharmony_cimegaraid_init_mbox(adapter_t *adapter) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci struct pci_dev *pdev; 7008c2ecf20Sopenharmony_ci mraid_device_t *raid_dev; 7018c2ecf20Sopenharmony_ci int i; 7028c2ecf20Sopenharmony_ci uint32_t magic64; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci adapter->ito = MBOX_TIMEOUT; 7068c2ecf20Sopenharmony_ci pdev = adapter->pdev; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* 7098c2ecf20Sopenharmony_ci * Allocate and initialize the init data structure for mailbox 7108c2ecf20Sopenharmony_ci * controllers 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_ci raid_dev = kzalloc(sizeof(mraid_device_t), GFP_KERNEL); 7138c2ecf20Sopenharmony_ci if (raid_dev == NULL) return -1; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* 7178c2ecf20Sopenharmony_ci * Attach the adapter soft state to raid device soft state 7188c2ecf20Sopenharmony_ci */ 7198c2ecf20Sopenharmony_ci adapter->raid_device = (caddr_t)raid_dev; 7208c2ecf20Sopenharmony_ci raid_dev->fast_load = megaraid_fast_load; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci // our baseport 7248c2ecf20Sopenharmony_ci raid_dev->baseport = pci_resource_start(pdev, 0); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (pci_request_regions(pdev, "MegaRAID: LSI Logic Corporation") != 0) { 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 7298c2ecf20Sopenharmony_ci "megaraid: mem region busy\n")); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci goto out_free_raid_dev; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci raid_dev->baseaddr = ioremap(raid_dev->baseport, 128); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (!raid_dev->baseaddr) { 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 7398c2ecf20Sopenharmony_ci "megaraid: could not map hba memory\n") ); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci goto out_release_regions; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci /* initialize the mutual exclusion lock for the mailbox */ 7458c2ecf20Sopenharmony_ci spin_lock_init(&raid_dev->mailbox_lock); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* allocate memory required for commands */ 7488c2ecf20Sopenharmony_ci if (megaraid_alloc_cmd_packets(adapter) != 0) 7498c2ecf20Sopenharmony_ci goto out_iounmap; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* 7528c2ecf20Sopenharmony_ci * Issue SYNC cmd to flush the pending cmds in the adapter 7538c2ecf20Sopenharmony_ci * and initialize its internal state 7548c2ecf20Sopenharmony_ci */ 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci if (megaraid_mbox_fire_sync_cmd(adapter)) 7578c2ecf20Sopenharmony_ci con_log(CL_ANN, ("megaraid: sync cmd failed\n")); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* 7608c2ecf20Sopenharmony_ci * Setup the rest of the soft state using the library of 7618c2ecf20Sopenharmony_ci * FW routines 7628c2ecf20Sopenharmony_ci */ 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* request IRQ and register the interrupt service routine */ 7658c2ecf20Sopenharmony_ci if (request_irq(adapter->irq, megaraid_isr, IRQF_SHARED, "megaraid", 7668c2ecf20Sopenharmony_ci adapter)) { 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 7698c2ecf20Sopenharmony_ci "megaraid: Couldn't register IRQ %d!\n", adapter->irq)); 7708c2ecf20Sopenharmony_ci goto out_alloc_cmds; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci // Product info 7758c2ecf20Sopenharmony_ci if (megaraid_mbox_product_info(adapter) != 0) 7768c2ecf20Sopenharmony_ci goto out_free_irq; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci // Do we support extended CDBs 7798c2ecf20Sopenharmony_ci adapter->max_cdb_sz = 10; 7808c2ecf20Sopenharmony_ci if (megaraid_mbox_extended_cdb(adapter) == 0) { 7818c2ecf20Sopenharmony_ci adapter->max_cdb_sz = 16; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* 7858c2ecf20Sopenharmony_ci * Do we support cluster environment, if we do, what is the initiator 7868c2ecf20Sopenharmony_ci * id. 7878c2ecf20Sopenharmony_ci * NOTE: In a non-cluster aware firmware environment, the LLD should 7888c2ecf20Sopenharmony_ci * return 7 as initiator id. 7898c2ecf20Sopenharmony_ci */ 7908c2ecf20Sopenharmony_ci adapter->ha = 0; 7918c2ecf20Sopenharmony_ci adapter->init_id = -1; 7928c2ecf20Sopenharmony_ci if (megaraid_mbox_support_ha(adapter, &adapter->init_id) == 0) { 7938c2ecf20Sopenharmony_ci adapter->ha = 1; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci /* 7978c2ecf20Sopenharmony_ci * Prepare the device ids array to have the mapping between the kernel 7988c2ecf20Sopenharmony_ci * device address and megaraid device address. 7998c2ecf20Sopenharmony_ci * We export the physical devices on their actual addresses. The 8008c2ecf20Sopenharmony_ci * logical drives are exported on a virtual SCSI channel 8018c2ecf20Sopenharmony_ci */ 8028c2ecf20Sopenharmony_ci megaraid_mbox_setup_device_map(adapter); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci // If the firmware supports random deletion, update the device id map 8058c2ecf20Sopenharmony_ci if (megaraid_mbox_support_random_del(adapter)) { 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci // Change the logical drives numbers in device_ids array one 8088c2ecf20Sopenharmony_ci // slot in device_ids is reserved for target id, that's why 8098c2ecf20Sopenharmony_ci // "<=" below 8108c2ecf20Sopenharmony_ci for (i = 0; i <= MAX_LOGICAL_DRIVES_40LD; i++) { 8118c2ecf20Sopenharmony_ci adapter->device_ids[adapter->max_channel][i] += 0x80; 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci adapter->device_ids[adapter->max_channel][adapter->init_id] = 8148c2ecf20Sopenharmony_ci 0xFF; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci raid_dev->random_del_supported = 1; 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* 8208c2ecf20Sopenharmony_ci * find out the maximum number of scatter-gather elements supported by 8218c2ecf20Sopenharmony_ci * this firmware 8228c2ecf20Sopenharmony_ci */ 8238c2ecf20Sopenharmony_ci adapter->sglen = megaraid_mbox_get_max_sg(adapter); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci // enumerate RAID and SCSI channels so that all devices on SCSI 8268c2ecf20Sopenharmony_ci // channels can later be exported, including disk devices 8278c2ecf20Sopenharmony_ci megaraid_mbox_enum_raid_scsi(adapter); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* 8308c2ecf20Sopenharmony_ci * Other parameters required by upper layer 8318c2ecf20Sopenharmony_ci * 8328c2ecf20Sopenharmony_ci * maximum number of sectors per IO command 8338c2ecf20Sopenharmony_ci */ 8348c2ecf20Sopenharmony_ci adapter->max_sectors = megaraid_max_sectors; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci /* 8378c2ecf20Sopenharmony_ci * number of queued commands per LUN. 8388c2ecf20Sopenharmony_ci */ 8398c2ecf20Sopenharmony_ci adapter->cmd_per_lun = megaraid_cmd_per_lun; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* 8428c2ecf20Sopenharmony_ci * Allocate resources required to issue FW calls, when sysfs is 8438c2ecf20Sopenharmony_ci * accessed 8448c2ecf20Sopenharmony_ci */ 8458c2ecf20Sopenharmony_ci if (megaraid_sysfs_alloc_resources(adapter) != 0) 8468c2ecf20Sopenharmony_ci goto out_free_irq; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci // Set the DMA mask to 64-bit. All supported controllers as capable of 8498c2ecf20Sopenharmony_ci // DMA in this range 8508c2ecf20Sopenharmony_ci pci_read_config_dword(adapter->pdev, PCI_CONF_AMISIG64, &magic64); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (((magic64 == HBA_SIGNATURE_64_BIT) && 8538c2ecf20Sopenharmony_ci ((adapter->pdev->subsystem_device != 8548c2ecf20Sopenharmony_ci PCI_SUBSYS_ID_MEGARAID_SATA_150_6) && 8558c2ecf20Sopenharmony_ci (adapter->pdev->subsystem_device != 8568c2ecf20Sopenharmony_ci PCI_SUBSYS_ID_MEGARAID_SATA_150_4))) || 8578c2ecf20Sopenharmony_ci (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && 8588c2ecf20Sopenharmony_ci adapter->pdev->device == PCI_DEVICE_ID_VERDE) || 8598c2ecf20Sopenharmony_ci (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && 8608c2ecf20Sopenharmony_ci adapter->pdev->device == PCI_DEVICE_ID_DOBSON) || 8618c2ecf20Sopenharmony_ci (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && 8628c2ecf20Sopenharmony_ci adapter->pdev->device == PCI_DEVICE_ID_LINDSAY) || 8638c2ecf20Sopenharmony_ci (adapter->pdev->vendor == PCI_VENDOR_ID_DELL && 8648c2ecf20Sopenharmony_ci adapter->pdev->device == PCI_DEVICE_ID_PERC4_DI_EVERGLADES) || 8658c2ecf20Sopenharmony_ci (adapter->pdev->vendor == PCI_VENDOR_ID_DELL && 8668c2ecf20Sopenharmony_ci adapter->pdev->device == PCI_DEVICE_ID_PERC4E_DI_KOBUK)) { 8678c2ecf20Sopenharmony_ci if (dma_set_mask(&adapter->pdev->dev, DMA_BIT_MASK(64))) { 8688c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 8698c2ecf20Sopenharmony_ci "megaraid: DMA mask for 64-bit failed\n")); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (dma_set_mask(&adapter->pdev->dev, 8728c2ecf20Sopenharmony_ci DMA_BIT_MASK(32))) { 8738c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 8748c2ecf20Sopenharmony_ci "megaraid: 32-bit DMA mask failed\n")); 8758c2ecf20Sopenharmony_ci goto out_free_sysfs_res; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci // setup tasklet for DPC 8818c2ecf20Sopenharmony_ci tasklet_init(&adapter->dpc_h, megaraid_mbox_dpc, 8828c2ecf20Sopenharmony_ci (unsigned long)adapter); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci con_log(CL_DLEVEL1, (KERN_INFO 8858c2ecf20Sopenharmony_ci "megaraid mbox hba successfully initialized\n")); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci return 0; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ciout_free_sysfs_res: 8908c2ecf20Sopenharmony_ci megaraid_sysfs_free_resources(adapter); 8918c2ecf20Sopenharmony_ciout_free_irq: 8928c2ecf20Sopenharmony_ci free_irq(adapter->irq, adapter); 8938c2ecf20Sopenharmony_ciout_alloc_cmds: 8948c2ecf20Sopenharmony_ci megaraid_free_cmd_packets(adapter); 8958c2ecf20Sopenharmony_ciout_iounmap: 8968c2ecf20Sopenharmony_ci iounmap(raid_dev->baseaddr); 8978c2ecf20Sopenharmony_ciout_release_regions: 8988c2ecf20Sopenharmony_ci pci_release_regions(pdev); 8998c2ecf20Sopenharmony_ciout_free_raid_dev: 9008c2ecf20Sopenharmony_ci kfree(raid_dev); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci return -1; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci/** 9078c2ecf20Sopenharmony_ci * megaraid_fini_mbox - undo controller initialization 9088c2ecf20Sopenharmony_ci * @adapter : our soft state 9098c2ecf20Sopenharmony_ci */ 9108c2ecf20Sopenharmony_cistatic void 9118c2ecf20Sopenharmony_cimegaraid_fini_mbox(adapter_t *adapter) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci // flush all caches 9168c2ecf20Sopenharmony_ci megaraid_mbox_flush_cache(adapter); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci tasklet_kill(&adapter->dpc_h); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci megaraid_sysfs_free_resources(adapter); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci megaraid_free_cmd_packets(adapter); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci free_irq(adapter->irq, adapter); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci iounmap(raid_dev->baseaddr); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci pci_release_regions(adapter->pdev); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci kfree(raid_dev); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci return; 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci/** 9378c2ecf20Sopenharmony_ci * megaraid_alloc_cmd_packets - allocate shared mailbox 9388c2ecf20Sopenharmony_ci * @adapter : soft state of the raid controller 9398c2ecf20Sopenharmony_ci * 9408c2ecf20Sopenharmony_ci * Allocate and align the shared mailbox. This mailbox is used to issue 9418c2ecf20Sopenharmony_ci * all the commands. For IO based controllers, the mailbox is also registered 9428c2ecf20Sopenharmony_ci * with the FW. Allocate memory for all commands as well. 9438c2ecf20Sopenharmony_ci * This is our big allocator. 9448c2ecf20Sopenharmony_ci */ 9458c2ecf20Sopenharmony_cistatic int 9468c2ecf20Sopenharmony_cimegaraid_alloc_cmd_packets(adapter_t *adapter) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 9498c2ecf20Sopenharmony_ci struct pci_dev *pdev; 9508c2ecf20Sopenharmony_ci unsigned long align; 9518c2ecf20Sopenharmony_ci scb_t *scb; 9528c2ecf20Sopenharmony_ci mbox_ccb_t *ccb; 9538c2ecf20Sopenharmony_ci struct mraid_pci_blk *epthru_pci_blk; 9548c2ecf20Sopenharmony_ci struct mraid_pci_blk *sg_pci_blk; 9558c2ecf20Sopenharmony_ci struct mraid_pci_blk *mbox_pci_blk; 9568c2ecf20Sopenharmony_ci int i; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci pdev = adapter->pdev; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci /* 9618c2ecf20Sopenharmony_ci * Setup the mailbox 9628c2ecf20Sopenharmony_ci * Allocate the common 16-byte aligned memory for the handshake 9638c2ecf20Sopenharmony_ci * mailbox. 9648c2ecf20Sopenharmony_ci */ 9658c2ecf20Sopenharmony_ci raid_dev->una_mbox64 = dma_alloc_coherent(&adapter->pdev->dev, 9668c2ecf20Sopenharmony_ci sizeof(mbox64_t), 9678c2ecf20Sopenharmony_ci &raid_dev->una_mbox64_dma, 9688c2ecf20Sopenharmony_ci GFP_KERNEL); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci if (!raid_dev->una_mbox64) { 9718c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 9728c2ecf20Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 9738c2ecf20Sopenharmony_ci __LINE__)); 9748c2ecf20Sopenharmony_ci return -1; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* 9788c2ecf20Sopenharmony_ci * Align the mailbox at 16-byte boundary 9798c2ecf20Sopenharmony_ci */ 9808c2ecf20Sopenharmony_ci raid_dev->mbox = &raid_dev->una_mbox64->mbox32; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci raid_dev->mbox = (mbox_t *)((((unsigned long)raid_dev->mbox) + 15) & 9838c2ecf20Sopenharmony_ci (~0UL ^ 0xFUL)); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci raid_dev->mbox64 = (mbox64_t *)(((unsigned long)raid_dev->mbox) - 8); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci align = ((void *)raid_dev->mbox - 9888c2ecf20Sopenharmony_ci ((void *)&raid_dev->una_mbox64->mbox32)); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci raid_dev->mbox_dma = (unsigned long)raid_dev->una_mbox64_dma + 8 + 9918c2ecf20Sopenharmony_ci align; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci // Allocate memory for commands issued internally 9948c2ecf20Sopenharmony_ci adapter->ibuf = dma_alloc_coherent(&pdev->dev, MBOX_IBUF_SIZE, 9958c2ecf20Sopenharmony_ci &adapter->ibuf_dma_h, GFP_KERNEL); 9968c2ecf20Sopenharmony_ci if (!adapter->ibuf) { 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 9998c2ecf20Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 10008c2ecf20Sopenharmony_ci __LINE__)); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci goto out_free_common_mbox; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci // Allocate memory for our SCSI Command Blocks and their associated 10068c2ecf20Sopenharmony_ci // memory 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci /* 10098c2ecf20Sopenharmony_ci * Allocate memory for the base list of scb. Later allocate memory for 10108c2ecf20Sopenharmony_ci * CCBs and embedded components of each CCB and point the pointers in 10118c2ecf20Sopenharmony_ci * scb to the allocated components 10128c2ecf20Sopenharmony_ci * NOTE: The code to allocate SCB will be duplicated in all the LLD 10138c2ecf20Sopenharmony_ci * since the calling routine does not yet know the number of available 10148c2ecf20Sopenharmony_ci * commands. 10158c2ecf20Sopenharmony_ci */ 10168c2ecf20Sopenharmony_ci adapter->kscb_list = kcalloc(MBOX_MAX_SCSI_CMDS, sizeof(scb_t), GFP_KERNEL); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci if (adapter->kscb_list == NULL) { 10198c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 10208c2ecf20Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 10218c2ecf20Sopenharmony_ci __LINE__)); 10228c2ecf20Sopenharmony_ci goto out_free_ibuf; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci // memory allocation for our command packets 10268c2ecf20Sopenharmony_ci if (megaraid_mbox_setup_dma_pools(adapter) != 0) { 10278c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 10288c2ecf20Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 10298c2ecf20Sopenharmony_ci __LINE__)); 10308c2ecf20Sopenharmony_ci goto out_free_scb_list; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci // Adjust the scb pointers and link in the free pool 10348c2ecf20Sopenharmony_ci epthru_pci_blk = raid_dev->epthru_pool; 10358c2ecf20Sopenharmony_ci sg_pci_blk = raid_dev->sg_pool; 10368c2ecf20Sopenharmony_ci mbox_pci_blk = raid_dev->mbox_pool; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { 10398c2ecf20Sopenharmony_ci scb = adapter->kscb_list + i; 10408c2ecf20Sopenharmony_ci ccb = raid_dev->ccb_list + i; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci ccb->mbox = (mbox_t *)(mbox_pci_blk[i].vaddr + 16); 10438c2ecf20Sopenharmony_ci ccb->raw_mbox = (uint8_t *)ccb->mbox; 10448c2ecf20Sopenharmony_ci ccb->mbox64 = (mbox64_t *)(mbox_pci_blk[i].vaddr + 8); 10458c2ecf20Sopenharmony_ci ccb->mbox_dma_h = (unsigned long)mbox_pci_blk[i].dma_addr + 16; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci // make sure the mailbox is aligned properly 10488c2ecf20Sopenharmony_ci if (ccb->mbox_dma_h & 0x0F) { 10498c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_CRIT 10508c2ecf20Sopenharmony_ci "megaraid mbox: not aligned on 16-bytes\n")); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci goto out_teardown_dma_pools; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci ccb->epthru = (mraid_epassthru_t *) 10568c2ecf20Sopenharmony_ci epthru_pci_blk[i].vaddr; 10578c2ecf20Sopenharmony_ci ccb->epthru_dma_h = epthru_pci_blk[i].dma_addr; 10588c2ecf20Sopenharmony_ci ccb->pthru = (mraid_passthru_t *)ccb->epthru; 10598c2ecf20Sopenharmony_ci ccb->pthru_dma_h = ccb->epthru_dma_h; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci ccb->sgl64 = (mbox_sgl64 *)sg_pci_blk[i].vaddr; 10638c2ecf20Sopenharmony_ci ccb->sgl_dma_h = sg_pci_blk[i].dma_addr; 10648c2ecf20Sopenharmony_ci ccb->sgl32 = (mbox_sgl32 *)ccb->sgl64; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci scb->ccb = (caddr_t)ccb; 10678c2ecf20Sopenharmony_ci scb->gp = 0; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci scb->sno = i; // command index 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci scb->scp = NULL; 10728c2ecf20Sopenharmony_ci scb->state = SCB_FREE; 10738c2ecf20Sopenharmony_ci scb->dma_direction = DMA_NONE; 10748c2ecf20Sopenharmony_ci scb->dma_type = MRAID_DMA_NONE; 10758c2ecf20Sopenharmony_ci scb->dev_channel = -1; 10768c2ecf20Sopenharmony_ci scb->dev_target = -1; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci // put scb in the free pool 10798c2ecf20Sopenharmony_ci list_add_tail(&scb->list, &adapter->kscb_pool); 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci return 0; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ciout_teardown_dma_pools: 10858c2ecf20Sopenharmony_ci megaraid_mbox_teardown_dma_pools(adapter); 10868c2ecf20Sopenharmony_ciout_free_scb_list: 10878c2ecf20Sopenharmony_ci kfree(adapter->kscb_list); 10888c2ecf20Sopenharmony_ciout_free_ibuf: 10898c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, MBOX_IBUF_SIZE, (void *)adapter->ibuf, 10908c2ecf20Sopenharmony_ci adapter->ibuf_dma_h); 10918c2ecf20Sopenharmony_ciout_free_common_mbox: 10928c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, sizeof(mbox64_t), 10938c2ecf20Sopenharmony_ci (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci return -1; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci/** 11008c2ecf20Sopenharmony_ci * megaraid_free_cmd_packets - free memory 11018c2ecf20Sopenharmony_ci * @adapter : soft state of the raid controller 11028c2ecf20Sopenharmony_ci * 11038c2ecf20Sopenharmony_ci * Release memory resources allocated for commands. 11048c2ecf20Sopenharmony_ci */ 11058c2ecf20Sopenharmony_cistatic void 11068c2ecf20Sopenharmony_cimegaraid_free_cmd_packets(adapter_t *adapter) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci megaraid_mbox_teardown_dma_pools(adapter); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci kfree(adapter->kscb_list); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, MBOX_IBUF_SIZE, 11158c2ecf20Sopenharmony_ci (void *)adapter->ibuf, adapter->ibuf_dma_h); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, sizeof(mbox64_t), 11188c2ecf20Sopenharmony_ci (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma); 11198c2ecf20Sopenharmony_ci return; 11208c2ecf20Sopenharmony_ci} 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci/** 11248c2ecf20Sopenharmony_ci * megaraid_mbox_setup_dma_pools - setup dma pool for command packets 11258c2ecf20Sopenharmony_ci * @adapter : HBA soft state 11268c2ecf20Sopenharmony_ci * 11278c2ecf20Sopenharmony_ci * Setup the dma pools for mailbox, passthru and extended passthru structures, 11288c2ecf20Sopenharmony_ci * and scatter-gather lists. 11298c2ecf20Sopenharmony_ci */ 11308c2ecf20Sopenharmony_cistatic int 11318c2ecf20Sopenharmony_cimegaraid_mbox_setup_dma_pools(adapter_t *adapter) 11328c2ecf20Sopenharmony_ci{ 11338c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 11348c2ecf20Sopenharmony_ci struct mraid_pci_blk *epthru_pci_blk; 11358c2ecf20Sopenharmony_ci struct mraid_pci_blk *sg_pci_blk; 11368c2ecf20Sopenharmony_ci struct mraid_pci_blk *mbox_pci_blk; 11378c2ecf20Sopenharmony_ci int i; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci // Allocate memory for 16-bytes aligned mailboxes 11428c2ecf20Sopenharmony_ci raid_dev->mbox_pool_handle = dma_pool_create("megaraid mbox pool", 11438c2ecf20Sopenharmony_ci &adapter->pdev->dev, 11448c2ecf20Sopenharmony_ci sizeof(mbox64_t) + 16, 11458c2ecf20Sopenharmony_ci 16, 0); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if (raid_dev->mbox_pool_handle == NULL) { 11488c2ecf20Sopenharmony_ci goto fail_setup_dma_pool; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci mbox_pci_blk = raid_dev->mbox_pool; 11528c2ecf20Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { 11538c2ecf20Sopenharmony_ci mbox_pci_blk[i].vaddr = dma_pool_alloc( 11548c2ecf20Sopenharmony_ci raid_dev->mbox_pool_handle, 11558c2ecf20Sopenharmony_ci GFP_KERNEL, 11568c2ecf20Sopenharmony_ci &mbox_pci_blk[i].dma_addr); 11578c2ecf20Sopenharmony_ci if (!mbox_pci_blk[i].vaddr) { 11588c2ecf20Sopenharmony_ci goto fail_setup_dma_pool; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci /* 11638c2ecf20Sopenharmony_ci * Allocate memory for each embedded passthru strucuture pointer 11648c2ecf20Sopenharmony_ci * Request for a 128 bytes aligned structure for each passthru command 11658c2ecf20Sopenharmony_ci * structure 11668c2ecf20Sopenharmony_ci * Since passthru and extended passthru commands are exclusive, they 11678c2ecf20Sopenharmony_ci * share common memory pool. Passthru structures piggyback on memory 11688c2ecf20Sopenharmony_ci * allocted to extended passthru since passthru is smaller of the two 11698c2ecf20Sopenharmony_ci */ 11708c2ecf20Sopenharmony_ci raid_dev->epthru_pool_handle = dma_pool_create("megaraid mbox pthru", 11718c2ecf20Sopenharmony_ci &adapter->pdev->dev, sizeof(mraid_epassthru_t), 128, 0); 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci if (raid_dev->epthru_pool_handle == NULL) { 11748c2ecf20Sopenharmony_ci goto fail_setup_dma_pool; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci epthru_pci_blk = raid_dev->epthru_pool; 11788c2ecf20Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { 11798c2ecf20Sopenharmony_ci epthru_pci_blk[i].vaddr = dma_pool_alloc( 11808c2ecf20Sopenharmony_ci raid_dev->epthru_pool_handle, 11818c2ecf20Sopenharmony_ci GFP_KERNEL, 11828c2ecf20Sopenharmony_ci &epthru_pci_blk[i].dma_addr); 11838c2ecf20Sopenharmony_ci if (!epthru_pci_blk[i].vaddr) { 11848c2ecf20Sopenharmony_ci goto fail_setup_dma_pool; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci // Allocate memory for each scatter-gather list. Request for 512 bytes 11908c2ecf20Sopenharmony_ci // alignment for each sg list 11918c2ecf20Sopenharmony_ci raid_dev->sg_pool_handle = dma_pool_create("megaraid mbox sg", 11928c2ecf20Sopenharmony_ci &adapter->pdev->dev, 11938c2ecf20Sopenharmony_ci sizeof(mbox_sgl64) * MBOX_MAX_SG_SIZE, 11948c2ecf20Sopenharmony_ci 512, 0); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci if (raid_dev->sg_pool_handle == NULL) { 11978c2ecf20Sopenharmony_ci goto fail_setup_dma_pool; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci sg_pci_blk = raid_dev->sg_pool; 12018c2ecf20Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { 12028c2ecf20Sopenharmony_ci sg_pci_blk[i].vaddr = dma_pool_alloc( 12038c2ecf20Sopenharmony_ci raid_dev->sg_pool_handle, 12048c2ecf20Sopenharmony_ci GFP_KERNEL, 12058c2ecf20Sopenharmony_ci &sg_pci_blk[i].dma_addr); 12068c2ecf20Sopenharmony_ci if (!sg_pci_blk[i].vaddr) { 12078c2ecf20Sopenharmony_ci goto fail_setup_dma_pool; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci return 0; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cifail_setup_dma_pool: 12148c2ecf20Sopenharmony_ci megaraid_mbox_teardown_dma_pools(adapter); 12158c2ecf20Sopenharmony_ci return -1; 12168c2ecf20Sopenharmony_ci} 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci/** 12208c2ecf20Sopenharmony_ci * megaraid_mbox_teardown_dma_pools - teardown dma pools for command packets 12218c2ecf20Sopenharmony_ci * @adapter : HBA soft state 12228c2ecf20Sopenharmony_ci * 12238c2ecf20Sopenharmony_ci * Teardown the dma pool for mailbox, passthru and extended passthru 12248c2ecf20Sopenharmony_ci * structures, and scatter-gather lists. 12258c2ecf20Sopenharmony_ci */ 12268c2ecf20Sopenharmony_cistatic void 12278c2ecf20Sopenharmony_cimegaraid_mbox_teardown_dma_pools(adapter_t *adapter) 12288c2ecf20Sopenharmony_ci{ 12298c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 12308c2ecf20Sopenharmony_ci struct mraid_pci_blk *epthru_pci_blk; 12318c2ecf20Sopenharmony_ci struct mraid_pci_blk *sg_pci_blk; 12328c2ecf20Sopenharmony_ci struct mraid_pci_blk *mbox_pci_blk; 12338c2ecf20Sopenharmony_ci int i; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci sg_pci_blk = raid_dev->sg_pool; 12378c2ecf20Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS && sg_pci_blk[i].vaddr; i++) { 12388c2ecf20Sopenharmony_ci dma_pool_free(raid_dev->sg_pool_handle, sg_pci_blk[i].vaddr, 12398c2ecf20Sopenharmony_ci sg_pci_blk[i].dma_addr); 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci dma_pool_destroy(raid_dev->sg_pool_handle); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci epthru_pci_blk = raid_dev->epthru_pool; 12458c2ecf20Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS && epthru_pci_blk[i].vaddr; i++) { 12468c2ecf20Sopenharmony_ci dma_pool_free(raid_dev->epthru_pool_handle, 12478c2ecf20Sopenharmony_ci epthru_pci_blk[i].vaddr, epthru_pci_blk[i].dma_addr); 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci dma_pool_destroy(raid_dev->epthru_pool_handle); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci mbox_pci_blk = raid_dev->mbox_pool; 12538c2ecf20Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS && mbox_pci_blk[i].vaddr; i++) { 12548c2ecf20Sopenharmony_ci dma_pool_free(raid_dev->mbox_pool_handle, 12558c2ecf20Sopenharmony_ci mbox_pci_blk[i].vaddr, mbox_pci_blk[i].dma_addr); 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci dma_pool_destroy(raid_dev->mbox_pool_handle); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci return; 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci/** 12648c2ecf20Sopenharmony_ci * megaraid_alloc_scb - detach and return a scb from the free list 12658c2ecf20Sopenharmony_ci * @adapter : controller's soft state 12668c2ecf20Sopenharmony_ci * @scp : pointer to the scsi command to be executed 12678c2ecf20Sopenharmony_ci * 12688c2ecf20Sopenharmony_ci * Return the scb from the head of the free list. %NULL if there are none 12698c2ecf20Sopenharmony_ci * available. 12708c2ecf20Sopenharmony_ci */ 12718c2ecf20Sopenharmony_cistatic scb_t * 12728c2ecf20Sopenharmony_cimegaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp) 12738c2ecf20Sopenharmony_ci{ 12748c2ecf20Sopenharmony_ci struct list_head *head = &adapter->kscb_pool; 12758c2ecf20Sopenharmony_ci scb_t *scb = NULL; 12768c2ecf20Sopenharmony_ci unsigned long flags; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci // detach scb from free pool 12798c2ecf20Sopenharmony_ci spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (list_empty(head)) { 12828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); 12838c2ecf20Sopenharmony_ci return NULL; 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci scb = list_entry(head->next, scb_t, list); 12878c2ecf20Sopenharmony_ci list_del_init(&scb->list); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci scb->state = SCB_ACTIVE; 12928c2ecf20Sopenharmony_ci scb->scp = scp; 12938c2ecf20Sopenharmony_ci scb->dma_type = MRAID_DMA_NONE; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci return scb; 12968c2ecf20Sopenharmony_ci} 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci/** 13008c2ecf20Sopenharmony_ci * megaraid_dealloc_scb - return the scb to the free pool 13018c2ecf20Sopenharmony_ci * @adapter : controller's soft state 13028c2ecf20Sopenharmony_ci * @scb : scb to be freed 13038c2ecf20Sopenharmony_ci * 13048c2ecf20Sopenharmony_ci * Return the scb back to the free list of scbs. The caller must 'flush' the 13058c2ecf20Sopenharmony_ci * SCB before calling us. E.g., performing pci_unamp and/or pci_sync etc. 13068c2ecf20Sopenharmony_ci * NOTE NOTE: Make sure the scb is not on any list before calling this 13078c2ecf20Sopenharmony_ci * routine. 13088c2ecf20Sopenharmony_ci */ 13098c2ecf20Sopenharmony_cistatic inline void 13108c2ecf20Sopenharmony_cimegaraid_dealloc_scb(adapter_t *adapter, scb_t *scb) 13118c2ecf20Sopenharmony_ci{ 13128c2ecf20Sopenharmony_ci unsigned long flags; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci // put scb in the free pool 13158c2ecf20Sopenharmony_ci scb->state = SCB_FREE; 13168c2ecf20Sopenharmony_ci scb->scp = NULL; 13178c2ecf20Sopenharmony_ci spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci list_add(&scb->list, &adapter->kscb_pool); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci return; 13248c2ecf20Sopenharmony_ci} 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci/** 13288c2ecf20Sopenharmony_ci * megaraid_mbox_mksgl - make the scatter-gather list 13298c2ecf20Sopenharmony_ci * @adapter : controller's soft state 13308c2ecf20Sopenharmony_ci * @scb : scsi control block 13318c2ecf20Sopenharmony_ci * 13328c2ecf20Sopenharmony_ci * Prepare the scatter-gather list. 13338c2ecf20Sopenharmony_ci */ 13348c2ecf20Sopenharmony_cistatic int 13358c2ecf20Sopenharmony_cimegaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb) 13368c2ecf20Sopenharmony_ci{ 13378c2ecf20Sopenharmony_ci struct scatterlist *sgl; 13388c2ecf20Sopenharmony_ci mbox_ccb_t *ccb; 13398c2ecf20Sopenharmony_ci struct scsi_cmnd *scp; 13408c2ecf20Sopenharmony_ci int sgcnt; 13418c2ecf20Sopenharmony_ci int i; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci scp = scb->scp; 13458c2ecf20Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci sgcnt = scsi_dma_map(scp); 13488c2ecf20Sopenharmony_ci BUG_ON(sgcnt < 0 || sgcnt > adapter->sglen); 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci // no mapping required if no data to be transferred 13518c2ecf20Sopenharmony_ci if (!sgcnt) 13528c2ecf20Sopenharmony_ci return 0; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci scb->dma_type = MRAID_DMA_WSG; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci scsi_for_each_sg(scp, sgl, sgcnt, i) { 13578c2ecf20Sopenharmony_ci ccb->sgl64[i].address = sg_dma_address(sgl); 13588c2ecf20Sopenharmony_ci ccb->sgl64[i].length = sg_dma_len(sgl); 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci // Return count of SG nodes 13628c2ecf20Sopenharmony_ci return sgcnt; 13638c2ecf20Sopenharmony_ci} 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci/** 13678c2ecf20Sopenharmony_ci * mbox_post_cmd - issue a mailbox command 13688c2ecf20Sopenharmony_ci * @adapter : controller's soft state 13698c2ecf20Sopenharmony_ci * @scb : command to be issued 13708c2ecf20Sopenharmony_ci * 13718c2ecf20Sopenharmony_ci * Post the command to the controller if mailbox is available. 13728c2ecf20Sopenharmony_ci */ 13738c2ecf20Sopenharmony_cistatic int 13748c2ecf20Sopenharmony_cimbox_post_cmd(adapter_t *adapter, scb_t *scb) 13758c2ecf20Sopenharmony_ci{ 13768c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 13778c2ecf20Sopenharmony_ci mbox64_t *mbox64; 13788c2ecf20Sopenharmony_ci mbox_t *mbox; 13798c2ecf20Sopenharmony_ci mbox_ccb_t *ccb; 13808c2ecf20Sopenharmony_ci unsigned long flags; 13818c2ecf20Sopenharmony_ci unsigned int i = 0; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 13858c2ecf20Sopenharmony_ci mbox = raid_dev->mbox; 13868c2ecf20Sopenharmony_ci mbox64 = raid_dev->mbox64; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci /* 13898c2ecf20Sopenharmony_ci * Check for busy mailbox. If it is, return failure - the caller 13908c2ecf20Sopenharmony_ci * should retry later. 13918c2ecf20Sopenharmony_ci */ 13928c2ecf20Sopenharmony_ci spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (unlikely(mbox->busy)) { 13958c2ecf20Sopenharmony_ci do { 13968c2ecf20Sopenharmony_ci udelay(1); 13978c2ecf20Sopenharmony_ci i++; 13988c2ecf20Sopenharmony_ci rmb(); 13998c2ecf20Sopenharmony_ci } while(mbox->busy && (i < max_mbox_busy_wait)); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci if (mbox->busy) { 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci return -1; 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci // Copy this command's mailbox data into "adapter's" mailbox 14118c2ecf20Sopenharmony_ci memcpy((caddr_t)mbox64, (caddr_t)ccb->mbox64, 22); 14128c2ecf20Sopenharmony_ci mbox->cmdid = scb->sno; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci adapter->outstanding_cmds++; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci mbox->busy = 1; // Set busy 14178c2ecf20Sopenharmony_ci mbox->poll = 0; 14188c2ecf20Sopenharmony_ci mbox->ack = 0; 14198c2ecf20Sopenharmony_ci wmb(); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci return 0; 14268c2ecf20Sopenharmony_ci} 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci/** 14308c2ecf20Sopenharmony_ci * megaraid_queue_command - generic queue entry point for all LLDs 14318c2ecf20Sopenharmony_ci * @scp : pointer to the scsi command to be executed 14328c2ecf20Sopenharmony_ci * @done : callback routine to be called after the cmd has be completed 14338c2ecf20Sopenharmony_ci * 14348c2ecf20Sopenharmony_ci * Queue entry point for mailbox based controllers. 14358c2ecf20Sopenharmony_ci */ 14368c2ecf20Sopenharmony_cistatic int 14378c2ecf20Sopenharmony_cimegaraid_queue_command_lck(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *)) 14388c2ecf20Sopenharmony_ci{ 14398c2ecf20Sopenharmony_ci adapter_t *adapter; 14408c2ecf20Sopenharmony_ci scb_t *scb; 14418c2ecf20Sopenharmony_ci int if_busy; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci adapter = SCP2ADAPTER(scp); 14448c2ecf20Sopenharmony_ci scp->scsi_done = done; 14458c2ecf20Sopenharmony_ci scp->result = 0; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci /* 14488c2ecf20Sopenharmony_ci * Allocate and build a SCB request 14498c2ecf20Sopenharmony_ci * if_busy flag will be set if megaraid_mbox_build_cmd() command could 14508c2ecf20Sopenharmony_ci * not allocate scb. We will return non-zero status in that case. 14518c2ecf20Sopenharmony_ci * NOTE: scb can be null even though certain commands completed 14528c2ecf20Sopenharmony_ci * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, it would 14538c2ecf20Sopenharmony_ci * return 0 in that case, and we would do the callback right away. 14548c2ecf20Sopenharmony_ci */ 14558c2ecf20Sopenharmony_ci if_busy = 0; 14568c2ecf20Sopenharmony_ci scb = megaraid_mbox_build_cmd(adapter, scp, &if_busy); 14578c2ecf20Sopenharmony_ci if (!scb) { // command already completed 14588c2ecf20Sopenharmony_ci done(scp); 14598c2ecf20Sopenharmony_ci return 0; 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci megaraid_mbox_runpendq(adapter, scb); 14638c2ecf20Sopenharmony_ci return if_busy; 14648c2ecf20Sopenharmony_ci} 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(megaraid_queue_command) 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci/** 14698c2ecf20Sopenharmony_ci * megaraid_mbox_build_cmd - transform the mid-layer scsi commands 14708c2ecf20Sopenharmony_ci * @adapter : controller's soft state 14718c2ecf20Sopenharmony_ci * @scp : mid-layer scsi command pointer 14728c2ecf20Sopenharmony_ci * @busy : set if request could not be completed because of lack of 14738c2ecf20Sopenharmony_ci * resources 14748c2ecf20Sopenharmony_ci * 14758c2ecf20Sopenharmony_ci * Transform the mid-layer scsi command to megaraid firmware lingua. 14768c2ecf20Sopenharmony_ci * Convert the command issued by mid-layer to format understood by megaraid 14778c2ecf20Sopenharmony_ci * firmware. We also complete certain commands without sending them to firmware. 14788c2ecf20Sopenharmony_ci */ 14798c2ecf20Sopenharmony_cistatic scb_t * 14808c2ecf20Sopenharmony_cimegaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) 14818c2ecf20Sopenharmony_ci{ 14828c2ecf20Sopenharmony_ci mraid_device_t *rdev = ADAP2RAIDDEV(adapter); 14838c2ecf20Sopenharmony_ci int channel; 14848c2ecf20Sopenharmony_ci int target; 14858c2ecf20Sopenharmony_ci int islogical; 14868c2ecf20Sopenharmony_ci mbox_ccb_t *ccb; 14878c2ecf20Sopenharmony_ci mraid_passthru_t *pthru; 14888c2ecf20Sopenharmony_ci mbox64_t *mbox64; 14898c2ecf20Sopenharmony_ci mbox_t *mbox; 14908c2ecf20Sopenharmony_ci scb_t *scb; 14918c2ecf20Sopenharmony_ci char skip[] = "skipping"; 14928c2ecf20Sopenharmony_ci char scan[] = "scanning"; 14938c2ecf20Sopenharmony_ci char *ss; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci /* 14978c2ecf20Sopenharmony_ci * Get the appropriate device map for the device this command is 14988c2ecf20Sopenharmony_ci * intended for 14998c2ecf20Sopenharmony_ci */ 15008c2ecf20Sopenharmony_ci MRAID_GET_DEVICE_MAP(adapter, scp, channel, target, islogical); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci /* 15038c2ecf20Sopenharmony_ci * Logical drive commands 15048c2ecf20Sopenharmony_ci */ 15058c2ecf20Sopenharmony_ci if (islogical) { 15068c2ecf20Sopenharmony_ci switch (scp->cmnd[0]) { 15078c2ecf20Sopenharmony_ci case TEST_UNIT_READY: 15088c2ecf20Sopenharmony_ci /* 15098c2ecf20Sopenharmony_ci * Do we support clustering and is the support enabled 15108c2ecf20Sopenharmony_ci * If no, return success always 15118c2ecf20Sopenharmony_ci */ 15128c2ecf20Sopenharmony_ci if (!adapter->ha) { 15138c2ecf20Sopenharmony_ci scp->result = (DID_OK << 16); 15148c2ecf20Sopenharmony_ci return NULL; 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci if (!(scb = megaraid_alloc_scb(adapter, scp))) { 15188c2ecf20Sopenharmony_ci scp->result = (DID_ERROR << 16); 15198c2ecf20Sopenharmony_ci *busy = 1; 15208c2ecf20Sopenharmony_ci return NULL; 15218c2ecf20Sopenharmony_ci } 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci scb->dma_direction = scp->sc_data_direction; 15248c2ecf20Sopenharmony_ci scb->dev_channel = 0xFF; 15258c2ecf20Sopenharmony_ci scb->dev_target = target; 15268c2ecf20Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci /* 15298c2ecf20Sopenharmony_ci * The command id will be provided by the command 15308c2ecf20Sopenharmony_ci * issuance routine 15318c2ecf20Sopenharmony_ci */ 15328c2ecf20Sopenharmony_ci ccb->raw_mbox[0] = CLUSTER_CMD; 15338c2ecf20Sopenharmony_ci ccb->raw_mbox[2] = RESERVATION_STATUS; 15348c2ecf20Sopenharmony_ci ccb->raw_mbox[3] = target; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci return scb; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci case MODE_SENSE: 15398c2ecf20Sopenharmony_ci { 15408c2ecf20Sopenharmony_ci struct scatterlist *sgl; 15418c2ecf20Sopenharmony_ci caddr_t vaddr; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci sgl = scsi_sglist(scp); 15448c2ecf20Sopenharmony_ci if (sg_page(sgl)) { 15458c2ecf20Sopenharmony_ci vaddr = (caddr_t) sg_virt(&sgl[0]); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci memset(vaddr, 0, scp->cmnd[4]); 15488c2ecf20Sopenharmony_ci } 15498c2ecf20Sopenharmony_ci else { 15508c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 15518c2ecf20Sopenharmony_ci "megaraid mailbox: invalid sg:%d\n", 15528c2ecf20Sopenharmony_ci __LINE__)); 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci scp->result = (DID_OK << 16); 15568c2ecf20Sopenharmony_ci return NULL; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci case INQUIRY: 15598c2ecf20Sopenharmony_ci /* 15608c2ecf20Sopenharmony_ci * Display the channel scan for logical drives 15618c2ecf20Sopenharmony_ci * Do not display scan for a channel if already done. 15628c2ecf20Sopenharmony_ci */ 15638c2ecf20Sopenharmony_ci if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) { 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_INFO 15668c2ecf20Sopenharmony_ci "scsi[%d]: scanning scsi channel %d", 15678c2ecf20Sopenharmony_ci adapter->host->host_no, 15688c2ecf20Sopenharmony_ci SCP2CHANNEL(scp))); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci con_log(CL_ANN, ( 15718c2ecf20Sopenharmony_ci " [virtual] for logical drives\n")); 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci rdev->last_disp |= (1L << SCP2CHANNEL(scp)); 15748c2ecf20Sopenharmony_ci } 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci if (scp->cmnd[1] & MEGA_SCSI_INQ_EVPD) { 15778c2ecf20Sopenharmony_ci scp->sense_buffer[0] = 0x70; 15788c2ecf20Sopenharmony_ci scp->sense_buffer[2] = ILLEGAL_REQUEST; 15798c2ecf20Sopenharmony_ci scp->sense_buffer[12] = MEGA_INVALID_FIELD_IN_CDB; 15808c2ecf20Sopenharmony_ci scp->result = CHECK_CONDITION << 1; 15818c2ecf20Sopenharmony_ci return NULL; 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci fallthrough; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci case READ_CAPACITY: 15878c2ecf20Sopenharmony_ci /* 15888c2ecf20Sopenharmony_ci * Do not allow LUN > 0 for logical drives and 15898c2ecf20Sopenharmony_ci * requests for more than 40 logical drives 15908c2ecf20Sopenharmony_ci */ 15918c2ecf20Sopenharmony_ci if (SCP2LUN(scp)) { 15928c2ecf20Sopenharmony_ci scp->result = (DID_BAD_TARGET << 16); 15938c2ecf20Sopenharmony_ci return NULL; 15948c2ecf20Sopenharmony_ci } 15958c2ecf20Sopenharmony_ci if ((target % 0x80) >= MAX_LOGICAL_DRIVES_40LD) { 15968c2ecf20Sopenharmony_ci scp->result = (DID_BAD_TARGET << 16); 15978c2ecf20Sopenharmony_ci return NULL; 15988c2ecf20Sopenharmony_ci } 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci /* Allocate a SCB and initialize passthru */ 16028c2ecf20Sopenharmony_ci if (!(scb = megaraid_alloc_scb(adapter, scp))) { 16038c2ecf20Sopenharmony_ci scp->result = (DID_ERROR << 16); 16048c2ecf20Sopenharmony_ci *busy = 1; 16058c2ecf20Sopenharmony_ci return NULL; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 16098c2ecf20Sopenharmony_ci scb->dev_channel = 0xFF; 16108c2ecf20Sopenharmony_ci scb->dev_target = target; 16118c2ecf20Sopenharmony_ci pthru = ccb->pthru; 16128c2ecf20Sopenharmony_ci mbox = ccb->mbox; 16138c2ecf20Sopenharmony_ci mbox64 = ccb->mbox64; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci pthru->timeout = 0; 16168c2ecf20Sopenharmony_ci pthru->ars = 1; 16178c2ecf20Sopenharmony_ci pthru->reqsenselen = 14; 16188c2ecf20Sopenharmony_ci pthru->islogical = 1; 16198c2ecf20Sopenharmony_ci pthru->logdrv = target; 16208c2ecf20Sopenharmony_ci pthru->cdblen = scp->cmd_len; 16218c2ecf20Sopenharmony_ci memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci mbox->cmd = MBOXCMD_PASSTHRU64; 16248c2ecf20Sopenharmony_ci scb->dma_direction = scp->sc_data_direction; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci pthru->dataxferlen = scsi_bufflen(scp); 16278c2ecf20Sopenharmony_ci pthru->dataxferaddr = ccb->sgl_dma_h; 16288c2ecf20Sopenharmony_ci pthru->numsge = megaraid_mbox_mksgl(adapter, 16298c2ecf20Sopenharmony_ci scb); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci mbox->xferaddr = 0xFFFFFFFF; 16328c2ecf20Sopenharmony_ci mbox64->xferaddr_lo = (uint32_t )ccb->pthru_dma_h; 16338c2ecf20Sopenharmony_ci mbox64->xferaddr_hi = 0; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci return scb; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci case READ_6: 16388c2ecf20Sopenharmony_ci case WRITE_6: 16398c2ecf20Sopenharmony_ci case READ_10: 16408c2ecf20Sopenharmony_ci case WRITE_10: 16418c2ecf20Sopenharmony_ci case READ_12: 16428c2ecf20Sopenharmony_ci case WRITE_12: 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci /* 16458c2ecf20Sopenharmony_ci * Allocate a SCB and initialize mailbox 16468c2ecf20Sopenharmony_ci */ 16478c2ecf20Sopenharmony_ci if (!(scb = megaraid_alloc_scb(adapter, scp))) { 16488c2ecf20Sopenharmony_ci scp->result = (DID_ERROR << 16); 16498c2ecf20Sopenharmony_ci *busy = 1; 16508c2ecf20Sopenharmony_ci return NULL; 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 16538c2ecf20Sopenharmony_ci scb->dev_channel = 0xFF; 16548c2ecf20Sopenharmony_ci scb->dev_target = target; 16558c2ecf20Sopenharmony_ci mbox = ccb->mbox; 16568c2ecf20Sopenharmony_ci mbox64 = ccb->mbox64; 16578c2ecf20Sopenharmony_ci mbox->logdrv = target; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci /* 16608c2ecf20Sopenharmony_ci * A little HACK: 2nd bit is zero for all scsi read 16618c2ecf20Sopenharmony_ci * commands and is set for all scsi write commands 16628c2ecf20Sopenharmony_ci */ 16638c2ecf20Sopenharmony_ci mbox->cmd = (scp->cmnd[0] & 0x02) ? MBOXCMD_LWRITE64: 16648c2ecf20Sopenharmony_ci MBOXCMD_LREAD64 ; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci /* 16678c2ecf20Sopenharmony_ci * 6-byte READ(0x08) or WRITE(0x0A) cdb 16688c2ecf20Sopenharmony_ci */ 16698c2ecf20Sopenharmony_ci if (scp->cmd_len == 6) { 16708c2ecf20Sopenharmony_ci mbox->numsectors = (uint32_t)scp->cmnd[4]; 16718c2ecf20Sopenharmony_ci mbox->lba = 16728c2ecf20Sopenharmony_ci ((uint32_t)scp->cmnd[1] << 16) | 16738c2ecf20Sopenharmony_ci ((uint32_t)scp->cmnd[2] << 8) | 16748c2ecf20Sopenharmony_ci (uint32_t)scp->cmnd[3]; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci mbox->lba &= 0x1FFFFF; 16778c2ecf20Sopenharmony_ci } 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci /* 16808c2ecf20Sopenharmony_ci * 10-byte READ(0x28) or WRITE(0x2A) cdb 16818c2ecf20Sopenharmony_ci */ 16828c2ecf20Sopenharmony_ci else if (scp->cmd_len == 10) { 16838c2ecf20Sopenharmony_ci mbox->numsectors = 16848c2ecf20Sopenharmony_ci (uint32_t)scp->cmnd[8] | 16858c2ecf20Sopenharmony_ci ((uint32_t)scp->cmnd[7] << 8); 16868c2ecf20Sopenharmony_ci mbox->lba = 16878c2ecf20Sopenharmony_ci ((uint32_t)scp->cmnd[2] << 24) | 16888c2ecf20Sopenharmony_ci ((uint32_t)scp->cmnd[3] << 16) | 16898c2ecf20Sopenharmony_ci ((uint32_t)scp->cmnd[4] << 8) | 16908c2ecf20Sopenharmony_ci (uint32_t)scp->cmnd[5]; 16918c2ecf20Sopenharmony_ci } 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci /* 16948c2ecf20Sopenharmony_ci * 12-byte READ(0xA8) or WRITE(0xAA) cdb 16958c2ecf20Sopenharmony_ci */ 16968c2ecf20Sopenharmony_ci else if (scp->cmd_len == 12) { 16978c2ecf20Sopenharmony_ci mbox->lba = 16988c2ecf20Sopenharmony_ci ((uint32_t)scp->cmnd[2] << 24) | 16998c2ecf20Sopenharmony_ci ((uint32_t)scp->cmnd[3] << 16) | 17008c2ecf20Sopenharmony_ci ((uint32_t)scp->cmnd[4] << 8) | 17018c2ecf20Sopenharmony_ci (uint32_t)scp->cmnd[5]; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci mbox->numsectors = 17048c2ecf20Sopenharmony_ci ((uint32_t)scp->cmnd[6] << 24) | 17058c2ecf20Sopenharmony_ci ((uint32_t)scp->cmnd[7] << 16) | 17068c2ecf20Sopenharmony_ci ((uint32_t)scp->cmnd[8] << 8) | 17078c2ecf20Sopenharmony_ci (uint32_t)scp->cmnd[9]; 17088c2ecf20Sopenharmony_ci } 17098c2ecf20Sopenharmony_ci else { 17108c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 17118c2ecf20Sopenharmony_ci "megaraid: unsupported CDB length\n")); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci megaraid_dealloc_scb(adapter, scb); 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci scp->result = (DID_ERROR << 16); 17168c2ecf20Sopenharmony_ci return NULL; 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci scb->dma_direction = scp->sc_data_direction; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci // Calculate Scatter-Gather info 17228c2ecf20Sopenharmony_ci mbox64->xferaddr_lo = (uint32_t )ccb->sgl_dma_h; 17238c2ecf20Sopenharmony_ci mbox->numsge = megaraid_mbox_mksgl(adapter, 17248c2ecf20Sopenharmony_ci scb); 17258c2ecf20Sopenharmony_ci mbox->xferaddr = 0xFFFFFFFF; 17268c2ecf20Sopenharmony_ci mbox64->xferaddr_hi = 0; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci return scb; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci case RESERVE: 17318c2ecf20Sopenharmony_ci case RELEASE: 17328c2ecf20Sopenharmony_ci /* 17338c2ecf20Sopenharmony_ci * Do we support clustering and is the support enabled 17348c2ecf20Sopenharmony_ci */ 17358c2ecf20Sopenharmony_ci if (!adapter->ha) { 17368c2ecf20Sopenharmony_ci scp->result = (DID_BAD_TARGET << 16); 17378c2ecf20Sopenharmony_ci return NULL; 17388c2ecf20Sopenharmony_ci } 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci /* 17418c2ecf20Sopenharmony_ci * Allocate a SCB and initialize mailbox 17428c2ecf20Sopenharmony_ci */ 17438c2ecf20Sopenharmony_ci if (!(scb = megaraid_alloc_scb(adapter, scp))) { 17448c2ecf20Sopenharmony_ci scp->result = (DID_ERROR << 16); 17458c2ecf20Sopenharmony_ci *busy = 1; 17468c2ecf20Sopenharmony_ci return NULL; 17478c2ecf20Sopenharmony_ci } 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 17508c2ecf20Sopenharmony_ci scb->dev_channel = 0xFF; 17518c2ecf20Sopenharmony_ci scb->dev_target = target; 17528c2ecf20Sopenharmony_ci ccb->raw_mbox[0] = CLUSTER_CMD; 17538c2ecf20Sopenharmony_ci ccb->raw_mbox[2] = (scp->cmnd[0] == RESERVE) ? 17548c2ecf20Sopenharmony_ci RESERVE_LD : RELEASE_LD; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci ccb->raw_mbox[3] = target; 17578c2ecf20Sopenharmony_ci scb->dma_direction = scp->sc_data_direction; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci return scb; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci default: 17628c2ecf20Sopenharmony_ci scp->result = (DID_BAD_TARGET << 16); 17638c2ecf20Sopenharmony_ci return NULL; 17648c2ecf20Sopenharmony_ci } 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci else { // Passthru device commands 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci // Do not allow access to target id > 15 or LUN > 7 17698c2ecf20Sopenharmony_ci if (target > 15 || SCP2LUN(scp) > 7) { 17708c2ecf20Sopenharmony_ci scp->result = (DID_BAD_TARGET << 16); 17718c2ecf20Sopenharmony_ci return NULL; 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci // if fast load option was set and scan for last device is 17758c2ecf20Sopenharmony_ci // over, reset the fast_load flag so that during a possible 17768c2ecf20Sopenharmony_ci // next scan, devices can be made available 17778c2ecf20Sopenharmony_ci if (rdev->fast_load && (target == 15) && 17788c2ecf20Sopenharmony_ci (SCP2CHANNEL(scp) == adapter->max_channel -1)) { 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_INFO 17818c2ecf20Sopenharmony_ci "megaraid[%d]: physical device scan re-enabled\n", 17828c2ecf20Sopenharmony_ci adapter->host->host_no)); 17838c2ecf20Sopenharmony_ci rdev->fast_load = 0; 17848c2ecf20Sopenharmony_ci } 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci /* 17878c2ecf20Sopenharmony_ci * Display the channel scan for physical devices 17888c2ecf20Sopenharmony_ci */ 17898c2ecf20Sopenharmony_ci if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) { 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci ss = rdev->fast_load ? skip : scan; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_INFO 17948c2ecf20Sopenharmony_ci "scsi[%d]: %s scsi channel %d [Phy %d]", 17958c2ecf20Sopenharmony_ci adapter->host->host_no, ss, SCP2CHANNEL(scp), 17968c2ecf20Sopenharmony_ci channel)); 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci con_log(CL_ANN, ( 17998c2ecf20Sopenharmony_ci " for non-raid devices\n")); 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci rdev->last_disp |= (1L << SCP2CHANNEL(scp)); 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci // disable channel sweep if fast load option given 18058c2ecf20Sopenharmony_ci if (rdev->fast_load) { 18068c2ecf20Sopenharmony_ci scp->result = (DID_BAD_TARGET << 16); 18078c2ecf20Sopenharmony_ci return NULL; 18088c2ecf20Sopenharmony_ci } 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci // Allocate a SCB and initialize passthru 18118c2ecf20Sopenharmony_ci if (!(scb = megaraid_alloc_scb(adapter, scp))) { 18128c2ecf20Sopenharmony_ci scp->result = (DID_ERROR << 16); 18138c2ecf20Sopenharmony_ci *busy = 1; 18148c2ecf20Sopenharmony_ci return NULL; 18158c2ecf20Sopenharmony_ci } 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 18188c2ecf20Sopenharmony_ci scb->dev_channel = channel; 18198c2ecf20Sopenharmony_ci scb->dev_target = target; 18208c2ecf20Sopenharmony_ci scb->dma_direction = scp->sc_data_direction; 18218c2ecf20Sopenharmony_ci mbox = ccb->mbox; 18228c2ecf20Sopenharmony_ci mbox64 = ccb->mbox64; 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci // Does this firmware support extended CDBs 18258c2ecf20Sopenharmony_ci if (adapter->max_cdb_sz == 16) { 18268c2ecf20Sopenharmony_ci mbox->cmd = MBOXCMD_EXTPTHRU; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci megaraid_mbox_prepare_epthru(adapter, scb, scp); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci mbox64->xferaddr_lo = (uint32_t)ccb->epthru_dma_h; 18318c2ecf20Sopenharmony_ci mbox64->xferaddr_hi = 0; 18328c2ecf20Sopenharmony_ci mbox->xferaddr = 0xFFFFFFFF; 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci else { 18358c2ecf20Sopenharmony_ci mbox->cmd = MBOXCMD_PASSTHRU64; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci megaraid_mbox_prepare_pthru(adapter, scb, scp); 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci mbox64->xferaddr_lo = (uint32_t)ccb->pthru_dma_h; 18408c2ecf20Sopenharmony_ci mbox64->xferaddr_hi = 0; 18418c2ecf20Sopenharmony_ci mbox->xferaddr = 0xFFFFFFFF; 18428c2ecf20Sopenharmony_ci } 18438c2ecf20Sopenharmony_ci return scb; 18448c2ecf20Sopenharmony_ci } 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci // NOT REACHED 18478c2ecf20Sopenharmony_ci} 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci/** 18518c2ecf20Sopenharmony_ci * megaraid_mbox_runpendq - execute commands queued in the pending queue 18528c2ecf20Sopenharmony_ci * @adapter : controller's soft state 18538c2ecf20Sopenharmony_ci * @scb_q : SCB to be queued in the pending list 18548c2ecf20Sopenharmony_ci * 18558c2ecf20Sopenharmony_ci * Scan the pending list for commands which are not yet issued and try to 18568c2ecf20Sopenharmony_ci * post to the controller. The SCB can be a null pointer, which would indicate 18578c2ecf20Sopenharmony_ci * no SCB to be queue, just try to execute the ones in the pending list. 18588c2ecf20Sopenharmony_ci * 18598c2ecf20Sopenharmony_ci * NOTE: We do not actually traverse the pending list. The SCBs are plucked 18608c2ecf20Sopenharmony_ci * out from the head of the pending list. If it is successfully issued, the 18618c2ecf20Sopenharmony_ci * next SCB is at the head now. 18628c2ecf20Sopenharmony_ci */ 18638c2ecf20Sopenharmony_cistatic void 18648c2ecf20Sopenharmony_cimegaraid_mbox_runpendq(adapter_t *adapter, scb_t *scb_q) 18658c2ecf20Sopenharmony_ci{ 18668c2ecf20Sopenharmony_ci scb_t *scb; 18678c2ecf20Sopenharmony_ci unsigned long flags; 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci if (scb_q) { 18728c2ecf20Sopenharmony_ci scb_q->state = SCB_PENDQ; 18738c2ecf20Sopenharmony_ci list_add_tail(&scb_q->list, &adapter->pend_list); 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci // if the adapter in not in quiescent mode, post the commands to FW 18778c2ecf20Sopenharmony_ci if (adapter->quiescent) { 18788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); 18798c2ecf20Sopenharmony_ci return; 18808c2ecf20Sopenharmony_ci } 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci while (!list_empty(&adapter->pend_list)) { 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci assert_spin_locked(PENDING_LIST_LOCK(adapter)); 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci scb = list_entry(adapter->pend_list.next, scb_t, list); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci // remove the scb from the pending list and try to 18898c2ecf20Sopenharmony_ci // issue. If we are unable to issue it, put back in 18908c2ecf20Sopenharmony_ci // the pending list and return 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci list_del_init(&scb->list); 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci // if mailbox was busy, return SCB back to pending 18978c2ecf20Sopenharmony_ci // list. Make sure to add at the head, since that's 18988c2ecf20Sopenharmony_ci // where it would have been removed from 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci scb->state = SCB_ISSUED; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci if (mbox_post_cmd(adapter, scb) != 0) { 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci scb->state = SCB_PENDQ; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci list_add(&scb->list, &adapter->pend_list); 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), 19118c2ecf20Sopenharmony_ci flags); 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci return; 19148c2ecf20Sopenharmony_ci } 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci return; 19238c2ecf20Sopenharmony_ci} 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci/** 19278c2ecf20Sopenharmony_ci * megaraid_mbox_prepare_pthru - prepare a command for physical devices 19288c2ecf20Sopenharmony_ci * @adapter : pointer to controller's soft state 19298c2ecf20Sopenharmony_ci * @scb : scsi control block 19308c2ecf20Sopenharmony_ci * @scp : scsi command from the mid-layer 19318c2ecf20Sopenharmony_ci * 19328c2ecf20Sopenharmony_ci * Prepare a command for the scsi physical devices. 19338c2ecf20Sopenharmony_ci */ 19348c2ecf20Sopenharmony_cistatic void 19358c2ecf20Sopenharmony_cimegaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb, 19368c2ecf20Sopenharmony_ci struct scsi_cmnd *scp) 19378c2ecf20Sopenharmony_ci{ 19388c2ecf20Sopenharmony_ci mbox_ccb_t *ccb; 19398c2ecf20Sopenharmony_ci mraid_passthru_t *pthru; 19408c2ecf20Sopenharmony_ci uint8_t channel; 19418c2ecf20Sopenharmony_ci uint8_t target; 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 19448c2ecf20Sopenharmony_ci pthru = ccb->pthru; 19458c2ecf20Sopenharmony_ci channel = scb->dev_channel; 19468c2ecf20Sopenharmony_ci target = scb->dev_target; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci // 0=6sec, 1=60sec, 2=10min, 3=3hrs, 4=NO timeout 19498c2ecf20Sopenharmony_ci pthru->timeout = 4; 19508c2ecf20Sopenharmony_ci pthru->ars = 1; 19518c2ecf20Sopenharmony_ci pthru->islogical = 0; 19528c2ecf20Sopenharmony_ci pthru->channel = 0; 19538c2ecf20Sopenharmony_ci pthru->target = (channel << 4) | target; 19548c2ecf20Sopenharmony_ci pthru->logdrv = SCP2LUN(scp); 19558c2ecf20Sopenharmony_ci pthru->reqsenselen = 14; 19568c2ecf20Sopenharmony_ci pthru->cdblen = scp->cmd_len; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci if (scsi_bufflen(scp)) { 19618c2ecf20Sopenharmony_ci pthru->dataxferlen = scsi_bufflen(scp); 19628c2ecf20Sopenharmony_ci pthru->dataxferaddr = ccb->sgl_dma_h; 19638c2ecf20Sopenharmony_ci pthru->numsge = megaraid_mbox_mksgl(adapter, scb); 19648c2ecf20Sopenharmony_ci } 19658c2ecf20Sopenharmony_ci else { 19668c2ecf20Sopenharmony_ci pthru->dataxferaddr = 0; 19678c2ecf20Sopenharmony_ci pthru->dataxferlen = 0; 19688c2ecf20Sopenharmony_ci pthru->numsge = 0; 19698c2ecf20Sopenharmony_ci } 19708c2ecf20Sopenharmony_ci return; 19718c2ecf20Sopenharmony_ci} 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci/** 19758c2ecf20Sopenharmony_ci * megaraid_mbox_prepare_epthru - prepare a command for physical devices 19768c2ecf20Sopenharmony_ci * @adapter : pointer to controller's soft state 19778c2ecf20Sopenharmony_ci * @scb : scsi control block 19788c2ecf20Sopenharmony_ci * @scp : scsi command from the mid-layer 19798c2ecf20Sopenharmony_ci * 19808c2ecf20Sopenharmony_ci * Prepare a command for the scsi physical devices. This routine prepares 19818c2ecf20Sopenharmony_ci * commands for devices which can take extended CDBs (>10 bytes). 19828c2ecf20Sopenharmony_ci */ 19838c2ecf20Sopenharmony_cistatic void 19848c2ecf20Sopenharmony_cimegaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb, 19858c2ecf20Sopenharmony_ci struct scsi_cmnd *scp) 19868c2ecf20Sopenharmony_ci{ 19878c2ecf20Sopenharmony_ci mbox_ccb_t *ccb; 19888c2ecf20Sopenharmony_ci mraid_epassthru_t *epthru; 19898c2ecf20Sopenharmony_ci uint8_t channel; 19908c2ecf20Sopenharmony_ci uint8_t target; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 19938c2ecf20Sopenharmony_ci epthru = ccb->epthru; 19948c2ecf20Sopenharmony_ci channel = scb->dev_channel; 19958c2ecf20Sopenharmony_ci target = scb->dev_target; 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci // 0=6sec, 1=60sec, 2=10min, 3=3hrs, 4=NO timeout 19988c2ecf20Sopenharmony_ci epthru->timeout = 4; 19998c2ecf20Sopenharmony_ci epthru->ars = 1; 20008c2ecf20Sopenharmony_ci epthru->islogical = 0; 20018c2ecf20Sopenharmony_ci epthru->channel = 0; 20028c2ecf20Sopenharmony_ci epthru->target = (channel << 4) | target; 20038c2ecf20Sopenharmony_ci epthru->logdrv = SCP2LUN(scp); 20048c2ecf20Sopenharmony_ci epthru->reqsenselen = 14; 20058c2ecf20Sopenharmony_ci epthru->cdblen = scp->cmd_len; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci memcpy(epthru->cdb, scp->cmnd, scp->cmd_len); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci if (scsi_bufflen(scp)) { 20108c2ecf20Sopenharmony_ci epthru->dataxferlen = scsi_bufflen(scp); 20118c2ecf20Sopenharmony_ci epthru->dataxferaddr = ccb->sgl_dma_h; 20128c2ecf20Sopenharmony_ci epthru->numsge = megaraid_mbox_mksgl(adapter, scb); 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci else { 20158c2ecf20Sopenharmony_ci epthru->dataxferaddr = 0; 20168c2ecf20Sopenharmony_ci epthru->dataxferlen = 0; 20178c2ecf20Sopenharmony_ci epthru->numsge = 0; 20188c2ecf20Sopenharmony_ci } 20198c2ecf20Sopenharmony_ci return; 20208c2ecf20Sopenharmony_ci} 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci/** 20248c2ecf20Sopenharmony_ci * megaraid_ack_sequence - interrupt ack sequence for memory mapped HBAs 20258c2ecf20Sopenharmony_ci * @adapter : controller's soft state 20268c2ecf20Sopenharmony_ci * 20278c2ecf20Sopenharmony_ci * Interrupt acknowledgement sequence for memory mapped HBAs. Find out the 20288c2ecf20Sopenharmony_ci * completed command and put them on the completed list for later processing. 20298c2ecf20Sopenharmony_ci * 20308c2ecf20Sopenharmony_ci * Returns: 1 if the interrupt is valid, 0 otherwise 20318c2ecf20Sopenharmony_ci */ 20328c2ecf20Sopenharmony_cistatic int 20338c2ecf20Sopenharmony_cimegaraid_ack_sequence(adapter_t *adapter) 20348c2ecf20Sopenharmony_ci{ 20358c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 20368c2ecf20Sopenharmony_ci mbox_t *mbox; 20378c2ecf20Sopenharmony_ci scb_t *scb; 20388c2ecf20Sopenharmony_ci uint8_t nstatus; 20398c2ecf20Sopenharmony_ci uint8_t completed[MBOX_MAX_FIRMWARE_STATUS]; 20408c2ecf20Sopenharmony_ci struct list_head clist; 20418c2ecf20Sopenharmony_ci int handled; 20428c2ecf20Sopenharmony_ci uint32_t dword; 20438c2ecf20Sopenharmony_ci unsigned long flags; 20448c2ecf20Sopenharmony_ci int i, j; 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci mbox = raid_dev->mbox; 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci // move the SCBs from the firmware completed array to our local list 20508c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&clist); 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci // loop till F/W has more commands for us to complete 20538c2ecf20Sopenharmony_ci handled = 0; 20548c2ecf20Sopenharmony_ci spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags); 20558c2ecf20Sopenharmony_ci do { 20568c2ecf20Sopenharmony_ci /* 20578c2ecf20Sopenharmony_ci * Check if a valid interrupt is pending. If found, force the 20588c2ecf20Sopenharmony_ci * interrupt line low. 20598c2ecf20Sopenharmony_ci */ 20608c2ecf20Sopenharmony_ci dword = RDOUTDOOR(raid_dev); 20618c2ecf20Sopenharmony_ci if (dword != 0x10001234) break; 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci handled = 1; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci WROUTDOOR(raid_dev, 0x10001234); 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci nstatus = 0; 20688c2ecf20Sopenharmony_ci // wait for valid numstatus to post 20698c2ecf20Sopenharmony_ci for (i = 0; i < 0xFFFFF; i++) { 20708c2ecf20Sopenharmony_ci if (mbox->numstatus != 0xFF) { 20718c2ecf20Sopenharmony_ci nstatus = mbox->numstatus; 20728c2ecf20Sopenharmony_ci break; 20738c2ecf20Sopenharmony_ci } 20748c2ecf20Sopenharmony_ci rmb(); 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci mbox->numstatus = 0xFF; 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci adapter->outstanding_cmds -= nstatus; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci for (i = 0; i < nstatus; i++) { 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci // wait for valid command index to post 20838c2ecf20Sopenharmony_ci for (j = 0; j < 0xFFFFF; j++) { 20848c2ecf20Sopenharmony_ci if (mbox->completed[i] != 0xFF) break; 20858c2ecf20Sopenharmony_ci rmb(); 20868c2ecf20Sopenharmony_ci } 20878c2ecf20Sopenharmony_ci completed[i] = mbox->completed[i]; 20888c2ecf20Sopenharmony_ci mbox->completed[i] = 0xFF; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci if (completed[i] == 0xFF) { 20918c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_CRIT 20928c2ecf20Sopenharmony_ci "megaraid: command posting timed out\n")); 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci BUG(); 20958c2ecf20Sopenharmony_ci continue; 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci // Get SCB associated with this command id 20998c2ecf20Sopenharmony_ci if (completed[i] >= MBOX_MAX_SCSI_CMDS) { 21008c2ecf20Sopenharmony_ci // a cmm command 21018c2ecf20Sopenharmony_ci scb = adapter->uscb_list + (completed[i] - 21028c2ecf20Sopenharmony_ci MBOX_MAX_SCSI_CMDS); 21038c2ecf20Sopenharmony_ci } 21048c2ecf20Sopenharmony_ci else { 21058c2ecf20Sopenharmony_ci // an os command 21068c2ecf20Sopenharmony_ci scb = adapter->kscb_list + completed[i]; 21078c2ecf20Sopenharmony_ci } 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci scb->status = mbox->status; 21108c2ecf20Sopenharmony_ci list_add_tail(&scb->list, &clist); 21118c2ecf20Sopenharmony_ci } 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci // Acknowledge interrupt 21148c2ecf20Sopenharmony_ci WRINDOOR(raid_dev, 0x02); 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci } while(1); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci // put the completed commands in the completed list. DPC would 21228c2ecf20Sopenharmony_ci // complete these commands later 21238c2ecf20Sopenharmony_ci spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci list_splice(&clist, &adapter->completed_list); 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci // schedule the DPC if there is some work for it 21318c2ecf20Sopenharmony_ci if (handled) 21328c2ecf20Sopenharmony_ci tasklet_schedule(&adapter->dpc_h); 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci return handled; 21358c2ecf20Sopenharmony_ci} 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci/** 21398c2ecf20Sopenharmony_ci * megaraid_isr - isr for memory based mailbox based controllers 21408c2ecf20Sopenharmony_ci * @irq : irq 21418c2ecf20Sopenharmony_ci * @devp : pointer to our soft state 21428c2ecf20Sopenharmony_ci * 21438c2ecf20Sopenharmony_ci * Interrupt service routine for memory-mapped mailbox controllers. 21448c2ecf20Sopenharmony_ci */ 21458c2ecf20Sopenharmony_cistatic irqreturn_t 21468c2ecf20Sopenharmony_cimegaraid_isr(int irq, void *devp) 21478c2ecf20Sopenharmony_ci{ 21488c2ecf20Sopenharmony_ci adapter_t *adapter = devp; 21498c2ecf20Sopenharmony_ci int handled; 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci handled = megaraid_ack_sequence(adapter); 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci /* Loop through any pending requests */ 21548c2ecf20Sopenharmony_ci if (!adapter->quiescent) { 21558c2ecf20Sopenharmony_ci megaraid_mbox_runpendq(adapter, NULL); 21568c2ecf20Sopenharmony_ci } 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 21598c2ecf20Sopenharmony_ci} 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci/** 21638c2ecf20Sopenharmony_ci * megaraid_mbox_dpc - the tasklet to complete the commands from completed list 21648c2ecf20Sopenharmony_ci * @devp : pointer to HBA soft state 21658c2ecf20Sopenharmony_ci * 21668c2ecf20Sopenharmony_ci * Pick up the commands from the completed list and send back to the owners. 21678c2ecf20Sopenharmony_ci * This is a reentrant function and does not assume any locks are held while 21688c2ecf20Sopenharmony_ci * it is being called. 21698c2ecf20Sopenharmony_ci */ 21708c2ecf20Sopenharmony_cistatic void 21718c2ecf20Sopenharmony_cimegaraid_mbox_dpc(unsigned long devp) 21728c2ecf20Sopenharmony_ci{ 21738c2ecf20Sopenharmony_ci adapter_t *adapter = (adapter_t *)devp; 21748c2ecf20Sopenharmony_ci mraid_device_t *raid_dev; 21758c2ecf20Sopenharmony_ci struct list_head clist; 21768c2ecf20Sopenharmony_ci struct scatterlist *sgl; 21778c2ecf20Sopenharmony_ci scb_t *scb; 21788c2ecf20Sopenharmony_ci scb_t *tmp; 21798c2ecf20Sopenharmony_ci struct scsi_cmnd *scp; 21808c2ecf20Sopenharmony_ci mraid_passthru_t *pthru; 21818c2ecf20Sopenharmony_ci mraid_epassthru_t *epthru; 21828c2ecf20Sopenharmony_ci mbox_ccb_t *ccb; 21838c2ecf20Sopenharmony_ci int islogical; 21848c2ecf20Sopenharmony_ci int pdev_index; 21858c2ecf20Sopenharmony_ci int pdev_state; 21868c2ecf20Sopenharmony_ci mbox_t *mbox; 21878c2ecf20Sopenharmony_ci unsigned long flags; 21888c2ecf20Sopenharmony_ci uint8_t c; 21898c2ecf20Sopenharmony_ci int status; 21908c2ecf20Sopenharmony_ci uioc_t *kioc; 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci if (!adapter) return; 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci raid_dev = ADAP2RAIDDEV(adapter); 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci // move the SCBs from the completed list to our local list 21988c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&clist); 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci list_splice_init(&adapter->completed_list, &clist); 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci list_for_each_entry_safe(scb, tmp, &clist, list) { 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci status = scb->status; 22108c2ecf20Sopenharmony_ci scp = scb->scp; 22118c2ecf20Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 22128c2ecf20Sopenharmony_ci pthru = ccb->pthru; 22138c2ecf20Sopenharmony_ci epthru = ccb->epthru; 22148c2ecf20Sopenharmony_ci mbox = ccb->mbox; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci // Make sure f/w has completed a valid command 22178c2ecf20Sopenharmony_ci if (scb->state != SCB_ISSUED) { 22188c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_CRIT 22198c2ecf20Sopenharmony_ci "megaraid critical err: invalid command %d:%d:%p\n", 22208c2ecf20Sopenharmony_ci scb->sno, scb->state, scp)); 22218c2ecf20Sopenharmony_ci BUG(); 22228c2ecf20Sopenharmony_ci continue; // Must never happen! 22238c2ecf20Sopenharmony_ci } 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci // check for the management command and complete it right away 22268c2ecf20Sopenharmony_ci if (scb->sno >= MBOX_MAX_SCSI_CMDS) { 22278c2ecf20Sopenharmony_ci scb->state = SCB_FREE; 22288c2ecf20Sopenharmony_ci scb->status = status; 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci // remove from local clist 22318c2ecf20Sopenharmony_ci list_del_init(&scb->list); 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci kioc = (uioc_t *)scb->gp; 22348c2ecf20Sopenharmony_ci kioc->status = 0; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci megaraid_mbox_mm_done(adapter, scb); 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci continue; 22398c2ecf20Sopenharmony_ci } 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci // Was an abort issued for this command earlier 22428c2ecf20Sopenharmony_ci if (scb->state & SCB_ABORT) { 22438c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 22448c2ecf20Sopenharmony_ci "megaraid: aborted cmd [%x] completed\n", 22458c2ecf20Sopenharmony_ci scb->sno)); 22468c2ecf20Sopenharmony_ci } 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci /* 22498c2ecf20Sopenharmony_ci * If the inquiry came of a disk drive which is not part of 22508c2ecf20Sopenharmony_ci * any RAID array, expose it to the kernel. For this to be 22518c2ecf20Sopenharmony_ci * enabled, user must set the "megaraid_expose_unconf_disks" 22528c2ecf20Sopenharmony_ci * flag to 1 by specifying it on module parameter list. 22538c2ecf20Sopenharmony_ci * This would enable data migration off drives from other 22548c2ecf20Sopenharmony_ci * configurations. 22558c2ecf20Sopenharmony_ci */ 22568c2ecf20Sopenharmony_ci islogical = MRAID_IS_LOGICAL(adapter, scp); 22578c2ecf20Sopenharmony_ci if (scp->cmnd[0] == INQUIRY && status == 0 && islogical == 0 22588c2ecf20Sopenharmony_ci && IS_RAID_CH(raid_dev, scb->dev_channel)) { 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci sgl = scsi_sglist(scp); 22618c2ecf20Sopenharmony_ci if (sg_page(sgl)) { 22628c2ecf20Sopenharmony_ci c = *(unsigned char *) sg_virt(&sgl[0]); 22638c2ecf20Sopenharmony_ci } else { 22648c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 22658c2ecf20Sopenharmony_ci "megaraid mailbox: invalid sg:%d\n", 22668c2ecf20Sopenharmony_ci __LINE__)); 22678c2ecf20Sopenharmony_ci c = 0; 22688c2ecf20Sopenharmony_ci } 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci if ((c & 0x1F ) == TYPE_DISK) { 22718c2ecf20Sopenharmony_ci pdev_index = (scb->dev_channel * 16) + 22728c2ecf20Sopenharmony_ci scb->dev_target; 22738c2ecf20Sopenharmony_ci pdev_state = 22748c2ecf20Sopenharmony_ci raid_dev->pdrv_state[pdev_index] & 0x0F; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci if (pdev_state == PDRV_ONLINE || 22778c2ecf20Sopenharmony_ci pdev_state == PDRV_FAILED || 22788c2ecf20Sopenharmony_ci pdev_state == PDRV_RBLD || 22798c2ecf20Sopenharmony_ci pdev_state == PDRV_HOTSPARE || 22808c2ecf20Sopenharmony_ci megaraid_expose_unconf_disks == 0) { 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci status = 0xF0; 22838c2ecf20Sopenharmony_ci } 22848c2ecf20Sopenharmony_ci } 22858c2ecf20Sopenharmony_ci } 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci // Convert MegaRAID status to Linux error code 22888c2ecf20Sopenharmony_ci switch (status) { 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci case 0x00: 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci scp->result = (DID_OK << 16); 22938c2ecf20Sopenharmony_ci break; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci case 0x02: 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci /* set sense_buffer and result fields */ 22988c2ecf20Sopenharmony_ci if (mbox->cmd == MBOXCMD_PASSTHRU || 22998c2ecf20Sopenharmony_ci mbox->cmd == MBOXCMD_PASSTHRU64) { 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci memcpy(scp->sense_buffer, pthru->reqsensearea, 23028c2ecf20Sopenharmony_ci 14); 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci scp->result = DRIVER_SENSE << 24 | 23058c2ecf20Sopenharmony_ci DID_OK << 16 | CHECK_CONDITION << 1; 23068c2ecf20Sopenharmony_ci } 23078c2ecf20Sopenharmony_ci else { 23088c2ecf20Sopenharmony_ci if (mbox->cmd == MBOXCMD_EXTPTHRU) { 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci memcpy(scp->sense_buffer, 23118c2ecf20Sopenharmony_ci epthru->reqsensearea, 14); 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci scp->result = DRIVER_SENSE << 24 | 23148c2ecf20Sopenharmony_ci DID_OK << 16 | 23158c2ecf20Sopenharmony_ci CHECK_CONDITION << 1; 23168c2ecf20Sopenharmony_ci } else { 23178c2ecf20Sopenharmony_ci scp->sense_buffer[0] = 0x70; 23188c2ecf20Sopenharmony_ci scp->sense_buffer[2] = ABORTED_COMMAND; 23198c2ecf20Sopenharmony_ci scp->result = CHECK_CONDITION << 1; 23208c2ecf20Sopenharmony_ci } 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci break; 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci case 0x08: 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci scp->result = DID_BUS_BUSY << 16 | status; 23278c2ecf20Sopenharmony_ci break; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci default: 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci /* 23328c2ecf20Sopenharmony_ci * If TEST_UNIT_READY fails, we know RESERVATION_STATUS 23338c2ecf20Sopenharmony_ci * failed 23348c2ecf20Sopenharmony_ci */ 23358c2ecf20Sopenharmony_ci if (scp->cmnd[0] == TEST_UNIT_READY) { 23368c2ecf20Sopenharmony_ci scp->result = DID_ERROR << 16 | 23378c2ecf20Sopenharmony_ci RESERVATION_CONFLICT << 1; 23388c2ecf20Sopenharmony_ci } 23398c2ecf20Sopenharmony_ci else 23408c2ecf20Sopenharmony_ci /* 23418c2ecf20Sopenharmony_ci * Error code returned is 1 if Reserve or Release 23428c2ecf20Sopenharmony_ci * failed or the input parameter is invalid 23438c2ecf20Sopenharmony_ci */ 23448c2ecf20Sopenharmony_ci if (status == 1 && (scp->cmnd[0] == RESERVE || 23458c2ecf20Sopenharmony_ci scp->cmnd[0] == RELEASE)) { 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci scp->result = DID_ERROR << 16 | 23488c2ecf20Sopenharmony_ci RESERVATION_CONFLICT << 1; 23498c2ecf20Sopenharmony_ci } 23508c2ecf20Sopenharmony_ci else { 23518c2ecf20Sopenharmony_ci scp->result = DID_BAD_TARGET << 16 | status; 23528c2ecf20Sopenharmony_ci } 23538c2ecf20Sopenharmony_ci } 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci // print a debug message for all failed commands 23568c2ecf20Sopenharmony_ci if (status) { 23578c2ecf20Sopenharmony_ci megaraid_mbox_display_scb(adapter, scb); 23588c2ecf20Sopenharmony_ci } 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci scsi_dma_unmap(scp); 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci // remove from local clist 23638c2ecf20Sopenharmony_ci list_del_init(&scb->list); 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci // put back in free list 23668c2ecf20Sopenharmony_ci megaraid_dealloc_scb(adapter, scb); 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci // send the scsi packet back to kernel 23698c2ecf20Sopenharmony_ci scp->scsi_done(scp); 23708c2ecf20Sopenharmony_ci } 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci return; 23738c2ecf20Sopenharmony_ci} 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci/** 23778c2ecf20Sopenharmony_ci * megaraid_abort_handler - abort the scsi command 23788c2ecf20Sopenharmony_ci * @scp : command to be aborted 23798c2ecf20Sopenharmony_ci * 23808c2ecf20Sopenharmony_ci * Abort a previous SCSI request. Only commands on the pending list can be 23818c2ecf20Sopenharmony_ci * aborted. All the commands issued to the F/W must complete. 23828c2ecf20Sopenharmony_ci **/ 23838c2ecf20Sopenharmony_cistatic int 23848c2ecf20Sopenharmony_cimegaraid_abort_handler(struct scsi_cmnd *scp) 23858c2ecf20Sopenharmony_ci{ 23868c2ecf20Sopenharmony_ci adapter_t *adapter; 23878c2ecf20Sopenharmony_ci mraid_device_t *raid_dev; 23888c2ecf20Sopenharmony_ci scb_t *scb; 23898c2ecf20Sopenharmony_ci scb_t *tmp; 23908c2ecf20Sopenharmony_ci int found; 23918c2ecf20Sopenharmony_ci unsigned long flags; 23928c2ecf20Sopenharmony_ci int i; 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ci adapter = SCP2ADAPTER(scp); 23968c2ecf20Sopenharmony_ci raid_dev = ADAP2RAIDDEV(adapter); 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 23998c2ecf20Sopenharmony_ci "megaraid: aborting cmd=%x <c=%d t=%d l=%d>\n", 24008c2ecf20Sopenharmony_ci scp->cmnd[0], SCP2CHANNEL(scp), 24018c2ecf20Sopenharmony_ci SCP2TARGET(scp), SCP2LUN(scp))); 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci // If FW has stopped responding, simply return failure 24048c2ecf20Sopenharmony_ci if (raid_dev->hw_error) { 24058c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 24068c2ecf20Sopenharmony_ci "megaraid: hw error, not aborting\n")); 24078c2ecf20Sopenharmony_ci return FAILED; 24088c2ecf20Sopenharmony_ci } 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci // There might a race here, where the command was completed by the 24118c2ecf20Sopenharmony_ci // firmware and now it is on the completed list. Before we could 24128c2ecf20Sopenharmony_ci // complete the command to the kernel in dpc, the abort came. 24138c2ecf20Sopenharmony_ci // Find out if this is the case to avoid the race. 24148c2ecf20Sopenharmony_ci scb = NULL; 24158c2ecf20Sopenharmony_ci spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); 24168c2ecf20Sopenharmony_ci list_for_each_entry_safe(scb, tmp, &adapter->completed_list, list) { 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci if (scb->scp == scp) { // Found command 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci list_del_init(&scb->list); // from completed list 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 24238c2ecf20Sopenharmony_ci "megaraid: %d[%d:%d], abort from completed list\n", 24248c2ecf20Sopenharmony_ci scb->sno, scb->dev_channel, scb->dev_target)); 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci scp->result = (DID_ABORT << 16); 24278c2ecf20Sopenharmony_ci scp->scsi_done(scp); 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci megaraid_dealloc_scb(adapter, scb); 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), 24328c2ecf20Sopenharmony_ci flags); 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci return SUCCESS; 24358c2ecf20Sopenharmony_ci } 24368c2ecf20Sopenharmony_ci } 24378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci // Find out if this command is still on the pending list. If it is and 24418c2ecf20Sopenharmony_ci // was never issued, abort and return success. If the command is owned 24428c2ecf20Sopenharmony_ci // by the firmware, we must wait for it to complete by the FW. 24438c2ecf20Sopenharmony_ci spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); 24448c2ecf20Sopenharmony_ci list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) { 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci if (scb->scp == scp) { // Found command 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci list_del_init(&scb->list); // from pending list 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci ASSERT(!(scb->state & SCB_ISSUED)); 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 24538c2ecf20Sopenharmony_ci "megaraid abort: [%d:%d], driver owner\n", 24548c2ecf20Sopenharmony_ci scb->dev_channel, scb->dev_target)); 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci scp->result = (DID_ABORT << 16); 24578c2ecf20Sopenharmony_ci scp->scsi_done(scp); 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci megaraid_dealloc_scb(adapter, scb); 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), 24628c2ecf20Sopenharmony_ci flags); 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci return SUCCESS; 24658c2ecf20Sopenharmony_ci } 24668c2ecf20Sopenharmony_ci } 24678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci // Check do we even own this command, in which case this would be 24718c2ecf20Sopenharmony_ci // owned by the firmware. The only way to locate the FW scb is to 24728c2ecf20Sopenharmony_ci // traverse through the list of all SCB, since driver does not 24738c2ecf20Sopenharmony_ci // maintain these SCBs on any list 24748c2ecf20Sopenharmony_ci found = 0; 24758c2ecf20Sopenharmony_ci spin_lock_irq(&adapter->lock); 24768c2ecf20Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { 24778c2ecf20Sopenharmony_ci scb = adapter->kscb_list + i; 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci if (scb->scp == scp) { 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci found = 1; 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci if (!(scb->state & SCB_ISSUED)) { 24848c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 24858c2ecf20Sopenharmony_ci "megaraid abort: %d[%d:%d], invalid state\n", 24868c2ecf20Sopenharmony_ci scb->sno, scb->dev_channel, scb->dev_target)); 24878c2ecf20Sopenharmony_ci BUG(); 24888c2ecf20Sopenharmony_ci } 24898c2ecf20Sopenharmony_ci else { 24908c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 24918c2ecf20Sopenharmony_ci "megaraid abort: %d[%d:%d], fw owner\n", 24928c2ecf20Sopenharmony_ci scb->sno, scb->dev_channel, scb->dev_target)); 24938c2ecf20Sopenharmony_ci } 24948c2ecf20Sopenharmony_ci } 24958c2ecf20Sopenharmony_ci } 24968c2ecf20Sopenharmony_ci spin_unlock_irq(&adapter->lock); 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci if (!found) { 24998c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING "megaraid abort: do now own\n")); 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci // FIXME: Should there be a callback for this command? 25028c2ecf20Sopenharmony_ci return SUCCESS; 25038c2ecf20Sopenharmony_ci } 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci // We cannot actually abort a command owned by firmware, return 25068c2ecf20Sopenharmony_ci // failure and wait for reset. In host reset handler, we will find out 25078c2ecf20Sopenharmony_ci // if the HBA is still live 25088c2ecf20Sopenharmony_ci return FAILED; 25098c2ecf20Sopenharmony_ci} 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci/** 25128c2ecf20Sopenharmony_ci * megaraid_reset_handler - device reset handler for mailbox based driver 25138c2ecf20Sopenharmony_ci * @scp : reference command 25148c2ecf20Sopenharmony_ci * 25158c2ecf20Sopenharmony_ci * Reset handler for the mailbox based controller. First try to find out if 25168c2ecf20Sopenharmony_ci * the FW is still live, in which case the outstanding commands counter mut go 25178c2ecf20Sopenharmony_ci * down to 0. If that happens, also issue the reservation reset command to 25188c2ecf20Sopenharmony_ci * relinquish (possible) reservations on the logical drives connected to this 25198c2ecf20Sopenharmony_ci * host. 25208c2ecf20Sopenharmony_ci **/ 25218c2ecf20Sopenharmony_cistatic int 25228c2ecf20Sopenharmony_cimegaraid_reset_handler(struct scsi_cmnd *scp) 25238c2ecf20Sopenharmony_ci{ 25248c2ecf20Sopenharmony_ci adapter_t *adapter; 25258c2ecf20Sopenharmony_ci scb_t *scb; 25268c2ecf20Sopenharmony_ci scb_t *tmp; 25278c2ecf20Sopenharmony_ci mraid_device_t *raid_dev; 25288c2ecf20Sopenharmony_ci unsigned long flags; 25298c2ecf20Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 25308c2ecf20Sopenharmony_ci int rval; 25318c2ecf20Sopenharmony_ci int recovery_window; 25328c2ecf20Sopenharmony_ci int i; 25338c2ecf20Sopenharmony_ci uioc_t *kioc; 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci adapter = SCP2ADAPTER(scp); 25368c2ecf20Sopenharmony_ci raid_dev = ADAP2RAIDDEV(adapter); 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci // return failure if adapter is not responding 25398c2ecf20Sopenharmony_ci if (raid_dev->hw_error) { 25408c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 25418c2ecf20Sopenharmony_ci "megaraid: hw error, cannot reset\n")); 25428c2ecf20Sopenharmony_ci return FAILED; 25438c2ecf20Sopenharmony_ci } 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_ci // Under exceptional conditions, FW can take up to 3 minutes to 25468c2ecf20Sopenharmony_ci // complete command processing. Wait for additional 2 minutes for the 25478c2ecf20Sopenharmony_ci // pending commands counter to go down to 0. If it doesn't, let the 25488c2ecf20Sopenharmony_ci // controller be marked offline 25498c2ecf20Sopenharmony_ci // Also, reset all the commands currently owned by the driver 25508c2ecf20Sopenharmony_ci spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); 25518c2ecf20Sopenharmony_ci list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) { 25528c2ecf20Sopenharmony_ci list_del_init(&scb->list); // from pending list 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci if (scb->sno >= MBOX_MAX_SCSI_CMDS) { 25558c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 25568c2ecf20Sopenharmony_ci "megaraid: IOCTL packet with %d[%d:%d] being reset\n", 25578c2ecf20Sopenharmony_ci scb->sno, scb->dev_channel, scb->dev_target)); 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci scb->status = -1; 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci kioc = (uioc_t *)scb->gp; 25628c2ecf20Sopenharmony_ci kioc->status = -EFAULT; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci megaraid_mbox_mm_done(adapter, scb); 25658c2ecf20Sopenharmony_ci } else { 25668c2ecf20Sopenharmony_ci if (scb->scp == scp) { // Found command 25678c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 25688c2ecf20Sopenharmony_ci "megaraid: %d[%d:%d], reset from pending list\n", 25698c2ecf20Sopenharmony_ci scb->sno, scb->dev_channel, scb->dev_target)); 25708c2ecf20Sopenharmony_ci } else { 25718c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 25728c2ecf20Sopenharmony_ci "megaraid: IO packet with %d[%d:%d] being reset\n", 25738c2ecf20Sopenharmony_ci scb->sno, scb->dev_channel, scb->dev_target)); 25748c2ecf20Sopenharmony_ci } 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci scb->scp->result = (DID_RESET << 16); 25778c2ecf20Sopenharmony_ci scb->scp->scsi_done(scb->scp); 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci megaraid_dealloc_scb(adapter, scb); 25808c2ecf20Sopenharmony_ci } 25818c2ecf20Sopenharmony_ci } 25828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci if (adapter->outstanding_cmds) { 25858c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 25868c2ecf20Sopenharmony_ci "megaraid: %d outstanding commands. Max wait %d sec\n", 25878c2ecf20Sopenharmony_ci adapter->outstanding_cmds, 25888c2ecf20Sopenharmony_ci (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT))); 25898c2ecf20Sopenharmony_ci } 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci for (i = 0; i < recovery_window; i++) { 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci megaraid_ack_sequence(adapter); 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci // print a message once every 5 seconds only 25988c2ecf20Sopenharmony_ci if (!(i % 5)) { 25998c2ecf20Sopenharmony_ci con_log(CL_ANN, ( 26008c2ecf20Sopenharmony_ci "megaraid mbox: Wait for %d commands to complete:%d\n", 26018c2ecf20Sopenharmony_ci adapter->outstanding_cmds, 26028c2ecf20Sopenharmony_ci (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT) - i)); 26038c2ecf20Sopenharmony_ci } 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci // bailout if no recovery happened in reset time 26068c2ecf20Sopenharmony_ci if (adapter->outstanding_cmds == 0) { 26078c2ecf20Sopenharmony_ci break; 26088c2ecf20Sopenharmony_ci } 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci msleep(1000); 26118c2ecf20Sopenharmony_ci } 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci spin_lock(&adapter->lock); 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci // If still outstanding commands, bail out 26168c2ecf20Sopenharmony_ci if (adapter->outstanding_cmds) { 26178c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 26188c2ecf20Sopenharmony_ci "megaraid mbox: critical hardware error!\n")); 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci raid_dev->hw_error = 1; 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci rval = FAILED; 26238c2ecf20Sopenharmony_ci goto out; 26248c2ecf20Sopenharmony_ci } 26258c2ecf20Sopenharmony_ci else { 26268c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 26278c2ecf20Sopenharmony_ci "megaraid mbox: reset sequence completed successfully\n")); 26288c2ecf20Sopenharmony_ci } 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci // If the controller supports clustering, reset reservations 26328c2ecf20Sopenharmony_ci if (!adapter->ha) { 26338c2ecf20Sopenharmony_ci rval = SUCCESS; 26348c2ecf20Sopenharmony_ci goto out; 26358c2ecf20Sopenharmony_ci } 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci // clear reservations if any 26388c2ecf20Sopenharmony_ci raw_mbox[0] = CLUSTER_CMD; 26398c2ecf20Sopenharmony_ci raw_mbox[2] = RESET_RESERVATIONS; 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_ci rval = SUCCESS; 26428c2ecf20Sopenharmony_ci if (mbox_post_sync_cmd_fast(adapter, raw_mbox) == 0) { 26438c2ecf20Sopenharmony_ci con_log(CL_ANN, 26448c2ecf20Sopenharmony_ci (KERN_INFO "megaraid: reservation reset\n")); 26458c2ecf20Sopenharmony_ci } 26468c2ecf20Sopenharmony_ci else { 26478c2ecf20Sopenharmony_ci rval = FAILED; 26488c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 26498c2ecf20Sopenharmony_ci "megaraid: reservation reset failed\n")); 26508c2ecf20Sopenharmony_ci } 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci out: 26538c2ecf20Sopenharmony_ci spin_unlock(&adapter->lock); 26548c2ecf20Sopenharmony_ci return rval; 26558c2ecf20Sopenharmony_ci} 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci/* 26588c2ecf20Sopenharmony_ci * START: internal commands library 26598c2ecf20Sopenharmony_ci * 26608c2ecf20Sopenharmony_ci * This section of the driver has the common routine used by the driver and 26618c2ecf20Sopenharmony_ci * also has all the FW routines 26628c2ecf20Sopenharmony_ci */ 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci/** 26658c2ecf20Sopenharmony_ci * mbox_post_sync_cmd() - blocking command to the mailbox based controllers 26668c2ecf20Sopenharmony_ci * @adapter : controller's soft state 26678c2ecf20Sopenharmony_ci * @raw_mbox : the mailbox 26688c2ecf20Sopenharmony_ci * 26698c2ecf20Sopenharmony_ci * Issue a scb in synchronous and non-interrupt mode for mailbox based 26708c2ecf20Sopenharmony_ci * controllers. 26718c2ecf20Sopenharmony_ci */ 26728c2ecf20Sopenharmony_cistatic int 26738c2ecf20Sopenharmony_cimbox_post_sync_cmd(adapter_t *adapter, uint8_t raw_mbox[]) 26748c2ecf20Sopenharmony_ci{ 26758c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 26768c2ecf20Sopenharmony_ci mbox_t *mbox; 26778c2ecf20Sopenharmony_ci uint8_t status; 26788c2ecf20Sopenharmony_ci int i; 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci mbox = raid_dev->mbox; 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci /* 26838c2ecf20Sopenharmony_ci * Wait until mailbox is free 26848c2ecf20Sopenharmony_ci */ 26858c2ecf20Sopenharmony_ci if (megaraid_busywait_mbox(raid_dev) != 0) 26868c2ecf20Sopenharmony_ci goto blocked_mailbox; 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci /* 26898c2ecf20Sopenharmony_ci * Copy mailbox data into host structure 26908c2ecf20Sopenharmony_ci */ 26918c2ecf20Sopenharmony_ci memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16); 26928c2ecf20Sopenharmony_ci mbox->cmdid = 0xFE; 26938c2ecf20Sopenharmony_ci mbox->busy = 1; 26948c2ecf20Sopenharmony_ci mbox->poll = 0; 26958c2ecf20Sopenharmony_ci mbox->ack = 0; 26968c2ecf20Sopenharmony_ci mbox->numstatus = 0xFF; 26978c2ecf20Sopenharmony_ci mbox->status = 0xFF; 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci wmb(); 27008c2ecf20Sopenharmony_ci WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci // wait for maximum 1 second for status to post. If the status is not 27038c2ecf20Sopenharmony_ci // available within 1 second, assume FW is initializing and wait 27048c2ecf20Sopenharmony_ci // for an extended amount of time 27058c2ecf20Sopenharmony_ci if (mbox->numstatus == 0xFF) { // status not yet available 27068c2ecf20Sopenharmony_ci udelay(25); 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci for (i = 0; mbox->numstatus == 0xFF && i < 1000; i++) { 27098c2ecf20Sopenharmony_ci rmb(); 27108c2ecf20Sopenharmony_ci msleep(1); 27118c2ecf20Sopenharmony_ci } 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci if (i == 1000) { 27158c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 27168c2ecf20Sopenharmony_ci "megaraid mailbox: wait for FW to boot ")); 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci for (i = 0; (mbox->numstatus == 0xFF) && 27198c2ecf20Sopenharmony_ci (i < MBOX_RESET_WAIT); i++) { 27208c2ecf20Sopenharmony_ci rmb(); 27218c2ecf20Sopenharmony_ci con_log(CL_ANN, ("\b\b\b\b\b[%03d]", 27228c2ecf20Sopenharmony_ci MBOX_RESET_WAIT - i)); 27238c2ecf20Sopenharmony_ci msleep(1000); 27248c2ecf20Sopenharmony_ci } 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci if (i == MBOX_RESET_WAIT) { 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_ci con_log(CL_ANN, ( 27298c2ecf20Sopenharmony_ci "\nmegaraid mailbox: status not available\n")); 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci return -1; 27328c2ecf20Sopenharmony_ci } 27338c2ecf20Sopenharmony_ci con_log(CL_ANN, ("\b\b\b\b\b[ok] \n")); 27348c2ecf20Sopenharmony_ci } 27358c2ecf20Sopenharmony_ci } 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci // wait for maximum 1 second for poll semaphore 27388c2ecf20Sopenharmony_ci if (mbox->poll != 0x77) { 27398c2ecf20Sopenharmony_ci udelay(25); 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci for (i = 0; (mbox->poll != 0x77) && (i < 1000); i++) { 27428c2ecf20Sopenharmony_ci rmb(); 27438c2ecf20Sopenharmony_ci msleep(1); 27448c2ecf20Sopenharmony_ci } 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci if (i == 1000) { 27478c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 27488c2ecf20Sopenharmony_ci "megaraid mailbox: could not get poll semaphore\n")); 27498c2ecf20Sopenharmony_ci return -1; 27508c2ecf20Sopenharmony_ci } 27518c2ecf20Sopenharmony_ci } 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2); 27548c2ecf20Sopenharmony_ci wmb(); 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci // wait for maximum 1 second for acknowledgement 27578c2ecf20Sopenharmony_ci if (RDINDOOR(raid_dev) & 0x2) { 27588c2ecf20Sopenharmony_ci udelay(25); 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci for (i = 0; (RDINDOOR(raid_dev) & 0x2) && (i < 1000); i++) { 27618c2ecf20Sopenharmony_ci rmb(); 27628c2ecf20Sopenharmony_ci msleep(1); 27638c2ecf20Sopenharmony_ci } 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_ci if (i == 1000) { 27668c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 27678c2ecf20Sopenharmony_ci "megaraid mailbox: could not acknowledge\n")); 27688c2ecf20Sopenharmony_ci return -1; 27698c2ecf20Sopenharmony_ci } 27708c2ecf20Sopenharmony_ci } 27718c2ecf20Sopenharmony_ci mbox->poll = 0; 27728c2ecf20Sopenharmony_ci mbox->ack = 0x77; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci status = mbox->status; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci // invalidate the completed command id array. After command 27778c2ecf20Sopenharmony_ci // completion, firmware would write the valid id. 27788c2ecf20Sopenharmony_ci mbox->numstatus = 0xFF; 27798c2ecf20Sopenharmony_ci mbox->status = 0xFF; 27808c2ecf20Sopenharmony_ci for (i = 0; i < MBOX_MAX_FIRMWARE_STATUS; i++) { 27818c2ecf20Sopenharmony_ci mbox->completed[i] = 0xFF; 27828c2ecf20Sopenharmony_ci } 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci return status; 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ciblocked_mailbox: 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n") ); 27898c2ecf20Sopenharmony_ci return -1; 27908c2ecf20Sopenharmony_ci} 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci/** 27948c2ecf20Sopenharmony_ci * mbox_post_sync_cmd_fast - blocking command to the mailbox based controllers 27958c2ecf20Sopenharmony_ci * @adapter : controller's soft state 27968c2ecf20Sopenharmony_ci * @raw_mbox : the mailbox 27978c2ecf20Sopenharmony_ci * 27988c2ecf20Sopenharmony_ci * Issue a scb in synchronous and non-interrupt mode for mailbox based 27998c2ecf20Sopenharmony_ci * controllers. This is a faster version of the synchronous command and 28008c2ecf20Sopenharmony_ci * therefore can be called in interrupt-context as well. 28018c2ecf20Sopenharmony_ci */ 28028c2ecf20Sopenharmony_cistatic int 28038c2ecf20Sopenharmony_cimbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[]) 28048c2ecf20Sopenharmony_ci{ 28058c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 28068c2ecf20Sopenharmony_ci mbox_t *mbox; 28078c2ecf20Sopenharmony_ci long i; 28088c2ecf20Sopenharmony_ci 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci mbox = raid_dev->mbox; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci // return immediately if the mailbox is busy 28138c2ecf20Sopenharmony_ci if (mbox->busy) return -1; 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_ci // Copy mailbox data into host structure 28168c2ecf20Sopenharmony_ci memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 14); 28178c2ecf20Sopenharmony_ci mbox->cmdid = 0xFE; 28188c2ecf20Sopenharmony_ci mbox->busy = 1; 28198c2ecf20Sopenharmony_ci mbox->poll = 0; 28208c2ecf20Sopenharmony_ci mbox->ack = 0; 28218c2ecf20Sopenharmony_ci mbox->numstatus = 0xFF; 28228c2ecf20Sopenharmony_ci mbox->status = 0xFF; 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_ci wmb(); 28258c2ecf20Sopenharmony_ci WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci for (i = 0; i < MBOX_SYNC_WAIT_CNT; i++) { 28288c2ecf20Sopenharmony_ci if (mbox->numstatus != 0xFF) break; 28298c2ecf20Sopenharmony_ci rmb(); 28308c2ecf20Sopenharmony_ci udelay(MBOX_SYNC_DELAY_200); 28318c2ecf20Sopenharmony_ci } 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci if (i == MBOX_SYNC_WAIT_CNT) { 28348c2ecf20Sopenharmony_ci // We may need to re-calibrate the counter 28358c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_CRIT 28368c2ecf20Sopenharmony_ci "megaraid: fast sync command timed out\n")); 28378c2ecf20Sopenharmony_ci } 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2); 28408c2ecf20Sopenharmony_ci wmb(); 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci return mbox->status; 28438c2ecf20Sopenharmony_ci} 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci/** 28478c2ecf20Sopenharmony_ci * megaraid_busywait_mbox() - Wait until the controller's mailbox is available 28488c2ecf20Sopenharmony_ci * @raid_dev : RAID device (HBA) soft state 28498c2ecf20Sopenharmony_ci * 28508c2ecf20Sopenharmony_ci * Wait until the controller's mailbox is available to accept more commands. 28518c2ecf20Sopenharmony_ci * Wait for at most 1 second. 28528c2ecf20Sopenharmony_ci */ 28538c2ecf20Sopenharmony_cistatic int 28548c2ecf20Sopenharmony_cimegaraid_busywait_mbox(mraid_device_t *raid_dev) 28558c2ecf20Sopenharmony_ci{ 28568c2ecf20Sopenharmony_ci mbox_t *mbox = raid_dev->mbox; 28578c2ecf20Sopenharmony_ci int i = 0; 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci if (mbox->busy) { 28608c2ecf20Sopenharmony_ci udelay(25); 28618c2ecf20Sopenharmony_ci for (i = 0; mbox->busy && i < 1000; i++) 28628c2ecf20Sopenharmony_ci msleep(1); 28638c2ecf20Sopenharmony_ci } 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci if (i < 1000) return 0; 28668c2ecf20Sopenharmony_ci else return -1; 28678c2ecf20Sopenharmony_ci} 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci/** 28718c2ecf20Sopenharmony_ci * megaraid_mbox_product_info - some static information about the controller 28728c2ecf20Sopenharmony_ci * @adapter : our soft state 28738c2ecf20Sopenharmony_ci * 28748c2ecf20Sopenharmony_ci * Issue commands to the controller to grab some parameters required by our 28758c2ecf20Sopenharmony_ci * caller. 28768c2ecf20Sopenharmony_ci */ 28778c2ecf20Sopenharmony_cistatic int 28788c2ecf20Sopenharmony_cimegaraid_mbox_product_info(adapter_t *adapter) 28798c2ecf20Sopenharmony_ci{ 28808c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 28818c2ecf20Sopenharmony_ci mbox_t *mbox; 28828c2ecf20Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 28838c2ecf20Sopenharmony_ci mraid_pinfo_t *pinfo; 28848c2ecf20Sopenharmony_ci dma_addr_t pinfo_dma_h; 28858c2ecf20Sopenharmony_ci mraid_inquiry3_t *mraid_inq3; 28868c2ecf20Sopenharmony_ci int i; 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); 28908c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci /* 28938c2ecf20Sopenharmony_ci * Issue an ENQUIRY3 command to find out certain adapter parameters, 28948c2ecf20Sopenharmony_ci * e.g., max channels, max commands etc. 28958c2ecf20Sopenharmony_ci */ 28968c2ecf20Sopenharmony_ci pinfo = dma_alloc_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), 28978c2ecf20Sopenharmony_ci &pinfo_dma_h, GFP_KERNEL); 28988c2ecf20Sopenharmony_ci if (pinfo == NULL) { 28998c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 29008c2ecf20Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 29018c2ecf20Sopenharmony_ci __LINE__)); 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_ci return -1; 29048c2ecf20Sopenharmony_ci } 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_ci mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; 29078c2ecf20Sopenharmony_ci memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_ci raw_mbox[0] = FC_NEW_CONFIG; 29108c2ecf20Sopenharmony_ci raw_mbox[2] = NC_SUBOP_ENQUIRY3; 29118c2ecf20Sopenharmony_ci raw_mbox[3] = ENQ3_GET_SOLICITED_FULL; 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci // Issue the command 29148c2ecf20Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { 29158c2ecf20Sopenharmony_ci 29168c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING "megaraid: Inquiry3 failed\n")); 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), 29198c2ecf20Sopenharmony_ci pinfo, pinfo_dma_h); 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci return -1; 29228c2ecf20Sopenharmony_ci } 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_ci /* 29258c2ecf20Sopenharmony_ci * Collect information about state of each physical drive 29268c2ecf20Sopenharmony_ci * attached to the controller. We will expose all the disks 29278c2ecf20Sopenharmony_ci * which are not part of RAID 29288c2ecf20Sopenharmony_ci */ 29298c2ecf20Sopenharmony_ci mraid_inq3 = (mraid_inquiry3_t *)adapter->ibuf; 29308c2ecf20Sopenharmony_ci for (i = 0; i < MBOX_MAX_PHYSICAL_DRIVES; i++) { 29318c2ecf20Sopenharmony_ci raid_dev->pdrv_state[i] = mraid_inq3->pdrv_state[i]; 29328c2ecf20Sopenharmony_ci } 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci /* 29358c2ecf20Sopenharmony_ci * Get product info for information like number of channels, 29368c2ecf20Sopenharmony_ci * maximum commands supported. 29378c2ecf20Sopenharmony_ci */ 29388c2ecf20Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); 29398c2ecf20Sopenharmony_ci mbox->xferaddr = (uint32_t)pinfo_dma_h; 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_ci raw_mbox[0] = FC_NEW_CONFIG; 29428c2ecf20Sopenharmony_ci raw_mbox[2] = NC_SUBOP_PRODUCT_INFO; 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 29478c2ecf20Sopenharmony_ci "megaraid: product info failed\n")); 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), 29508c2ecf20Sopenharmony_ci pinfo, pinfo_dma_h); 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci return -1; 29538c2ecf20Sopenharmony_ci } 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ci /* 29568c2ecf20Sopenharmony_ci * Setup some parameters for host, as required by our caller 29578c2ecf20Sopenharmony_ci */ 29588c2ecf20Sopenharmony_ci adapter->max_channel = pinfo->nchannels; 29598c2ecf20Sopenharmony_ci 29608c2ecf20Sopenharmony_ci /* 29618c2ecf20Sopenharmony_ci * we will export all the logical drives on a single channel. 29628c2ecf20Sopenharmony_ci * Add 1 since inquires do not come for inititor ID 29638c2ecf20Sopenharmony_ci */ 29648c2ecf20Sopenharmony_ci adapter->max_target = MAX_LOGICAL_DRIVES_40LD + 1; 29658c2ecf20Sopenharmony_ci adapter->max_lun = 8; // up to 8 LUNs for non-disk devices 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci /* 29688c2ecf20Sopenharmony_ci * These are the maximum outstanding commands for the scsi-layer 29698c2ecf20Sopenharmony_ci */ 29708c2ecf20Sopenharmony_ci adapter->max_cmds = MBOX_MAX_SCSI_CMDS; 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci memset(adapter->fw_version, 0, VERSION_SIZE); 29738c2ecf20Sopenharmony_ci memset(adapter->bios_version, 0, VERSION_SIZE); 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci memcpy(adapter->fw_version, pinfo->fw_version, 4); 29768c2ecf20Sopenharmony_ci adapter->fw_version[4] = 0; 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci memcpy(adapter->bios_version, pinfo->bios_version, 4); 29798c2ecf20Sopenharmony_ci adapter->bios_version[4] = 0; 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 29828c2ecf20Sopenharmony_ci "megaraid: fw version:[%s] bios version:[%s]\n", 29838c2ecf20Sopenharmony_ci adapter->fw_version, adapter->bios_version)); 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), pinfo, 29868c2ecf20Sopenharmony_ci pinfo_dma_h); 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci return 0; 29898c2ecf20Sopenharmony_ci} 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci/** 29948c2ecf20Sopenharmony_ci * megaraid_mbox_extended_cdb - check for support for extended CDBs 29958c2ecf20Sopenharmony_ci * @adapter : soft state for the controller 29968c2ecf20Sopenharmony_ci * 29978c2ecf20Sopenharmony_ci * This routine check whether the controller in question supports extended 29988c2ecf20Sopenharmony_ci * ( > 10 bytes ) CDBs. 29998c2ecf20Sopenharmony_ci */ 30008c2ecf20Sopenharmony_cistatic int 30018c2ecf20Sopenharmony_cimegaraid_mbox_extended_cdb(adapter_t *adapter) 30028c2ecf20Sopenharmony_ci{ 30038c2ecf20Sopenharmony_ci mbox_t *mbox; 30048c2ecf20Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 30058c2ecf20Sopenharmony_ci int rval; 30068c2ecf20Sopenharmony_ci 30078c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); 30108c2ecf20Sopenharmony_ci mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci raw_mbox[0] = MAIN_MISC_OPCODE; 30158c2ecf20Sopenharmony_ci raw_mbox[2] = SUPPORT_EXT_CDB; 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci /* 30188c2ecf20Sopenharmony_ci * Issue the command 30198c2ecf20Sopenharmony_ci */ 30208c2ecf20Sopenharmony_ci rval = 0; 30218c2ecf20Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { 30228c2ecf20Sopenharmony_ci rval = -1; 30238c2ecf20Sopenharmony_ci } 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci return rval; 30268c2ecf20Sopenharmony_ci} 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci/** 30308c2ecf20Sopenharmony_ci * megaraid_mbox_support_ha - Do we support clustering 30318c2ecf20Sopenharmony_ci * @adapter : soft state for the controller 30328c2ecf20Sopenharmony_ci * @init_id : ID of the initiator 30338c2ecf20Sopenharmony_ci * 30348c2ecf20Sopenharmony_ci * Determine if the firmware supports clustering and the ID of the initiator. 30358c2ecf20Sopenharmony_ci */ 30368c2ecf20Sopenharmony_cistatic int 30378c2ecf20Sopenharmony_cimegaraid_mbox_support_ha(adapter_t *adapter, uint16_t *init_id) 30388c2ecf20Sopenharmony_ci{ 30398c2ecf20Sopenharmony_ci mbox_t *mbox; 30408c2ecf20Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 30418c2ecf20Sopenharmony_ci int rval; 30428c2ecf20Sopenharmony_ci 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_ci raw_mbox[0] = GET_TARGET_ID; 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci // Issue the command 30558c2ecf20Sopenharmony_ci *init_id = 7; 30568c2ecf20Sopenharmony_ci rval = -1; 30578c2ecf20Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci *init_id = *(uint8_t *)adapter->ibuf; 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_INFO 30628c2ecf20Sopenharmony_ci "megaraid: cluster firmware, initiator ID: %d\n", 30638c2ecf20Sopenharmony_ci *init_id)); 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci rval = 0; 30668c2ecf20Sopenharmony_ci } 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci return rval; 30698c2ecf20Sopenharmony_ci} 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci/** 30738c2ecf20Sopenharmony_ci * megaraid_mbox_support_random_del - Do we support random deletion 30748c2ecf20Sopenharmony_ci * @adapter : soft state for the controller 30758c2ecf20Sopenharmony_ci * 30768c2ecf20Sopenharmony_ci * Determine if the firmware supports random deletion. 30778c2ecf20Sopenharmony_ci * Return: 1 is operation supported, 0 otherwise 30788c2ecf20Sopenharmony_ci */ 30798c2ecf20Sopenharmony_cistatic int 30808c2ecf20Sopenharmony_cimegaraid_mbox_support_random_del(adapter_t *adapter) 30818c2ecf20Sopenharmony_ci{ 30828c2ecf20Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 30838c2ecf20Sopenharmony_ci int rval; 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci /* 30868c2ecf20Sopenharmony_ci * Newer firmware on Dell CERC expect a different 30878c2ecf20Sopenharmony_ci * random deletion handling, so disable it. 30888c2ecf20Sopenharmony_ci */ 30898c2ecf20Sopenharmony_ci if (adapter->pdev->vendor == PCI_VENDOR_ID_AMI && 30908c2ecf20Sopenharmony_ci adapter->pdev->device == PCI_DEVICE_ID_AMI_MEGARAID3 && 30918c2ecf20Sopenharmony_ci adapter->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL && 30928c2ecf20Sopenharmony_ci adapter->pdev->subsystem_device == PCI_SUBSYS_ID_CERC_ATA100_4CH && 30938c2ecf20Sopenharmony_ci (adapter->fw_version[0] > '6' || 30948c2ecf20Sopenharmony_ci (adapter->fw_version[0] == '6' && 30958c2ecf20Sopenharmony_ci adapter->fw_version[2] > '6') || 30968c2ecf20Sopenharmony_ci (adapter->fw_version[0] == '6' 30978c2ecf20Sopenharmony_ci && adapter->fw_version[2] == '6' 30988c2ecf20Sopenharmony_ci && adapter->fw_version[3] > '1'))) { 30998c2ecf20Sopenharmony_ci con_log(CL_DLEVEL1, ("megaraid: disable random deletion\n")); 31008c2ecf20Sopenharmony_ci return 0; 31018c2ecf20Sopenharmony_ci } 31028c2ecf20Sopenharmony_ci 31038c2ecf20Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci raw_mbox[0] = FC_DEL_LOGDRV; 31068c2ecf20Sopenharmony_ci raw_mbox[2] = OP_SUP_DEL_LOGDRV; 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_ci // Issue the command 31098c2ecf20Sopenharmony_ci rval = 0; 31108c2ecf20Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci con_log(CL_DLEVEL1, ("megaraid: supports random deletion\n")); 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci rval = 1; 31158c2ecf20Sopenharmony_ci } 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_ci return rval; 31188c2ecf20Sopenharmony_ci} 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci/** 31228c2ecf20Sopenharmony_ci * megaraid_mbox_get_max_sg - maximum sg elements supported by the firmware 31238c2ecf20Sopenharmony_ci * @adapter : soft state for the controller 31248c2ecf20Sopenharmony_ci * 31258c2ecf20Sopenharmony_ci * Find out the maximum number of scatter-gather elements supported by the 31268c2ecf20Sopenharmony_ci * firmware. 31278c2ecf20Sopenharmony_ci */ 31288c2ecf20Sopenharmony_cistatic int 31298c2ecf20Sopenharmony_cimegaraid_mbox_get_max_sg(adapter_t *adapter) 31308c2ecf20Sopenharmony_ci{ 31318c2ecf20Sopenharmony_ci mbox_t *mbox; 31328c2ecf20Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 31338c2ecf20Sopenharmony_ci int nsg; 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_ci raw_mbox[0] = MAIN_MISC_OPCODE; 31458c2ecf20Sopenharmony_ci raw_mbox[2] = GET_MAX_SG_SUPPORT; 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci // Issue the command 31488c2ecf20Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { 31498c2ecf20Sopenharmony_ci nsg = *(uint8_t *)adapter->ibuf; 31508c2ecf20Sopenharmony_ci } 31518c2ecf20Sopenharmony_ci else { 31528c2ecf20Sopenharmony_ci nsg = MBOX_DEFAULT_SG_SIZE; 31538c2ecf20Sopenharmony_ci } 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_ci if (nsg > MBOX_MAX_SG_SIZE) nsg = MBOX_MAX_SG_SIZE; 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci return nsg; 31588c2ecf20Sopenharmony_ci} 31598c2ecf20Sopenharmony_ci 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_ci/** 31628c2ecf20Sopenharmony_ci * megaraid_mbox_enum_raid_scsi - enumerate the RAID and SCSI channels 31638c2ecf20Sopenharmony_ci * @adapter : soft state for the controller 31648c2ecf20Sopenharmony_ci * 31658c2ecf20Sopenharmony_ci * Enumerate the RAID and SCSI channels for ROMB platforms so that channels 31668c2ecf20Sopenharmony_ci * can be exported as regular SCSI channels. 31678c2ecf20Sopenharmony_ci */ 31688c2ecf20Sopenharmony_cistatic void 31698c2ecf20Sopenharmony_cimegaraid_mbox_enum_raid_scsi(adapter_t *adapter) 31708c2ecf20Sopenharmony_ci{ 31718c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 31728c2ecf20Sopenharmony_ci mbox_t *mbox; 31738c2ecf20Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 31748c2ecf20Sopenharmony_ci 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; 31818c2ecf20Sopenharmony_ci 31828c2ecf20Sopenharmony_ci memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); 31838c2ecf20Sopenharmony_ci 31848c2ecf20Sopenharmony_ci raw_mbox[0] = CHNL_CLASS; 31858c2ecf20Sopenharmony_ci raw_mbox[2] = GET_CHNL_CLASS; 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ci // Issue the command. If the command fails, all channels are RAID 31888c2ecf20Sopenharmony_ci // channels 31898c2ecf20Sopenharmony_ci raid_dev->channel_class = 0xFF; 31908c2ecf20Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { 31918c2ecf20Sopenharmony_ci raid_dev->channel_class = *(uint8_t *)adapter->ibuf; 31928c2ecf20Sopenharmony_ci } 31938c2ecf20Sopenharmony_ci 31948c2ecf20Sopenharmony_ci return; 31958c2ecf20Sopenharmony_ci} 31968c2ecf20Sopenharmony_ci 31978c2ecf20Sopenharmony_ci 31988c2ecf20Sopenharmony_ci/** 31998c2ecf20Sopenharmony_ci * megaraid_mbox_flush_cache - flush adapter and disks cache 32008c2ecf20Sopenharmony_ci * @adapter : soft state for the controller 32018c2ecf20Sopenharmony_ci * 32028c2ecf20Sopenharmony_ci * Flush adapter cache followed by disks cache. 32038c2ecf20Sopenharmony_ci */ 32048c2ecf20Sopenharmony_cistatic void 32058c2ecf20Sopenharmony_cimegaraid_mbox_flush_cache(adapter_t *adapter) 32068c2ecf20Sopenharmony_ci{ 32078c2ecf20Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci raw_mbox[0] = FLUSH_ADAPTER; 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { 32148c2ecf20Sopenharmony_ci con_log(CL_ANN, ("megaraid: flush adapter failed\n")); 32158c2ecf20Sopenharmony_ci } 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci raw_mbox[0] = FLUSH_SYSTEM; 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { 32208c2ecf20Sopenharmony_ci con_log(CL_ANN, ("megaraid: flush disks cache failed\n")); 32218c2ecf20Sopenharmony_ci } 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci return; 32248c2ecf20Sopenharmony_ci} 32258c2ecf20Sopenharmony_ci 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci/** 32288c2ecf20Sopenharmony_ci * megaraid_mbox_fire_sync_cmd - fire the sync cmd 32298c2ecf20Sopenharmony_ci * @adapter : soft state for the controller 32308c2ecf20Sopenharmony_ci * 32318c2ecf20Sopenharmony_ci * Clears the pending cmds in FW and reinits its RAID structs. 32328c2ecf20Sopenharmony_ci */ 32338c2ecf20Sopenharmony_cistatic int 32348c2ecf20Sopenharmony_cimegaraid_mbox_fire_sync_cmd(adapter_t *adapter) 32358c2ecf20Sopenharmony_ci{ 32368c2ecf20Sopenharmony_ci mbox_t *mbox; 32378c2ecf20Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 32388c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 32398c2ecf20Sopenharmony_ci int status = 0; 32408c2ecf20Sopenharmony_ci int i; 32418c2ecf20Sopenharmony_ci uint32_t dword; 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci raw_mbox[0] = 0xFF; 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci mbox = raid_dev->mbox; 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci /* Wait until mailbox is free */ 32528c2ecf20Sopenharmony_ci if (megaraid_busywait_mbox(raid_dev) != 0) { 32538c2ecf20Sopenharmony_ci status = 1; 32548c2ecf20Sopenharmony_ci goto blocked_mailbox; 32558c2ecf20Sopenharmony_ci } 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci /* Copy mailbox data into host structure */ 32588c2ecf20Sopenharmony_ci memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16); 32598c2ecf20Sopenharmony_ci mbox->cmdid = 0xFE; 32608c2ecf20Sopenharmony_ci mbox->busy = 1; 32618c2ecf20Sopenharmony_ci mbox->poll = 0; 32628c2ecf20Sopenharmony_ci mbox->ack = 0; 32638c2ecf20Sopenharmony_ci mbox->numstatus = 0; 32648c2ecf20Sopenharmony_ci mbox->status = 0; 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci wmb(); 32678c2ecf20Sopenharmony_ci WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci /* Wait for maximum 1 min for status to post. 32708c2ecf20Sopenharmony_ci * If the Firmware SUPPORTS the ABOVE COMMAND, 32718c2ecf20Sopenharmony_ci * mbox->cmd will be set to 0 32728c2ecf20Sopenharmony_ci * else 32738c2ecf20Sopenharmony_ci * the firmware will reject the command with 32748c2ecf20Sopenharmony_ci * mbox->numstatus set to 1 32758c2ecf20Sopenharmony_ci */ 32768c2ecf20Sopenharmony_ci 32778c2ecf20Sopenharmony_ci i = 0; 32788c2ecf20Sopenharmony_ci status = 0; 32798c2ecf20Sopenharmony_ci while (!mbox->numstatus && mbox->cmd == 0xFF) { 32808c2ecf20Sopenharmony_ci rmb(); 32818c2ecf20Sopenharmony_ci msleep(1); 32828c2ecf20Sopenharmony_ci i++; 32838c2ecf20Sopenharmony_ci if (i > 1000 * 60) { 32848c2ecf20Sopenharmony_ci status = 1; 32858c2ecf20Sopenharmony_ci break; 32868c2ecf20Sopenharmony_ci } 32878c2ecf20Sopenharmony_ci } 32888c2ecf20Sopenharmony_ci if (mbox->numstatus == 1) 32898c2ecf20Sopenharmony_ci status = 1; /*cmd not supported*/ 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_ci /* Check for interrupt line */ 32928c2ecf20Sopenharmony_ci dword = RDOUTDOOR(raid_dev); 32938c2ecf20Sopenharmony_ci WROUTDOOR(raid_dev, dword); 32948c2ecf20Sopenharmony_ci WRINDOOR(raid_dev,2); 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ci return status; 32978c2ecf20Sopenharmony_ci 32988c2ecf20Sopenharmony_ciblocked_mailbox: 32998c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n")); 33008c2ecf20Sopenharmony_ci return status; 33018c2ecf20Sopenharmony_ci} 33028c2ecf20Sopenharmony_ci 33038c2ecf20Sopenharmony_ci/** 33048c2ecf20Sopenharmony_ci * megaraid_mbox_display_scb - display SCB information, mostly debug purposes 33058c2ecf20Sopenharmony_ci * @adapter : controller's soft state 33068c2ecf20Sopenharmony_ci * @scb : SCB to be displayed 33078c2ecf20Sopenharmony_ci * 33088c2ecf20Sopenharmony_ci * Diplay information about the given SCB iff the current debug level is 33098c2ecf20Sopenharmony_ci * verbose. 33108c2ecf20Sopenharmony_ci */ 33118c2ecf20Sopenharmony_cistatic void 33128c2ecf20Sopenharmony_cimegaraid_mbox_display_scb(adapter_t *adapter, scb_t *scb) 33138c2ecf20Sopenharmony_ci{ 33148c2ecf20Sopenharmony_ci mbox_ccb_t *ccb; 33158c2ecf20Sopenharmony_ci struct scsi_cmnd *scp; 33168c2ecf20Sopenharmony_ci mbox_t *mbox; 33178c2ecf20Sopenharmony_ci int level; 33188c2ecf20Sopenharmony_ci int i; 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 33228c2ecf20Sopenharmony_ci scp = scb->scp; 33238c2ecf20Sopenharmony_ci mbox = ccb->mbox; 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci level = CL_DLEVEL3; 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci con_log(level, (KERN_NOTICE 33288c2ecf20Sopenharmony_ci "megaraid mailbox: status:%#x cmd:%#x id:%#x ", scb->status, 33298c2ecf20Sopenharmony_ci mbox->cmd, scb->sno)); 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci con_log(level, ("sec:%#x lba:%#x addr:%#x ld:%d sg:%d\n", 33328c2ecf20Sopenharmony_ci mbox->numsectors, mbox->lba, mbox->xferaddr, mbox->logdrv, 33338c2ecf20Sopenharmony_ci mbox->numsge)); 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_ci if (!scp) return; 33368c2ecf20Sopenharmony_ci 33378c2ecf20Sopenharmony_ci con_log(level, (KERN_NOTICE "scsi cmnd: ")); 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci for (i = 0; i < scp->cmd_len; i++) { 33408c2ecf20Sopenharmony_ci con_log(level, ("%#2.02x ", scp->cmnd[i])); 33418c2ecf20Sopenharmony_ci } 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci con_log(level, ("\n")); 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_ci return; 33468c2ecf20Sopenharmony_ci} 33478c2ecf20Sopenharmony_ci 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_ci/** 33508c2ecf20Sopenharmony_ci * megaraid_mbox_setup_device_map - manage device ids 33518c2ecf20Sopenharmony_ci * @adapter : Driver's soft state 33528c2ecf20Sopenharmony_ci * 33538c2ecf20Sopenharmony_ci * Manage the device ids to have an appropriate mapping between the kernel 33548c2ecf20Sopenharmony_ci * scsi addresses and megaraid scsi and logical drive addresses. We export 33558c2ecf20Sopenharmony_ci * scsi devices on their actual addresses, whereas the logical drives are 33568c2ecf20Sopenharmony_ci * exported on a virtual scsi channel. 33578c2ecf20Sopenharmony_ci */ 33588c2ecf20Sopenharmony_cistatic void 33598c2ecf20Sopenharmony_cimegaraid_mbox_setup_device_map(adapter_t *adapter) 33608c2ecf20Sopenharmony_ci{ 33618c2ecf20Sopenharmony_ci uint8_t c; 33628c2ecf20Sopenharmony_ci uint8_t t; 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci /* 33658c2ecf20Sopenharmony_ci * First fill the values on the logical drive channel 33668c2ecf20Sopenharmony_ci */ 33678c2ecf20Sopenharmony_ci for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++) 33688c2ecf20Sopenharmony_ci adapter->device_ids[adapter->max_channel][t] = 33698c2ecf20Sopenharmony_ci (t < adapter->init_id) ? t : t - 1; 33708c2ecf20Sopenharmony_ci 33718c2ecf20Sopenharmony_ci adapter->device_ids[adapter->max_channel][adapter->init_id] = 0xFF; 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ci /* 33748c2ecf20Sopenharmony_ci * Fill the values on the physical devices channels 33758c2ecf20Sopenharmony_ci */ 33768c2ecf20Sopenharmony_ci for (c = 0; c < adapter->max_channel; c++) 33778c2ecf20Sopenharmony_ci for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++) 33788c2ecf20Sopenharmony_ci adapter->device_ids[c][t] = (c << 8) | t; 33798c2ecf20Sopenharmony_ci} 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_ci/* 33838c2ecf20Sopenharmony_ci * END: internal commands library 33848c2ecf20Sopenharmony_ci */ 33858c2ecf20Sopenharmony_ci 33868c2ecf20Sopenharmony_ci/* 33878c2ecf20Sopenharmony_ci * START: Interface for the common management module 33888c2ecf20Sopenharmony_ci * 33898c2ecf20Sopenharmony_ci * This is the module, which interfaces with the common management module to 33908c2ecf20Sopenharmony_ci * provide support for ioctl and sysfs 33918c2ecf20Sopenharmony_ci */ 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_ci/** 33948c2ecf20Sopenharmony_ci * megaraid_cmm_register - register with the management module 33958c2ecf20Sopenharmony_ci * @adapter : HBA soft state 33968c2ecf20Sopenharmony_ci * 33978c2ecf20Sopenharmony_ci * Register with the management module, which allows applications to issue 33988c2ecf20Sopenharmony_ci * ioctl calls to the drivers. This interface is used by the management module 33998c2ecf20Sopenharmony_ci * to setup sysfs support as well. 34008c2ecf20Sopenharmony_ci */ 34018c2ecf20Sopenharmony_cistatic int 34028c2ecf20Sopenharmony_cimegaraid_cmm_register(adapter_t *adapter) 34038c2ecf20Sopenharmony_ci{ 34048c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 34058c2ecf20Sopenharmony_ci mraid_mmadp_t adp; 34068c2ecf20Sopenharmony_ci scb_t *scb; 34078c2ecf20Sopenharmony_ci mbox_ccb_t *ccb; 34088c2ecf20Sopenharmony_ci int rval; 34098c2ecf20Sopenharmony_ci int i; 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_ci // Allocate memory for the base list of scb for management module. 34128c2ecf20Sopenharmony_ci adapter->uscb_list = kcalloc(MBOX_MAX_USER_CMDS, sizeof(scb_t), GFP_KERNEL); 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci if (adapter->uscb_list == NULL) { 34158c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 34168c2ecf20Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 34178c2ecf20Sopenharmony_ci __LINE__)); 34188c2ecf20Sopenharmony_ci return -1; 34198c2ecf20Sopenharmony_ci } 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci 34228c2ecf20Sopenharmony_ci // Initialize the synchronization parameters for resources for 34238c2ecf20Sopenharmony_ci // commands for management module 34248c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->uscb_pool); 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci spin_lock_init(USER_FREE_LIST_LOCK(adapter)); 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_ci 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci // link all the packets. Note, CCB for commands, coming from the 34318c2ecf20Sopenharmony_ci // commom management module, mailbox physical address are already 34328c2ecf20Sopenharmony_ci // setup by it. We just need placeholder for that in our local command 34338c2ecf20Sopenharmony_ci // control blocks 34348c2ecf20Sopenharmony_ci for (i = 0; i < MBOX_MAX_USER_CMDS; i++) { 34358c2ecf20Sopenharmony_ci 34368c2ecf20Sopenharmony_ci scb = adapter->uscb_list + i; 34378c2ecf20Sopenharmony_ci ccb = raid_dev->uccb_list + i; 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_ci scb->ccb = (caddr_t)ccb; 34408c2ecf20Sopenharmony_ci ccb->mbox64 = raid_dev->umbox64 + i; 34418c2ecf20Sopenharmony_ci ccb->mbox = &ccb->mbox64->mbox32; 34428c2ecf20Sopenharmony_ci ccb->raw_mbox = (uint8_t *)ccb->mbox; 34438c2ecf20Sopenharmony_ci 34448c2ecf20Sopenharmony_ci scb->gp = 0; 34458c2ecf20Sopenharmony_ci 34468c2ecf20Sopenharmony_ci // COMMAND ID 0 - (MBOX_MAX_SCSI_CMDS-1) ARE RESERVED FOR 34478c2ecf20Sopenharmony_ci // COMMANDS COMING FROM IO SUBSYSTEM (MID-LAYER) 34488c2ecf20Sopenharmony_ci scb->sno = i + MBOX_MAX_SCSI_CMDS; 34498c2ecf20Sopenharmony_ci 34508c2ecf20Sopenharmony_ci scb->scp = NULL; 34518c2ecf20Sopenharmony_ci scb->state = SCB_FREE; 34528c2ecf20Sopenharmony_ci scb->dma_direction = DMA_NONE; 34538c2ecf20Sopenharmony_ci scb->dma_type = MRAID_DMA_NONE; 34548c2ecf20Sopenharmony_ci scb->dev_channel = -1; 34558c2ecf20Sopenharmony_ci scb->dev_target = -1; 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci // put scb in the free pool 34588c2ecf20Sopenharmony_ci list_add_tail(&scb->list, &adapter->uscb_pool); 34598c2ecf20Sopenharmony_ci } 34608c2ecf20Sopenharmony_ci 34618c2ecf20Sopenharmony_ci adp.unique_id = adapter->unique_id; 34628c2ecf20Sopenharmony_ci adp.drvr_type = DRVRTYPE_MBOX; 34638c2ecf20Sopenharmony_ci adp.drvr_data = (unsigned long)adapter; 34648c2ecf20Sopenharmony_ci adp.pdev = adapter->pdev; 34658c2ecf20Sopenharmony_ci adp.issue_uioc = megaraid_mbox_mm_handler; 34668c2ecf20Sopenharmony_ci adp.timeout = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; 34678c2ecf20Sopenharmony_ci adp.max_kioc = MBOX_MAX_USER_CMDS; 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci if ((rval = mraid_mm_register_adp(&adp)) != 0) { 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 34728c2ecf20Sopenharmony_ci "megaraid mbox: did not register with CMM\n")); 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci kfree(adapter->uscb_list); 34758c2ecf20Sopenharmony_ci } 34768c2ecf20Sopenharmony_ci 34778c2ecf20Sopenharmony_ci return rval; 34788c2ecf20Sopenharmony_ci} 34798c2ecf20Sopenharmony_ci 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci/** 34828c2ecf20Sopenharmony_ci * megaraid_cmm_unregister - un-register with the management module 34838c2ecf20Sopenharmony_ci * @adapter : HBA soft state 34848c2ecf20Sopenharmony_ci * 34858c2ecf20Sopenharmony_ci * Un-register with the management module. 34868c2ecf20Sopenharmony_ci * FIXME: mgmt module must return failure for unregister if it has pending 34878c2ecf20Sopenharmony_ci * commands in LLD. 34888c2ecf20Sopenharmony_ci */ 34898c2ecf20Sopenharmony_cistatic int 34908c2ecf20Sopenharmony_cimegaraid_cmm_unregister(adapter_t *adapter) 34918c2ecf20Sopenharmony_ci{ 34928c2ecf20Sopenharmony_ci kfree(adapter->uscb_list); 34938c2ecf20Sopenharmony_ci mraid_mm_unregister_adp(adapter->unique_id); 34948c2ecf20Sopenharmony_ci return 0; 34958c2ecf20Sopenharmony_ci} 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci 34988c2ecf20Sopenharmony_ci/** 34998c2ecf20Sopenharmony_ci * megaraid_mbox_mm_handler - interface for CMM to issue commands to LLD 35008c2ecf20Sopenharmony_ci * @drvr_data : LLD specific data 35018c2ecf20Sopenharmony_ci * @kioc : CMM interface packet 35028c2ecf20Sopenharmony_ci * @action : command action 35038c2ecf20Sopenharmony_ci * 35048c2ecf20Sopenharmony_ci * This routine is invoked whenever the Common Management Module (CMM) has a 35058c2ecf20Sopenharmony_ci * command for us. The 'action' parameter specifies if this is a new command 35068c2ecf20Sopenharmony_ci * or otherwise. 35078c2ecf20Sopenharmony_ci */ 35088c2ecf20Sopenharmony_cistatic int 35098c2ecf20Sopenharmony_cimegaraid_mbox_mm_handler(unsigned long drvr_data, uioc_t *kioc, uint32_t action) 35108c2ecf20Sopenharmony_ci{ 35118c2ecf20Sopenharmony_ci adapter_t *adapter; 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_ci if (action != IOCTL_ISSUE) { 35148c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 35158c2ecf20Sopenharmony_ci "megaraid: unsupported management action:%#2x\n", 35168c2ecf20Sopenharmony_ci action)); 35178c2ecf20Sopenharmony_ci return (-ENOTSUPP); 35188c2ecf20Sopenharmony_ci } 35198c2ecf20Sopenharmony_ci 35208c2ecf20Sopenharmony_ci adapter = (adapter_t *)drvr_data; 35218c2ecf20Sopenharmony_ci 35228c2ecf20Sopenharmony_ci // make sure this adapter is not being detached right now. 35238c2ecf20Sopenharmony_ci if (atomic_read(&adapter->being_detached)) { 35248c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 35258c2ecf20Sopenharmony_ci "megaraid: reject management request, detaching\n")); 35268c2ecf20Sopenharmony_ci return (-ENODEV); 35278c2ecf20Sopenharmony_ci } 35288c2ecf20Sopenharmony_ci 35298c2ecf20Sopenharmony_ci switch (kioc->opcode) { 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_ci case GET_ADAP_INFO: 35328c2ecf20Sopenharmony_ci 35338c2ecf20Sopenharmony_ci kioc->status = gather_hbainfo(adapter, (mraid_hba_info_t *) 35348c2ecf20Sopenharmony_ci (unsigned long)kioc->buf_vaddr); 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_ci kioc->done(kioc); 35378c2ecf20Sopenharmony_ci 35388c2ecf20Sopenharmony_ci return kioc->status; 35398c2ecf20Sopenharmony_ci 35408c2ecf20Sopenharmony_ci case MBOX_CMD: 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci return megaraid_mbox_mm_command(adapter, kioc); 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci default: 35458c2ecf20Sopenharmony_ci kioc->status = (-EINVAL); 35468c2ecf20Sopenharmony_ci kioc->done(kioc); 35478c2ecf20Sopenharmony_ci return (-EINVAL); 35488c2ecf20Sopenharmony_ci } 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci return 0; // not reached 35518c2ecf20Sopenharmony_ci} 35528c2ecf20Sopenharmony_ci 35538c2ecf20Sopenharmony_ci/** 35548c2ecf20Sopenharmony_ci * megaraid_mbox_mm_command - issues commands routed through CMM 35558c2ecf20Sopenharmony_ci * @adapter : HBA soft state 35568c2ecf20Sopenharmony_ci * @kioc : management command packet 35578c2ecf20Sopenharmony_ci * 35588c2ecf20Sopenharmony_ci * Issues commands, which are routed through the management module. 35598c2ecf20Sopenharmony_ci */ 35608c2ecf20Sopenharmony_cistatic int 35618c2ecf20Sopenharmony_cimegaraid_mbox_mm_command(adapter_t *adapter, uioc_t *kioc) 35628c2ecf20Sopenharmony_ci{ 35638c2ecf20Sopenharmony_ci struct list_head *head = &adapter->uscb_pool; 35648c2ecf20Sopenharmony_ci mbox64_t *mbox64; 35658c2ecf20Sopenharmony_ci uint8_t *raw_mbox; 35668c2ecf20Sopenharmony_ci scb_t *scb; 35678c2ecf20Sopenharmony_ci mbox_ccb_t *ccb; 35688c2ecf20Sopenharmony_ci unsigned long flags; 35698c2ecf20Sopenharmony_ci 35708c2ecf20Sopenharmony_ci // detach one scb from free pool 35718c2ecf20Sopenharmony_ci spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags); 35728c2ecf20Sopenharmony_ci 35738c2ecf20Sopenharmony_ci if (list_empty(head)) { // should never happen because of CMM 35748c2ecf20Sopenharmony_ci 35758c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 35768c2ecf20Sopenharmony_ci "megaraid mbox: bug in cmm handler, lost resources\n")); 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); 35798c2ecf20Sopenharmony_ci 35808c2ecf20Sopenharmony_ci return (-EINVAL); 35818c2ecf20Sopenharmony_ci } 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_ci scb = list_entry(head->next, scb_t, list); 35848c2ecf20Sopenharmony_ci list_del_init(&scb->list); 35858c2ecf20Sopenharmony_ci 35868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci scb->state = SCB_ACTIVE; 35898c2ecf20Sopenharmony_ci scb->dma_type = MRAID_DMA_NONE; 35908c2ecf20Sopenharmony_ci scb->dma_direction = DMA_NONE; 35918c2ecf20Sopenharmony_ci 35928c2ecf20Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 35938c2ecf20Sopenharmony_ci mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; 35948c2ecf20Sopenharmony_ci raw_mbox = (uint8_t *)&mbox64->mbox32; 35958c2ecf20Sopenharmony_ci 35968c2ecf20Sopenharmony_ci memcpy(ccb->mbox64, mbox64, sizeof(mbox64_t)); 35978c2ecf20Sopenharmony_ci 35988c2ecf20Sopenharmony_ci scb->gp = (unsigned long)kioc; 35998c2ecf20Sopenharmony_ci 36008c2ecf20Sopenharmony_ci /* 36018c2ecf20Sopenharmony_ci * If it is a logdrv random delete operation, we have to wait till 36028c2ecf20Sopenharmony_ci * there are no outstanding cmds at the fw and then issue it directly 36038c2ecf20Sopenharmony_ci */ 36048c2ecf20Sopenharmony_ci if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) { 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ci if (wait_till_fw_empty(adapter)) { 36078c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 36088c2ecf20Sopenharmony_ci "megaraid mbox: LD delete, timed out\n")); 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_ci kioc->status = -ETIME; 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_ci scb->status = -1; 36138c2ecf20Sopenharmony_ci 36148c2ecf20Sopenharmony_ci megaraid_mbox_mm_done(adapter, scb); 36158c2ecf20Sopenharmony_ci 36168c2ecf20Sopenharmony_ci return (-ETIME); 36178c2ecf20Sopenharmony_ci } 36188c2ecf20Sopenharmony_ci 36198c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&scb->list); 36208c2ecf20Sopenharmony_ci 36218c2ecf20Sopenharmony_ci scb->state = SCB_ISSUED; 36228c2ecf20Sopenharmony_ci if (mbox_post_cmd(adapter, scb) != 0) { 36238c2ecf20Sopenharmony_ci 36248c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 36258c2ecf20Sopenharmony_ci "megaraid mbox: LD delete, mailbox busy\n")); 36268c2ecf20Sopenharmony_ci 36278c2ecf20Sopenharmony_ci kioc->status = -EBUSY; 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_ci scb->status = -1; 36308c2ecf20Sopenharmony_ci 36318c2ecf20Sopenharmony_ci megaraid_mbox_mm_done(adapter, scb); 36328c2ecf20Sopenharmony_ci 36338c2ecf20Sopenharmony_ci return (-EBUSY); 36348c2ecf20Sopenharmony_ci } 36358c2ecf20Sopenharmony_ci 36368c2ecf20Sopenharmony_ci return 0; 36378c2ecf20Sopenharmony_ci } 36388c2ecf20Sopenharmony_ci 36398c2ecf20Sopenharmony_ci // put the command on the pending list and execute 36408c2ecf20Sopenharmony_ci megaraid_mbox_runpendq(adapter, scb); 36418c2ecf20Sopenharmony_ci 36428c2ecf20Sopenharmony_ci return 0; 36438c2ecf20Sopenharmony_ci} 36448c2ecf20Sopenharmony_ci 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_cistatic int 36478c2ecf20Sopenharmony_ciwait_till_fw_empty(adapter_t *adapter) 36488c2ecf20Sopenharmony_ci{ 36498c2ecf20Sopenharmony_ci unsigned long flags = 0; 36508c2ecf20Sopenharmony_ci int i; 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci 36538c2ecf20Sopenharmony_ci /* 36548c2ecf20Sopenharmony_ci * Set the quiescent flag to stop issuing cmds to FW. 36558c2ecf20Sopenharmony_ci */ 36568c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->lock, flags); 36578c2ecf20Sopenharmony_ci adapter->quiescent++; 36588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->lock, flags); 36598c2ecf20Sopenharmony_ci 36608c2ecf20Sopenharmony_ci /* 36618c2ecf20Sopenharmony_ci * Wait till there are no more cmds outstanding at FW. Try for at most 36628c2ecf20Sopenharmony_ci * 60 seconds 36638c2ecf20Sopenharmony_ci */ 36648c2ecf20Sopenharmony_ci for (i = 0; i < 60 && adapter->outstanding_cmds; i++) { 36658c2ecf20Sopenharmony_ci con_log(CL_DLEVEL1, (KERN_INFO 36668c2ecf20Sopenharmony_ci "megaraid: FW has %d pending commands\n", 36678c2ecf20Sopenharmony_ci adapter->outstanding_cmds)); 36688c2ecf20Sopenharmony_ci 36698c2ecf20Sopenharmony_ci msleep(1000); 36708c2ecf20Sopenharmony_ci } 36718c2ecf20Sopenharmony_ci 36728c2ecf20Sopenharmony_ci return adapter->outstanding_cmds; 36738c2ecf20Sopenharmony_ci} 36748c2ecf20Sopenharmony_ci 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci/** 36778c2ecf20Sopenharmony_ci * megaraid_mbox_mm_done - callback for CMM commands 36788c2ecf20Sopenharmony_ci * @adapter : HBA soft state 36798c2ecf20Sopenharmony_ci * @scb : completed command 36808c2ecf20Sopenharmony_ci * 36818c2ecf20Sopenharmony_ci * Callback routine for internal commands originated from the management 36828c2ecf20Sopenharmony_ci * module. 36838c2ecf20Sopenharmony_ci */ 36848c2ecf20Sopenharmony_cistatic void 36858c2ecf20Sopenharmony_cimegaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb) 36868c2ecf20Sopenharmony_ci{ 36878c2ecf20Sopenharmony_ci uioc_t *kioc; 36888c2ecf20Sopenharmony_ci mbox64_t *mbox64; 36898c2ecf20Sopenharmony_ci uint8_t *raw_mbox; 36908c2ecf20Sopenharmony_ci unsigned long flags; 36918c2ecf20Sopenharmony_ci 36928c2ecf20Sopenharmony_ci kioc = (uioc_t *)scb->gp; 36938c2ecf20Sopenharmony_ci mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; 36948c2ecf20Sopenharmony_ci mbox64->mbox32.status = scb->status; 36958c2ecf20Sopenharmony_ci raw_mbox = (uint8_t *)&mbox64->mbox32; 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_ci 36988c2ecf20Sopenharmony_ci // put scb in the free pool 36998c2ecf20Sopenharmony_ci scb->state = SCB_FREE; 37008c2ecf20Sopenharmony_ci scb->scp = NULL; 37018c2ecf20Sopenharmony_ci 37028c2ecf20Sopenharmony_ci spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags); 37038c2ecf20Sopenharmony_ci 37048c2ecf20Sopenharmony_ci list_add(&scb->list, &adapter->uscb_pool); 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); 37078c2ecf20Sopenharmony_ci 37088c2ecf20Sopenharmony_ci // if a delete logical drive operation succeeded, restart the 37098c2ecf20Sopenharmony_ci // controller 37108c2ecf20Sopenharmony_ci if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) { 37118c2ecf20Sopenharmony_ci 37128c2ecf20Sopenharmony_ci adapter->quiescent--; 37138c2ecf20Sopenharmony_ci 37148c2ecf20Sopenharmony_ci megaraid_mbox_runpendq(adapter, NULL); 37158c2ecf20Sopenharmony_ci } 37168c2ecf20Sopenharmony_ci 37178c2ecf20Sopenharmony_ci kioc->done(kioc); 37188c2ecf20Sopenharmony_ci 37198c2ecf20Sopenharmony_ci return; 37208c2ecf20Sopenharmony_ci} 37218c2ecf20Sopenharmony_ci 37228c2ecf20Sopenharmony_ci 37238c2ecf20Sopenharmony_ci/** 37248c2ecf20Sopenharmony_ci * gather_hbainfo - HBA characteristics for the applications 37258c2ecf20Sopenharmony_ci * @adapter : HBA soft state 37268c2ecf20Sopenharmony_ci * @hinfo : pointer to the caller's host info strucuture 37278c2ecf20Sopenharmony_ci */ 37288c2ecf20Sopenharmony_cistatic int 37298c2ecf20Sopenharmony_cigather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo) 37308c2ecf20Sopenharmony_ci{ 37318c2ecf20Sopenharmony_ci hinfo->pci_vendor_id = adapter->pdev->vendor; 37328c2ecf20Sopenharmony_ci hinfo->pci_device_id = adapter->pdev->device; 37338c2ecf20Sopenharmony_ci hinfo->subsys_vendor_id = adapter->pdev->subsystem_vendor; 37348c2ecf20Sopenharmony_ci hinfo->subsys_device_id = adapter->pdev->subsystem_device; 37358c2ecf20Sopenharmony_ci 37368c2ecf20Sopenharmony_ci hinfo->pci_bus = adapter->pdev->bus->number; 37378c2ecf20Sopenharmony_ci hinfo->pci_dev_fn = adapter->pdev->devfn; 37388c2ecf20Sopenharmony_ci hinfo->pci_slot = PCI_SLOT(adapter->pdev->devfn); 37398c2ecf20Sopenharmony_ci hinfo->irq = adapter->host->irq; 37408c2ecf20Sopenharmony_ci hinfo->baseport = ADAP2RAIDDEV(adapter)->baseport; 37418c2ecf20Sopenharmony_ci 37428c2ecf20Sopenharmony_ci hinfo->unique_id = (hinfo->pci_bus << 8) | adapter->pdev->devfn; 37438c2ecf20Sopenharmony_ci hinfo->host_no = adapter->host->host_no; 37448c2ecf20Sopenharmony_ci 37458c2ecf20Sopenharmony_ci return 0; 37468c2ecf20Sopenharmony_ci} 37478c2ecf20Sopenharmony_ci 37488c2ecf20Sopenharmony_ci/* 37498c2ecf20Sopenharmony_ci * END: Interface for the common management module 37508c2ecf20Sopenharmony_ci */ 37518c2ecf20Sopenharmony_ci 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_ci/** 37558c2ecf20Sopenharmony_ci * megaraid_sysfs_alloc_resources - allocate sysfs related resources 37568c2ecf20Sopenharmony_ci * @adapter : controller's soft state 37578c2ecf20Sopenharmony_ci * 37588c2ecf20Sopenharmony_ci * Allocate packets required to issue FW calls whenever the sysfs attributes 37598c2ecf20Sopenharmony_ci * are read. These attributes would require up-to-date information from the 37608c2ecf20Sopenharmony_ci * FW. Also set up resources for mutual exclusion to share these resources and 37618c2ecf20Sopenharmony_ci * the wait queue. 37628c2ecf20Sopenharmony_ci * 37638c2ecf20Sopenharmony_ci * Return 0 on success. 37648c2ecf20Sopenharmony_ci * Return -ERROR_CODE on failure. 37658c2ecf20Sopenharmony_ci */ 37668c2ecf20Sopenharmony_cistatic int 37678c2ecf20Sopenharmony_cimegaraid_sysfs_alloc_resources(adapter_t *adapter) 37688c2ecf20Sopenharmony_ci{ 37698c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 37708c2ecf20Sopenharmony_ci int rval = 0; 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci raid_dev->sysfs_uioc = kmalloc(sizeof(uioc_t), GFP_KERNEL); 37738c2ecf20Sopenharmony_ci 37748c2ecf20Sopenharmony_ci raid_dev->sysfs_mbox64 = kmalloc(sizeof(mbox64_t), GFP_KERNEL); 37758c2ecf20Sopenharmony_ci 37768c2ecf20Sopenharmony_ci raid_dev->sysfs_buffer = dma_alloc_coherent(&adapter->pdev->dev, 37778c2ecf20Sopenharmony_ci PAGE_SIZE, &raid_dev->sysfs_buffer_dma, GFP_KERNEL); 37788c2ecf20Sopenharmony_ci 37798c2ecf20Sopenharmony_ci if (!raid_dev->sysfs_uioc || !raid_dev->sysfs_mbox64 || 37808c2ecf20Sopenharmony_ci !raid_dev->sysfs_buffer) { 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 37838c2ecf20Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 37848c2ecf20Sopenharmony_ci __LINE__)); 37858c2ecf20Sopenharmony_ci 37868c2ecf20Sopenharmony_ci rval = -ENOMEM; 37878c2ecf20Sopenharmony_ci 37888c2ecf20Sopenharmony_ci megaraid_sysfs_free_resources(adapter); 37898c2ecf20Sopenharmony_ci } 37908c2ecf20Sopenharmony_ci 37918c2ecf20Sopenharmony_ci mutex_init(&raid_dev->sysfs_mtx); 37928c2ecf20Sopenharmony_ci 37938c2ecf20Sopenharmony_ci init_waitqueue_head(&raid_dev->sysfs_wait_q); 37948c2ecf20Sopenharmony_ci 37958c2ecf20Sopenharmony_ci return rval; 37968c2ecf20Sopenharmony_ci} 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_ci/** 38008c2ecf20Sopenharmony_ci * megaraid_sysfs_free_resources - free sysfs related resources 38018c2ecf20Sopenharmony_ci * @adapter : controller's soft state 38028c2ecf20Sopenharmony_ci * 38038c2ecf20Sopenharmony_ci * Free packets allocated for sysfs FW commands 38048c2ecf20Sopenharmony_ci */ 38058c2ecf20Sopenharmony_cistatic void 38068c2ecf20Sopenharmony_cimegaraid_sysfs_free_resources(adapter_t *adapter) 38078c2ecf20Sopenharmony_ci{ 38088c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci kfree(raid_dev->sysfs_uioc); 38118c2ecf20Sopenharmony_ci kfree(raid_dev->sysfs_mbox64); 38128c2ecf20Sopenharmony_ci 38138c2ecf20Sopenharmony_ci if (raid_dev->sysfs_buffer) { 38148c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, PAGE_SIZE, 38158c2ecf20Sopenharmony_ci raid_dev->sysfs_buffer, raid_dev->sysfs_buffer_dma); 38168c2ecf20Sopenharmony_ci } 38178c2ecf20Sopenharmony_ci} 38188c2ecf20Sopenharmony_ci 38198c2ecf20Sopenharmony_ci 38208c2ecf20Sopenharmony_ci/** 38218c2ecf20Sopenharmony_ci * megaraid_sysfs_get_ldmap_done - callback for get ldmap 38228c2ecf20Sopenharmony_ci * @uioc : completed packet 38238c2ecf20Sopenharmony_ci * 38248c2ecf20Sopenharmony_ci * Callback routine called in the ISR/tasklet context for get ldmap call 38258c2ecf20Sopenharmony_ci */ 38268c2ecf20Sopenharmony_cistatic void 38278c2ecf20Sopenharmony_cimegaraid_sysfs_get_ldmap_done(uioc_t *uioc) 38288c2ecf20Sopenharmony_ci{ 38298c2ecf20Sopenharmony_ci adapter_t *adapter = (adapter_t *)uioc->buf_vaddr; 38308c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 38318c2ecf20Sopenharmony_ci 38328c2ecf20Sopenharmony_ci uioc->status = 0; 38338c2ecf20Sopenharmony_ci 38348c2ecf20Sopenharmony_ci wake_up(&raid_dev->sysfs_wait_q); 38358c2ecf20Sopenharmony_ci} 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_ci/** 38388c2ecf20Sopenharmony_ci * megaraid_sysfs_get_ldmap_timeout - timeout handling for get ldmap 38398c2ecf20Sopenharmony_ci * @t : timed out timer 38408c2ecf20Sopenharmony_ci * 38418c2ecf20Sopenharmony_ci * Timeout routine to recover and return to application, in case the adapter 38428c2ecf20Sopenharmony_ci * has stopped responding. A timeout of 60 seconds for this command seems like 38438c2ecf20Sopenharmony_ci * a good value. 38448c2ecf20Sopenharmony_ci */ 38458c2ecf20Sopenharmony_cistatic void 38468c2ecf20Sopenharmony_cimegaraid_sysfs_get_ldmap_timeout(struct timer_list *t) 38478c2ecf20Sopenharmony_ci{ 38488c2ecf20Sopenharmony_ci struct uioc_timeout *timeout = from_timer(timeout, t, timer); 38498c2ecf20Sopenharmony_ci uioc_t *uioc = timeout->uioc; 38508c2ecf20Sopenharmony_ci adapter_t *adapter = (adapter_t *)uioc->buf_vaddr; 38518c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 38528c2ecf20Sopenharmony_ci 38538c2ecf20Sopenharmony_ci uioc->status = -ETIME; 38548c2ecf20Sopenharmony_ci 38558c2ecf20Sopenharmony_ci wake_up(&raid_dev->sysfs_wait_q); 38568c2ecf20Sopenharmony_ci} 38578c2ecf20Sopenharmony_ci 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_ci/** 38608c2ecf20Sopenharmony_ci * megaraid_sysfs_get_ldmap - get update logical drive map 38618c2ecf20Sopenharmony_ci * @adapter : controller's soft state 38628c2ecf20Sopenharmony_ci * 38638c2ecf20Sopenharmony_ci * This routine will be called whenever user reads the logical drive 38648c2ecf20Sopenharmony_ci * attributes, go get the current logical drive mapping table from the 38658c2ecf20Sopenharmony_ci * firmware. We use the management API's to issue commands to the controller. 38668c2ecf20Sopenharmony_ci * 38678c2ecf20Sopenharmony_ci * NOTE: The commands issuance functionality is not generalized and 38688c2ecf20Sopenharmony_ci * implemented in context of "get ld map" command only. If required, the 38698c2ecf20Sopenharmony_ci * command issuance logical can be trivially pulled out and implemented as a 38708c2ecf20Sopenharmony_ci * standalone library. For now, this should suffice since there is no other 38718c2ecf20Sopenharmony_ci * user of this interface. 38728c2ecf20Sopenharmony_ci * 38738c2ecf20Sopenharmony_ci * Return 0 on success. 38748c2ecf20Sopenharmony_ci * Return -1 on failure. 38758c2ecf20Sopenharmony_ci */ 38768c2ecf20Sopenharmony_cistatic int 38778c2ecf20Sopenharmony_cimegaraid_sysfs_get_ldmap(adapter_t *adapter) 38788c2ecf20Sopenharmony_ci{ 38798c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 38808c2ecf20Sopenharmony_ci uioc_t *uioc; 38818c2ecf20Sopenharmony_ci mbox64_t *mbox64; 38828c2ecf20Sopenharmony_ci mbox_t *mbox; 38838c2ecf20Sopenharmony_ci char *raw_mbox; 38848c2ecf20Sopenharmony_ci struct uioc_timeout timeout; 38858c2ecf20Sopenharmony_ci caddr_t ldmap; 38868c2ecf20Sopenharmony_ci int rval = 0; 38878c2ecf20Sopenharmony_ci 38888c2ecf20Sopenharmony_ci /* 38898c2ecf20Sopenharmony_ci * Allow only one read at a time to go through the sysfs attributes 38908c2ecf20Sopenharmony_ci */ 38918c2ecf20Sopenharmony_ci mutex_lock(&raid_dev->sysfs_mtx); 38928c2ecf20Sopenharmony_ci 38938c2ecf20Sopenharmony_ci uioc = raid_dev->sysfs_uioc; 38948c2ecf20Sopenharmony_ci mbox64 = raid_dev->sysfs_mbox64; 38958c2ecf20Sopenharmony_ci ldmap = raid_dev->sysfs_buffer; 38968c2ecf20Sopenharmony_ci 38978c2ecf20Sopenharmony_ci memset(uioc, 0, sizeof(uioc_t)); 38988c2ecf20Sopenharmony_ci memset(mbox64, 0, sizeof(mbox64_t)); 38998c2ecf20Sopenharmony_ci memset(ldmap, 0, sizeof(raid_dev->curr_ldmap)); 39008c2ecf20Sopenharmony_ci 39018c2ecf20Sopenharmony_ci mbox = &mbox64->mbox32; 39028c2ecf20Sopenharmony_ci raw_mbox = (char *)mbox; 39038c2ecf20Sopenharmony_ci uioc->cmdbuf = (uint64_t)(unsigned long)mbox64; 39048c2ecf20Sopenharmony_ci uioc->buf_vaddr = (caddr_t)adapter; 39058c2ecf20Sopenharmony_ci uioc->status = -ENODATA; 39068c2ecf20Sopenharmony_ci uioc->done = megaraid_sysfs_get_ldmap_done; 39078c2ecf20Sopenharmony_ci 39088c2ecf20Sopenharmony_ci /* 39098c2ecf20Sopenharmony_ci * Prepare the mailbox packet to get the current logical drive mapping 39108c2ecf20Sopenharmony_ci * table 39118c2ecf20Sopenharmony_ci */ 39128c2ecf20Sopenharmony_ci mbox->xferaddr = (uint32_t)raid_dev->sysfs_buffer_dma; 39138c2ecf20Sopenharmony_ci 39148c2ecf20Sopenharmony_ci raw_mbox[0] = FC_DEL_LOGDRV; 39158c2ecf20Sopenharmony_ci raw_mbox[2] = OP_GET_LDID_MAP; 39168c2ecf20Sopenharmony_ci 39178c2ecf20Sopenharmony_ci /* 39188c2ecf20Sopenharmony_ci * Setup a timer to recover from a non-responding controller 39198c2ecf20Sopenharmony_ci */ 39208c2ecf20Sopenharmony_ci timeout.uioc = uioc; 39218c2ecf20Sopenharmony_ci timer_setup_on_stack(&timeout.timer, 39228c2ecf20Sopenharmony_ci megaraid_sysfs_get_ldmap_timeout, 0); 39238c2ecf20Sopenharmony_ci 39248c2ecf20Sopenharmony_ci timeout.timer.expires = jiffies + 60 * HZ; 39258c2ecf20Sopenharmony_ci add_timer(&timeout.timer); 39268c2ecf20Sopenharmony_ci 39278c2ecf20Sopenharmony_ci /* 39288c2ecf20Sopenharmony_ci * Send the command to the firmware 39298c2ecf20Sopenharmony_ci */ 39308c2ecf20Sopenharmony_ci rval = megaraid_mbox_mm_command(adapter, uioc); 39318c2ecf20Sopenharmony_ci 39328c2ecf20Sopenharmony_ci if (rval == 0) { // command successfully issued 39338c2ecf20Sopenharmony_ci wait_event(raid_dev->sysfs_wait_q, (uioc->status != -ENODATA)); 39348c2ecf20Sopenharmony_ci 39358c2ecf20Sopenharmony_ci /* 39368c2ecf20Sopenharmony_ci * Check if the command timed out 39378c2ecf20Sopenharmony_ci */ 39388c2ecf20Sopenharmony_ci if (uioc->status == -ETIME) { 39398c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 39408c2ecf20Sopenharmony_ci "megaraid: sysfs get ld map timed out\n")); 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci rval = -ETIME; 39438c2ecf20Sopenharmony_ci } 39448c2ecf20Sopenharmony_ci else { 39458c2ecf20Sopenharmony_ci rval = mbox->status; 39468c2ecf20Sopenharmony_ci } 39478c2ecf20Sopenharmony_ci 39488c2ecf20Sopenharmony_ci if (rval == 0) { 39498c2ecf20Sopenharmony_ci memcpy(raid_dev->curr_ldmap, ldmap, 39508c2ecf20Sopenharmony_ci sizeof(raid_dev->curr_ldmap)); 39518c2ecf20Sopenharmony_ci } 39528c2ecf20Sopenharmony_ci else { 39538c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 39548c2ecf20Sopenharmony_ci "megaraid: get ld map failed with %x\n", rval)); 39558c2ecf20Sopenharmony_ci } 39568c2ecf20Sopenharmony_ci } 39578c2ecf20Sopenharmony_ci else { 39588c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 39598c2ecf20Sopenharmony_ci "megaraid: could not issue ldmap command:%x\n", rval)); 39608c2ecf20Sopenharmony_ci } 39618c2ecf20Sopenharmony_ci 39628c2ecf20Sopenharmony_ci 39638c2ecf20Sopenharmony_ci del_timer_sync(&timeout.timer); 39648c2ecf20Sopenharmony_ci destroy_timer_on_stack(&timeout.timer); 39658c2ecf20Sopenharmony_ci 39668c2ecf20Sopenharmony_ci mutex_unlock(&raid_dev->sysfs_mtx); 39678c2ecf20Sopenharmony_ci 39688c2ecf20Sopenharmony_ci return rval; 39698c2ecf20Sopenharmony_ci} 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci 39728c2ecf20Sopenharmony_ci/** 39738c2ecf20Sopenharmony_ci * megaraid_sysfs_show_app_hndl - display application handle for this adapter 39748c2ecf20Sopenharmony_ci * @dev : class device object representation for the host 39758c2ecf20Sopenharmony_ci * @attr : device attribute (unused) 39768c2ecf20Sopenharmony_ci * @buf : buffer to send data to 39778c2ecf20Sopenharmony_ci * 39788c2ecf20Sopenharmony_ci * Display the handle used by the applications while executing management 39798c2ecf20Sopenharmony_ci * tasks on the adapter. We invoke a management module API to get the adapter 39808c2ecf20Sopenharmony_ci * handle, since we do not interface with applications directly. 39818c2ecf20Sopenharmony_ci */ 39828c2ecf20Sopenharmony_cistatic ssize_t 39838c2ecf20Sopenharmony_cimegaraid_sysfs_show_app_hndl(struct device *dev, struct device_attribute *attr, 39848c2ecf20Sopenharmony_ci char *buf) 39858c2ecf20Sopenharmony_ci{ 39868c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 39878c2ecf20Sopenharmony_ci adapter_t *adapter = (adapter_t *)SCSIHOST2ADAP(shost); 39888c2ecf20Sopenharmony_ci uint32_t app_hndl; 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci app_hndl = mraid_mm_adapter_app_handle(adapter->unique_id); 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_ci return snprintf(buf, 8, "%u\n", app_hndl); 39938c2ecf20Sopenharmony_ci} 39948c2ecf20Sopenharmony_ci 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci/** 39978c2ecf20Sopenharmony_ci * megaraid_sysfs_show_ldnum - display the logical drive number for this device 39988c2ecf20Sopenharmony_ci * @dev : device object representation for the scsi device 39998c2ecf20Sopenharmony_ci * @attr : device attribute to show 40008c2ecf20Sopenharmony_ci * @buf : buffer to send data to 40018c2ecf20Sopenharmony_ci * 40028c2ecf20Sopenharmony_ci * Display the logical drive number for the device in question, if it a valid 40038c2ecf20Sopenharmony_ci * logical drive. For physical devices, "-1" is returned. 40048c2ecf20Sopenharmony_ci * 40058c2ecf20Sopenharmony_ci * The logical drive number is displayed in following format: 40068c2ecf20Sopenharmony_ci * 40078c2ecf20Sopenharmony_ci * <SCSI ID> <LD NUM> <LD STICKY ID> <APP ADAPTER HANDLE> 40088c2ecf20Sopenharmony_ci * 40098c2ecf20Sopenharmony_ci * <int> <int> <int> <int> 40108c2ecf20Sopenharmony_ci */ 40118c2ecf20Sopenharmony_cistatic ssize_t 40128c2ecf20Sopenharmony_cimegaraid_sysfs_show_ldnum(struct device *dev, struct device_attribute *attr, char *buf) 40138c2ecf20Sopenharmony_ci{ 40148c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 40158c2ecf20Sopenharmony_ci adapter_t *adapter = (adapter_t *)SCSIHOST2ADAP(sdev->host); 40168c2ecf20Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 40178c2ecf20Sopenharmony_ci int scsi_id = -1; 40188c2ecf20Sopenharmony_ci int logical_drv = -1; 40198c2ecf20Sopenharmony_ci int ldid_map = -1; 40208c2ecf20Sopenharmony_ci uint32_t app_hndl = 0; 40218c2ecf20Sopenharmony_ci int mapped_sdev_id; 40228c2ecf20Sopenharmony_ci int rval; 40238c2ecf20Sopenharmony_ci int i; 40248c2ecf20Sopenharmony_ci 40258c2ecf20Sopenharmony_ci if (raid_dev->random_del_supported && 40268c2ecf20Sopenharmony_ci MRAID_IS_LOGICAL_SDEV(adapter, sdev)) { 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci rval = megaraid_sysfs_get_ldmap(adapter); 40298c2ecf20Sopenharmony_ci if (rval == 0) { 40308c2ecf20Sopenharmony_ci 40318c2ecf20Sopenharmony_ci for (i = 0; i < MAX_LOGICAL_DRIVES_40LD; i++) { 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci mapped_sdev_id = sdev->id; 40348c2ecf20Sopenharmony_ci 40358c2ecf20Sopenharmony_ci if (sdev->id > adapter->init_id) { 40368c2ecf20Sopenharmony_ci mapped_sdev_id -= 1; 40378c2ecf20Sopenharmony_ci } 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_ci if (raid_dev->curr_ldmap[i] == mapped_sdev_id) { 40408c2ecf20Sopenharmony_ci 40418c2ecf20Sopenharmony_ci scsi_id = sdev->id; 40428c2ecf20Sopenharmony_ci 40438c2ecf20Sopenharmony_ci logical_drv = i; 40448c2ecf20Sopenharmony_ci 40458c2ecf20Sopenharmony_ci ldid_map = raid_dev->curr_ldmap[i]; 40468c2ecf20Sopenharmony_ci 40478c2ecf20Sopenharmony_ci app_hndl = mraid_mm_adapter_app_handle( 40488c2ecf20Sopenharmony_ci adapter->unique_id); 40498c2ecf20Sopenharmony_ci 40508c2ecf20Sopenharmony_ci break; 40518c2ecf20Sopenharmony_ci } 40528c2ecf20Sopenharmony_ci } 40538c2ecf20Sopenharmony_ci } 40548c2ecf20Sopenharmony_ci else { 40558c2ecf20Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 40568c2ecf20Sopenharmony_ci "megaraid: sysfs get ld map failed: %x\n", 40578c2ecf20Sopenharmony_ci rval)); 40588c2ecf20Sopenharmony_ci } 40598c2ecf20Sopenharmony_ci } 40608c2ecf20Sopenharmony_ci 40618c2ecf20Sopenharmony_ci return snprintf(buf, 36, "%d %d %d %d\n", scsi_id, logical_drv, 40628c2ecf20Sopenharmony_ci ldid_map, app_hndl); 40638c2ecf20Sopenharmony_ci} 40648c2ecf20Sopenharmony_ci 40658c2ecf20Sopenharmony_ci 40668c2ecf20Sopenharmony_ci/* 40678c2ecf20Sopenharmony_ci * END: Mailbox Low Level Driver 40688c2ecf20Sopenharmony_ci */ 40698c2ecf20Sopenharmony_cimodule_init(megaraid_init); 40708c2ecf20Sopenharmony_cimodule_exit(megaraid_exit); 40718c2ecf20Sopenharmony_ci 40728c2ecf20Sopenharmony_ci/* vim: set ts=8 sw=8 tw=78 ai si: */ 4073