162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Linux MegaRAID device driver 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 2003-2004 LSI Logic Corporation. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * FILE : megaraid_mbox.c 962306a36Sopenharmony_ci * Version : v2.20.5.1 (Nov 16 2006) 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Authors: 1262306a36Sopenharmony_ci * Atul Mukker <Atul.Mukker@lsi.com> 1362306a36Sopenharmony_ci * Sreenivas Bagalkote <Sreenivas.Bagalkote@lsi.com> 1462306a36Sopenharmony_ci * Manoj Jose <Manoj.Jose@lsi.com> 1562306a36Sopenharmony_ci * Seokmann Ju 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * List of supported controllers 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * OEM Product Name VID DID SSVID SSID 2062306a36Sopenharmony_ci * --- ------------ --- --- ---- ---- 2162306a36Sopenharmony_ci * Dell PERC3/QC 101E 1960 1028 0471 2262306a36Sopenharmony_ci * Dell PERC3/DC 101E 1960 1028 0493 2362306a36Sopenharmony_ci * Dell PERC3/SC 101E 1960 1028 0475 2462306a36Sopenharmony_ci * Dell PERC3/Di 1028 1960 1028 0123 2562306a36Sopenharmony_ci * Dell PERC4/SC 1000 1960 1028 0520 2662306a36Sopenharmony_ci * Dell PERC4/DC 1000 1960 1028 0518 2762306a36Sopenharmony_ci * Dell PERC4/QC 1000 0407 1028 0531 2862306a36Sopenharmony_ci * Dell PERC4/Di 1028 000F 1028 014A 2962306a36Sopenharmony_ci * Dell PERC 4e/Si 1028 0013 1028 016c 3062306a36Sopenharmony_ci * Dell PERC 4e/Di 1028 0013 1028 016d 3162306a36Sopenharmony_ci * Dell PERC 4e/Di 1028 0013 1028 016e 3262306a36Sopenharmony_ci * Dell PERC 4e/Di 1028 0013 1028 016f 3362306a36Sopenharmony_ci * Dell PERC 4e/Di 1028 0013 1028 0170 3462306a36Sopenharmony_ci * Dell PERC 4e/DC 1000 0408 1028 0002 3562306a36Sopenharmony_ci * Dell PERC 4e/SC 1000 0408 1028 0001 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * LSI MegaRAID SCSI 320-0 1000 1960 1000 A520 3862306a36Sopenharmony_ci * LSI MegaRAID SCSI 320-1 1000 1960 1000 0520 3962306a36Sopenharmony_ci * LSI MegaRAID SCSI 320-2 1000 1960 1000 0518 4062306a36Sopenharmony_ci * LSI MegaRAID SCSI 320-0X 1000 0407 1000 0530 4162306a36Sopenharmony_ci * LSI MegaRAID SCSI 320-2X 1000 0407 1000 0532 4262306a36Sopenharmony_ci * LSI MegaRAID SCSI 320-4X 1000 0407 1000 0531 4362306a36Sopenharmony_ci * LSI MegaRAID SCSI 320-1E 1000 0408 1000 0001 4462306a36Sopenharmony_ci * LSI MegaRAID SCSI 320-2E 1000 0408 1000 0002 4562306a36Sopenharmony_ci * LSI MegaRAID SATA 150-4 1000 1960 1000 4523 4662306a36Sopenharmony_ci * LSI MegaRAID SATA 150-6 1000 1960 1000 0523 4762306a36Sopenharmony_ci * LSI MegaRAID SATA 300-4X 1000 0409 1000 3004 4862306a36Sopenharmony_ci * LSI MegaRAID SATA 300-8X 1000 0409 1000 3008 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * INTEL RAID Controller SRCU42X 1000 0407 8086 0532 5162306a36Sopenharmony_ci * INTEL RAID Controller SRCS16 1000 1960 8086 0523 5262306a36Sopenharmony_ci * INTEL RAID Controller SRCU42E 1000 0408 8086 0002 5362306a36Sopenharmony_ci * INTEL RAID Controller SRCZCRX 1000 0407 8086 0530 5462306a36Sopenharmony_ci * INTEL RAID Controller SRCS28X 1000 0409 8086 3008 5562306a36Sopenharmony_ci * INTEL RAID Controller SROMBU42E 1000 0408 8086 3431 5662306a36Sopenharmony_ci * INTEL RAID Controller SROMBU42E 1000 0408 8086 3499 5762306a36Sopenharmony_ci * INTEL RAID Controller SRCU51L 1000 1960 8086 0520 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * FSC MegaRAID PCI Express ROMB 1000 0408 1734 1065 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * ACER MegaRAID ROMB-2E 1000 0408 1025 004D 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * NEC MegaRAID PCI Express ROMB 1000 0408 1033 8287 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * For history of changes, see Documentation/scsi/ChangeLog.megaraid 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#include <linux/slab.h> 6962306a36Sopenharmony_ci#include <linux/module.h> 7062306a36Sopenharmony_ci#include "megaraid_mbox.h" 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int megaraid_init(void); 7362306a36Sopenharmony_cistatic void megaraid_exit(void); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int megaraid_probe_one(struct pci_dev*, const struct pci_device_id *); 7662306a36Sopenharmony_cistatic void megaraid_detach_one(struct pci_dev *); 7762306a36Sopenharmony_cistatic void megaraid_mbox_shutdown(struct pci_dev *); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic int megaraid_io_attach(adapter_t *); 8062306a36Sopenharmony_cistatic void megaraid_io_detach(adapter_t *); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int megaraid_init_mbox(adapter_t *); 8362306a36Sopenharmony_cistatic void megaraid_fini_mbox(adapter_t *); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic int megaraid_alloc_cmd_packets(adapter_t *); 8662306a36Sopenharmony_cistatic void megaraid_free_cmd_packets(adapter_t *); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int megaraid_mbox_setup_dma_pools(adapter_t *); 8962306a36Sopenharmony_cistatic void megaraid_mbox_teardown_dma_pools(adapter_t *); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int megaraid_sysfs_alloc_resources(adapter_t *); 9262306a36Sopenharmony_cistatic void megaraid_sysfs_free_resources(adapter_t *); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int megaraid_abort_handler(struct scsi_cmnd *); 9562306a36Sopenharmony_cistatic int megaraid_reset_handler(struct scsi_cmnd *); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int mbox_post_sync_cmd(adapter_t *, uint8_t []); 9862306a36Sopenharmony_cistatic int mbox_post_sync_cmd_fast(adapter_t *, uint8_t []); 9962306a36Sopenharmony_cistatic int megaraid_busywait_mbox(mraid_device_t *); 10062306a36Sopenharmony_cistatic int megaraid_mbox_product_info(adapter_t *); 10162306a36Sopenharmony_cistatic int megaraid_mbox_extended_cdb(adapter_t *); 10262306a36Sopenharmony_cistatic int megaraid_mbox_support_ha(adapter_t *, uint16_t *); 10362306a36Sopenharmony_cistatic int megaraid_mbox_support_random_del(adapter_t *); 10462306a36Sopenharmony_cistatic int megaraid_mbox_get_max_sg(adapter_t *); 10562306a36Sopenharmony_cistatic void megaraid_mbox_enum_raid_scsi(adapter_t *); 10662306a36Sopenharmony_cistatic void megaraid_mbox_flush_cache(adapter_t *); 10762306a36Sopenharmony_cistatic int megaraid_mbox_fire_sync_cmd(adapter_t *); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void megaraid_mbox_display_scb(adapter_t *, scb_t *); 11062306a36Sopenharmony_cistatic void megaraid_mbox_setup_device_map(adapter_t *); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int megaraid_queue_command(struct Scsi_Host *, struct scsi_cmnd *); 11362306a36Sopenharmony_cistatic scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *); 11462306a36Sopenharmony_cistatic void megaraid_mbox_runpendq(adapter_t *, scb_t *); 11562306a36Sopenharmony_cistatic void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *, 11662306a36Sopenharmony_ci struct scsi_cmnd *); 11762306a36Sopenharmony_cistatic void megaraid_mbox_prepare_epthru(adapter_t *, scb_t *, 11862306a36Sopenharmony_ci struct scsi_cmnd *); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic irqreturn_t megaraid_isr(int, void *); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic void megaraid_mbox_dpc(unsigned long); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic ssize_t megaraid_mbox_app_hndl_show(struct device *, struct device_attribute *attr, char *); 12562306a36Sopenharmony_cistatic ssize_t megaraid_mbox_ld_show(struct device *, struct device_attribute *attr, char *); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int megaraid_cmm_register(adapter_t *); 12862306a36Sopenharmony_cistatic int megaraid_cmm_unregister(adapter_t *); 12962306a36Sopenharmony_cistatic int megaraid_mbox_mm_handler(unsigned long, uioc_t *, uint32_t); 13062306a36Sopenharmony_cistatic int megaraid_mbox_mm_command(adapter_t *, uioc_t *); 13162306a36Sopenharmony_cistatic void megaraid_mbox_mm_done(adapter_t *, scb_t *); 13262306a36Sopenharmony_cistatic int gather_hbainfo(adapter_t *, mraid_hba_info_t *); 13362306a36Sopenharmony_cistatic int wait_till_fw_empty(adapter_t *); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ciMODULE_AUTHOR("megaraidlinux@lsi.com"); 13862306a36Sopenharmony_ciMODULE_DESCRIPTION("LSI Logic MegaRAID Mailbox Driver"); 13962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 14062306a36Sopenharmony_ciMODULE_VERSION(MEGARAID_VERSION); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* 14362306a36Sopenharmony_ci * ### modules parameters for driver ### 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* 14762306a36Sopenharmony_ci * Set to enable driver to expose unconfigured disk to kernel 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_cistatic int megaraid_expose_unconf_disks = 0; 15062306a36Sopenharmony_cimodule_param_named(unconf_disks, megaraid_expose_unconf_disks, int, 0); 15162306a36Sopenharmony_ciMODULE_PARM_DESC(unconf_disks, 15262306a36Sopenharmony_ci "Set to expose unconfigured disks to kernel (default=0)"); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* 15562306a36Sopenharmony_ci * driver wait time if the adapter's mailbox is busy 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cistatic unsigned int max_mbox_busy_wait = MBOX_BUSY_WAIT; 15862306a36Sopenharmony_cimodule_param_named(busy_wait, max_mbox_busy_wait, int, 0); 15962306a36Sopenharmony_ciMODULE_PARM_DESC(busy_wait, 16062306a36Sopenharmony_ci "Max wait for mailbox in microseconds if busy (default=10)"); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* 16362306a36Sopenharmony_ci * number of sectors per IO command 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_cistatic unsigned int megaraid_max_sectors = MBOX_MAX_SECTORS; 16662306a36Sopenharmony_cimodule_param_named(max_sectors, megaraid_max_sectors, int, 0); 16762306a36Sopenharmony_ciMODULE_PARM_DESC(max_sectors, 16862306a36Sopenharmony_ci "Maximum number of sectors per IO command (default=128)"); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* 17162306a36Sopenharmony_ci * number of commands per logical unit 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_cistatic unsigned int megaraid_cmd_per_lun = MBOX_DEF_CMD_PER_LUN; 17462306a36Sopenharmony_cimodule_param_named(cmd_per_lun, megaraid_cmd_per_lun, int, 0); 17562306a36Sopenharmony_ciMODULE_PARM_DESC(cmd_per_lun, 17662306a36Sopenharmony_ci "Maximum number of commands per logical unit (default=64)"); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* 18062306a36Sopenharmony_ci * Fast driver load option, skip scanning for physical devices during load. 18162306a36Sopenharmony_ci * This would result in non-disk devices being skipped during driver load 18262306a36Sopenharmony_ci * time. These can be later added though, using /proc/scsi/scsi 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_cistatic unsigned int megaraid_fast_load; 18562306a36Sopenharmony_cimodule_param_named(fast_load, megaraid_fast_load, int, 0); 18662306a36Sopenharmony_ciMODULE_PARM_DESC(fast_load, 18762306a36Sopenharmony_ci "Faster loading of the driver, skips physical devices! (default=0)"); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* 19162306a36Sopenharmony_ci * mraid_debug level - threshold for amount of information to be displayed by 19262306a36Sopenharmony_ci * the driver. This level can be changed through modules parameters, ioctl or 19362306a36Sopenharmony_ci * sysfs/proc interface. By default, print the announcement messages only. 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_ciint mraid_debug_level = CL_ANN; 19662306a36Sopenharmony_cimodule_param_named(debug_level, mraid_debug_level, int, 0); 19762306a36Sopenharmony_ciMODULE_PARM_DESC(debug_level, "Debug level for driver (default=0)"); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/* 20062306a36Sopenharmony_ci * PCI table for all supported controllers. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_cistatic struct pci_device_id pci_id_table_g[] = { 20362306a36Sopenharmony_ci { 20462306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 20562306a36Sopenharmony_ci PCI_DEVICE_ID_PERC4_DI_DISCOVERY, 20662306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 20762306a36Sopenharmony_ci PCI_SUBSYS_ID_PERC4_DI_DISCOVERY, 20862306a36Sopenharmony_ci }, 20962306a36Sopenharmony_ci { 21062306a36Sopenharmony_ci PCI_VENDOR_ID_LSI_LOGIC, 21162306a36Sopenharmony_ci PCI_DEVICE_ID_PERC4_SC, 21262306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 21362306a36Sopenharmony_ci PCI_SUBSYS_ID_PERC4_SC, 21462306a36Sopenharmony_ci }, 21562306a36Sopenharmony_ci { 21662306a36Sopenharmony_ci PCI_VENDOR_ID_LSI_LOGIC, 21762306a36Sopenharmony_ci PCI_DEVICE_ID_PERC4_DC, 21862306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 21962306a36Sopenharmony_ci PCI_SUBSYS_ID_PERC4_DC, 22062306a36Sopenharmony_ci }, 22162306a36Sopenharmony_ci { 22262306a36Sopenharmony_ci PCI_VENDOR_ID_LSI_LOGIC, 22362306a36Sopenharmony_ci PCI_DEVICE_ID_VERDE, 22462306a36Sopenharmony_ci PCI_ANY_ID, 22562306a36Sopenharmony_ci PCI_ANY_ID, 22662306a36Sopenharmony_ci }, 22762306a36Sopenharmony_ci { 22862306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 22962306a36Sopenharmony_ci PCI_DEVICE_ID_PERC4_DI_EVERGLADES, 23062306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 23162306a36Sopenharmony_ci PCI_SUBSYS_ID_PERC4_DI_EVERGLADES, 23262306a36Sopenharmony_ci }, 23362306a36Sopenharmony_ci { 23462306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 23562306a36Sopenharmony_ci PCI_DEVICE_ID_PERC4E_SI_BIGBEND, 23662306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 23762306a36Sopenharmony_ci PCI_SUBSYS_ID_PERC4E_SI_BIGBEND, 23862306a36Sopenharmony_ci }, 23962306a36Sopenharmony_ci { 24062306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 24162306a36Sopenharmony_ci PCI_DEVICE_ID_PERC4E_DI_KOBUK, 24262306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 24362306a36Sopenharmony_ci PCI_SUBSYS_ID_PERC4E_DI_KOBUK, 24462306a36Sopenharmony_ci }, 24562306a36Sopenharmony_ci { 24662306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 24762306a36Sopenharmony_ci PCI_DEVICE_ID_PERC4E_DI_CORVETTE, 24862306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 24962306a36Sopenharmony_ci PCI_SUBSYS_ID_PERC4E_DI_CORVETTE, 25062306a36Sopenharmony_ci }, 25162306a36Sopenharmony_ci { 25262306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 25362306a36Sopenharmony_ci PCI_DEVICE_ID_PERC4E_DI_EXPEDITION, 25462306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 25562306a36Sopenharmony_ci PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION, 25662306a36Sopenharmony_ci }, 25762306a36Sopenharmony_ci { 25862306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 25962306a36Sopenharmony_ci PCI_DEVICE_ID_PERC4E_DI_GUADALUPE, 26062306a36Sopenharmony_ci PCI_VENDOR_ID_DELL, 26162306a36Sopenharmony_ci PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE, 26262306a36Sopenharmony_ci }, 26362306a36Sopenharmony_ci { 26462306a36Sopenharmony_ci PCI_VENDOR_ID_LSI_LOGIC, 26562306a36Sopenharmony_ci PCI_DEVICE_ID_DOBSON, 26662306a36Sopenharmony_ci PCI_ANY_ID, 26762306a36Sopenharmony_ci PCI_ANY_ID, 26862306a36Sopenharmony_ci }, 26962306a36Sopenharmony_ci { 27062306a36Sopenharmony_ci PCI_VENDOR_ID_AMI, 27162306a36Sopenharmony_ci PCI_DEVICE_ID_AMI_MEGARAID3, 27262306a36Sopenharmony_ci PCI_ANY_ID, 27362306a36Sopenharmony_ci PCI_ANY_ID, 27462306a36Sopenharmony_ci }, 27562306a36Sopenharmony_ci { 27662306a36Sopenharmony_ci PCI_VENDOR_ID_LSI_LOGIC, 27762306a36Sopenharmony_ci PCI_DEVICE_ID_AMI_MEGARAID3, 27862306a36Sopenharmony_ci PCI_ANY_ID, 27962306a36Sopenharmony_ci PCI_ANY_ID, 28062306a36Sopenharmony_ci }, 28162306a36Sopenharmony_ci { 28262306a36Sopenharmony_ci PCI_VENDOR_ID_LSI_LOGIC, 28362306a36Sopenharmony_ci PCI_DEVICE_ID_LINDSAY, 28462306a36Sopenharmony_ci PCI_ANY_ID, 28562306a36Sopenharmony_ci PCI_ANY_ID, 28662306a36Sopenharmony_ci }, 28762306a36Sopenharmony_ci {0} /* Terminating entry */ 28862306a36Sopenharmony_ci}; 28962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pci_id_table_g); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic struct pci_driver megaraid_pci_driver = { 29362306a36Sopenharmony_ci .name = "megaraid", 29462306a36Sopenharmony_ci .id_table = pci_id_table_g, 29562306a36Sopenharmony_ci .probe = megaraid_probe_one, 29662306a36Sopenharmony_ci .remove = megaraid_detach_one, 29762306a36Sopenharmony_ci .shutdown = megaraid_mbox_shutdown, 29862306a36Sopenharmony_ci}; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci// definitions for the device attributes for exporting logical drive number 30362306a36Sopenharmony_ci// for a scsi address (Host, Channel, Id, Lun) 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic DEVICE_ATTR_ADMIN_RO(megaraid_mbox_app_hndl); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci// Host template initializer for megaraid mbox sysfs device attributes 30862306a36Sopenharmony_cistatic struct attribute *megaraid_shost_attrs[] = { 30962306a36Sopenharmony_ci &dev_attr_megaraid_mbox_app_hndl.attr, 31062306a36Sopenharmony_ci NULL, 31162306a36Sopenharmony_ci}; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ciATTRIBUTE_GROUPS(megaraid_shost); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic DEVICE_ATTR_ADMIN_RO(megaraid_mbox_ld); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci// Host template initializer for megaraid mbox sysfs device attributes 31862306a36Sopenharmony_cistatic struct attribute *megaraid_sdev_attrs[] = { 31962306a36Sopenharmony_ci &dev_attr_megaraid_mbox_ld.attr, 32062306a36Sopenharmony_ci NULL, 32162306a36Sopenharmony_ci}; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ciATTRIBUTE_GROUPS(megaraid_sdev); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci/* 32662306a36Sopenharmony_ci * Scsi host template for megaraid unified driver 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_cistatic const struct scsi_host_template megaraid_template_g = { 32962306a36Sopenharmony_ci .module = THIS_MODULE, 33062306a36Sopenharmony_ci .name = "LSI Logic MegaRAID driver", 33162306a36Sopenharmony_ci .proc_name = "megaraid", 33262306a36Sopenharmony_ci .queuecommand = megaraid_queue_command, 33362306a36Sopenharmony_ci .eh_abort_handler = megaraid_abort_handler, 33462306a36Sopenharmony_ci .eh_host_reset_handler = megaraid_reset_handler, 33562306a36Sopenharmony_ci .change_queue_depth = scsi_change_queue_depth, 33662306a36Sopenharmony_ci .no_write_same = 1, 33762306a36Sopenharmony_ci .sdev_groups = megaraid_sdev_groups, 33862306a36Sopenharmony_ci .shost_groups = megaraid_shost_groups, 33962306a36Sopenharmony_ci}; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci/** 34362306a36Sopenharmony_ci * megaraid_init - module load hook 34462306a36Sopenharmony_ci * 34562306a36Sopenharmony_ci * We register ourselves as hotplug enabled module and let PCI subsystem 34662306a36Sopenharmony_ci * discover our adapters. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_cistatic int __init 34962306a36Sopenharmony_cimegaraid_init(void) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci int rval; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci // Announce the driver version 35462306a36Sopenharmony_ci con_log(CL_ANN, (KERN_INFO "megaraid: %s %s\n", MEGARAID_VERSION, 35562306a36Sopenharmony_ci MEGARAID_EXT_VERSION)); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci // check validity of module parameters 35862306a36Sopenharmony_ci if (megaraid_cmd_per_lun > MBOX_MAX_SCSI_CMDS) { 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 36162306a36Sopenharmony_ci "megaraid mailbox: max commands per lun reset to %d\n", 36262306a36Sopenharmony_ci MBOX_MAX_SCSI_CMDS)); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci megaraid_cmd_per_lun = MBOX_MAX_SCSI_CMDS; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci // register as a PCI hot-plug driver module 36962306a36Sopenharmony_ci rval = pci_register_driver(&megaraid_pci_driver); 37062306a36Sopenharmony_ci if (rval < 0) { 37162306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 37262306a36Sopenharmony_ci "megaraid: could not register hotplug support.\n")); 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci return rval; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/** 38062306a36Sopenharmony_ci * megaraid_exit - driver unload entry point 38162306a36Sopenharmony_ci * 38262306a36Sopenharmony_ci * We simply unwrap the megaraid_init routine here. 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_cistatic void __exit 38562306a36Sopenharmony_cimegaraid_exit(void) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n")); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci // unregister as PCI hotplug driver 39062306a36Sopenharmony_ci pci_unregister_driver(&megaraid_pci_driver); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci return; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/** 39762306a36Sopenharmony_ci * megaraid_probe_one - PCI hotplug entry point 39862306a36Sopenharmony_ci * @pdev : handle to this controller's PCI configuration space 39962306a36Sopenharmony_ci * @id : pci device id of the class of controllers 40062306a36Sopenharmony_ci * 40162306a36Sopenharmony_ci * This routine should be called whenever a new adapter is detected by the 40262306a36Sopenharmony_ci * PCI hotplug susbsystem. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_cistatic int 40562306a36Sopenharmony_cimegaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci adapter_t *adapter; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci // detected a new controller 41162306a36Sopenharmony_ci con_log(CL_ANN, (KERN_INFO 41262306a36Sopenharmony_ci "megaraid: probe new device %#4.04x:%#4.04x:%#4.04x:%#4.04x: ", 41362306a36Sopenharmony_ci pdev->vendor, pdev->device, pdev->subsystem_vendor, 41462306a36Sopenharmony_ci pdev->subsystem_device)); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci con_log(CL_ANN, ("bus %d:slot %d:func %d\n", pdev->bus->number, 41762306a36Sopenharmony_ci PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn))); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (pci_enable_device(pdev)) { 42062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 42162306a36Sopenharmony_ci "megaraid: pci_enable_device failed\n")); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci return -ENODEV; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci // Enable bus-mastering on this controller 42762306a36Sopenharmony_ci pci_set_master(pdev); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci // Allocate the per driver initialization structure 43062306a36Sopenharmony_ci adapter = kzalloc(sizeof(adapter_t), GFP_KERNEL); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (adapter == NULL) { 43362306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 43462306a36Sopenharmony_ci "megaraid: out of memory, %s %d.\n", __func__, __LINE__)); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci goto out_probe_one; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci // set up PCI related soft state and other pre-known parameters 44162306a36Sopenharmony_ci adapter->unique_id = pci_dev_id(pdev); 44262306a36Sopenharmony_ci adapter->irq = pdev->irq; 44362306a36Sopenharmony_ci adapter->pdev = pdev; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci atomic_set(&adapter->being_detached, 0); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci // Setup the default DMA mask. This would be changed later on 44862306a36Sopenharmony_ci // depending on hardware capabilities 44962306a36Sopenharmony_ci if (dma_set_mask(&adapter->pdev->dev, DMA_BIT_MASK(32))) { 45062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 45162306a36Sopenharmony_ci "megaraid: dma_set_mask failed:%d\n", __LINE__)); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci goto out_free_adapter; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci // Initialize the synchronization lock for kernel and LLD 45862306a36Sopenharmony_ci spin_lock_init(&adapter->lock); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci // Initialize the command queues: the list of free SCBs and the list 46162306a36Sopenharmony_ci // of pending SCBs. 46262306a36Sopenharmony_ci INIT_LIST_HEAD(&adapter->kscb_pool); 46362306a36Sopenharmony_ci spin_lock_init(SCSI_FREE_LIST_LOCK(adapter)); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci INIT_LIST_HEAD(&adapter->pend_list); 46662306a36Sopenharmony_ci spin_lock_init(PENDING_LIST_LOCK(adapter)); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci INIT_LIST_HEAD(&adapter->completed_list); 46962306a36Sopenharmony_ci spin_lock_init(COMPLETED_LIST_LOCK(adapter)); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci // Start the mailbox based controller 47362306a36Sopenharmony_ci if (megaraid_init_mbox(adapter) != 0) { 47462306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 47562306a36Sopenharmony_ci "megaraid: mailbox adapter did not initialize\n")); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci goto out_free_adapter; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci // Register with LSI Common Management Module 48162306a36Sopenharmony_ci if (megaraid_cmm_register(adapter) != 0) { 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 48462306a36Sopenharmony_ci "megaraid: could not register with management module\n")); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci goto out_fini_mbox; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci // setup adapter handle in PCI soft state 49062306a36Sopenharmony_ci pci_set_drvdata(pdev, adapter); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci // attach with scsi mid-layer 49362306a36Sopenharmony_ci if (megaraid_io_attach(adapter) != 0) { 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING "megaraid: io attach failed\n")); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci goto out_cmm_unreg; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ciout_cmm_unreg: 50362306a36Sopenharmony_ci megaraid_cmm_unregister(adapter); 50462306a36Sopenharmony_ciout_fini_mbox: 50562306a36Sopenharmony_ci megaraid_fini_mbox(adapter); 50662306a36Sopenharmony_ciout_free_adapter: 50762306a36Sopenharmony_ci kfree(adapter); 50862306a36Sopenharmony_ciout_probe_one: 50962306a36Sopenharmony_ci pci_disable_device(pdev); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci return -ENODEV; 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci/** 51662306a36Sopenharmony_ci * megaraid_detach_one - release framework resources and call LLD release routine 51762306a36Sopenharmony_ci * @pdev : handle for our PCI configuration space 51862306a36Sopenharmony_ci * 51962306a36Sopenharmony_ci * This routine is called during driver unload. We free all the allocated 52062306a36Sopenharmony_ci * resources and call the corresponding LLD so that it can also release all 52162306a36Sopenharmony_ci * its resources. 52262306a36Sopenharmony_ci * 52362306a36Sopenharmony_ci * This routine is also called from the PCI hotplug system. 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_cistatic void 52662306a36Sopenharmony_cimegaraid_detach_one(struct pci_dev *pdev) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci adapter_t *adapter; 52962306a36Sopenharmony_ci struct Scsi_Host *host; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci // Start a rollback on this adapter 53362306a36Sopenharmony_ci adapter = pci_get_drvdata(pdev); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (!adapter) { 53662306a36Sopenharmony_ci con_log(CL_ANN, (KERN_CRIT 53762306a36Sopenharmony_ci "megaraid: Invalid detach on %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", 53862306a36Sopenharmony_ci pdev->vendor, pdev->device, pdev->subsystem_vendor, 53962306a36Sopenharmony_ci pdev->subsystem_device)); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci return; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci else { 54462306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 54562306a36Sopenharmony_ci "megaraid: detaching device %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", 54662306a36Sopenharmony_ci pdev->vendor, pdev->device, pdev->subsystem_vendor, 54762306a36Sopenharmony_ci pdev->subsystem_device)); 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci host = adapter->host; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci // do not allow any more requests from the management module for this 55462306a36Sopenharmony_ci // adapter. 55562306a36Sopenharmony_ci // FIXME: How do we account for the request which might still be 55662306a36Sopenharmony_ci // pending with us? 55762306a36Sopenharmony_ci atomic_set(&adapter->being_detached, 1); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci // detach from the IO sub-system 56062306a36Sopenharmony_ci megaraid_io_detach(adapter); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci // Unregister from common management module 56362306a36Sopenharmony_ci // 56462306a36Sopenharmony_ci // FIXME: this must return success or failure for conditions if there 56562306a36Sopenharmony_ci // is a command pending with LLD or not. 56662306a36Sopenharmony_ci megaraid_cmm_unregister(adapter); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci // finalize the mailbox based controller and release all resources 56962306a36Sopenharmony_ci megaraid_fini_mbox(adapter); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci kfree(adapter); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci scsi_host_put(host); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci pci_disable_device(pdev); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci/** 58262306a36Sopenharmony_ci * megaraid_mbox_shutdown - PCI shutdown for megaraid HBA 58362306a36Sopenharmony_ci * @pdev : generic driver model device 58462306a36Sopenharmony_ci * 58562306a36Sopenharmony_ci * Shutdown notification, perform flush cache. 58662306a36Sopenharmony_ci */ 58762306a36Sopenharmony_cistatic void 58862306a36Sopenharmony_cimegaraid_mbox_shutdown(struct pci_dev *pdev) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci adapter_t *adapter = pci_get_drvdata(pdev); 59162306a36Sopenharmony_ci static int counter; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (!adapter) { 59462306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 59562306a36Sopenharmony_ci "megaraid: null device in shutdown\n")); 59662306a36Sopenharmony_ci return; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci // flush caches now 60062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_INFO "megaraid: flushing adapter %d...", 60162306a36Sopenharmony_ci counter++)); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci megaraid_mbox_flush_cache(adapter); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci con_log(CL_ANN, ("done\n")); 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci/** 61062306a36Sopenharmony_ci * megaraid_io_attach - attach a device with the IO subsystem 61162306a36Sopenharmony_ci * @adapter : controller's soft state 61262306a36Sopenharmony_ci * 61362306a36Sopenharmony_ci * Attach this device with the IO subsystem. 61462306a36Sopenharmony_ci */ 61562306a36Sopenharmony_cistatic int 61662306a36Sopenharmony_cimegaraid_io_attach(adapter_t *adapter) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci struct Scsi_Host *host; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci // Initialize SCSI Host structure 62162306a36Sopenharmony_ci host = scsi_host_alloc(&megaraid_template_g, 8); 62262306a36Sopenharmony_ci if (!host) { 62362306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 62462306a36Sopenharmony_ci "megaraid mbox: scsi_register failed\n")); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci return -1; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci SCSIHOST2ADAP(host) = (caddr_t)adapter; 63062306a36Sopenharmony_ci adapter->host = host; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci host->irq = adapter->irq; 63362306a36Sopenharmony_ci host->unique_id = adapter->unique_id; 63462306a36Sopenharmony_ci host->can_queue = adapter->max_cmds; 63562306a36Sopenharmony_ci host->this_id = adapter->init_id; 63662306a36Sopenharmony_ci host->sg_tablesize = adapter->sglen; 63762306a36Sopenharmony_ci host->max_sectors = adapter->max_sectors; 63862306a36Sopenharmony_ci host->cmd_per_lun = adapter->cmd_per_lun; 63962306a36Sopenharmony_ci host->max_channel = adapter->max_channel; 64062306a36Sopenharmony_ci host->max_id = adapter->max_target; 64162306a36Sopenharmony_ci host->max_lun = adapter->max_lun; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci // notify mid-layer about the new controller 64562306a36Sopenharmony_ci if (scsi_add_host(host, &adapter->pdev->dev)) { 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 64862306a36Sopenharmony_ci "megaraid mbox: scsi_add_host failed\n")); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci scsi_host_put(host); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci return -1; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci scsi_scan_host(host); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return 0; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci/** 66262306a36Sopenharmony_ci * megaraid_io_detach - detach a device from the IO subsystem 66362306a36Sopenharmony_ci * @adapter : controller's soft state 66462306a36Sopenharmony_ci * 66562306a36Sopenharmony_ci * Detach this device from the IO subsystem. 66662306a36Sopenharmony_ci */ 66762306a36Sopenharmony_cistatic void 66862306a36Sopenharmony_cimegaraid_io_detach(adapter_t *adapter) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci struct Scsi_Host *host; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci con_log(CL_DLEVEL1, (KERN_INFO "megaraid: io detach\n")); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci host = adapter->host; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci scsi_remove_host(host); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci return; 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci/* 68362306a36Sopenharmony_ci * START: Mailbox Low Level Driver 68462306a36Sopenharmony_ci * 68562306a36Sopenharmony_ci * This is section specific to the single mailbox based controllers 68662306a36Sopenharmony_ci */ 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci/** 68962306a36Sopenharmony_ci * megaraid_init_mbox - initialize controller 69062306a36Sopenharmony_ci * @adapter : our soft state 69162306a36Sopenharmony_ci * 69262306a36Sopenharmony_ci * - Allocate 16-byte aligned mailbox memory for firmware handshake 69362306a36Sopenharmony_ci * - Allocate controller's memory resources 69462306a36Sopenharmony_ci * - Find out all initialization data 69562306a36Sopenharmony_ci * - Allocate memory required for all the commands 69662306a36Sopenharmony_ci * - Use internal library of FW routines, build up complete soft state 69762306a36Sopenharmony_ci */ 69862306a36Sopenharmony_cistatic int 69962306a36Sopenharmony_cimegaraid_init_mbox(adapter_t *adapter) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci struct pci_dev *pdev; 70262306a36Sopenharmony_ci mraid_device_t *raid_dev; 70362306a36Sopenharmony_ci int i; 70462306a36Sopenharmony_ci uint32_t magic64; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci adapter->ito = MBOX_TIMEOUT; 70862306a36Sopenharmony_ci pdev = adapter->pdev; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* 71162306a36Sopenharmony_ci * Allocate and initialize the init data structure for mailbox 71262306a36Sopenharmony_ci * controllers 71362306a36Sopenharmony_ci */ 71462306a36Sopenharmony_ci raid_dev = kzalloc(sizeof(mraid_device_t), GFP_KERNEL); 71562306a36Sopenharmony_ci if (raid_dev == NULL) return -1; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* 71962306a36Sopenharmony_ci * Attach the adapter soft state to raid device soft state 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_ci adapter->raid_device = (caddr_t)raid_dev; 72262306a36Sopenharmony_ci raid_dev->fast_load = megaraid_fast_load; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci // our baseport 72662306a36Sopenharmony_ci raid_dev->baseport = pci_resource_start(pdev, 0); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (pci_request_regions(pdev, "MegaRAID: LSI Logic Corporation") != 0) { 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 73162306a36Sopenharmony_ci "megaraid: mem region busy\n")); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci goto out_free_raid_dev; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci raid_dev->baseaddr = ioremap(raid_dev->baseport, 128); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (!raid_dev->baseaddr) { 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 74162306a36Sopenharmony_ci "megaraid: could not map hba memory\n") ); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci goto out_release_regions; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* initialize the mutual exclusion lock for the mailbox */ 74762306a36Sopenharmony_ci spin_lock_init(&raid_dev->mailbox_lock); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci /* allocate memory required for commands */ 75062306a36Sopenharmony_ci if (megaraid_alloc_cmd_packets(adapter) != 0) 75162306a36Sopenharmony_ci goto out_iounmap; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* 75462306a36Sopenharmony_ci * Issue SYNC cmd to flush the pending cmds in the adapter 75562306a36Sopenharmony_ci * and initialize its internal state 75662306a36Sopenharmony_ci */ 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (megaraid_mbox_fire_sync_cmd(adapter)) 75962306a36Sopenharmony_ci con_log(CL_ANN, ("megaraid: sync cmd failed\n")); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* 76262306a36Sopenharmony_ci * Setup the rest of the soft state using the library of 76362306a36Sopenharmony_ci * FW routines 76462306a36Sopenharmony_ci */ 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* request IRQ and register the interrupt service routine */ 76762306a36Sopenharmony_ci if (request_irq(adapter->irq, megaraid_isr, IRQF_SHARED, "megaraid", 76862306a36Sopenharmony_ci adapter)) { 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 77162306a36Sopenharmony_ci "megaraid: Couldn't register IRQ %d!\n", adapter->irq)); 77262306a36Sopenharmony_ci goto out_alloc_cmds; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci // Product info 77762306a36Sopenharmony_ci if (megaraid_mbox_product_info(adapter) != 0) 77862306a36Sopenharmony_ci goto out_free_irq; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci // Do we support extended CDBs 78162306a36Sopenharmony_ci adapter->max_cdb_sz = 10; 78262306a36Sopenharmony_ci if (megaraid_mbox_extended_cdb(adapter) == 0) { 78362306a36Sopenharmony_ci adapter->max_cdb_sz = 16; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* 78762306a36Sopenharmony_ci * Do we support cluster environment, if we do, what is the initiator 78862306a36Sopenharmony_ci * id. 78962306a36Sopenharmony_ci * NOTE: In a non-cluster aware firmware environment, the LLD should 79062306a36Sopenharmony_ci * return 7 as initiator id. 79162306a36Sopenharmony_ci */ 79262306a36Sopenharmony_ci adapter->ha = 0; 79362306a36Sopenharmony_ci adapter->init_id = -1; 79462306a36Sopenharmony_ci if (megaraid_mbox_support_ha(adapter, &adapter->init_id) == 0) { 79562306a36Sopenharmony_ci adapter->ha = 1; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci /* 79962306a36Sopenharmony_ci * Prepare the device ids array to have the mapping between the kernel 80062306a36Sopenharmony_ci * device address and megaraid device address. 80162306a36Sopenharmony_ci * We export the physical devices on their actual addresses. The 80262306a36Sopenharmony_ci * logical drives are exported on a virtual SCSI channel 80362306a36Sopenharmony_ci */ 80462306a36Sopenharmony_ci megaraid_mbox_setup_device_map(adapter); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci // If the firmware supports random deletion, update the device id map 80762306a36Sopenharmony_ci if (megaraid_mbox_support_random_del(adapter)) { 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci // Change the logical drives numbers in device_ids array one 81062306a36Sopenharmony_ci // slot in device_ids is reserved for target id, that's why 81162306a36Sopenharmony_ci // "<=" below 81262306a36Sopenharmony_ci for (i = 0; i <= MAX_LOGICAL_DRIVES_40LD; i++) { 81362306a36Sopenharmony_ci adapter->device_ids[adapter->max_channel][i] += 0x80; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci adapter->device_ids[adapter->max_channel][adapter->init_id] = 81662306a36Sopenharmony_ci 0xFF; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci raid_dev->random_del_supported = 1; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci /* 82262306a36Sopenharmony_ci * find out the maximum number of scatter-gather elements supported by 82362306a36Sopenharmony_ci * this firmware 82462306a36Sopenharmony_ci */ 82562306a36Sopenharmony_ci adapter->sglen = megaraid_mbox_get_max_sg(adapter); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci // enumerate RAID and SCSI channels so that all devices on SCSI 82862306a36Sopenharmony_ci // channels can later be exported, including disk devices 82962306a36Sopenharmony_ci megaraid_mbox_enum_raid_scsi(adapter); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* 83262306a36Sopenharmony_ci * Other parameters required by upper layer 83362306a36Sopenharmony_ci * 83462306a36Sopenharmony_ci * maximum number of sectors per IO command 83562306a36Sopenharmony_ci */ 83662306a36Sopenharmony_ci adapter->max_sectors = megaraid_max_sectors; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci /* 83962306a36Sopenharmony_ci * number of queued commands per LUN. 84062306a36Sopenharmony_ci */ 84162306a36Sopenharmony_ci adapter->cmd_per_lun = megaraid_cmd_per_lun; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci /* 84462306a36Sopenharmony_ci * Allocate resources required to issue FW calls, when sysfs is 84562306a36Sopenharmony_ci * accessed 84662306a36Sopenharmony_ci */ 84762306a36Sopenharmony_ci if (megaraid_sysfs_alloc_resources(adapter) != 0) 84862306a36Sopenharmony_ci goto out_free_irq; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci // Set the DMA mask to 64-bit. All supported controllers as capable of 85162306a36Sopenharmony_ci // DMA in this range 85262306a36Sopenharmony_ci pci_read_config_dword(adapter->pdev, PCI_CONF_AMISIG64, &magic64); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (((magic64 == HBA_SIGNATURE_64_BIT) && 85562306a36Sopenharmony_ci ((adapter->pdev->subsystem_device != 85662306a36Sopenharmony_ci PCI_SUBSYS_ID_MEGARAID_SATA_150_6) && 85762306a36Sopenharmony_ci (adapter->pdev->subsystem_device != 85862306a36Sopenharmony_ci PCI_SUBSYS_ID_MEGARAID_SATA_150_4))) || 85962306a36Sopenharmony_ci (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && 86062306a36Sopenharmony_ci adapter->pdev->device == PCI_DEVICE_ID_VERDE) || 86162306a36Sopenharmony_ci (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && 86262306a36Sopenharmony_ci adapter->pdev->device == PCI_DEVICE_ID_DOBSON) || 86362306a36Sopenharmony_ci (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && 86462306a36Sopenharmony_ci adapter->pdev->device == PCI_DEVICE_ID_LINDSAY) || 86562306a36Sopenharmony_ci (adapter->pdev->vendor == PCI_VENDOR_ID_DELL && 86662306a36Sopenharmony_ci adapter->pdev->device == PCI_DEVICE_ID_PERC4_DI_EVERGLADES) || 86762306a36Sopenharmony_ci (adapter->pdev->vendor == PCI_VENDOR_ID_DELL && 86862306a36Sopenharmony_ci adapter->pdev->device == PCI_DEVICE_ID_PERC4E_DI_KOBUK)) { 86962306a36Sopenharmony_ci if (dma_set_mask(&adapter->pdev->dev, DMA_BIT_MASK(64))) { 87062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 87162306a36Sopenharmony_ci "megaraid: DMA mask for 64-bit failed\n")); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (dma_set_mask(&adapter->pdev->dev, 87462306a36Sopenharmony_ci DMA_BIT_MASK(32))) { 87562306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 87662306a36Sopenharmony_ci "megaraid: 32-bit DMA mask failed\n")); 87762306a36Sopenharmony_ci goto out_free_sysfs_res; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci // setup tasklet for DPC 88362306a36Sopenharmony_ci tasklet_init(&adapter->dpc_h, megaraid_mbox_dpc, 88462306a36Sopenharmony_ci (unsigned long)adapter); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci con_log(CL_DLEVEL1, (KERN_INFO 88762306a36Sopenharmony_ci "megaraid mbox hba successfully initialized\n")); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci return 0; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ciout_free_sysfs_res: 89262306a36Sopenharmony_ci megaraid_sysfs_free_resources(adapter); 89362306a36Sopenharmony_ciout_free_irq: 89462306a36Sopenharmony_ci free_irq(adapter->irq, adapter); 89562306a36Sopenharmony_ciout_alloc_cmds: 89662306a36Sopenharmony_ci megaraid_free_cmd_packets(adapter); 89762306a36Sopenharmony_ciout_iounmap: 89862306a36Sopenharmony_ci iounmap(raid_dev->baseaddr); 89962306a36Sopenharmony_ciout_release_regions: 90062306a36Sopenharmony_ci pci_release_regions(pdev); 90162306a36Sopenharmony_ciout_free_raid_dev: 90262306a36Sopenharmony_ci kfree(raid_dev); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci return -1; 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci/** 90962306a36Sopenharmony_ci * megaraid_fini_mbox - undo controller initialization 91062306a36Sopenharmony_ci * @adapter : our soft state 91162306a36Sopenharmony_ci */ 91262306a36Sopenharmony_cistatic void 91362306a36Sopenharmony_cimegaraid_fini_mbox(adapter_t *adapter) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci // flush all caches 91862306a36Sopenharmony_ci megaraid_mbox_flush_cache(adapter); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci tasklet_kill(&adapter->dpc_h); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci megaraid_sysfs_free_resources(adapter); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci megaraid_free_cmd_packets(adapter); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci free_irq(adapter->irq, adapter); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci iounmap(raid_dev->baseaddr); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci pci_release_regions(adapter->pdev); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci kfree(raid_dev); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci return; 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci/** 93962306a36Sopenharmony_ci * megaraid_alloc_cmd_packets - allocate shared mailbox 94062306a36Sopenharmony_ci * @adapter : soft state of the raid controller 94162306a36Sopenharmony_ci * 94262306a36Sopenharmony_ci * Allocate and align the shared mailbox. This mailbox is used to issue 94362306a36Sopenharmony_ci * all the commands. For IO based controllers, the mailbox is also registered 94462306a36Sopenharmony_ci * with the FW. Allocate memory for all commands as well. 94562306a36Sopenharmony_ci * This is our big allocator. 94662306a36Sopenharmony_ci */ 94762306a36Sopenharmony_cistatic int 94862306a36Sopenharmony_cimegaraid_alloc_cmd_packets(adapter_t *adapter) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 95162306a36Sopenharmony_ci struct pci_dev *pdev; 95262306a36Sopenharmony_ci unsigned long align; 95362306a36Sopenharmony_ci scb_t *scb; 95462306a36Sopenharmony_ci mbox_ccb_t *ccb; 95562306a36Sopenharmony_ci struct mraid_pci_blk *epthru_pci_blk; 95662306a36Sopenharmony_ci struct mraid_pci_blk *sg_pci_blk; 95762306a36Sopenharmony_ci struct mraid_pci_blk *mbox_pci_blk; 95862306a36Sopenharmony_ci int i; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci pdev = adapter->pdev; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci /* 96362306a36Sopenharmony_ci * Setup the mailbox 96462306a36Sopenharmony_ci * Allocate the common 16-byte aligned memory for the handshake 96562306a36Sopenharmony_ci * mailbox. 96662306a36Sopenharmony_ci */ 96762306a36Sopenharmony_ci raid_dev->una_mbox64 = dma_alloc_coherent(&adapter->pdev->dev, 96862306a36Sopenharmony_ci sizeof(mbox64_t), 96962306a36Sopenharmony_ci &raid_dev->una_mbox64_dma, 97062306a36Sopenharmony_ci GFP_KERNEL); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (!raid_dev->una_mbox64) { 97362306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 97462306a36Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 97562306a36Sopenharmony_ci __LINE__)); 97662306a36Sopenharmony_ci return -1; 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci /* 98062306a36Sopenharmony_ci * Align the mailbox at 16-byte boundary 98162306a36Sopenharmony_ci */ 98262306a36Sopenharmony_ci raid_dev->mbox = &raid_dev->una_mbox64->mbox32; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci raid_dev->mbox = (mbox_t *)((((unsigned long)raid_dev->mbox) + 15) & 98562306a36Sopenharmony_ci (~0UL ^ 0xFUL)); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci raid_dev->mbox64 = (mbox64_t *)(((unsigned long)raid_dev->mbox) - 8); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci align = ((void *)raid_dev->mbox - 99062306a36Sopenharmony_ci ((void *)&raid_dev->una_mbox64->mbox32)); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci raid_dev->mbox_dma = (unsigned long)raid_dev->una_mbox64_dma + 8 + 99362306a36Sopenharmony_ci align; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci // Allocate memory for commands issued internally 99662306a36Sopenharmony_ci adapter->ibuf = dma_alloc_coherent(&pdev->dev, MBOX_IBUF_SIZE, 99762306a36Sopenharmony_ci &adapter->ibuf_dma_h, GFP_KERNEL); 99862306a36Sopenharmony_ci if (!adapter->ibuf) { 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 100162306a36Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 100262306a36Sopenharmony_ci __LINE__)); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci goto out_free_common_mbox; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci // Allocate memory for our SCSI Command Blocks and their associated 100862306a36Sopenharmony_ci // memory 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci /* 101162306a36Sopenharmony_ci * Allocate memory for the base list of scb. Later allocate memory for 101262306a36Sopenharmony_ci * CCBs and embedded components of each CCB and point the pointers in 101362306a36Sopenharmony_ci * scb to the allocated components 101462306a36Sopenharmony_ci * NOTE: The code to allocate SCB will be duplicated in all the LLD 101562306a36Sopenharmony_ci * since the calling routine does not yet know the number of available 101662306a36Sopenharmony_ci * commands. 101762306a36Sopenharmony_ci */ 101862306a36Sopenharmony_ci adapter->kscb_list = kcalloc(MBOX_MAX_SCSI_CMDS, sizeof(scb_t), GFP_KERNEL); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci if (adapter->kscb_list == NULL) { 102162306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 102262306a36Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 102362306a36Sopenharmony_ci __LINE__)); 102462306a36Sopenharmony_ci goto out_free_ibuf; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci // memory allocation for our command packets 102862306a36Sopenharmony_ci if (megaraid_mbox_setup_dma_pools(adapter) != 0) { 102962306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 103062306a36Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 103162306a36Sopenharmony_ci __LINE__)); 103262306a36Sopenharmony_ci goto out_free_scb_list; 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci // Adjust the scb pointers and link in the free pool 103662306a36Sopenharmony_ci epthru_pci_blk = raid_dev->epthru_pool; 103762306a36Sopenharmony_ci sg_pci_blk = raid_dev->sg_pool; 103862306a36Sopenharmony_ci mbox_pci_blk = raid_dev->mbox_pool; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { 104162306a36Sopenharmony_ci scb = adapter->kscb_list + i; 104262306a36Sopenharmony_ci ccb = raid_dev->ccb_list + i; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci ccb->mbox = (mbox_t *)(mbox_pci_blk[i].vaddr + 16); 104562306a36Sopenharmony_ci ccb->raw_mbox = (uint8_t *)ccb->mbox; 104662306a36Sopenharmony_ci ccb->mbox64 = (mbox64_t *)(mbox_pci_blk[i].vaddr + 8); 104762306a36Sopenharmony_ci ccb->mbox_dma_h = (unsigned long)mbox_pci_blk[i].dma_addr + 16; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci // make sure the mailbox is aligned properly 105062306a36Sopenharmony_ci if (ccb->mbox_dma_h & 0x0F) { 105162306a36Sopenharmony_ci con_log(CL_ANN, (KERN_CRIT 105262306a36Sopenharmony_ci "megaraid mbox: not aligned on 16-bytes\n")); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci goto out_teardown_dma_pools; 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci ccb->epthru = (mraid_epassthru_t *) 105862306a36Sopenharmony_ci epthru_pci_blk[i].vaddr; 105962306a36Sopenharmony_ci ccb->epthru_dma_h = epthru_pci_blk[i].dma_addr; 106062306a36Sopenharmony_ci ccb->pthru = (mraid_passthru_t *)ccb->epthru; 106162306a36Sopenharmony_ci ccb->pthru_dma_h = ccb->epthru_dma_h; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci ccb->sgl64 = (mbox_sgl64 *)sg_pci_blk[i].vaddr; 106562306a36Sopenharmony_ci ccb->sgl_dma_h = sg_pci_blk[i].dma_addr; 106662306a36Sopenharmony_ci ccb->sgl32 = (mbox_sgl32 *)ccb->sgl64; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci scb->ccb = (caddr_t)ccb; 106962306a36Sopenharmony_ci scb->gp = 0; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci scb->sno = i; // command index 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci scb->scp = NULL; 107462306a36Sopenharmony_ci scb->state = SCB_FREE; 107562306a36Sopenharmony_ci scb->dma_direction = DMA_NONE; 107662306a36Sopenharmony_ci scb->dma_type = MRAID_DMA_NONE; 107762306a36Sopenharmony_ci scb->dev_channel = -1; 107862306a36Sopenharmony_ci scb->dev_target = -1; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci // put scb in the free pool 108162306a36Sopenharmony_ci list_add_tail(&scb->list, &adapter->kscb_pool); 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci return 0; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ciout_teardown_dma_pools: 108762306a36Sopenharmony_ci megaraid_mbox_teardown_dma_pools(adapter); 108862306a36Sopenharmony_ciout_free_scb_list: 108962306a36Sopenharmony_ci kfree(adapter->kscb_list); 109062306a36Sopenharmony_ciout_free_ibuf: 109162306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, MBOX_IBUF_SIZE, (void *)adapter->ibuf, 109262306a36Sopenharmony_ci adapter->ibuf_dma_h); 109362306a36Sopenharmony_ciout_free_common_mbox: 109462306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, sizeof(mbox64_t), 109562306a36Sopenharmony_ci (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci return -1; 109862306a36Sopenharmony_ci} 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci/** 110262306a36Sopenharmony_ci * megaraid_free_cmd_packets - free memory 110362306a36Sopenharmony_ci * @adapter : soft state of the raid controller 110462306a36Sopenharmony_ci * 110562306a36Sopenharmony_ci * Release memory resources allocated for commands. 110662306a36Sopenharmony_ci */ 110762306a36Sopenharmony_cistatic void 110862306a36Sopenharmony_cimegaraid_free_cmd_packets(adapter_t *adapter) 110962306a36Sopenharmony_ci{ 111062306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci megaraid_mbox_teardown_dma_pools(adapter); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci kfree(adapter->kscb_list); 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, MBOX_IBUF_SIZE, 111762306a36Sopenharmony_ci (void *)adapter->ibuf, adapter->ibuf_dma_h); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, sizeof(mbox64_t), 112062306a36Sopenharmony_ci (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma); 112162306a36Sopenharmony_ci return; 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci/** 112662306a36Sopenharmony_ci * megaraid_mbox_setup_dma_pools - setup dma pool for command packets 112762306a36Sopenharmony_ci * @adapter : HBA soft state 112862306a36Sopenharmony_ci * 112962306a36Sopenharmony_ci * Setup the dma pools for mailbox, passthru and extended passthru structures, 113062306a36Sopenharmony_ci * and scatter-gather lists. 113162306a36Sopenharmony_ci */ 113262306a36Sopenharmony_cistatic int 113362306a36Sopenharmony_cimegaraid_mbox_setup_dma_pools(adapter_t *adapter) 113462306a36Sopenharmony_ci{ 113562306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 113662306a36Sopenharmony_ci struct mraid_pci_blk *epthru_pci_blk; 113762306a36Sopenharmony_ci struct mraid_pci_blk *sg_pci_blk; 113862306a36Sopenharmony_ci struct mraid_pci_blk *mbox_pci_blk; 113962306a36Sopenharmony_ci int i; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci // Allocate memory for 16-bytes aligned mailboxes 114462306a36Sopenharmony_ci raid_dev->mbox_pool_handle = dma_pool_create("megaraid mbox pool", 114562306a36Sopenharmony_ci &adapter->pdev->dev, 114662306a36Sopenharmony_ci sizeof(mbox64_t) + 16, 114762306a36Sopenharmony_ci 16, 0); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci if (raid_dev->mbox_pool_handle == NULL) { 115062306a36Sopenharmony_ci goto fail_setup_dma_pool; 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci mbox_pci_blk = raid_dev->mbox_pool; 115462306a36Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { 115562306a36Sopenharmony_ci mbox_pci_blk[i].vaddr = dma_pool_alloc( 115662306a36Sopenharmony_ci raid_dev->mbox_pool_handle, 115762306a36Sopenharmony_ci GFP_KERNEL, 115862306a36Sopenharmony_ci &mbox_pci_blk[i].dma_addr); 115962306a36Sopenharmony_ci if (!mbox_pci_blk[i].vaddr) { 116062306a36Sopenharmony_ci goto fail_setup_dma_pool; 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* 116562306a36Sopenharmony_ci * Allocate memory for each embedded passthru strucuture pointer 116662306a36Sopenharmony_ci * Request for a 128 bytes aligned structure for each passthru command 116762306a36Sopenharmony_ci * structure 116862306a36Sopenharmony_ci * Since passthru and extended passthru commands are exclusive, they 116962306a36Sopenharmony_ci * share common memory pool. Passthru structures piggyback on memory 117062306a36Sopenharmony_ci * allocated to extended passthru since passthru is smaller of the two 117162306a36Sopenharmony_ci */ 117262306a36Sopenharmony_ci raid_dev->epthru_pool_handle = dma_pool_create("megaraid mbox pthru", 117362306a36Sopenharmony_ci &adapter->pdev->dev, sizeof(mraid_epassthru_t), 128, 0); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (raid_dev->epthru_pool_handle == NULL) { 117662306a36Sopenharmony_ci goto fail_setup_dma_pool; 117762306a36Sopenharmony_ci } 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci epthru_pci_blk = raid_dev->epthru_pool; 118062306a36Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { 118162306a36Sopenharmony_ci epthru_pci_blk[i].vaddr = dma_pool_alloc( 118262306a36Sopenharmony_ci raid_dev->epthru_pool_handle, 118362306a36Sopenharmony_ci GFP_KERNEL, 118462306a36Sopenharmony_ci &epthru_pci_blk[i].dma_addr); 118562306a36Sopenharmony_ci if (!epthru_pci_blk[i].vaddr) { 118662306a36Sopenharmony_ci goto fail_setup_dma_pool; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci // Allocate memory for each scatter-gather list. Request for 512 bytes 119262306a36Sopenharmony_ci // alignment for each sg list 119362306a36Sopenharmony_ci raid_dev->sg_pool_handle = dma_pool_create("megaraid mbox sg", 119462306a36Sopenharmony_ci &adapter->pdev->dev, 119562306a36Sopenharmony_ci sizeof(mbox_sgl64) * MBOX_MAX_SG_SIZE, 119662306a36Sopenharmony_ci 512, 0); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci if (raid_dev->sg_pool_handle == NULL) { 119962306a36Sopenharmony_ci goto fail_setup_dma_pool; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci sg_pci_blk = raid_dev->sg_pool; 120362306a36Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { 120462306a36Sopenharmony_ci sg_pci_blk[i].vaddr = dma_pool_alloc( 120562306a36Sopenharmony_ci raid_dev->sg_pool_handle, 120662306a36Sopenharmony_ci GFP_KERNEL, 120762306a36Sopenharmony_ci &sg_pci_blk[i].dma_addr); 120862306a36Sopenharmony_ci if (!sg_pci_blk[i].vaddr) { 120962306a36Sopenharmony_ci goto fail_setup_dma_pool; 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci return 0; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cifail_setup_dma_pool: 121662306a36Sopenharmony_ci megaraid_mbox_teardown_dma_pools(adapter); 121762306a36Sopenharmony_ci return -1; 121862306a36Sopenharmony_ci} 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci/** 122262306a36Sopenharmony_ci * megaraid_mbox_teardown_dma_pools - teardown dma pools for command packets 122362306a36Sopenharmony_ci * @adapter : HBA soft state 122462306a36Sopenharmony_ci * 122562306a36Sopenharmony_ci * Teardown the dma pool for mailbox, passthru and extended passthru 122662306a36Sopenharmony_ci * structures, and scatter-gather lists. 122762306a36Sopenharmony_ci */ 122862306a36Sopenharmony_cistatic void 122962306a36Sopenharmony_cimegaraid_mbox_teardown_dma_pools(adapter_t *adapter) 123062306a36Sopenharmony_ci{ 123162306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 123262306a36Sopenharmony_ci struct mraid_pci_blk *epthru_pci_blk; 123362306a36Sopenharmony_ci struct mraid_pci_blk *sg_pci_blk; 123462306a36Sopenharmony_ci struct mraid_pci_blk *mbox_pci_blk; 123562306a36Sopenharmony_ci int i; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci sg_pci_blk = raid_dev->sg_pool; 123962306a36Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS && sg_pci_blk[i].vaddr; i++) { 124062306a36Sopenharmony_ci dma_pool_free(raid_dev->sg_pool_handle, sg_pci_blk[i].vaddr, 124162306a36Sopenharmony_ci sg_pci_blk[i].dma_addr); 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci dma_pool_destroy(raid_dev->sg_pool_handle); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci epthru_pci_blk = raid_dev->epthru_pool; 124762306a36Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS && epthru_pci_blk[i].vaddr; i++) { 124862306a36Sopenharmony_ci dma_pool_free(raid_dev->epthru_pool_handle, 124962306a36Sopenharmony_ci epthru_pci_blk[i].vaddr, epthru_pci_blk[i].dma_addr); 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci dma_pool_destroy(raid_dev->epthru_pool_handle); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci mbox_pci_blk = raid_dev->mbox_pool; 125562306a36Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS && mbox_pci_blk[i].vaddr; i++) { 125662306a36Sopenharmony_ci dma_pool_free(raid_dev->mbox_pool_handle, 125762306a36Sopenharmony_ci mbox_pci_blk[i].vaddr, mbox_pci_blk[i].dma_addr); 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci dma_pool_destroy(raid_dev->mbox_pool_handle); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci return; 126262306a36Sopenharmony_ci} 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci/** 126662306a36Sopenharmony_ci * megaraid_alloc_scb - detach and return a scb from the free list 126762306a36Sopenharmony_ci * @adapter : controller's soft state 126862306a36Sopenharmony_ci * @scp : pointer to the scsi command to be executed 126962306a36Sopenharmony_ci * 127062306a36Sopenharmony_ci * Return the scb from the head of the free list. %NULL if there are none 127162306a36Sopenharmony_ci * available. 127262306a36Sopenharmony_ci */ 127362306a36Sopenharmony_cistatic scb_t * 127462306a36Sopenharmony_cimegaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp) 127562306a36Sopenharmony_ci{ 127662306a36Sopenharmony_ci struct list_head *head = &adapter->kscb_pool; 127762306a36Sopenharmony_ci scb_t *scb = NULL; 127862306a36Sopenharmony_ci unsigned long flags; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci // detach scb from free pool 128162306a36Sopenharmony_ci spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci if (list_empty(head)) { 128462306a36Sopenharmony_ci spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); 128562306a36Sopenharmony_ci return NULL; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci scb = list_entry(head->next, scb_t, list); 128962306a36Sopenharmony_ci list_del_init(&scb->list); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci scb->state = SCB_ACTIVE; 129462306a36Sopenharmony_ci scb->scp = scp; 129562306a36Sopenharmony_ci scb->dma_type = MRAID_DMA_NONE; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci return scb; 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci/** 130262306a36Sopenharmony_ci * megaraid_dealloc_scb - return the scb to the free pool 130362306a36Sopenharmony_ci * @adapter : controller's soft state 130462306a36Sopenharmony_ci * @scb : scb to be freed 130562306a36Sopenharmony_ci * 130662306a36Sopenharmony_ci * Return the scb back to the free list of scbs. The caller must 'flush' the 130762306a36Sopenharmony_ci * SCB before calling us. E.g., performing pci_unamp and/or pci_sync etc. 130862306a36Sopenharmony_ci * NOTE NOTE: Make sure the scb is not on any list before calling this 130962306a36Sopenharmony_ci * routine. 131062306a36Sopenharmony_ci */ 131162306a36Sopenharmony_cistatic inline void 131262306a36Sopenharmony_cimegaraid_dealloc_scb(adapter_t *adapter, scb_t *scb) 131362306a36Sopenharmony_ci{ 131462306a36Sopenharmony_ci unsigned long flags; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci // put scb in the free pool 131762306a36Sopenharmony_ci scb->state = SCB_FREE; 131862306a36Sopenharmony_ci scb->scp = NULL; 131962306a36Sopenharmony_ci spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci list_add(&scb->list, &adapter->kscb_pool); 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci return; 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci/** 133062306a36Sopenharmony_ci * megaraid_mbox_mksgl - make the scatter-gather list 133162306a36Sopenharmony_ci * @adapter : controller's soft state 133262306a36Sopenharmony_ci * @scb : scsi control block 133362306a36Sopenharmony_ci * 133462306a36Sopenharmony_ci * Prepare the scatter-gather list. 133562306a36Sopenharmony_ci */ 133662306a36Sopenharmony_cistatic int 133762306a36Sopenharmony_cimegaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb) 133862306a36Sopenharmony_ci{ 133962306a36Sopenharmony_ci struct scatterlist *sgl; 134062306a36Sopenharmony_ci mbox_ccb_t *ccb; 134162306a36Sopenharmony_ci struct scsi_cmnd *scp; 134262306a36Sopenharmony_ci int sgcnt; 134362306a36Sopenharmony_ci int i; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci scp = scb->scp; 134762306a36Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci sgcnt = scsi_dma_map(scp); 135062306a36Sopenharmony_ci BUG_ON(sgcnt < 0 || sgcnt > adapter->sglen); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci // no mapping required if no data to be transferred 135362306a36Sopenharmony_ci if (!sgcnt) 135462306a36Sopenharmony_ci return 0; 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci scb->dma_type = MRAID_DMA_WSG; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci scsi_for_each_sg(scp, sgl, sgcnt, i) { 135962306a36Sopenharmony_ci ccb->sgl64[i].address = sg_dma_address(sgl); 136062306a36Sopenharmony_ci ccb->sgl64[i].length = sg_dma_len(sgl); 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci // Return count of SG nodes 136462306a36Sopenharmony_ci return sgcnt; 136562306a36Sopenharmony_ci} 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci/** 136962306a36Sopenharmony_ci * mbox_post_cmd - issue a mailbox command 137062306a36Sopenharmony_ci * @adapter : controller's soft state 137162306a36Sopenharmony_ci * @scb : command to be issued 137262306a36Sopenharmony_ci * 137362306a36Sopenharmony_ci * Post the command to the controller if mailbox is available. 137462306a36Sopenharmony_ci */ 137562306a36Sopenharmony_cistatic int 137662306a36Sopenharmony_cimbox_post_cmd(adapter_t *adapter, scb_t *scb) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 137962306a36Sopenharmony_ci mbox64_t *mbox64; 138062306a36Sopenharmony_ci mbox_t *mbox; 138162306a36Sopenharmony_ci mbox_ccb_t *ccb; 138262306a36Sopenharmony_ci unsigned long flags; 138362306a36Sopenharmony_ci unsigned int i = 0; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 138762306a36Sopenharmony_ci mbox = raid_dev->mbox; 138862306a36Sopenharmony_ci mbox64 = raid_dev->mbox64; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci /* 139162306a36Sopenharmony_ci * Check for busy mailbox. If it is, return failure - the caller 139262306a36Sopenharmony_ci * should retry later. 139362306a36Sopenharmony_ci */ 139462306a36Sopenharmony_ci spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci if (unlikely(mbox->busy)) { 139762306a36Sopenharmony_ci do { 139862306a36Sopenharmony_ci udelay(1); 139962306a36Sopenharmony_ci i++; 140062306a36Sopenharmony_ci rmb(); 140162306a36Sopenharmony_ci } while(mbox->busy && (i < max_mbox_busy_wait)); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (mbox->busy) { 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci return -1; 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci // Copy this command's mailbox data into "adapter's" mailbox 141362306a36Sopenharmony_ci memcpy((caddr_t)mbox64, (caddr_t)ccb->mbox64, 22); 141462306a36Sopenharmony_ci mbox->cmdid = scb->sno; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci adapter->outstanding_cmds++; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci mbox->busy = 1; // Set busy 141962306a36Sopenharmony_ci mbox->poll = 0; 142062306a36Sopenharmony_ci mbox->ack = 0; 142162306a36Sopenharmony_ci wmb(); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci return 0; 142862306a36Sopenharmony_ci} 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci/** 143262306a36Sopenharmony_ci * megaraid_queue_command_lck - generic queue entry point for all LLDs 143362306a36Sopenharmony_ci * @scp : pointer to the scsi command to be executed 143462306a36Sopenharmony_ci * 143562306a36Sopenharmony_ci * Queue entry point for mailbox based controllers. 143662306a36Sopenharmony_ci */ 143762306a36Sopenharmony_cistatic int megaraid_queue_command_lck(struct scsi_cmnd *scp) 143862306a36Sopenharmony_ci{ 143962306a36Sopenharmony_ci void (*done)(struct scsi_cmnd *) = scsi_done; 144062306a36Sopenharmony_ci adapter_t *adapter; 144162306a36Sopenharmony_ci scb_t *scb; 144262306a36Sopenharmony_ci int if_busy; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci adapter = SCP2ADAPTER(scp); 144562306a36Sopenharmony_ci scp->result = 0; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci /* 144862306a36Sopenharmony_ci * Allocate and build a SCB request 144962306a36Sopenharmony_ci * if_busy flag will be set if megaraid_mbox_build_cmd() command could 145062306a36Sopenharmony_ci * not allocate scb. We will return non-zero status in that case. 145162306a36Sopenharmony_ci * NOTE: scb can be null even though certain commands completed 145262306a36Sopenharmony_ci * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, it would 145362306a36Sopenharmony_ci * return 0 in that case, and we would do the callback right away. 145462306a36Sopenharmony_ci */ 145562306a36Sopenharmony_ci if_busy = 0; 145662306a36Sopenharmony_ci scb = megaraid_mbox_build_cmd(adapter, scp, &if_busy); 145762306a36Sopenharmony_ci if (!scb) { // command already completed 145862306a36Sopenharmony_ci done(scp); 145962306a36Sopenharmony_ci return 0; 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci megaraid_mbox_runpendq(adapter, scb); 146362306a36Sopenharmony_ci return if_busy; 146462306a36Sopenharmony_ci} 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_cistatic DEF_SCSI_QCMD(megaraid_queue_command) 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci/** 146962306a36Sopenharmony_ci * megaraid_mbox_build_cmd - transform the mid-layer scsi commands 147062306a36Sopenharmony_ci * @adapter : controller's soft state 147162306a36Sopenharmony_ci * @scp : mid-layer scsi command pointer 147262306a36Sopenharmony_ci * @busy : set if request could not be completed because of lack of 147362306a36Sopenharmony_ci * resources 147462306a36Sopenharmony_ci * 147562306a36Sopenharmony_ci * Transform the mid-layer scsi command to megaraid firmware lingua. 147662306a36Sopenharmony_ci * Convert the command issued by mid-layer to format understood by megaraid 147762306a36Sopenharmony_ci * firmware. We also complete certain commands without sending them to firmware. 147862306a36Sopenharmony_ci */ 147962306a36Sopenharmony_cistatic scb_t * 148062306a36Sopenharmony_cimegaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) 148162306a36Sopenharmony_ci{ 148262306a36Sopenharmony_ci mraid_device_t *rdev = ADAP2RAIDDEV(adapter); 148362306a36Sopenharmony_ci int channel; 148462306a36Sopenharmony_ci int target; 148562306a36Sopenharmony_ci int islogical; 148662306a36Sopenharmony_ci mbox_ccb_t *ccb; 148762306a36Sopenharmony_ci mraid_passthru_t *pthru; 148862306a36Sopenharmony_ci mbox64_t *mbox64; 148962306a36Sopenharmony_ci mbox_t *mbox; 149062306a36Sopenharmony_ci scb_t *scb; 149162306a36Sopenharmony_ci char skip[] = "skipping"; 149262306a36Sopenharmony_ci char scan[] = "scanning"; 149362306a36Sopenharmony_ci char *ss; 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci /* 149762306a36Sopenharmony_ci * Get the appropriate device map for the device this command is 149862306a36Sopenharmony_ci * intended for 149962306a36Sopenharmony_ci */ 150062306a36Sopenharmony_ci MRAID_GET_DEVICE_MAP(adapter, scp, channel, target, islogical); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci /* 150362306a36Sopenharmony_ci * Logical drive commands 150462306a36Sopenharmony_ci */ 150562306a36Sopenharmony_ci if (islogical) { 150662306a36Sopenharmony_ci switch (scp->cmnd[0]) { 150762306a36Sopenharmony_ci case TEST_UNIT_READY: 150862306a36Sopenharmony_ci /* 150962306a36Sopenharmony_ci * Do we support clustering and is the support enabled 151062306a36Sopenharmony_ci * If no, return success always 151162306a36Sopenharmony_ci */ 151262306a36Sopenharmony_ci if (!adapter->ha) { 151362306a36Sopenharmony_ci scp->result = (DID_OK << 16); 151462306a36Sopenharmony_ci return NULL; 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci if (!(scb = megaraid_alloc_scb(adapter, scp))) { 151862306a36Sopenharmony_ci scp->result = (DID_ERROR << 16); 151962306a36Sopenharmony_ci *busy = 1; 152062306a36Sopenharmony_ci return NULL; 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci scb->dma_direction = scp->sc_data_direction; 152462306a36Sopenharmony_ci scb->dev_channel = 0xFF; 152562306a36Sopenharmony_ci scb->dev_target = target; 152662306a36Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci /* 152962306a36Sopenharmony_ci * The command id will be provided by the command 153062306a36Sopenharmony_ci * issuance routine 153162306a36Sopenharmony_ci */ 153262306a36Sopenharmony_ci ccb->raw_mbox[0] = CLUSTER_CMD; 153362306a36Sopenharmony_ci ccb->raw_mbox[2] = RESERVATION_STATUS; 153462306a36Sopenharmony_ci ccb->raw_mbox[3] = target; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci return scb; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci case MODE_SENSE: 153962306a36Sopenharmony_ci { 154062306a36Sopenharmony_ci struct scatterlist *sgl; 154162306a36Sopenharmony_ci caddr_t vaddr; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci sgl = scsi_sglist(scp); 154462306a36Sopenharmony_ci if (sg_page(sgl)) { 154562306a36Sopenharmony_ci vaddr = (caddr_t) sg_virt(&sgl[0]); 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci memset(vaddr, 0, scp->cmnd[4]); 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci else { 155062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 155162306a36Sopenharmony_ci "megaraid mailbox: invalid sg:%d\n", 155262306a36Sopenharmony_ci __LINE__)); 155362306a36Sopenharmony_ci } 155462306a36Sopenharmony_ci } 155562306a36Sopenharmony_ci scp->result = (DID_OK << 16); 155662306a36Sopenharmony_ci return NULL; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci case INQUIRY: 155962306a36Sopenharmony_ci /* 156062306a36Sopenharmony_ci * Display the channel scan for logical drives 156162306a36Sopenharmony_ci * Do not display scan for a channel if already done. 156262306a36Sopenharmony_ci */ 156362306a36Sopenharmony_ci if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) { 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci con_log(CL_ANN, (KERN_INFO 156662306a36Sopenharmony_ci "scsi[%d]: scanning scsi channel %d", 156762306a36Sopenharmony_ci adapter->host->host_no, 156862306a36Sopenharmony_ci SCP2CHANNEL(scp))); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci con_log(CL_ANN, ( 157162306a36Sopenharmony_ci " [virtual] for logical drives\n")); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci rdev->last_disp |= (1L << SCP2CHANNEL(scp)); 157462306a36Sopenharmony_ci } 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci if (scp->cmnd[1] & MEGA_SCSI_INQ_EVPD) { 157762306a36Sopenharmony_ci scsi_build_sense(scp, 0, ILLEGAL_REQUEST, 157862306a36Sopenharmony_ci MEGA_INVALID_FIELD_IN_CDB, 0); 157962306a36Sopenharmony_ci return NULL; 158062306a36Sopenharmony_ci } 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci fallthrough; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci case READ_CAPACITY: 158562306a36Sopenharmony_ci /* 158662306a36Sopenharmony_ci * Do not allow LUN > 0 for logical drives and 158762306a36Sopenharmony_ci * requests for more than 40 logical drives 158862306a36Sopenharmony_ci */ 158962306a36Sopenharmony_ci if (SCP2LUN(scp)) { 159062306a36Sopenharmony_ci scp->result = (DID_BAD_TARGET << 16); 159162306a36Sopenharmony_ci return NULL; 159262306a36Sopenharmony_ci } 159362306a36Sopenharmony_ci if ((target % 0x80) >= MAX_LOGICAL_DRIVES_40LD) { 159462306a36Sopenharmony_ci scp->result = (DID_BAD_TARGET << 16); 159562306a36Sopenharmony_ci return NULL; 159662306a36Sopenharmony_ci } 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci /* Allocate a SCB and initialize passthru */ 160062306a36Sopenharmony_ci if (!(scb = megaraid_alloc_scb(adapter, scp))) { 160162306a36Sopenharmony_ci scp->result = (DID_ERROR << 16); 160262306a36Sopenharmony_ci *busy = 1; 160362306a36Sopenharmony_ci return NULL; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 160762306a36Sopenharmony_ci scb->dev_channel = 0xFF; 160862306a36Sopenharmony_ci scb->dev_target = target; 160962306a36Sopenharmony_ci pthru = ccb->pthru; 161062306a36Sopenharmony_ci mbox = ccb->mbox; 161162306a36Sopenharmony_ci mbox64 = ccb->mbox64; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci pthru->timeout = 0; 161462306a36Sopenharmony_ci pthru->ars = 1; 161562306a36Sopenharmony_ci pthru->reqsenselen = 14; 161662306a36Sopenharmony_ci pthru->islogical = 1; 161762306a36Sopenharmony_ci pthru->logdrv = target; 161862306a36Sopenharmony_ci pthru->cdblen = scp->cmd_len; 161962306a36Sopenharmony_ci memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci mbox->cmd = MBOXCMD_PASSTHRU64; 162262306a36Sopenharmony_ci scb->dma_direction = scp->sc_data_direction; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci pthru->dataxferlen = scsi_bufflen(scp); 162562306a36Sopenharmony_ci pthru->dataxferaddr = ccb->sgl_dma_h; 162662306a36Sopenharmony_ci pthru->numsge = megaraid_mbox_mksgl(adapter, 162762306a36Sopenharmony_ci scb); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci mbox->xferaddr = 0xFFFFFFFF; 163062306a36Sopenharmony_ci mbox64->xferaddr_lo = (uint32_t )ccb->pthru_dma_h; 163162306a36Sopenharmony_ci mbox64->xferaddr_hi = 0; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci return scb; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci case READ_6: 163662306a36Sopenharmony_ci case WRITE_6: 163762306a36Sopenharmony_ci case READ_10: 163862306a36Sopenharmony_ci case WRITE_10: 163962306a36Sopenharmony_ci case READ_12: 164062306a36Sopenharmony_ci case WRITE_12: 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci /* 164362306a36Sopenharmony_ci * Allocate a SCB and initialize mailbox 164462306a36Sopenharmony_ci */ 164562306a36Sopenharmony_ci if (!(scb = megaraid_alloc_scb(adapter, scp))) { 164662306a36Sopenharmony_ci scp->result = (DID_ERROR << 16); 164762306a36Sopenharmony_ci *busy = 1; 164862306a36Sopenharmony_ci return NULL; 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 165162306a36Sopenharmony_ci scb->dev_channel = 0xFF; 165262306a36Sopenharmony_ci scb->dev_target = target; 165362306a36Sopenharmony_ci mbox = ccb->mbox; 165462306a36Sopenharmony_ci mbox64 = ccb->mbox64; 165562306a36Sopenharmony_ci mbox->logdrv = target; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci /* 165862306a36Sopenharmony_ci * A little HACK: 2nd bit is zero for all scsi read 165962306a36Sopenharmony_ci * commands and is set for all scsi write commands 166062306a36Sopenharmony_ci */ 166162306a36Sopenharmony_ci mbox->cmd = (scp->cmnd[0] & 0x02) ? MBOXCMD_LWRITE64: 166262306a36Sopenharmony_ci MBOXCMD_LREAD64 ; 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci /* 166562306a36Sopenharmony_ci * 6-byte READ(0x08) or WRITE(0x0A) cdb 166662306a36Sopenharmony_ci */ 166762306a36Sopenharmony_ci if (scp->cmd_len == 6) { 166862306a36Sopenharmony_ci mbox->numsectors = (uint32_t)scp->cmnd[4]; 166962306a36Sopenharmony_ci mbox->lba = 167062306a36Sopenharmony_ci ((uint32_t)scp->cmnd[1] << 16) | 167162306a36Sopenharmony_ci ((uint32_t)scp->cmnd[2] << 8) | 167262306a36Sopenharmony_ci (uint32_t)scp->cmnd[3]; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci mbox->lba &= 0x1FFFFF; 167562306a36Sopenharmony_ci } 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci /* 167862306a36Sopenharmony_ci * 10-byte READ(0x28) or WRITE(0x2A) cdb 167962306a36Sopenharmony_ci */ 168062306a36Sopenharmony_ci else if (scp->cmd_len == 10) { 168162306a36Sopenharmony_ci mbox->numsectors = 168262306a36Sopenharmony_ci (uint32_t)scp->cmnd[8] | 168362306a36Sopenharmony_ci ((uint32_t)scp->cmnd[7] << 8); 168462306a36Sopenharmony_ci mbox->lba = 168562306a36Sopenharmony_ci ((uint32_t)scp->cmnd[2] << 24) | 168662306a36Sopenharmony_ci ((uint32_t)scp->cmnd[3] << 16) | 168762306a36Sopenharmony_ci ((uint32_t)scp->cmnd[4] << 8) | 168862306a36Sopenharmony_ci (uint32_t)scp->cmnd[5]; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci /* 169262306a36Sopenharmony_ci * 12-byte READ(0xA8) or WRITE(0xAA) cdb 169362306a36Sopenharmony_ci */ 169462306a36Sopenharmony_ci else if (scp->cmd_len == 12) { 169562306a36Sopenharmony_ci mbox->lba = 169662306a36Sopenharmony_ci ((uint32_t)scp->cmnd[2] << 24) | 169762306a36Sopenharmony_ci ((uint32_t)scp->cmnd[3] << 16) | 169862306a36Sopenharmony_ci ((uint32_t)scp->cmnd[4] << 8) | 169962306a36Sopenharmony_ci (uint32_t)scp->cmnd[5]; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci mbox->numsectors = 170262306a36Sopenharmony_ci ((uint32_t)scp->cmnd[6] << 24) | 170362306a36Sopenharmony_ci ((uint32_t)scp->cmnd[7] << 16) | 170462306a36Sopenharmony_ci ((uint32_t)scp->cmnd[8] << 8) | 170562306a36Sopenharmony_ci (uint32_t)scp->cmnd[9]; 170662306a36Sopenharmony_ci } 170762306a36Sopenharmony_ci else { 170862306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 170962306a36Sopenharmony_ci "megaraid: unsupported CDB length\n")); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci megaraid_dealloc_scb(adapter, scb); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci scp->result = (DID_ERROR << 16); 171462306a36Sopenharmony_ci return NULL; 171562306a36Sopenharmony_ci } 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci scb->dma_direction = scp->sc_data_direction; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci // Calculate Scatter-Gather info 172062306a36Sopenharmony_ci mbox64->xferaddr_lo = (uint32_t )ccb->sgl_dma_h; 172162306a36Sopenharmony_ci mbox->numsge = megaraid_mbox_mksgl(adapter, 172262306a36Sopenharmony_ci scb); 172362306a36Sopenharmony_ci mbox->xferaddr = 0xFFFFFFFF; 172462306a36Sopenharmony_ci mbox64->xferaddr_hi = 0; 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci return scb; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci case RESERVE: 172962306a36Sopenharmony_ci case RELEASE: 173062306a36Sopenharmony_ci /* 173162306a36Sopenharmony_ci * Do we support clustering and is the support enabled 173262306a36Sopenharmony_ci */ 173362306a36Sopenharmony_ci if (!adapter->ha) { 173462306a36Sopenharmony_ci scp->result = (DID_BAD_TARGET << 16); 173562306a36Sopenharmony_ci return NULL; 173662306a36Sopenharmony_ci } 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci /* 173962306a36Sopenharmony_ci * Allocate a SCB and initialize mailbox 174062306a36Sopenharmony_ci */ 174162306a36Sopenharmony_ci if (!(scb = megaraid_alloc_scb(adapter, scp))) { 174262306a36Sopenharmony_ci scp->result = (DID_ERROR << 16); 174362306a36Sopenharmony_ci *busy = 1; 174462306a36Sopenharmony_ci return NULL; 174562306a36Sopenharmony_ci } 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 174862306a36Sopenharmony_ci scb->dev_channel = 0xFF; 174962306a36Sopenharmony_ci scb->dev_target = target; 175062306a36Sopenharmony_ci ccb->raw_mbox[0] = CLUSTER_CMD; 175162306a36Sopenharmony_ci ccb->raw_mbox[2] = (scp->cmnd[0] == RESERVE) ? 175262306a36Sopenharmony_ci RESERVE_LD : RELEASE_LD; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci ccb->raw_mbox[3] = target; 175562306a36Sopenharmony_ci scb->dma_direction = scp->sc_data_direction; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci return scb; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci default: 176062306a36Sopenharmony_ci scp->result = (DID_BAD_TARGET << 16); 176162306a36Sopenharmony_ci return NULL; 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci } 176462306a36Sopenharmony_ci else { // Passthru device commands 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci // Do not allow access to target id > 15 or LUN > 7 176762306a36Sopenharmony_ci if (target > 15 || SCP2LUN(scp) > 7) { 176862306a36Sopenharmony_ci scp->result = (DID_BAD_TARGET << 16); 176962306a36Sopenharmony_ci return NULL; 177062306a36Sopenharmony_ci } 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci // if fast load option was set and scan for last device is 177362306a36Sopenharmony_ci // over, reset the fast_load flag so that during a possible 177462306a36Sopenharmony_ci // next scan, devices can be made available 177562306a36Sopenharmony_ci if (rdev->fast_load && (target == 15) && 177662306a36Sopenharmony_ci (SCP2CHANNEL(scp) == adapter->max_channel -1)) { 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci con_log(CL_ANN, (KERN_INFO 177962306a36Sopenharmony_ci "megaraid[%d]: physical device scan re-enabled\n", 178062306a36Sopenharmony_ci adapter->host->host_no)); 178162306a36Sopenharmony_ci rdev->fast_load = 0; 178262306a36Sopenharmony_ci } 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci /* 178562306a36Sopenharmony_ci * Display the channel scan for physical devices 178662306a36Sopenharmony_ci */ 178762306a36Sopenharmony_ci if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) { 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci ss = rdev->fast_load ? skip : scan; 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci con_log(CL_ANN, (KERN_INFO 179262306a36Sopenharmony_ci "scsi[%d]: %s scsi channel %d [Phy %d]", 179362306a36Sopenharmony_ci adapter->host->host_no, ss, SCP2CHANNEL(scp), 179462306a36Sopenharmony_ci channel)); 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci con_log(CL_ANN, ( 179762306a36Sopenharmony_ci " for non-raid devices\n")); 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci rdev->last_disp |= (1L << SCP2CHANNEL(scp)); 180062306a36Sopenharmony_ci } 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci // disable channel sweep if fast load option given 180362306a36Sopenharmony_ci if (rdev->fast_load) { 180462306a36Sopenharmony_ci scp->result = (DID_BAD_TARGET << 16); 180562306a36Sopenharmony_ci return NULL; 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci // Allocate a SCB and initialize passthru 180962306a36Sopenharmony_ci if (!(scb = megaraid_alloc_scb(adapter, scp))) { 181062306a36Sopenharmony_ci scp->result = (DID_ERROR << 16); 181162306a36Sopenharmony_ci *busy = 1; 181262306a36Sopenharmony_ci return NULL; 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 181662306a36Sopenharmony_ci scb->dev_channel = channel; 181762306a36Sopenharmony_ci scb->dev_target = target; 181862306a36Sopenharmony_ci scb->dma_direction = scp->sc_data_direction; 181962306a36Sopenharmony_ci mbox = ccb->mbox; 182062306a36Sopenharmony_ci mbox64 = ccb->mbox64; 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci // Does this firmware support extended CDBs 182362306a36Sopenharmony_ci if (adapter->max_cdb_sz == 16) { 182462306a36Sopenharmony_ci mbox->cmd = MBOXCMD_EXTPTHRU; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci megaraid_mbox_prepare_epthru(adapter, scb, scp); 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci mbox64->xferaddr_lo = (uint32_t)ccb->epthru_dma_h; 182962306a36Sopenharmony_ci mbox64->xferaddr_hi = 0; 183062306a36Sopenharmony_ci mbox->xferaddr = 0xFFFFFFFF; 183162306a36Sopenharmony_ci } 183262306a36Sopenharmony_ci else { 183362306a36Sopenharmony_ci mbox->cmd = MBOXCMD_PASSTHRU64; 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci megaraid_mbox_prepare_pthru(adapter, scb, scp); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci mbox64->xferaddr_lo = (uint32_t)ccb->pthru_dma_h; 183862306a36Sopenharmony_ci mbox64->xferaddr_hi = 0; 183962306a36Sopenharmony_ci mbox->xferaddr = 0xFFFFFFFF; 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci return scb; 184262306a36Sopenharmony_ci } 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci // NOT REACHED 184562306a36Sopenharmony_ci} 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci/** 184962306a36Sopenharmony_ci * megaraid_mbox_runpendq - execute commands queued in the pending queue 185062306a36Sopenharmony_ci * @adapter : controller's soft state 185162306a36Sopenharmony_ci * @scb_q : SCB to be queued in the pending list 185262306a36Sopenharmony_ci * 185362306a36Sopenharmony_ci * Scan the pending list for commands which are not yet issued and try to 185462306a36Sopenharmony_ci * post to the controller. The SCB can be a null pointer, which would indicate 185562306a36Sopenharmony_ci * no SCB to be queue, just try to execute the ones in the pending list. 185662306a36Sopenharmony_ci * 185762306a36Sopenharmony_ci * NOTE: We do not actually traverse the pending list. The SCBs are plucked 185862306a36Sopenharmony_ci * out from the head of the pending list. If it is successfully issued, the 185962306a36Sopenharmony_ci * next SCB is at the head now. 186062306a36Sopenharmony_ci */ 186162306a36Sopenharmony_cistatic void 186262306a36Sopenharmony_cimegaraid_mbox_runpendq(adapter_t *adapter, scb_t *scb_q) 186362306a36Sopenharmony_ci{ 186462306a36Sopenharmony_ci scb_t *scb; 186562306a36Sopenharmony_ci unsigned long flags; 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci if (scb_q) { 187062306a36Sopenharmony_ci scb_q->state = SCB_PENDQ; 187162306a36Sopenharmony_ci list_add_tail(&scb_q->list, &adapter->pend_list); 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci // if the adapter in not in quiescent mode, post the commands to FW 187562306a36Sopenharmony_ci if (adapter->quiescent) { 187662306a36Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); 187762306a36Sopenharmony_ci return; 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci while (!list_empty(&adapter->pend_list)) { 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci assert_spin_locked(PENDING_LIST_LOCK(adapter)); 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci scb = list_entry(adapter->pend_list.next, scb_t, list); 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci // remove the scb from the pending list and try to 188762306a36Sopenharmony_ci // issue. If we are unable to issue it, put back in 188862306a36Sopenharmony_ci // the pending list and return 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci list_del_init(&scb->list); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci // if mailbox was busy, return SCB back to pending 189562306a36Sopenharmony_ci // list. Make sure to add at the head, since that's 189662306a36Sopenharmony_ci // where it would have been removed from 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci scb->state = SCB_ISSUED; 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci if (mbox_post_cmd(adapter, scb) != 0) { 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci scb->state = SCB_PENDQ; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci list_add(&scb->list, &adapter->pend_list); 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), 190962306a36Sopenharmony_ci flags); 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci return; 191262306a36Sopenharmony_ci } 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); 191562306a36Sopenharmony_ci } 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci return; 192162306a36Sopenharmony_ci} 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci/** 192562306a36Sopenharmony_ci * megaraid_mbox_prepare_pthru - prepare a command for physical devices 192662306a36Sopenharmony_ci * @adapter : pointer to controller's soft state 192762306a36Sopenharmony_ci * @scb : scsi control block 192862306a36Sopenharmony_ci * @scp : scsi command from the mid-layer 192962306a36Sopenharmony_ci * 193062306a36Sopenharmony_ci * Prepare a command for the scsi physical devices. 193162306a36Sopenharmony_ci */ 193262306a36Sopenharmony_cistatic void 193362306a36Sopenharmony_cimegaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb, 193462306a36Sopenharmony_ci struct scsi_cmnd *scp) 193562306a36Sopenharmony_ci{ 193662306a36Sopenharmony_ci mbox_ccb_t *ccb; 193762306a36Sopenharmony_ci mraid_passthru_t *pthru; 193862306a36Sopenharmony_ci uint8_t channel; 193962306a36Sopenharmony_ci uint8_t target; 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 194262306a36Sopenharmony_ci pthru = ccb->pthru; 194362306a36Sopenharmony_ci channel = scb->dev_channel; 194462306a36Sopenharmony_ci target = scb->dev_target; 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci // 0=6sec, 1=60sec, 2=10min, 3=3hrs, 4=NO timeout 194762306a36Sopenharmony_ci pthru->timeout = 4; 194862306a36Sopenharmony_ci pthru->ars = 1; 194962306a36Sopenharmony_ci pthru->islogical = 0; 195062306a36Sopenharmony_ci pthru->channel = 0; 195162306a36Sopenharmony_ci pthru->target = (channel << 4) | target; 195262306a36Sopenharmony_ci pthru->logdrv = SCP2LUN(scp); 195362306a36Sopenharmony_ci pthru->reqsenselen = 14; 195462306a36Sopenharmony_ci pthru->cdblen = scp->cmd_len; 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci if (scsi_bufflen(scp)) { 195962306a36Sopenharmony_ci pthru->dataxferlen = scsi_bufflen(scp); 196062306a36Sopenharmony_ci pthru->dataxferaddr = ccb->sgl_dma_h; 196162306a36Sopenharmony_ci pthru->numsge = megaraid_mbox_mksgl(adapter, scb); 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci else { 196462306a36Sopenharmony_ci pthru->dataxferaddr = 0; 196562306a36Sopenharmony_ci pthru->dataxferlen = 0; 196662306a36Sopenharmony_ci pthru->numsge = 0; 196762306a36Sopenharmony_ci } 196862306a36Sopenharmony_ci return; 196962306a36Sopenharmony_ci} 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci/** 197362306a36Sopenharmony_ci * megaraid_mbox_prepare_epthru - prepare a command for physical devices 197462306a36Sopenharmony_ci * @adapter : pointer to controller's soft state 197562306a36Sopenharmony_ci * @scb : scsi control block 197662306a36Sopenharmony_ci * @scp : scsi command from the mid-layer 197762306a36Sopenharmony_ci * 197862306a36Sopenharmony_ci * Prepare a command for the scsi physical devices. This routine prepares 197962306a36Sopenharmony_ci * commands for devices which can take extended CDBs (>10 bytes). 198062306a36Sopenharmony_ci */ 198162306a36Sopenharmony_cistatic void 198262306a36Sopenharmony_cimegaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb, 198362306a36Sopenharmony_ci struct scsi_cmnd *scp) 198462306a36Sopenharmony_ci{ 198562306a36Sopenharmony_ci mbox_ccb_t *ccb; 198662306a36Sopenharmony_ci mraid_epassthru_t *epthru; 198762306a36Sopenharmony_ci uint8_t channel; 198862306a36Sopenharmony_ci uint8_t target; 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 199162306a36Sopenharmony_ci epthru = ccb->epthru; 199262306a36Sopenharmony_ci channel = scb->dev_channel; 199362306a36Sopenharmony_ci target = scb->dev_target; 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci // 0=6sec, 1=60sec, 2=10min, 3=3hrs, 4=NO timeout 199662306a36Sopenharmony_ci epthru->timeout = 4; 199762306a36Sopenharmony_ci epthru->ars = 1; 199862306a36Sopenharmony_ci epthru->islogical = 0; 199962306a36Sopenharmony_ci epthru->channel = 0; 200062306a36Sopenharmony_ci epthru->target = (channel << 4) | target; 200162306a36Sopenharmony_ci epthru->logdrv = SCP2LUN(scp); 200262306a36Sopenharmony_ci epthru->reqsenselen = 14; 200362306a36Sopenharmony_ci epthru->cdblen = scp->cmd_len; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci memcpy(epthru->cdb, scp->cmnd, scp->cmd_len); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci if (scsi_bufflen(scp)) { 200862306a36Sopenharmony_ci epthru->dataxferlen = scsi_bufflen(scp); 200962306a36Sopenharmony_ci epthru->dataxferaddr = ccb->sgl_dma_h; 201062306a36Sopenharmony_ci epthru->numsge = megaraid_mbox_mksgl(adapter, scb); 201162306a36Sopenharmony_ci } 201262306a36Sopenharmony_ci else { 201362306a36Sopenharmony_ci epthru->dataxferaddr = 0; 201462306a36Sopenharmony_ci epthru->dataxferlen = 0; 201562306a36Sopenharmony_ci epthru->numsge = 0; 201662306a36Sopenharmony_ci } 201762306a36Sopenharmony_ci return; 201862306a36Sopenharmony_ci} 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci/** 202262306a36Sopenharmony_ci * megaraid_ack_sequence - interrupt ack sequence for memory mapped HBAs 202362306a36Sopenharmony_ci * @adapter : controller's soft state 202462306a36Sopenharmony_ci * 202562306a36Sopenharmony_ci * Interrupt acknowledgement sequence for memory mapped HBAs. Find out the 202662306a36Sopenharmony_ci * completed command and put them on the completed list for later processing. 202762306a36Sopenharmony_ci * 202862306a36Sopenharmony_ci * Returns: 1 if the interrupt is valid, 0 otherwise 202962306a36Sopenharmony_ci */ 203062306a36Sopenharmony_cistatic int 203162306a36Sopenharmony_cimegaraid_ack_sequence(adapter_t *adapter) 203262306a36Sopenharmony_ci{ 203362306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 203462306a36Sopenharmony_ci mbox_t *mbox; 203562306a36Sopenharmony_ci scb_t *scb; 203662306a36Sopenharmony_ci uint8_t nstatus; 203762306a36Sopenharmony_ci uint8_t completed[MBOX_MAX_FIRMWARE_STATUS]; 203862306a36Sopenharmony_ci struct list_head clist; 203962306a36Sopenharmony_ci int handled; 204062306a36Sopenharmony_ci uint32_t dword; 204162306a36Sopenharmony_ci unsigned long flags; 204262306a36Sopenharmony_ci int i, j; 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci mbox = raid_dev->mbox; 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci // move the SCBs from the firmware completed array to our local list 204862306a36Sopenharmony_ci INIT_LIST_HEAD(&clist); 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci // loop till F/W has more commands for us to complete 205162306a36Sopenharmony_ci handled = 0; 205262306a36Sopenharmony_ci spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags); 205362306a36Sopenharmony_ci do { 205462306a36Sopenharmony_ci /* 205562306a36Sopenharmony_ci * Check if a valid interrupt is pending. If found, force the 205662306a36Sopenharmony_ci * interrupt line low. 205762306a36Sopenharmony_ci */ 205862306a36Sopenharmony_ci dword = RDOUTDOOR(raid_dev); 205962306a36Sopenharmony_ci if (dword != 0x10001234) break; 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci handled = 1; 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci WROUTDOOR(raid_dev, 0x10001234); 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci nstatus = 0; 206662306a36Sopenharmony_ci // wait for valid numstatus to post 206762306a36Sopenharmony_ci for (i = 0; i < 0xFFFFF; i++) { 206862306a36Sopenharmony_ci if (mbox->numstatus != 0xFF) { 206962306a36Sopenharmony_ci nstatus = mbox->numstatus; 207062306a36Sopenharmony_ci break; 207162306a36Sopenharmony_ci } 207262306a36Sopenharmony_ci rmb(); 207362306a36Sopenharmony_ci } 207462306a36Sopenharmony_ci mbox->numstatus = 0xFF; 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci adapter->outstanding_cmds -= nstatus; 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci for (i = 0; i < nstatus; i++) { 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci // wait for valid command index to post 208162306a36Sopenharmony_ci for (j = 0; j < 0xFFFFF; j++) { 208262306a36Sopenharmony_ci if (mbox->completed[i] != 0xFF) break; 208362306a36Sopenharmony_ci rmb(); 208462306a36Sopenharmony_ci } 208562306a36Sopenharmony_ci completed[i] = mbox->completed[i]; 208662306a36Sopenharmony_ci mbox->completed[i] = 0xFF; 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci if (completed[i] == 0xFF) { 208962306a36Sopenharmony_ci con_log(CL_ANN, (KERN_CRIT 209062306a36Sopenharmony_ci "megaraid: command posting timed out\n")); 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci BUG(); 209362306a36Sopenharmony_ci continue; 209462306a36Sopenharmony_ci } 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci // Get SCB associated with this command id 209762306a36Sopenharmony_ci if (completed[i] >= MBOX_MAX_SCSI_CMDS) { 209862306a36Sopenharmony_ci // a cmm command 209962306a36Sopenharmony_ci scb = adapter->uscb_list + (completed[i] - 210062306a36Sopenharmony_ci MBOX_MAX_SCSI_CMDS); 210162306a36Sopenharmony_ci } 210262306a36Sopenharmony_ci else { 210362306a36Sopenharmony_ci // an os command 210462306a36Sopenharmony_ci scb = adapter->kscb_list + completed[i]; 210562306a36Sopenharmony_ci } 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci scb->status = mbox->status; 210862306a36Sopenharmony_ci list_add_tail(&scb->list, &clist); 210962306a36Sopenharmony_ci } 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci // Acknowledge interrupt 211262306a36Sopenharmony_ci WRINDOOR(raid_dev, 0x02); 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci } while(1); 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci // put the completed commands in the completed list. DPC would 212062306a36Sopenharmony_ci // complete these commands later 212162306a36Sopenharmony_ci spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci list_splice(&clist, &adapter->completed_list); 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci // schedule the DPC if there is some work for it 212962306a36Sopenharmony_ci if (handled) 213062306a36Sopenharmony_ci tasklet_schedule(&adapter->dpc_h); 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci return handled; 213362306a36Sopenharmony_ci} 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci/** 213762306a36Sopenharmony_ci * megaraid_isr - isr for memory based mailbox based controllers 213862306a36Sopenharmony_ci * @irq : irq 213962306a36Sopenharmony_ci * @devp : pointer to our soft state 214062306a36Sopenharmony_ci * 214162306a36Sopenharmony_ci * Interrupt service routine for memory-mapped mailbox controllers. 214262306a36Sopenharmony_ci */ 214362306a36Sopenharmony_cistatic irqreturn_t 214462306a36Sopenharmony_cimegaraid_isr(int irq, void *devp) 214562306a36Sopenharmony_ci{ 214662306a36Sopenharmony_ci adapter_t *adapter = devp; 214762306a36Sopenharmony_ci int handled; 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci handled = megaraid_ack_sequence(adapter); 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci /* Loop through any pending requests */ 215262306a36Sopenharmony_ci if (!adapter->quiescent) { 215362306a36Sopenharmony_ci megaraid_mbox_runpendq(adapter, NULL); 215462306a36Sopenharmony_ci } 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci return IRQ_RETVAL(handled); 215762306a36Sopenharmony_ci} 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci/** 216162306a36Sopenharmony_ci * megaraid_mbox_dpc - the tasklet to complete the commands from completed list 216262306a36Sopenharmony_ci * @devp : pointer to HBA soft state 216362306a36Sopenharmony_ci * 216462306a36Sopenharmony_ci * Pick up the commands from the completed list and send back to the owners. 216562306a36Sopenharmony_ci * This is a reentrant function and does not assume any locks are held while 216662306a36Sopenharmony_ci * it is being called. 216762306a36Sopenharmony_ci */ 216862306a36Sopenharmony_cistatic void 216962306a36Sopenharmony_cimegaraid_mbox_dpc(unsigned long devp) 217062306a36Sopenharmony_ci{ 217162306a36Sopenharmony_ci adapter_t *adapter = (adapter_t *)devp; 217262306a36Sopenharmony_ci mraid_device_t *raid_dev; 217362306a36Sopenharmony_ci struct list_head clist; 217462306a36Sopenharmony_ci struct scatterlist *sgl; 217562306a36Sopenharmony_ci scb_t *scb; 217662306a36Sopenharmony_ci scb_t *tmp; 217762306a36Sopenharmony_ci struct scsi_cmnd *scp; 217862306a36Sopenharmony_ci mraid_passthru_t *pthru; 217962306a36Sopenharmony_ci mraid_epassthru_t *epthru; 218062306a36Sopenharmony_ci mbox_ccb_t *ccb; 218162306a36Sopenharmony_ci int islogical; 218262306a36Sopenharmony_ci int pdev_index; 218362306a36Sopenharmony_ci int pdev_state; 218462306a36Sopenharmony_ci mbox_t *mbox; 218562306a36Sopenharmony_ci unsigned long flags; 218662306a36Sopenharmony_ci uint8_t c; 218762306a36Sopenharmony_ci int status; 218862306a36Sopenharmony_ci uioc_t *kioc; 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci if (!adapter) return; 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci raid_dev = ADAP2RAIDDEV(adapter); 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci // move the SCBs from the completed list to our local list 219662306a36Sopenharmony_ci INIT_LIST_HEAD(&clist); 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci list_splice_init(&adapter->completed_list, &clist); 220162306a36Sopenharmony_ci 220262306a36Sopenharmony_ci spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci list_for_each_entry_safe(scb, tmp, &clist, list) { 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci status = scb->status; 220862306a36Sopenharmony_ci scp = scb->scp; 220962306a36Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 221062306a36Sopenharmony_ci pthru = ccb->pthru; 221162306a36Sopenharmony_ci epthru = ccb->epthru; 221262306a36Sopenharmony_ci mbox = ccb->mbox; 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci // Make sure f/w has completed a valid command 221562306a36Sopenharmony_ci if (scb->state != SCB_ISSUED) { 221662306a36Sopenharmony_ci con_log(CL_ANN, (KERN_CRIT 221762306a36Sopenharmony_ci "megaraid critical err: invalid command %d:%d:%p\n", 221862306a36Sopenharmony_ci scb->sno, scb->state, scp)); 221962306a36Sopenharmony_ci BUG(); 222062306a36Sopenharmony_ci continue; // Must never happen! 222162306a36Sopenharmony_ci } 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci // check for the management command and complete it right away 222462306a36Sopenharmony_ci if (scb->sno >= MBOX_MAX_SCSI_CMDS) { 222562306a36Sopenharmony_ci scb->state = SCB_FREE; 222662306a36Sopenharmony_ci scb->status = status; 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci // remove from local clist 222962306a36Sopenharmony_ci list_del_init(&scb->list); 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci kioc = (uioc_t *)scb->gp; 223262306a36Sopenharmony_ci kioc->status = 0; 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci megaraid_mbox_mm_done(adapter, scb); 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci continue; 223762306a36Sopenharmony_ci } 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci // Was an abort issued for this command earlier 224062306a36Sopenharmony_ci if (scb->state & SCB_ABORT) { 224162306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 224262306a36Sopenharmony_ci "megaraid: aborted cmd [%x] completed\n", 224362306a36Sopenharmony_ci scb->sno)); 224462306a36Sopenharmony_ci } 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci /* 224762306a36Sopenharmony_ci * If the inquiry came of a disk drive which is not part of 224862306a36Sopenharmony_ci * any RAID array, expose it to the kernel. For this to be 224962306a36Sopenharmony_ci * enabled, user must set the "megaraid_expose_unconf_disks" 225062306a36Sopenharmony_ci * flag to 1 by specifying it on module parameter list. 225162306a36Sopenharmony_ci * This would enable data migration off drives from other 225262306a36Sopenharmony_ci * configurations. 225362306a36Sopenharmony_ci */ 225462306a36Sopenharmony_ci islogical = MRAID_IS_LOGICAL(adapter, scp); 225562306a36Sopenharmony_ci if (scp->cmnd[0] == INQUIRY && status == 0 && islogical == 0 225662306a36Sopenharmony_ci && IS_RAID_CH(raid_dev, scb->dev_channel)) { 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci sgl = scsi_sglist(scp); 225962306a36Sopenharmony_ci if (sg_page(sgl)) { 226062306a36Sopenharmony_ci c = *(unsigned char *) sg_virt(&sgl[0]); 226162306a36Sopenharmony_ci } else { 226262306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 226362306a36Sopenharmony_ci "megaraid mailbox: invalid sg:%d\n", 226462306a36Sopenharmony_ci __LINE__)); 226562306a36Sopenharmony_ci c = 0; 226662306a36Sopenharmony_ci } 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci if ((c & 0x1F ) == TYPE_DISK) { 226962306a36Sopenharmony_ci pdev_index = (scb->dev_channel * 16) + 227062306a36Sopenharmony_ci scb->dev_target; 227162306a36Sopenharmony_ci pdev_state = 227262306a36Sopenharmony_ci raid_dev->pdrv_state[pdev_index] & 0x0F; 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci if (pdev_state == PDRV_ONLINE || 227562306a36Sopenharmony_ci pdev_state == PDRV_FAILED || 227662306a36Sopenharmony_ci pdev_state == PDRV_RBLD || 227762306a36Sopenharmony_ci pdev_state == PDRV_HOTSPARE || 227862306a36Sopenharmony_ci megaraid_expose_unconf_disks == 0) { 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci status = 0xF0; 228162306a36Sopenharmony_ci } 228262306a36Sopenharmony_ci } 228362306a36Sopenharmony_ci } 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci // Convert MegaRAID status to Linux error code 228662306a36Sopenharmony_ci switch (status) { 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ci case 0x00: 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_ci scp->result = (DID_OK << 16); 229162306a36Sopenharmony_ci break; 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci case 0x02: 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci /* set sense_buffer and result fields */ 229662306a36Sopenharmony_ci if (mbox->cmd == MBOXCMD_PASSTHRU || 229762306a36Sopenharmony_ci mbox->cmd == MBOXCMD_PASSTHRU64) { 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci memcpy(scp->sense_buffer, pthru->reqsensearea, 230062306a36Sopenharmony_ci 14); 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci scp->result = SAM_STAT_CHECK_CONDITION; 230362306a36Sopenharmony_ci } 230462306a36Sopenharmony_ci else { 230562306a36Sopenharmony_ci if (mbox->cmd == MBOXCMD_EXTPTHRU) { 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci memcpy(scp->sense_buffer, 230862306a36Sopenharmony_ci epthru->reqsensearea, 14); 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci scp->result = SAM_STAT_CHECK_CONDITION; 231162306a36Sopenharmony_ci } else 231262306a36Sopenharmony_ci scsi_build_sense(scp, 0, 231362306a36Sopenharmony_ci ABORTED_COMMAND, 0, 0); 231462306a36Sopenharmony_ci } 231562306a36Sopenharmony_ci break; 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci case 0x08: 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci scp->result = DID_BUS_BUSY << 16 | status; 232062306a36Sopenharmony_ci break; 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci default: 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci /* 232562306a36Sopenharmony_ci * If TEST_UNIT_READY fails, we know RESERVATION_STATUS 232662306a36Sopenharmony_ci * failed 232762306a36Sopenharmony_ci */ 232862306a36Sopenharmony_ci if (scp->cmnd[0] == TEST_UNIT_READY) { 232962306a36Sopenharmony_ci scp->result = DID_ERROR << 16 | 233062306a36Sopenharmony_ci SAM_STAT_RESERVATION_CONFLICT; 233162306a36Sopenharmony_ci } 233262306a36Sopenharmony_ci else 233362306a36Sopenharmony_ci /* 233462306a36Sopenharmony_ci * Error code returned is 1 if Reserve or Release 233562306a36Sopenharmony_ci * failed or the input parameter is invalid 233662306a36Sopenharmony_ci */ 233762306a36Sopenharmony_ci if (status == 1 && (scp->cmnd[0] == RESERVE || 233862306a36Sopenharmony_ci scp->cmnd[0] == RELEASE)) { 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_ci scp->result = DID_ERROR << 16 | 234162306a36Sopenharmony_ci SAM_STAT_RESERVATION_CONFLICT; 234262306a36Sopenharmony_ci } 234362306a36Sopenharmony_ci else { 234462306a36Sopenharmony_ci scp->result = DID_BAD_TARGET << 16 | status; 234562306a36Sopenharmony_ci } 234662306a36Sopenharmony_ci } 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci // print a debug message for all failed commands 234962306a36Sopenharmony_ci if (status) { 235062306a36Sopenharmony_ci megaraid_mbox_display_scb(adapter, scb); 235162306a36Sopenharmony_ci } 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci scsi_dma_unmap(scp); 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci // remove from local clist 235662306a36Sopenharmony_ci list_del_init(&scb->list); 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci // put back in free list 235962306a36Sopenharmony_ci megaraid_dealloc_scb(adapter, scb); 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci // send the scsi packet back to kernel 236262306a36Sopenharmony_ci scsi_done(scp); 236362306a36Sopenharmony_ci } 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci return; 236662306a36Sopenharmony_ci} 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci/** 237062306a36Sopenharmony_ci * megaraid_abort_handler - abort the scsi command 237162306a36Sopenharmony_ci * @scp : command to be aborted 237262306a36Sopenharmony_ci * 237362306a36Sopenharmony_ci * Abort a previous SCSI request. Only commands on the pending list can be 237462306a36Sopenharmony_ci * aborted. All the commands issued to the F/W must complete. 237562306a36Sopenharmony_ci **/ 237662306a36Sopenharmony_cistatic int 237762306a36Sopenharmony_cimegaraid_abort_handler(struct scsi_cmnd *scp) 237862306a36Sopenharmony_ci{ 237962306a36Sopenharmony_ci adapter_t *adapter; 238062306a36Sopenharmony_ci mraid_device_t *raid_dev; 238162306a36Sopenharmony_ci scb_t *scb; 238262306a36Sopenharmony_ci scb_t *tmp; 238362306a36Sopenharmony_ci int found; 238462306a36Sopenharmony_ci unsigned long flags; 238562306a36Sopenharmony_ci int i; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci adapter = SCP2ADAPTER(scp); 238962306a36Sopenharmony_ci raid_dev = ADAP2RAIDDEV(adapter); 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 239262306a36Sopenharmony_ci "megaraid: aborting cmd=%x <c=%d t=%d l=%d>\n", 239362306a36Sopenharmony_ci scp->cmnd[0], SCP2CHANNEL(scp), 239462306a36Sopenharmony_ci SCP2TARGET(scp), SCP2LUN(scp))); 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci // If FW has stopped responding, simply return failure 239762306a36Sopenharmony_ci if (raid_dev->hw_error) { 239862306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 239962306a36Sopenharmony_ci "megaraid: hw error, not aborting\n")); 240062306a36Sopenharmony_ci return FAILED; 240162306a36Sopenharmony_ci } 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci // There might a race here, where the command was completed by the 240462306a36Sopenharmony_ci // firmware and now it is on the completed list. Before we could 240562306a36Sopenharmony_ci // complete the command to the kernel in dpc, the abort came. 240662306a36Sopenharmony_ci // Find out if this is the case to avoid the race. 240762306a36Sopenharmony_ci scb = NULL; 240862306a36Sopenharmony_ci spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); 240962306a36Sopenharmony_ci list_for_each_entry_safe(scb, tmp, &adapter->completed_list, list) { 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci if (scb->scp == scp) { // Found command 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci list_del_init(&scb->list); // from completed list 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 241662306a36Sopenharmony_ci "megaraid: %d[%d:%d], abort from completed list\n", 241762306a36Sopenharmony_ci scb->sno, scb->dev_channel, scb->dev_target)); 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci scp->result = (DID_ABORT << 16); 242062306a36Sopenharmony_ci scsi_done(scp); 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci megaraid_dealloc_scb(adapter, scb); 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), 242562306a36Sopenharmony_ci flags); 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci return SUCCESS; 242862306a36Sopenharmony_ci } 242962306a36Sopenharmony_ci } 243062306a36Sopenharmony_ci spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_ci // Find out if this command is still on the pending list. If it is and 243462306a36Sopenharmony_ci // was never issued, abort and return success. If the command is owned 243562306a36Sopenharmony_ci // by the firmware, we must wait for it to complete by the FW. 243662306a36Sopenharmony_ci spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); 243762306a36Sopenharmony_ci list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) { 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci if (scb->scp == scp) { // Found command 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci list_del_init(&scb->list); // from pending list 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci ASSERT(!(scb->state & SCB_ISSUED)); 244462306a36Sopenharmony_ci 244562306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 244662306a36Sopenharmony_ci "megaraid abort: [%d:%d], driver owner\n", 244762306a36Sopenharmony_ci scb->dev_channel, scb->dev_target)); 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_ci scp->result = (DID_ABORT << 16); 245062306a36Sopenharmony_ci scsi_done(scp); 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci megaraid_dealloc_scb(adapter, scb); 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), 245562306a36Sopenharmony_ci flags); 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci return SUCCESS; 245862306a36Sopenharmony_ci } 245962306a36Sopenharmony_ci } 246062306a36Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci // Check do we even own this command, in which case this would be 246462306a36Sopenharmony_ci // owned by the firmware. The only way to locate the FW scb is to 246562306a36Sopenharmony_ci // traverse through the list of all SCB, since driver does not 246662306a36Sopenharmony_ci // maintain these SCBs on any list 246762306a36Sopenharmony_ci found = 0; 246862306a36Sopenharmony_ci spin_lock_irq(&adapter->lock); 246962306a36Sopenharmony_ci for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { 247062306a36Sopenharmony_ci scb = adapter->kscb_list + i; 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci if (scb->scp == scp) { 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci found = 1; 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci if (!(scb->state & SCB_ISSUED)) { 247762306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 247862306a36Sopenharmony_ci "megaraid abort: %d[%d:%d], invalid state\n", 247962306a36Sopenharmony_ci scb->sno, scb->dev_channel, scb->dev_target)); 248062306a36Sopenharmony_ci BUG(); 248162306a36Sopenharmony_ci } 248262306a36Sopenharmony_ci else { 248362306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 248462306a36Sopenharmony_ci "megaraid abort: %d[%d:%d], fw owner\n", 248562306a36Sopenharmony_ci scb->sno, scb->dev_channel, scb->dev_target)); 248662306a36Sopenharmony_ci } 248762306a36Sopenharmony_ci } 248862306a36Sopenharmony_ci } 248962306a36Sopenharmony_ci spin_unlock_irq(&adapter->lock); 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci if (!found) { 249262306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING "megaraid abort: do now own\n")); 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci // FIXME: Should there be a callback for this command? 249562306a36Sopenharmony_ci return SUCCESS; 249662306a36Sopenharmony_ci } 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci // We cannot actually abort a command owned by firmware, return 249962306a36Sopenharmony_ci // failure and wait for reset. In host reset handler, we will find out 250062306a36Sopenharmony_ci // if the HBA is still live 250162306a36Sopenharmony_ci return FAILED; 250262306a36Sopenharmony_ci} 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci/** 250562306a36Sopenharmony_ci * megaraid_reset_handler - device reset handler for mailbox based driver 250662306a36Sopenharmony_ci * @scp : reference command 250762306a36Sopenharmony_ci * 250862306a36Sopenharmony_ci * Reset handler for the mailbox based controller. First try to find out if 250962306a36Sopenharmony_ci * the FW is still live, in which case the outstanding commands counter mut go 251062306a36Sopenharmony_ci * down to 0. If that happens, also issue the reservation reset command to 251162306a36Sopenharmony_ci * relinquish (possible) reservations on the logical drives connected to this 251262306a36Sopenharmony_ci * host. 251362306a36Sopenharmony_ci **/ 251462306a36Sopenharmony_cistatic int 251562306a36Sopenharmony_cimegaraid_reset_handler(struct scsi_cmnd *scp) 251662306a36Sopenharmony_ci{ 251762306a36Sopenharmony_ci adapter_t *adapter; 251862306a36Sopenharmony_ci scb_t *scb; 251962306a36Sopenharmony_ci scb_t *tmp; 252062306a36Sopenharmony_ci mraid_device_t *raid_dev; 252162306a36Sopenharmony_ci unsigned long flags; 252262306a36Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 252362306a36Sopenharmony_ci int rval; 252462306a36Sopenharmony_ci int recovery_window; 252562306a36Sopenharmony_ci int i; 252662306a36Sopenharmony_ci uioc_t *kioc; 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci adapter = SCP2ADAPTER(scp); 252962306a36Sopenharmony_ci raid_dev = ADAP2RAIDDEV(adapter); 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci // return failure if adapter is not responding 253262306a36Sopenharmony_ci if (raid_dev->hw_error) { 253362306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 253462306a36Sopenharmony_ci "megaraid: hw error, cannot reset\n")); 253562306a36Sopenharmony_ci return FAILED; 253662306a36Sopenharmony_ci } 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci // Under exceptional conditions, FW can take up to 3 minutes to 253962306a36Sopenharmony_ci // complete command processing. Wait for additional 2 minutes for the 254062306a36Sopenharmony_ci // pending commands counter to go down to 0. If it doesn't, let the 254162306a36Sopenharmony_ci // controller be marked offline 254262306a36Sopenharmony_ci // Also, reset all the commands currently owned by the driver 254362306a36Sopenharmony_ci spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); 254462306a36Sopenharmony_ci list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) { 254562306a36Sopenharmony_ci list_del_init(&scb->list); // from pending list 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_ci if (scb->sno >= MBOX_MAX_SCSI_CMDS) { 254862306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 254962306a36Sopenharmony_ci "megaraid: IOCTL packet with %d[%d:%d] being reset\n", 255062306a36Sopenharmony_ci scb->sno, scb->dev_channel, scb->dev_target)); 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ci scb->status = -1; 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci kioc = (uioc_t *)scb->gp; 255562306a36Sopenharmony_ci kioc->status = -EFAULT; 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci megaraid_mbox_mm_done(adapter, scb); 255862306a36Sopenharmony_ci } else { 255962306a36Sopenharmony_ci if (scb->scp == scp) { // Found command 256062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 256162306a36Sopenharmony_ci "megaraid: %d[%d:%d], reset from pending list\n", 256262306a36Sopenharmony_ci scb->sno, scb->dev_channel, scb->dev_target)); 256362306a36Sopenharmony_ci } else { 256462306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 256562306a36Sopenharmony_ci "megaraid: IO packet with %d[%d:%d] being reset\n", 256662306a36Sopenharmony_ci scb->sno, scb->dev_channel, scb->dev_target)); 256762306a36Sopenharmony_ci } 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci scb->scp->result = (DID_RESET << 16); 257062306a36Sopenharmony_ci scsi_done(scb->scp); 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci megaraid_dealloc_scb(adapter, scb); 257362306a36Sopenharmony_ci } 257462306a36Sopenharmony_ci } 257562306a36Sopenharmony_ci spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci if (adapter->outstanding_cmds) { 257862306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 257962306a36Sopenharmony_ci "megaraid: %d outstanding commands. Max wait %d sec\n", 258062306a36Sopenharmony_ci adapter->outstanding_cmds, 258162306a36Sopenharmony_ci (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT))); 258262306a36Sopenharmony_ci } 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci for (i = 0; i < recovery_window; i++) { 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci megaraid_ack_sequence(adapter); 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci // print a message once every 5 seconds only 259162306a36Sopenharmony_ci if (!(i % 5)) { 259262306a36Sopenharmony_ci con_log(CL_ANN, ( 259362306a36Sopenharmony_ci "megaraid mbox: Wait for %d commands to complete:%d\n", 259462306a36Sopenharmony_ci adapter->outstanding_cmds, 259562306a36Sopenharmony_ci (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT) - i)); 259662306a36Sopenharmony_ci } 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci // bailout if no recovery happened in reset time 259962306a36Sopenharmony_ci if (adapter->outstanding_cmds == 0) { 260062306a36Sopenharmony_ci break; 260162306a36Sopenharmony_ci } 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci msleep(1000); 260462306a36Sopenharmony_ci } 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci spin_lock(&adapter->lock); 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_ci // If still outstanding commands, bail out 260962306a36Sopenharmony_ci if (adapter->outstanding_cmds) { 261062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 261162306a36Sopenharmony_ci "megaraid mbox: critical hardware error!\n")); 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci raid_dev->hw_error = 1; 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci rval = FAILED; 261662306a36Sopenharmony_ci goto out; 261762306a36Sopenharmony_ci } 261862306a36Sopenharmony_ci else { 261962306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 262062306a36Sopenharmony_ci "megaraid mbox: reset sequence completed successfully\n")); 262162306a36Sopenharmony_ci } 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci // If the controller supports clustering, reset reservations 262562306a36Sopenharmony_ci if (!adapter->ha) { 262662306a36Sopenharmony_ci rval = SUCCESS; 262762306a36Sopenharmony_ci goto out; 262862306a36Sopenharmony_ci } 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci // clear reservations if any 263162306a36Sopenharmony_ci raw_mbox[0] = CLUSTER_CMD; 263262306a36Sopenharmony_ci raw_mbox[2] = RESET_RESERVATIONS; 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci rval = SUCCESS; 263562306a36Sopenharmony_ci if (mbox_post_sync_cmd_fast(adapter, raw_mbox) == 0) { 263662306a36Sopenharmony_ci con_log(CL_ANN, 263762306a36Sopenharmony_ci (KERN_INFO "megaraid: reservation reset\n")); 263862306a36Sopenharmony_ci } 263962306a36Sopenharmony_ci else { 264062306a36Sopenharmony_ci rval = FAILED; 264162306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 264262306a36Sopenharmony_ci "megaraid: reservation reset failed\n")); 264362306a36Sopenharmony_ci } 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci out: 264662306a36Sopenharmony_ci spin_unlock(&adapter->lock); 264762306a36Sopenharmony_ci return rval; 264862306a36Sopenharmony_ci} 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci/* 265162306a36Sopenharmony_ci * START: internal commands library 265262306a36Sopenharmony_ci * 265362306a36Sopenharmony_ci * This section of the driver has the common routine used by the driver and 265462306a36Sopenharmony_ci * also has all the FW routines 265562306a36Sopenharmony_ci */ 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ci/** 265862306a36Sopenharmony_ci * mbox_post_sync_cmd() - blocking command to the mailbox based controllers 265962306a36Sopenharmony_ci * @adapter : controller's soft state 266062306a36Sopenharmony_ci * @raw_mbox : the mailbox 266162306a36Sopenharmony_ci * 266262306a36Sopenharmony_ci * Issue a scb in synchronous and non-interrupt mode for mailbox based 266362306a36Sopenharmony_ci * controllers. 266462306a36Sopenharmony_ci */ 266562306a36Sopenharmony_cistatic int 266662306a36Sopenharmony_cimbox_post_sync_cmd(adapter_t *adapter, uint8_t raw_mbox[]) 266762306a36Sopenharmony_ci{ 266862306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 266962306a36Sopenharmony_ci mbox_t *mbox; 267062306a36Sopenharmony_ci uint8_t status; 267162306a36Sopenharmony_ci int i; 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci mbox = raid_dev->mbox; 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci /* 267662306a36Sopenharmony_ci * Wait until mailbox is free 267762306a36Sopenharmony_ci */ 267862306a36Sopenharmony_ci if (megaraid_busywait_mbox(raid_dev) != 0) 267962306a36Sopenharmony_ci goto blocked_mailbox; 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci /* 268262306a36Sopenharmony_ci * Copy mailbox data into host structure 268362306a36Sopenharmony_ci */ 268462306a36Sopenharmony_ci memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16); 268562306a36Sopenharmony_ci mbox->cmdid = 0xFE; 268662306a36Sopenharmony_ci mbox->busy = 1; 268762306a36Sopenharmony_ci mbox->poll = 0; 268862306a36Sopenharmony_ci mbox->ack = 0; 268962306a36Sopenharmony_ci mbox->numstatus = 0xFF; 269062306a36Sopenharmony_ci mbox->status = 0xFF; 269162306a36Sopenharmony_ci 269262306a36Sopenharmony_ci wmb(); 269362306a36Sopenharmony_ci WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci // wait for maximum 1 second for status to post. If the status is not 269662306a36Sopenharmony_ci // available within 1 second, assume FW is initializing and wait 269762306a36Sopenharmony_ci // for an extended amount of time 269862306a36Sopenharmony_ci if (mbox->numstatus == 0xFF) { // status not yet available 269962306a36Sopenharmony_ci udelay(25); 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci for (i = 0; mbox->numstatus == 0xFF && i < 1000; i++) { 270262306a36Sopenharmony_ci rmb(); 270362306a36Sopenharmony_ci msleep(1); 270462306a36Sopenharmony_ci } 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci if (i == 1000) { 270862306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 270962306a36Sopenharmony_ci "megaraid mailbox: wait for FW to boot ")); 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci for (i = 0; (mbox->numstatus == 0xFF) && 271262306a36Sopenharmony_ci (i < MBOX_RESET_WAIT); i++) { 271362306a36Sopenharmony_ci rmb(); 271462306a36Sopenharmony_ci con_log(CL_ANN, ("\b\b\b\b\b[%03d]", 271562306a36Sopenharmony_ci MBOX_RESET_WAIT - i)); 271662306a36Sopenharmony_ci msleep(1000); 271762306a36Sopenharmony_ci } 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci if (i == MBOX_RESET_WAIT) { 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ci con_log(CL_ANN, ( 272262306a36Sopenharmony_ci "\nmegaraid mailbox: status not available\n")); 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci return -1; 272562306a36Sopenharmony_ci } 272662306a36Sopenharmony_ci con_log(CL_ANN, ("\b\b\b\b\b[ok] \n")); 272762306a36Sopenharmony_ci } 272862306a36Sopenharmony_ci } 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci // wait for maximum 1 second for poll semaphore 273162306a36Sopenharmony_ci if (mbox->poll != 0x77) { 273262306a36Sopenharmony_ci udelay(25); 273362306a36Sopenharmony_ci 273462306a36Sopenharmony_ci for (i = 0; (mbox->poll != 0x77) && (i < 1000); i++) { 273562306a36Sopenharmony_ci rmb(); 273662306a36Sopenharmony_ci msleep(1); 273762306a36Sopenharmony_ci } 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci if (i == 1000) { 274062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 274162306a36Sopenharmony_ci "megaraid mailbox: could not get poll semaphore\n")); 274262306a36Sopenharmony_ci return -1; 274362306a36Sopenharmony_ci } 274462306a36Sopenharmony_ci } 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_ci WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2); 274762306a36Sopenharmony_ci wmb(); 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci // wait for maximum 1 second for acknowledgement 275062306a36Sopenharmony_ci if (RDINDOOR(raid_dev) & 0x2) { 275162306a36Sopenharmony_ci udelay(25); 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci for (i = 0; (RDINDOOR(raid_dev) & 0x2) && (i < 1000); i++) { 275462306a36Sopenharmony_ci rmb(); 275562306a36Sopenharmony_ci msleep(1); 275662306a36Sopenharmony_ci } 275762306a36Sopenharmony_ci 275862306a36Sopenharmony_ci if (i == 1000) { 275962306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 276062306a36Sopenharmony_ci "megaraid mailbox: could not acknowledge\n")); 276162306a36Sopenharmony_ci return -1; 276262306a36Sopenharmony_ci } 276362306a36Sopenharmony_ci } 276462306a36Sopenharmony_ci mbox->poll = 0; 276562306a36Sopenharmony_ci mbox->ack = 0x77; 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci status = mbox->status; 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci // invalidate the completed command id array. After command 277062306a36Sopenharmony_ci // completion, firmware would write the valid id. 277162306a36Sopenharmony_ci mbox->numstatus = 0xFF; 277262306a36Sopenharmony_ci mbox->status = 0xFF; 277362306a36Sopenharmony_ci for (i = 0; i < MBOX_MAX_FIRMWARE_STATUS; i++) { 277462306a36Sopenharmony_ci mbox->completed[i] = 0xFF; 277562306a36Sopenharmony_ci } 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci return status; 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ciblocked_mailbox: 278062306a36Sopenharmony_ci 278162306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n") ); 278262306a36Sopenharmony_ci return -1; 278362306a36Sopenharmony_ci} 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci/** 278762306a36Sopenharmony_ci * mbox_post_sync_cmd_fast - blocking command to the mailbox based controllers 278862306a36Sopenharmony_ci * @adapter : controller's soft state 278962306a36Sopenharmony_ci * @raw_mbox : the mailbox 279062306a36Sopenharmony_ci * 279162306a36Sopenharmony_ci * Issue a scb in synchronous and non-interrupt mode for mailbox based 279262306a36Sopenharmony_ci * controllers. This is a faster version of the synchronous command and 279362306a36Sopenharmony_ci * therefore can be called in interrupt-context as well. 279462306a36Sopenharmony_ci */ 279562306a36Sopenharmony_cistatic int 279662306a36Sopenharmony_cimbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[]) 279762306a36Sopenharmony_ci{ 279862306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 279962306a36Sopenharmony_ci mbox_t *mbox; 280062306a36Sopenharmony_ci long i; 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci mbox = raid_dev->mbox; 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ci // return immediately if the mailbox is busy 280662306a36Sopenharmony_ci if (mbox->busy) return -1; 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_ci // Copy mailbox data into host structure 280962306a36Sopenharmony_ci memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 14); 281062306a36Sopenharmony_ci mbox->cmdid = 0xFE; 281162306a36Sopenharmony_ci mbox->busy = 1; 281262306a36Sopenharmony_ci mbox->poll = 0; 281362306a36Sopenharmony_ci mbox->ack = 0; 281462306a36Sopenharmony_ci mbox->numstatus = 0xFF; 281562306a36Sopenharmony_ci mbox->status = 0xFF; 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_ci wmb(); 281862306a36Sopenharmony_ci WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); 281962306a36Sopenharmony_ci 282062306a36Sopenharmony_ci for (i = 0; i < MBOX_SYNC_WAIT_CNT; i++) { 282162306a36Sopenharmony_ci if (mbox->numstatus != 0xFF) break; 282262306a36Sopenharmony_ci rmb(); 282362306a36Sopenharmony_ci udelay(MBOX_SYNC_DELAY_200); 282462306a36Sopenharmony_ci } 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci if (i == MBOX_SYNC_WAIT_CNT) { 282762306a36Sopenharmony_ci // We may need to re-calibrate the counter 282862306a36Sopenharmony_ci con_log(CL_ANN, (KERN_CRIT 282962306a36Sopenharmony_ci "megaraid: fast sync command timed out\n")); 283062306a36Sopenharmony_ci } 283162306a36Sopenharmony_ci 283262306a36Sopenharmony_ci WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2); 283362306a36Sopenharmony_ci wmb(); 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci return mbox->status; 283662306a36Sopenharmony_ci} 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci/** 284062306a36Sopenharmony_ci * megaraid_busywait_mbox() - Wait until the controller's mailbox is available 284162306a36Sopenharmony_ci * @raid_dev : RAID device (HBA) soft state 284262306a36Sopenharmony_ci * 284362306a36Sopenharmony_ci * Wait until the controller's mailbox is available to accept more commands. 284462306a36Sopenharmony_ci * Wait for at most 1 second. 284562306a36Sopenharmony_ci */ 284662306a36Sopenharmony_cistatic int 284762306a36Sopenharmony_cimegaraid_busywait_mbox(mraid_device_t *raid_dev) 284862306a36Sopenharmony_ci{ 284962306a36Sopenharmony_ci mbox_t *mbox = raid_dev->mbox; 285062306a36Sopenharmony_ci int i = 0; 285162306a36Sopenharmony_ci 285262306a36Sopenharmony_ci if (mbox->busy) { 285362306a36Sopenharmony_ci udelay(25); 285462306a36Sopenharmony_ci for (i = 0; mbox->busy && i < 1000; i++) 285562306a36Sopenharmony_ci msleep(1); 285662306a36Sopenharmony_ci } 285762306a36Sopenharmony_ci 285862306a36Sopenharmony_ci if (i < 1000) return 0; 285962306a36Sopenharmony_ci else return -1; 286062306a36Sopenharmony_ci} 286162306a36Sopenharmony_ci 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci/** 286462306a36Sopenharmony_ci * megaraid_mbox_product_info - some static information about the controller 286562306a36Sopenharmony_ci * @adapter : our soft state 286662306a36Sopenharmony_ci * 286762306a36Sopenharmony_ci * Issue commands to the controller to grab some parameters required by our 286862306a36Sopenharmony_ci * caller. 286962306a36Sopenharmony_ci */ 287062306a36Sopenharmony_cistatic int 287162306a36Sopenharmony_cimegaraid_mbox_product_info(adapter_t *adapter) 287262306a36Sopenharmony_ci{ 287362306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 287462306a36Sopenharmony_ci mbox_t *mbox; 287562306a36Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 287662306a36Sopenharmony_ci mraid_pinfo_t *pinfo; 287762306a36Sopenharmony_ci dma_addr_t pinfo_dma_h; 287862306a36Sopenharmony_ci mraid_inquiry3_t *mraid_inq3; 287962306a36Sopenharmony_ci int i; 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); 288362306a36Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 288462306a36Sopenharmony_ci 288562306a36Sopenharmony_ci /* 288662306a36Sopenharmony_ci * Issue an ENQUIRY3 command to find out certain adapter parameters, 288762306a36Sopenharmony_ci * e.g., max channels, max commands etc. 288862306a36Sopenharmony_ci */ 288962306a36Sopenharmony_ci pinfo = dma_alloc_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), 289062306a36Sopenharmony_ci &pinfo_dma_h, GFP_KERNEL); 289162306a36Sopenharmony_ci if (pinfo == NULL) { 289262306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 289362306a36Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 289462306a36Sopenharmony_ci __LINE__)); 289562306a36Sopenharmony_ci 289662306a36Sopenharmony_ci return -1; 289762306a36Sopenharmony_ci } 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; 290062306a36Sopenharmony_ci memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); 290162306a36Sopenharmony_ci 290262306a36Sopenharmony_ci raw_mbox[0] = FC_NEW_CONFIG; 290362306a36Sopenharmony_ci raw_mbox[2] = NC_SUBOP_ENQUIRY3; 290462306a36Sopenharmony_ci raw_mbox[3] = ENQ3_GET_SOLICITED_FULL; 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci // Issue the command 290762306a36Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { 290862306a36Sopenharmony_ci 290962306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING "megaraid: Inquiry3 failed\n")); 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), 291262306a36Sopenharmony_ci pinfo, pinfo_dma_h); 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ci return -1; 291562306a36Sopenharmony_ci } 291662306a36Sopenharmony_ci 291762306a36Sopenharmony_ci /* 291862306a36Sopenharmony_ci * Collect information about state of each physical drive 291962306a36Sopenharmony_ci * attached to the controller. We will expose all the disks 292062306a36Sopenharmony_ci * which are not part of RAID 292162306a36Sopenharmony_ci */ 292262306a36Sopenharmony_ci mraid_inq3 = (mraid_inquiry3_t *)adapter->ibuf; 292362306a36Sopenharmony_ci for (i = 0; i < MBOX_MAX_PHYSICAL_DRIVES; i++) { 292462306a36Sopenharmony_ci raid_dev->pdrv_state[i] = mraid_inq3->pdrv_state[i]; 292562306a36Sopenharmony_ci } 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ci /* 292862306a36Sopenharmony_ci * Get product info for information like number of channels, 292962306a36Sopenharmony_ci * maximum commands supported. 293062306a36Sopenharmony_ci */ 293162306a36Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); 293262306a36Sopenharmony_ci mbox->xferaddr = (uint32_t)pinfo_dma_h; 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci raw_mbox[0] = FC_NEW_CONFIG; 293562306a36Sopenharmony_ci raw_mbox[2] = NC_SUBOP_PRODUCT_INFO; 293662306a36Sopenharmony_ci 293762306a36Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { 293862306a36Sopenharmony_ci 293962306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 294062306a36Sopenharmony_ci "megaraid: product info failed\n")); 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), 294362306a36Sopenharmony_ci pinfo, pinfo_dma_h); 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci return -1; 294662306a36Sopenharmony_ci } 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_ci /* 294962306a36Sopenharmony_ci * Setup some parameters for host, as required by our caller 295062306a36Sopenharmony_ci */ 295162306a36Sopenharmony_ci adapter->max_channel = pinfo->nchannels; 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci /* 295462306a36Sopenharmony_ci * we will export all the logical drives on a single channel. 295562306a36Sopenharmony_ci * Add 1 since inquires do not come for inititor ID 295662306a36Sopenharmony_ci */ 295762306a36Sopenharmony_ci adapter->max_target = MAX_LOGICAL_DRIVES_40LD + 1; 295862306a36Sopenharmony_ci adapter->max_lun = 8; // up to 8 LUNs for non-disk devices 295962306a36Sopenharmony_ci 296062306a36Sopenharmony_ci /* 296162306a36Sopenharmony_ci * These are the maximum outstanding commands for the scsi-layer 296262306a36Sopenharmony_ci */ 296362306a36Sopenharmony_ci adapter->max_cmds = MBOX_MAX_SCSI_CMDS; 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci memset(adapter->fw_version, 0, VERSION_SIZE); 296662306a36Sopenharmony_ci memset(adapter->bios_version, 0, VERSION_SIZE); 296762306a36Sopenharmony_ci 296862306a36Sopenharmony_ci memcpy(adapter->fw_version, pinfo->fw_version, 4); 296962306a36Sopenharmony_ci adapter->fw_version[4] = 0; 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ci memcpy(adapter->bios_version, pinfo->bios_version, 4); 297262306a36Sopenharmony_ci adapter->bios_version[4] = 0; 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 297562306a36Sopenharmony_ci "megaraid: fw version:[%s] bios version:[%s]\n", 297662306a36Sopenharmony_ci adapter->fw_version, adapter->bios_version)); 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), pinfo, 297962306a36Sopenharmony_ci pinfo_dma_h); 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci return 0; 298262306a36Sopenharmony_ci} 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci 298562306a36Sopenharmony_ci 298662306a36Sopenharmony_ci/** 298762306a36Sopenharmony_ci * megaraid_mbox_extended_cdb - check for support for extended CDBs 298862306a36Sopenharmony_ci * @adapter : soft state for the controller 298962306a36Sopenharmony_ci * 299062306a36Sopenharmony_ci * This routine check whether the controller in question supports extended 299162306a36Sopenharmony_ci * ( > 10 bytes ) CDBs. 299262306a36Sopenharmony_ci */ 299362306a36Sopenharmony_cistatic int 299462306a36Sopenharmony_cimegaraid_mbox_extended_cdb(adapter_t *adapter) 299562306a36Sopenharmony_ci{ 299662306a36Sopenharmony_ci mbox_t *mbox; 299762306a36Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 299862306a36Sopenharmony_ci int rval; 299962306a36Sopenharmony_ci 300062306a36Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); 300362306a36Sopenharmony_ci mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_ci memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); 300662306a36Sopenharmony_ci 300762306a36Sopenharmony_ci raw_mbox[0] = MAIN_MISC_OPCODE; 300862306a36Sopenharmony_ci raw_mbox[2] = SUPPORT_EXT_CDB; 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_ci /* 301162306a36Sopenharmony_ci * Issue the command 301262306a36Sopenharmony_ci */ 301362306a36Sopenharmony_ci rval = 0; 301462306a36Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { 301562306a36Sopenharmony_ci rval = -1; 301662306a36Sopenharmony_ci } 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci return rval; 301962306a36Sopenharmony_ci} 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci 302262306a36Sopenharmony_ci/** 302362306a36Sopenharmony_ci * megaraid_mbox_support_ha - Do we support clustering 302462306a36Sopenharmony_ci * @adapter : soft state for the controller 302562306a36Sopenharmony_ci * @init_id : ID of the initiator 302662306a36Sopenharmony_ci * 302762306a36Sopenharmony_ci * Determine if the firmware supports clustering and the ID of the initiator. 302862306a36Sopenharmony_ci */ 302962306a36Sopenharmony_cistatic int 303062306a36Sopenharmony_cimegaraid_mbox_support_ha(adapter_t *adapter, uint16_t *init_id) 303162306a36Sopenharmony_ci{ 303262306a36Sopenharmony_ci mbox_t *mbox; 303362306a36Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 303462306a36Sopenharmony_ci int rval; 303562306a36Sopenharmony_ci 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 303862306a36Sopenharmony_ci 303962306a36Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); 304062306a36Sopenharmony_ci 304162306a36Sopenharmony_ci mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; 304262306a36Sopenharmony_ci 304362306a36Sopenharmony_ci memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci raw_mbox[0] = GET_TARGET_ID; 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_ci // Issue the command 304862306a36Sopenharmony_ci *init_id = 7; 304962306a36Sopenharmony_ci rval = -1; 305062306a36Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_ci *init_id = *(uint8_t *)adapter->ibuf; 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_ci con_log(CL_ANN, (KERN_INFO 305562306a36Sopenharmony_ci "megaraid: cluster firmware, initiator ID: %d\n", 305662306a36Sopenharmony_ci *init_id)); 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci rval = 0; 305962306a36Sopenharmony_ci } 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_ci return rval; 306262306a36Sopenharmony_ci} 306362306a36Sopenharmony_ci 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_ci/** 306662306a36Sopenharmony_ci * megaraid_mbox_support_random_del - Do we support random deletion 306762306a36Sopenharmony_ci * @adapter : soft state for the controller 306862306a36Sopenharmony_ci * 306962306a36Sopenharmony_ci * Determine if the firmware supports random deletion. 307062306a36Sopenharmony_ci * Return: 1 is operation supported, 0 otherwise 307162306a36Sopenharmony_ci */ 307262306a36Sopenharmony_cistatic int 307362306a36Sopenharmony_cimegaraid_mbox_support_random_del(adapter_t *adapter) 307462306a36Sopenharmony_ci{ 307562306a36Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 307662306a36Sopenharmony_ci int rval; 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ci /* 307962306a36Sopenharmony_ci * Newer firmware on Dell CERC expect a different 308062306a36Sopenharmony_ci * random deletion handling, so disable it. 308162306a36Sopenharmony_ci */ 308262306a36Sopenharmony_ci if (adapter->pdev->vendor == PCI_VENDOR_ID_AMI && 308362306a36Sopenharmony_ci adapter->pdev->device == PCI_DEVICE_ID_AMI_MEGARAID3 && 308462306a36Sopenharmony_ci adapter->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL && 308562306a36Sopenharmony_ci adapter->pdev->subsystem_device == PCI_SUBSYS_ID_CERC_ATA100_4CH && 308662306a36Sopenharmony_ci (adapter->fw_version[0] > '6' || 308762306a36Sopenharmony_ci (adapter->fw_version[0] == '6' && 308862306a36Sopenharmony_ci adapter->fw_version[2] > '6') || 308962306a36Sopenharmony_ci (adapter->fw_version[0] == '6' 309062306a36Sopenharmony_ci && adapter->fw_version[2] == '6' 309162306a36Sopenharmony_ci && adapter->fw_version[3] > '1'))) { 309262306a36Sopenharmony_ci con_log(CL_DLEVEL1, ("megaraid: disable random deletion\n")); 309362306a36Sopenharmony_ci return 0; 309462306a36Sopenharmony_ci } 309562306a36Sopenharmony_ci 309662306a36Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_ci raw_mbox[0] = FC_DEL_LOGDRV; 309962306a36Sopenharmony_ci raw_mbox[2] = OP_SUP_DEL_LOGDRV; 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci // Issue the command 310262306a36Sopenharmony_ci rval = 0; 310362306a36Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { 310462306a36Sopenharmony_ci 310562306a36Sopenharmony_ci con_log(CL_DLEVEL1, ("megaraid: supports random deletion\n")); 310662306a36Sopenharmony_ci 310762306a36Sopenharmony_ci rval = 1; 310862306a36Sopenharmony_ci } 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci return rval; 311162306a36Sopenharmony_ci} 311262306a36Sopenharmony_ci 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci/** 311562306a36Sopenharmony_ci * megaraid_mbox_get_max_sg - maximum sg elements supported by the firmware 311662306a36Sopenharmony_ci * @adapter : soft state for the controller 311762306a36Sopenharmony_ci * 311862306a36Sopenharmony_ci * Find out the maximum number of scatter-gather elements supported by the 311962306a36Sopenharmony_ci * firmware. 312062306a36Sopenharmony_ci */ 312162306a36Sopenharmony_cistatic int 312262306a36Sopenharmony_cimegaraid_mbox_get_max_sg(adapter_t *adapter) 312362306a36Sopenharmony_ci{ 312462306a36Sopenharmony_ci mbox_t *mbox; 312562306a36Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 312662306a36Sopenharmony_ci int nsg; 312762306a36Sopenharmony_ci 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 313062306a36Sopenharmony_ci 313162306a36Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_ci mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; 313462306a36Sopenharmony_ci 313562306a36Sopenharmony_ci memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci raw_mbox[0] = MAIN_MISC_OPCODE; 313862306a36Sopenharmony_ci raw_mbox[2] = GET_MAX_SG_SUPPORT; 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_ci // Issue the command 314162306a36Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { 314262306a36Sopenharmony_ci nsg = *(uint8_t *)adapter->ibuf; 314362306a36Sopenharmony_ci } 314462306a36Sopenharmony_ci else { 314562306a36Sopenharmony_ci nsg = MBOX_DEFAULT_SG_SIZE; 314662306a36Sopenharmony_ci } 314762306a36Sopenharmony_ci 314862306a36Sopenharmony_ci if (nsg > MBOX_MAX_SG_SIZE) nsg = MBOX_MAX_SG_SIZE; 314962306a36Sopenharmony_ci 315062306a36Sopenharmony_ci return nsg; 315162306a36Sopenharmony_ci} 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci 315462306a36Sopenharmony_ci/** 315562306a36Sopenharmony_ci * megaraid_mbox_enum_raid_scsi - enumerate the RAID and SCSI channels 315662306a36Sopenharmony_ci * @adapter : soft state for the controller 315762306a36Sopenharmony_ci * 315862306a36Sopenharmony_ci * Enumerate the RAID and SCSI channels for ROMB platforms so that channels 315962306a36Sopenharmony_ci * can be exported as regular SCSI channels. 316062306a36Sopenharmony_ci */ 316162306a36Sopenharmony_cistatic void 316262306a36Sopenharmony_cimegaraid_mbox_enum_raid_scsi(adapter_t *adapter) 316362306a36Sopenharmony_ci{ 316462306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 316562306a36Sopenharmony_ci mbox_t *mbox; 316662306a36Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_ci 316962306a36Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 317062306a36Sopenharmony_ci 317162306a36Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ci memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); 317662306a36Sopenharmony_ci 317762306a36Sopenharmony_ci raw_mbox[0] = CHNL_CLASS; 317862306a36Sopenharmony_ci raw_mbox[2] = GET_CHNL_CLASS; 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_ci // Issue the command. If the command fails, all channels are RAID 318162306a36Sopenharmony_ci // channels 318262306a36Sopenharmony_ci raid_dev->channel_class = 0xFF; 318362306a36Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { 318462306a36Sopenharmony_ci raid_dev->channel_class = *(uint8_t *)adapter->ibuf; 318562306a36Sopenharmony_ci } 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci return; 318862306a36Sopenharmony_ci} 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci/** 319262306a36Sopenharmony_ci * megaraid_mbox_flush_cache - flush adapter and disks cache 319362306a36Sopenharmony_ci * @adapter : soft state for the controller 319462306a36Sopenharmony_ci * 319562306a36Sopenharmony_ci * Flush adapter cache followed by disks cache. 319662306a36Sopenharmony_ci */ 319762306a36Sopenharmony_cistatic void 319862306a36Sopenharmony_cimegaraid_mbox_flush_cache(adapter_t *adapter) 319962306a36Sopenharmony_ci{ 320062306a36Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 320162306a36Sopenharmony_ci 320262306a36Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); 320362306a36Sopenharmony_ci 320462306a36Sopenharmony_ci raw_mbox[0] = FLUSH_ADAPTER; 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { 320762306a36Sopenharmony_ci con_log(CL_ANN, ("megaraid: flush adapter failed\n")); 320862306a36Sopenharmony_ci } 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci raw_mbox[0] = FLUSH_SYSTEM; 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_ci if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { 321362306a36Sopenharmony_ci con_log(CL_ANN, ("megaraid: flush disks cache failed\n")); 321462306a36Sopenharmony_ci } 321562306a36Sopenharmony_ci 321662306a36Sopenharmony_ci return; 321762306a36Sopenharmony_ci} 321862306a36Sopenharmony_ci 321962306a36Sopenharmony_ci 322062306a36Sopenharmony_ci/** 322162306a36Sopenharmony_ci * megaraid_mbox_fire_sync_cmd - fire the sync cmd 322262306a36Sopenharmony_ci * @adapter : soft state for the controller 322362306a36Sopenharmony_ci * 322462306a36Sopenharmony_ci * Clears the pending cmds in FW and reinits its RAID structs. 322562306a36Sopenharmony_ci */ 322662306a36Sopenharmony_cistatic int 322762306a36Sopenharmony_cimegaraid_mbox_fire_sync_cmd(adapter_t *adapter) 322862306a36Sopenharmony_ci{ 322962306a36Sopenharmony_ci mbox_t *mbox; 323062306a36Sopenharmony_ci uint8_t raw_mbox[sizeof(mbox_t)]; 323162306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 323262306a36Sopenharmony_ci int status = 0; 323362306a36Sopenharmony_ci int i; 323462306a36Sopenharmony_ci uint32_t dword; 323562306a36Sopenharmony_ci 323662306a36Sopenharmony_ci memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); 323762306a36Sopenharmony_ci 323862306a36Sopenharmony_ci raw_mbox[0] = 0xFF; 323962306a36Sopenharmony_ci 324062306a36Sopenharmony_ci mbox = raid_dev->mbox; 324162306a36Sopenharmony_ci 324262306a36Sopenharmony_ci /* Wait until mailbox is free */ 324362306a36Sopenharmony_ci if (megaraid_busywait_mbox(raid_dev) != 0) { 324462306a36Sopenharmony_ci status = 1; 324562306a36Sopenharmony_ci goto blocked_mailbox; 324662306a36Sopenharmony_ci } 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci /* Copy mailbox data into host structure */ 324962306a36Sopenharmony_ci memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16); 325062306a36Sopenharmony_ci mbox->cmdid = 0xFE; 325162306a36Sopenharmony_ci mbox->busy = 1; 325262306a36Sopenharmony_ci mbox->poll = 0; 325362306a36Sopenharmony_ci mbox->ack = 0; 325462306a36Sopenharmony_ci mbox->numstatus = 0; 325562306a36Sopenharmony_ci mbox->status = 0; 325662306a36Sopenharmony_ci 325762306a36Sopenharmony_ci wmb(); 325862306a36Sopenharmony_ci WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ci /* Wait for maximum 1 min for status to post. 326162306a36Sopenharmony_ci * If the Firmware SUPPORTS the ABOVE COMMAND, 326262306a36Sopenharmony_ci * mbox->cmd will be set to 0 326362306a36Sopenharmony_ci * else 326462306a36Sopenharmony_ci * the firmware will reject the command with 326562306a36Sopenharmony_ci * mbox->numstatus set to 1 326662306a36Sopenharmony_ci */ 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_ci i = 0; 326962306a36Sopenharmony_ci status = 0; 327062306a36Sopenharmony_ci while (!mbox->numstatus && mbox->cmd == 0xFF) { 327162306a36Sopenharmony_ci rmb(); 327262306a36Sopenharmony_ci msleep(1); 327362306a36Sopenharmony_ci i++; 327462306a36Sopenharmony_ci if (i > 1000 * 60) { 327562306a36Sopenharmony_ci status = 1; 327662306a36Sopenharmony_ci break; 327762306a36Sopenharmony_ci } 327862306a36Sopenharmony_ci } 327962306a36Sopenharmony_ci if (mbox->numstatus == 1) 328062306a36Sopenharmony_ci status = 1; /*cmd not supported*/ 328162306a36Sopenharmony_ci 328262306a36Sopenharmony_ci /* Check for interrupt line */ 328362306a36Sopenharmony_ci dword = RDOUTDOOR(raid_dev); 328462306a36Sopenharmony_ci WROUTDOOR(raid_dev, dword); 328562306a36Sopenharmony_ci WRINDOOR(raid_dev,2); 328662306a36Sopenharmony_ci 328762306a36Sopenharmony_ci return status; 328862306a36Sopenharmony_ci 328962306a36Sopenharmony_ciblocked_mailbox: 329062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n")); 329162306a36Sopenharmony_ci return status; 329262306a36Sopenharmony_ci} 329362306a36Sopenharmony_ci 329462306a36Sopenharmony_ci/** 329562306a36Sopenharmony_ci * megaraid_mbox_display_scb - display SCB information, mostly debug purposes 329662306a36Sopenharmony_ci * @adapter : controller's soft state 329762306a36Sopenharmony_ci * @scb : SCB to be displayed 329862306a36Sopenharmony_ci * 329962306a36Sopenharmony_ci * Diplay information about the given SCB iff the current debug level is 330062306a36Sopenharmony_ci * verbose. 330162306a36Sopenharmony_ci */ 330262306a36Sopenharmony_cistatic void 330362306a36Sopenharmony_cimegaraid_mbox_display_scb(adapter_t *adapter, scb_t *scb) 330462306a36Sopenharmony_ci{ 330562306a36Sopenharmony_ci mbox_ccb_t *ccb; 330662306a36Sopenharmony_ci struct scsi_cmnd *scp; 330762306a36Sopenharmony_ci mbox_t *mbox; 330862306a36Sopenharmony_ci int level; 330962306a36Sopenharmony_ci int i; 331062306a36Sopenharmony_ci 331162306a36Sopenharmony_ci 331262306a36Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 331362306a36Sopenharmony_ci scp = scb->scp; 331462306a36Sopenharmony_ci mbox = ccb->mbox; 331562306a36Sopenharmony_ci 331662306a36Sopenharmony_ci level = CL_DLEVEL3; 331762306a36Sopenharmony_ci 331862306a36Sopenharmony_ci con_log(level, (KERN_NOTICE 331962306a36Sopenharmony_ci "megaraid mailbox: status:%#x cmd:%#x id:%#x ", scb->status, 332062306a36Sopenharmony_ci mbox->cmd, scb->sno)); 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ci con_log(level, ("sec:%#x lba:%#x addr:%#x ld:%d sg:%d\n", 332362306a36Sopenharmony_ci mbox->numsectors, mbox->lba, mbox->xferaddr, mbox->logdrv, 332462306a36Sopenharmony_ci mbox->numsge)); 332562306a36Sopenharmony_ci 332662306a36Sopenharmony_ci if (!scp) return; 332762306a36Sopenharmony_ci 332862306a36Sopenharmony_ci con_log(level, (KERN_NOTICE "scsi cmnd: ")); 332962306a36Sopenharmony_ci 333062306a36Sopenharmony_ci for (i = 0; i < scp->cmd_len; i++) { 333162306a36Sopenharmony_ci con_log(level, ("%#2.02x ", scp->cmnd[i])); 333262306a36Sopenharmony_ci } 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci con_log(level, ("\n")); 333562306a36Sopenharmony_ci 333662306a36Sopenharmony_ci return; 333762306a36Sopenharmony_ci} 333862306a36Sopenharmony_ci 333962306a36Sopenharmony_ci 334062306a36Sopenharmony_ci/** 334162306a36Sopenharmony_ci * megaraid_mbox_setup_device_map - manage device ids 334262306a36Sopenharmony_ci * @adapter : Driver's soft state 334362306a36Sopenharmony_ci * 334462306a36Sopenharmony_ci * Manage the device ids to have an appropriate mapping between the kernel 334562306a36Sopenharmony_ci * scsi addresses and megaraid scsi and logical drive addresses. We export 334662306a36Sopenharmony_ci * scsi devices on their actual addresses, whereas the logical drives are 334762306a36Sopenharmony_ci * exported on a virtual scsi channel. 334862306a36Sopenharmony_ci */ 334962306a36Sopenharmony_cistatic void 335062306a36Sopenharmony_cimegaraid_mbox_setup_device_map(adapter_t *adapter) 335162306a36Sopenharmony_ci{ 335262306a36Sopenharmony_ci uint8_t c; 335362306a36Sopenharmony_ci uint8_t t; 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_ci /* 335662306a36Sopenharmony_ci * First fill the values on the logical drive channel 335762306a36Sopenharmony_ci */ 335862306a36Sopenharmony_ci for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++) 335962306a36Sopenharmony_ci adapter->device_ids[adapter->max_channel][t] = 336062306a36Sopenharmony_ci (t < adapter->init_id) ? t : t - 1; 336162306a36Sopenharmony_ci 336262306a36Sopenharmony_ci adapter->device_ids[adapter->max_channel][adapter->init_id] = 0xFF; 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci /* 336562306a36Sopenharmony_ci * Fill the values on the physical devices channels 336662306a36Sopenharmony_ci */ 336762306a36Sopenharmony_ci for (c = 0; c < adapter->max_channel; c++) 336862306a36Sopenharmony_ci for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++) 336962306a36Sopenharmony_ci adapter->device_ids[c][t] = (c << 8) | t; 337062306a36Sopenharmony_ci} 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci 337362306a36Sopenharmony_ci/* 337462306a36Sopenharmony_ci * END: internal commands library 337562306a36Sopenharmony_ci */ 337662306a36Sopenharmony_ci 337762306a36Sopenharmony_ci/* 337862306a36Sopenharmony_ci * START: Interface for the common management module 337962306a36Sopenharmony_ci * 338062306a36Sopenharmony_ci * This is the module, which interfaces with the common management module to 338162306a36Sopenharmony_ci * provide support for ioctl and sysfs 338262306a36Sopenharmony_ci */ 338362306a36Sopenharmony_ci 338462306a36Sopenharmony_ci/** 338562306a36Sopenharmony_ci * megaraid_cmm_register - register with the management module 338662306a36Sopenharmony_ci * @adapter : HBA soft state 338762306a36Sopenharmony_ci * 338862306a36Sopenharmony_ci * Register with the management module, which allows applications to issue 338962306a36Sopenharmony_ci * ioctl calls to the drivers. This interface is used by the management module 339062306a36Sopenharmony_ci * to setup sysfs support as well. 339162306a36Sopenharmony_ci */ 339262306a36Sopenharmony_cistatic int 339362306a36Sopenharmony_cimegaraid_cmm_register(adapter_t *adapter) 339462306a36Sopenharmony_ci{ 339562306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 339662306a36Sopenharmony_ci mraid_mmadp_t adp; 339762306a36Sopenharmony_ci scb_t *scb; 339862306a36Sopenharmony_ci mbox_ccb_t *ccb; 339962306a36Sopenharmony_ci int rval; 340062306a36Sopenharmony_ci int i; 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_ci // Allocate memory for the base list of scb for management module. 340362306a36Sopenharmony_ci adapter->uscb_list = kcalloc(MBOX_MAX_USER_CMDS, sizeof(scb_t), GFP_KERNEL); 340462306a36Sopenharmony_ci 340562306a36Sopenharmony_ci if (adapter->uscb_list == NULL) { 340662306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 340762306a36Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 340862306a36Sopenharmony_ci __LINE__)); 340962306a36Sopenharmony_ci return -1; 341062306a36Sopenharmony_ci } 341162306a36Sopenharmony_ci 341262306a36Sopenharmony_ci 341362306a36Sopenharmony_ci // Initialize the synchronization parameters for resources for 341462306a36Sopenharmony_ci // commands for management module 341562306a36Sopenharmony_ci INIT_LIST_HEAD(&adapter->uscb_pool); 341662306a36Sopenharmony_ci 341762306a36Sopenharmony_ci spin_lock_init(USER_FREE_LIST_LOCK(adapter)); 341862306a36Sopenharmony_ci 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci 342162306a36Sopenharmony_ci // link all the packets. Note, CCB for commands, coming from the 342262306a36Sopenharmony_ci // commom management module, mailbox physical address are already 342362306a36Sopenharmony_ci // setup by it. We just need placeholder for that in our local command 342462306a36Sopenharmony_ci // control blocks 342562306a36Sopenharmony_ci for (i = 0; i < MBOX_MAX_USER_CMDS; i++) { 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci scb = adapter->uscb_list + i; 342862306a36Sopenharmony_ci ccb = raid_dev->uccb_list + i; 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_ci scb->ccb = (caddr_t)ccb; 343162306a36Sopenharmony_ci ccb->mbox64 = raid_dev->umbox64 + i; 343262306a36Sopenharmony_ci ccb->mbox = &ccb->mbox64->mbox32; 343362306a36Sopenharmony_ci ccb->raw_mbox = (uint8_t *)ccb->mbox; 343462306a36Sopenharmony_ci 343562306a36Sopenharmony_ci scb->gp = 0; 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci // COMMAND ID 0 - (MBOX_MAX_SCSI_CMDS-1) ARE RESERVED FOR 343862306a36Sopenharmony_ci // COMMANDS COMING FROM IO SUBSYSTEM (MID-LAYER) 343962306a36Sopenharmony_ci scb->sno = i + MBOX_MAX_SCSI_CMDS; 344062306a36Sopenharmony_ci 344162306a36Sopenharmony_ci scb->scp = NULL; 344262306a36Sopenharmony_ci scb->state = SCB_FREE; 344362306a36Sopenharmony_ci scb->dma_direction = DMA_NONE; 344462306a36Sopenharmony_ci scb->dma_type = MRAID_DMA_NONE; 344562306a36Sopenharmony_ci scb->dev_channel = -1; 344662306a36Sopenharmony_ci scb->dev_target = -1; 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci // put scb in the free pool 344962306a36Sopenharmony_ci list_add_tail(&scb->list, &adapter->uscb_pool); 345062306a36Sopenharmony_ci } 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci adp.unique_id = adapter->unique_id; 345362306a36Sopenharmony_ci adp.drvr_type = DRVRTYPE_MBOX; 345462306a36Sopenharmony_ci adp.drvr_data = (unsigned long)adapter; 345562306a36Sopenharmony_ci adp.pdev = adapter->pdev; 345662306a36Sopenharmony_ci adp.issue_uioc = megaraid_mbox_mm_handler; 345762306a36Sopenharmony_ci adp.timeout = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; 345862306a36Sopenharmony_ci adp.max_kioc = MBOX_MAX_USER_CMDS; 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci if ((rval = mraid_mm_register_adp(&adp)) != 0) { 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 346362306a36Sopenharmony_ci "megaraid mbox: did not register with CMM\n")); 346462306a36Sopenharmony_ci 346562306a36Sopenharmony_ci kfree(adapter->uscb_list); 346662306a36Sopenharmony_ci } 346762306a36Sopenharmony_ci 346862306a36Sopenharmony_ci return rval; 346962306a36Sopenharmony_ci} 347062306a36Sopenharmony_ci 347162306a36Sopenharmony_ci 347262306a36Sopenharmony_ci/** 347362306a36Sopenharmony_ci * megaraid_cmm_unregister - un-register with the management module 347462306a36Sopenharmony_ci * @adapter : HBA soft state 347562306a36Sopenharmony_ci * 347662306a36Sopenharmony_ci * Un-register with the management module. 347762306a36Sopenharmony_ci * FIXME: mgmt module must return failure for unregister if it has pending 347862306a36Sopenharmony_ci * commands in LLD. 347962306a36Sopenharmony_ci */ 348062306a36Sopenharmony_cistatic int 348162306a36Sopenharmony_cimegaraid_cmm_unregister(adapter_t *adapter) 348262306a36Sopenharmony_ci{ 348362306a36Sopenharmony_ci kfree(adapter->uscb_list); 348462306a36Sopenharmony_ci mraid_mm_unregister_adp(adapter->unique_id); 348562306a36Sopenharmony_ci return 0; 348662306a36Sopenharmony_ci} 348762306a36Sopenharmony_ci 348862306a36Sopenharmony_ci 348962306a36Sopenharmony_ci/** 349062306a36Sopenharmony_ci * megaraid_mbox_mm_handler - interface for CMM to issue commands to LLD 349162306a36Sopenharmony_ci * @drvr_data : LLD specific data 349262306a36Sopenharmony_ci * @kioc : CMM interface packet 349362306a36Sopenharmony_ci * @action : command action 349462306a36Sopenharmony_ci * 349562306a36Sopenharmony_ci * This routine is invoked whenever the Common Management Module (CMM) has a 349662306a36Sopenharmony_ci * command for us. The 'action' parameter specifies if this is a new command 349762306a36Sopenharmony_ci * or otherwise. 349862306a36Sopenharmony_ci */ 349962306a36Sopenharmony_cistatic int 350062306a36Sopenharmony_cimegaraid_mbox_mm_handler(unsigned long drvr_data, uioc_t *kioc, uint32_t action) 350162306a36Sopenharmony_ci{ 350262306a36Sopenharmony_ci adapter_t *adapter; 350362306a36Sopenharmony_ci 350462306a36Sopenharmony_ci if (action != IOCTL_ISSUE) { 350562306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 350662306a36Sopenharmony_ci "megaraid: unsupported management action:%#2x\n", 350762306a36Sopenharmony_ci action)); 350862306a36Sopenharmony_ci return (-ENOTSUPP); 350962306a36Sopenharmony_ci } 351062306a36Sopenharmony_ci 351162306a36Sopenharmony_ci adapter = (adapter_t *)drvr_data; 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_ci // make sure this adapter is not being detached right now. 351462306a36Sopenharmony_ci if (atomic_read(&adapter->being_detached)) { 351562306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 351662306a36Sopenharmony_ci "megaraid: reject management request, detaching\n")); 351762306a36Sopenharmony_ci return (-ENODEV); 351862306a36Sopenharmony_ci } 351962306a36Sopenharmony_ci 352062306a36Sopenharmony_ci switch (kioc->opcode) { 352162306a36Sopenharmony_ci 352262306a36Sopenharmony_ci case GET_ADAP_INFO: 352362306a36Sopenharmony_ci 352462306a36Sopenharmony_ci kioc->status = gather_hbainfo(adapter, (mraid_hba_info_t *) 352562306a36Sopenharmony_ci (unsigned long)kioc->buf_vaddr); 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci kioc->done(kioc); 352862306a36Sopenharmony_ci 352962306a36Sopenharmony_ci return kioc->status; 353062306a36Sopenharmony_ci 353162306a36Sopenharmony_ci case MBOX_CMD: 353262306a36Sopenharmony_ci 353362306a36Sopenharmony_ci return megaraid_mbox_mm_command(adapter, kioc); 353462306a36Sopenharmony_ci 353562306a36Sopenharmony_ci default: 353662306a36Sopenharmony_ci kioc->status = (-EINVAL); 353762306a36Sopenharmony_ci kioc->done(kioc); 353862306a36Sopenharmony_ci return (-EINVAL); 353962306a36Sopenharmony_ci } 354062306a36Sopenharmony_ci 354162306a36Sopenharmony_ci return 0; // not reached 354262306a36Sopenharmony_ci} 354362306a36Sopenharmony_ci 354462306a36Sopenharmony_ci/** 354562306a36Sopenharmony_ci * megaraid_mbox_mm_command - issues commands routed through CMM 354662306a36Sopenharmony_ci * @adapter : HBA soft state 354762306a36Sopenharmony_ci * @kioc : management command packet 354862306a36Sopenharmony_ci * 354962306a36Sopenharmony_ci * Issues commands, which are routed through the management module. 355062306a36Sopenharmony_ci */ 355162306a36Sopenharmony_cistatic int 355262306a36Sopenharmony_cimegaraid_mbox_mm_command(adapter_t *adapter, uioc_t *kioc) 355362306a36Sopenharmony_ci{ 355462306a36Sopenharmony_ci struct list_head *head = &adapter->uscb_pool; 355562306a36Sopenharmony_ci mbox64_t *mbox64; 355662306a36Sopenharmony_ci uint8_t *raw_mbox; 355762306a36Sopenharmony_ci scb_t *scb; 355862306a36Sopenharmony_ci mbox_ccb_t *ccb; 355962306a36Sopenharmony_ci unsigned long flags; 356062306a36Sopenharmony_ci 356162306a36Sopenharmony_ci // detach one scb from free pool 356262306a36Sopenharmony_ci spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags); 356362306a36Sopenharmony_ci 356462306a36Sopenharmony_ci if (list_empty(head)) { // should never happen because of CMM 356562306a36Sopenharmony_ci 356662306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 356762306a36Sopenharmony_ci "megaraid mbox: bug in cmm handler, lost resources\n")); 356862306a36Sopenharmony_ci 356962306a36Sopenharmony_ci spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); 357062306a36Sopenharmony_ci 357162306a36Sopenharmony_ci return (-EINVAL); 357262306a36Sopenharmony_ci } 357362306a36Sopenharmony_ci 357462306a36Sopenharmony_ci scb = list_entry(head->next, scb_t, list); 357562306a36Sopenharmony_ci list_del_init(&scb->list); 357662306a36Sopenharmony_ci 357762306a36Sopenharmony_ci spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); 357862306a36Sopenharmony_ci 357962306a36Sopenharmony_ci scb->state = SCB_ACTIVE; 358062306a36Sopenharmony_ci scb->dma_type = MRAID_DMA_NONE; 358162306a36Sopenharmony_ci scb->dma_direction = DMA_NONE; 358262306a36Sopenharmony_ci 358362306a36Sopenharmony_ci ccb = (mbox_ccb_t *)scb->ccb; 358462306a36Sopenharmony_ci mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; 358562306a36Sopenharmony_ci raw_mbox = (uint8_t *)&mbox64->mbox32; 358662306a36Sopenharmony_ci 358762306a36Sopenharmony_ci memcpy(ccb->mbox64, mbox64, sizeof(mbox64_t)); 358862306a36Sopenharmony_ci 358962306a36Sopenharmony_ci scb->gp = (unsigned long)kioc; 359062306a36Sopenharmony_ci 359162306a36Sopenharmony_ci /* 359262306a36Sopenharmony_ci * If it is a logdrv random delete operation, we have to wait till 359362306a36Sopenharmony_ci * there are no outstanding cmds at the fw and then issue it directly 359462306a36Sopenharmony_ci */ 359562306a36Sopenharmony_ci if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) { 359662306a36Sopenharmony_ci 359762306a36Sopenharmony_ci if (wait_till_fw_empty(adapter)) { 359862306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 359962306a36Sopenharmony_ci "megaraid mbox: LD delete, timed out\n")); 360062306a36Sopenharmony_ci 360162306a36Sopenharmony_ci kioc->status = -ETIME; 360262306a36Sopenharmony_ci 360362306a36Sopenharmony_ci scb->status = -1; 360462306a36Sopenharmony_ci 360562306a36Sopenharmony_ci megaraid_mbox_mm_done(adapter, scb); 360662306a36Sopenharmony_ci 360762306a36Sopenharmony_ci return (-ETIME); 360862306a36Sopenharmony_ci } 360962306a36Sopenharmony_ci 361062306a36Sopenharmony_ci INIT_LIST_HEAD(&scb->list); 361162306a36Sopenharmony_ci 361262306a36Sopenharmony_ci scb->state = SCB_ISSUED; 361362306a36Sopenharmony_ci if (mbox_post_cmd(adapter, scb) != 0) { 361462306a36Sopenharmony_ci 361562306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 361662306a36Sopenharmony_ci "megaraid mbox: LD delete, mailbox busy\n")); 361762306a36Sopenharmony_ci 361862306a36Sopenharmony_ci kioc->status = -EBUSY; 361962306a36Sopenharmony_ci 362062306a36Sopenharmony_ci scb->status = -1; 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_ci megaraid_mbox_mm_done(adapter, scb); 362362306a36Sopenharmony_ci 362462306a36Sopenharmony_ci return (-EBUSY); 362562306a36Sopenharmony_ci } 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci return 0; 362862306a36Sopenharmony_ci } 362962306a36Sopenharmony_ci 363062306a36Sopenharmony_ci // put the command on the pending list and execute 363162306a36Sopenharmony_ci megaraid_mbox_runpendq(adapter, scb); 363262306a36Sopenharmony_ci 363362306a36Sopenharmony_ci return 0; 363462306a36Sopenharmony_ci} 363562306a36Sopenharmony_ci 363662306a36Sopenharmony_ci 363762306a36Sopenharmony_cistatic int 363862306a36Sopenharmony_ciwait_till_fw_empty(adapter_t *adapter) 363962306a36Sopenharmony_ci{ 364062306a36Sopenharmony_ci unsigned long flags = 0; 364162306a36Sopenharmony_ci int i; 364262306a36Sopenharmony_ci 364362306a36Sopenharmony_ci 364462306a36Sopenharmony_ci /* 364562306a36Sopenharmony_ci * Set the quiescent flag to stop issuing cmds to FW. 364662306a36Sopenharmony_ci */ 364762306a36Sopenharmony_ci spin_lock_irqsave(&adapter->lock, flags); 364862306a36Sopenharmony_ci adapter->quiescent++; 364962306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->lock, flags); 365062306a36Sopenharmony_ci 365162306a36Sopenharmony_ci /* 365262306a36Sopenharmony_ci * Wait till there are no more cmds outstanding at FW. Try for at most 365362306a36Sopenharmony_ci * 60 seconds 365462306a36Sopenharmony_ci */ 365562306a36Sopenharmony_ci for (i = 0; i < 60 && adapter->outstanding_cmds; i++) { 365662306a36Sopenharmony_ci con_log(CL_DLEVEL1, (KERN_INFO 365762306a36Sopenharmony_ci "megaraid: FW has %d pending commands\n", 365862306a36Sopenharmony_ci adapter->outstanding_cmds)); 365962306a36Sopenharmony_ci 366062306a36Sopenharmony_ci msleep(1000); 366162306a36Sopenharmony_ci } 366262306a36Sopenharmony_ci 366362306a36Sopenharmony_ci return adapter->outstanding_cmds; 366462306a36Sopenharmony_ci} 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ci 366762306a36Sopenharmony_ci/** 366862306a36Sopenharmony_ci * megaraid_mbox_mm_done - callback for CMM commands 366962306a36Sopenharmony_ci * @adapter : HBA soft state 367062306a36Sopenharmony_ci * @scb : completed command 367162306a36Sopenharmony_ci * 367262306a36Sopenharmony_ci * Callback routine for internal commands originated from the management 367362306a36Sopenharmony_ci * module. 367462306a36Sopenharmony_ci */ 367562306a36Sopenharmony_cistatic void 367662306a36Sopenharmony_cimegaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb) 367762306a36Sopenharmony_ci{ 367862306a36Sopenharmony_ci uioc_t *kioc; 367962306a36Sopenharmony_ci mbox64_t *mbox64; 368062306a36Sopenharmony_ci uint8_t *raw_mbox; 368162306a36Sopenharmony_ci unsigned long flags; 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_ci kioc = (uioc_t *)scb->gp; 368462306a36Sopenharmony_ci mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; 368562306a36Sopenharmony_ci mbox64->mbox32.status = scb->status; 368662306a36Sopenharmony_ci raw_mbox = (uint8_t *)&mbox64->mbox32; 368762306a36Sopenharmony_ci 368862306a36Sopenharmony_ci 368962306a36Sopenharmony_ci // put scb in the free pool 369062306a36Sopenharmony_ci scb->state = SCB_FREE; 369162306a36Sopenharmony_ci scb->scp = NULL; 369262306a36Sopenharmony_ci 369362306a36Sopenharmony_ci spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags); 369462306a36Sopenharmony_ci 369562306a36Sopenharmony_ci list_add(&scb->list, &adapter->uscb_pool); 369662306a36Sopenharmony_ci 369762306a36Sopenharmony_ci spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); 369862306a36Sopenharmony_ci 369962306a36Sopenharmony_ci // if a delete logical drive operation succeeded, restart the 370062306a36Sopenharmony_ci // controller 370162306a36Sopenharmony_ci if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) { 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_ci adapter->quiescent--; 370462306a36Sopenharmony_ci 370562306a36Sopenharmony_ci megaraid_mbox_runpendq(adapter, NULL); 370662306a36Sopenharmony_ci } 370762306a36Sopenharmony_ci 370862306a36Sopenharmony_ci kioc->done(kioc); 370962306a36Sopenharmony_ci 371062306a36Sopenharmony_ci return; 371162306a36Sopenharmony_ci} 371262306a36Sopenharmony_ci 371362306a36Sopenharmony_ci 371462306a36Sopenharmony_ci/** 371562306a36Sopenharmony_ci * gather_hbainfo - HBA characteristics for the applications 371662306a36Sopenharmony_ci * @adapter : HBA soft state 371762306a36Sopenharmony_ci * @hinfo : pointer to the caller's host info strucuture 371862306a36Sopenharmony_ci */ 371962306a36Sopenharmony_cistatic int 372062306a36Sopenharmony_cigather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo) 372162306a36Sopenharmony_ci{ 372262306a36Sopenharmony_ci hinfo->pci_vendor_id = adapter->pdev->vendor; 372362306a36Sopenharmony_ci hinfo->pci_device_id = adapter->pdev->device; 372462306a36Sopenharmony_ci hinfo->subsys_vendor_id = adapter->pdev->subsystem_vendor; 372562306a36Sopenharmony_ci hinfo->subsys_device_id = adapter->pdev->subsystem_device; 372662306a36Sopenharmony_ci 372762306a36Sopenharmony_ci hinfo->pci_bus = adapter->pdev->bus->number; 372862306a36Sopenharmony_ci hinfo->pci_dev_fn = adapter->pdev->devfn; 372962306a36Sopenharmony_ci hinfo->pci_slot = PCI_SLOT(adapter->pdev->devfn); 373062306a36Sopenharmony_ci hinfo->irq = adapter->host->irq; 373162306a36Sopenharmony_ci hinfo->baseport = ADAP2RAIDDEV(adapter)->baseport; 373262306a36Sopenharmony_ci 373362306a36Sopenharmony_ci hinfo->unique_id = (hinfo->pci_bus << 8) | adapter->pdev->devfn; 373462306a36Sopenharmony_ci hinfo->host_no = adapter->host->host_no; 373562306a36Sopenharmony_ci 373662306a36Sopenharmony_ci return 0; 373762306a36Sopenharmony_ci} 373862306a36Sopenharmony_ci 373962306a36Sopenharmony_ci/* 374062306a36Sopenharmony_ci * END: Interface for the common management module 374162306a36Sopenharmony_ci */ 374262306a36Sopenharmony_ci 374362306a36Sopenharmony_ci 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci/** 374662306a36Sopenharmony_ci * megaraid_sysfs_alloc_resources - allocate sysfs related resources 374762306a36Sopenharmony_ci * @adapter : controller's soft state 374862306a36Sopenharmony_ci * 374962306a36Sopenharmony_ci * Allocate packets required to issue FW calls whenever the sysfs attributes 375062306a36Sopenharmony_ci * are read. These attributes would require up-to-date information from the 375162306a36Sopenharmony_ci * FW. Also set up resources for mutual exclusion to share these resources and 375262306a36Sopenharmony_ci * the wait queue. 375362306a36Sopenharmony_ci * 375462306a36Sopenharmony_ci * Return 0 on success. 375562306a36Sopenharmony_ci * Return -ERROR_CODE on failure. 375662306a36Sopenharmony_ci */ 375762306a36Sopenharmony_cistatic int 375862306a36Sopenharmony_cimegaraid_sysfs_alloc_resources(adapter_t *adapter) 375962306a36Sopenharmony_ci{ 376062306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 376162306a36Sopenharmony_ci int rval = 0; 376262306a36Sopenharmony_ci 376362306a36Sopenharmony_ci raid_dev->sysfs_uioc = kmalloc(sizeof(uioc_t), GFP_KERNEL); 376462306a36Sopenharmony_ci 376562306a36Sopenharmony_ci raid_dev->sysfs_mbox64 = kmalloc(sizeof(mbox64_t), GFP_KERNEL); 376662306a36Sopenharmony_ci 376762306a36Sopenharmony_ci raid_dev->sysfs_buffer = dma_alloc_coherent(&adapter->pdev->dev, 376862306a36Sopenharmony_ci PAGE_SIZE, &raid_dev->sysfs_buffer_dma, GFP_KERNEL); 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_ci if (!raid_dev->sysfs_uioc || !raid_dev->sysfs_mbox64 || 377162306a36Sopenharmony_ci !raid_dev->sysfs_buffer) { 377262306a36Sopenharmony_ci 377362306a36Sopenharmony_ci con_log(CL_ANN, (KERN_WARNING 377462306a36Sopenharmony_ci "megaraid: out of memory, %s %d\n", __func__, 377562306a36Sopenharmony_ci __LINE__)); 377662306a36Sopenharmony_ci 377762306a36Sopenharmony_ci rval = -ENOMEM; 377862306a36Sopenharmony_ci 377962306a36Sopenharmony_ci megaraid_sysfs_free_resources(adapter); 378062306a36Sopenharmony_ci } 378162306a36Sopenharmony_ci 378262306a36Sopenharmony_ci mutex_init(&raid_dev->sysfs_mtx); 378362306a36Sopenharmony_ci 378462306a36Sopenharmony_ci init_waitqueue_head(&raid_dev->sysfs_wait_q); 378562306a36Sopenharmony_ci 378662306a36Sopenharmony_ci return rval; 378762306a36Sopenharmony_ci} 378862306a36Sopenharmony_ci 378962306a36Sopenharmony_ci 379062306a36Sopenharmony_ci/** 379162306a36Sopenharmony_ci * megaraid_sysfs_free_resources - free sysfs related resources 379262306a36Sopenharmony_ci * @adapter : controller's soft state 379362306a36Sopenharmony_ci * 379462306a36Sopenharmony_ci * Free packets allocated for sysfs FW commands 379562306a36Sopenharmony_ci */ 379662306a36Sopenharmony_cistatic void 379762306a36Sopenharmony_cimegaraid_sysfs_free_resources(adapter_t *adapter) 379862306a36Sopenharmony_ci{ 379962306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 380062306a36Sopenharmony_ci 380162306a36Sopenharmony_ci kfree(raid_dev->sysfs_uioc); 380262306a36Sopenharmony_ci kfree(raid_dev->sysfs_mbox64); 380362306a36Sopenharmony_ci 380462306a36Sopenharmony_ci if (raid_dev->sysfs_buffer) { 380562306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, PAGE_SIZE, 380662306a36Sopenharmony_ci raid_dev->sysfs_buffer, raid_dev->sysfs_buffer_dma); 380762306a36Sopenharmony_ci } 380862306a36Sopenharmony_ci} 380962306a36Sopenharmony_ci 381062306a36Sopenharmony_ci 381162306a36Sopenharmony_ci/** 381262306a36Sopenharmony_ci * megaraid_sysfs_get_ldmap_done - callback for get ldmap 381362306a36Sopenharmony_ci * @uioc : completed packet 381462306a36Sopenharmony_ci * 381562306a36Sopenharmony_ci * Callback routine called in the ISR/tasklet context for get ldmap call 381662306a36Sopenharmony_ci */ 381762306a36Sopenharmony_cistatic void 381862306a36Sopenharmony_cimegaraid_sysfs_get_ldmap_done(uioc_t *uioc) 381962306a36Sopenharmony_ci{ 382062306a36Sopenharmony_ci adapter_t *adapter = (adapter_t *)uioc->buf_vaddr; 382162306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 382262306a36Sopenharmony_ci 382362306a36Sopenharmony_ci uioc->status = 0; 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_ci wake_up(&raid_dev->sysfs_wait_q); 382662306a36Sopenharmony_ci} 382762306a36Sopenharmony_ci 382862306a36Sopenharmony_ci/** 382962306a36Sopenharmony_ci * megaraid_sysfs_get_ldmap_timeout - timeout handling for get ldmap 383062306a36Sopenharmony_ci * @t : timed out timer 383162306a36Sopenharmony_ci * 383262306a36Sopenharmony_ci * Timeout routine to recover and return to application, in case the adapter 383362306a36Sopenharmony_ci * has stopped responding. A timeout of 60 seconds for this command seems like 383462306a36Sopenharmony_ci * a good value. 383562306a36Sopenharmony_ci */ 383662306a36Sopenharmony_cistatic void 383762306a36Sopenharmony_cimegaraid_sysfs_get_ldmap_timeout(struct timer_list *t) 383862306a36Sopenharmony_ci{ 383962306a36Sopenharmony_ci struct uioc_timeout *timeout = from_timer(timeout, t, timer); 384062306a36Sopenharmony_ci uioc_t *uioc = timeout->uioc; 384162306a36Sopenharmony_ci adapter_t *adapter = (adapter_t *)uioc->buf_vaddr; 384262306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 384362306a36Sopenharmony_ci 384462306a36Sopenharmony_ci uioc->status = -ETIME; 384562306a36Sopenharmony_ci 384662306a36Sopenharmony_ci wake_up(&raid_dev->sysfs_wait_q); 384762306a36Sopenharmony_ci} 384862306a36Sopenharmony_ci 384962306a36Sopenharmony_ci 385062306a36Sopenharmony_ci/** 385162306a36Sopenharmony_ci * megaraid_sysfs_get_ldmap - get update logical drive map 385262306a36Sopenharmony_ci * @adapter : controller's soft state 385362306a36Sopenharmony_ci * 385462306a36Sopenharmony_ci * This routine will be called whenever user reads the logical drive 385562306a36Sopenharmony_ci * attributes, go get the current logical drive mapping table from the 385662306a36Sopenharmony_ci * firmware. We use the management API's to issue commands to the controller. 385762306a36Sopenharmony_ci * 385862306a36Sopenharmony_ci * NOTE: The commands issuance functionality is not generalized and 385962306a36Sopenharmony_ci * implemented in context of "get ld map" command only. If required, the 386062306a36Sopenharmony_ci * command issuance logical can be trivially pulled out and implemented as a 386162306a36Sopenharmony_ci * standalone library. For now, this should suffice since there is no other 386262306a36Sopenharmony_ci * user of this interface. 386362306a36Sopenharmony_ci * 386462306a36Sopenharmony_ci * Return 0 on success. 386562306a36Sopenharmony_ci * Return -1 on failure. 386662306a36Sopenharmony_ci */ 386762306a36Sopenharmony_cistatic int 386862306a36Sopenharmony_cimegaraid_sysfs_get_ldmap(adapter_t *adapter) 386962306a36Sopenharmony_ci{ 387062306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 387162306a36Sopenharmony_ci uioc_t *uioc; 387262306a36Sopenharmony_ci mbox64_t *mbox64; 387362306a36Sopenharmony_ci mbox_t *mbox; 387462306a36Sopenharmony_ci char *raw_mbox; 387562306a36Sopenharmony_ci struct uioc_timeout timeout; 387662306a36Sopenharmony_ci caddr_t ldmap; 387762306a36Sopenharmony_ci int rval = 0; 387862306a36Sopenharmony_ci 387962306a36Sopenharmony_ci /* 388062306a36Sopenharmony_ci * Allow only one read at a time to go through the sysfs attributes 388162306a36Sopenharmony_ci */ 388262306a36Sopenharmony_ci mutex_lock(&raid_dev->sysfs_mtx); 388362306a36Sopenharmony_ci 388462306a36Sopenharmony_ci uioc = raid_dev->sysfs_uioc; 388562306a36Sopenharmony_ci mbox64 = raid_dev->sysfs_mbox64; 388662306a36Sopenharmony_ci ldmap = raid_dev->sysfs_buffer; 388762306a36Sopenharmony_ci 388862306a36Sopenharmony_ci memset(uioc, 0, sizeof(uioc_t)); 388962306a36Sopenharmony_ci memset(mbox64, 0, sizeof(mbox64_t)); 389062306a36Sopenharmony_ci memset(ldmap, 0, sizeof(raid_dev->curr_ldmap)); 389162306a36Sopenharmony_ci 389262306a36Sopenharmony_ci mbox = &mbox64->mbox32; 389362306a36Sopenharmony_ci raw_mbox = (char *)mbox; 389462306a36Sopenharmony_ci uioc->cmdbuf = (uint64_t)(unsigned long)mbox64; 389562306a36Sopenharmony_ci uioc->buf_vaddr = (caddr_t)adapter; 389662306a36Sopenharmony_ci uioc->status = -ENODATA; 389762306a36Sopenharmony_ci uioc->done = megaraid_sysfs_get_ldmap_done; 389862306a36Sopenharmony_ci 389962306a36Sopenharmony_ci /* 390062306a36Sopenharmony_ci * Prepare the mailbox packet to get the current logical drive mapping 390162306a36Sopenharmony_ci * table 390262306a36Sopenharmony_ci */ 390362306a36Sopenharmony_ci mbox->xferaddr = (uint32_t)raid_dev->sysfs_buffer_dma; 390462306a36Sopenharmony_ci 390562306a36Sopenharmony_ci raw_mbox[0] = FC_DEL_LOGDRV; 390662306a36Sopenharmony_ci raw_mbox[2] = OP_GET_LDID_MAP; 390762306a36Sopenharmony_ci 390862306a36Sopenharmony_ci /* 390962306a36Sopenharmony_ci * Setup a timer to recover from a non-responding controller 391062306a36Sopenharmony_ci */ 391162306a36Sopenharmony_ci timeout.uioc = uioc; 391262306a36Sopenharmony_ci timer_setup_on_stack(&timeout.timer, 391362306a36Sopenharmony_ci megaraid_sysfs_get_ldmap_timeout, 0); 391462306a36Sopenharmony_ci 391562306a36Sopenharmony_ci timeout.timer.expires = jiffies + 60 * HZ; 391662306a36Sopenharmony_ci add_timer(&timeout.timer); 391762306a36Sopenharmony_ci 391862306a36Sopenharmony_ci /* 391962306a36Sopenharmony_ci * Send the command to the firmware 392062306a36Sopenharmony_ci */ 392162306a36Sopenharmony_ci rval = megaraid_mbox_mm_command(adapter, uioc); 392262306a36Sopenharmony_ci 392362306a36Sopenharmony_ci if (rval == 0) { // command successfully issued 392462306a36Sopenharmony_ci wait_event(raid_dev->sysfs_wait_q, (uioc->status != -ENODATA)); 392562306a36Sopenharmony_ci 392662306a36Sopenharmony_ci /* 392762306a36Sopenharmony_ci * Check if the command timed out 392862306a36Sopenharmony_ci */ 392962306a36Sopenharmony_ci if (uioc->status == -ETIME) { 393062306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 393162306a36Sopenharmony_ci "megaraid: sysfs get ld map timed out\n")); 393262306a36Sopenharmony_ci 393362306a36Sopenharmony_ci rval = -ETIME; 393462306a36Sopenharmony_ci } 393562306a36Sopenharmony_ci else { 393662306a36Sopenharmony_ci rval = mbox->status; 393762306a36Sopenharmony_ci } 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_ci if (rval == 0) { 394062306a36Sopenharmony_ci memcpy(raid_dev->curr_ldmap, ldmap, 394162306a36Sopenharmony_ci sizeof(raid_dev->curr_ldmap)); 394262306a36Sopenharmony_ci } 394362306a36Sopenharmony_ci else { 394462306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 394562306a36Sopenharmony_ci "megaraid: get ld map failed with %x\n", rval)); 394662306a36Sopenharmony_ci } 394762306a36Sopenharmony_ci } 394862306a36Sopenharmony_ci else { 394962306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 395062306a36Sopenharmony_ci "megaraid: could not issue ldmap command:%x\n", rval)); 395162306a36Sopenharmony_ci } 395262306a36Sopenharmony_ci 395362306a36Sopenharmony_ci 395462306a36Sopenharmony_ci del_timer_sync(&timeout.timer); 395562306a36Sopenharmony_ci destroy_timer_on_stack(&timeout.timer); 395662306a36Sopenharmony_ci 395762306a36Sopenharmony_ci mutex_unlock(&raid_dev->sysfs_mtx); 395862306a36Sopenharmony_ci 395962306a36Sopenharmony_ci return rval; 396062306a36Sopenharmony_ci} 396162306a36Sopenharmony_ci 396262306a36Sopenharmony_ci 396362306a36Sopenharmony_ci/** 396462306a36Sopenharmony_ci * megaraid_mbox_app_hndl_show - display application handle for this adapter 396562306a36Sopenharmony_ci * @dev : class device object representation for the host 396662306a36Sopenharmony_ci * @attr : device attribute (unused) 396762306a36Sopenharmony_ci * @buf : buffer to send data to 396862306a36Sopenharmony_ci * 396962306a36Sopenharmony_ci * Display the handle used by the applications while executing management 397062306a36Sopenharmony_ci * tasks on the adapter. We invoke a management module API to get the adapter 397162306a36Sopenharmony_ci * handle, since we do not interface with applications directly. 397262306a36Sopenharmony_ci */ 397362306a36Sopenharmony_cistatic ssize_t 397462306a36Sopenharmony_cimegaraid_mbox_app_hndl_show(struct device *dev, struct device_attribute *attr, char *buf) 397562306a36Sopenharmony_ci{ 397662306a36Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 397762306a36Sopenharmony_ci adapter_t *adapter = (adapter_t *)SCSIHOST2ADAP(shost); 397862306a36Sopenharmony_ci uint32_t app_hndl; 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ci app_hndl = mraid_mm_adapter_app_handle(adapter->unique_id); 398162306a36Sopenharmony_ci 398262306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", app_hndl); 398362306a36Sopenharmony_ci} 398462306a36Sopenharmony_ci 398562306a36Sopenharmony_ci 398662306a36Sopenharmony_ci/** 398762306a36Sopenharmony_ci * megaraid_mbox_ld_show - display the logical drive number for this device 398862306a36Sopenharmony_ci * @dev : device object representation for the scsi device 398962306a36Sopenharmony_ci * @attr : device attribute to show 399062306a36Sopenharmony_ci * @buf : buffer to send data to 399162306a36Sopenharmony_ci * 399262306a36Sopenharmony_ci * Display the logical drive number for the device in question, if it a valid 399362306a36Sopenharmony_ci * logical drive. For physical devices, "-1" is returned. 399462306a36Sopenharmony_ci * 399562306a36Sopenharmony_ci * The logical drive number is displayed in following format: 399662306a36Sopenharmony_ci * 399762306a36Sopenharmony_ci * <SCSI ID> <LD NUM> <LD STICKY ID> <APP ADAPTER HANDLE> 399862306a36Sopenharmony_ci * 399962306a36Sopenharmony_ci * <int> <int> <int> <int> 400062306a36Sopenharmony_ci */ 400162306a36Sopenharmony_cistatic ssize_t 400262306a36Sopenharmony_cimegaraid_mbox_ld_show(struct device *dev, struct device_attribute *attr, char *buf) 400362306a36Sopenharmony_ci{ 400462306a36Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 400562306a36Sopenharmony_ci adapter_t *adapter = (adapter_t *)SCSIHOST2ADAP(sdev->host); 400662306a36Sopenharmony_ci mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); 400762306a36Sopenharmony_ci int scsi_id = -1; 400862306a36Sopenharmony_ci int logical_drv = -1; 400962306a36Sopenharmony_ci int ldid_map = -1; 401062306a36Sopenharmony_ci uint32_t app_hndl = 0; 401162306a36Sopenharmony_ci int mapped_sdev_id; 401262306a36Sopenharmony_ci int rval; 401362306a36Sopenharmony_ci int i; 401462306a36Sopenharmony_ci 401562306a36Sopenharmony_ci if (raid_dev->random_del_supported && 401662306a36Sopenharmony_ci MRAID_IS_LOGICAL_SDEV(adapter, sdev)) { 401762306a36Sopenharmony_ci 401862306a36Sopenharmony_ci rval = megaraid_sysfs_get_ldmap(adapter); 401962306a36Sopenharmony_ci if (rval == 0) { 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_ci for (i = 0; i < MAX_LOGICAL_DRIVES_40LD; i++) { 402262306a36Sopenharmony_ci 402362306a36Sopenharmony_ci mapped_sdev_id = sdev->id; 402462306a36Sopenharmony_ci 402562306a36Sopenharmony_ci if (sdev->id > adapter->init_id) { 402662306a36Sopenharmony_ci mapped_sdev_id -= 1; 402762306a36Sopenharmony_ci } 402862306a36Sopenharmony_ci 402962306a36Sopenharmony_ci if (raid_dev->curr_ldmap[i] == mapped_sdev_id) { 403062306a36Sopenharmony_ci 403162306a36Sopenharmony_ci scsi_id = sdev->id; 403262306a36Sopenharmony_ci 403362306a36Sopenharmony_ci logical_drv = i; 403462306a36Sopenharmony_ci 403562306a36Sopenharmony_ci ldid_map = raid_dev->curr_ldmap[i]; 403662306a36Sopenharmony_ci 403762306a36Sopenharmony_ci app_hndl = mraid_mm_adapter_app_handle( 403862306a36Sopenharmony_ci adapter->unique_id); 403962306a36Sopenharmony_ci 404062306a36Sopenharmony_ci break; 404162306a36Sopenharmony_ci } 404262306a36Sopenharmony_ci } 404362306a36Sopenharmony_ci } 404462306a36Sopenharmony_ci else { 404562306a36Sopenharmony_ci con_log(CL_ANN, (KERN_NOTICE 404662306a36Sopenharmony_ci "megaraid: sysfs get ld map failed: %x\n", 404762306a36Sopenharmony_ci rval)); 404862306a36Sopenharmony_ci } 404962306a36Sopenharmony_ci } 405062306a36Sopenharmony_ci 405162306a36Sopenharmony_ci return sysfs_emit(buf, "%d %d %d %d\n", scsi_id, logical_drv, 405262306a36Sopenharmony_ci ldid_map, app_hndl); 405362306a36Sopenharmony_ci} 405462306a36Sopenharmony_ci 405562306a36Sopenharmony_ci 405662306a36Sopenharmony_ci/* 405762306a36Sopenharmony_ci * END: Mailbox Low Level Driver 405862306a36Sopenharmony_ci */ 405962306a36Sopenharmony_cimodule_init(megaraid_init); 406062306a36Sopenharmony_cimodule_exit(megaraid_exit); 4061