18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux MegaRAID driver for SAS based RAID controllers 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2003-2013 LSI Corporation 68c2ecf20Sopenharmony_ci * Copyright (c) 2013-2016 Avago Technologies 78c2ecf20Sopenharmony_ci * Copyright (c) 2016-2018 Broadcom Inc. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Authors: Broadcom Inc. 108c2ecf20Sopenharmony_ci * Sreenivas Bagalkote 118c2ecf20Sopenharmony_ci * Sumant Patro 128c2ecf20Sopenharmony_ci * Bo Yang 138c2ecf20Sopenharmony_ci * Adam Radford 148c2ecf20Sopenharmony_ci * Kashyap Desai <kashyap.desai@broadcom.com> 158c2ecf20Sopenharmony_ci * Sumit Saxena <sumit.saxena@broadcom.com> 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Send feedback to: megaraidlinux.pdl@broadcom.com 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/types.h> 228c2ecf20Sopenharmony_ci#include <linux/pci.h> 238c2ecf20Sopenharmony_ci#include <linux/list.h> 248c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 258c2ecf20Sopenharmony_ci#include <linux/module.h> 268c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 278c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 288c2ecf20Sopenharmony_ci#include <linux/delay.h> 298c2ecf20Sopenharmony_ci#include <linux/uio.h> 308c2ecf20Sopenharmony_ci#include <linux/slab.h> 318c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 328c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 338c2ecf20Sopenharmony_ci#include <linux/fs.h> 348c2ecf20Sopenharmony_ci#include <linux/compat.h> 358c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 368c2ecf20Sopenharmony_ci#include <linux/mutex.h> 378c2ecf20Sopenharmony_ci#include <linux/poll.h> 388c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 398c2ecf20Sopenharmony_ci#include <linux/irq_poll.h> 408c2ecf20Sopenharmony_ci#include <linux/blk-mq-pci.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 438c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 448c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 458c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 468c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 478c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h> 488c2ecf20Sopenharmony_ci#include "megaraid_sas_fusion.h" 498c2ecf20Sopenharmony_ci#include "megaraid_sas.h" 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* 528c2ecf20Sopenharmony_ci * Number of sectors per IO command 538c2ecf20Sopenharmony_ci * Will be set in megasas_init_mfi if user does not provide 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_cistatic unsigned int max_sectors; 568c2ecf20Sopenharmony_cimodule_param_named(max_sectors, max_sectors, int, 0444); 578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_sectors, 588c2ecf20Sopenharmony_ci "Maximum number of sectors per IO command"); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic int msix_disable; 618c2ecf20Sopenharmony_cimodule_param(msix_disable, int, 0444); 628c2ecf20Sopenharmony_ciMODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0"); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic unsigned int msix_vectors; 658c2ecf20Sopenharmony_cimodule_param(msix_vectors, int, 0444); 668c2ecf20Sopenharmony_ciMODULE_PARM_DESC(msix_vectors, "MSI-X max vector count. Default: Set by FW"); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int allow_vf_ioctls; 698c2ecf20Sopenharmony_cimodule_param(allow_vf_ioctls, int, 0444); 708c2ecf20Sopenharmony_ciMODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0"); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic unsigned int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH; 738c2ecf20Sopenharmony_cimodule_param(throttlequeuedepth, int, 0444); 748c2ecf20Sopenharmony_ciMODULE_PARM_DESC(throttlequeuedepth, 758c2ecf20Sopenharmony_ci "Adapter queue depth when throttled due to I/O timeout. Default: 16"); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ciunsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME; 788c2ecf20Sopenharmony_cimodule_param(resetwaittime, int, 0444); 798c2ecf20Sopenharmony_ciMODULE_PARM_DESC(resetwaittime, "Wait time in (1-180s) after I/O timeout before resetting adapter. Default: 180s"); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int smp_affinity_enable = 1; 828c2ecf20Sopenharmony_cimodule_param(smp_affinity_enable, int, 0444); 838c2ecf20Sopenharmony_ciMODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)"); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int rdpq_enable = 1; 868c2ecf20Sopenharmony_cimodule_param(rdpq_enable, int, 0444); 878c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rdpq_enable, "Allocate reply queue in chunks for large queue depth enable/disable Default: enable(1)"); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ciunsigned int dual_qdepth_disable; 908c2ecf20Sopenharmony_cimodule_param(dual_qdepth_disable, int, 0444); 918c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0"); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT; 948c2ecf20Sopenharmony_cimodule_param(scmd_timeout, int, 0444); 958c2ecf20Sopenharmony_ciMODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer."); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciint perf_mode = -1; 988c2ecf20Sopenharmony_cimodule_param(perf_mode, int, 0444); 998c2ecf20Sopenharmony_ciMODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options:\n\t\t" 1008c2ecf20Sopenharmony_ci "0 - balanced: High iops and low latency queues are allocated &\n\t\t" 1018c2ecf20Sopenharmony_ci "interrupt coalescing is enabled only on high iops queues\n\t\t" 1028c2ecf20Sopenharmony_ci "1 - iops: High iops queues are not allocated &\n\t\t" 1038c2ecf20Sopenharmony_ci "interrupt coalescing is enabled on all queues\n\t\t" 1048c2ecf20Sopenharmony_ci "2 - latency: High iops queues are not allocated &\n\t\t" 1058c2ecf20Sopenharmony_ci "interrupt coalescing is disabled on all queues\n\t\t" 1068c2ecf20Sopenharmony_ci "default mode is 'balanced'" 1078c2ecf20Sopenharmony_ci ); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciint event_log_level = MFI_EVT_CLASS_CRITICAL; 1108c2ecf20Sopenharmony_cimodule_param(event_log_level, int, 0644); 1118c2ecf20Sopenharmony_ciMODULE_PARM_DESC(event_log_level, "Asynchronous event logging level- range is: -2(CLASS_DEBUG) to 4(CLASS_DEAD), Default: 2(CLASS_CRITICAL)"); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ciunsigned int enable_sdev_max_qd; 1148c2ecf20Sopenharmony_cimodule_param(enable_sdev_max_qd, int, 0444); 1158c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable_sdev_max_qd, "Enable sdev max qd as can_queue. Default: 0"); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ciint host_tagset_enable = 1; 1188c2ecf20Sopenharmony_cimodule_param(host_tagset_enable, int, 0444); 1198c2ecf20Sopenharmony_ciMODULE_PARM_DESC(host_tagset_enable, "Shared host tagset enable/disable Default: enable(1)"); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1228c2ecf20Sopenharmony_ciMODULE_VERSION(MEGASAS_VERSION); 1238c2ecf20Sopenharmony_ciMODULE_AUTHOR("megaraidlinux.pdl@broadcom.com"); 1248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Broadcom MegaRAID SAS Driver"); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ciint megasas_transition_to_ready(struct megasas_instance *instance, int ocr); 1278c2ecf20Sopenharmony_cistatic int megasas_get_pd_list(struct megasas_instance *instance); 1288c2ecf20Sopenharmony_cistatic int megasas_ld_list_query(struct megasas_instance *instance, 1298c2ecf20Sopenharmony_ci u8 query_type); 1308c2ecf20Sopenharmony_cistatic int megasas_issue_init_mfi(struct megasas_instance *instance); 1318c2ecf20Sopenharmony_cistatic int megasas_register_aen(struct megasas_instance *instance, 1328c2ecf20Sopenharmony_ci u32 seq_num, u32 class_locale_word); 1338c2ecf20Sopenharmony_cistatic void megasas_get_pd_info(struct megasas_instance *instance, 1348c2ecf20Sopenharmony_ci struct scsi_device *sdev); 1358c2ecf20Sopenharmony_cistatic void 1368c2ecf20Sopenharmony_cimegasas_set_ld_removed_by_fw(struct megasas_instance *instance); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* 1398c2ecf20Sopenharmony_ci * PCI ID table for all supported controllers 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_cistatic struct pci_device_id megasas_pci_table[] = { 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064R)}, 1448c2ecf20Sopenharmony_ci /* xscale IOP */ 1458c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078R)}, 1468c2ecf20Sopenharmony_ci /* ppc IOP */ 1478c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078DE)}, 1488c2ecf20Sopenharmony_ci /* ppc IOP */ 1498c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078GEN2)}, 1508c2ecf20Sopenharmony_ci /* gen2*/ 1518c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0079GEN2)}, 1528c2ecf20Sopenharmony_ci /* gen2*/ 1538c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0073SKINNY)}, 1548c2ecf20Sopenharmony_ci /* skinny*/ 1558c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0071SKINNY)}, 1568c2ecf20Sopenharmony_ci /* skinny*/ 1578c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)}, 1588c2ecf20Sopenharmony_ci /* xscale IOP, vega */ 1598c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)}, 1608c2ecf20Sopenharmony_ci /* xscale IOP */ 1618c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)}, 1628c2ecf20Sopenharmony_ci /* Fusion */ 1638c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_PLASMA)}, 1648c2ecf20Sopenharmony_ci /* Plasma */ 1658c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INVADER)}, 1668c2ecf20Sopenharmony_ci /* Invader */ 1678c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FURY)}, 1688c2ecf20Sopenharmony_ci /* Fury */ 1698c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER)}, 1708c2ecf20Sopenharmony_ci /* Intruder */ 1718c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER_24)}, 1728c2ecf20Sopenharmony_ci /* Intruder 24 port*/ 1738c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_52)}, 1748c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_53)}, 1758c2ecf20Sopenharmony_ci /* VENTURA */ 1768c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VENTURA)}, 1778c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CRUSADER)}, 1788c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_HARPOON)}, 1798c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_TOMCAT)}, 1808c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VENTURA_4PORT)}, 1818c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CRUSADER_4PORT)}, 1828c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E1)}, 1838c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E2)}, 1848c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E5)}, 1858c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E6)}, 1868c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E0)}, 1878c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E3)}, 1888c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E4)}, 1898c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E7)}, 1908c2ecf20Sopenharmony_ci {} 1918c2ecf20Sopenharmony_ci}; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, megasas_pci_table); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int megasas_mgmt_majorno; 1968c2ecf20Sopenharmony_cistruct megasas_mgmt_info megasas_mgmt_info; 1978c2ecf20Sopenharmony_cistatic struct fasync_struct *megasas_async_queue; 1988c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(megasas_async_queue_mutex); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int megasas_poll_wait_aen; 2018c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait); 2028c2ecf20Sopenharmony_cistatic u32 support_poll_for_event; 2038c2ecf20Sopenharmony_ciu32 megasas_dbg_lvl; 2048c2ecf20Sopenharmony_cistatic u32 support_device_change; 2058c2ecf20Sopenharmony_cistatic bool support_nvme_encapsulation; 2068c2ecf20Sopenharmony_cistatic bool support_pci_lane_margining; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/* define lock for aen poll */ 2098c2ecf20Sopenharmony_cistatic spinlock_t poll_aen_lock; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ciextern struct dentry *megasas_debugfs_root; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_civoid 2148c2ecf20Sopenharmony_cimegasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, 2158c2ecf20Sopenharmony_ci u8 alt_status); 2168c2ecf20Sopenharmony_cistatic u32 2178c2ecf20Sopenharmony_cimegasas_read_fw_status_reg_gen2(struct megasas_instance *instance); 2188c2ecf20Sopenharmony_cistatic int 2198c2ecf20Sopenharmony_cimegasas_adp_reset_gen2(struct megasas_instance *instance, 2208c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *reg_set); 2218c2ecf20Sopenharmony_cistatic irqreturn_t megasas_isr(int irq, void *devp); 2228c2ecf20Sopenharmony_cistatic u32 2238c2ecf20Sopenharmony_cimegasas_init_adapter_mfi(struct megasas_instance *instance); 2248c2ecf20Sopenharmony_ciu32 2258c2ecf20Sopenharmony_cimegasas_build_and_issue_cmd(struct megasas_instance *instance, 2268c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd); 2278c2ecf20Sopenharmony_cistatic void megasas_complete_cmd_dpc(unsigned long instance_addr); 2288c2ecf20Sopenharmony_ciint 2298c2ecf20Sopenharmony_ciwait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd, 2308c2ecf20Sopenharmony_ci int seconds); 2318c2ecf20Sopenharmony_civoid megasas_fusion_ocr_wq(struct work_struct *work); 2328c2ecf20Sopenharmony_cistatic int megasas_get_ld_vf_affiliation(struct megasas_instance *instance, 2338c2ecf20Sopenharmony_ci int initial); 2348c2ecf20Sopenharmony_cistatic int 2358c2ecf20Sopenharmony_cimegasas_set_dma_mask(struct megasas_instance *instance); 2368c2ecf20Sopenharmony_cistatic int 2378c2ecf20Sopenharmony_cimegasas_alloc_ctrl_mem(struct megasas_instance *instance); 2388c2ecf20Sopenharmony_cistatic inline void 2398c2ecf20Sopenharmony_cimegasas_free_ctrl_mem(struct megasas_instance *instance); 2408c2ecf20Sopenharmony_cistatic inline int 2418c2ecf20Sopenharmony_cimegasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance); 2428c2ecf20Sopenharmony_cistatic inline void 2438c2ecf20Sopenharmony_cimegasas_free_ctrl_dma_buffers(struct megasas_instance *instance); 2448c2ecf20Sopenharmony_cistatic inline void 2458c2ecf20Sopenharmony_cimegasas_init_ctrl_params(struct megasas_instance *instance); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ciu32 megasas_readl(struct megasas_instance *instance, 2488c2ecf20Sopenharmony_ci const volatile void __iomem *addr) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci u32 i = 0, ret_val; 2518c2ecf20Sopenharmony_ci /* 2528c2ecf20Sopenharmony_ci * Due to a HW errata in Aero controllers, reads to certain 2538c2ecf20Sopenharmony_ci * Fusion registers could intermittently return all zeroes. 2548c2ecf20Sopenharmony_ci * This behavior is transient in nature and subsequent reads will 2558c2ecf20Sopenharmony_ci * return valid value. As a workaround in driver, retry readl for 2568c2ecf20Sopenharmony_ci * up to thirty times until a non-zero value is read. 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_ci if (instance->adapter_type == AERO_SERIES) { 2598c2ecf20Sopenharmony_ci do { 2608c2ecf20Sopenharmony_ci ret_val = readl(addr); 2618c2ecf20Sopenharmony_ci i++; 2628c2ecf20Sopenharmony_ci } while (ret_val == 0 && i < 30); 2638c2ecf20Sopenharmony_ci return ret_val; 2648c2ecf20Sopenharmony_ci } else { 2658c2ecf20Sopenharmony_ci return readl(addr); 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/** 2708c2ecf20Sopenharmony_ci * megasas_set_dma_settings - Populate DMA address, length and flags for DCMDs 2718c2ecf20Sopenharmony_ci * @instance: Adapter soft state 2728c2ecf20Sopenharmony_ci * @dcmd: DCMD frame inside MFI command 2738c2ecf20Sopenharmony_ci * @dma_addr: DMA address of buffer to be passed to FW 2748c2ecf20Sopenharmony_ci * @dma_len: Length of DMA buffer to be passed to FW 2758c2ecf20Sopenharmony_ci * @return: void 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_civoid megasas_set_dma_settings(struct megasas_instance *instance, 2788c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd, 2798c2ecf20Sopenharmony_ci dma_addr_t dma_addr, u32 dma_len) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci if (instance->consistent_mask_64bit) { 2828c2ecf20Sopenharmony_ci dcmd->sgl.sge64[0].phys_addr = cpu_to_le64(dma_addr); 2838c2ecf20Sopenharmony_ci dcmd->sgl.sge64[0].length = cpu_to_le32(dma_len); 2848c2ecf20Sopenharmony_ci dcmd->flags = cpu_to_le16(dcmd->flags | MFI_FRAME_SGL64); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci } else { 2878c2ecf20Sopenharmony_ci dcmd->sgl.sge32[0].phys_addr = 2888c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(dma_addr)); 2898c2ecf20Sopenharmony_ci dcmd->sgl.sge32[0].length = cpu_to_le32(dma_len); 2908c2ecf20Sopenharmony_ci dcmd->flags = cpu_to_le16(dcmd->flags); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic void 2958c2ecf20Sopenharmony_cimegasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci instance->instancet->fire_cmd(instance, 2988c2ecf20Sopenharmony_ci cmd->frame_phys_addr, 0, instance->reg_set); 2998c2ecf20Sopenharmony_ci return; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci/** 3038c2ecf20Sopenharmony_ci * megasas_get_cmd - Get a command from the free pool 3048c2ecf20Sopenharmony_ci * @instance: Adapter soft state 3058c2ecf20Sopenharmony_ci * 3068c2ecf20Sopenharmony_ci * Returns a free command from the pool 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_cistruct megasas_cmd *megasas_get_cmd(struct megasas_instance 3098c2ecf20Sopenharmony_ci *instance) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci unsigned long flags; 3128c2ecf20Sopenharmony_ci struct megasas_cmd *cmd = NULL; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->mfi_pool_lock, flags); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (!list_empty(&instance->cmd_pool)) { 3178c2ecf20Sopenharmony_ci cmd = list_entry((&instance->cmd_pool)->next, 3188c2ecf20Sopenharmony_ci struct megasas_cmd, list); 3198c2ecf20Sopenharmony_ci list_del_init(&cmd->list); 3208c2ecf20Sopenharmony_ci } else { 3218c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Command pool empty!\n"); 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->mfi_pool_lock, flags); 3258c2ecf20Sopenharmony_ci return cmd; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci/** 3298c2ecf20Sopenharmony_ci * megasas_return_cmd - Return a cmd to free command pool 3308c2ecf20Sopenharmony_ci * @instance: Adapter soft state 3318c2ecf20Sopenharmony_ci * @cmd: Command packet to be returned to free command pool 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_civoid 3348c2ecf20Sopenharmony_cimegasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci unsigned long flags; 3378c2ecf20Sopenharmony_ci u32 blk_tags; 3388c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd_fusion; 3398c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* This flag is used only for fusion adapter. 3428c2ecf20Sopenharmony_ci * Wait for Interrupt for Polled mode DCMD 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_ci if (cmd->flags & DRV_DCMD_POLLED_MODE) 3458c2ecf20Sopenharmony_ci return; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->mfi_pool_lock, flags); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (fusion) { 3508c2ecf20Sopenharmony_ci blk_tags = instance->max_scsi_cmds + cmd->index; 3518c2ecf20Sopenharmony_ci cmd_fusion = fusion->cmd_list[blk_tags]; 3528c2ecf20Sopenharmony_ci megasas_return_cmd_fusion(instance, cmd_fusion); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci cmd->scmd = NULL; 3558c2ecf20Sopenharmony_ci cmd->frame_count = 0; 3568c2ecf20Sopenharmony_ci cmd->flags = 0; 3578c2ecf20Sopenharmony_ci memset(cmd->frame, 0, instance->mfi_frame_size); 3588c2ecf20Sopenharmony_ci cmd->frame->io.context = cpu_to_le32(cmd->index); 3598c2ecf20Sopenharmony_ci if (!fusion && reset_devices) 3608c2ecf20Sopenharmony_ci cmd->frame->hdr.cmd = MFI_CMD_INVALID; 3618c2ecf20Sopenharmony_ci list_add(&cmd->list, (&instance->cmd_pool)->next); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->mfi_pool_lock, flags); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic const char * 3688c2ecf20Sopenharmony_ciformat_timestamp(uint32_t timestamp) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci static char buffer[32]; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if ((timestamp & 0xff000000) == 0xff000000) 3738c2ecf20Sopenharmony_ci snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & 3748c2ecf20Sopenharmony_ci 0x00ffffff); 3758c2ecf20Sopenharmony_ci else 3768c2ecf20Sopenharmony_ci snprintf(buffer, sizeof(buffer), "%us", timestamp); 3778c2ecf20Sopenharmony_ci return buffer; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic const char * 3818c2ecf20Sopenharmony_ciformat_class(int8_t class) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci static char buffer[6]; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci switch (class) { 3868c2ecf20Sopenharmony_ci case MFI_EVT_CLASS_DEBUG: 3878c2ecf20Sopenharmony_ci return "debug"; 3888c2ecf20Sopenharmony_ci case MFI_EVT_CLASS_PROGRESS: 3898c2ecf20Sopenharmony_ci return "progress"; 3908c2ecf20Sopenharmony_ci case MFI_EVT_CLASS_INFO: 3918c2ecf20Sopenharmony_ci return "info"; 3928c2ecf20Sopenharmony_ci case MFI_EVT_CLASS_WARNING: 3938c2ecf20Sopenharmony_ci return "WARN"; 3948c2ecf20Sopenharmony_ci case MFI_EVT_CLASS_CRITICAL: 3958c2ecf20Sopenharmony_ci return "CRIT"; 3968c2ecf20Sopenharmony_ci case MFI_EVT_CLASS_FATAL: 3978c2ecf20Sopenharmony_ci return "FATAL"; 3988c2ecf20Sopenharmony_ci case MFI_EVT_CLASS_DEAD: 3998c2ecf20Sopenharmony_ci return "DEAD"; 4008c2ecf20Sopenharmony_ci default: 4018c2ecf20Sopenharmony_ci snprintf(buffer, sizeof(buffer), "%d", class); 4028c2ecf20Sopenharmony_ci return buffer; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci/** 4078c2ecf20Sopenharmony_ci * megasas_decode_evt: Decode FW AEN event and print critical event 4088c2ecf20Sopenharmony_ci * for information. 4098c2ecf20Sopenharmony_ci * @instance: Adapter soft state 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_cistatic void 4128c2ecf20Sopenharmony_cimegasas_decode_evt(struct megasas_instance *instance) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct megasas_evt_detail *evt_detail = instance->evt_detail; 4158c2ecf20Sopenharmony_ci union megasas_evt_class_locale class_locale; 4168c2ecf20Sopenharmony_ci class_locale.word = le32_to_cpu(evt_detail->cl.word); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if ((event_log_level < MFI_EVT_CLASS_DEBUG) || 4198c2ecf20Sopenharmony_ci (event_log_level > MFI_EVT_CLASS_DEAD)) { 4208c2ecf20Sopenharmony_ci printk(KERN_WARNING "megaraid_sas: provided event log level is out of range, setting it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n"); 4218c2ecf20Sopenharmony_ci event_log_level = MFI_EVT_CLASS_CRITICAL; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (class_locale.members.class >= event_log_level) 4258c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "%d (%s/0x%04x/%s) - %s\n", 4268c2ecf20Sopenharmony_ci le32_to_cpu(evt_detail->seq_num), 4278c2ecf20Sopenharmony_ci format_timestamp(le32_to_cpu(evt_detail->time_stamp)), 4288c2ecf20Sopenharmony_ci (class_locale.members.locale), 4298c2ecf20Sopenharmony_ci format_class(class_locale.members.class), 4308c2ecf20Sopenharmony_ci evt_detail->description); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & LD_PD_DEBUG) 4338c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 4348c2ecf20Sopenharmony_ci "evt_detail.args.ld.target_id/index %d/%d\n", 4358c2ecf20Sopenharmony_ci evt_detail->args.ld.target_id, evt_detail->args.ld.ld_index); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/* 4408c2ecf20Sopenharmony_ci * The following functions are defined for xscale 4418c2ecf20Sopenharmony_ci * (deviceid : 1064R, PERC5) controllers 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci/** 4458c2ecf20Sopenharmony_ci * megasas_enable_intr_xscale - Enables interrupts 4468c2ecf20Sopenharmony_ci * @instance: Adapter soft state 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_cistatic inline void 4498c2ecf20Sopenharmony_cimegasas_enable_intr_xscale(struct megasas_instance *instance) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci regs = instance->reg_set; 4548c2ecf20Sopenharmony_ci writel(0, &(regs)->outbound_intr_mask); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* Dummy readl to force pci flush */ 4578c2ecf20Sopenharmony_ci readl(®s->outbound_intr_mask); 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci/** 4618c2ecf20Sopenharmony_ci * megasas_disable_intr_xscale -Disables interrupt 4628c2ecf20Sopenharmony_ci * @instance: Adapter soft state 4638c2ecf20Sopenharmony_ci */ 4648c2ecf20Sopenharmony_cistatic inline void 4658c2ecf20Sopenharmony_cimegasas_disable_intr_xscale(struct megasas_instance *instance) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 4688c2ecf20Sopenharmony_ci u32 mask = 0x1f; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci regs = instance->reg_set; 4718c2ecf20Sopenharmony_ci writel(mask, ®s->outbound_intr_mask); 4728c2ecf20Sopenharmony_ci /* Dummy readl to force pci flush */ 4738c2ecf20Sopenharmony_ci readl(®s->outbound_intr_mask); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci/** 4778c2ecf20Sopenharmony_ci * megasas_read_fw_status_reg_xscale - returns the current FW status value 4788c2ecf20Sopenharmony_ci * @instance: Adapter soft state 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_cistatic u32 4818c2ecf20Sopenharmony_cimegasas_read_fw_status_reg_xscale(struct megasas_instance *instance) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci return readl(&instance->reg_set->outbound_msg_0); 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci/** 4868c2ecf20Sopenharmony_ci * megasas_clear_interrupt_xscale - Check & clear interrupt 4878c2ecf20Sopenharmony_ci * @instance: Adapter soft state 4888c2ecf20Sopenharmony_ci */ 4898c2ecf20Sopenharmony_cistatic int 4908c2ecf20Sopenharmony_cimegasas_clear_intr_xscale(struct megasas_instance *instance) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci u32 status; 4938c2ecf20Sopenharmony_ci u32 mfiStatus = 0; 4948c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 4958c2ecf20Sopenharmony_ci regs = instance->reg_set; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci /* 4988c2ecf20Sopenharmony_ci * Check if it is our interrupt 4998c2ecf20Sopenharmony_ci */ 5008c2ecf20Sopenharmony_ci status = readl(®s->outbound_intr_status); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (status & MFI_OB_INTR_STATUS_MASK) 5038c2ecf20Sopenharmony_ci mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE; 5048c2ecf20Sopenharmony_ci if (status & MFI_XSCALE_OMR0_CHANGE_INTERRUPT) 5058c2ecf20Sopenharmony_ci mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* 5088c2ecf20Sopenharmony_ci * Clear the interrupt by writing back the same value 5098c2ecf20Sopenharmony_ci */ 5108c2ecf20Sopenharmony_ci if (mfiStatus) 5118c2ecf20Sopenharmony_ci writel(status, ®s->outbound_intr_status); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* Dummy readl to force pci flush */ 5148c2ecf20Sopenharmony_ci readl(®s->outbound_intr_status); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return mfiStatus; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci/** 5208c2ecf20Sopenharmony_ci * megasas_fire_cmd_xscale - Sends command to the FW 5218c2ecf20Sopenharmony_ci * @instance: Adapter soft state 5228c2ecf20Sopenharmony_ci * @frame_phys_addr : Physical address of cmd 5238c2ecf20Sopenharmony_ci * @frame_count : Number of frames for the command 5248c2ecf20Sopenharmony_ci * @regs : MFI register set 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_cistatic inline void 5278c2ecf20Sopenharmony_cimegasas_fire_cmd_xscale(struct megasas_instance *instance, 5288c2ecf20Sopenharmony_ci dma_addr_t frame_phys_addr, 5298c2ecf20Sopenharmony_ci u32 frame_count, 5308c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci unsigned long flags; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->hba_lock, flags); 5358c2ecf20Sopenharmony_ci writel((frame_phys_addr >> 3)|(frame_count), 5368c2ecf20Sopenharmony_ci &(regs)->inbound_queue_port); 5378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->hba_lock, flags); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci/** 5418c2ecf20Sopenharmony_ci * megasas_adp_reset_xscale - For controller reset 5428c2ecf20Sopenharmony_ci * @instance: Adapter soft state 5438c2ecf20Sopenharmony_ci * @regs: MFI register set 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_cistatic int 5468c2ecf20Sopenharmony_cimegasas_adp_reset_xscale(struct megasas_instance *instance, 5478c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci u32 i; 5508c2ecf20Sopenharmony_ci u32 pcidata; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci writel(MFI_ADP_RESET, ®s->inbound_doorbell); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) 5558c2ecf20Sopenharmony_ci msleep(1000); /* sleep for 3 secs */ 5568c2ecf20Sopenharmony_ci pcidata = 0; 5578c2ecf20Sopenharmony_ci pci_read_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, &pcidata); 5588c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "pcidata = %x\n", pcidata); 5598c2ecf20Sopenharmony_ci if (pcidata & 0x2) { 5608c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "mfi 1068 offset read=%x\n", pcidata); 5618c2ecf20Sopenharmony_ci pcidata &= ~0x2; 5628c2ecf20Sopenharmony_ci pci_write_config_dword(instance->pdev, 5638c2ecf20Sopenharmony_ci MFI_1068_PCSR_OFFSET, pcidata); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) 5668c2ecf20Sopenharmony_ci msleep(1000); /* need to wait 2 secs again */ 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci pcidata = 0; 5698c2ecf20Sopenharmony_ci pci_read_config_dword(instance->pdev, 5708c2ecf20Sopenharmony_ci MFI_1068_FW_HANDSHAKE_OFFSET, &pcidata); 5718c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "1068 offset handshake read=%x\n", pcidata); 5728c2ecf20Sopenharmony_ci if ((pcidata & 0xffff0000) == MFI_1068_FW_READY) { 5738c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "1068 offset pcidt=%x\n", pcidata); 5748c2ecf20Sopenharmony_ci pcidata = 0; 5758c2ecf20Sopenharmony_ci pci_write_config_dword(instance->pdev, 5768c2ecf20Sopenharmony_ci MFI_1068_FW_HANDSHAKE_OFFSET, pcidata); 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci return 0; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci/** 5838c2ecf20Sopenharmony_ci * megasas_check_reset_xscale - For controller reset check 5848c2ecf20Sopenharmony_ci * @instance: Adapter soft state 5858c2ecf20Sopenharmony_ci * @regs: MFI register set 5868c2ecf20Sopenharmony_ci */ 5878c2ecf20Sopenharmony_cistatic int 5888c2ecf20Sopenharmony_cimegasas_check_reset_xscale(struct megasas_instance *instance, 5898c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci if ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) && 5928c2ecf20Sopenharmony_ci (le32_to_cpu(*instance->consumer) == 5938c2ecf20Sopenharmony_ci MEGASAS_ADPRESET_INPROG_SIGN)) 5948c2ecf20Sopenharmony_ci return 1; 5958c2ecf20Sopenharmony_ci return 0; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic struct megasas_instance_template megasas_instance_template_xscale = { 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci .fire_cmd = megasas_fire_cmd_xscale, 6018c2ecf20Sopenharmony_ci .enable_intr = megasas_enable_intr_xscale, 6028c2ecf20Sopenharmony_ci .disable_intr = megasas_disable_intr_xscale, 6038c2ecf20Sopenharmony_ci .clear_intr = megasas_clear_intr_xscale, 6048c2ecf20Sopenharmony_ci .read_fw_status_reg = megasas_read_fw_status_reg_xscale, 6058c2ecf20Sopenharmony_ci .adp_reset = megasas_adp_reset_xscale, 6068c2ecf20Sopenharmony_ci .check_reset = megasas_check_reset_xscale, 6078c2ecf20Sopenharmony_ci .service_isr = megasas_isr, 6088c2ecf20Sopenharmony_ci .tasklet = megasas_complete_cmd_dpc, 6098c2ecf20Sopenharmony_ci .init_adapter = megasas_init_adapter_mfi, 6108c2ecf20Sopenharmony_ci .build_and_issue_cmd = megasas_build_and_issue_cmd, 6118c2ecf20Sopenharmony_ci .issue_dcmd = megasas_issue_dcmd, 6128c2ecf20Sopenharmony_ci}; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci/* 6158c2ecf20Sopenharmony_ci * This is the end of set of functions & definitions specific 6168c2ecf20Sopenharmony_ci * to xscale (deviceid : 1064R, PERC5) controllers 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci/* 6208c2ecf20Sopenharmony_ci * The following functions are defined for ppc (deviceid : 0x60) 6218c2ecf20Sopenharmony_ci * controllers 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci/** 6258c2ecf20Sopenharmony_ci * megasas_enable_intr_ppc - Enables interrupts 6268c2ecf20Sopenharmony_ci * @instance: Adapter soft state 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_cistatic inline void 6298c2ecf20Sopenharmony_cimegasas_enable_intr_ppc(struct megasas_instance *instance) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci regs = instance->reg_set; 6348c2ecf20Sopenharmony_ci writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci writel(~0x80000000, &(regs)->outbound_intr_mask); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* Dummy readl to force pci flush */ 6398c2ecf20Sopenharmony_ci readl(®s->outbound_intr_mask); 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci/** 6438c2ecf20Sopenharmony_ci * megasas_disable_intr_ppc - Disable interrupt 6448c2ecf20Sopenharmony_ci * @instance: Adapter soft state 6458c2ecf20Sopenharmony_ci */ 6468c2ecf20Sopenharmony_cistatic inline void 6478c2ecf20Sopenharmony_cimegasas_disable_intr_ppc(struct megasas_instance *instance) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 6508c2ecf20Sopenharmony_ci u32 mask = 0xFFFFFFFF; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci regs = instance->reg_set; 6538c2ecf20Sopenharmony_ci writel(mask, ®s->outbound_intr_mask); 6548c2ecf20Sopenharmony_ci /* Dummy readl to force pci flush */ 6558c2ecf20Sopenharmony_ci readl(®s->outbound_intr_mask); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci/** 6598c2ecf20Sopenharmony_ci * megasas_read_fw_status_reg_ppc - returns the current FW status value 6608c2ecf20Sopenharmony_ci * @instance: Adapter soft state 6618c2ecf20Sopenharmony_ci */ 6628c2ecf20Sopenharmony_cistatic u32 6638c2ecf20Sopenharmony_cimegasas_read_fw_status_reg_ppc(struct megasas_instance *instance) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci return readl(&instance->reg_set->outbound_scratch_pad_0); 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci/** 6698c2ecf20Sopenharmony_ci * megasas_clear_interrupt_ppc - Check & clear interrupt 6708c2ecf20Sopenharmony_ci * @instance: Adapter soft state 6718c2ecf20Sopenharmony_ci */ 6728c2ecf20Sopenharmony_cistatic int 6738c2ecf20Sopenharmony_cimegasas_clear_intr_ppc(struct megasas_instance *instance) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci u32 status, mfiStatus = 0; 6768c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 6778c2ecf20Sopenharmony_ci regs = instance->reg_set; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* 6808c2ecf20Sopenharmony_ci * Check if it is our interrupt 6818c2ecf20Sopenharmony_ci */ 6828c2ecf20Sopenharmony_ci status = readl(®s->outbound_intr_status); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (status & MFI_REPLY_1078_MESSAGE_INTERRUPT) 6858c2ecf20Sopenharmony_ci mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT) 6888c2ecf20Sopenharmony_ci mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* 6918c2ecf20Sopenharmony_ci * Clear the interrupt by writing back the same value 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_ci writel(status, ®s->outbound_doorbell_clear); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* Dummy readl to force pci flush */ 6968c2ecf20Sopenharmony_ci readl(®s->outbound_doorbell_clear); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci return mfiStatus; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci/** 7028c2ecf20Sopenharmony_ci * megasas_fire_cmd_ppc - Sends command to the FW 7038c2ecf20Sopenharmony_ci * @instance: Adapter soft state 7048c2ecf20Sopenharmony_ci * @frame_phys_addr: Physical address of cmd 7058c2ecf20Sopenharmony_ci * @frame_count: Number of frames for the command 7068c2ecf20Sopenharmony_ci * @regs: MFI register set 7078c2ecf20Sopenharmony_ci */ 7088c2ecf20Sopenharmony_cistatic inline void 7098c2ecf20Sopenharmony_cimegasas_fire_cmd_ppc(struct megasas_instance *instance, 7108c2ecf20Sopenharmony_ci dma_addr_t frame_phys_addr, 7118c2ecf20Sopenharmony_ci u32 frame_count, 7128c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci unsigned long flags; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->hba_lock, flags); 7178c2ecf20Sopenharmony_ci writel((frame_phys_addr | (frame_count<<1))|1, 7188c2ecf20Sopenharmony_ci &(regs)->inbound_queue_port); 7198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->hba_lock, flags); 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci/** 7238c2ecf20Sopenharmony_ci * megasas_check_reset_ppc - For controller reset check 7248c2ecf20Sopenharmony_ci * @instance: Adapter soft state 7258c2ecf20Sopenharmony_ci * @regs: MFI register set 7268c2ecf20Sopenharmony_ci */ 7278c2ecf20Sopenharmony_cistatic int 7288c2ecf20Sopenharmony_cimegasas_check_reset_ppc(struct megasas_instance *instance, 7298c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) 7328c2ecf20Sopenharmony_ci return 1; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci return 0; 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic struct megasas_instance_template megasas_instance_template_ppc = { 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci .fire_cmd = megasas_fire_cmd_ppc, 7408c2ecf20Sopenharmony_ci .enable_intr = megasas_enable_intr_ppc, 7418c2ecf20Sopenharmony_ci .disable_intr = megasas_disable_intr_ppc, 7428c2ecf20Sopenharmony_ci .clear_intr = megasas_clear_intr_ppc, 7438c2ecf20Sopenharmony_ci .read_fw_status_reg = megasas_read_fw_status_reg_ppc, 7448c2ecf20Sopenharmony_ci .adp_reset = megasas_adp_reset_xscale, 7458c2ecf20Sopenharmony_ci .check_reset = megasas_check_reset_ppc, 7468c2ecf20Sopenharmony_ci .service_isr = megasas_isr, 7478c2ecf20Sopenharmony_ci .tasklet = megasas_complete_cmd_dpc, 7488c2ecf20Sopenharmony_ci .init_adapter = megasas_init_adapter_mfi, 7498c2ecf20Sopenharmony_ci .build_and_issue_cmd = megasas_build_and_issue_cmd, 7508c2ecf20Sopenharmony_ci .issue_dcmd = megasas_issue_dcmd, 7518c2ecf20Sopenharmony_ci}; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci/** 7548c2ecf20Sopenharmony_ci * megasas_enable_intr_skinny - Enables interrupts 7558c2ecf20Sopenharmony_ci * @instance: Adapter soft state 7568c2ecf20Sopenharmony_ci */ 7578c2ecf20Sopenharmony_cistatic inline void 7588c2ecf20Sopenharmony_cimegasas_enable_intr_skinny(struct megasas_instance *instance) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci regs = instance->reg_set; 7638c2ecf20Sopenharmony_ci writel(0xFFFFFFFF, &(regs)->outbound_intr_mask); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci writel(~MFI_SKINNY_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci /* Dummy readl to force pci flush */ 7688c2ecf20Sopenharmony_ci readl(®s->outbound_intr_mask); 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci/** 7728c2ecf20Sopenharmony_ci * megasas_disable_intr_skinny - Disables interrupt 7738c2ecf20Sopenharmony_ci * @instance: Adapter soft state 7748c2ecf20Sopenharmony_ci */ 7758c2ecf20Sopenharmony_cistatic inline void 7768c2ecf20Sopenharmony_cimegasas_disable_intr_skinny(struct megasas_instance *instance) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 7798c2ecf20Sopenharmony_ci u32 mask = 0xFFFFFFFF; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci regs = instance->reg_set; 7828c2ecf20Sopenharmony_ci writel(mask, ®s->outbound_intr_mask); 7838c2ecf20Sopenharmony_ci /* Dummy readl to force pci flush */ 7848c2ecf20Sopenharmony_ci readl(®s->outbound_intr_mask); 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci/** 7888c2ecf20Sopenharmony_ci * megasas_read_fw_status_reg_skinny - returns the current FW status value 7898c2ecf20Sopenharmony_ci * @instance: Adapter soft state 7908c2ecf20Sopenharmony_ci */ 7918c2ecf20Sopenharmony_cistatic u32 7928c2ecf20Sopenharmony_cimegasas_read_fw_status_reg_skinny(struct megasas_instance *instance) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci return readl(&instance->reg_set->outbound_scratch_pad_0); 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci/** 7988c2ecf20Sopenharmony_ci * megasas_clear_interrupt_skinny - Check & clear interrupt 7998c2ecf20Sopenharmony_ci * @instance: Adapter soft state 8008c2ecf20Sopenharmony_ci */ 8018c2ecf20Sopenharmony_cistatic int 8028c2ecf20Sopenharmony_cimegasas_clear_intr_skinny(struct megasas_instance *instance) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci u32 status; 8058c2ecf20Sopenharmony_ci u32 mfiStatus = 0; 8068c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 8078c2ecf20Sopenharmony_ci regs = instance->reg_set; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* 8108c2ecf20Sopenharmony_ci * Check if it is our interrupt 8118c2ecf20Sopenharmony_ci */ 8128c2ecf20Sopenharmony_ci status = readl(®s->outbound_intr_status); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) { 8158c2ecf20Sopenharmony_ci return 0; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* 8198c2ecf20Sopenharmony_ci * Check if it is our interrupt 8208c2ecf20Sopenharmony_ci */ 8218c2ecf20Sopenharmony_ci if ((megasas_read_fw_status_reg_skinny(instance) & MFI_STATE_MASK) == 8228c2ecf20Sopenharmony_ci MFI_STATE_FAULT) { 8238c2ecf20Sopenharmony_ci mfiStatus = MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE; 8248c2ecf20Sopenharmony_ci } else 8258c2ecf20Sopenharmony_ci mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci /* 8288c2ecf20Sopenharmony_ci * Clear the interrupt by writing back the same value 8298c2ecf20Sopenharmony_ci */ 8308c2ecf20Sopenharmony_ci writel(status, ®s->outbound_intr_status); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci /* 8338c2ecf20Sopenharmony_ci * dummy read to flush PCI 8348c2ecf20Sopenharmony_ci */ 8358c2ecf20Sopenharmony_ci readl(®s->outbound_intr_status); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci return mfiStatus; 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci/** 8418c2ecf20Sopenharmony_ci * megasas_fire_cmd_skinny - Sends command to the FW 8428c2ecf20Sopenharmony_ci * @instance: Adapter soft state 8438c2ecf20Sopenharmony_ci * @frame_phys_addr: Physical address of cmd 8448c2ecf20Sopenharmony_ci * @frame_count: Number of frames for the command 8458c2ecf20Sopenharmony_ci * @regs: MFI register set 8468c2ecf20Sopenharmony_ci */ 8478c2ecf20Sopenharmony_cistatic inline void 8488c2ecf20Sopenharmony_cimegasas_fire_cmd_skinny(struct megasas_instance *instance, 8498c2ecf20Sopenharmony_ci dma_addr_t frame_phys_addr, 8508c2ecf20Sopenharmony_ci u32 frame_count, 8518c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci unsigned long flags; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->hba_lock, flags); 8568c2ecf20Sopenharmony_ci writel(upper_32_bits(frame_phys_addr), 8578c2ecf20Sopenharmony_ci &(regs)->inbound_high_queue_port); 8588c2ecf20Sopenharmony_ci writel((lower_32_bits(frame_phys_addr) | (frame_count<<1))|1, 8598c2ecf20Sopenharmony_ci &(regs)->inbound_low_queue_port); 8608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->hba_lock, flags); 8618c2ecf20Sopenharmony_ci} 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci/** 8648c2ecf20Sopenharmony_ci * megasas_check_reset_skinny - For controller reset check 8658c2ecf20Sopenharmony_ci * @instance: Adapter soft state 8668c2ecf20Sopenharmony_ci * @regs: MFI register set 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_cistatic int 8698c2ecf20Sopenharmony_cimegasas_check_reset_skinny(struct megasas_instance *instance, 8708c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) 8738c2ecf20Sopenharmony_ci return 1; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci return 0; 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic struct megasas_instance_template megasas_instance_template_skinny = { 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci .fire_cmd = megasas_fire_cmd_skinny, 8818c2ecf20Sopenharmony_ci .enable_intr = megasas_enable_intr_skinny, 8828c2ecf20Sopenharmony_ci .disable_intr = megasas_disable_intr_skinny, 8838c2ecf20Sopenharmony_ci .clear_intr = megasas_clear_intr_skinny, 8848c2ecf20Sopenharmony_ci .read_fw_status_reg = megasas_read_fw_status_reg_skinny, 8858c2ecf20Sopenharmony_ci .adp_reset = megasas_adp_reset_gen2, 8868c2ecf20Sopenharmony_ci .check_reset = megasas_check_reset_skinny, 8878c2ecf20Sopenharmony_ci .service_isr = megasas_isr, 8888c2ecf20Sopenharmony_ci .tasklet = megasas_complete_cmd_dpc, 8898c2ecf20Sopenharmony_ci .init_adapter = megasas_init_adapter_mfi, 8908c2ecf20Sopenharmony_ci .build_and_issue_cmd = megasas_build_and_issue_cmd, 8918c2ecf20Sopenharmony_ci .issue_dcmd = megasas_issue_dcmd, 8928c2ecf20Sopenharmony_ci}; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci/* 8968c2ecf20Sopenharmony_ci * The following functions are defined for gen2 (deviceid : 0x78 0x79) 8978c2ecf20Sopenharmony_ci * controllers 8988c2ecf20Sopenharmony_ci */ 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci/** 9018c2ecf20Sopenharmony_ci * megasas_enable_intr_gen2 - Enables interrupts 9028c2ecf20Sopenharmony_ci * @instance: Adapter soft state 9038c2ecf20Sopenharmony_ci */ 9048c2ecf20Sopenharmony_cistatic inline void 9058c2ecf20Sopenharmony_cimegasas_enable_intr_gen2(struct megasas_instance *instance) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci regs = instance->reg_set; 9108c2ecf20Sopenharmony_ci writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* write ~0x00000005 (4 & 1) to the intr mask*/ 9138c2ecf20Sopenharmony_ci writel(~MFI_GEN2_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* Dummy readl to force pci flush */ 9168c2ecf20Sopenharmony_ci readl(®s->outbound_intr_mask); 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci/** 9208c2ecf20Sopenharmony_ci * megasas_disable_intr_gen2 - Disables interrupt 9218c2ecf20Sopenharmony_ci * @instance: Adapter soft state 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_cistatic inline void 9248c2ecf20Sopenharmony_cimegasas_disable_intr_gen2(struct megasas_instance *instance) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 9278c2ecf20Sopenharmony_ci u32 mask = 0xFFFFFFFF; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci regs = instance->reg_set; 9308c2ecf20Sopenharmony_ci writel(mask, ®s->outbound_intr_mask); 9318c2ecf20Sopenharmony_ci /* Dummy readl to force pci flush */ 9328c2ecf20Sopenharmony_ci readl(®s->outbound_intr_mask); 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci/** 9368c2ecf20Sopenharmony_ci * megasas_read_fw_status_reg_gen2 - returns the current FW status value 9378c2ecf20Sopenharmony_ci * @instance: Adapter soft state 9388c2ecf20Sopenharmony_ci */ 9398c2ecf20Sopenharmony_cistatic u32 9408c2ecf20Sopenharmony_cimegasas_read_fw_status_reg_gen2(struct megasas_instance *instance) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci return readl(&instance->reg_set->outbound_scratch_pad_0); 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci/** 9468c2ecf20Sopenharmony_ci * megasas_clear_interrupt_gen2 - Check & clear interrupt 9478c2ecf20Sopenharmony_ci * @instance: Adapter soft state 9488c2ecf20Sopenharmony_ci */ 9498c2ecf20Sopenharmony_cistatic int 9508c2ecf20Sopenharmony_cimegasas_clear_intr_gen2(struct megasas_instance *instance) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci u32 status; 9538c2ecf20Sopenharmony_ci u32 mfiStatus = 0; 9548c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 9558c2ecf20Sopenharmony_ci regs = instance->reg_set; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci /* 9588c2ecf20Sopenharmony_ci * Check if it is our interrupt 9598c2ecf20Sopenharmony_ci */ 9608c2ecf20Sopenharmony_ci status = readl(®s->outbound_intr_status); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (status & MFI_INTR_FLAG_REPLY_MESSAGE) { 9638c2ecf20Sopenharmony_ci mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT) { 9668c2ecf20Sopenharmony_ci mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci /* 9708c2ecf20Sopenharmony_ci * Clear the interrupt by writing back the same value 9718c2ecf20Sopenharmony_ci */ 9728c2ecf20Sopenharmony_ci if (mfiStatus) 9738c2ecf20Sopenharmony_ci writel(status, ®s->outbound_doorbell_clear); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* Dummy readl to force pci flush */ 9768c2ecf20Sopenharmony_ci readl(®s->outbound_intr_status); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci return mfiStatus; 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci/** 9828c2ecf20Sopenharmony_ci * megasas_fire_cmd_gen2 - Sends command to the FW 9838c2ecf20Sopenharmony_ci * @instance: Adapter soft state 9848c2ecf20Sopenharmony_ci * @frame_phys_addr: Physical address of cmd 9858c2ecf20Sopenharmony_ci * @frame_count: Number of frames for the command 9868c2ecf20Sopenharmony_ci * @regs: MFI register set 9878c2ecf20Sopenharmony_ci */ 9888c2ecf20Sopenharmony_cistatic inline void 9898c2ecf20Sopenharmony_cimegasas_fire_cmd_gen2(struct megasas_instance *instance, 9908c2ecf20Sopenharmony_ci dma_addr_t frame_phys_addr, 9918c2ecf20Sopenharmony_ci u32 frame_count, 9928c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci unsigned long flags; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->hba_lock, flags); 9978c2ecf20Sopenharmony_ci writel((frame_phys_addr | (frame_count<<1))|1, 9988c2ecf20Sopenharmony_ci &(regs)->inbound_queue_port); 9998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->hba_lock, flags); 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci/** 10038c2ecf20Sopenharmony_ci * megasas_adp_reset_gen2 - For controller reset 10048c2ecf20Sopenharmony_ci * @instance: Adapter soft state 10058c2ecf20Sopenharmony_ci * @reg_set: MFI register set 10068c2ecf20Sopenharmony_ci */ 10078c2ecf20Sopenharmony_cistatic int 10088c2ecf20Sopenharmony_cimegasas_adp_reset_gen2(struct megasas_instance *instance, 10098c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *reg_set) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci u32 retry = 0 ; 10128c2ecf20Sopenharmony_ci u32 HostDiag; 10138c2ecf20Sopenharmony_ci u32 __iomem *seq_offset = ®_set->seq_offset; 10148c2ecf20Sopenharmony_ci u32 __iomem *hostdiag_offset = ®_set->host_diag; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if (instance->instancet == &megasas_instance_template_skinny) { 10178c2ecf20Sopenharmony_ci seq_offset = ®_set->fusion_seq_offset; 10188c2ecf20Sopenharmony_ci hostdiag_offset = ®_set->fusion_host_diag; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci writel(0, seq_offset); 10228c2ecf20Sopenharmony_ci writel(4, seq_offset); 10238c2ecf20Sopenharmony_ci writel(0xb, seq_offset); 10248c2ecf20Sopenharmony_ci writel(2, seq_offset); 10258c2ecf20Sopenharmony_ci writel(7, seq_offset); 10268c2ecf20Sopenharmony_ci writel(0xd, seq_offset); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci msleep(1000); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci HostDiag = (u32)readl(hostdiag_offset); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci while (!(HostDiag & DIAG_WRITE_ENABLE)) { 10338c2ecf20Sopenharmony_ci msleep(100); 10348c2ecf20Sopenharmony_ci HostDiag = (u32)readl(hostdiag_offset); 10358c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "RESETGEN2: retry=%x, hostdiag=%x\n", 10368c2ecf20Sopenharmony_ci retry, HostDiag); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci if (retry++ >= 100) 10398c2ecf20Sopenharmony_ci return 1; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci writel((HostDiag | DIAG_RESET_ADAPTER), hostdiag_offset); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci ssleep(10); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci HostDiag = (u32)readl(hostdiag_offset); 10508c2ecf20Sopenharmony_ci while (HostDiag & DIAG_RESET_ADAPTER) { 10518c2ecf20Sopenharmony_ci msleep(100); 10528c2ecf20Sopenharmony_ci HostDiag = (u32)readl(hostdiag_offset); 10538c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "RESET_GEN2: retry=%x, hostdiag=%x\n", 10548c2ecf20Sopenharmony_ci retry, HostDiag); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci if (retry++ >= 1000) 10578c2ecf20Sopenharmony_ci return 1; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci return 0; 10618c2ecf20Sopenharmony_ci} 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci/** 10648c2ecf20Sopenharmony_ci * megasas_check_reset_gen2 - For controller reset check 10658c2ecf20Sopenharmony_ci * @instance: Adapter soft state 10668c2ecf20Sopenharmony_ci * @regs: MFI register set 10678c2ecf20Sopenharmony_ci */ 10688c2ecf20Sopenharmony_cistatic int 10698c2ecf20Sopenharmony_cimegasas_check_reset_gen2(struct megasas_instance *instance, 10708c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) 10738c2ecf20Sopenharmony_ci return 1; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci return 0; 10768c2ecf20Sopenharmony_ci} 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_cistatic struct megasas_instance_template megasas_instance_template_gen2 = { 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci .fire_cmd = megasas_fire_cmd_gen2, 10818c2ecf20Sopenharmony_ci .enable_intr = megasas_enable_intr_gen2, 10828c2ecf20Sopenharmony_ci .disable_intr = megasas_disable_intr_gen2, 10838c2ecf20Sopenharmony_ci .clear_intr = megasas_clear_intr_gen2, 10848c2ecf20Sopenharmony_ci .read_fw_status_reg = megasas_read_fw_status_reg_gen2, 10858c2ecf20Sopenharmony_ci .adp_reset = megasas_adp_reset_gen2, 10868c2ecf20Sopenharmony_ci .check_reset = megasas_check_reset_gen2, 10878c2ecf20Sopenharmony_ci .service_isr = megasas_isr, 10888c2ecf20Sopenharmony_ci .tasklet = megasas_complete_cmd_dpc, 10898c2ecf20Sopenharmony_ci .init_adapter = megasas_init_adapter_mfi, 10908c2ecf20Sopenharmony_ci .build_and_issue_cmd = megasas_build_and_issue_cmd, 10918c2ecf20Sopenharmony_ci .issue_dcmd = megasas_issue_dcmd, 10928c2ecf20Sopenharmony_ci}; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci/* 10958c2ecf20Sopenharmony_ci * This is the end of set of functions & definitions 10968c2ecf20Sopenharmony_ci * specific to gen2 (deviceid : 0x78, 0x79) controllers 10978c2ecf20Sopenharmony_ci */ 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci/* 11008c2ecf20Sopenharmony_ci * Template added for TB (Fusion) 11018c2ecf20Sopenharmony_ci */ 11028c2ecf20Sopenharmony_ciextern struct megasas_instance_template megasas_instance_template_fusion; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci/** 11058c2ecf20Sopenharmony_ci * megasas_issue_polled - Issues a polling command 11068c2ecf20Sopenharmony_ci * @instance: Adapter soft state 11078c2ecf20Sopenharmony_ci * @cmd: Command packet to be issued 11088c2ecf20Sopenharmony_ci * 11098c2ecf20Sopenharmony_ci * For polling, MFI requires the cmd_status to be set to MFI_STAT_INVALID_STATUS before posting. 11108c2ecf20Sopenharmony_ci */ 11118c2ecf20Sopenharmony_ciint 11128c2ecf20Sopenharmony_cimegasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci struct megasas_header *frame_hdr = &cmd->frame->hdr; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci frame_hdr->cmd_status = MFI_STAT_INVALID_STATUS; 11178c2ecf20Sopenharmony_ci frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) { 11208c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed from %s %d\n", 11218c2ecf20Sopenharmony_ci __func__, __LINE__); 11228c2ecf20Sopenharmony_ci return DCMD_INIT; 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci instance->instancet->issue_dcmd(instance, cmd); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci return wait_and_poll(instance, cmd, instance->requestorId ? 11288c2ecf20Sopenharmony_ci MEGASAS_ROUTINE_WAIT_TIME_VF : MFI_IO_TIMEOUT_SECS); 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci/** 11328c2ecf20Sopenharmony_ci * megasas_issue_blocked_cmd - Synchronous wrapper around regular FW cmds 11338c2ecf20Sopenharmony_ci * @instance: Adapter soft state 11348c2ecf20Sopenharmony_ci * @cmd: Command to be issued 11358c2ecf20Sopenharmony_ci * @timeout: Timeout in seconds 11368c2ecf20Sopenharmony_ci * 11378c2ecf20Sopenharmony_ci * This function waits on an event for the command to be returned from ISR. 11388c2ecf20Sopenharmony_ci * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs 11398c2ecf20Sopenharmony_ci * Used to issue ioctl commands. 11408c2ecf20Sopenharmony_ci */ 11418c2ecf20Sopenharmony_ciint 11428c2ecf20Sopenharmony_cimegasas_issue_blocked_cmd(struct megasas_instance *instance, 11438c2ecf20Sopenharmony_ci struct megasas_cmd *cmd, int timeout) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci int ret = 0; 11468c2ecf20Sopenharmony_ci cmd->cmd_status_drv = DCMD_INIT; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) { 11498c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed from %s %d\n", 11508c2ecf20Sopenharmony_ci __func__, __LINE__); 11518c2ecf20Sopenharmony_ci return DCMD_INIT; 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci instance->instancet->issue_dcmd(instance, cmd); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci if (timeout) { 11578c2ecf20Sopenharmony_ci ret = wait_event_timeout(instance->int_cmd_wait_q, 11588c2ecf20Sopenharmony_ci cmd->cmd_status_drv != DCMD_INIT, timeout * HZ); 11598c2ecf20Sopenharmony_ci if (!ret) { 11608c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 11618c2ecf20Sopenharmony_ci "DCMD(opcode: 0x%x) is timed out, func:%s\n", 11628c2ecf20Sopenharmony_ci cmd->frame->dcmd.opcode, __func__); 11638c2ecf20Sopenharmony_ci return DCMD_TIMEOUT; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci } else 11668c2ecf20Sopenharmony_ci wait_event(instance->int_cmd_wait_q, 11678c2ecf20Sopenharmony_ci cmd->cmd_status_drv != DCMD_INIT); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci return cmd->cmd_status_drv; 11708c2ecf20Sopenharmony_ci} 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci/** 11738c2ecf20Sopenharmony_ci * megasas_issue_blocked_abort_cmd - Aborts previously issued cmd 11748c2ecf20Sopenharmony_ci * @instance: Adapter soft state 11758c2ecf20Sopenharmony_ci * @cmd_to_abort: Previously issued cmd to be aborted 11768c2ecf20Sopenharmony_ci * @timeout: Timeout in seconds 11778c2ecf20Sopenharmony_ci * 11788c2ecf20Sopenharmony_ci * MFI firmware can abort previously issued AEN comamnd (automatic event 11798c2ecf20Sopenharmony_ci * notification). The megasas_issue_blocked_abort_cmd() issues such abort 11808c2ecf20Sopenharmony_ci * cmd and waits for return status. 11818c2ecf20Sopenharmony_ci * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs 11828c2ecf20Sopenharmony_ci */ 11838c2ecf20Sopenharmony_cistatic int 11848c2ecf20Sopenharmony_cimegasas_issue_blocked_abort_cmd(struct megasas_instance *instance, 11858c2ecf20Sopenharmony_ci struct megasas_cmd *cmd_to_abort, int timeout) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 11888c2ecf20Sopenharmony_ci struct megasas_abort_frame *abort_fr; 11898c2ecf20Sopenharmony_ci int ret = 0; 11908c2ecf20Sopenharmony_ci u32 opcode; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci if (!cmd) 11958c2ecf20Sopenharmony_ci return -1; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci abort_fr = &cmd->frame->abort; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* 12008c2ecf20Sopenharmony_ci * Prepare and issue the abort frame 12018c2ecf20Sopenharmony_ci */ 12028c2ecf20Sopenharmony_ci abort_fr->cmd = MFI_CMD_ABORT; 12038c2ecf20Sopenharmony_ci abort_fr->cmd_status = MFI_STAT_INVALID_STATUS; 12048c2ecf20Sopenharmony_ci abort_fr->flags = cpu_to_le16(0); 12058c2ecf20Sopenharmony_ci abort_fr->abort_context = cpu_to_le32(cmd_to_abort->index); 12068c2ecf20Sopenharmony_ci abort_fr->abort_mfi_phys_addr_lo = 12078c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(cmd_to_abort->frame_phys_addr)); 12088c2ecf20Sopenharmony_ci abort_fr->abort_mfi_phys_addr_hi = 12098c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(cmd_to_abort->frame_phys_addr)); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci cmd->sync_cmd = 1; 12128c2ecf20Sopenharmony_ci cmd->cmd_status_drv = DCMD_INIT; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) { 12158c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed from %s %d\n", 12168c2ecf20Sopenharmony_ci __func__, __LINE__); 12178c2ecf20Sopenharmony_ci return DCMD_INIT; 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci instance->instancet->issue_dcmd(instance, cmd); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (timeout) { 12238c2ecf20Sopenharmony_ci ret = wait_event_timeout(instance->abort_cmd_wait_q, 12248c2ecf20Sopenharmony_ci cmd->cmd_status_drv != DCMD_INIT, timeout * HZ); 12258c2ecf20Sopenharmony_ci if (!ret) { 12268c2ecf20Sopenharmony_ci opcode = cmd_to_abort->frame->dcmd.opcode; 12278c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 12288c2ecf20Sopenharmony_ci "Abort(to be aborted DCMD opcode: 0x%x) is timed out func:%s\n", 12298c2ecf20Sopenharmony_ci opcode, __func__); 12308c2ecf20Sopenharmony_ci return DCMD_TIMEOUT; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci } else 12338c2ecf20Sopenharmony_ci wait_event(instance->abort_cmd_wait_q, 12348c2ecf20Sopenharmony_ci cmd->cmd_status_drv != DCMD_INIT); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci cmd->sync_cmd = 0; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 12398c2ecf20Sopenharmony_ci return cmd->cmd_status_drv; 12408c2ecf20Sopenharmony_ci} 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci/** 12438c2ecf20Sopenharmony_ci * megasas_make_sgl32 - Prepares 32-bit SGL 12448c2ecf20Sopenharmony_ci * @instance: Adapter soft state 12458c2ecf20Sopenharmony_ci * @scp: SCSI command from the mid-layer 12468c2ecf20Sopenharmony_ci * @mfi_sgl: SGL to be filled in 12478c2ecf20Sopenharmony_ci * 12488c2ecf20Sopenharmony_ci * If successful, this function returns the number of SG elements. Otherwise, 12498c2ecf20Sopenharmony_ci * it returnes -1. 12508c2ecf20Sopenharmony_ci */ 12518c2ecf20Sopenharmony_cistatic int 12528c2ecf20Sopenharmony_cimegasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp, 12538c2ecf20Sopenharmony_ci union megasas_sgl *mfi_sgl) 12548c2ecf20Sopenharmony_ci{ 12558c2ecf20Sopenharmony_ci int i; 12568c2ecf20Sopenharmony_ci int sge_count; 12578c2ecf20Sopenharmony_ci struct scatterlist *os_sgl; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci sge_count = scsi_dma_map(scp); 12608c2ecf20Sopenharmony_ci BUG_ON(sge_count < 0); 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci if (sge_count) { 12638c2ecf20Sopenharmony_ci scsi_for_each_sg(scp, os_sgl, sge_count, i) { 12648c2ecf20Sopenharmony_ci mfi_sgl->sge32[i].length = cpu_to_le32(sg_dma_len(os_sgl)); 12658c2ecf20Sopenharmony_ci mfi_sgl->sge32[i].phys_addr = cpu_to_le32(sg_dma_address(os_sgl)); 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci return sge_count; 12698c2ecf20Sopenharmony_ci} 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci/** 12728c2ecf20Sopenharmony_ci * megasas_make_sgl64 - Prepares 64-bit SGL 12738c2ecf20Sopenharmony_ci * @instance: Adapter soft state 12748c2ecf20Sopenharmony_ci * @scp: SCSI command from the mid-layer 12758c2ecf20Sopenharmony_ci * @mfi_sgl: SGL to be filled in 12768c2ecf20Sopenharmony_ci * 12778c2ecf20Sopenharmony_ci * If successful, this function returns the number of SG elements. Otherwise, 12788c2ecf20Sopenharmony_ci * it returnes -1. 12798c2ecf20Sopenharmony_ci */ 12808c2ecf20Sopenharmony_cistatic int 12818c2ecf20Sopenharmony_cimegasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp, 12828c2ecf20Sopenharmony_ci union megasas_sgl *mfi_sgl) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci int i; 12858c2ecf20Sopenharmony_ci int sge_count; 12868c2ecf20Sopenharmony_ci struct scatterlist *os_sgl; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci sge_count = scsi_dma_map(scp); 12898c2ecf20Sopenharmony_ci BUG_ON(sge_count < 0); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if (sge_count) { 12928c2ecf20Sopenharmony_ci scsi_for_each_sg(scp, os_sgl, sge_count, i) { 12938c2ecf20Sopenharmony_ci mfi_sgl->sge64[i].length = cpu_to_le32(sg_dma_len(os_sgl)); 12948c2ecf20Sopenharmony_ci mfi_sgl->sge64[i].phys_addr = cpu_to_le64(sg_dma_address(os_sgl)); 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci return sge_count; 12988c2ecf20Sopenharmony_ci} 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci/** 13018c2ecf20Sopenharmony_ci * megasas_make_sgl_skinny - Prepares IEEE SGL 13028c2ecf20Sopenharmony_ci * @instance: Adapter soft state 13038c2ecf20Sopenharmony_ci * @scp: SCSI command from the mid-layer 13048c2ecf20Sopenharmony_ci * @mfi_sgl: SGL to be filled in 13058c2ecf20Sopenharmony_ci * 13068c2ecf20Sopenharmony_ci * If successful, this function returns the number of SG elements. Otherwise, 13078c2ecf20Sopenharmony_ci * it returnes -1. 13088c2ecf20Sopenharmony_ci */ 13098c2ecf20Sopenharmony_cistatic int 13108c2ecf20Sopenharmony_cimegasas_make_sgl_skinny(struct megasas_instance *instance, 13118c2ecf20Sopenharmony_ci struct scsi_cmnd *scp, union megasas_sgl *mfi_sgl) 13128c2ecf20Sopenharmony_ci{ 13138c2ecf20Sopenharmony_ci int i; 13148c2ecf20Sopenharmony_ci int sge_count; 13158c2ecf20Sopenharmony_ci struct scatterlist *os_sgl; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci sge_count = scsi_dma_map(scp); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci if (sge_count) { 13208c2ecf20Sopenharmony_ci scsi_for_each_sg(scp, os_sgl, sge_count, i) { 13218c2ecf20Sopenharmony_ci mfi_sgl->sge_skinny[i].length = 13228c2ecf20Sopenharmony_ci cpu_to_le32(sg_dma_len(os_sgl)); 13238c2ecf20Sopenharmony_ci mfi_sgl->sge_skinny[i].phys_addr = 13248c2ecf20Sopenharmony_ci cpu_to_le64(sg_dma_address(os_sgl)); 13258c2ecf20Sopenharmony_ci mfi_sgl->sge_skinny[i].flag = cpu_to_le32(0); 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci return sge_count; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci /** 13328c2ecf20Sopenharmony_ci * megasas_get_frame_count - Computes the number of frames 13338c2ecf20Sopenharmony_ci * @frame_type : type of frame- io or pthru frame 13348c2ecf20Sopenharmony_ci * @sge_count : number of sg elements 13358c2ecf20Sopenharmony_ci * 13368c2ecf20Sopenharmony_ci * Returns the number of frames required for numnber of sge's (sge_count) 13378c2ecf20Sopenharmony_ci */ 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_cistatic u32 megasas_get_frame_count(struct megasas_instance *instance, 13408c2ecf20Sopenharmony_ci u8 sge_count, u8 frame_type) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci int num_cnt; 13438c2ecf20Sopenharmony_ci int sge_bytes; 13448c2ecf20Sopenharmony_ci u32 sge_sz; 13458c2ecf20Sopenharmony_ci u32 frame_count = 0; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) : 13488c2ecf20Sopenharmony_ci sizeof(struct megasas_sge32); 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci if (instance->flag_ieee) { 13518c2ecf20Sopenharmony_ci sge_sz = sizeof(struct megasas_sge_skinny); 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci /* 13558c2ecf20Sopenharmony_ci * Main frame can contain 2 SGEs for 64-bit SGLs and 13568c2ecf20Sopenharmony_ci * 3 SGEs for 32-bit SGLs for ldio & 13578c2ecf20Sopenharmony_ci * 1 SGEs for 64-bit SGLs and 13588c2ecf20Sopenharmony_ci * 2 SGEs for 32-bit SGLs for pthru frame 13598c2ecf20Sopenharmony_ci */ 13608c2ecf20Sopenharmony_ci if (unlikely(frame_type == PTHRU_FRAME)) { 13618c2ecf20Sopenharmony_ci if (instance->flag_ieee == 1) { 13628c2ecf20Sopenharmony_ci num_cnt = sge_count - 1; 13638c2ecf20Sopenharmony_ci } else if (IS_DMA64) 13648c2ecf20Sopenharmony_ci num_cnt = sge_count - 1; 13658c2ecf20Sopenharmony_ci else 13668c2ecf20Sopenharmony_ci num_cnt = sge_count - 2; 13678c2ecf20Sopenharmony_ci } else { 13688c2ecf20Sopenharmony_ci if (instance->flag_ieee == 1) { 13698c2ecf20Sopenharmony_ci num_cnt = sge_count - 1; 13708c2ecf20Sopenharmony_ci } else if (IS_DMA64) 13718c2ecf20Sopenharmony_ci num_cnt = sge_count - 2; 13728c2ecf20Sopenharmony_ci else 13738c2ecf20Sopenharmony_ci num_cnt = sge_count - 3; 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci if (num_cnt > 0) { 13778c2ecf20Sopenharmony_ci sge_bytes = sge_sz * num_cnt; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) + 13808c2ecf20Sopenharmony_ci ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci /* Main frame */ 13838c2ecf20Sopenharmony_ci frame_count += 1; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci if (frame_count > 7) 13868c2ecf20Sopenharmony_ci frame_count = 8; 13878c2ecf20Sopenharmony_ci return frame_count; 13888c2ecf20Sopenharmony_ci} 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci/** 13918c2ecf20Sopenharmony_ci * megasas_build_dcdb - Prepares a direct cdb (DCDB) command 13928c2ecf20Sopenharmony_ci * @instance: Adapter soft state 13938c2ecf20Sopenharmony_ci * @scp: SCSI command 13948c2ecf20Sopenharmony_ci * @cmd: Command to be prepared in 13958c2ecf20Sopenharmony_ci * 13968c2ecf20Sopenharmony_ci * This function prepares CDB commands. These are typcially pass-through 13978c2ecf20Sopenharmony_ci * commands to the devices. 13988c2ecf20Sopenharmony_ci */ 13998c2ecf20Sopenharmony_cistatic int 14008c2ecf20Sopenharmony_cimegasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp, 14018c2ecf20Sopenharmony_ci struct megasas_cmd *cmd) 14028c2ecf20Sopenharmony_ci{ 14038c2ecf20Sopenharmony_ci u32 is_logical; 14048c2ecf20Sopenharmony_ci u32 device_id; 14058c2ecf20Sopenharmony_ci u16 flags = 0; 14068c2ecf20Sopenharmony_ci struct megasas_pthru_frame *pthru; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci is_logical = MEGASAS_IS_LOGICAL(scp->device); 14098c2ecf20Sopenharmony_ci device_id = MEGASAS_DEV_INDEX(scp); 14108c2ecf20Sopenharmony_ci pthru = (struct megasas_pthru_frame *)cmd->frame; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci if (scp->sc_data_direction == DMA_TO_DEVICE) 14138c2ecf20Sopenharmony_ci flags = MFI_FRAME_DIR_WRITE; 14148c2ecf20Sopenharmony_ci else if (scp->sc_data_direction == DMA_FROM_DEVICE) 14158c2ecf20Sopenharmony_ci flags = MFI_FRAME_DIR_READ; 14168c2ecf20Sopenharmony_ci else if (scp->sc_data_direction == DMA_NONE) 14178c2ecf20Sopenharmony_ci flags = MFI_FRAME_DIR_NONE; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if (instance->flag_ieee == 1) { 14208c2ecf20Sopenharmony_ci flags |= MFI_FRAME_IEEE; 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci /* 14248c2ecf20Sopenharmony_ci * Prepare the DCDB frame 14258c2ecf20Sopenharmony_ci */ 14268c2ecf20Sopenharmony_ci pthru->cmd = (is_logical) ? MFI_CMD_LD_SCSI_IO : MFI_CMD_PD_SCSI_IO; 14278c2ecf20Sopenharmony_ci pthru->cmd_status = 0x0; 14288c2ecf20Sopenharmony_ci pthru->scsi_status = 0x0; 14298c2ecf20Sopenharmony_ci pthru->target_id = device_id; 14308c2ecf20Sopenharmony_ci pthru->lun = scp->device->lun; 14318c2ecf20Sopenharmony_ci pthru->cdb_len = scp->cmd_len; 14328c2ecf20Sopenharmony_ci pthru->timeout = 0; 14338c2ecf20Sopenharmony_ci pthru->pad_0 = 0; 14348c2ecf20Sopenharmony_ci pthru->flags = cpu_to_le16(flags); 14358c2ecf20Sopenharmony_ci pthru->data_xfer_len = cpu_to_le32(scsi_bufflen(scp)); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci /* 14408c2ecf20Sopenharmony_ci * If the command is for the tape device, set the 14418c2ecf20Sopenharmony_ci * pthru timeout to the os layer timeout value. 14428c2ecf20Sopenharmony_ci */ 14438c2ecf20Sopenharmony_ci if (scp->device->type == TYPE_TAPE) { 14448c2ecf20Sopenharmony_ci if ((scp->request->timeout / HZ) > 0xFFFF) 14458c2ecf20Sopenharmony_ci pthru->timeout = cpu_to_le16(0xFFFF); 14468c2ecf20Sopenharmony_ci else 14478c2ecf20Sopenharmony_ci pthru->timeout = cpu_to_le16(scp->request->timeout / HZ); 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci /* 14518c2ecf20Sopenharmony_ci * Construct SGL 14528c2ecf20Sopenharmony_ci */ 14538c2ecf20Sopenharmony_ci if (instance->flag_ieee == 1) { 14548c2ecf20Sopenharmony_ci pthru->flags |= cpu_to_le16(MFI_FRAME_SGL64); 14558c2ecf20Sopenharmony_ci pthru->sge_count = megasas_make_sgl_skinny(instance, scp, 14568c2ecf20Sopenharmony_ci &pthru->sgl); 14578c2ecf20Sopenharmony_ci } else if (IS_DMA64) { 14588c2ecf20Sopenharmony_ci pthru->flags |= cpu_to_le16(MFI_FRAME_SGL64); 14598c2ecf20Sopenharmony_ci pthru->sge_count = megasas_make_sgl64(instance, scp, 14608c2ecf20Sopenharmony_ci &pthru->sgl); 14618c2ecf20Sopenharmony_ci } else 14628c2ecf20Sopenharmony_ci pthru->sge_count = megasas_make_sgl32(instance, scp, 14638c2ecf20Sopenharmony_ci &pthru->sgl); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci if (pthru->sge_count > instance->max_num_sge) { 14668c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "DCDB too many SGE NUM=%x\n", 14678c2ecf20Sopenharmony_ci pthru->sge_count); 14688c2ecf20Sopenharmony_ci return 0; 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci /* 14728c2ecf20Sopenharmony_ci * Sense info specific 14738c2ecf20Sopenharmony_ci */ 14748c2ecf20Sopenharmony_ci pthru->sense_len = SCSI_SENSE_BUFFERSIZE; 14758c2ecf20Sopenharmony_ci pthru->sense_buf_phys_addr_hi = 14768c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(cmd->sense_phys_addr)); 14778c2ecf20Sopenharmony_ci pthru->sense_buf_phys_addr_lo = 14788c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(cmd->sense_phys_addr)); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci /* 14818c2ecf20Sopenharmony_ci * Compute the total number of frames this command consumes. FW uses 14828c2ecf20Sopenharmony_ci * this number to pull sufficient number of frames from host memory. 14838c2ecf20Sopenharmony_ci */ 14848c2ecf20Sopenharmony_ci cmd->frame_count = megasas_get_frame_count(instance, pthru->sge_count, 14858c2ecf20Sopenharmony_ci PTHRU_FRAME); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci return cmd->frame_count; 14888c2ecf20Sopenharmony_ci} 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci/** 14918c2ecf20Sopenharmony_ci * megasas_build_ldio - Prepares IOs to logical devices 14928c2ecf20Sopenharmony_ci * @instance: Adapter soft state 14938c2ecf20Sopenharmony_ci * @scp: SCSI command 14948c2ecf20Sopenharmony_ci * @cmd: Command to be prepared 14958c2ecf20Sopenharmony_ci * 14968c2ecf20Sopenharmony_ci * Frames (and accompanying SGLs) for regular SCSI IOs use this function. 14978c2ecf20Sopenharmony_ci */ 14988c2ecf20Sopenharmony_cistatic int 14998c2ecf20Sopenharmony_cimegasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, 15008c2ecf20Sopenharmony_ci struct megasas_cmd *cmd) 15018c2ecf20Sopenharmony_ci{ 15028c2ecf20Sopenharmony_ci u32 device_id; 15038c2ecf20Sopenharmony_ci u8 sc = scp->cmnd[0]; 15048c2ecf20Sopenharmony_ci u16 flags = 0; 15058c2ecf20Sopenharmony_ci struct megasas_io_frame *ldio; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci device_id = MEGASAS_DEV_INDEX(scp); 15088c2ecf20Sopenharmony_ci ldio = (struct megasas_io_frame *)cmd->frame; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci if (scp->sc_data_direction == DMA_TO_DEVICE) 15118c2ecf20Sopenharmony_ci flags = MFI_FRAME_DIR_WRITE; 15128c2ecf20Sopenharmony_ci else if (scp->sc_data_direction == DMA_FROM_DEVICE) 15138c2ecf20Sopenharmony_ci flags = MFI_FRAME_DIR_READ; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci if (instance->flag_ieee == 1) { 15168c2ecf20Sopenharmony_ci flags |= MFI_FRAME_IEEE; 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci /* 15208c2ecf20Sopenharmony_ci * Prepare the Logical IO frame: 2nd bit is zero for all read cmds 15218c2ecf20Sopenharmony_ci */ 15228c2ecf20Sopenharmony_ci ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ; 15238c2ecf20Sopenharmony_ci ldio->cmd_status = 0x0; 15248c2ecf20Sopenharmony_ci ldio->scsi_status = 0x0; 15258c2ecf20Sopenharmony_ci ldio->target_id = device_id; 15268c2ecf20Sopenharmony_ci ldio->timeout = 0; 15278c2ecf20Sopenharmony_ci ldio->reserved_0 = 0; 15288c2ecf20Sopenharmony_ci ldio->pad_0 = 0; 15298c2ecf20Sopenharmony_ci ldio->flags = cpu_to_le16(flags); 15308c2ecf20Sopenharmony_ci ldio->start_lba_hi = 0; 15318c2ecf20Sopenharmony_ci ldio->access_byte = (scp->cmd_len != 6) ? scp->cmnd[1] : 0; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci /* 15348c2ecf20Sopenharmony_ci * 6-byte READ(0x08) or WRITE(0x0A) cdb 15358c2ecf20Sopenharmony_ci */ 15368c2ecf20Sopenharmony_ci if (scp->cmd_len == 6) { 15378c2ecf20Sopenharmony_ci ldio->lba_count = cpu_to_le32((u32) scp->cmnd[4]); 15388c2ecf20Sopenharmony_ci ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[1] << 16) | 15398c2ecf20Sopenharmony_ci ((u32) scp->cmnd[2] << 8) | 15408c2ecf20Sopenharmony_ci (u32) scp->cmnd[3]); 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci ldio->start_lba_lo &= cpu_to_le32(0x1FFFFF); 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci /* 15468c2ecf20Sopenharmony_ci * 10-byte READ(0x28) or WRITE(0x2A) cdb 15478c2ecf20Sopenharmony_ci */ 15488c2ecf20Sopenharmony_ci else if (scp->cmd_len == 10) { 15498c2ecf20Sopenharmony_ci ldio->lba_count = cpu_to_le32((u32) scp->cmnd[8] | 15508c2ecf20Sopenharmony_ci ((u32) scp->cmnd[7] << 8)); 15518c2ecf20Sopenharmony_ci ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[2] << 24) | 15528c2ecf20Sopenharmony_ci ((u32) scp->cmnd[3] << 16) | 15538c2ecf20Sopenharmony_ci ((u32) scp->cmnd[4] << 8) | 15548c2ecf20Sopenharmony_ci (u32) scp->cmnd[5]); 15558c2ecf20Sopenharmony_ci } 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci /* 15588c2ecf20Sopenharmony_ci * 12-byte READ(0xA8) or WRITE(0xAA) cdb 15598c2ecf20Sopenharmony_ci */ 15608c2ecf20Sopenharmony_ci else if (scp->cmd_len == 12) { 15618c2ecf20Sopenharmony_ci ldio->lba_count = cpu_to_le32(((u32) scp->cmnd[6] << 24) | 15628c2ecf20Sopenharmony_ci ((u32) scp->cmnd[7] << 16) | 15638c2ecf20Sopenharmony_ci ((u32) scp->cmnd[8] << 8) | 15648c2ecf20Sopenharmony_ci (u32) scp->cmnd[9]); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[2] << 24) | 15678c2ecf20Sopenharmony_ci ((u32) scp->cmnd[3] << 16) | 15688c2ecf20Sopenharmony_ci ((u32) scp->cmnd[4] << 8) | 15698c2ecf20Sopenharmony_ci (u32) scp->cmnd[5]); 15708c2ecf20Sopenharmony_ci } 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci /* 15738c2ecf20Sopenharmony_ci * 16-byte READ(0x88) or WRITE(0x8A) cdb 15748c2ecf20Sopenharmony_ci */ 15758c2ecf20Sopenharmony_ci else if (scp->cmd_len == 16) { 15768c2ecf20Sopenharmony_ci ldio->lba_count = cpu_to_le32(((u32) scp->cmnd[10] << 24) | 15778c2ecf20Sopenharmony_ci ((u32) scp->cmnd[11] << 16) | 15788c2ecf20Sopenharmony_ci ((u32) scp->cmnd[12] << 8) | 15798c2ecf20Sopenharmony_ci (u32) scp->cmnd[13]); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[6] << 24) | 15828c2ecf20Sopenharmony_ci ((u32) scp->cmnd[7] << 16) | 15838c2ecf20Sopenharmony_ci ((u32) scp->cmnd[8] << 8) | 15848c2ecf20Sopenharmony_ci (u32) scp->cmnd[9]); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci ldio->start_lba_hi = cpu_to_le32(((u32) scp->cmnd[2] << 24) | 15878c2ecf20Sopenharmony_ci ((u32) scp->cmnd[3] << 16) | 15888c2ecf20Sopenharmony_ci ((u32) scp->cmnd[4] << 8) | 15898c2ecf20Sopenharmony_ci (u32) scp->cmnd[5]); 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci /* 15948c2ecf20Sopenharmony_ci * Construct SGL 15958c2ecf20Sopenharmony_ci */ 15968c2ecf20Sopenharmony_ci if (instance->flag_ieee) { 15978c2ecf20Sopenharmony_ci ldio->flags |= cpu_to_le16(MFI_FRAME_SGL64); 15988c2ecf20Sopenharmony_ci ldio->sge_count = megasas_make_sgl_skinny(instance, scp, 15998c2ecf20Sopenharmony_ci &ldio->sgl); 16008c2ecf20Sopenharmony_ci } else if (IS_DMA64) { 16018c2ecf20Sopenharmony_ci ldio->flags |= cpu_to_le16(MFI_FRAME_SGL64); 16028c2ecf20Sopenharmony_ci ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl); 16038c2ecf20Sopenharmony_ci } else 16048c2ecf20Sopenharmony_ci ldio->sge_count = megasas_make_sgl32(instance, scp, &ldio->sgl); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci if (ldio->sge_count > instance->max_num_sge) { 16078c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "build_ld_io: sge_count = %x\n", 16088c2ecf20Sopenharmony_ci ldio->sge_count); 16098c2ecf20Sopenharmony_ci return 0; 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci /* 16138c2ecf20Sopenharmony_ci * Sense info specific 16148c2ecf20Sopenharmony_ci */ 16158c2ecf20Sopenharmony_ci ldio->sense_len = SCSI_SENSE_BUFFERSIZE; 16168c2ecf20Sopenharmony_ci ldio->sense_buf_phys_addr_hi = 0; 16178c2ecf20Sopenharmony_ci ldio->sense_buf_phys_addr_lo = cpu_to_le32(cmd->sense_phys_addr); 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci /* 16208c2ecf20Sopenharmony_ci * Compute the total number of frames this command consumes. FW uses 16218c2ecf20Sopenharmony_ci * this number to pull sufficient number of frames from host memory. 16228c2ecf20Sopenharmony_ci */ 16238c2ecf20Sopenharmony_ci cmd->frame_count = megasas_get_frame_count(instance, 16248c2ecf20Sopenharmony_ci ldio->sge_count, IO_FRAME); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci return cmd->frame_count; 16278c2ecf20Sopenharmony_ci} 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci/** 16308c2ecf20Sopenharmony_ci * megasas_cmd_type - Checks if the cmd is for logical drive/sysPD 16318c2ecf20Sopenharmony_ci * and whether it's RW or non RW 16328c2ecf20Sopenharmony_ci * @cmd: SCSI command 16338c2ecf20Sopenharmony_ci * 16348c2ecf20Sopenharmony_ci */ 16358c2ecf20Sopenharmony_ciinline int megasas_cmd_type(struct scsi_cmnd *cmd) 16368c2ecf20Sopenharmony_ci{ 16378c2ecf20Sopenharmony_ci int ret; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci switch (cmd->cmnd[0]) { 16408c2ecf20Sopenharmony_ci case READ_10: 16418c2ecf20Sopenharmony_ci case WRITE_10: 16428c2ecf20Sopenharmony_ci case READ_12: 16438c2ecf20Sopenharmony_ci case WRITE_12: 16448c2ecf20Sopenharmony_ci case READ_6: 16458c2ecf20Sopenharmony_ci case WRITE_6: 16468c2ecf20Sopenharmony_ci case READ_16: 16478c2ecf20Sopenharmony_ci case WRITE_16: 16488c2ecf20Sopenharmony_ci ret = (MEGASAS_IS_LOGICAL(cmd->device)) ? 16498c2ecf20Sopenharmony_ci READ_WRITE_LDIO : READ_WRITE_SYSPDIO; 16508c2ecf20Sopenharmony_ci break; 16518c2ecf20Sopenharmony_ci default: 16528c2ecf20Sopenharmony_ci ret = (MEGASAS_IS_LOGICAL(cmd->device)) ? 16538c2ecf20Sopenharmony_ci NON_READ_WRITE_LDIO : NON_READ_WRITE_SYSPDIO; 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci return ret; 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci /** 16598c2ecf20Sopenharmony_ci * megasas_dump_pending_frames - Dumps the frame address of all pending cmds 16608c2ecf20Sopenharmony_ci * in FW 16618c2ecf20Sopenharmony_ci * @instance: Adapter soft state 16628c2ecf20Sopenharmony_ci */ 16638c2ecf20Sopenharmony_cistatic inline void 16648c2ecf20Sopenharmony_cimegasas_dump_pending_frames(struct megasas_instance *instance) 16658c2ecf20Sopenharmony_ci{ 16668c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 16678c2ecf20Sopenharmony_ci int i,n; 16688c2ecf20Sopenharmony_ci union megasas_sgl *mfi_sgl; 16698c2ecf20Sopenharmony_ci struct megasas_io_frame *ldio; 16708c2ecf20Sopenharmony_ci struct megasas_pthru_frame *pthru; 16718c2ecf20Sopenharmony_ci u32 sgcount; 16728c2ecf20Sopenharmony_ci u16 max_cmd = instance->max_fw_cmds; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no); 16758c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding)); 16768c2ecf20Sopenharmony_ci if (IS_DMA64) 16778c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no); 16788c2ecf20Sopenharmony_ci else 16798c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no); 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "[%d]: Pending OS cmds in FW : \n",instance->host->host_no); 16828c2ecf20Sopenharmony_ci for (i = 0; i < max_cmd; i++) { 16838c2ecf20Sopenharmony_ci cmd = instance->cmd_list[i]; 16848c2ecf20Sopenharmony_ci if (!cmd->scmd) 16858c2ecf20Sopenharmony_ci continue; 16868c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr); 16878c2ecf20Sopenharmony_ci if (megasas_cmd_type(cmd->scmd) == READ_WRITE_LDIO) { 16888c2ecf20Sopenharmony_ci ldio = (struct megasas_io_frame *)cmd->frame; 16898c2ecf20Sopenharmony_ci mfi_sgl = &ldio->sgl; 16908c2ecf20Sopenharmony_ci sgcount = ldio->sge_count; 16918c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x," 16928c2ecf20Sopenharmony_ci " lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n", 16938c2ecf20Sopenharmony_ci instance->host->host_no, cmd->frame_count, ldio->cmd, ldio->target_id, 16948c2ecf20Sopenharmony_ci le32_to_cpu(ldio->start_lba_lo), le32_to_cpu(ldio->start_lba_hi), 16958c2ecf20Sopenharmony_ci le32_to_cpu(ldio->sense_buf_phys_addr_lo), sgcount); 16968c2ecf20Sopenharmony_ci } else { 16978c2ecf20Sopenharmony_ci pthru = (struct megasas_pthru_frame *) cmd->frame; 16988c2ecf20Sopenharmony_ci mfi_sgl = &pthru->sgl; 16998c2ecf20Sopenharmony_ci sgcount = pthru->sge_count; 17008c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, " 17018c2ecf20Sopenharmony_ci "lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n", 17028c2ecf20Sopenharmony_ci instance->host->host_no, cmd->frame_count, pthru->cmd, pthru->target_id, 17038c2ecf20Sopenharmony_ci pthru->lun, pthru->cdb_len, le32_to_cpu(pthru->data_xfer_len), 17048c2ecf20Sopenharmony_ci le32_to_cpu(pthru->sense_buf_phys_addr_lo), sgcount); 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & MEGASAS_DBG_LVL) { 17078c2ecf20Sopenharmony_ci for (n = 0; n < sgcount; n++) { 17088c2ecf20Sopenharmony_ci if (IS_DMA64) 17098c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%llx\n", 17108c2ecf20Sopenharmony_ci le32_to_cpu(mfi_sgl->sge64[n].length), 17118c2ecf20Sopenharmony_ci le64_to_cpu(mfi_sgl->sge64[n].phys_addr)); 17128c2ecf20Sopenharmony_ci else 17138c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%x\n", 17148c2ecf20Sopenharmony_ci le32_to_cpu(mfi_sgl->sge32[n].length), 17158c2ecf20Sopenharmony_ci le32_to_cpu(mfi_sgl->sge32[n].phys_addr)); 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci } /*for max_cmd*/ 17198c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "[%d]: Pending Internal cmds in FW : \n",instance->host->host_no); 17208c2ecf20Sopenharmony_ci for (i = 0; i < max_cmd; i++) { 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci cmd = instance->cmd_list[i]; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci if (cmd->sync_cmd == 1) 17258c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "0x%08lx : ", (unsigned long)cmd->frame_phys_addr); 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "[%d]: Dumping Done\n\n",instance->host->host_no); 17288c2ecf20Sopenharmony_ci} 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ciu32 17318c2ecf20Sopenharmony_cimegasas_build_and_issue_cmd(struct megasas_instance *instance, 17328c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd) 17338c2ecf20Sopenharmony_ci{ 17348c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 17358c2ecf20Sopenharmony_ci u32 frame_count; 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 17388c2ecf20Sopenharmony_ci if (!cmd) 17398c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci /* 17428c2ecf20Sopenharmony_ci * Logical drive command 17438c2ecf20Sopenharmony_ci */ 17448c2ecf20Sopenharmony_ci if (megasas_cmd_type(scmd) == READ_WRITE_LDIO) 17458c2ecf20Sopenharmony_ci frame_count = megasas_build_ldio(instance, scmd, cmd); 17468c2ecf20Sopenharmony_ci else 17478c2ecf20Sopenharmony_ci frame_count = megasas_build_dcdb(instance, scmd, cmd); 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci if (!frame_count) 17508c2ecf20Sopenharmony_ci goto out_return_cmd; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci cmd->scmd = scmd; 17538c2ecf20Sopenharmony_ci scmd->SCp.ptr = (char *)cmd; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci /* 17568c2ecf20Sopenharmony_ci * Issue the command to the FW 17578c2ecf20Sopenharmony_ci */ 17588c2ecf20Sopenharmony_ci atomic_inc(&instance->fw_outstanding); 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci instance->instancet->fire_cmd(instance, cmd->frame_phys_addr, 17618c2ecf20Sopenharmony_ci cmd->frame_count-1, instance->reg_set); 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci return 0; 17648c2ecf20Sopenharmony_ciout_return_cmd: 17658c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 17668c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci/** 17718c2ecf20Sopenharmony_ci * megasas_queue_command - Queue entry point 17728c2ecf20Sopenharmony_ci * @shost: adapter SCSI host 17738c2ecf20Sopenharmony_ci * @scmd: SCSI command to be queued 17748c2ecf20Sopenharmony_ci */ 17758c2ecf20Sopenharmony_cistatic int 17768c2ecf20Sopenharmony_cimegasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) 17778c2ecf20Sopenharmony_ci{ 17788c2ecf20Sopenharmony_ci struct megasas_instance *instance; 17798c2ecf20Sopenharmony_ci struct MR_PRIV_DEVICE *mr_device_priv_data; 17808c2ecf20Sopenharmony_ci u32 ld_tgt_id; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci instance = (struct megasas_instance *) 17838c2ecf20Sopenharmony_ci scmd->device->host->hostdata; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci if (instance->unload == 1) { 17868c2ecf20Sopenharmony_ci scmd->result = DID_NO_CONNECT << 16; 17878c2ecf20Sopenharmony_ci scmd->scsi_done(scmd); 17888c2ecf20Sopenharmony_ci return 0; 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci if (instance->issuepend_done == 0) 17928c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci /* Check for an mpio path and adjust behavior */ 17968c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) { 17978c2ecf20Sopenharmony_ci if (megasas_check_mpio_paths(instance, scmd) == 17988c2ecf20Sopenharmony_ci (DID_REQUEUE << 16)) { 17998c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 18008c2ecf20Sopenharmony_ci } else { 18018c2ecf20Sopenharmony_ci scmd->result = DID_NO_CONNECT << 16; 18028c2ecf20Sopenharmony_ci scmd->scsi_done(scmd); 18038c2ecf20Sopenharmony_ci return 0; 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci mr_device_priv_data = scmd->device->hostdata; 18088c2ecf20Sopenharmony_ci if (!mr_device_priv_data || 18098c2ecf20Sopenharmony_ci (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)) { 18108c2ecf20Sopenharmony_ci scmd->result = DID_NO_CONNECT << 16; 18118c2ecf20Sopenharmony_ci scmd->scsi_done(scmd); 18128c2ecf20Sopenharmony_ci return 0; 18138c2ecf20Sopenharmony_ci } 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci if (MEGASAS_IS_LOGICAL(scmd->device)) { 18168c2ecf20Sopenharmony_ci ld_tgt_id = MEGASAS_TARGET_ID(scmd->device); 18178c2ecf20Sopenharmony_ci if (instance->ld_tgtid_status[ld_tgt_id] == LD_TARGET_ID_DELETED) { 18188c2ecf20Sopenharmony_ci scmd->result = DID_NO_CONNECT << 16; 18198c2ecf20Sopenharmony_ci scmd->scsi_done(scmd); 18208c2ecf20Sopenharmony_ci return 0; 18218c2ecf20Sopenharmony_ci } 18228c2ecf20Sopenharmony_ci } 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) 18258c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci if (mr_device_priv_data->tm_busy) 18288c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci scmd->result = 0; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci if (MEGASAS_IS_LOGICAL(scmd->device) && 18348c2ecf20Sopenharmony_ci (scmd->device->id >= instance->fw_supported_vd_count || 18358c2ecf20Sopenharmony_ci scmd->device->lun)) { 18368c2ecf20Sopenharmony_ci scmd->result = DID_BAD_TARGET << 16; 18378c2ecf20Sopenharmony_ci goto out_done; 18388c2ecf20Sopenharmony_ci } 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci if ((scmd->cmnd[0] == SYNCHRONIZE_CACHE) && 18418c2ecf20Sopenharmony_ci MEGASAS_IS_LOGICAL(scmd->device) && 18428c2ecf20Sopenharmony_ci (!instance->fw_sync_cache_support)) { 18438c2ecf20Sopenharmony_ci scmd->result = DID_OK << 16; 18448c2ecf20Sopenharmony_ci goto out_done; 18458c2ecf20Sopenharmony_ci } 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci return instance->instancet->build_and_issue_cmd(instance, scmd); 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci out_done: 18508c2ecf20Sopenharmony_ci scmd->scsi_done(scmd); 18518c2ecf20Sopenharmony_ci return 0; 18528c2ecf20Sopenharmony_ci} 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_cistatic struct megasas_instance *megasas_lookup_instance(u16 host_no) 18558c2ecf20Sopenharmony_ci{ 18568c2ecf20Sopenharmony_ci int i; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci for (i = 0; i < megasas_mgmt_info.max_index; i++) { 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci if ((megasas_mgmt_info.instance[i]) && 18618c2ecf20Sopenharmony_ci (megasas_mgmt_info.instance[i]->host->host_no == host_no)) 18628c2ecf20Sopenharmony_ci return megasas_mgmt_info.instance[i]; 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci return NULL; 18668c2ecf20Sopenharmony_ci} 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci/* 18698c2ecf20Sopenharmony_ci* megasas_set_dynamic_target_properties - 18708c2ecf20Sopenharmony_ci* Device property set by driver may not be static and it is required to be 18718c2ecf20Sopenharmony_ci* updated after OCR 18728c2ecf20Sopenharmony_ci* 18738c2ecf20Sopenharmony_ci* set tm_capable. 18748c2ecf20Sopenharmony_ci* set dma alignment (only for eedp protection enable vd). 18758c2ecf20Sopenharmony_ci* 18768c2ecf20Sopenharmony_ci* @sdev: OS provided scsi device 18778c2ecf20Sopenharmony_ci* 18788c2ecf20Sopenharmony_ci* Returns void 18798c2ecf20Sopenharmony_ci*/ 18808c2ecf20Sopenharmony_civoid megasas_set_dynamic_target_properties(struct scsi_device *sdev, 18818c2ecf20Sopenharmony_ci bool is_target_prop) 18828c2ecf20Sopenharmony_ci{ 18838c2ecf20Sopenharmony_ci u16 pd_index = 0, ld; 18848c2ecf20Sopenharmony_ci u32 device_id; 18858c2ecf20Sopenharmony_ci struct megasas_instance *instance; 18868c2ecf20Sopenharmony_ci struct fusion_context *fusion; 18878c2ecf20Sopenharmony_ci struct MR_PRIV_DEVICE *mr_device_priv_data; 18888c2ecf20Sopenharmony_ci struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; 18898c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid; 18908c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *local_map_ptr; 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci instance = megasas_lookup_instance(sdev->host->host_no); 18938c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 18948c2ecf20Sopenharmony_ci mr_device_priv_data = sdev->hostdata; 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci if (!fusion || !mr_device_priv_data) 18978c2ecf20Sopenharmony_ci return; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci if (MEGASAS_IS_LOGICAL(sdev)) { 19008c2ecf20Sopenharmony_ci device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) 19018c2ecf20Sopenharmony_ci + sdev->id; 19028c2ecf20Sopenharmony_ci local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; 19038c2ecf20Sopenharmony_ci ld = MR_TargetIdToLdGet(device_id, local_map_ptr); 19048c2ecf20Sopenharmony_ci if (ld >= instance->fw_supported_vd_count) 19058c2ecf20Sopenharmony_ci return; 19068c2ecf20Sopenharmony_ci raid = MR_LdRaidGet(ld, local_map_ptr); 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) 19098c2ecf20Sopenharmony_ci blk_queue_update_dma_alignment(sdev->request_queue, 0x7); 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci mr_device_priv_data->is_tm_capable = 19128c2ecf20Sopenharmony_ci raid->capability.tmCapable; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci if (!raid->flags.isEPD) 19158c2ecf20Sopenharmony_ci sdev->no_write_same = 1; 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci } else if (instance->use_seqnum_jbod_fp) { 19188c2ecf20Sopenharmony_ci pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + 19198c2ecf20Sopenharmony_ci sdev->id; 19208c2ecf20Sopenharmony_ci pd_sync = (void *)fusion->pd_seq_sync 19218c2ecf20Sopenharmony_ci [(instance->pd_seq_map_id - 1) & 1]; 19228c2ecf20Sopenharmony_ci mr_device_priv_data->is_tm_capable = 19238c2ecf20Sopenharmony_ci pd_sync->seq[pd_index].capability.tmCapable; 19248c2ecf20Sopenharmony_ci } 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci if (is_target_prop && instance->tgt_prop->reset_tmo) { 19278c2ecf20Sopenharmony_ci /* 19288c2ecf20Sopenharmony_ci * If FW provides a target reset timeout value, driver will use 19298c2ecf20Sopenharmony_ci * it. If not set, fallback to default values. 19308c2ecf20Sopenharmony_ci */ 19318c2ecf20Sopenharmony_ci mr_device_priv_data->target_reset_tmo = 19328c2ecf20Sopenharmony_ci min_t(u8, instance->max_reset_tmo, 19338c2ecf20Sopenharmony_ci instance->tgt_prop->reset_tmo); 19348c2ecf20Sopenharmony_ci mr_device_priv_data->task_abort_tmo = instance->task_abort_tmo; 19358c2ecf20Sopenharmony_ci } else { 19368c2ecf20Sopenharmony_ci mr_device_priv_data->target_reset_tmo = 19378c2ecf20Sopenharmony_ci MEGASAS_DEFAULT_TM_TIMEOUT; 19388c2ecf20Sopenharmony_ci mr_device_priv_data->task_abort_tmo = 19398c2ecf20Sopenharmony_ci MEGASAS_DEFAULT_TM_TIMEOUT; 19408c2ecf20Sopenharmony_ci } 19418c2ecf20Sopenharmony_ci} 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci/* 19448c2ecf20Sopenharmony_ci * megasas_set_nvme_device_properties - 19458c2ecf20Sopenharmony_ci * set nomerges=2 19468c2ecf20Sopenharmony_ci * set virtual page boundary = 4K (current mr_nvme_pg_size is 4K). 19478c2ecf20Sopenharmony_ci * set maximum io transfer = MDTS of NVME device provided by MR firmware. 19488c2ecf20Sopenharmony_ci * 19498c2ecf20Sopenharmony_ci * MR firmware provides value in KB. Caller of this function converts 19508c2ecf20Sopenharmony_ci * kb into bytes. 19518c2ecf20Sopenharmony_ci * 19528c2ecf20Sopenharmony_ci * e.a MDTS=5 means 2^5 * nvme page size. (In case of 4K page size, 19538c2ecf20Sopenharmony_ci * MR firmware provides value 128 as (32 * 4K) = 128K. 19548c2ecf20Sopenharmony_ci * 19558c2ecf20Sopenharmony_ci * @sdev: scsi device 19568c2ecf20Sopenharmony_ci * @max_io_size: maximum io transfer size 19578c2ecf20Sopenharmony_ci * 19588c2ecf20Sopenharmony_ci */ 19598c2ecf20Sopenharmony_cistatic inline void 19608c2ecf20Sopenharmony_cimegasas_set_nvme_device_properties(struct scsi_device *sdev, u32 max_io_size) 19618c2ecf20Sopenharmony_ci{ 19628c2ecf20Sopenharmony_ci struct megasas_instance *instance; 19638c2ecf20Sopenharmony_ci u32 mr_nvme_pg_size; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)sdev->host->hostdata; 19668c2ecf20Sopenharmony_ci mr_nvme_pg_size = max_t(u32, instance->nvme_page_size, 19678c2ecf20Sopenharmony_ci MR_DEFAULT_NVME_PAGE_SIZE); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci blk_queue_max_hw_sectors(sdev->request_queue, (max_io_size / 512)); 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_NOMERGES, sdev->request_queue); 19728c2ecf20Sopenharmony_ci blk_queue_virt_boundary(sdev->request_queue, mr_nvme_pg_size - 1); 19738c2ecf20Sopenharmony_ci} 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci/* 19768c2ecf20Sopenharmony_ci * megasas_set_fw_assisted_qd - 19778c2ecf20Sopenharmony_ci * set device queue depth to can_queue 19788c2ecf20Sopenharmony_ci * set device queue depth to fw assisted qd 19798c2ecf20Sopenharmony_ci * 19808c2ecf20Sopenharmony_ci * @sdev: scsi device 19818c2ecf20Sopenharmony_ci * @is_target_prop true, if fw provided target properties. 19828c2ecf20Sopenharmony_ci */ 19838c2ecf20Sopenharmony_cistatic void megasas_set_fw_assisted_qd(struct scsi_device *sdev, 19848c2ecf20Sopenharmony_ci bool is_target_prop) 19858c2ecf20Sopenharmony_ci{ 19868c2ecf20Sopenharmony_ci u8 interface_type; 19878c2ecf20Sopenharmony_ci u32 device_qd = MEGASAS_DEFAULT_CMD_PER_LUN; 19888c2ecf20Sopenharmony_ci u32 tgt_device_qd; 19898c2ecf20Sopenharmony_ci struct megasas_instance *instance; 19908c2ecf20Sopenharmony_ci struct MR_PRIV_DEVICE *mr_device_priv_data; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci instance = megasas_lookup_instance(sdev->host->host_no); 19938c2ecf20Sopenharmony_ci mr_device_priv_data = sdev->hostdata; 19948c2ecf20Sopenharmony_ci interface_type = mr_device_priv_data->interface_type; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci switch (interface_type) { 19978c2ecf20Sopenharmony_ci case SAS_PD: 19988c2ecf20Sopenharmony_ci device_qd = MEGASAS_SAS_QD; 19998c2ecf20Sopenharmony_ci break; 20008c2ecf20Sopenharmony_ci case SATA_PD: 20018c2ecf20Sopenharmony_ci device_qd = MEGASAS_SATA_QD; 20028c2ecf20Sopenharmony_ci break; 20038c2ecf20Sopenharmony_ci case NVME_PD: 20048c2ecf20Sopenharmony_ci device_qd = MEGASAS_NVME_QD; 20058c2ecf20Sopenharmony_ci break; 20068c2ecf20Sopenharmony_ci } 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci if (is_target_prop) { 20098c2ecf20Sopenharmony_ci tgt_device_qd = le32_to_cpu(instance->tgt_prop->device_qdepth); 20108c2ecf20Sopenharmony_ci if (tgt_device_qd) 20118c2ecf20Sopenharmony_ci device_qd = min(instance->host->can_queue, 20128c2ecf20Sopenharmony_ci (int)tgt_device_qd); 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci if (instance->enable_sdev_max_qd && interface_type != UNKNOWN_DRIVE) 20168c2ecf20Sopenharmony_ci device_qd = instance->host->can_queue; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci scsi_change_queue_depth(sdev, device_qd); 20198c2ecf20Sopenharmony_ci} 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci/* 20228c2ecf20Sopenharmony_ci * megasas_set_static_target_properties - 20238c2ecf20Sopenharmony_ci * Device property set by driver are static and it is not required to be 20248c2ecf20Sopenharmony_ci * updated after OCR. 20258c2ecf20Sopenharmony_ci * 20268c2ecf20Sopenharmony_ci * set io timeout 20278c2ecf20Sopenharmony_ci * set device queue depth 20288c2ecf20Sopenharmony_ci * set nvme device properties. see - megasas_set_nvme_device_properties 20298c2ecf20Sopenharmony_ci * 20308c2ecf20Sopenharmony_ci * @sdev: scsi device 20318c2ecf20Sopenharmony_ci * @is_target_prop true, if fw provided target properties. 20328c2ecf20Sopenharmony_ci */ 20338c2ecf20Sopenharmony_cistatic void megasas_set_static_target_properties(struct scsi_device *sdev, 20348c2ecf20Sopenharmony_ci bool is_target_prop) 20358c2ecf20Sopenharmony_ci{ 20368c2ecf20Sopenharmony_ci u32 max_io_size_kb = MR_DEFAULT_NVME_MDTS_KB; 20378c2ecf20Sopenharmony_ci struct megasas_instance *instance; 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci instance = megasas_lookup_instance(sdev->host->host_no); 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci /* 20428c2ecf20Sopenharmony_ci * The RAID firmware may require extended timeouts. 20438c2ecf20Sopenharmony_ci */ 20448c2ecf20Sopenharmony_ci blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ); 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci /* max_io_size_kb will be set to non zero for 20478c2ecf20Sopenharmony_ci * nvme based vd and syspd. 20488c2ecf20Sopenharmony_ci */ 20498c2ecf20Sopenharmony_ci if (is_target_prop) 20508c2ecf20Sopenharmony_ci max_io_size_kb = le32_to_cpu(instance->tgt_prop->max_io_size_kb); 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci if (instance->nvme_page_size && max_io_size_kb) 20538c2ecf20Sopenharmony_ci megasas_set_nvme_device_properties(sdev, (max_io_size_kb << 10)); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci megasas_set_fw_assisted_qd(sdev, is_target_prop); 20568c2ecf20Sopenharmony_ci} 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_cistatic int megasas_slave_configure(struct scsi_device *sdev) 20608c2ecf20Sopenharmony_ci{ 20618c2ecf20Sopenharmony_ci u16 pd_index = 0; 20628c2ecf20Sopenharmony_ci struct megasas_instance *instance; 20638c2ecf20Sopenharmony_ci int ret_target_prop = DCMD_FAILED; 20648c2ecf20Sopenharmony_ci bool is_target_prop = false; 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci instance = megasas_lookup_instance(sdev->host->host_no); 20678c2ecf20Sopenharmony_ci if (instance->pd_list_not_supported) { 20688c2ecf20Sopenharmony_ci if (!MEGASAS_IS_LOGICAL(sdev) && sdev->type == TYPE_DISK) { 20698c2ecf20Sopenharmony_ci pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + 20708c2ecf20Sopenharmony_ci sdev->id; 20718c2ecf20Sopenharmony_ci if (instance->pd_list[pd_index].driveState != 20728c2ecf20Sopenharmony_ci MR_PD_STATE_SYSTEM) 20738c2ecf20Sopenharmony_ci return -ENXIO; 20748c2ecf20Sopenharmony_ci } 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 20788c2ecf20Sopenharmony_ci /* Send DCMD to Firmware and cache the information */ 20798c2ecf20Sopenharmony_ci if ((instance->pd_info) && !MEGASAS_IS_LOGICAL(sdev)) 20808c2ecf20Sopenharmony_ci megasas_get_pd_info(instance, sdev); 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci /* Some ventura firmware may not have instance->nvme_page_size set. 20838c2ecf20Sopenharmony_ci * Do not send MR_DCMD_DRV_GET_TARGET_PROP 20848c2ecf20Sopenharmony_ci */ 20858c2ecf20Sopenharmony_ci if ((instance->tgt_prop) && (instance->nvme_page_size)) 20868c2ecf20Sopenharmony_ci ret_target_prop = megasas_get_target_prop(instance, sdev); 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false; 20898c2ecf20Sopenharmony_ci megasas_set_static_target_properties(sdev, is_target_prop); 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci /* This sdev property may change post OCR */ 20928c2ecf20Sopenharmony_ci megasas_set_dynamic_target_properties(sdev, is_target_prop); 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci return 0; 20978c2ecf20Sopenharmony_ci} 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_cistatic int megasas_slave_alloc(struct scsi_device *sdev) 21008c2ecf20Sopenharmony_ci{ 21018c2ecf20Sopenharmony_ci u16 pd_index = 0, ld_tgt_id; 21028c2ecf20Sopenharmony_ci struct megasas_instance *instance ; 21038c2ecf20Sopenharmony_ci struct MR_PRIV_DEVICE *mr_device_priv_data; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci instance = megasas_lookup_instance(sdev->host->host_no); 21068c2ecf20Sopenharmony_ci if (!MEGASAS_IS_LOGICAL(sdev)) { 21078c2ecf20Sopenharmony_ci /* 21088c2ecf20Sopenharmony_ci * Open the OS scan to the SYSTEM PD 21098c2ecf20Sopenharmony_ci */ 21108c2ecf20Sopenharmony_ci pd_index = 21118c2ecf20Sopenharmony_ci (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + 21128c2ecf20Sopenharmony_ci sdev->id; 21138c2ecf20Sopenharmony_ci if ((instance->pd_list_not_supported || 21148c2ecf20Sopenharmony_ci instance->pd_list[pd_index].driveState == 21158c2ecf20Sopenharmony_ci MR_PD_STATE_SYSTEM)) { 21168c2ecf20Sopenharmony_ci goto scan_target; 21178c2ecf20Sopenharmony_ci } 21188c2ecf20Sopenharmony_ci return -ENXIO; 21198c2ecf20Sopenharmony_ci } else if (!MEGASAS_IS_LUN_VALID(sdev)) { 21208c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, sdev, "%s: invalid LUN\n", __func__); 21218c2ecf20Sopenharmony_ci return -ENXIO; 21228c2ecf20Sopenharmony_ci } 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ciscan_target: 21258c2ecf20Sopenharmony_ci mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data), 21268c2ecf20Sopenharmony_ci GFP_KERNEL); 21278c2ecf20Sopenharmony_ci if (!mr_device_priv_data) 21288c2ecf20Sopenharmony_ci return -ENOMEM; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci if (MEGASAS_IS_LOGICAL(sdev)) { 21318c2ecf20Sopenharmony_ci ld_tgt_id = MEGASAS_TARGET_ID(sdev); 21328c2ecf20Sopenharmony_ci instance->ld_tgtid_status[ld_tgt_id] = LD_TARGET_ID_ACTIVE; 21338c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & LD_PD_DEBUG) 21348c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, sdev, "LD target ID %d created.\n", ld_tgt_id); 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci sdev->hostdata = mr_device_priv_data; 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci atomic_set(&mr_device_priv_data->r1_ldio_hint, 21408c2ecf20Sopenharmony_ci instance->r1_ldio_hint_default); 21418c2ecf20Sopenharmony_ci return 0; 21428c2ecf20Sopenharmony_ci} 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_cistatic void megasas_slave_destroy(struct scsi_device *sdev) 21458c2ecf20Sopenharmony_ci{ 21468c2ecf20Sopenharmony_ci u16 ld_tgt_id; 21478c2ecf20Sopenharmony_ci struct megasas_instance *instance; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci instance = megasas_lookup_instance(sdev->host->host_no); 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci if (MEGASAS_IS_LOGICAL(sdev)) { 21528c2ecf20Sopenharmony_ci if (!MEGASAS_IS_LUN_VALID(sdev)) { 21538c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, sdev, "%s: invalid LUN\n", __func__); 21548c2ecf20Sopenharmony_ci return; 21558c2ecf20Sopenharmony_ci } 21568c2ecf20Sopenharmony_ci ld_tgt_id = MEGASAS_TARGET_ID(sdev); 21578c2ecf20Sopenharmony_ci instance->ld_tgtid_status[ld_tgt_id] = LD_TARGET_ID_DELETED; 21588c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & LD_PD_DEBUG) 21598c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, sdev, 21608c2ecf20Sopenharmony_ci "LD target ID %d removed from OS stack\n", ld_tgt_id); 21618c2ecf20Sopenharmony_ci } 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci kfree(sdev->hostdata); 21648c2ecf20Sopenharmony_ci sdev->hostdata = NULL; 21658c2ecf20Sopenharmony_ci} 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci/* 21688c2ecf20Sopenharmony_ci* megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a 21698c2ecf20Sopenharmony_ci* kill adapter 21708c2ecf20Sopenharmony_ci* @instance: Adapter soft state 21718c2ecf20Sopenharmony_ci* 21728c2ecf20Sopenharmony_ci*/ 21738c2ecf20Sopenharmony_cistatic void megasas_complete_outstanding_ioctls(struct megasas_instance *instance) 21748c2ecf20Sopenharmony_ci{ 21758c2ecf20Sopenharmony_ci int i; 21768c2ecf20Sopenharmony_ci struct megasas_cmd *cmd_mfi; 21778c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd_fusion; 21788c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci /* Find all outstanding ioctls */ 21818c2ecf20Sopenharmony_ci if (fusion) { 21828c2ecf20Sopenharmony_ci for (i = 0; i < instance->max_fw_cmds; i++) { 21838c2ecf20Sopenharmony_ci cmd_fusion = fusion->cmd_list[i]; 21848c2ecf20Sopenharmony_ci if (cmd_fusion->sync_cmd_idx != (u32)ULONG_MAX) { 21858c2ecf20Sopenharmony_ci cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx]; 21868c2ecf20Sopenharmony_ci if (cmd_mfi->sync_cmd && 21878c2ecf20Sopenharmony_ci (cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT)) { 21888c2ecf20Sopenharmony_ci cmd_mfi->frame->hdr.cmd_status = 21898c2ecf20Sopenharmony_ci MFI_STAT_WRONG_STATE; 21908c2ecf20Sopenharmony_ci megasas_complete_cmd(instance, 21918c2ecf20Sopenharmony_ci cmd_mfi, DID_OK); 21928c2ecf20Sopenharmony_ci } 21938c2ecf20Sopenharmony_ci } 21948c2ecf20Sopenharmony_ci } 21958c2ecf20Sopenharmony_ci } else { 21968c2ecf20Sopenharmony_ci for (i = 0; i < instance->max_fw_cmds; i++) { 21978c2ecf20Sopenharmony_ci cmd_mfi = instance->cmd_list[i]; 21988c2ecf20Sopenharmony_ci if (cmd_mfi->sync_cmd && cmd_mfi->frame->hdr.cmd != 21998c2ecf20Sopenharmony_ci MFI_CMD_ABORT) 22008c2ecf20Sopenharmony_ci megasas_complete_cmd(instance, cmd_mfi, DID_OK); 22018c2ecf20Sopenharmony_ci } 22028c2ecf20Sopenharmony_ci } 22038c2ecf20Sopenharmony_ci} 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_civoid megaraid_sas_kill_hba(struct megasas_instance *instance) 22078c2ecf20Sopenharmony_ci{ 22088c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) { 22098c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, 22108c2ecf20Sopenharmony_ci "Adapter already dead, skipping kill HBA\n"); 22118c2ecf20Sopenharmony_ci return; 22128c2ecf20Sopenharmony_ci } 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci /* Set critical error to block I/O & ioctls in case caller didn't */ 22158c2ecf20Sopenharmony_ci atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR); 22168c2ecf20Sopenharmony_ci /* Wait 1 second to ensure IO or ioctls in build have posted */ 22178c2ecf20Sopenharmony_ci msleep(1000); 22188c2ecf20Sopenharmony_ci if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || 22198c2ecf20Sopenharmony_ci (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || 22208c2ecf20Sopenharmony_ci (instance->adapter_type != MFI_SERIES)) { 22218c2ecf20Sopenharmony_ci if (!instance->requestorId) { 22228c2ecf20Sopenharmony_ci writel(MFI_STOP_ADP, &instance->reg_set->doorbell); 22238c2ecf20Sopenharmony_ci /* Flush */ 22248c2ecf20Sopenharmony_ci readl(&instance->reg_set->doorbell); 22258c2ecf20Sopenharmony_ci } 22268c2ecf20Sopenharmony_ci if (instance->requestorId && instance->peerIsPresent) 22278c2ecf20Sopenharmony_ci memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); 22288c2ecf20Sopenharmony_ci } else { 22298c2ecf20Sopenharmony_ci writel(MFI_STOP_ADP, 22308c2ecf20Sopenharmony_ci &instance->reg_set->inbound_doorbell); 22318c2ecf20Sopenharmony_ci } 22328c2ecf20Sopenharmony_ci /* Complete outstanding ioctls when adapter is killed */ 22338c2ecf20Sopenharmony_ci megasas_complete_outstanding_ioctls(instance); 22348c2ecf20Sopenharmony_ci} 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci /** 22378c2ecf20Sopenharmony_ci * megasas_check_and_restore_queue_depth - Check if queue depth needs to be 22388c2ecf20Sopenharmony_ci * restored to max value 22398c2ecf20Sopenharmony_ci * @instance: Adapter soft state 22408c2ecf20Sopenharmony_ci * 22418c2ecf20Sopenharmony_ci */ 22428c2ecf20Sopenharmony_civoid 22438c2ecf20Sopenharmony_cimegasas_check_and_restore_queue_depth(struct megasas_instance *instance) 22448c2ecf20Sopenharmony_ci{ 22458c2ecf20Sopenharmony_ci unsigned long flags; 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci if (instance->flag & MEGASAS_FW_BUSY 22488c2ecf20Sopenharmony_ci && time_after(jiffies, instance->last_time + 5 * HZ) 22498c2ecf20Sopenharmony_ci && atomic_read(&instance->fw_outstanding) < 22508c2ecf20Sopenharmony_ci instance->throttlequeuedepth + 1) { 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci spin_lock_irqsave(instance->host->host_lock, flags); 22538c2ecf20Sopenharmony_ci instance->flag &= ~MEGASAS_FW_BUSY; 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci instance->host->can_queue = instance->cur_can_queue; 22568c2ecf20Sopenharmony_ci spin_unlock_irqrestore(instance->host->host_lock, flags); 22578c2ecf20Sopenharmony_ci } 22588c2ecf20Sopenharmony_ci} 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci/** 22618c2ecf20Sopenharmony_ci * megasas_complete_cmd_dpc - Returns FW's controller structure 22628c2ecf20Sopenharmony_ci * @instance_addr: Address of adapter soft state 22638c2ecf20Sopenharmony_ci * 22648c2ecf20Sopenharmony_ci * Tasklet to complete cmds 22658c2ecf20Sopenharmony_ci */ 22668c2ecf20Sopenharmony_cistatic void megasas_complete_cmd_dpc(unsigned long instance_addr) 22678c2ecf20Sopenharmony_ci{ 22688c2ecf20Sopenharmony_ci u32 producer; 22698c2ecf20Sopenharmony_ci u32 consumer; 22708c2ecf20Sopenharmony_ci u32 context; 22718c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 22728c2ecf20Sopenharmony_ci struct megasas_instance *instance = 22738c2ecf20Sopenharmony_ci (struct megasas_instance *)instance_addr; 22748c2ecf20Sopenharmony_ci unsigned long flags; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci /* If we have already declared adapter dead, donot complete cmds */ 22778c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) 22788c2ecf20Sopenharmony_ci return; 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->completion_lock, flags); 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci producer = le32_to_cpu(*instance->producer); 22838c2ecf20Sopenharmony_ci consumer = le32_to_cpu(*instance->consumer); 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci while (consumer != producer) { 22868c2ecf20Sopenharmony_ci context = le32_to_cpu(instance->reply_queue[consumer]); 22878c2ecf20Sopenharmony_ci if (context >= instance->max_fw_cmds) { 22888c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Unexpected context value %x\n", 22898c2ecf20Sopenharmony_ci context); 22908c2ecf20Sopenharmony_ci BUG(); 22918c2ecf20Sopenharmony_ci } 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci cmd = instance->cmd_list[context]; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci megasas_complete_cmd(instance, cmd, DID_OK); 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci consumer++; 22988c2ecf20Sopenharmony_ci if (consumer == (instance->max_fw_cmds + 1)) { 22998c2ecf20Sopenharmony_ci consumer = 0; 23008c2ecf20Sopenharmony_ci } 23018c2ecf20Sopenharmony_ci } 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci *instance->consumer = cpu_to_le32(producer); 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->completion_lock, flags); 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci /* 23088c2ecf20Sopenharmony_ci * Check if we can restore can_queue 23098c2ecf20Sopenharmony_ci */ 23108c2ecf20Sopenharmony_ci megasas_check_and_restore_queue_depth(instance); 23118c2ecf20Sopenharmony_ci} 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_cistatic void megasas_sriov_heartbeat_handler(struct timer_list *t); 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci/** 23168c2ecf20Sopenharmony_ci * megasas_start_timer - Initializes sriov heartbeat timer object 23178c2ecf20Sopenharmony_ci * @instance: Adapter soft state 23188c2ecf20Sopenharmony_ci * 23198c2ecf20Sopenharmony_ci */ 23208c2ecf20Sopenharmony_civoid megasas_start_timer(struct megasas_instance *instance) 23218c2ecf20Sopenharmony_ci{ 23228c2ecf20Sopenharmony_ci struct timer_list *timer = &instance->sriov_heartbeat_timer; 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci timer_setup(timer, megasas_sriov_heartbeat_handler, 0); 23258c2ecf20Sopenharmony_ci timer->expires = jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF; 23268c2ecf20Sopenharmony_ci add_timer(timer); 23278c2ecf20Sopenharmony_ci} 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_cistatic void 23308c2ecf20Sopenharmony_cimegasas_internal_reset_defer_cmds(struct megasas_instance *instance); 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_cistatic void 23338c2ecf20Sopenharmony_ciprocess_fw_state_change_wq(struct work_struct *work); 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_cistatic void megasas_do_ocr(struct megasas_instance *instance) 23368c2ecf20Sopenharmony_ci{ 23378c2ecf20Sopenharmony_ci if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) || 23388c2ecf20Sopenharmony_ci (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) || 23398c2ecf20Sopenharmony_ci (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)) { 23408c2ecf20Sopenharmony_ci *instance->consumer = cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN); 23418c2ecf20Sopenharmony_ci } 23428c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 23438c2ecf20Sopenharmony_ci atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT); 23448c2ecf20Sopenharmony_ci instance->issuepend_done = 0; 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci atomic_set(&instance->fw_outstanding, 0); 23478c2ecf20Sopenharmony_ci megasas_internal_reset_defer_cmds(instance); 23488c2ecf20Sopenharmony_ci process_fw_state_change_wq(&instance->work_init); 23498c2ecf20Sopenharmony_ci} 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_cistatic int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance, 23528c2ecf20Sopenharmony_ci int initial) 23538c2ecf20Sopenharmony_ci{ 23548c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 23558c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 23568c2ecf20Sopenharmony_ci struct MR_LD_VF_AFFILIATION_111 *new_affiliation_111 = NULL; 23578c2ecf20Sopenharmony_ci dma_addr_t new_affiliation_111_h; 23588c2ecf20Sopenharmony_ci int ld, retval = 0; 23598c2ecf20Sopenharmony_ci u8 thisVf; 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci if (!cmd) { 23648c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_vf_affiliation_111:" 23658c2ecf20Sopenharmony_ci "Failed to get cmd for scsi%d\n", 23668c2ecf20Sopenharmony_ci instance->host->host_no); 23678c2ecf20Sopenharmony_ci return -ENOMEM; 23688c2ecf20Sopenharmony_ci } 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci if (!instance->vf_affiliation_111) { 23738c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV: Couldn't get LD/VF " 23748c2ecf20Sopenharmony_ci "affiliation for scsi%d\n", instance->host->host_no); 23758c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 23768c2ecf20Sopenharmony_ci return -ENOMEM; 23778c2ecf20Sopenharmony_ci } 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci if (initial) 23808c2ecf20Sopenharmony_ci memset(instance->vf_affiliation_111, 0, 23818c2ecf20Sopenharmony_ci sizeof(struct MR_LD_VF_AFFILIATION_111)); 23828c2ecf20Sopenharmony_ci else { 23838c2ecf20Sopenharmony_ci new_affiliation_111 = 23848c2ecf20Sopenharmony_ci dma_alloc_coherent(&instance->pdev->dev, 23858c2ecf20Sopenharmony_ci sizeof(struct MR_LD_VF_AFFILIATION_111), 23868c2ecf20Sopenharmony_ci &new_affiliation_111_h, GFP_KERNEL); 23878c2ecf20Sopenharmony_ci if (!new_affiliation_111) { 23888c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate " 23898c2ecf20Sopenharmony_ci "memory for new affiliation for scsi%d\n", 23908c2ecf20Sopenharmony_ci instance->host->host_no); 23918c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 23928c2ecf20Sopenharmony_ci return -ENOMEM; 23938c2ecf20Sopenharmony_ci } 23948c2ecf20Sopenharmony_ci } 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 23998c2ecf20Sopenharmony_ci dcmd->cmd_status = MFI_STAT_INVALID_STATUS; 24008c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 24018c2ecf20Sopenharmony_ci dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_BOTH); 24028c2ecf20Sopenharmony_ci dcmd->timeout = 0; 24038c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 24048c2ecf20Sopenharmony_ci dcmd->data_xfer_len = 24058c2ecf20Sopenharmony_ci cpu_to_le32(sizeof(struct MR_LD_VF_AFFILIATION_111)); 24068c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111); 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci if (initial) 24098c2ecf20Sopenharmony_ci dcmd->sgl.sge32[0].phys_addr = 24108c2ecf20Sopenharmony_ci cpu_to_le32(instance->vf_affiliation_111_h); 24118c2ecf20Sopenharmony_ci else 24128c2ecf20Sopenharmony_ci dcmd->sgl.sge32[0].phys_addr = 24138c2ecf20Sopenharmony_ci cpu_to_le32(new_affiliation_111_h); 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci dcmd->sgl.sge32[0].length = cpu_to_le32( 24168c2ecf20Sopenharmony_ci sizeof(struct MR_LD_VF_AFFILIATION_111)); 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for " 24198c2ecf20Sopenharmony_ci "scsi%d\n", instance->host->host_no); 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) { 24228c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD" 24238c2ecf20Sopenharmony_ci " failed with status 0x%x for scsi%d\n", 24248c2ecf20Sopenharmony_ci dcmd->cmd_status, instance->host->host_no); 24258c2ecf20Sopenharmony_ci retval = 1; /* Do a scan if we couldn't get affiliation */ 24268c2ecf20Sopenharmony_ci goto out; 24278c2ecf20Sopenharmony_ci } 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci if (!initial) { 24308c2ecf20Sopenharmony_ci thisVf = new_affiliation_111->thisVf; 24318c2ecf20Sopenharmony_ci for (ld = 0 ; ld < new_affiliation_111->vdCount; ld++) 24328c2ecf20Sopenharmony_ci if (instance->vf_affiliation_111->map[ld].policy[thisVf] != 24338c2ecf20Sopenharmony_ci new_affiliation_111->map[ld].policy[thisVf]) { 24348c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV: " 24358c2ecf20Sopenharmony_ci "Got new LD/VF affiliation for scsi%d\n", 24368c2ecf20Sopenharmony_ci instance->host->host_no); 24378c2ecf20Sopenharmony_ci memcpy(instance->vf_affiliation_111, 24388c2ecf20Sopenharmony_ci new_affiliation_111, 24398c2ecf20Sopenharmony_ci sizeof(struct MR_LD_VF_AFFILIATION_111)); 24408c2ecf20Sopenharmony_ci retval = 1; 24418c2ecf20Sopenharmony_ci goto out; 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci } 24448c2ecf20Sopenharmony_ciout: 24458c2ecf20Sopenharmony_ci if (new_affiliation_111) { 24468c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, 24478c2ecf20Sopenharmony_ci sizeof(struct MR_LD_VF_AFFILIATION_111), 24488c2ecf20Sopenharmony_ci new_affiliation_111, 24498c2ecf20Sopenharmony_ci new_affiliation_111_h); 24508c2ecf20Sopenharmony_ci } 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci return retval; 24558c2ecf20Sopenharmony_ci} 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_cistatic int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance, 24588c2ecf20Sopenharmony_ci int initial) 24598c2ecf20Sopenharmony_ci{ 24608c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 24618c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 24628c2ecf20Sopenharmony_ci struct MR_LD_VF_AFFILIATION *new_affiliation = NULL; 24638c2ecf20Sopenharmony_ci struct MR_LD_VF_MAP *newmap = NULL, *savedmap = NULL; 24648c2ecf20Sopenharmony_ci dma_addr_t new_affiliation_h; 24658c2ecf20Sopenharmony_ci int i, j, retval = 0, found = 0, doscan = 0; 24668c2ecf20Sopenharmony_ci u8 thisVf; 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci if (!cmd) { 24718c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_vf_affiliation12: " 24728c2ecf20Sopenharmony_ci "Failed to get cmd for scsi%d\n", 24738c2ecf20Sopenharmony_ci instance->host->host_no); 24748c2ecf20Sopenharmony_ci return -ENOMEM; 24758c2ecf20Sopenharmony_ci } 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci if (!instance->vf_affiliation) { 24808c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV: Couldn't get LD/VF " 24818c2ecf20Sopenharmony_ci "affiliation for scsi%d\n", instance->host->host_no); 24828c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 24838c2ecf20Sopenharmony_ci return -ENOMEM; 24848c2ecf20Sopenharmony_ci } 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci if (initial) 24878c2ecf20Sopenharmony_ci memset(instance->vf_affiliation, 0, (MAX_LOGICAL_DRIVES + 1) * 24888c2ecf20Sopenharmony_ci sizeof(struct MR_LD_VF_AFFILIATION)); 24898c2ecf20Sopenharmony_ci else { 24908c2ecf20Sopenharmony_ci new_affiliation = 24918c2ecf20Sopenharmony_ci dma_alloc_coherent(&instance->pdev->dev, 24928c2ecf20Sopenharmony_ci (MAX_LOGICAL_DRIVES + 1) * sizeof(struct MR_LD_VF_AFFILIATION), 24938c2ecf20Sopenharmony_ci &new_affiliation_h, GFP_KERNEL); 24948c2ecf20Sopenharmony_ci if (!new_affiliation) { 24958c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate " 24968c2ecf20Sopenharmony_ci "memory for new affiliation for scsi%d\n", 24978c2ecf20Sopenharmony_ci instance->host->host_no); 24988c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 24998c2ecf20Sopenharmony_ci return -ENOMEM; 25008c2ecf20Sopenharmony_ci } 25018c2ecf20Sopenharmony_ci } 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 25068c2ecf20Sopenharmony_ci dcmd->cmd_status = MFI_STAT_INVALID_STATUS; 25078c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 25088c2ecf20Sopenharmony_ci dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_BOTH); 25098c2ecf20Sopenharmony_ci dcmd->timeout = 0; 25108c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 25118c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32((MAX_LOGICAL_DRIVES + 1) * 25128c2ecf20Sopenharmony_ci sizeof(struct MR_LD_VF_AFFILIATION)); 25138c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_LD_VF_MAP_GET_ALL_LDS); 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci if (initial) 25168c2ecf20Sopenharmony_ci dcmd->sgl.sge32[0].phys_addr = 25178c2ecf20Sopenharmony_ci cpu_to_le32(instance->vf_affiliation_h); 25188c2ecf20Sopenharmony_ci else 25198c2ecf20Sopenharmony_ci dcmd->sgl.sge32[0].phys_addr = 25208c2ecf20Sopenharmony_ci cpu_to_le32(new_affiliation_h); 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci dcmd->sgl.sge32[0].length = cpu_to_le32((MAX_LOGICAL_DRIVES + 1) * 25238c2ecf20Sopenharmony_ci sizeof(struct MR_LD_VF_AFFILIATION)); 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for " 25268c2ecf20Sopenharmony_ci "scsi%d\n", instance->host->host_no); 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) { 25308c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD" 25318c2ecf20Sopenharmony_ci " failed with status 0x%x for scsi%d\n", 25328c2ecf20Sopenharmony_ci dcmd->cmd_status, instance->host->host_no); 25338c2ecf20Sopenharmony_ci retval = 1; /* Do a scan if we couldn't get affiliation */ 25348c2ecf20Sopenharmony_ci goto out; 25358c2ecf20Sopenharmony_ci } 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci if (!initial) { 25388c2ecf20Sopenharmony_ci if (!new_affiliation->ldCount) { 25398c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV: Got new LD/VF " 25408c2ecf20Sopenharmony_ci "affiliation for passive path for scsi%d\n", 25418c2ecf20Sopenharmony_ci instance->host->host_no); 25428c2ecf20Sopenharmony_ci retval = 1; 25438c2ecf20Sopenharmony_ci goto out; 25448c2ecf20Sopenharmony_ci } 25458c2ecf20Sopenharmony_ci newmap = new_affiliation->map; 25468c2ecf20Sopenharmony_ci savedmap = instance->vf_affiliation->map; 25478c2ecf20Sopenharmony_ci thisVf = new_affiliation->thisVf; 25488c2ecf20Sopenharmony_ci for (i = 0 ; i < new_affiliation->ldCount; i++) { 25498c2ecf20Sopenharmony_ci found = 0; 25508c2ecf20Sopenharmony_ci for (j = 0; j < instance->vf_affiliation->ldCount; 25518c2ecf20Sopenharmony_ci j++) { 25528c2ecf20Sopenharmony_ci if (newmap->ref.targetId == 25538c2ecf20Sopenharmony_ci savedmap->ref.targetId) { 25548c2ecf20Sopenharmony_ci found = 1; 25558c2ecf20Sopenharmony_ci if (newmap->policy[thisVf] != 25568c2ecf20Sopenharmony_ci savedmap->policy[thisVf]) { 25578c2ecf20Sopenharmony_ci doscan = 1; 25588c2ecf20Sopenharmony_ci goto out; 25598c2ecf20Sopenharmony_ci } 25608c2ecf20Sopenharmony_ci } 25618c2ecf20Sopenharmony_ci savedmap = (struct MR_LD_VF_MAP *) 25628c2ecf20Sopenharmony_ci ((unsigned char *)savedmap + 25638c2ecf20Sopenharmony_ci savedmap->size); 25648c2ecf20Sopenharmony_ci } 25658c2ecf20Sopenharmony_ci if (!found && newmap->policy[thisVf] != 25668c2ecf20Sopenharmony_ci MR_LD_ACCESS_HIDDEN) { 25678c2ecf20Sopenharmony_ci doscan = 1; 25688c2ecf20Sopenharmony_ci goto out; 25698c2ecf20Sopenharmony_ci } 25708c2ecf20Sopenharmony_ci newmap = (struct MR_LD_VF_MAP *) 25718c2ecf20Sopenharmony_ci ((unsigned char *)newmap + newmap->size); 25728c2ecf20Sopenharmony_ci } 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci newmap = new_affiliation->map; 25758c2ecf20Sopenharmony_ci savedmap = instance->vf_affiliation->map; 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci for (i = 0 ; i < instance->vf_affiliation->ldCount; i++) { 25788c2ecf20Sopenharmony_ci found = 0; 25798c2ecf20Sopenharmony_ci for (j = 0 ; j < new_affiliation->ldCount; j++) { 25808c2ecf20Sopenharmony_ci if (savedmap->ref.targetId == 25818c2ecf20Sopenharmony_ci newmap->ref.targetId) { 25828c2ecf20Sopenharmony_ci found = 1; 25838c2ecf20Sopenharmony_ci if (savedmap->policy[thisVf] != 25848c2ecf20Sopenharmony_ci newmap->policy[thisVf]) { 25858c2ecf20Sopenharmony_ci doscan = 1; 25868c2ecf20Sopenharmony_ci goto out; 25878c2ecf20Sopenharmony_ci } 25888c2ecf20Sopenharmony_ci } 25898c2ecf20Sopenharmony_ci newmap = (struct MR_LD_VF_MAP *) 25908c2ecf20Sopenharmony_ci ((unsigned char *)newmap + 25918c2ecf20Sopenharmony_ci newmap->size); 25928c2ecf20Sopenharmony_ci } 25938c2ecf20Sopenharmony_ci if (!found && savedmap->policy[thisVf] != 25948c2ecf20Sopenharmony_ci MR_LD_ACCESS_HIDDEN) { 25958c2ecf20Sopenharmony_ci doscan = 1; 25968c2ecf20Sopenharmony_ci goto out; 25978c2ecf20Sopenharmony_ci } 25988c2ecf20Sopenharmony_ci savedmap = (struct MR_LD_VF_MAP *) 25998c2ecf20Sopenharmony_ci ((unsigned char *)savedmap + 26008c2ecf20Sopenharmony_ci savedmap->size); 26018c2ecf20Sopenharmony_ci } 26028c2ecf20Sopenharmony_ci } 26038c2ecf20Sopenharmony_ciout: 26048c2ecf20Sopenharmony_ci if (doscan) { 26058c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV: Got new LD/VF " 26068c2ecf20Sopenharmony_ci "affiliation for scsi%d\n", instance->host->host_no); 26078c2ecf20Sopenharmony_ci memcpy(instance->vf_affiliation, new_affiliation, 26088c2ecf20Sopenharmony_ci new_affiliation->size); 26098c2ecf20Sopenharmony_ci retval = 1; 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci if (new_affiliation) 26138c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, 26148c2ecf20Sopenharmony_ci (MAX_LOGICAL_DRIVES + 1) * 26158c2ecf20Sopenharmony_ci sizeof(struct MR_LD_VF_AFFILIATION), 26168c2ecf20Sopenharmony_ci new_affiliation, new_affiliation_h); 26178c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci return retval; 26208c2ecf20Sopenharmony_ci} 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci/* This function will get the current SR-IOV LD/VF affiliation */ 26238c2ecf20Sopenharmony_cistatic int megasas_get_ld_vf_affiliation(struct megasas_instance *instance, 26248c2ecf20Sopenharmony_ci int initial) 26258c2ecf20Sopenharmony_ci{ 26268c2ecf20Sopenharmony_ci int retval; 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci if (instance->PlasmaFW111) 26298c2ecf20Sopenharmony_ci retval = megasas_get_ld_vf_affiliation_111(instance, initial); 26308c2ecf20Sopenharmony_ci else 26318c2ecf20Sopenharmony_ci retval = megasas_get_ld_vf_affiliation_12(instance, initial); 26328c2ecf20Sopenharmony_ci return retval; 26338c2ecf20Sopenharmony_ci} 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci/* This function will tell FW to start the SR-IOV heartbeat */ 26368c2ecf20Sopenharmony_ciint megasas_sriov_start_heartbeat(struct megasas_instance *instance, 26378c2ecf20Sopenharmony_ci int initial) 26388c2ecf20Sopenharmony_ci{ 26398c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 26408c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 26418c2ecf20Sopenharmony_ci int retval = 0; 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci if (!cmd) { 26468c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_sriov_start_heartbeat: " 26478c2ecf20Sopenharmony_ci "Failed to get cmd for scsi%d\n", 26488c2ecf20Sopenharmony_ci instance->host->host_no); 26498c2ecf20Sopenharmony_ci return -ENOMEM; 26508c2ecf20Sopenharmony_ci } 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci if (initial) { 26558c2ecf20Sopenharmony_ci instance->hb_host_mem = 26568c2ecf20Sopenharmony_ci dma_alloc_coherent(&instance->pdev->dev, 26578c2ecf20Sopenharmony_ci sizeof(struct MR_CTRL_HB_HOST_MEM), 26588c2ecf20Sopenharmony_ci &instance->hb_host_mem_h, 26598c2ecf20Sopenharmony_ci GFP_KERNEL); 26608c2ecf20Sopenharmony_ci if (!instance->hb_host_mem) { 26618c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate" 26628c2ecf20Sopenharmony_ci " memory for heartbeat host memory for scsi%d\n", 26638c2ecf20Sopenharmony_ci instance->host->host_no); 26648c2ecf20Sopenharmony_ci retval = -ENOMEM; 26658c2ecf20Sopenharmony_ci goto out; 26668c2ecf20Sopenharmony_ci } 26678c2ecf20Sopenharmony_ci } 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci dcmd->mbox.s[0] = cpu_to_le16(sizeof(struct MR_CTRL_HB_HOST_MEM)); 26728c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 26738c2ecf20Sopenharmony_ci dcmd->cmd_status = MFI_STAT_INVALID_STATUS; 26748c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 26758c2ecf20Sopenharmony_ci dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_BOTH); 26768c2ecf20Sopenharmony_ci dcmd->timeout = 0; 26778c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 26788c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_CTRL_HB_HOST_MEM)); 26798c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC); 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, instance->hb_host_mem_h, 26828c2ecf20Sopenharmony_ci sizeof(struct MR_CTRL_HB_HOST_MEM)); 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV: Starting heartbeat for scsi%d\n", 26858c2ecf20Sopenharmony_ci instance->host->host_no); 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci if ((instance->adapter_type != MFI_SERIES) && 26888c2ecf20Sopenharmony_ci !instance->mask_interrupts) 26898c2ecf20Sopenharmony_ci retval = megasas_issue_blocked_cmd(instance, cmd, 26908c2ecf20Sopenharmony_ci MEGASAS_ROUTINE_WAIT_TIME_VF); 26918c2ecf20Sopenharmony_ci else 26928c2ecf20Sopenharmony_ci retval = megasas_issue_polled(instance, cmd); 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci if (retval) { 26958c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV: MR_DCMD_CTRL_SHARED_HOST" 26968c2ecf20Sopenharmony_ci "_MEM_ALLOC DCMD %s for scsi%d\n", 26978c2ecf20Sopenharmony_ci (dcmd->cmd_status == MFI_STAT_INVALID_STATUS) ? 26988c2ecf20Sopenharmony_ci "timed out" : "failed", instance->host->host_no); 26998c2ecf20Sopenharmony_ci retval = 1; 27008c2ecf20Sopenharmony_ci } 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ciout: 27038c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci return retval; 27068c2ecf20Sopenharmony_ci} 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci/* Handler for SR-IOV heartbeat */ 27098c2ecf20Sopenharmony_cistatic void megasas_sriov_heartbeat_handler(struct timer_list *t) 27108c2ecf20Sopenharmony_ci{ 27118c2ecf20Sopenharmony_ci struct megasas_instance *instance = 27128c2ecf20Sopenharmony_ci from_timer(instance, t, sriov_heartbeat_timer); 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci if (instance->hb_host_mem->HB.fwCounter != 27158c2ecf20Sopenharmony_ci instance->hb_host_mem->HB.driverCounter) { 27168c2ecf20Sopenharmony_ci instance->hb_host_mem->HB.driverCounter = 27178c2ecf20Sopenharmony_ci instance->hb_host_mem->HB.fwCounter; 27188c2ecf20Sopenharmony_ci mod_timer(&instance->sriov_heartbeat_timer, 27198c2ecf20Sopenharmony_ci jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF); 27208c2ecf20Sopenharmony_ci } else { 27218c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV: Heartbeat never " 27228c2ecf20Sopenharmony_ci "completed for scsi%d\n", instance->host->host_no); 27238c2ecf20Sopenharmony_ci schedule_work(&instance->work_init); 27248c2ecf20Sopenharmony_ci } 27258c2ecf20Sopenharmony_ci} 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci/** 27288c2ecf20Sopenharmony_ci * megasas_wait_for_outstanding - Wait for all outstanding cmds 27298c2ecf20Sopenharmony_ci * @instance: Adapter soft state 27308c2ecf20Sopenharmony_ci * 27318c2ecf20Sopenharmony_ci * This function waits for up to MEGASAS_RESET_WAIT_TIME seconds for FW to 27328c2ecf20Sopenharmony_ci * complete all its outstanding commands. Returns error if one or more IOs 27338c2ecf20Sopenharmony_ci * are pending after this time period. It also marks the controller dead. 27348c2ecf20Sopenharmony_ci */ 27358c2ecf20Sopenharmony_cistatic int megasas_wait_for_outstanding(struct megasas_instance *instance) 27368c2ecf20Sopenharmony_ci{ 27378c2ecf20Sopenharmony_ci int i, sl, outstanding; 27388c2ecf20Sopenharmony_ci u32 reset_index; 27398c2ecf20Sopenharmony_ci u32 wait_time = MEGASAS_RESET_WAIT_TIME; 27408c2ecf20Sopenharmony_ci unsigned long flags; 27418c2ecf20Sopenharmony_ci struct list_head clist_local; 27428c2ecf20Sopenharmony_ci struct megasas_cmd *reset_cmd; 27438c2ecf20Sopenharmony_ci u32 fw_state; 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) { 27468c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "%s:%d HBA is killed.\n", 27478c2ecf20Sopenharmony_ci __func__, __LINE__); 27488c2ecf20Sopenharmony_ci return FAILED; 27498c2ecf20Sopenharmony_ci } 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) { 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&clist_local); 27548c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->hba_lock, flags); 27558c2ecf20Sopenharmony_ci list_splice_init(&instance->internal_reset_pending_q, 27568c2ecf20Sopenharmony_ci &clist_local); 27578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->hba_lock, flags); 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "HBA reset wait ...\n"); 27608c2ecf20Sopenharmony_ci for (i = 0; i < wait_time; i++) { 27618c2ecf20Sopenharmony_ci msleep(1000); 27628c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) 27638c2ecf20Sopenharmony_ci break; 27648c2ecf20Sopenharmony_ci } 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) { 27678c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "reset: Stopping HBA.\n"); 27688c2ecf20Sopenharmony_ci atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR); 27698c2ecf20Sopenharmony_ci return FAILED; 27708c2ecf20Sopenharmony_ci } 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci reset_index = 0; 27738c2ecf20Sopenharmony_ci while (!list_empty(&clist_local)) { 27748c2ecf20Sopenharmony_ci reset_cmd = list_entry((&clist_local)->next, 27758c2ecf20Sopenharmony_ci struct megasas_cmd, list); 27768c2ecf20Sopenharmony_ci list_del_init(&reset_cmd->list); 27778c2ecf20Sopenharmony_ci if (reset_cmd->scmd) { 27788c2ecf20Sopenharmony_ci reset_cmd->scmd->result = DID_REQUEUE << 16; 27798c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "%d:%p reset [%02x]\n", 27808c2ecf20Sopenharmony_ci reset_index, reset_cmd, 27818c2ecf20Sopenharmony_ci reset_cmd->scmd->cmnd[0]); 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci reset_cmd->scmd->scsi_done(reset_cmd->scmd); 27848c2ecf20Sopenharmony_ci megasas_return_cmd(instance, reset_cmd); 27858c2ecf20Sopenharmony_ci } else if (reset_cmd->sync_cmd) { 27868c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "%p synch cmds" 27878c2ecf20Sopenharmony_ci "reset queue\n", 27888c2ecf20Sopenharmony_ci reset_cmd); 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci reset_cmd->cmd_status_drv = DCMD_INIT; 27918c2ecf20Sopenharmony_ci instance->instancet->fire_cmd(instance, 27928c2ecf20Sopenharmony_ci reset_cmd->frame_phys_addr, 27938c2ecf20Sopenharmony_ci 0, instance->reg_set); 27948c2ecf20Sopenharmony_ci } else { 27958c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "%p unexpected" 27968c2ecf20Sopenharmony_ci "cmds lst\n", 27978c2ecf20Sopenharmony_ci reset_cmd); 27988c2ecf20Sopenharmony_ci } 27998c2ecf20Sopenharmony_ci reset_index++; 28008c2ecf20Sopenharmony_ci } 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci return SUCCESS; 28038c2ecf20Sopenharmony_ci } 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci for (i = 0; i < resetwaittime; i++) { 28068c2ecf20Sopenharmony_ci outstanding = atomic_read(&instance->fw_outstanding); 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_ci if (!outstanding) 28098c2ecf20Sopenharmony_ci break; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { 28128c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "[%2d]waiting for %d " 28138c2ecf20Sopenharmony_ci "commands to complete\n",i,outstanding); 28148c2ecf20Sopenharmony_ci /* 28158c2ecf20Sopenharmony_ci * Call cmd completion routine. Cmd to be 28168c2ecf20Sopenharmony_ci * be completed directly without depending on isr. 28178c2ecf20Sopenharmony_ci */ 28188c2ecf20Sopenharmony_ci megasas_complete_cmd_dpc((unsigned long)instance); 28198c2ecf20Sopenharmony_ci } 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci msleep(1000); 28228c2ecf20Sopenharmony_ci } 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_ci i = 0; 28258c2ecf20Sopenharmony_ci outstanding = atomic_read(&instance->fw_outstanding); 28268c2ecf20Sopenharmony_ci fw_state = instance->instancet->read_fw_status_reg(instance) & MFI_STATE_MASK; 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL))) 28298c2ecf20Sopenharmony_ci goto no_outstanding; 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci if (instance->disableOnlineCtrlReset) 28328c2ecf20Sopenharmony_ci goto kill_hba_and_failed; 28338c2ecf20Sopenharmony_ci do { 28348c2ecf20Sopenharmony_ci if ((fw_state == MFI_STATE_FAULT) || atomic_read(&instance->fw_outstanding)) { 28358c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 28368c2ecf20Sopenharmony_ci "%s:%d waiting_for_outstanding: before issue OCR. FW state = 0x%x, outstanding 0x%x\n", 28378c2ecf20Sopenharmony_ci __func__, __LINE__, fw_state, atomic_read(&instance->fw_outstanding)); 28388c2ecf20Sopenharmony_ci if (i == 3) 28398c2ecf20Sopenharmony_ci goto kill_hba_and_failed; 28408c2ecf20Sopenharmony_ci megasas_do_ocr(instance); 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) { 28438c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "%s:%d OCR failed and HBA is killed.\n", 28448c2ecf20Sopenharmony_ci __func__, __LINE__); 28458c2ecf20Sopenharmony_ci return FAILED; 28468c2ecf20Sopenharmony_ci } 28478c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "%s:%d waiting_for_outstanding: after issue OCR.\n", 28488c2ecf20Sopenharmony_ci __func__, __LINE__); 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci for (sl = 0; sl < 10; sl++) 28518c2ecf20Sopenharmony_ci msleep(500); 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci outstanding = atomic_read(&instance->fw_outstanding); 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci fw_state = instance->instancet->read_fw_status_reg(instance) & MFI_STATE_MASK; 28568c2ecf20Sopenharmony_ci if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL))) 28578c2ecf20Sopenharmony_ci goto no_outstanding; 28588c2ecf20Sopenharmony_ci } 28598c2ecf20Sopenharmony_ci i++; 28608c2ecf20Sopenharmony_ci } while (i <= 3); 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_cino_outstanding: 28638c2ecf20Sopenharmony_ci 28648c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "%s:%d no more pending commands remain after reset handling.\n", 28658c2ecf20Sopenharmony_ci __func__, __LINE__); 28668c2ecf20Sopenharmony_ci return SUCCESS; 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_cikill_hba_and_failed: 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci /* Reset not supported, kill adapter */ 28718c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "%s:%d killing adapter scsi%d" 28728c2ecf20Sopenharmony_ci " disableOnlineCtrlReset %d fw_outstanding %d \n", 28738c2ecf20Sopenharmony_ci __func__, __LINE__, instance->host->host_no, instance->disableOnlineCtrlReset, 28748c2ecf20Sopenharmony_ci atomic_read(&instance->fw_outstanding)); 28758c2ecf20Sopenharmony_ci megasas_dump_pending_frames(instance); 28768c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci return FAILED; 28798c2ecf20Sopenharmony_ci} 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci/** 28828c2ecf20Sopenharmony_ci * megasas_generic_reset - Generic reset routine 28838c2ecf20Sopenharmony_ci * @scmd: Mid-layer SCSI command 28848c2ecf20Sopenharmony_ci * 28858c2ecf20Sopenharmony_ci * This routine implements a generic reset handler for device, bus and host 28868c2ecf20Sopenharmony_ci * reset requests. Device, bus and host specific reset handlers can use this 28878c2ecf20Sopenharmony_ci * function after they do their specific tasks. 28888c2ecf20Sopenharmony_ci */ 28898c2ecf20Sopenharmony_cistatic int megasas_generic_reset(struct scsi_cmnd *scmd) 28908c2ecf20Sopenharmony_ci{ 28918c2ecf20Sopenharmony_ci int ret_val; 28928c2ecf20Sopenharmony_ci struct megasas_instance *instance; 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)scmd->device->host->hostdata; 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_ci scmd_printk(KERN_NOTICE, scmd, "megasas: RESET cmd=%x retries=%x\n", 28978c2ecf20Sopenharmony_ci scmd->cmnd[0], scmd->retries); 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) { 29008c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "cannot recover from previous reset failures\n"); 29018c2ecf20Sopenharmony_ci return FAILED; 29028c2ecf20Sopenharmony_ci } 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_ci ret_val = megasas_wait_for_outstanding(instance); 29058c2ecf20Sopenharmony_ci if (ret_val == SUCCESS) 29068c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "reset successful\n"); 29078c2ecf20Sopenharmony_ci else 29088c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "failed to do reset\n"); 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci return ret_val; 29118c2ecf20Sopenharmony_ci} 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci/** 29148c2ecf20Sopenharmony_ci * megasas_reset_timer - quiesce the adapter if required 29158c2ecf20Sopenharmony_ci * @scmd: scsi cmnd 29168c2ecf20Sopenharmony_ci * 29178c2ecf20Sopenharmony_ci * Sets the FW busy flag and reduces the host->can_queue if the 29188c2ecf20Sopenharmony_ci * cmd has not been completed within the timeout period. 29198c2ecf20Sopenharmony_ci */ 29208c2ecf20Sopenharmony_cistatic enum 29218c2ecf20Sopenharmony_ciblk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) 29228c2ecf20Sopenharmony_ci{ 29238c2ecf20Sopenharmony_ci struct megasas_instance *instance; 29248c2ecf20Sopenharmony_ci unsigned long flags; 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci if (time_after(jiffies, scmd->jiffies_at_alloc + 29278c2ecf20Sopenharmony_ci (scmd_timeout * 2) * HZ)) { 29288c2ecf20Sopenharmony_ci return BLK_EH_DONE; 29298c2ecf20Sopenharmony_ci } 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)scmd->device->host->hostdata; 29328c2ecf20Sopenharmony_ci if (!(instance->flag & MEGASAS_FW_BUSY)) { 29338c2ecf20Sopenharmony_ci /* FW is busy, throttle IO */ 29348c2ecf20Sopenharmony_ci spin_lock_irqsave(instance->host->host_lock, flags); 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci instance->host->can_queue = instance->throttlequeuedepth; 29378c2ecf20Sopenharmony_ci instance->last_time = jiffies; 29388c2ecf20Sopenharmony_ci instance->flag |= MEGASAS_FW_BUSY; 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(instance->host->host_lock, flags); 29418c2ecf20Sopenharmony_ci } 29428c2ecf20Sopenharmony_ci return BLK_EH_RESET_TIMER; 29438c2ecf20Sopenharmony_ci} 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci/** 29468c2ecf20Sopenharmony_ci * megasas_dump - This function will print hexdump of provided buffer. 29478c2ecf20Sopenharmony_ci * @buf: Buffer to be dumped 29488c2ecf20Sopenharmony_ci * @sz: Size in bytes 29498c2ecf20Sopenharmony_ci * @format: Different formats of dumping e.g. format=n will 29508c2ecf20Sopenharmony_ci * cause only 'n' 32 bit words to be dumped in a single 29518c2ecf20Sopenharmony_ci * line. 29528c2ecf20Sopenharmony_ci */ 29538c2ecf20Sopenharmony_ciinline void 29548c2ecf20Sopenharmony_cimegasas_dump(void *buf, int sz, int format) 29558c2ecf20Sopenharmony_ci{ 29568c2ecf20Sopenharmony_ci int i; 29578c2ecf20Sopenharmony_ci __le32 *buf_loc = (__le32 *)buf; 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_ci for (i = 0; i < (sz / sizeof(__le32)); i++) { 29608c2ecf20Sopenharmony_ci if ((i % format) == 0) { 29618c2ecf20Sopenharmony_ci if (i != 0) 29628c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 29638c2ecf20Sopenharmony_ci printk(KERN_CONT "%08x: ", (i * 4)); 29648c2ecf20Sopenharmony_ci } 29658c2ecf20Sopenharmony_ci printk(KERN_CONT "%08x ", le32_to_cpu(buf_loc[i])); 29668c2ecf20Sopenharmony_ci } 29678c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 29688c2ecf20Sopenharmony_ci} 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci/** 29718c2ecf20Sopenharmony_ci * megasas_dump_reg_set - This function will print hexdump of register set 29728c2ecf20Sopenharmony_ci * @reg_set: Register set to be dumped 29738c2ecf20Sopenharmony_ci */ 29748c2ecf20Sopenharmony_ciinline void 29758c2ecf20Sopenharmony_cimegasas_dump_reg_set(void __iomem *reg_set) 29768c2ecf20Sopenharmony_ci{ 29778c2ecf20Sopenharmony_ci unsigned int i, sz = 256; 29788c2ecf20Sopenharmony_ci u32 __iomem *reg = (u32 __iomem *)reg_set; 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci for (i = 0; i < (sz / sizeof(u32)); i++) 29818c2ecf20Sopenharmony_ci printk("%08x: %08x\n", (i * 4), readl(®[i])); 29828c2ecf20Sopenharmony_ci} 29838c2ecf20Sopenharmony_ci 29848c2ecf20Sopenharmony_ci/** 29858c2ecf20Sopenharmony_ci * megasas_dump_fusion_io - This function will print key details 29868c2ecf20Sopenharmony_ci * of SCSI IO 29878c2ecf20Sopenharmony_ci * @scmd: SCSI command pointer of SCSI IO 29888c2ecf20Sopenharmony_ci */ 29898c2ecf20Sopenharmony_civoid 29908c2ecf20Sopenharmony_cimegasas_dump_fusion_io(struct scsi_cmnd *scmd) 29918c2ecf20Sopenharmony_ci{ 29928c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd; 29938c2ecf20Sopenharmony_ci union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; 29948c2ecf20Sopenharmony_ci struct megasas_instance *instance; 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci cmd = (struct megasas_cmd_fusion *)scmd->SCp.ptr; 29978c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)scmd->device->host->hostdata; 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, scmd, 30008c2ecf20Sopenharmony_ci "scmd: (0x%p) retries: 0x%x allowed: 0x%x\n", 30018c2ecf20Sopenharmony_ci scmd, scmd->retries, scmd->allowed); 30028c2ecf20Sopenharmony_ci scsi_print_command(scmd); 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci if (cmd) { 30058c2ecf20Sopenharmony_ci req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc; 30068c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, scmd, "Request descriptor details:\n"); 30078c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, scmd, 30088c2ecf20Sopenharmony_ci "RequestFlags:0x%x MSIxIndex:0x%x SMID:0x%x LMID:0x%x DevHandle:0x%x\n", 30098c2ecf20Sopenharmony_ci req_desc->SCSIIO.RequestFlags, 30108c2ecf20Sopenharmony_ci req_desc->SCSIIO.MSIxIndex, req_desc->SCSIIO.SMID, 30118c2ecf20Sopenharmony_ci req_desc->SCSIIO.LMID, req_desc->SCSIIO.DevHandle); 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci printk(KERN_INFO "IO request frame:\n"); 30148c2ecf20Sopenharmony_ci megasas_dump(cmd->io_request, 30158c2ecf20Sopenharmony_ci MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE, 8); 30168c2ecf20Sopenharmony_ci printk(KERN_INFO "Chain frame:\n"); 30178c2ecf20Sopenharmony_ci megasas_dump(cmd->sg_frame, 30188c2ecf20Sopenharmony_ci instance->max_chain_frame_sz, 8); 30198c2ecf20Sopenharmony_ci } 30208c2ecf20Sopenharmony_ci 30218c2ecf20Sopenharmony_ci} 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci/* 30248c2ecf20Sopenharmony_ci * megasas_dump_sys_regs - This function will dump system registers through 30258c2ecf20Sopenharmony_ci * sysfs. 30268c2ecf20Sopenharmony_ci * @reg_set: Pointer to System register set. 30278c2ecf20Sopenharmony_ci * @buf: Buffer to which output is to be written. 30288c2ecf20Sopenharmony_ci * @return: Number of bytes written to buffer. 30298c2ecf20Sopenharmony_ci */ 30308c2ecf20Sopenharmony_cistatic inline ssize_t 30318c2ecf20Sopenharmony_cimegasas_dump_sys_regs(void __iomem *reg_set, char *buf) 30328c2ecf20Sopenharmony_ci{ 30338c2ecf20Sopenharmony_ci unsigned int i, sz = 256; 30348c2ecf20Sopenharmony_ci int bytes_wrote = 0; 30358c2ecf20Sopenharmony_ci char *loc = (char *)buf; 30368c2ecf20Sopenharmony_ci u32 __iomem *reg = (u32 __iomem *)reg_set; 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci for (i = 0; i < sz / sizeof(u32); i++) { 30398c2ecf20Sopenharmony_ci bytes_wrote += scnprintf(loc + bytes_wrote, 30408c2ecf20Sopenharmony_ci PAGE_SIZE - bytes_wrote, 30418c2ecf20Sopenharmony_ci "%08x: %08x\n", (i * 4), 30428c2ecf20Sopenharmony_ci readl(®[i])); 30438c2ecf20Sopenharmony_ci } 30448c2ecf20Sopenharmony_ci return bytes_wrote; 30458c2ecf20Sopenharmony_ci} 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci/** 30488c2ecf20Sopenharmony_ci * megasas_reset_bus_host - Bus & host reset handler entry point 30498c2ecf20Sopenharmony_ci * @scmd: Mid-layer SCSI command 30508c2ecf20Sopenharmony_ci */ 30518c2ecf20Sopenharmony_cistatic int megasas_reset_bus_host(struct scsi_cmnd *scmd) 30528c2ecf20Sopenharmony_ci{ 30538c2ecf20Sopenharmony_ci int ret; 30548c2ecf20Sopenharmony_ci struct megasas_instance *instance; 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)scmd->device->host->hostdata; 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, scmd, 30598c2ecf20Sopenharmony_ci "OCR is requested due to IO timeout!!\n"); 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, scmd, 30628c2ecf20Sopenharmony_ci "SCSI host state: %d SCSI host busy: %d FW outstanding: %d\n", 30638c2ecf20Sopenharmony_ci scmd->device->host->shost_state, 30648c2ecf20Sopenharmony_ci scsi_host_busy(scmd->device->host), 30658c2ecf20Sopenharmony_ci atomic_read(&instance->fw_outstanding)); 30668c2ecf20Sopenharmony_ci /* 30678c2ecf20Sopenharmony_ci * First wait for all commands to complete 30688c2ecf20Sopenharmony_ci */ 30698c2ecf20Sopenharmony_ci if (instance->adapter_type == MFI_SERIES) { 30708c2ecf20Sopenharmony_ci ret = megasas_generic_reset(scmd); 30718c2ecf20Sopenharmony_ci } else { 30728c2ecf20Sopenharmony_ci megasas_dump_fusion_io(scmd); 30738c2ecf20Sopenharmony_ci ret = megasas_reset_fusion(scmd->device->host, 30748c2ecf20Sopenharmony_ci SCSIIO_TIMEOUT_OCR); 30758c2ecf20Sopenharmony_ci } 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_ci return ret; 30788c2ecf20Sopenharmony_ci} 30798c2ecf20Sopenharmony_ci 30808c2ecf20Sopenharmony_ci/** 30818c2ecf20Sopenharmony_ci * megasas_task_abort - Issues task abort request to firmware 30828c2ecf20Sopenharmony_ci * (supported only for fusion adapters) 30838c2ecf20Sopenharmony_ci * @scmd: SCSI command pointer 30848c2ecf20Sopenharmony_ci */ 30858c2ecf20Sopenharmony_cistatic int megasas_task_abort(struct scsi_cmnd *scmd) 30868c2ecf20Sopenharmony_ci{ 30878c2ecf20Sopenharmony_ci int ret; 30888c2ecf20Sopenharmony_ci struct megasas_instance *instance; 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)scmd->device->host->hostdata; 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) 30938c2ecf20Sopenharmony_ci ret = megasas_task_abort_fusion(scmd); 30948c2ecf20Sopenharmony_ci else { 30958c2ecf20Sopenharmony_ci sdev_printk(KERN_NOTICE, scmd->device, "TASK ABORT not supported\n"); 30968c2ecf20Sopenharmony_ci ret = FAILED; 30978c2ecf20Sopenharmony_ci } 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_ci return ret; 31008c2ecf20Sopenharmony_ci} 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci/** 31038c2ecf20Sopenharmony_ci * megasas_reset_target: Issues target reset request to firmware 31048c2ecf20Sopenharmony_ci * (supported only for fusion adapters) 31058c2ecf20Sopenharmony_ci * @scmd: SCSI command pointer 31068c2ecf20Sopenharmony_ci */ 31078c2ecf20Sopenharmony_cistatic int megasas_reset_target(struct scsi_cmnd *scmd) 31088c2ecf20Sopenharmony_ci{ 31098c2ecf20Sopenharmony_ci int ret; 31108c2ecf20Sopenharmony_ci struct megasas_instance *instance; 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)scmd->device->host->hostdata; 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) 31158c2ecf20Sopenharmony_ci ret = megasas_reset_target_fusion(scmd); 31168c2ecf20Sopenharmony_ci else { 31178c2ecf20Sopenharmony_ci sdev_printk(KERN_NOTICE, scmd->device, "TARGET RESET not supported\n"); 31188c2ecf20Sopenharmony_ci ret = FAILED; 31198c2ecf20Sopenharmony_ci } 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci return ret; 31228c2ecf20Sopenharmony_ci} 31238c2ecf20Sopenharmony_ci 31248c2ecf20Sopenharmony_ci/** 31258c2ecf20Sopenharmony_ci * megasas_bios_param - Returns disk geometry for a disk 31268c2ecf20Sopenharmony_ci * @sdev: device handle 31278c2ecf20Sopenharmony_ci * @bdev: block device 31288c2ecf20Sopenharmony_ci * @capacity: drive capacity 31298c2ecf20Sopenharmony_ci * @geom: geometry parameters 31308c2ecf20Sopenharmony_ci */ 31318c2ecf20Sopenharmony_cistatic int 31328c2ecf20Sopenharmony_cimegasas_bios_param(struct scsi_device *sdev, struct block_device *bdev, 31338c2ecf20Sopenharmony_ci sector_t capacity, int geom[]) 31348c2ecf20Sopenharmony_ci{ 31358c2ecf20Sopenharmony_ci int heads; 31368c2ecf20Sopenharmony_ci int sectors; 31378c2ecf20Sopenharmony_ci sector_t cylinders; 31388c2ecf20Sopenharmony_ci unsigned long tmp; 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci /* Default heads (64) & sectors (32) */ 31418c2ecf20Sopenharmony_ci heads = 64; 31428c2ecf20Sopenharmony_ci sectors = 32; 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_ci tmp = heads * sectors; 31458c2ecf20Sopenharmony_ci cylinders = capacity; 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci sector_div(cylinders, tmp); 31488c2ecf20Sopenharmony_ci 31498c2ecf20Sopenharmony_ci /* 31508c2ecf20Sopenharmony_ci * Handle extended translation size for logical drives > 1Gb 31518c2ecf20Sopenharmony_ci */ 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci if (capacity >= 0x200000) { 31548c2ecf20Sopenharmony_ci heads = 255; 31558c2ecf20Sopenharmony_ci sectors = 63; 31568c2ecf20Sopenharmony_ci tmp = heads*sectors; 31578c2ecf20Sopenharmony_ci cylinders = capacity; 31588c2ecf20Sopenharmony_ci sector_div(cylinders, tmp); 31598c2ecf20Sopenharmony_ci } 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_ci geom[0] = heads; 31628c2ecf20Sopenharmony_ci geom[1] = sectors; 31638c2ecf20Sopenharmony_ci geom[2] = cylinders; 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci return 0; 31668c2ecf20Sopenharmony_ci} 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_cistatic int megasas_map_queues(struct Scsi_Host *shost) 31698c2ecf20Sopenharmony_ci{ 31708c2ecf20Sopenharmony_ci struct megasas_instance *instance; 31718c2ecf20Sopenharmony_ci 31728c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)shost->hostdata; 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci if (shost->nr_hw_queues == 1) 31758c2ecf20Sopenharmony_ci return 0; 31768c2ecf20Sopenharmony_ci 31778c2ecf20Sopenharmony_ci return blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT], 31788c2ecf20Sopenharmony_ci instance->pdev, instance->low_latency_index_start); 31798c2ecf20Sopenharmony_ci} 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_cistatic void megasas_aen_polling(struct work_struct *work); 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci/** 31848c2ecf20Sopenharmony_ci * megasas_service_aen - Processes an event notification 31858c2ecf20Sopenharmony_ci * @instance: Adapter soft state 31868c2ecf20Sopenharmony_ci * @cmd: AEN command completed by the ISR 31878c2ecf20Sopenharmony_ci * 31888c2ecf20Sopenharmony_ci * For AEN, driver sends a command down to FW that is held by the FW till an 31898c2ecf20Sopenharmony_ci * event occurs. When an event of interest occurs, FW completes the command 31908c2ecf20Sopenharmony_ci * that it was previously holding. 31918c2ecf20Sopenharmony_ci * 31928c2ecf20Sopenharmony_ci * This routines sends SIGIO signal to processes that have registered with the 31938c2ecf20Sopenharmony_ci * driver for AEN. 31948c2ecf20Sopenharmony_ci */ 31958c2ecf20Sopenharmony_cistatic void 31968c2ecf20Sopenharmony_cimegasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) 31978c2ecf20Sopenharmony_ci{ 31988c2ecf20Sopenharmony_ci unsigned long flags; 31998c2ecf20Sopenharmony_ci 32008c2ecf20Sopenharmony_ci /* 32018c2ecf20Sopenharmony_ci * Don't signal app if it is just an aborted previously registered aen 32028c2ecf20Sopenharmony_ci */ 32038c2ecf20Sopenharmony_ci if ((!cmd->abort_aen) && (instance->unload == 0)) { 32048c2ecf20Sopenharmony_ci spin_lock_irqsave(&poll_aen_lock, flags); 32058c2ecf20Sopenharmony_ci megasas_poll_wait_aen = 1; 32068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&poll_aen_lock, flags); 32078c2ecf20Sopenharmony_ci wake_up(&megasas_poll_wait); 32088c2ecf20Sopenharmony_ci kill_fasync(&megasas_async_queue, SIGIO, POLL_IN); 32098c2ecf20Sopenharmony_ci } 32108c2ecf20Sopenharmony_ci else 32118c2ecf20Sopenharmony_ci cmd->abort_aen = 0; 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci instance->aen_cmd = NULL; 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci if ((instance->unload == 0) && 32188c2ecf20Sopenharmony_ci ((instance->issuepend_done == 1))) { 32198c2ecf20Sopenharmony_ci struct megasas_aen_event *ev; 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci ev = kzalloc(sizeof(*ev), GFP_ATOMIC); 32228c2ecf20Sopenharmony_ci if (!ev) { 32238c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "megasas_service_aen: out of memory\n"); 32248c2ecf20Sopenharmony_ci } else { 32258c2ecf20Sopenharmony_ci ev->instance = instance; 32268c2ecf20Sopenharmony_ci instance->ev = ev; 32278c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&ev->hotplug_work, 32288c2ecf20Sopenharmony_ci megasas_aen_polling); 32298c2ecf20Sopenharmony_ci schedule_delayed_work(&ev->hotplug_work, 0); 32308c2ecf20Sopenharmony_ci } 32318c2ecf20Sopenharmony_ci } 32328c2ecf20Sopenharmony_ci} 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_cistatic ssize_t 32358c2ecf20Sopenharmony_cifw_crash_buffer_store(struct device *cdev, 32368c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 32378c2ecf20Sopenharmony_ci{ 32388c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 32398c2ecf20Sopenharmony_ci struct megasas_instance *instance = 32408c2ecf20Sopenharmony_ci (struct megasas_instance *) shost->hostdata; 32418c2ecf20Sopenharmony_ci int val = 0; 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ci if (kstrtoint(buf, 0, &val) != 0) 32448c2ecf20Sopenharmony_ci return -EINVAL; 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci mutex_lock(&instance->crashdump_lock); 32478c2ecf20Sopenharmony_ci instance->fw_crash_buffer_offset = val; 32488c2ecf20Sopenharmony_ci mutex_unlock(&instance->crashdump_lock); 32498c2ecf20Sopenharmony_ci return strlen(buf); 32508c2ecf20Sopenharmony_ci} 32518c2ecf20Sopenharmony_ci 32528c2ecf20Sopenharmony_cistatic ssize_t 32538c2ecf20Sopenharmony_cifw_crash_buffer_show(struct device *cdev, 32548c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 32558c2ecf20Sopenharmony_ci{ 32568c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 32578c2ecf20Sopenharmony_ci struct megasas_instance *instance = 32588c2ecf20Sopenharmony_ci (struct megasas_instance *) shost->hostdata; 32598c2ecf20Sopenharmony_ci u32 size; 32608c2ecf20Sopenharmony_ci unsigned long dmachunk = CRASH_DMA_BUF_SIZE; 32618c2ecf20Sopenharmony_ci unsigned long chunk_left_bytes; 32628c2ecf20Sopenharmony_ci unsigned long src_addr; 32638c2ecf20Sopenharmony_ci u32 buff_offset; 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci mutex_lock(&instance->crashdump_lock); 32668c2ecf20Sopenharmony_ci buff_offset = instance->fw_crash_buffer_offset; 32678c2ecf20Sopenharmony_ci if (!instance->crash_dump_buf || 32688c2ecf20Sopenharmony_ci !((instance->fw_crash_state == AVAILABLE) || 32698c2ecf20Sopenharmony_ci (instance->fw_crash_state == COPYING))) { 32708c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 32718c2ecf20Sopenharmony_ci "Firmware crash dump is not available\n"); 32728c2ecf20Sopenharmony_ci mutex_unlock(&instance->crashdump_lock); 32738c2ecf20Sopenharmony_ci return -EINVAL; 32748c2ecf20Sopenharmony_ci } 32758c2ecf20Sopenharmony_ci 32768c2ecf20Sopenharmony_ci if (buff_offset > (instance->fw_crash_buffer_size * dmachunk)) { 32778c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 32788c2ecf20Sopenharmony_ci "Firmware crash dump offset is out of range\n"); 32798c2ecf20Sopenharmony_ci mutex_unlock(&instance->crashdump_lock); 32808c2ecf20Sopenharmony_ci return 0; 32818c2ecf20Sopenharmony_ci } 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_ci size = (instance->fw_crash_buffer_size * dmachunk) - buff_offset; 32848c2ecf20Sopenharmony_ci chunk_left_bytes = dmachunk - (buff_offset % dmachunk); 32858c2ecf20Sopenharmony_ci size = (size > chunk_left_bytes) ? chunk_left_bytes : size; 32868c2ecf20Sopenharmony_ci size = (size >= PAGE_SIZE) ? (PAGE_SIZE - 1) : size; 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci src_addr = (unsigned long)instance->crash_buf[buff_offset / dmachunk] + 32898c2ecf20Sopenharmony_ci (buff_offset % dmachunk); 32908c2ecf20Sopenharmony_ci memcpy(buf, (void *)src_addr, size); 32918c2ecf20Sopenharmony_ci mutex_unlock(&instance->crashdump_lock); 32928c2ecf20Sopenharmony_ci 32938c2ecf20Sopenharmony_ci return size; 32948c2ecf20Sopenharmony_ci} 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_cistatic ssize_t 32978c2ecf20Sopenharmony_cifw_crash_buffer_size_show(struct device *cdev, 32988c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 32998c2ecf20Sopenharmony_ci{ 33008c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 33018c2ecf20Sopenharmony_ci struct megasas_instance *instance = 33028c2ecf20Sopenharmony_ci (struct megasas_instance *) shost->hostdata; 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long) 33058c2ecf20Sopenharmony_ci ((instance->fw_crash_buffer_size) * 1024 * 1024)/PAGE_SIZE); 33068c2ecf20Sopenharmony_ci} 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_cistatic ssize_t 33098c2ecf20Sopenharmony_cifw_crash_state_store(struct device *cdev, 33108c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 33118c2ecf20Sopenharmony_ci{ 33128c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 33138c2ecf20Sopenharmony_ci struct megasas_instance *instance = 33148c2ecf20Sopenharmony_ci (struct megasas_instance *) shost->hostdata; 33158c2ecf20Sopenharmony_ci int val = 0; 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci if (kstrtoint(buf, 0, &val) != 0) 33188c2ecf20Sopenharmony_ci return -EINVAL; 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci if ((val <= AVAILABLE || val > COPY_ERROR)) { 33218c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "application updates invalid " 33228c2ecf20Sopenharmony_ci "firmware crash state\n"); 33238c2ecf20Sopenharmony_ci return -EINVAL; 33248c2ecf20Sopenharmony_ci } 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci instance->fw_crash_state = val; 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci if ((val == COPIED) || (val == COPY_ERROR)) { 33298c2ecf20Sopenharmony_ci mutex_lock(&instance->crashdump_lock); 33308c2ecf20Sopenharmony_ci megasas_free_host_crash_buffer(instance); 33318c2ecf20Sopenharmony_ci mutex_unlock(&instance->crashdump_lock); 33328c2ecf20Sopenharmony_ci if (val == COPY_ERROR) 33338c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "application failed to " 33348c2ecf20Sopenharmony_ci "copy Firmware crash dump\n"); 33358c2ecf20Sopenharmony_ci else 33368c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Firmware crash dump " 33378c2ecf20Sopenharmony_ci "copied successfully\n"); 33388c2ecf20Sopenharmony_ci } 33398c2ecf20Sopenharmony_ci return strlen(buf); 33408c2ecf20Sopenharmony_ci} 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_cistatic ssize_t 33438c2ecf20Sopenharmony_cifw_crash_state_show(struct device *cdev, 33448c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 33458c2ecf20Sopenharmony_ci{ 33468c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 33478c2ecf20Sopenharmony_ci struct megasas_instance *instance = 33488c2ecf20Sopenharmony_ci (struct megasas_instance *) shost->hostdata; 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", instance->fw_crash_state); 33518c2ecf20Sopenharmony_ci} 33528c2ecf20Sopenharmony_ci 33538c2ecf20Sopenharmony_cistatic ssize_t 33548c2ecf20Sopenharmony_cipage_size_show(struct device *cdev, 33558c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 33568c2ecf20Sopenharmony_ci{ 33578c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1); 33588c2ecf20Sopenharmony_ci} 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_cistatic ssize_t 33618c2ecf20Sopenharmony_cildio_outstanding_show(struct device *cdev, struct device_attribute *attr, 33628c2ecf20Sopenharmony_ci char *buf) 33638c2ecf20Sopenharmony_ci{ 33648c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 33658c2ecf20Sopenharmony_ci struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata; 33668c2ecf20Sopenharmony_ci 33678c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->ldio_outstanding)); 33688c2ecf20Sopenharmony_ci} 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_cistatic ssize_t 33718c2ecf20Sopenharmony_cifw_cmds_outstanding_show(struct device *cdev, 33728c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 33738c2ecf20Sopenharmony_ci{ 33748c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 33758c2ecf20Sopenharmony_ci struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata; 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->fw_outstanding)); 33788c2ecf20Sopenharmony_ci} 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_cistatic ssize_t 33818c2ecf20Sopenharmony_cienable_sdev_max_qd_show(struct device *cdev, 33828c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 33838c2ecf20Sopenharmony_ci{ 33848c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 33858c2ecf20Sopenharmony_ci struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata; 33868c2ecf20Sopenharmony_ci 33878c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", instance->enable_sdev_max_qd); 33888c2ecf20Sopenharmony_ci} 33898c2ecf20Sopenharmony_ci 33908c2ecf20Sopenharmony_cistatic ssize_t 33918c2ecf20Sopenharmony_cienable_sdev_max_qd_store(struct device *cdev, 33928c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 33938c2ecf20Sopenharmony_ci{ 33948c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 33958c2ecf20Sopenharmony_ci struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata; 33968c2ecf20Sopenharmony_ci u32 val = 0; 33978c2ecf20Sopenharmony_ci bool is_target_prop; 33988c2ecf20Sopenharmony_ci int ret_target_prop = DCMD_FAILED; 33998c2ecf20Sopenharmony_ci struct scsi_device *sdev; 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_ci if (kstrtou32(buf, 0, &val) != 0) { 34028c2ecf20Sopenharmony_ci pr_err("megasas: could not set enable_sdev_max_qd\n"); 34038c2ecf20Sopenharmony_ci return -EINVAL; 34048c2ecf20Sopenharmony_ci } 34058c2ecf20Sopenharmony_ci 34068c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 34078c2ecf20Sopenharmony_ci if (val) 34088c2ecf20Sopenharmony_ci instance->enable_sdev_max_qd = true; 34098c2ecf20Sopenharmony_ci else 34108c2ecf20Sopenharmony_ci instance->enable_sdev_max_qd = false; 34118c2ecf20Sopenharmony_ci 34128c2ecf20Sopenharmony_ci shost_for_each_device(sdev, shost) { 34138c2ecf20Sopenharmony_ci ret_target_prop = megasas_get_target_prop(instance, sdev); 34148c2ecf20Sopenharmony_ci is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false; 34158c2ecf20Sopenharmony_ci megasas_set_fw_assisted_qd(sdev, is_target_prop); 34168c2ecf20Sopenharmony_ci } 34178c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 34188c2ecf20Sopenharmony_ci 34198c2ecf20Sopenharmony_ci return strlen(buf); 34208c2ecf20Sopenharmony_ci} 34218c2ecf20Sopenharmony_ci 34228c2ecf20Sopenharmony_cistatic ssize_t 34238c2ecf20Sopenharmony_cidump_system_regs_show(struct device *cdev, 34248c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 34258c2ecf20Sopenharmony_ci{ 34268c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 34278c2ecf20Sopenharmony_ci struct megasas_instance *instance = 34288c2ecf20Sopenharmony_ci (struct megasas_instance *)shost->hostdata; 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci return megasas_dump_sys_regs(instance->reg_set, buf); 34318c2ecf20Sopenharmony_ci} 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_cistatic ssize_t 34348c2ecf20Sopenharmony_ciraid_map_id_show(struct device *cdev, struct device_attribute *attr, 34358c2ecf20Sopenharmony_ci char *buf) 34368c2ecf20Sopenharmony_ci{ 34378c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 34388c2ecf20Sopenharmony_ci struct megasas_instance *instance = 34398c2ecf20Sopenharmony_ci (struct megasas_instance *)shost->hostdata; 34408c2ecf20Sopenharmony_ci 34418c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%ld\n", 34428c2ecf20Sopenharmony_ci (unsigned long)instance->map_id); 34438c2ecf20Sopenharmony_ci} 34448c2ecf20Sopenharmony_ci 34458c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(fw_crash_buffer); 34468c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(fw_crash_buffer_size); 34478c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(fw_crash_state); 34488c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(page_size); 34498c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(ldio_outstanding); 34508c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(fw_cmds_outstanding); 34518c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(enable_sdev_max_qd); 34528c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(dump_system_regs); 34538c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(raid_map_id); 34548c2ecf20Sopenharmony_ci 34558c2ecf20Sopenharmony_cistatic struct device_attribute *megaraid_host_attrs[] = { 34568c2ecf20Sopenharmony_ci &dev_attr_fw_crash_buffer_size, 34578c2ecf20Sopenharmony_ci &dev_attr_fw_crash_buffer, 34588c2ecf20Sopenharmony_ci &dev_attr_fw_crash_state, 34598c2ecf20Sopenharmony_ci &dev_attr_page_size, 34608c2ecf20Sopenharmony_ci &dev_attr_ldio_outstanding, 34618c2ecf20Sopenharmony_ci &dev_attr_fw_cmds_outstanding, 34628c2ecf20Sopenharmony_ci &dev_attr_enable_sdev_max_qd, 34638c2ecf20Sopenharmony_ci &dev_attr_dump_system_regs, 34648c2ecf20Sopenharmony_ci &dev_attr_raid_map_id, 34658c2ecf20Sopenharmony_ci NULL, 34668c2ecf20Sopenharmony_ci}; 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci/* 34698c2ecf20Sopenharmony_ci * Scsi host template for megaraid_sas driver 34708c2ecf20Sopenharmony_ci */ 34718c2ecf20Sopenharmony_cistatic struct scsi_host_template megasas_template = { 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_ci .module = THIS_MODULE, 34748c2ecf20Sopenharmony_ci .name = "Avago SAS based MegaRAID driver", 34758c2ecf20Sopenharmony_ci .proc_name = "megaraid_sas", 34768c2ecf20Sopenharmony_ci .slave_configure = megasas_slave_configure, 34778c2ecf20Sopenharmony_ci .slave_alloc = megasas_slave_alloc, 34788c2ecf20Sopenharmony_ci .slave_destroy = megasas_slave_destroy, 34798c2ecf20Sopenharmony_ci .queuecommand = megasas_queue_command, 34808c2ecf20Sopenharmony_ci .eh_target_reset_handler = megasas_reset_target, 34818c2ecf20Sopenharmony_ci .eh_abort_handler = megasas_task_abort, 34828c2ecf20Sopenharmony_ci .eh_host_reset_handler = megasas_reset_bus_host, 34838c2ecf20Sopenharmony_ci .eh_timed_out = megasas_reset_timer, 34848c2ecf20Sopenharmony_ci .shost_attrs = megaraid_host_attrs, 34858c2ecf20Sopenharmony_ci .bios_param = megasas_bios_param, 34868c2ecf20Sopenharmony_ci .map_queues = megasas_map_queues, 34878c2ecf20Sopenharmony_ci .change_queue_depth = scsi_change_queue_depth, 34888c2ecf20Sopenharmony_ci .max_segment_size = 0xffffffff, 34898c2ecf20Sopenharmony_ci}; 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_ci/** 34928c2ecf20Sopenharmony_ci * megasas_complete_int_cmd - Completes an internal command 34938c2ecf20Sopenharmony_ci * @instance: Adapter soft state 34948c2ecf20Sopenharmony_ci * @cmd: Command to be completed 34958c2ecf20Sopenharmony_ci * 34968c2ecf20Sopenharmony_ci * The megasas_issue_blocked_cmd() function waits for a command to complete 34978c2ecf20Sopenharmony_ci * after it issues a command. This function wakes up that waiting routine by 34988c2ecf20Sopenharmony_ci * calling wake_up() on the wait queue. 34998c2ecf20Sopenharmony_ci */ 35008c2ecf20Sopenharmony_cistatic void 35018c2ecf20Sopenharmony_cimegasas_complete_int_cmd(struct megasas_instance *instance, 35028c2ecf20Sopenharmony_ci struct megasas_cmd *cmd) 35038c2ecf20Sopenharmony_ci{ 35048c2ecf20Sopenharmony_ci if (cmd->cmd_status_drv == DCMD_INIT) 35058c2ecf20Sopenharmony_ci cmd->cmd_status_drv = 35068c2ecf20Sopenharmony_ci (cmd->frame->io.cmd_status == MFI_STAT_OK) ? 35078c2ecf20Sopenharmony_ci DCMD_SUCCESS : DCMD_FAILED; 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_ci wake_up(&instance->int_cmd_wait_q); 35108c2ecf20Sopenharmony_ci} 35118c2ecf20Sopenharmony_ci 35128c2ecf20Sopenharmony_ci/** 35138c2ecf20Sopenharmony_ci * megasas_complete_abort - Completes aborting a command 35148c2ecf20Sopenharmony_ci * @instance: Adapter soft state 35158c2ecf20Sopenharmony_ci * @cmd: Cmd that was issued to abort another cmd 35168c2ecf20Sopenharmony_ci * 35178c2ecf20Sopenharmony_ci * The megasas_issue_blocked_abort_cmd() function waits on abort_cmd_wait_q 35188c2ecf20Sopenharmony_ci * after it issues an abort on a previously issued command. This function 35198c2ecf20Sopenharmony_ci * wakes up all functions waiting on the same wait queue. 35208c2ecf20Sopenharmony_ci */ 35218c2ecf20Sopenharmony_cistatic void 35228c2ecf20Sopenharmony_cimegasas_complete_abort(struct megasas_instance *instance, 35238c2ecf20Sopenharmony_ci struct megasas_cmd *cmd) 35248c2ecf20Sopenharmony_ci{ 35258c2ecf20Sopenharmony_ci if (cmd->sync_cmd) { 35268c2ecf20Sopenharmony_ci cmd->sync_cmd = 0; 35278c2ecf20Sopenharmony_ci cmd->cmd_status_drv = DCMD_SUCCESS; 35288c2ecf20Sopenharmony_ci wake_up(&instance->abort_cmd_wait_q); 35298c2ecf20Sopenharmony_ci } 35308c2ecf20Sopenharmony_ci} 35318c2ecf20Sopenharmony_ci 35328c2ecf20Sopenharmony_cistatic void 35338c2ecf20Sopenharmony_cimegasas_set_ld_removed_by_fw(struct megasas_instance *instance) 35348c2ecf20Sopenharmony_ci{ 35358c2ecf20Sopenharmony_ci uint i; 35368c2ecf20Sopenharmony_ci 35378c2ecf20Sopenharmony_ci for (i = 0; (i < MEGASAS_MAX_LD_IDS); i++) { 35388c2ecf20Sopenharmony_ci if (instance->ld_ids_prev[i] != 0xff && 35398c2ecf20Sopenharmony_ci instance->ld_ids_from_raidmap[i] == 0xff) { 35408c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & LD_PD_DEBUG) 35418c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 35428c2ecf20Sopenharmony_ci "LD target ID %d removed from RAID map\n", i); 35438c2ecf20Sopenharmony_ci instance->ld_tgtid_status[i] = LD_TARGET_ID_DELETED; 35448c2ecf20Sopenharmony_ci } 35458c2ecf20Sopenharmony_ci } 35468c2ecf20Sopenharmony_ci} 35478c2ecf20Sopenharmony_ci 35488c2ecf20Sopenharmony_ci/** 35498c2ecf20Sopenharmony_ci * megasas_complete_cmd - Completes a command 35508c2ecf20Sopenharmony_ci * @instance: Adapter soft state 35518c2ecf20Sopenharmony_ci * @cmd: Command to be completed 35528c2ecf20Sopenharmony_ci * @alt_status: If non-zero, use this value as status to 35538c2ecf20Sopenharmony_ci * SCSI mid-layer instead of the value returned 35548c2ecf20Sopenharmony_ci * by the FW. This should be used if caller wants 35558c2ecf20Sopenharmony_ci * an alternate status (as in the case of aborted 35568c2ecf20Sopenharmony_ci * commands) 35578c2ecf20Sopenharmony_ci */ 35588c2ecf20Sopenharmony_civoid 35598c2ecf20Sopenharmony_cimegasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, 35608c2ecf20Sopenharmony_ci u8 alt_status) 35618c2ecf20Sopenharmony_ci{ 35628c2ecf20Sopenharmony_ci int exception = 0; 35638c2ecf20Sopenharmony_ci struct megasas_header *hdr = &cmd->frame->hdr; 35648c2ecf20Sopenharmony_ci unsigned long flags; 35658c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 35668c2ecf20Sopenharmony_ci u32 opcode, status; 35678c2ecf20Sopenharmony_ci 35688c2ecf20Sopenharmony_ci /* flag for the retry reset */ 35698c2ecf20Sopenharmony_ci cmd->retry_for_fw_reset = 0; 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_ci if (cmd->scmd) 35728c2ecf20Sopenharmony_ci cmd->scmd->SCp.ptr = NULL; 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ci switch (hdr->cmd) { 35758c2ecf20Sopenharmony_ci case MFI_CMD_INVALID: 35768c2ecf20Sopenharmony_ci /* Some older 1068 controller FW may keep a pended 35778c2ecf20Sopenharmony_ci MR_DCMD_CTRL_EVENT_GET_INFO left over from the main kernel 35788c2ecf20Sopenharmony_ci when booting the kdump kernel. Ignore this command to 35798c2ecf20Sopenharmony_ci prevent a kernel panic on shutdown of the kdump kernel. */ 35808c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "MFI_CMD_INVALID command " 35818c2ecf20Sopenharmony_ci "completed\n"); 35828c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "If you have a controller " 35838c2ecf20Sopenharmony_ci "other than PERC5, please upgrade your firmware\n"); 35848c2ecf20Sopenharmony_ci break; 35858c2ecf20Sopenharmony_ci case MFI_CMD_PD_SCSI_IO: 35868c2ecf20Sopenharmony_ci case MFI_CMD_LD_SCSI_IO: 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci /* 35898c2ecf20Sopenharmony_ci * MFI_CMD_PD_SCSI_IO and MFI_CMD_LD_SCSI_IO could have been 35908c2ecf20Sopenharmony_ci * issued either through an IO path or an IOCTL path. If it 35918c2ecf20Sopenharmony_ci * was via IOCTL, we will send it to internal completion. 35928c2ecf20Sopenharmony_ci */ 35938c2ecf20Sopenharmony_ci if (cmd->sync_cmd) { 35948c2ecf20Sopenharmony_ci cmd->sync_cmd = 0; 35958c2ecf20Sopenharmony_ci megasas_complete_int_cmd(instance, cmd); 35968c2ecf20Sopenharmony_ci break; 35978c2ecf20Sopenharmony_ci } 35988c2ecf20Sopenharmony_ci fallthrough; 35998c2ecf20Sopenharmony_ci 36008c2ecf20Sopenharmony_ci case MFI_CMD_LD_READ: 36018c2ecf20Sopenharmony_ci case MFI_CMD_LD_WRITE: 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_ci if (alt_status) { 36048c2ecf20Sopenharmony_ci cmd->scmd->result = alt_status << 16; 36058c2ecf20Sopenharmony_ci exception = 1; 36068c2ecf20Sopenharmony_ci } 36078c2ecf20Sopenharmony_ci 36088c2ecf20Sopenharmony_ci if (exception) { 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_ci atomic_dec(&instance->fw_outstanding); 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_ci scsi_dma_unmap(cmd->scmd); 36138c2ecf20Sopenharmony_ci cmd->scmd->scsi_done(cmd->scmd); 36148c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 36158c2ecf20Sopenharmony_ci 36168c2ecf20Sopenharmony_ci break; 36178c2ecf20Sopenharmony_ci } 36188c2ecf20Sopenharmony_ci 36198c2ecf20Sopenharmony_ci switch (hdr->cmd_status) { 36208c2ecf20Sopenharmony_ci 36218c2ecf20Sopenharmony_ci case MFI_STAT_OK: 36228c2ecf20Sopenharmony_ci cmd->scmd->result = DID_OK << 16; 36238c2ecf20Sopenharmony_ci break; 36248c2ecf20Sopenharmony_ci 36258c2ecf20Sopenharmony_ci case MFI_STAT_SCSI_IO_FAILED: 36268c2ecf20Sopenharmony_ci case MFI_STAT_LD_INIT_IN_PROGRESS: 36278c2ecf20Sopenharmony_ci cmd->scmd->result = 36288c2ecf20Sopenharmony_ci (DID_ERROR << 16) | hdr->scsi_status; 36298c2ecf20Sopenharmony_ci break; 36308c2ecf20Sopenharmony_ci 36318c2ecf20Sopenharmony_ci case MFI_STAT_SCSI_DONE_WITH_ERROR: 36328c2ecf20Sopenharmony_ci 36338c2ecf20Sopenharmony_ci cmd->scmd->result = (DID_OK << 16) | hdr->scsi_status; 36348c2ecf20Sopenharmony_ci 36358c2ecf20Sopenharmony_ci if (hdr->scsi_status == SAM_STAT_CHECK_CONDITION) { 36368c2ecf20Sopenharmony_ci memset(cmd->scmd->sense_buffer, 0, 36378c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE); 36388c2ecf20Sopenharmony_ci memcpy(cmd->scmd->sense_buffer, cmd->sense, 36398c2ecf20Sopenharmony_ci hdr->sense_len); 36408c2ecf20Sopenharmony_ci 36418c2ecf20Sopenharmony_ci cmd->scmd->result |= DRIVER_SENSE << 24; 36428c2ecf20Sopenharmony_ci } 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_ci break; 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_ci case MFI_STAT_LD_OFFLINE: 36478c2ecf20Sopenharmony_ci case MFI_STAT_DEVICE_NOT_FOUND: 36488c2ecf20Sopenharmony_ci cmd->scmd->result = DID_BAD_TARGET << 16; 36498c2ecf20Sopenharmony_ci break; 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ci default: 36528c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "MFI FW status %#x\n", 36538c2ecf20Sopenharmony_ci hdr->cmd_status); 36548c2ecf20Sopenharmony_ci cmd->scmd->result = DID_ERROR << 16; 36558c2ecf20Sopenharmony_ci break; 36568c2ecf20Sopenharmony_ci } 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_ci atomic_dec(&instance->fw_outstanding); 36598c2ecf20Sopenharmony_ci 36608c2ecf20Sopenharmony_ci scsi_dma_unmap(cmd->scmd); 36618c2ecf20Sopenharmony_ci cmd->scmd->scsi_done(cmd->scmd); 36628c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci break; 36658c2ecf20Sopenharmony_ci 36668c2ecf20Sopenharmony_ci case MFI_CMD_SMP: 36678c2ecf20Sopenharmony_ci case MFI_CMD_STP: 36688c2ecf20Sopenharmony_ci case MFI_CMD_NVME: 36698c2ecf20Sopenharmony_ci case MFI_CMD_TOOLBOX: 36708c2ecf20Sopenharmony_ci megasas_complete_int_cmd(instance, cmd); 36718c2ecf20Sopenharmony_ci break; 36728c2ecf20Sopenharmony_ci 36738c2ecf20Sopenharmony_ci case MFI_CMD_DCMD: 36748c2ecf20Sopenharmony_ci opcode = le32_to_cpu(cmd->frame->dcmd.opcode); 36758c2ecf20Sopenharmony_ci /* Check for LD map update */ 36768c2ecf20Sopenharmony_ci if ((opcode == MR_DCMD_LD_MAP_GET_INFO) 36778c2ecf20Sopenharmony_ci && (cmd->frame->dcmd.mbox.b[1] == 1)) { 36788c2ecf20Sopenharmony_ci fusion->fast_path_io = 0; 36798c2ecf20Sopenharmony_ci spin_lock_irqsave(instance->host->host_lock, flags); 36808c2ecf20Sopenharmony_ci status = cmd->frame->hdr.cmd_status; 36818c2ecf20Sopenharmony_ci instance->map_update_cmd = NULL; 36828c2ecf20Sopenharmony_ci if (status != MFI_STAT_OK) { 36838c2ecf20Sopenharmony_ci if (status != MFI_STAT_NOT_FOUND) 36848c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "map syncfailed, status = 0x%x\n", 36858c2ecf20Sopenharmony_ci cmd->frame->hdr.cmd_status); 36868c2ecf20Sopenharmony_ci else { 36878c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 36888c2ecf20Sopenharmony_ci spin_unlock_irqrestore( 36898c2ecf20Sopenharmony_ci instance->host->host_lock, 36908c2ecf20Sopenharmony_ci flags); 36918c2ecf20Sopenharmony_ci break; 36928c2ecf20Sopenharmony_ci } 36938c2ecf20Sopenharmony_ci } 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_ci /* 36988c2ecf20Sopenharmony_ci * Set fast path IO to ZERO. 36998c2ecf20Sopenharmony_ci * Validate Map will set proper value. 37008c2ecf20Sopenharmony_ci * Meanwhile all IOs will go as LD IO. 37018c2ecf20Sopenharmony_ci */ 37028c2ecf20Sopenharmony_ci if (status == MFI_STAT_OK && 37038c2ecf20Sopenharmony_ci (MR_ValidateMapInfo(instance, (instance->map_id + 1)))) { 37048c2ecf20Sopenharmony_ci instance->map_id++; 37058c2ecf20Sopenharmony_ci fusion->fast_path_io = 1; 37068c2ecf20Sopenharmony_ci } else { 37078c2ecf20Sopenharmony_ci fusion->fast_path_io = 0; 37088c2ecf20Sopenharmony_ci } 37098c2ecf20Sopenharmony_ci 37108c2ecf20Sopenharmony_ci if (instance->adapter_type >= INVADER_SERIES) 37118c2ecf20Sopenharmony_ci megasas_set_ld_removed_by_fw(instance); 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci megasas_sync_map_info(instance); 37148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(instance->host->host_lock, 37158c2ecf20Sopenharmony_ci flags); 37168c2ecf20Sopenharmony_ci 37178c2ecf20Sopenharmony_ci break; 37188c2ecf20Sopenharmony_ci } 37198c2ecf20Sopenharmony_ci if (opcode == MR_DCMD_CTRL_EVENT_GET_INFO || 37208c2ecf20Sopenharmony_ci opcode == MR_DCMD_CTRL_EVENT_GET) { 37218c2ecf20Sopenharmony_ci spin_lock_irqsave(&poll_aen_lock, flags); 37228c2ecf20Sopenharmony_ci megasas_poll_wait_aen = 0; 37238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&poll_aen_lock, flags); 37248c2ecf20Sopenharmony_ci } 37258c2ecf20Sopenharmony_ci 37268c2ecf20Sopenharmony_ci /* FW has an updated PD sequence */ 37278c2ecf20Sopenharmony_ci if ((opcode == MR_DCMD_SYSTEM_PD_MAP_GET_INFO) && 37288c2ecf20Sopenharmony_ci (cmd->frame->dcmd.mbox.b[0] == 1)) { 37298c2ecf20Sopenharmony_ci 37308c2ecf20Sopenharmony_ci spin_lock_irqsave(instance->host->host_lock, flags); 37318c2ecf20Sopenharmony_ci status = cmd->frame->hdr.cmd_status; 37328c2ecf20Sopenharmony_ci instance->jbod_seq_cmd = NULL; 37338c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 37348c2ecf20Sopenharmony_ci 37358c2ecf20Sopenharmony_ci if (status == MFI_STAT_OK) { 37368c2ecf20Sopenharmony_ci instance->pd_seq_map_id++; 37378c2ecf20Sopenharmony_ci /* Re-register a pd sync seq num cmd */ 37388c2ecf20Sopenharmony_ci if (megasas_sync_pd_seq_num(instance, true)) 37398c2ecf20Sopenharmony_ci instance->use_seqnum_jbod_fp = false; 37408c2ecf20Sopenharmony_ci } else 37418c2ecf20Sopenharmony_ci instance->use_seqnum_jbod_fp = false; 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(instance->host->host_lock, flags); 37448c2ecf20Sopenharmony_ci break; 37458c2ecf20Sopenharmony_ci } 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_ci /* 37488c2ecf20Sopenharmony_ci * See if got an event notification 37498c2ecf20Sopenharmony_ci */ 37508c2ecf20Sopenharmony_ci if (opcode == MR_DCMD_CTRL_EVENT_WAIT) 37518c2ecf20Sopenharmony_ci megasas_service_aen(instance, cmd); 37528c2ecf20Sopenharmony_ci else 37538c2ecf20Sopenharmony_ci megasas_complete_int_cmd(instance, cmd); 37548c2ecf20Sopenharmony_ci 37558c2ecf20Sopenharmony_ci break; 37568c2ecf20Sopenharmony_ci 37578c2ecf20Sopenharmony_ci case MFI_CMD_ABORT: 37588c2ecf20Sopenharmony_ci /* 37598c2ecf20Sopenharmony_ci * Cmd issued to abort another cmd returned 37608c2ecf20Sopenharmony_ci */ 37618c2ecf20Sopenharmony_ci megasas_complete_abort(instance, cmd); 37628c2ecf20Sopenharmony_ci break; 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci default: 37658c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Unknown command completed! [0x%X]\n", 37668c2ecf20Sopenharmony_ci hdr->cmd); 37678c2ecf20Sopenharmony_ci megasas_complete_int_cmd(instance, cmd); 37688c2ecf20Sopenharmony_ci break; 37698c2ecf20Sopenharmony_ci } 37708c2ecf20Sopenharmony_ci} 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci/** 37738c2ecf20Sopenharmony_ci * megasas_issue_pending_cmds_again - issue all pending cmds 37748c2ecf20Sopenharmony_ci * in FW again because of the fw reset 37758c2ecf20Sopenharmony_ci * @instance: Adapter soft state 37768c2ecf20Sopenharmony_ci */ 37778c2ecf20Sopenharmony_cistatic inline void 37788c2ecf20Sopenharmony_cimegasas_issue_pending_cmds_again(struct megasas_instance *instance) 37798c2ecf20Sopenharmony_ci{ 37808c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 37818c2ecf20Sopenharmony_ci struct list_head clist_local; 37828c2ecf20Sopenharmony_ci union megasas_evt_class_locale class_locale; 37838c2ecf20Sopenharmony_ci unsigned long flags; 37848c2ecf20Sopenharmony_ci u32 seq_num; 37858c2ecf20Sopenharmony_ci 37868c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&clist_local); 37878c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->hba_lock, flags); 37888c2ecf20Sopenharmony_ci list_splice_init(&instance->internal_reset_pending_q, &clist_local); 37898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->hba_lock, flags); 37908c2ecf20Sopenharmony_ci 37918c2ecf20Sopenharmony_ci while (!list_empty(&clist_local)) { 37928c2ecf20Sopenharmony_ci cmd = list_entry((&clist_local)->next, 37938c2ecf20Sopenharmony_ci struct megasas_cmd, list); 37948c2ecf20Sopenharmony_ci list_del_init(&cmd->list); 37958c2ecf20Sopenharmony_ci 37968c2ecf20Sopenharmony_ci if (cmd->sync_cmd || cmd->scmd) { 37978c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "command %p, %p:%d" 37988c2ecf20Sopenharmony_ci "detected to be pending while HBA reset\n", 37998c2ecf20Sopenharmony_ci cmd, cmd->scmd, cmd->sync_cmd); 38008c2ecf20Sopenharmony_ci 38018c2ecf20Sopenharmony_ci cmd->retry_for_fw_reset++; 38028c2ecf20Sopenharmony_ci 38038c2ecf20Sopenharmony_ci if (cmd->retry_for_fw_reset == 3) { 38048c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "cmd %p, %p:%d" 38058c2ecf20Sopenharmony_ci "was tried multiple times during reset." 38068c2ecf20Sopenharmony_ci "Shutting down the HBA\n", 38078c2ecf20Sopenharmony_ci cmd, cmd->scmd, cmd->sync_cmd); 38088c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 38098c2ecf20Sopenharmony_ci atomic_set(&instance->fw_reset_no_pci_access, 1); 38108c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 38118c2ecf20Sopenharmony_ci return; 38128c2ecf20Sopenharmony_ci } 38138c2ecf20Sopenharmony_ci } 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ci if (cmd->sync_cmd == 1) { 38168c2ecf20Sopenharmony_ci if (cmd->scmd) { 38178c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "unexpected" 38188c2ecf20Sopenharmony_ci "cmd attached to internal command!\n"); 38198c2ecf20Sopenharmony_ci } 38208c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "%p synchronous cmd" 38218c2ecf20Sopenharmony_ci "on the internal reset queue," 38228c2ecf20Sopenharmony_ci "issue it again.\n", cmd); 38238c2ecf20Sopenharmony_ci cmd->cmd_status_drv = DCMD_INIT; 38248c2ecf20Sopenharmony_ci instance->instancet->fire_cmd(instance, 38258c2ecf20Sopenharmony_ci cmd->frame_phys_addr, 38268c2ecf20Sopenharmony_ci 0, instance->reg_set); 38278c2ecf20Sopenharmony_ci } else if (cmd->scmd) { 38288c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "%p scsi cmd [%02x]" 38298c2ecf20Sopenharmony_ci "detected on the internal queue, issue again.\n", 38308c2ecf20Sopenharmony_ci cmd, cmd->scmd->cmnd[0]); 38318c2ecf20Sopenharmony_ci 38328c2ecf20Sopenharmony_ci atomic_inc(&instance->fw_outstanding); 38338c2ecf20Sopenharmony_ci instance->instancet->fire_cmd(instance, 38348c2ecf20Sopenharmony_ci cmd->frame_phys_addr, 38358c2ecf20Sopenharmony_ci cmd->frame_count-1, instance->reg_set); 38368c2ecf20Sopenharmony_ci } else { 38378c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "%p unexpected cmd on the" 38388c2ecf20Sopenharmony_ci "internal reset defer list while re-issue!!\n", 38398c2ecf20Sopenharmony_ci cmd); 38408c2ecf20Sopenharmony_ci } 38418c2ecf20Sopenharmony_ci } 38428c2ecf20Sopenharmony_ci 38438c2ecf20Sopenharmony_ci if (instance->aen_cmd) { 38448c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "aen_cmd in def process\n"); 38458c2ecf20Sopenharmony_ci megasas_return_cmd(instance, instance->aen_cmd); 38468c2ecf20Sopenharmony_ci 38478c2ecf20Sopenharmony_ci instance->aen_cmd = NULL; 38488c2ecf20Sopenharmony_ci } 38498c2ecf20Sopenharmony_ci 38508c2ecf20Sopenharmony_ci /* 38518c2ecf20Sopenharmony_ci * Initiate AEN (Asynchronous Event Notification) 38528c2ecf20Sopenharmony_ci */ 38538c2ecf20Sopenharmony_ci seq_num = instance->last_seq_num; 38548c2ecf20Sopenharmony_ci class_locale.members.reserved = 0; 38558c2ecf20Sopenharmony_ci class_locale.members.locale = MR_EVT_LOCALE_ALL; 38568c2ecf20Sopenharmony_ci class_locale.members.class = MR_EVT_CLASS_DEBUG; 38578c2ecf20Sopenharmony_ci 38588c2ecf20Sopenharmony_ci megasas_register_aen(instance, seq_num, class_locale.word); 38598c2ecf20Sopenharmony_ci} 38608c2ecf20Sopenharmony_ci 38618c2ecf20Sopenharmony_ci/* 38628c2ecf20Sopenharmony_ci * Move the internal reset pending commands to a deferred queue. 38638c2ecf20Sopenharmony_ci * 38648c2ecf20Sopenharmony_ci * We move the commands pending at internal reset time to a 38658c2ecf20Sopenharmony_ci * pending queue. This queue would be flushed after successful 38668c2ecf20Sopenharmony_ci * completion of the internal reset sequence. if the internal reset 38678c2ecf20Sopenharmony_ci * did not complete in time, the kernel reset handler would flush 38688c2ecf20Sopenharmony_ci * these commands. 38698c2ecf20Sopenharmony_ci */ 38708c2ecf20Sopenharmony_cistatic void 38718c2ecf20Sopenharmony_cimegasas_internal_reset_defer_cmds(struct megasas_instance *instance) 38728c2ecf20Sopenharmony_ci{ 38738c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 38748c2ecf20Sopenharmony_ci int i; 38758c2ecf20Sopenharmony_ci u16 max_cmd = instance->max_fw_cmds; 38768c2ecf20Sopenharmony_ci u32 defer_index; 38778c2ecf20Sopenharmony_ci unsigned long flags; 38788c2ecf20Sopenharmony_ci 38798c2ecf20Sopenharmony_ci defer_index = 0; 38808c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->mfi_pool_lock, flags); 38818c2ecf20Sopenharmony_ci for (i = 0; i < max_cmd; i++) { 38828c2ecf20Sopenharmony_ci cmd = instance->cmd_list[i]; 38838c2ecf20Sopenharmony_ci if (cmd->sync_cmd == 1 || cmd->scmd) { 38848c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "moving cmd[%d]:%p:%d:%p" 38858c2ecf20Sopenharmony_ci "on the defer queue as internal\n", 38868c2ecf20Sopenharmony_ci defer_index, cmd, cmd->sync_cmd, cmd->scmd); 38878c2ecf20Sopenharmony_ci 38888c2ecf20Sopenharmony_ci if (!list_empty(&cmd->list)) { 38898c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "ERROR while" 38908c2ecf20Sopenharmony_ci " moving this cmd:%p, %d %p, it was" 38918c2ecf20Sopenharmony_ci "discovered on some list?\n", 38928c2ecf20Sopenharmony_ci cmd, cmd->sync_cmd, cmd->scmd); 38938c2ecf20Sopenharmony_ci 38948c2ecf20Sopenharmony_ci list_del_init(&cmd->list); 38958c2ecf20Sopenharmony_ci } 38968c2ecf20Sopenharmony_ci defer_index++; 38978c2ecf20Sopenharmony_ci list_add_tail(&cmd->list, 38988c2ecf20Sopenharmony_ci &instance->internal_reset_pending_q); 38998c2ecf20Sopenharmony_ci } 39008c2ecf20Sopenharmony_ci } 39018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->mfi_pool_lock, flags); 39028c2ecf20Sopenharmony_ci} 39038c2ecf20Sopenharmony_ci 39048c2ecf20Sopenharmony_ci 39058c2ecf20Sopenharmony_cistatic void 39068c2ecf20Sopenharmony_ciprocess_fw_state_change_wq(struct work_struct *work) 39078c2ecf20Sopenharmony_ci{ 39088c2ecf20Sopenharmony_ci struct megasas_instance *instance = 39098c2ecf20Sopenharmony_ci container_of(work, struct megasas_instance, work_init); 39108c2ecf20Sopenharmony_ci u32 wait; 39118c2ecf20Sopenharmony_ci unsigned long flags; 39128c2ecf20Sopenharmony_ci 39138c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) != MEGASAS_ADPRESET_SM_INFAULT) { 39148c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "error, recovery st %x\n", 39158c2ecf20Sopenharmony_ci atomic_read(&instance->adprecovery)); 39168c2ecf20Sopenharmony_ci return ; 39178c2ecf20Sopenharmony_ci } 39188c2ecf20Sopenharmony_ci 39198c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) { 39208c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "FW detected to be in fault" 39218c2ecf20Sopenharmony_ci "state, restarting it...\n"); 39228c2ecf20Sopenharmony_ci 39238c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 39248c2ecf20Sopenharmony_ci atomic_set(&instance->fw_outstanding, 0); 39258c2ecf20Sopenharmony_ci 39268c2ecf20Sopenharmony_ci atomic_set(&instance->fw_reset_no_pci_access, 1); 39278c2ecf20Sopenharmony_ci instance->instancet->adp_reset(instance, instance->reg_set); 39288c2ecf20Sopenharmony_ci atomic_set(&instance->fw_reset_no_pci_access, 0); 39298c2ecf20Sopenharmony_ci 39308c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "FW restarted successfully," 39318c2ecf20Sopenharmony_ci "initiating next stage...\n"); 39328c2ecf20Sopenharmony_ci 39338c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "HBA recovery state machine," 39348c2ecf20Sopenharmony_ci "state 2 starting...\n"); 39358c2ecf20Sopenharmony_ci 39368c2ecf20Sopenharmony_ci /* waiting for about 20 second before start the second init */ 39378c2ecf20Sopenharmony_ci for (wait = 0; wait < 30; wait++) { 39388c2ecf20Sopenharmony_ci msleep(1000); 39398c2ecf20Sopenharmony_ci } 39408c2ecf20Sopenharmony_ci 39418c2ecf20Sopenharmony_ci if (megasas_transition_to_ready(instance, 1)) { 39428c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "adapter not ready\n"); 39438c2ecf20Sopenharmony_ci 39448c2ecf20Sopenharmony_ci atomic_set(&instance->fw_reset_no_pci_access, 1); 39458c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 39468c2ecf20Sopenharmony_ci return ; 39478c2ecf20Sopenharmony_ci } 39488c2ecf20Sopenharmony_ci 39498c2ecf20Sopenharmony_ci if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) || 39508c2ecf20Sopenharmony_ci (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) || 39518c2ecf20Sopenharmony_ci (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR) 39528c2ecf20Sopenharmony_ci ) { 39538c2ecf20Sopenharmony_ci *instance->consumer = *instance->producer; 39548c2ecf20Sopenharmony_ci } else { 39558c2ecf20Sopenharmony_ci *instance->consumer = 0; 39568c2ecf20Sopenharmony_ci *instance->producer = 0; 39578c2ecf20Sopenharmony_ci } 39588c2ecf20Sopenharmony_ci 39598c2ecf20Sopenharmony_ci megasas_issue_init_mfi(instance); 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->hba_lock, flags); 39628c2ecf20Sopenharmony_ci atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL); 39638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->hba_lock, flags); 39648c2ecf20Sopenharmony_ci instance->instancet->enable_intr(instance); 39658c2ecf20Sopenharmony_ci 39668c2ecf20Sopenharmony_ci megasas_issue_pending_cmds_again(instance); 39678c2ecf20Sopenharmony_ci instance->issuepend_done = 1; 39688c2ecf20Sopenharmony_ci } 39698c2ecf20Sopenharmony_ci} 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci/** 39728c2ecf20Sopenharmony_ci * megasas_deplete_reply_queue - Processes all completed commands 39738c2ecf20Sopenharmony_ci * @instance: Adapter soft state 39748c2ecf20Sopenharmony_ci * @alt_status: Alternate status to be returned to 39758c2ecf20Sopenharmony_ci * SCSI mid-layer instead of the status 39768c2ecf20Sopenharmony_ci * returned by the FW 39778c2ecf20Sopenharmony_ci * Note: this must be called with hba lock held 39788c2ecf20Sopenharmony_ci */ 39798c2ecf20Sopenharmony_cistatic int 39808c2ecf20Sopenharmony_cimegasas_deplete_reply_queue(struct megasas_instance *instance, 39818c2ecf20Sopenharmony_ci u8 alt_status) 39828c2ecf20Sopenharmony_ci{ 39838c2ecf20Sopenharmony_ci u32 mfiStatus; 39848c2ecf20Sopenharmony_ci u32 fw_state; 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_ci if ((mfiStatus = instance->instancet->check_reset(instance, 39878c2ecf20Sopenharmony_ci instance->reg_set)) == 1) { 39888c2ecf20Sopenharmony_ci return IRQ_HANDLED; 39898c2ecf20Sopenharmony_ci } 39908c2ecf20Sopenharmony_ci 39918c2ecf20Sopenharmony_ci mfiStatus = instance->instancet->clear_intr(instance); 39928c2ecf20Sopenharmony_ci if (mfiStatus == 0) { 39938c2ecf20Sopenharmony_ci /* Hardware may not set outbound_intr_status in MSI-X mode */ 39948c2ecf20Sopenharmony_ci if (!instance->msix_vectors) 39958c2ecf20Sopenharmony_ci return IRQ_NONE; 39968c2ecf20Sopenharmony_ci } 39978c2ecf20Sopenharmony_ci 39988c2ecf20Sopenharmony_ci instance->mfiStatus = mfiStatus; 39998c2ecf20Sopenharmony_ci 40008c2ecf20Sopenharmony_ci if ((mfiStatus & MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE)) { 40018c2ecf20Sopenharmony_ci fw_state = instance->instancet->read_fw_status_reg( 40028c2ecf20Sopenharmony_ci instance) & MFI_STATE_MASK; 40038c2ecf20Sopenharmony_ci 40048c2ecf20Sopenharmony_ci if (fw_state != MFI_STATE_FAULT) { 40058c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "fw state:%x\n", 40068c2ecf20Sopenharmony_ci fw_state); 40078c2ecf20Sopenharmony_ci } 40088c2ecf20Sopenharmony_ci 40098c2ecf20Sopenharmony_ci if ((fw_state == MFI_STATE_FAULT) && 40108c2ecf20Sopenharmony_ci (instance->disableOnlineCtrlReset == 0)) { 40118c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "wait adp restart\n"); 40128c2ecf20Sopenharmony_ci 40138c2ecf20Sopenharmony_ci if ((instance->pdev->device == 40148c2ecf20Sopenharmony_ci PCI_DEVICE_ID_LSI_SAS1064R) || 40158c2ecf20Sopenharmony_ci (instance->pdev->device == 40168c2ecf20Sopenharmony_ci PCI_DEVICE_ID_DELL_PERC5) || 40178c2ecf20Sopenharmony_ci (instance->pdev->device == 40188c2ecf20Sopenharmony_ci PCI_DEVICE_ID_LSI_VERDE_ZCR)) { 40198c2ecf20Sopenharmony_ci 40208c2ecf20Sopenharmony_ci *instance->consumer = 40218c2ecf20Sopenharmony_ci cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN); 40228c2ecf20Sopenharmony_ci } 40238c2ecf20Sopenharmony_ci 40248c2ecf20Sopenharmony_ci 40258c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 40268c2ecf20Sopenharmony_ci atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT); 40278c2ecf20Sopenharmony_ci instance->issuepend_done = 0; 40288c2ecf20Sopenharmony_ci 40298c2ecf20Sopenharmony_ci atomic_set(&instance->fw_outstanding, 0); 40308c2ecf20Sopenharmony_ci megasas_internal_reset_defer_cmds(instance); 40318c2ecf20Sopenharmony_ci 40328c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "fwState=%x, stage:%d\n", 40338c2ecf20Sopenharmony_ci fw_state, atomic_read(&instance->adprecovery)); 40348c2ecf20Sopenharmony_ci 40358c2ecf20Sopenharmony_ci schedule_work(&instance->work_init); 40368c2ecf20Sopenharmony_ci return IRQ_HANDLED; 40378c2ecf20Sopenharmony_ci 40388c2ecf20Sopenharmony_ci } else { 40398c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "fwstate:%x, dis_OCR=%x\n", 40408c2ecf20Sopenharmony_ci fw_state, instance->disableOnlineCtrlReset); 40418c2ecf20Sopenharmony_ci } 40428c2ecf20Sopenharmony_ci } 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_ci tasklet_schedule(&instance->isr_tasklet); 40458c2ecf20Sopenharmony_ci return IRQ_HANDLED; 40468c2ecf20Sopenharmony_ci} 40478c2ecf20Sopenharmony_ci 40488c2ecf20Sopenharmony_ci/** 40498c2ecf20Sopenharmony_ci * megasas_isr - isr entry point 40508c2ecf20Sopenharmony_ci * @irq: IRQ number 40518c2ecf20Sopenharmony_ci * @devp: IRQ context address 40528c2ecf20Sopenharmony_ci */ 40538c2ecf20Sopenharmony_cistatic irqreturn_t megasas_isr(int irq, void *devp) 40548c2ecf20Sopenharmony_ci{ 40558c2ecf20Sopenharmony_ci struct megasas_irq_context *irq_context = devp; 40568c2ecf20Sopenharmony_ci struct megasas_instance *instance = irq_context->instance; 40578c2ecf20Sopenharmony_ci unsigned long flags; 40588c2ecf20Sopenharmony_ci irqreturn_t rc; 40598c2ecf20Sopenharmony_ci 40608c2ecf20Sopenharmony_ci if (atomic_read(&instance->fw_reset_no_pci_access)) 40618c2ecf20Sopenharmony_ci return IRQ_HANDLED; 40628c2ecf20Sopenharmony_ci 40638c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->hba_lock, flags); 40648c2ecf20Sopenharmony_ci rc = megasas_deplete_reply_queue(instance, DID_OK); 40658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->hba_lock, flags); 40668c2ecf20Sopenharmony_ci 40678c2ecf20Sopenharmony_ci return rc; 40688c2ecf20Sopenharmony_ci} 40698c2ecf20Sopenharmony_ci 40708c2ecf20Sopenharmony_ci/** 40718c2ecf20Sopenharmony_ci * megasas_transition_to_ready - Move the FW to READY state 40728c2ecf20Sopenharmony_ci * @instance: Adapter soft state 40738c2ecf20Sopenharmony_ci * @ocr: Adapter reset state 40748c2ecf20Sopenharmony_ci * 40758c2ecf20Sopenharmony_ci * During the initialization, FW passes can potentially be in any one of 40768c2ecf20Sopenharmony_ci * several possible states. If the FW in operational, waiting-for-handshake 40778c2ecf20Sopenharmony_ci * states, driver must take steps to bring it to ready state. Otherwise, it 40788c2ecf20Sopenharmony_ci * has to wait for the ready state. 40798c2ecf20Sopenharmony_ci */ 40808c2ecf20Sopenharmony_ciint 40818c2ecf20Sopenharmony_cimegasas_transition_to_ready(struct megasas_instance *instance, int ocr) 40828c2ecf20Sopenharmony_ci{ 40838c2ecf20Sopenharmony_ci int i; 40848c2ecf20Sopenharmony_ci u8 max_wait; 40858c2ecf20Sopenharmony_ci u32 fw_state; 40868c2ecf20Sopenharmony_ci u32 abs_state, curr_abs_state; 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci abs_state = instance->instancet->read_fw_status_reg(instance); 40898c2ecf20Sopenharmony_ci fw_state = abs_state & MFI_STATE_MASK; 40908c2ecf20Sopenharmony_ci 40918c2ecf20Sopenharmony_ci if (fw_state != MFI_STATE_READY) 40928c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Waiting for FW to come to ready" 40938c2ecf20Sopenharmony_ci " state\n"); 40948c2ecf20Sopenharmony_ci 40958c2ecf20Sopenharmony_ci while (fw_state != MFI_STATE_READY) { 40968c2ecf20Sopenharmony_ci 40978c2ecf20Sopenharmony_ci switch (fw_state) { 40988c2ecf20Sopenharmony_ci 40998c2ecf20Sopenharmony_ci case MFI_STATE_FAULT: 41008c2ecf20Sopenharmony_ci dev_printk(KERN_ERR, &instance->pdev->dev, 41018c2ecf20Sopenharmony_ci "FW in FAULT state, Fault code:0x%x subcode:0x%x func:%s\n", 41028c2ecf20Sopenharmony_ci abs_state & MFI_STATE_FAULT_CODE, 41038c2ecf20Sopenharmony_ci abs_state & MFI_STATE_FAULT_SUBCODE, __func__); 41048c2ecf20Sopenharmony_ci if (ocr) { 41058c2ecf20Sopenharmony_ci max_wait = MEGASAS_RESET_WAIT_TIME; 41068c2ecf20Sopenharmony_ci break; 41078c2ecf20Sopenharmony_ci } else { 41088c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n"); 41098c2ecf20Sopenharmony_ci megasas_dump_reg_set(instance->reg_set); 41108c2ecf20Sopenharmony_ci return -ENODEV; 41118c2ecf20Sopenharmony_ci } 41128c2ecf20Sopenharmony_ci 41138c2ecf20Sopenharmony_ci case MFI_STATE_WAIT_HANDSHAKE: 41148c2ecf20Sopenharmony_ci /* 41158c2ecf20Sopenharmony_ci * Set the CLR bit in inbound doorbell 41168c2ecf20Sopenharmony_ci */ 41178c2ecf20Sopenharmony_ci if ((instance->pdev->device == 41188c2ecf20Sopenharmony_ci PCI_DEVICE_ID_LSI_SAS0073SKINNY) || 41198c2ecf20Sopenharmony_ci (instance->pdev->device == 41208c2ecf20Sopenharmony_ci PCI_DEVICE_ID_LSI_SAS0071SKINNY) || 41218c2ecf20Sopenharmony_ci (instance->adapter_type != MFI_SERIES)) 41228c2ecf20Sopenharmony_ci writel( 41238c2ecf20Sopenharmony_ci MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, 41248c2ecf20Sopenharmony_ci &instance->reg_set->doorbell); 41258c2ecf20Sopenharmony_ci else 41268c2ecf20Sopenharmony_ci writel( 41278c2ecf20Sopenharmony_ci MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, 41288c2ecf20Sopenharmony_ci &instance->reg_set->inbound_doorbell); 41298c2ecf20Sopenharmony_ci 41308c2ecf20Sopenharmony_ci max_wait = MEGASAS_RESET_WAIT_TIME; 41318c2ecf20Sopenharmony_ci break; 41328c2ecf20Sopenharmony_ci 41338c2ecf20Sopenharmony_ci case MFI_STATE_BOOT_MESSAGE_PENDING: 41348c2ecf20Sopenharmony_ci if ((instance->pdev->device == 41358c2ecf20Sopenharmony_ci PCI_DEVICE_ID_LSI_SAS0073SKINNY) || 41368c2ecf20Sopenharmony_ci (instance->pdev->device == 41378c2ecf20Sopenharmony_ci PCI_DEVICE_ID_LSI_SAS0071SKINNY) || 41388c2ecf20Sopenharmony_ci (instance->adapter_type != MFI_SERIES)) 41398c2ecf20Sopenharmony_ci writel(MFI_INIT_HOTPLUG, 41408c2ecf20Sopenharmony_ci &instance->reg_set->doorbell); 41418c2ecf20Sopenharmony_ci else 41428c2ecf20Sopenharmony_ci writel(MFI_INIT_HOTPLUG, 41438c2ecf20Sopenharmony_ci &instance->reg_set->inbound_doorbell); 41448c2ecf20Sopenharmony_ci 41458c2ecf20Sopenharmony_ci max_wait = MEGASAS_RESET_WAIT_TIME; 41468c2ecf20Sopenharmony_ci break; 41478c2ecf20Sopenharmony_ci 41488c2ecf20Sopenharmony_ci case MFI_STATE_OPERATIONAL: 41498c2ecf20Sopenharmony_ci /* 41508c2ecf20Sopenharmony_ci * Bring it to READY state; assuming max wait 10 secs 41518c2ecf20Sopenharmony_ci */ 41528c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 41538c2ecf20Sopenharmony_ci if ((instance->pdev->device == 41548c2ecf20Sopenharmony_ci PCI_DEVICE_ID_LSI_SAS0073SKINNY) || 41558c2ecf20Sopenharmony_ci (instance->pdev->device == 41568c2ecf20Sopenharmony_ci PCI_DEVICE_ID_LSI_SAS0071SKINNY) || 41578c2ecf20Sopenharmony_ci (instance->adapter_type != MFI_SERIES)) { 41588c2ecf20Sopenharmony_ci writel(MFI_RESET_FLAGS, 41598c2ecf20Sopenharmony_ci &instance->reg_set->doorbell); 41608c2ecf20Sopenharmony_ci 41618c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) { 41628c2ecf20Sopenharmony_ci for (i = 0; i < (10 * 1000); i += 20) { 41638c2ecf20Sopenharmony_ci if (megasas_readl( 41648c2ecf20Sopenharmony_ci instance, 41658c2ecf20Sopenharmony_ci &instance-> 41668c2ecf20Sopenharmony_ci reg_set-> 41678c2ecf20Sopenharmony_ci doorbell) & 1) 41688c2ecf20Sopenharmony_ci msleep(20); 41698c2ecf20Sopenharmony_ci else 41708c2ecf20Sopenharmony_ci break; 41718c2ecf20Sopenharmony_ci } 41728c2ecf20Sopenharmony_ci } 41738c2ecf20Sopenharmony_ci } else 41748c2ecf20Sopenharmony_ci writel(MFI_RESET_FLAGS, 41758c2ecf20Sopenharmony_ci &instance->reg_set->inbound_doorbell); 41768c2ecf20Sopenharmony_ci 41778c2ecf20Sopenharmony_ci max_wait = MEGASAS_RESET_WAIT_TIME; 41788c2ecf20Sopenharmony_ci break; 41798c2ecf20Sopenharmony_ci 41808c2ecf20Sopenharmony_ci case MFI_STATE_UNDEFINED: 41818c2ecf20Sopenharmony_ci /* 41828c2ecf20Sopenharmony_ci * This state should not last for more than 2 seconds 41838c2ecf20Sopenharmony_ci */ 41848c2ecf20Sopenharmony_ci max_wait = MEGASAS_RESET_WAIT_TIME; 41858c2ecf20Sopenharmony_ci break; 41868c2ecf20Sopenharmony_ci 41878c2ecf20Sopenharmony_ci case MFI_STATE_BB_INIT: 41888c2ecf20Sopenharmony_ci max_wait = MEGASAS_RESET_WAIT_TIME; 41898c2ecf20Sopenharmony_ci break; 41908c2ecf20Sopenharmony_ci 41918c2ecf20Sopenharmony_ci case MFI_STATE_FW_INIT: 41928c2ecf20Sopenharmony_ci max_wait = MEGASAS_RESET_WAIT_TIME; 41938c2ecf20Sopenharmony_ci break; 41948c2ecf20Sopenharmony_ci 41958c2ecf20Sopenharmony_ci case MFI_STATE_FW_INIT_2: 41968c2ecf20Sopenharmony_ci max_wait = MEGASAS_RESET_WAIT_TIME; 41978c2ecf20Sopenharmony_ci break; 41988c2ecf20Sopenharmony_ci 41998c2ecf20Sopenharmony_ci case MFI_STATE_DEVICE_SCAN: 42008c2ecf20Sopenharmony_ci max_wait = MEGASAS_RESET_WAIT_TIME; 42018c2ecf20Sopenharmony_ci break; 42028c2ecf20Sopenharmony_ci 42038c2ecf20Sopenharmony_ci case MFI_STATE_FLUSH_CACHE: 42048c2ecf20Sopenharmony_ci max_wait = MEGASAS_RESET_WAIT_TIME; 42058c2ecf20Sopenharmony_ci break; 42068c2ecf20Sopenharmony_ci 42078c2ecf20Sopenharmony_ci default: 42088c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "Unknown state 0x%x\n", 42098c2ecf20Sopenharmony_ci fw_state); 42108c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n"); 42118c2ecf20Sopenharmony_ci megasas_dump_reg_set(instance->reg_set); 42128c2ecf20Sopenharmony_ci return -ENODEV; 42138c2ecf20Sopenharmony_ci } 42148c2ecf20Sopenharmony_ci 42158c2ecf20Sopenharmony_ci /* 42168c2ecf20Sopenharmony_ci * The cur_state should not last for more than max_wait secs 42178c2ecf20Sopenharmony_ci */ 42188c2ecf20Sopenharmony_ci for (i = 0; i < max_wait * 50; i++) { 42198c2ecf20Sopenharmony_ci curr_abs_state = instance->instancet-> 42208c2ecf20Sopenharmony_ci read_fw_status_reg(instance); 42218c2ecf20Sopenharmony_ci 42228c2ecf20Sopenharmony_ci if (abs_state == curr_abs_state) { 42238c2ecf20Sopenharmony_ci msleep(20); 42248c2ecf20Sopenharmony_ci } else 42258c2ecf20Sopenharmony_ci break; 42268c2ecf20Sopenharmony_ci } 42278c2ecf20Sopenharmony_ci 42288c2ecf20Sopenharmony_ci /* 42298c2ecf20Sopenharmony_ci * Return error if fw_state hasn't changed after max_wait 42308c2ecf20Sopenharmony_ci */ 42318c2ecf20Sopenharmony_ci if (curr_abs_state == abs_state) { 42328c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW state [%d] hasn't changed " 42338c2ecf20Sopenharmony_ci "in %d secs\n", fw_state, max_wait); 42348c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n"); 42358c2ecf20Sopenharmony_ci megasas_dump_reg_set(instance->reg_set); 42368c2ecf20Sopenharmony_ci return -ENODEV; 42378c2ecf20Sopenharmony_ci } 42388c2ecf20Sopenharmony_ci 42398c2ecf20Sopenharmony_ci abs_state = curr_abs_state; 42408c2ecf20Sopenharmony_ci fw_state = curr_abs_state & MFI_STATE_MASK; 42418c2ecf20Sopenharmony_ci } 42428c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "FW now in Ready state\n"); 42438c2ecf20Sopenharmony_ci 42448c2ecf20Sopenharmony_ci return 0; 42458c2ecf20Sopenharmony_ci} 42468c2ecf20Sopenharmony_ci 42478c2ecf20Sopenharmony_ci/** 42488c2ecf20Sopenharmony_ci * megasas_teardown_frame_pool - Destroy the cmd frame DMA pool 42498c2ecf20Sopenharmony_ci * @instance: Adapter soft state 42508c2ecf20Sopenharmony_ci */ 42518c2ecf20Sopenharmony_cistatic void megasas_teardown_frame_pool(struct megasas_instance *instance) 42528c2ecf20Sopenharmony_ci{ 42538c2ecf20Sopenharmony_ci int i; 42548c2ecf20Sopenharmony_ci u16 max_cmd = instance->max_mfi_cmds; 42558c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 42568c2ecf20Sopenharmony_ci 42578c2ecf20Sopenharmony_ci if (!instance->frame_dma_pool) 42588c2ecf20Sopenharmony_ci return; 42598c2ecf20Sopenharmony_ci 42608c2ecf20Sopenharmony_ci /* 42618c2ecf20Sopenharmony_ci * Return all frames to pool 42628c2ecf20Sopenharmony_ci */ 42638c2ecf20Sopenharmony_ci for (i = 0; i < max_cmd; i++) { 42648c2ecf20Sopenharmony_ci 42658c2ecf20Sopenharmony_ci cmd = instance->cmd_list[i]; 42668c2ecf20Sopenharmony_ci 42678c2ecf20Sopenharmony_ci if (cmd->frame) 42688c2ecf20Sopenharmony_ci dma_pool_free(instance->frame_dma_pool, cmd->frame, 42698c2ecf20Sopenharmony_ci cmd->frame_phys_addr); 42708c2ecf20Sopenharmony_ci 42718c2ecf20Sopenharmony_ci if (cmd->sense) 42728c2ecf20Sopenharmony_ci dma_pool_free(instance->sense_dma_pool, cmd->sense, 42738c2ecf20Sopenharmony_ci cmd->sense_phys_addr); 42748c2ecf20Sopenharmony_ci } 42758c2ecf20Sopenharmony_ci 42768c2ecf20Sopenharmony_ci /* 42778c2ecf20Sopenharmony_ci * Now destroy the pool itself 42788c2ecf20Sopenharmony_ci */ 42798c2ecf20Sopenharmony_ci dma_pool_destroy(instance->frame_dma_pool); 42808c2ecf20Sopenharmony_ci dma_pool_destroy(instance->sense_dma_pool); 42818c2ecf20Sopenharmony_ci 42828c2ecf20Sopenharmony_ci instance->frame_dma_pool = NULL; 42838c2ecf20Sopenharmony_ci instance->sense_dma_pool = NULL; 42848c2ecf20Sopenharmony_ci} 42858c2ecf20Sopenharmony_ci 42868c2ecf20Sopenharmony_ci/** 42878c2ecf20Sopenharmony_ci * megasas_create_frame_pool - Creates DMA pool for cmd frames 42888c2ecf20Sopenharmony_ci * @instance: Adapter soft state 42898c2ecf20Sopenharmony_ci * 42908c2ecf20Sopenharmony_ci * Each command packet has an embedded DMA memory buffer that is used for 42918c2ecf20Sopenharmony_ci * filling MFI frame and the SG list that immediately follows the frame. This 42928c2ecf20Sopenharmony_ci * function creates those DMA memory buffers for each command packet by using 42938c2ecf20Sopenharmony_ci * PCI pool facility. 42948c2ecf20Sopenharmony_ci */ 42958c2ecf20Sopenharmony_cistatic int megasas_create_frame_pool(struct megasas_instance *instance) 42968c2ecf20Sopenharmony_ci{ 42978c2ecf20Sopenharmony_ci int i; 42988c2ecf20Sopenharmony_ci u16 max_cmd; 42998c2ecf20Sopenharmony_ci u32 frame_count; 43008c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 43018c2ecf20Sopenharmony_ci 43028c2ecf20Sopenharmony_ci max_cmd = instance->max_mfi_cmds; 43038c2ecf20Sopenharmony_ci 43048c2ecf20Sopenharmony_ci /* 43058c2ecf20Sopenharmony_ci * For MFI controllers. 43068c2ecf20Sopenharmony_ci * max_num_sge = 60 43078c2ecf20Sopenharmony_ci * max_sge_sz = 16 byte (sizeof megasas_sge_skinny) 43088c2ecf20Sopenharmony_ci * Total 960 byte (15 MFI frame of 64 byte) 43098c2ecf20Sopenharmony_ci * 43108c2ecf20Sopenharmony_ci * Fusion adapter require only 3 extra frame. 43118c2ecf20Sopenharmony_ci * max_num_sge = 16 (defined as MAX_IOCTL_SGE) 43128c2ecf20Sopenharmony_ci * max_sge_sz = 12 byte (sizeof megasas_sge64) 43138c2ecf20Sopenharmony_ci * Total 192 byte (3 MFI frame of 64 byte) 43148c2ecf20Sopenharmony_ci */ 43158c2ecf20Sopenharmony_ci frame_count = (instance->adapter_type == MFI_SERIES) ? 43168c2ecf20Sopenharmony_ci (15 + 1) : (3 + 1); 43178c2ecf20Sopenharmony_ci instance->mfi_frame_size = MEGAMFI_FRAME_SIZE * frame_count; 43188c2ecf20Sopenharmony_ci /* 43198c2ecf20Sopenharmony_ci * Use DMA pool facility provided by PCI layer 43208c2ecf20Sopenharmony_ci */ 43218c2ecf20Sopenharmony_ci instance->frame_dma_pool = dma_pool_create("megasas frame pool", 43228c2ecf20Sopenharmony_ci &instance->pdev->dev, 43238c2ecf20Sopenharmony_ci instance->mfi_frame_size, 256, 0); 43248c2ecf20Sopenharmony_ci 43258c2ecf20Sopenharmony_ci if (!instance->frame_dma_pool) { 43268c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup frame pool\n"); 43278c2ecf20Sopenharmony_ci return -ENOMEM; 43288c2ecf20Sopenharmony_ci } 43298c2ecf20Sopenharmony_ci 43308c2ecf20Sopenharmony_ci instance->sense_dma_pool = dma_pool_create("megasas sense pool", 43318c2ecf20Sopenharmony_ci &instance->pdev->dev, 128, 43328c2ecf20Sopenharmony_ci 4, 0); 43338c2ecf20Sopenharmony_ci 43348c2ecf20Sopenharmony_ci if (!instance->sense_dma_pool) { 43358c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool\n"); 43368c2ecf20Sopenharmony_ci 43378c2ecf20Sopenharmony_ci dma_pool_destroy(instance->frame_dma_pool); 43388c2ecf20Sopenharmony_ci instance->frame_dma_pool = NULL; 43398c2ecf20Sopenharmony_ci 43408c2ecf20Sopenharmony_ci return -ENOMEM; 43418c2ecf20Sopenharmony_ci } 43428c2ecf20Sopenharmony_ci 43438c2ecf20Sopenharmony_ci /* 43448c2ecf20Sopenharmony_ci * Allocate and attach a frame to each of the commands in cmd_list. 43458c2ecf20Sopenharmony_ci * By making cmd->index as the context instead of the &cmd, we can 43468c2ecf20Sopenharmony_ci * always use 32bit context regardless of the architecture 43478c2ecf20Sopenharmony_ci */ 43488c2ecf20Sopenharmony_ci for (i = 0; i < max_cmd; i++) { 43498c2ecf20Sopenharmony_ci 43508c2ecf20Sopenharmony_ci cmd = instance->cmd_list[i]; 43518c2ecf20Sopenharmony_ci 43528c2ecf20Sopenharmony_ci cmd->frame = dma_pool_zalloc(instance->frame_dma_pool, 43538c2ecf20Sopenharmony_ci GFP_KERNEL, &cmd->frame_phys_addr); 43548c2ecf20Sopenharmony_ci 43558c2ecf20Sopenharmony_ci cmd->sense = dma_pool_alloc(instance->sense_dma_pool, 43568c2ecf20Sopenharmony_ci GFP_KERNEL, &cmd->sense_phys_addr); 43578c2ecf20Sopenharmony_ci 43588c2ecf20Sopenharmony_ci /* 43598c2ecf20Sopenharmony_ci * megasas_teardown_frame_pool() takes care of freeing 43608c2ecf20Sopenharmony_ci * whatever has been allocated 43618c2ecf20Sopenharmony_ci */ 43628c2ecf20Sopenharmony_ci if (!cmd->frame || !cmd->sense) { 43638c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "dma_pool_alloc failed\n"); 43648c2ecf20Sopenharmony_ci megasas_teardown_frame_pool(instance); 43658c2ecf20Sopenharmony_ci return -ENOMEM; 43668c2ecf20Sopenharmony_ci } 43678c2ecf20Sopenharmony_ci 43688c2ecf20Sopenharmony_ci cmd->frame->io.context = cpu_to_le32(cmd->index); 43698c2ecf20Sopenharmony_ci cmd->frame->io.pad_0 = 0; 43708c2ecf20Sopenharmony_ci if ((instance->adapter_type == MFI_SERIES) && reset_devices) 43718c2ecf20Sopenharmony_ci cmd->frame->hdr.cmd = MFI_CMD_INVALID; 43728c2ecf20Sopenharmony_ci } 43738c2ecf20Sopenharmony_ci 43748c2ecf20Sopenharmony_ci return 0; 43758c2ecf20Sopenharmony_ci} 43768c2ecf20Sopenharmony_ci 43778c2ecf20Sopenharmony_ci/** 43788c2ecf20Sopenharmony_ci * megasas_free_cmds - Free all the cmds in the free cmd pool 43798c2ecf20Sopenharmony_ci * @instance: Adapter soft state 43808c2ecf20Sopenharmony_ci */ 43818c2ecf20Sopenharmony_civoid megasas_free_cmds(struct megasas_instance *instance) 43828c2ecf20Sopenharmony_ci{ 43838c2ecf20Sopenharmony_ci int i; 43848c2ecf20Sopenharmony_ci 43858c2ecf20Sopenharmony_ci /* First free the MFI frame pool */ 43868c2ecf20Sopenharmony_ci megasas_teardown_frame_pool(instance); 43878c2ecf20Sopenharmony_ci 43888c2ecf20Sopenharmony_ci /* Free all the commands in the cmd_list */ 43898c2ecf20Sopenharmony_ci for (i = 0; i < instance->max_mfi_cmds; i++) 43908c2ecf20Sopenharmony_ci 43918c2ecf20Sopenharmony_ci kfree(instance->cmd_list[i]); 43928c2ecf20Sopenharmony_ci 43938c2ecf20Sopenharmony_ci /* Free the cmd_list buffer itself */ 43948c2ecf20Sopenharmony_ci kfree(instance->cmd_list); 43958c2ecf20Sopenharmony_ci instance->cmd_list = NULL; 43968c2ecf20Sopenharmony_ci 43978c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&instance->cmd_pool); 43988c2ecf20Sopenharmony_ci} 43998c2ecf20Sopenharmony_ci 44008c2ecf20Sopenharmony_ci/** 44018c2ecf20Sopenharmony_ci * megasas_alloc_cmds - Allocates the command packets 44028c2ecf20Sopenharmony_ci * @instance: Adapter soft state 44038c2ecf20Sopenharmony_ci * 44048c2ecf20Sopenharmony_ci * Each command that is issued to the FW, whether IO commands from the OS or 44058c2ecf20Sopenharmony_ci * internal commands like IOCTLs, are wrapped in local data structure called 44068c2ecf20Sopenharmony_ci * megasas_cmd. The frame embedded in this megasas_cmd is actually issued to 44078c2ecf20Sopenharmony_ci * the FW. 44088c2ecf20Sopenharmony_ci * 44098c2ecf20Sopenharmony_ci * Each frame has a 32-bit field called context (tag). This context is used 44108c2ecf20Sopenharmony_ci * to get back the megasas_cmd from the frame when a frame gets completed in 44118c2ecf20Sopenharmony_ci * the ISR. Typically the address of the megasas_cmd itself would be used as 44128c2ecf20Sopenharmony_ci * the context. But we wanted to keep the differences between 32 and 64 bit 44138c2ecf20Sopenharmony_ci * systems to the mininum. We always use 32 bit integers for the context. In 44148c2ecf20Sopenharmony_ci * this driver, the 32 bit values are the indices into an array cmd_list. 44158c2ecf20Sopenharmony_ci * This array is used only to look up the megasas_cmd given the context. The 44168c2ecf20Sopenharmony_ci * free commands themselves are maintained in a linked list called cmd_pool. 44178c2ecf20Sopenharmony_ci */ 44188c2ecf20Sopenharmony_ciint megasas_alloc_cmds(struct megasas_instance *instance) 44198c2ecf20Sopenharmony_ci{ 44208c2ecf20Sopenharmony_ci int i; 44218c2ecf20Sopenharmony_ci int j; 44228c2ecf20Sopenharmony_ci u16 max_cmd; 44238c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 44248c2ecf20Sopenharmony_ci 44258c2ecf20Sopenharmony_ci max_cmd = instance->max_mfi_cmds; 44268c2ecf20Sopenharmony_ci 44278c2ecf20Sopenharmony_ci /* 44288c2ecf20Sopenharmony_ci * instance->cmd_list is an array of struct megasas_cmd pointers. 44298c2ecf20Sopenharmony_ci * Allocate the dynamic array first and then allocate individual 44308c2ecf20Sopenharmony_ci * commands. 44318c2ecf20Sopenharmony_ci */ 44328c2ecf20Sopenharmony_ci instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL); 44338c2ecf20Sopenharmony_ci 44348c2ecf20Sopenharmony_ci if (!instance->cmd_list) { 44358c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory\n"); 44368c2ecf20Sopenharmony_ci return -ENOMEM; 44378c2ecf20Sopenharmony_ci } 44388c2ecf20Sopenharmony_ci 44398c2ecf20Sopenharmony_ci memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) *max_cmd); 44408c2ecf20Sopenharmony_ci 44418c2ecf20Sopenharmony_ci for (i = 0; i < max_cmd; i++) { 44428c2ecf20Sopenharmony_ci instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd), 44438c2ecf20Sopenharmony_ci GFP_KERNEL); 44448c2ecf20Sopenharmony_ci 44458c2ecf20Sopenharmony_ci if (!instance->cmd_list[i]) { 44468c2ecf20Sopenharmony_ci 44478c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) 44488c2ecf20Sopenharmony_ci kfree(instance->cmd_list[j]); 44498c2ecf20Sopenharmony_ci 44508c2ecf20Sopenharmony_ci kfree(instance->cmd_list); 44518c2ecf20Sopenharmony_ci instance->cmd_list = NULL; 44528c2ecf20Sopenharmony_ci 44538c2ecf20Sopenharmony_ci return -ENOMEM; 44548c2ecf20Sopenharmony_ci } 44558c2ecf20Sopenharmony_ci } 44568c2ecf20Sopenharmony_ci 44578c2ecf20Sopenharmony_ci for (i = 0; i < max_cmd; i++) { 44588c2ecf20Sopenharmony_ci cmd = instance->cmd_list[i]; 44598c2ecf20Sopenharmony_ci memset(cmd, 0, sizeof(struct megasas_cmd)); 44608c2ecf20Sopenharmony_ci cmd->index = i; 44618c2ecf20Sopenharmony_ci cmd->scmd = NULL; 44628c2ecf20Sopenharmony_ci cmd->instance = instance; 44638c2ecf20Sopenharmony_ci 44648c2ecf20Sopenharmony_ci list_add_tail(&cmd->list, &instance->cmd_pool); 44658c2ecf20Sopenharmony_ci } 44668c2ecf20Sopenharmony_ci 44678c2ecf20Sopenharmony_ci /* 44688c2ecf20Sopenharmony_ci * Create a frame pool and assign one frame to each cmd 44698c2ecf20Sopenharmony_ci */ 44708c2ecf20Sopenharmony_ci if (megasas_create_frame_pool(instance)) { 44718c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n"); 44728c2ecf20Sopenharmony_ci megasas_free_cmds(instance); 44738c2ecf20Sopenharmony_ci return -ENOMEM; 44748c2ecf20Sopenharmony_ci } 44758c2ecf20Sopenharmony_ci 44768c2ecf20Sopenharmony_ci return 0; 44778c2ecf20Sopenharmony_ci} 44788c2ecf20Sopenharmony_ci 44798c2ecf20Sopenharmony_ci/* 44808c2ecf20Sopenharmony_ci * dcmd_timeout_ocr_possible - Check if OCR is possible based on Driver/FW state. 44818c2ecf20Sopenharmony_ci * @instance: Adapter soft state 44828c2ecf20Sopenharmony_ci * 44838c2ecf20Sopenharmony_ci * Return 0 for only Fusion adapter, if driver load/unload is not in progress 44848c2ecf20Sopenharmony_ci * or FW is not under OCR. 44858c2ecf20Sopenharmony_ci */ 44868c2ecf20Sopenharmony_ciinline int 44878c2ecf20Sopenharmony_cidcmd_timeout_ocr_possible(struct megasas_instance *instance) { 44888c2ecf20Sopenharmony_ci 44898c2ecf20Sopenharmony_ci if (instance->adapter_type == MFI_SERIES) 44908c2ecf20Sopenharmony_ci return KILL_ADAPTER; 44918c2ecf20Sopenharmony_ci else if (instance->unload || 44928c2ecf20Sopenharmony_ci test_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE, 44938c2ecf20Sopenharmony_ci &instance->reset_flags)) 44948c2ecf20Sopenharmony_ci return IGNORE_TIMEOUT; 44958c2ecf20Sopenharmony_ci else 44968c2ecf20Sopenharmony_ci return INITIATE_OCR; 44978c2ecf20Sopenharmony_ci} 44988c2ecf20Sopenharmony_ci 44998c2ecf20Sopenharmony_cistatic void 45008c2ecf20Sopenharmony_cimegasas_get_pd_info(struct megasas_instance *instance, struct scsi_device *sdev) 45018c2ecf20Sopenharmony_ci{ 45028c2ecf20Sopenharmony_ci int ret; 45038c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 45048c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 45058c2ecf20Sopenharmony_ci 45068c2ecf20Sopenharmony_ci struct MR_PRIV_DEVICE *mr_device_priv_data; 45078c2ecf20Sopenharmony_ci u16 device_id = 0; 45088c2ecf20Sopenharmony_ci 45098c2ecf20Sopenharmony_ci device_id = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id; 45108c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 45118c2ecf20Sopenharmony_ci 45128c2ecf20Sopenharmony_ci if (!cmd) { 45138c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed to get cmd %s\n", __func__); 45148c2ecf20Sopenharmony_ci return; 45158c2ecf20Sopenharmony_ci } 45168c2ecf20Sopenharmony_ci 45178c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 45188c2ecf20Sopenharmony_ci 45198c2ecf20Sopenharmony_ci memset(instance->pd_info, 0, sizeof(*instance->pd_info)); 45208c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 45218c2ecf20Sopenharmony_ci 45228c2ecf20Sopenharmony_ci dcmd->mbox.s[0] = cpu_to_le16(device_id); 45238c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 45248c2ecf20Sopenharmony_ci dcmd->cmd_status = 0xFF; 45258c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 45268c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_READ; 45278c2ecf20Sopenharmony_ci dcmd->timeout = 0; 45288c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 45298c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_PD_INFO)); 45308c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_PD_GET_INFO); 45318c2ecf20Sopenharmony_ci 45328c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, instance->pd_info_h, 45338c2ecf20Sopenharmony_ci sizeof(struct MR_PD_INFO)); 45348c2ecf20Sopenharmony_ci 45358c2ecf20Sopenharmony_ci if ((instance->adapter_type != MFI_SERIES) && 45368c2ecf20Sopenharmony_ci !instance->mask_interrupts) 45378c2ecf20Sopenharmony_ci ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS); 45388c2ecf20Sopenharmony_ci else 45398c2ecf20Sopenharmony_ci ret = megasas_issue_polled(instance, cmd); 45408c2ecf20Sopenharmony_ci 45418c2ecf20Sopenharmony_ci switch (ret) { 45428c2ecf20Sopenharmony_ci case DCMD_SUCCESS: 45438c2ecf20Sopenharmony_ci mr_device_priv_data = sdev->hostdata; 45448c2ecf20Sopenharmony_ci le16_to_cpus((u16 *)&instance->pd_info->state.ddf.pdType); 45458c2ecf20Sopenharmony_ci mr_device_priv_data->interface_type = 45468c2ecf20Sopenharmony_ci instance->pd_info->state.ddf.pdType.intf; 45478c2ecf20Sopenharmony_ci break; 45488c2ecf20Sopenharmony_ci 45498c2ecf20Sopenharmony_ci case DCMD_TIMEOUT: 45508c2ecf20Sopenharmony_ci 45518c2ecf20Sopenharmony_ci switch (dcmd_timeout_ocr_possible(instance)) { 45528c2ecf20Sopenharmony_ci case INITIATE_OCR: 45538c2ecf20Sopenharmony_ci cmd->flags |= DRV_DCMD_SKIP_REFIRE; 45548c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 45558c2ecf20Sopenharmony_ci megasas_reset_fusion(instance->host, 45568c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_OCR); 45578c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 45588c2ecf20Sopenharmony_ci break; 45598c2ecf20Sopenharmony_ci case KILL_ADAPTER: 45608c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 45618c2ecf20Sopenharmony_ci break; 45628c2ecf20Sopenharmony_ci case IGNORE_TIMEOUT: 45638c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n", 45648c2ecf20Sopenharmony_ci __func__, __LINE__); 45658c2ecf20Sopenharmony_ci break; 45668c2ecf20Sopenharmony_ci } 45678c2ecf20Sopenharmony_ci 45688c2ecf20Sopenharmony_ci break; 45698c2ecf20Sopenharmony_ci } 45708c2ecf20Sopenharmony_ci 45718c2ecf20Sopenharmony_ci if (ret != DCMD_TIMEOUT) 45728c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 45738c2ecf20Sopenharmony_ci 45748c2ecf20Sopenharmony_ci return; 45758c2ecf20Sopenharmony_ci} 45768c2ecf20Sopenharmony_ci/* 45778c2ecf20Sopenharmony_ci * megasas_get_pd_list_info - Returns FW's pd_list structure 45788c2ecf20Sopenharmony_ci * @instance: Adapter soft state 45798c2ecf20Sopenharmony_ci * @pd_list: pd_list structure 45808c2ecf20Sopenharmony_ci * 45818c2ecf20Sopenharmony_ci * Issues an internal command (DCMD) to get the FW's controller PD 45828c2ecf20Sopenharmony_ci * list structure. This information is mainly used to find out SYSTEM 45838c2ecf20Sopenharmony_ci * supported by the FW. 45848c2ecf20Sopenharmony_ci */ 45858c2ecf20Sopenharmony_cistatic int 45868c2ecf20Sopenharmony_cimegasas_get_pd_list(struct megasas_instance *instance) 45878c2ecf20Sopenharmony_ci{ 45888c2ecf20Sopenharmony_ci int ret = 0, pd_index = 0; 45898c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 45908c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 45918c2ecf20Sopenharmony_ci struct MR_PD_LIST *ci; 45928c2ecf20Sopenharmony_ci struct MR_PD_ADDRESS *pd_addr; 45938c2ecf20Sopenharmony_ci 45948c2ecf20Sopenharmony_ci if (instance->pd_list_not_supported) { 45958c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY " 45968c2ecf20Sopenharmony_ci "not supported by firmware\n"); 45978c2ecf20Sopenharmony_ci return ret; 45988c2ecf20Sopenharmony_ci } 45998c2ecf20Sopenharmony_ci 46008c2ecf20Sopenharmony_ci ci = instance->pd_list_buf; 46018c2ecf20Sopenharmony_ci 46028c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 46038c2ecf20Sopenharmony_ci 46048c2ecf20Sopenharmony_ci if (!cmd) { 46058c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "(get_pd_list): Failed to get cmd\n"); 46068c2ecf20Sopenharmony_ci return -ENOMEM; 46078c2ecf20Sopenharmony_ci } 46088c2ecf20Sopenharmony_ci 46098c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 46108c2ecf20Sopenharmony_ci 46118c2ecf20Sopenharmony_ci memset(ci, 0, sizeof(*ci)); 46128c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 46138c2ecf20Sopenharmony_ci 46148c2ecf20Sopenharmony_ci dcmd->mbox.b[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST; 46158c2ecf20Sopenharmony_ci dcmd->mbox.b[1] = 0; 46168c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 46178c2ecf20Sopenharmony_ci dcmd->cmd_status = MFI_STAT_INVALID_STATUS; 46188c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 46198c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_READ; 46208c2ecf20Sopenharmony_ci dcmd->timeout = 0; 46218c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 46228c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST)); 46238c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_PD_LIST_QUERY); 46248c2ecf20Sopenharmony_ci 46258c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, instance->pd_list_buf_h, 46268c2ecf20Sopenharmony_ci (MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST))); 46278c2ecf20Sopenharmony_ci 46288c2ecf20Sopenharmony_ci if ((instance->adapter_type != MFI_SERIES) && 46298c2ecf20Sopenharmony_ci !instance->mask_interrupts) 46308c2ecf20Sopenharmony_ci ret = megasas_issue_blocked_cmd(instance, cmd, 46318c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_SECS); 46328c2ecf20Sopenharmony_ci else 46338c2ecf20Sopenharmony_ci ret = megasas_issue_polled(instance, cmd); 46348c2ecf20Sopenharmony_ci 46358c2ecf20Sopenharmony_ci switch (ret) { 46368c2ecf20Sopenharmony_ci case DCMD_FAILED: 46378c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY " 46388c2ecf20Sopenharmony_ci "failed/not supported by firmware\n"); 46398c2ecf20Sopenharmony_ci 46408c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) 46418c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 46428c2ecf20Sopenharmony_ci else 46438c2ecf20Sopenharmony_ci instance->pd_list_not_supported = 1; 46448c2ecf20Sopenharmony_ci break; 46458c2ecf20Sopenharmony_ci case DCMD_TIMEOUT: 46468c2ecf20Sopenharmony_ci 46478c2ecf20Sopenharmony_ci switch (dcmd_timeout_ocr_possible(instance)) { 46488c2ecf20Sopenharmony_ci case INITIATE_OCR: 46498c2ecf20Sopenharmony_ci cmd->flags |= DRV_DCMD_SKIP_REFIRE; 46508c2ecf20Sopenharmony_ci /* 46518c2ecf20Sopenharmony_ci * DCMD failed from AEN path. 46528c2ecf20Sopenharmony_ci * AEN path already hold reset_mutex to avoid PCI access 46538c2ecf20Sopenharmony_ci * while OCR is in progress. 46548c2ecf20Sopenharmony_ci */ 46558c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 46568c2ecf20Sopenharmony_ci megasas_reset_fusion(instance->host, 46578c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_OCR); 46588c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 46598c2ecf20Sopenharmony_ci break; 46608c2ecf20Sopenharmony_ci case KILL_ADAPTER: 46618c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 46628c2ecf20Sopenharmony_ci break; 46638c2ecf20Sopenharmony_ci case IGNORE_TIMEOUT: 46648c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d \n", 46658c2ecf20Sopenharmony_ci __func__, __LINE__); 46668c2ecf20Sopenharmony_ci break; 46678c2ecf20Sopenharmony_ci } 46688c2ecf20Sopenharmony_ci 46698c2ecf20Sopenharmony_ci break; 46708c2ecf20Sopenharmony_ci 46718c2ecf20Sopenharmony_ci case DCMD_SUCCESS: 46728c2ecf20Sopenharmony_ci pd_addr = ci->addr; 46738c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & LD_PD_DEBUG) 46748c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "%s, sysPD count: 0x%x\n", 46758c2ecf20Sopenharmony_ci __func__, le32_to_cpu(ci->count)); 46768c2ecf20Sopenharmony_ci 46778c2ecf20Sopenharmony_ci if ((le32_to_cpu(ci->count) > 46788c2ecf20Sopenharmony_ci (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) 46798c2ecf20Sopenharmony_ci break; 46808c2ecf20Sopenharmony_ci 46818c2ecf20Sopenharmony_ci memset(instance->local_pd_list, 0, 46828c2ecf20Sopenharmony_ci MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)); 46838c2ecf20Sopenharmony_ci 46848c2ecf20Sopenharmony_ci for (pd_index = 0; pd_index < le32_to_cpu(ci->count); pd_index++) { 46858c2ecf20Sopenharmony_ci instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].tid = 46868c2ecf20Sopenharmony_ci le16_to_cpu(pd_addr->deviceId); 46878c2ecf20Sopenharmony_ci instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveType = 46888c2ecf20Sopenharmony_ci pd_addr->scsiDevType; 46898c2ecf20Sopenharmony_ci instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveState = 46908c2ecf20Sopenharmony_ci MR_PD_STATE_SYSTEM; 46918c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & LD_PD_DEBUG) 46928c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 46938c2ecf20Sopenharmony_ci "PD%d: targetID: 0x%03x deviceType:0x%x\n", 46948c2ecf20Sopenharmony_ci pd_index, le16_to_cpu(pd_addr->deviceId), 46958c2ecf20Sopenharmony_ci pd_addr->scsiDevType); 46968c2ecf20Sopenharmony_ci pd_addr++; 46978c2ecf20Sopenharmony_ci } 46988c2ecf20Sopenharmony_ci 46998c2ecf20Sopenharmony_ci memcpy(instance->pd_list, instance->local_pd_list, 47008c2ecf20Sopenharmony_ci sizeof(instance->pd_list)); 47018c2ecf20Sopenharmony_ci break; 47028c2ecf20Sopenharmony_ci 47038c2ecf20Sopenharmony_ci } 47048c2ecf20Sopenharmony_ci 47058c2ecf20Sopenharmony_ci if (ret != DCMD_TIMEOUT) 47068c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 47078c2ecf20Sopenharmony_ci 47088c2ecf20Sopenharmony_ci return ret; 47098c2ecf20Sopenharmony_ci} 47108c2ecf20Sopenharmony_ci 47118c2ecf20Sopenharmony_ci/* 47128c2ecf20Sopenharmony_ci * megasas_get_ld_list_info - Returns FW's ld_list structure 47138c2ecf20Sopenharmony_ci * @instance: Adapter soft state 47148c2ecf20Sopenharmony_ci * @ld_list: ld_list structure 47158c2ecf20Sopenharmony_ci * 47168c2ecf20Sopenharmony_ci * Issues an internal command (DCMD) to get the FW's controller PD 47178c2ecf20Sopenharmony_ci * list structure. This information is mainly used to find out SYSTEM 47188c2ecf20Sopenharmony_ci * supported by the FW. 47198c2ecf20Sopenharmony_ci */ 47208c2ecf20Sopenharmony_cistatic int 47218c2ecf20Sopenharmony_cimegasas_get_ld_list(struct megasas_instance *instance) 47228c2ecf20Sopenharmony_ci{ 47238c2ecf20Sopenharmony_ci int ret = 0, ld_index = 0, ids = 0; 47248c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 47258c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 47268c2ecf20Sopenharmony_ci struct MR_LD_LIST *ci; 47278c2ecf20Sopenharmony_ci dma_addr_t ci_h = 0; 47288c2ecf20Sopenharmony_ci u32 ld_count; 47298c2ecf20Sopenharmony_ci 47308c2ecf20Sopenharmony_ci ci = instance->ld_list_buf; 47318c2ecf20Sopenharmony_ci ci_h = instance->ld_list_buf_h; 47328c2ecf20Sopenharmony_ci 47338c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 47348c2ecf20Sopenharmony_ci 47358c2ecf20Sopenharmony_ci if (!cmd) { 47368c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_list: Failed to get cmd\n"); 47378c2ecf20Sopenharmony_ci return -ENOMEM; 47388c2ecf20Sopenharmony_ci } 47398c2ecf20Sopenharmony_ci 47408c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 47418c2ecf20Sopenharmony_ci 47428c2ecf20Sopenharmony_ci memset(ci, 0, sizeof(*ci)); 47438c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 47448c2ecf20Sopenharmony_ci 47458c2ecf20Sopenharmony_ci if (instance->supportmax256vd) 47468c2ecf20Sopenharmony_ci dcmd->mbox.b[0] = 1; 47478c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 47488c2ecf20Sopenharmony_ci dcmd->cmd_status = MFI_STAT_INVALID_STATUS; 47498c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 47508c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_READ; 47518c2ecf20Sopenharmony_ci dcmd->timeout = 0; 47528c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_LD_LIST)); 47538c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_LD_GET_LIST); 47548c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 47558c2ecf20Sopenharmony_ci 47568c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, ci_h, 47578c2ecf20Sopenharmony_ci sizeof(struct MR_LD_LIST)); 47588c2ecf20Sopenharmony_ci 47598c2ecf20Sopenharmony_ci if ((instance->adapter_type != MFI_SERIES) && 47608c2ecf20Sopenharmony_ci !instance->mask_interrupts) 47618c2ecf20Sopenharmony_ci ret = megasas_issue_blocked_cmd(instance, cmd, 47628c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_SECS); 47638c2ecf20Sopenharmony_ci else 47648c2ecf20Sopenharmony_ci ret = megasas_issue_polled(instance, cmd); 47658c2ecf20Sopenharmony_ci 47668c2ecf20Sopenharmony_ci ld_count = le32_to_cpu(ci->ldCount); 47678c2ecf20Sopenharmony_ci 47688c2ecf20Sopenharmony_ci switch (ret) { 47698c2ecf20Sopenharmony_ci case DCMD_FAILED: 47708c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 47718c2ecf20Sopenharmony_ci break; 47728c2ecf20Sopenharmony_ci case DCMD_TIMEOUT: 47738c2ecf20Sopenharmony_ci 47748c2ecf20Sopenharmony_ci switch (dcmd_timeout_ocr_possible(instance)) { 47758c2ecf20Sopenharmony_ci case INITIATE_OCR: 47768c2ecf20Sopenharmony_ci cmd->flags |= DRV_DCMD_SKIP_REFIRE; 47778c2ecf20Sopenharmony_ci /* 47788c2ecf20Sopenharmony_ci * DCMD failed from AEN path. 47798c2ecf20Sopenharmony_ci * AEN path already hold reset_mutex to avoid PCI access 47808c2ecf20Sopenharmony_ci * while OCR is in progress. 47818c2ecf20Sopenharmony_ci */ 47828c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 47838c2ecf20Sopenharmony_ci megasas_reset_fusion(instance->host, 47848c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_OCR); 47858c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 47868c2ecf20Sopenharmony_ci break; 47878c2ecf20Sopenharmony_ci case KILL_ADAPTER: 47888c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 47898c2ecf20Sopenharmony_ci break; 47908c2ecf20Sopenharmony_ci case IGNORE_TIMEOUT: 47918c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n", 47928c2ecf20Sopenharmony_ci __func__, __LINE__); 47938c2ecf20Sopenharmony_ci break; 47948c2ecf20Sopenharmony_ci } 47958c2ecf20Sopenharmony_ci 47968c2ecf20Sopenharmony_ci break; 47978c2ecf20Sopenharmony_ci 47988c2ecf20Sopenharmony_ci case DCMD_SUCCESS: 47998c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & LD_PD_DEBUG) 48008c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n", 48018c2ecf20Sopenharmony_ci __func__, ld_count); 48028c2ecf20Sopenharmony_ci 48038c2ecf20Sopenharmony_ci if (ld_count > instance->fw_supported_vd_count) 48048c2ecf20Sopenharmony_ci break; 48058c2ecf20Sopenharmony_ci 48068c2ecf20Sopenharmony_ci memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT); 48078c2ecf20Sopenharmony_ci 48088c2ecf20Sopenharmony_ci for (ld_index = 0; ld_index < ld_count; ld_index++) { 48098c2ecf20Sopenharmony_ci if (ci->ldList[ld_index].state != 0) { 48108c2ecf20Sopenharmony_ci ids = ci->ldList[ld_index].ref.targetId; 48118c2ecf20Sopenharmony_ci instance->ld_ids[ids] = ci->ldList[ld_index].ref.targetId; 48128c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & LD_PD_DEBUG) 48138c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 48148c2ecf20Sopenharmony_ci "LD%d: targetID: 0x%03x\n", 48158c2ecf20Sopenharmony_ci ld_index, ids); 48168c2ecf20Sopenharmony_ci } 48178c2ecf20Sopenharmony_ci } 48188c2ecf20Sopenharmony_ci 48198c2ecf20Sopenharmony_ci break; 48208c2ecf20Sopenharmony_ci } 48218c2ecf20Sopenharmony_ci 48228c2ecf20Sopenharmony_ci if (ret != DCMD_TIMEOUT) 48238c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 48248c2ecf20Sopenharmony_ci 48258c2ecf20Sopenharmony_ci return ret; 48268c2ecf20Sopenharmony_ci} 48278c2ecf20Sopenharmony_ci 48288c2ecf20Sopenharmony_ci/** 48298c2ecf20Sopenharmony_ci * megasas_ld_list_query - Returns FW's ld_list structure 48308c2ecf20Sopenharmony_ci * @instance: Adapter soft state 48318c2ecf20Sopenharmony_ci * @query_type: ld_list structure type 48328c2ecf20Sopenharmony_ci * 48338c2ecf20Sopenharmony_ci * Issues an internal command (DCMD) to get the FW's controller PD 48348c2ecf20Sopenharmony_ci * list structure. This information is mainly used to find out SYSTEM 48358c2ecf20Sopenharmony_ci * supported by the FW. 48368c2ecf20Sopenharmony_ci */ 48378c2ecf20Sopenharmony_cistatic int 48388c2ecf20Sopenharmony_cimegasas_ld_list_query(struct megasas_instance *instance, u8 query_type) 48398c2ecf20Sopenharmony_ci{ 48408c2ecf20Sopenharmony_ci int ret = 0, ld_index = 0, ids = 0; 48418c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 48428c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 48438c2ecf20Sopenharmony_ci struct MR_LD_TARGETID_LIST *ci; 48448c2ecf20Sopenharmony_ci dma_addr_t ci_h = 0; 48458c2ecf20Sopenharmony_ci u32 tgtid_count; 48468c2ecf20Sopenharmony_ci 48478c2ecf20Sopenharmony_ci ci = instance->ld_targetid_list_buf; 48488c2ecf20Sopenharmony_ci ci_h = instance->ld_targetid_list_buf_h; 48498c2ecf20Sopenharmony_ci 48508c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 48518c2ecf20Sopenharmony_ci 48528c2ecf20Sopenharmony_ci if (!cmd) { 48538c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, 48548c2ecf20Sopenharmony_ci "megasas_ld_list_query: Failed to get cmd\n"); 48558c2ecf20Sopenharmony_ci return -ENOMEM; 48568c2ecf20Sopenharmony_ci } 48578c2ecf20Sopenharmony_ci 48588c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 48598c2ecf20Sopenharmony_ci 48608c2ecf20Sopenharmony_ci memset(ci, 0, sizeof(*ci)); 48618c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 48628c2ecf20Sopenharmony_ci 48638c2ecf20Sopenharmony_ci dcmd->mbox.b[0] = query_type; 48648c2ecf20Sopenharmony_ci if (instance->supportmax256vd) 48658c2ecf20Sopenharmony_ci dcmd->mbox.b[2] = 1; 48668c2ecf20Sopenharmony_ci 48678c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 48688c2ecf20Sopenharmony_ci dcmd->cmd_status = MFI_STAT_INVALID_STATUS; 48698c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 48708c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_READ; 48718c2ecf20Sopenharmony_ci dcmd->timeout = 0; 48728c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_LD_TARGETID_LIST)); 48738c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_LD_LIST_QUERY); 48748c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 48758c2ecf20Sopenharmony_ci 48768c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, ci_h, 48778c2ecf20Sopenharmony_ci sizeof(struct MR_LD_TARGETID_LIST)); 48788c2ecf20Sopenharmony_ci 48798c2ecf20Sopenharmony_ci if ((instance->adapter_type != MFI_SERIES) && 48808c2ecf20Sopenharmony_ci !instance->mask_interrupts) 48818c2ecf20Sopenharmony_ci ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS); 48828c2ecf20Sopenharmony_ci else 48838c2ecf20Sopenharmony_ci ret = megasas_issue_polled(instance, cmd); 48848c2ecf20Sopenharmony_ci 48858c2ecf20Sopenharmony_ci switch (ret) { 48868c2ecf20Sopenharmony_ci case DCMD_FAILED: 48878c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 48888c2ecf20Sopenharmony_ci "DCMD not supported by firmware - %s %d\n", 48898c2ecf20Sopenharmony_ci __func__, __LINE__); 48908c2ecf20Sopenharmony_ci ret = megasas_get_ld_list(instance); 48918c2ecf20Sopenharmony_ci break; 48928c2ecf20Sopenharmony_ci case DCMD_TIMEOUT: 48938c2ecf20Sopenharmony_ci switch (dcmd_timeout_ocr_possible(instance)) { 48948c2ecf20Sopenharmony_ci case INITIATE_OCR: 48958c2ecf20Sopenharmony_ci cmd->flags |= DRV_DCMD_SKIP_REFIRE; 48968c2ecf20Sopenharmony_ci /* 48978c2ecf20Sopenharmony_ci * DCMD failed from AEN path. 48988c2ecf20Sopenharmony_ci * AEN path already hold reset_mutex to avoid PCI access 48998c2ecf20Sopenharmony_ci * while OCR is in progress. 49008c2ecf20Sopenharmony_ci */ 49018c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 49028c2ecf20Sopenharmony_ci megasas_reset_fusion(instance->host, 49038c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_OCR); 49048c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 49058c2ecf20Sopenharmony_ci break; 49068c2ecf20Sopenharmony_ci case KILL_ADAPTER: 49078c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 49088c2ecf20Sopenharmony_ci break; 49098c2ecf20Sopenharmony_ci case IGNORE_TIMEOUT: 49108c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n", 49118c2ecf20Sopenharmony_ci __func__, __LINE__); 49128c2ecf20Sopenharmony_ci break; 49138c2ecf20Sopenharmony_ci } 49148c2ecf20Sopenharmony_ci 49158c2ecf20Sopenharmony_ci break; 49168c2ecf20Sopenharmony_ci case DCMD_SUCCESS: 49178c2ecf20Sopenharmony_ci tgtid_count = le32_to_cpu(ci->count); 49188c2ecf20Sopenharmony_ci 49198c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & LD_PD_DEBUG) 49208c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n", 49218c2ecf20Sopenharmony_ci __func__, tgtid_count); 49228c2ecf20Sopenharmony_ci 49238c2ecf20Sopenharmony_ci if ((tgtid_count > (instance->fw_supported_vd_count))) 49248c2ecf20Sopenharmony_ci break; 49258c2ecf20Sopenharmony_ci 49268c2ecf20Sopenharmony_ci memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); 49278c2ecf20Sopenharmony_ci for (ld_index = 0; ld_index < tgtid_count; ld_index++) { 49288c2ecf20Sopenharmony_ci ids = ci->targetId[ld_index]; 49298c2ecf20Sopenharmony_ci instance->ld_ids[ids] = ci->targetId[ld_index]; 49308c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & LD_PD_DEBUG) 49318c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "LD%d: targetID: 0x%03x\n", 49328c2ecf20Sopenharmony_ci ld_index, ci->targetId[ld_index]); 49338c2ecf20Sopenharmony_ci } 49348c2ecf20Sopenharmony_ci 49358c2ecf20Sopenharmony_ci break; 49368c2ecf20Sopenharmony_ci } 49378c2ecf20Sopenharmony_ci 49388c2ecf20Sopenharmony_ci if (ret != DCMD_TIMEOUT) 49398c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 49408c2ecf20Sopenharmony_ci 49418c2ecf20Sopenharmony_ci return ret; 49428c2ecf20Sopenharmony_ci} 49438c2ecf20Sopenharmony_ci 49448c2ecf20Sopenharmony_ci/** 49458c2ecf20Sopenharmony_ci * dcmd.opcode - MR_DCMD_CTRL_DEVICE_LIST_GET 49468c2ecf20Sopenharmony_ci * dcmd.mbox - reserved 49478c2ecf20Sopenharmony_ci * dcmd.sge IN - ptr to return MR_HOST_DEVICE_LIST structure 49488c2ecf20Sopenharmony_ci * Desc: This DCMD will return the combined device list 49498c2ecf20Sopenharmony_ci * Status: MFI_STAT_OK - List returned successfully 49508c2ecf20Sopenharmony_ci * MFI_STAT_INVALID_CMD - Firmware support for the feature has been 49518c2ecf20Sopenharmony_ci * disabled 49528c2ecf20Sopenharmony_ci * @instance: Adapter soft state 49538c2ecf20Sopenharmony_ci * @is_probe: Driver probe check 49548c2ecf20Sopenharmony_ci * Return: 0 if DCMD succeeded 49558c2ecf20Sopenharmony_ci * non-zero if failed 49568c2ecf20Sopenharmony_ci */ 49578c2ecf20Sopenharmony_cistatic int 49588c2ecf20Sopenharmony_cimegasas_host_device_list_query(struct megasas_instance *instance, 49598c2ecf20Sopenharmony_ci bool is_probe) 49608c2ecf20Sopenharmony_ci{ 49618c2ecf20Sopenharmony_ci int ret, i, target_id; 49628c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 49638c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 49648c2ecf20Sopenharmony_ci struct MR_HOST_DEVICE_LIST *ci; 49658c2ecf20Sopenharmony_ci u32 count; 49668c2ecf20Sopenharmony_ci dma_addr_t ci_h; 49678c2ecf20Sopenharmony_ci 49688c2ecf20Sopenharmony_ci ci = instance->host_device_list_buf; 49698c2ecf20Sopenharmony_ci ci_h = instance->host_device_list_buf_h; 49708c2ecf20Sopenharmony_ci 49718c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 49728c2ecf20Sopenharmony_ci 49738c2ecf20Sopenharmony_ci if (!cmd) { 49748c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, 49758c2ecf20Sopenharmony_ci "%s: failed to get cmd\n", 49768c2ecf20Sopenharmony_ci __func__); 49778c2ecf20Sopenharmony_ci return -ENOMEM; 49788c2ecf20Sopenharmony_ci } 49798c2ecf20Sopenharmony_ci 49808c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 49818c2ecf20Sopenharmony_ci 49828c2ecf20Sopenharmony_ci memset(ci, 0, sizeof(*ci)); 49838c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 49848c2ecf20Sopenharmony_ci 49858c2ecf20Sopenharmony_ci dcmd->mbox.b[0] = is_probe ? 0 : 1; 49868c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 49878c2ecf20Sopenharmony_ci dcmd->cmd_status = MFI_STAT_INVALID_STATUS; 49888c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 49898c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_READ; 49908c2ecf20Sopenharmony_ci dcmd->timeout = 0; 49918c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 49928c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(HOST_DEVICE_LIST_SZ); 49938c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_DEVICE_LIST_GET); 49948c2ecf20Sopenharmony_ci 49958c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, ci_h, HOST_DEVICE_LIST_SZ); 49968c2ecf20Sopenharmony_ci 49978c2ecf20Sopenharmony_ci if (!instance->mask_interrupts) { 49988c2ecf20Sopenharmony_ci ret = megasas_issue_blocked_cmd(instance, cmd, 49998c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_SECS); 50008c2ecf20Sopenharmony_ci } else { 50018c2ecf20Sopenharmony_ci ret = megasas_issue_polled(instance, cmd); 50028c2ecf20Sopenharmony_ci cmd->flags |= DRV_DCMD_SKIP_REFIRE; 50038c2ecf20Sopenharmony_ci } 50048c2ecf20Sopenharmony_ci 50058c2ecf20Sopenharmony_ci switch (ret) { 50068c2ecf20Sopenharmony_ci case DCMD_SUCCESS: 50078c2ecf20Sopenharmony_ci /* Fill the internal pd_list and ld_ids array based on 50088c2ecf20Sopenharmony_ci * targetIds returned by FW 50098c2ecf20Sopenharmony_ci */ 50108c2ecf20Sopenharmony_ci count = le32_to_cpu(ci->count); 50118c2ecf20Sopenharmony_ci 50128c2ecf20Sopenharmony_ci if (count > (MEGASAS_MAX_PD + MAX_LOGICAL_DRIVES_EXT)) 50138c2ecf20Sopenharmony_ci break; 50148c2ecf20Sopenharmony_ci 50158c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & LD_PD_DEBUG) 50168c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "%s, Device count: 0x%x\n", 50178c2ecf20Sopenharmony_ci __func__, count); 50188c2ecf20Sopenharmony_ci 50198c2ecf20Sopenharmony_ci memset(instance->local_pd_list, 0, 50208c2ecf20Sopenharmony_ci MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)); 50218c2ecf20Sopenharmony_ci memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT); 50228c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 50238c2ecf20Sopenharmony_ci target_id = le16_to_cpu(ci->host_device_list[i].target_id); 50248c2ecf20Sopenharmony_ci if (ci->host_device_list[i].flags.u.bits.is_sys_pd) { 50258c2ecf20Sopenharmony_ci instance->local_pd_list[target_id].tid = target_id; 50268c2ecf20Sopenharmony_ci instance->local_pd_list[target_id].driveType = 50278c2ecf20Sopenharmony_ci ci->host_device_list[i].scsi_type; 50288c2ecf20Sopenharmony_ci instance->local_pd_list[target_id].driveState = 50298c2ecf20Sopenharmony_ci MR_PD_STATE_SYSTEM; 50308c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & LD_PD_DEBUG) 50318c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 50328c2ecf20Sopenharmony_ci "Device %d: PD targetID: 0x%03x deviceType:0x%x\n", 50338c2ecf20Sopenharmony_ci i, target_id, ci->host_device_list[i].scsi_type); 50348c2ecf20Sopenharmony_ci } else { 50358c2ecf20Sopenharmony_ci instance->ld_ids[target_id] = target_id; 50368c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & LD_PD_DEBUG) 50378c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 50388c2ecf20Sopenharmony_ci "Device %d: LD targetID: 0x%03x\n", 50398c2ecf20Sopenharmony_ci i, target_id); 50408c2ecf20Sopenharmony_ci } 50418c2ecf20Sopenharmony_ci } 50428c2ecf20Sopenharmony_ci 50438c2ecf20Sopenharmony_ci memcpy(instance->pd_list, instance->local_pd_list, 50448c2ecf20Sopenharmony_ci sizeof(instance->pd_list)); 50458c2ecf20Sopenharmony_ci break; 50468c2ecf20Sopenharmony_ci 50478c2ecf20Sopenharmony_ci case DCMD_TIMEOUT: 50488c2ecf20Sopenharmony_ci switch (dcmd_timeout_ocr_possible(instance)) { 50498c2ecf20Sopenharmony_ci case INITIATE_OCR: 50508c2ecf20Sopenharmony_ci cmd->flags |= DRV_DCMD_SKIP_REFIRE; 50518c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 50528c2ecf20Sopenharmony_ci megasas_reset_fusion(instance->host, 50538c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_OCR); 50548c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 50558c2ecf20Sopenharmony_ci break; 50568c2ecf20Sopenharmony_ci case KILL_ADAPTER: 50578c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 50588c2ecf20Sopenharmony_ci break; 50598c2ecf20Sopenharmony_ci case IGNORE_TIMEOUT: 50608c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n", 50618c2ecf20Sopenharmony_ci __func__, __LINE__); 50628c2ecf20Sopenharmony_ci break; 50638c2ecf20Sopenharmony_ci } 50648c2ecf20Sopenharmony_ci break; 50658c2ecf20Sopenharmony_ci case DCMD_FAILED: 50668c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 50678c2ecf20Sopenharmony_ci "%s: MR_DCMD_CTRL_DEVICE_LIST_GET failed\n", 50688c2ecf20Sopenharmony_ci __func__); 50698c2ecf20Sopenharmony_ci break; 50708c2ecf20Sopenharmony_ci } 50718c2ecf20Sopenharmony_ci 50728c2ecf20Sopenharmony_ci if (ret != DCMD_TIMEOUT) 50738c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 50748c2ecf20Sopenharmony_ci 50758c2ecf20Sopenharmony_ci return ret; 50768c2ecf20Sopenharmony_ci} 50778c2ecf20Sopenharmony_ci 50788c2ecf20Sopenharmony_ci/* 50798c2ecf20Sopenharmony_ci * megasas_update_ext_vd_details : Update details w.r.t Extended VD 50808c2ecf20Sopenharmony_ci * instance : Controller's instance 50818c2ecf20Sopenharmony_ci*/ 50828c2ecf20Sopenharmony_cistatic void megasas_update_ext_vd_details(struct megasas_instance *instance) 50838c2ecf20Sopenharmony_ci{ 50848c2ecf20Sopenharmony_ci struct fusion_context *fusion; 50858c2ecf20Sopenharmony_ci u32 ventura_map_sz = 0; 50868c2ecf20Sopenharmony_ci 50878c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 50888c2ecf20Sopenharmony_ci /* For MFI based controllers return dummy success */ 50898c2ecf20Sopenharmony_ci if (!fusion) 50908c2ecf20Sopenharmony_ci return; 50918c2ecf20Sopenharmony_ci 50928c2ecf20Sopenharmony_ci instance->supportmax256vd = 50938c2ecf20Sopenharmony_ci instance->ctrl_info_buf->adapterOperations3.supportMaxExtLDs; 50948c2ecf20Sopenharmony_ci /* Below is additional check to address future FW enhancement */ 50958c2ecf20Sopenharmony_ci if (instance->ctrl_info_buf->max_lds > 64) 50968c2ecf20Sopenharmony_ci instance->supportmax256vd = 1; 50978c2ecf20Sopenharmony_ci 50988c2ecf20Sopenharmony_ci instance->drv_supported_vd_count = MEGASAS_MAX_LD_CHANNELS 50998c2ecf20Sopenharmony_ci * MEGASAS_MAX_DEV_PER_CHANNEL; 51008c2ecf20Sopenharmony_ci instance->drv_supported_pd_count = MEGASAS_MAX_PD_CHANNELS 51018c2ecf20Sopenharmony_ci * MEGASAS_MAX_DEV_PER_CHANNEL; 51028c2ecf20Sopenharmony_ci if (instance->supportmax256vd) { 51038c2ecf20Sopenharmony_ci instance->fw_supported_vd_count = MAX_LOGICAL_DRIVES_EXT; 51048c2ecf20Sopenharmony_ci instance->fw_supported_pd_count = MAX_PHYSICAL_DEVICES; 51058c2ecf20Sopenharmony_ci } else { 51068c2ecf20Sopenharmony_ci instance->fw_supported_vd_count = MAX_LOGICAL_DRIVES; 51078c2ecf20Sopenharmony_ci instance->fw_supported_pd_count = MAX_PHYSICAL_DEVICES; 51088c2ecf20Sopenharmony_ci } 51098c2ecf20Sopenharmony_ci 51108c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 51118c2ecf20Sopenharmony_ci "FW provided supportMaxExtLDs: %d\tmax_lds: %d\n", 51128c2ecf20Sopenharmony_ci instance->ctrl_info_buf->adapterOperations3.supportMaxExtLDs ? 1 : 0, 51138c2ecf20Sopenharmony_ci instance->ctrl_info_buf->max_lds); 51148c2ecf20Sopenharmony_ci 51158c2ecf20Sopenharmony_ci if (instance->max_raid_mapsize) { 51168c2ecf20Sopenharmony_ci ventura_map_sz = instance->max_raid_mapsize * 51178c2ecf20Sopenharmony_ci MR_MIN_MAP_SIZE; /* 64k */ 51188c2ecf20Sopenharmony_ci fusion->current_map_sz = ventura_map_sz; 51198c2ecf20Sopenharmony_ci fusion->max_map_sz = ventura_map_sz; 51208c2ecf20Sopenharmony_ci } else { 51218c2ecf20Sopenharmony_ci fusion->old_map_sz = sizeof(struct MR_FW_RAID_MAP) + 51228c2ecf20Sopenharmony_ci (sizeof(struct MR_LD_SPAN_MAP) * 51238c2ecf20Sopenharmony_ci (instance->fw_supported_vd_count - 1)); 51248c2ecf20Sopenharmony_ci fusion->new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT); 51258c2ecf20Sopenharmony_ci 51268c2ecf20Sopenharmony_ci fusion->max_map_sz = 51278c2ecf20Sopenharmony_ci max(fusion->old_map_sz, fusion->new_map_sz); 51288c2ecf20Sopenharmony_ci 51298c2ecf20Sopenharmony_ci if (instance->supportmax256vd) 51308c2ecf20Sopenharmony_ci fusion->current_map_sz = fusion->new_map_sz; 51318c2ecf20Sopenharmony_ci else 51328c2ecf20Sopenharmony_ci fusion->current_map_sz = fusion->old_map_sz; 51338c2ecf20Sopenharmony_ci } 51348c2ecf20Sopenharmony_ci /* irrespective of FW raid maps, driver raid map is constant */ 51358c2ecf20Sopenharmony_ci fusion->drv_map_sz = sizeof(struct MR_DRV_RAID_MAP_ALL); 51368c2ecf20Sopenharmony_ci} 51378c2ecf20Sopenharmony_ci 51388c2ecf20Sopenharmony_ci/* 51398c2ecf20Sopenharmony_ci * dcmd.opcode - MR_DCMD_CTRL_SNAPDUMP_GET_PROPERTIES 51408c2ecf20Sopenharmony_ci * dcmd.hdr.length - number of bytes to read 51418c2ecf20Sopenharmony_ci * dcmd.sge - Ptr to MR_SNAPDUMP_PROPERTIES 51428c2ecf20Sopenharmony_ci * Desc: Fill in snapdump properties 51438c2ecf20Sopenharmony_ci * Status: MFI_STAT_OK- Command successful 51448c2ecf20Sopenharmony_ci */ 51458c2ecf20Sopenharmony_civoid megasas_get_snapdump_properties(struct megasas_instance *instance) 51468c2ecf20Sopenharmony_ci{ 51478c2ecf20Sopenharmony_ci int ret = 0; 51488c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 51498c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 51508c2ecf20Sopenharmony_ci struct MR_SNAPDUMP_PROPERTIES *ci; 51518c2ecf20Sopenharmony_ci dma_addr_t ci_h = 0; 51528c2ecf20Sopenharmony_ci 51538c2ecf20Sopenharmony_ci ci = instance->snapdump_prop; 51548c2ecf20Sopenharmony_ci ci_h = instance->snapdump_prop_h; 51558c2ecf20Sopenharmony_ci 51568c2ecf20Sopenharmony_ci if (!ci) 51578c2ecf20Sopenharmony_ci return; 51588c2ecf20Sopenharmony_ci 51598c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 51608c2ecf20Sopenharmony_ci 51618c2ecf20Sopenharmony_ci if (!cmd) { 51628c2ecf20Sopenharmony_ci dev_dbg(&instance->pdev->dev, "Failed to get a free cmd\n"); 51638c2ecf20Sopenharmony_ci return; 51648c2ecf20Sopenharmony_ci } 51658c2ecf20Sopenharmony_ci 51668c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 51678c2ecf20Sopenharmony_ci 51688c2ecf20Sopenharmony_ci memset(ci, 0, sizeof(*ci)); 51698c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 51708c2ecf20Sopenharmony_ci 51718c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 51728c2ecf20Sopenharmony_ci dcmd->cmd_status = MFI_STAT_INVALID_STATUS; 51738c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 51748c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_READ; 51758c2ecf20Sopenharmony_ci dcmd->timeout = 0; 51768c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 51778c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_SNAPDUMP_PROPERTIES)); 51788c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_SNAPDUMP_GET_PROPERTIES); 51798c2ecf20Sopenharmony_ci 51808c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, ci_h, 51818c2ecf20Sopenharmony_ci sizeof(struct MR_SNAPDUMP_PROPERTIES)); 51828c2ecf20Sopenharmony_ci 51838c2ecf20Sopenharmony_ci if (!instance->mask_interrupts) { 51848c2ecf20Sopenharmony_ci ret = megasas_issue_blocked_cmd(instance, cmd, 51858c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_SECS); 51868c2ecf20Sopenharmony_ci } else { 51878c2ecf20Sopenharmony_ci ret = megasas_issue_polled(instance, cmd); 51888c2ecf20Sopenharmony_ci cmd->flags |= DRV_DCMD_SKIP_REFIRE; 51898c2ecf20Sopenharmony_ci } 51908c2ecf20Sopenharmony_ci 51918c2ecf20Sopenharmony_ci switch (ret) { 51928c2ecf20Sopenharmony_ci case DCMD_SUCCESS: 51938c2ecf20Sopenharmony_ci instance->snapdump_wait_time = 51948c2ecf20Sopenharmony_ci min_t(u8, ci->trigger_min_num_sec_before_ocr, 51958c2ecf20Sopenharmony_ci MEGASAS_MAX_SNAP_DUMP_WAIT_TIME); 51968c2ecf20Sopenharmony_ci break; 51978c2ecf20Sopenharmony_ci 51988c2ecf20Sopenharmony_ci case DCMD_TIMEOUT: 51998c2ecf20Sopenharmony_ci switch (dcmd_timeout_ocr_possible(instance)) { 52008c2ecf20Sopenharmony_ci case INITIATE_OCR: 52018c2ecf20Sopenharmony_ci cmd->flags |= DRV_DCMD_SKIP_REFIRE; 52028c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 52038c2ecf20Sopenharmony_ci megasas_reset_fusion(instance->host, 52048c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_OCR); 52058c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 52068c2ecf20Sopenharmony_ci break; 52078c2ecf20Sopenharmony_ci case KILL_ADAPTER: 52088c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 52098c2ecf20Sopenharmony_ci break; 52108c2ecf20Sopenharmony_ci case IGNORE_TIMEOUT: 52118c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n", 52128c2ecf20Sopenharmony_ci __func__, __LINE__); 52138c2ecf20Sopenharmony_ci break; 52148c2ecf20Sopenharmony_ci } 52158c2ecf20Sopenharmony_ci } 52168c2ecf20Sopenharmony_ci 52178c2ecf20Sopenharmony_ci if (ret != DCMD_TIMEOUT) 52188c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 52198c2ecf20Sopenharmony_ci} 52208c2ecf20Sopenharmony_ci 52218c2ecf20Sopenharmony_ci/** 52228c2ecf20Sopenharmony_ci * megasas_get_controller_info - Returns FW's controller structure 52238c2ecf20Sopenharmony_ci * @instance: Adapter soft state 52248c2ecf20Sopenharmony_ci * 52258c2ecf20Sopenharmony_ci * Issues an internal command (DCMD) to get the FW's controller structure. 52268c2ecf20Sopenharmony_ci * This information is mainly used to find out the maximum IO transfer per 52278c2ecf20Sopenharmony_ci * command supported by the FW. 52288c2ecf20Sopenharmony_ci */ 52298c2ecf20Sopenharmony_ciint 52308c2ecf20Sopenharmony_cimegasas_get_ctrl_info(struct megasas_instance *instance) 52318c2ecf20Sopenharmony_ci{ 52328c2ecf20Sopenharmony_ci int ret = 0; 52338c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 52348c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 52358c2ecf20Sopenharmony_ci struct megasas_ctrl_info *ci; 52368c2ecf20Sopenharmony_ci dma_addr_t ci_h = 0; 52378c2ecf20Sopenharmony_ci 52388c2ecf20Sopenharmony_ci ci = instance->ctrl_info_buf; 52398c2ecf20Sopenharmony_ci ci_h = instance->ctrl_info_buf_h; 52408c2ecf20Sopenharmony_ci 52418c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 52428c2ecf20Sopenharmony_ci 52438c2ecf20Sopenharmony_ci if (!cmd) { 52448c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get a free cmd\n"); 52458c2ecf20Sopenharmony_ci return -ENOMEM; 52468c2ecf20Sopenharmony_ci } 52478c2ecf20Sopenharmony_ci 52488c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 52498c2ecf20Sopenharmony_ci 52508c2ecf20Sopenharmony_ci memset(ci, 0, sizeof(*ci)); 52518c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 52528c2ecf20Sopenharmony_ci 52538c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 52548c2ecf20Sopenharmony_ci dcmd->cmd_status = MFI_STAT_INVALID_STATUS; 52558c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 52568c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_READ; 52578c2ecf20Sopenharmony_ci dcmd->timeout = 0; 52588c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 52598c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_ctrl_info)); 52608c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_GET_INFO); 52618c2ecf20Sopenharmony_ci dcmd->mbox.b[0] = 1; 52628c2ecf20Sopenharmony_ci 52638c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, ci_h, 52648c2ecf20Sopenharmony_ci sizeof(struct megasas_ctrl_info)); 52658c2ecf20Sopenharmony_ci 52668c2ecf20Sopenharmony_ci if ((instance->adapter_type != MFI_SERIES) && 52678c2ecf20Sopenharmony_ci !instance->mask_interrupts) { 52688c2ecf20Sopenharmony_ci ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS); 52698c2ecf20Sopenharmony_ci } else { 52708c2ecf20Sopenharmony_ci ret = megasas_issue_polled(instance, cmd); 52718c2ecf20Sopenharmony_ci cmd->flags |= DRV_DCMD_SKIP_REFIRE; 52728c2ecf20Sopenharmony_ci } 52738c2ecf20Sopenharmony_ci 52748c2ecf20Sopenharmony_ci switch (ret) { 52758c2ecf20Sopenharmony_ci case DCMD_SUCCESS: 52768c2ecf20Sopenharmony_ci /* Save required controller information in 52778c2ecf20Sopenharmony_ci * CPU endianness format. 52788c2ecf20Sopenharmony_ci */ 52798c2ecf20Sopenharmony_ci le32_to_cpus((u32 *)&ci->properties.OnOffProperties); 52808c2ecf20Sopenharmony_ci le16_to_cpus((u16 *)&ci->properties.on_off_properties2); 52818c2ecf20Sopenharmony_ci le32_to_cpus((u32 *)&ci->adapterOperations2); 52828c2ecf20Sopenharmony_ci le32_to_cpus((u32 *)&ci->adapterOperations3); 52838c2ecf20Sopenharmony_ci le16_to_cpus((u16 *)&ci->adapter_operations4); 52848c2ecf20Sopenharmony_ci le32_to_cpus((u32 *)&ci->adapter_operations5); 52858c2ecf20Sopenharmony_ci 52868c2ecf20Sopenharmony_ci /* Update the latest Ext VD info. 52878c2ecf20Sopenharmony_ci * From Init path, store current firmware details. 52888c2ecf20Sopenharmony_ci * From OCR path, detect any firmware properties changes. 52898c2ecf20Sopenharmony_ci * in case of Firmware upgrade without system reboot. 52908c2ecf20Sopenharmony_ci */ 52918c2ecf20Sopenharmony_ci megasas_update_ext_vd_details(instance); 52928c2ecf20Sopenharmony_ci instance->support_seqnum_jbod_fp = 52938c2ecf20Sopenharmony_ci ci->adapterOperations3.useSeqNumJbodFP; 52948c2ecf20Sopenharmony_ci instance->support_morethan256jbod = 52958c2ecf20Sopenharmony_ci ci->adapter_operations4.support_pd_map_target_id; 52968c2ecf20Sopenharmony_ci instance->support_nvme_passthru = 52978c2ecf20Sopenharmony_ci ci->adapter_operations4.support_nvme_passthru; 52988c2ecf20Sopenharmony_ci instance->support_pci_lane_margining = 52998c2ecf20Sopenharmony_ci ci->adapter_operations5.support_pci_lane_margining; 53008c2ecf20Sopenharmony_ci instance->task_abort_tmo = ci->TaskAbortTO; 53018c2ecf20Sopenharmony_ci instance->max_reset_tmo = ci->MaxResetTO; 53028c2ecf20Sopenharmony_ci 53038c2ecf20Sopenharmony_ci /*Check whether controller is iMR or MR */ 53048c2ecf20Sopenharmony_ci instance->is_imr = (ci->memory_size ? 0 : 1); 53058c2ecf20Sopenharmony_ci 53068c2ecf20Sopenharmony_ci instance->snapdump_wait_time = 53078c2ecf20Sopenharmony_ci (ci->properties.on_off_properties2.enable_snap_dump ? 53088c2ecf20Sopenharmony_ci MEGASAS_DEFAULT_SNAP_DUMP_WAIT_TIME : 0); 53098c2ecf20Sopenharmony_ci 53108c2ecf20Sopenharmony_ci instance->enable_fw_dev_list = 53118c2ecf20Sopenharmony_ci ci->properties.on_off_properties2.enable_fw_dev_list; 53128c2ecf20Sopenharmony_ci 53138c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 53148c2ecf20Sopenharmony_ci "controller type\t: %s(%dMB)\n", 53158c2ecf20Sopenharmony_ci instance->is_imr ? "iMR" : "MR", 53168c2ecf20Sopenharmony_ci le16_to_cpu(ci->memory_size)); 53178c2ecf20Sopenharmony_ci 53188c2ecf20Sopenharmony_ci instance->disableOnlineCtrlReset = 53198c2ecf20Sopenharmony_ci ci->properties.OnOffProperties.disableOnlineCtrlReset; 53208c2ecf20Sopenharmony_ci instance->secure_jbod_support = 53218c2ecf20Sopenharmony_ci ci->adapterOperations3.supportSecurityonJBOD; 53228c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Online Controller Reset(OCR)\t: %s\n", 53238c2ecf20Sopenharmony_ci instance->disableOnlineCtrlReset ? "Disabled" : "Enabled"); 53248c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Secure JBOD support\t: %s\n", 53258c2ecf20Sopenharmony_ci instance->secure_jbod_support ? "Yes" : "No"); 53268c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "NVMe passthru support\t: %s\n", 53278c2ecf20Sopenharmony_ci instance->support_nvme_passthru ? "Yes" : "No"); 53288c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 53298c2ecf20Sopenharmony_ci "FW provided TM TaskAbort/Reset timeout\t: %d secs/%d secs\n", 53308c2ecf20Sopenharmony_ci instance->task_abort_tmo, instance->max_reset_tmo); 53318c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "JBOD sequence map support\t: %s\n", 53328c2ecf20Sopenharmony_ci instance->support_seqnum_jbod_fp ? "Yes" : "No"); 53338c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "PCI Lane Margining support\t: %s\n", 53348c2ecf20Sopenharmony_ci instance->support_pci_lane_margining ? "Yes" : "No"); 53358c2ecf20Sopenharmony_ci 53368c2ecf20Sopenharmony_ci break; 53378c2ecf20Sopenharmony_ci 53388c2ecf20Sopenharmony_ci case DCMD_TIMEOUT: 53398c2ecf20Sopenharmony_ci switch (dcmd_timeout_ocr_possible(instance)) { 53408c2ecf20Sopenharmony_ci case INITIATE_OCR: 53418c2ecf20Sopenharmony_ci cmd->flags |= DRV_DCMD_SKIP_REFIRE; 53428c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 53438c2ecf20Sopenharmony_ci megasas_reset_fusion(instance->host, 53448c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_OCR); 53458c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 53468c2ecf20Sopenharmony_ci break; 53478c2ecf20Sopenharmony_ci case KILL_ADAPTER: 53488c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 53498c2ecf20Sopenharmony_ci break; 53508c2ecf20Sopenharmony_ci case IGNORE_TIMEOUT: 53518c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n", 53528c2ecf20Sopenharmony_ci __func__, __LINE__); 53538c2ecf20Sopenharmony_ci break; 53548c2ecf20Sopenharmony_ci } 53558c2ecf20Sopenharmony_ci break; 53568c2ecf20Sopenharmony_ci case DCMD_FAILED: 53578c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 53588c2ecf20Sopenharmony_ci break; 53598c2ecf20Sopenharmony_ci 53608c2ecf20Sopenharmony_ci } 53618c2ecf20Sopenharmony_ci 53628c2ecf20Sopenharmony_ci if (ret != DCMD_TIMEOUT) 53638c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 53648c2ecf20Sopenharmony_ci 53658c2ecf20Sopenharmony_ci return ret; 53668c2ecf20Sopenharmony_ci} 53678c2ecf20Sopenharmony_ci 53688c2ecf20Sopenharmony_ci/* 53698c2ecf20Sopenharmony_ci * megasas_set_crash_dump_params - Sends address of crash dump DMA buffer 53708c2ecf20Sopenharmony_ci * to firmware 53718c2ecf20Sopenharmony_ci * 53728c2ecf20Sopenharmony_ci * @instance: Adapter soft state 53738c2ecf20Sopenharmony_ci * @crash_buf_state - tell FW to turn ON/OFF crash dump feature 53748c2ecf20Sopenharmony_ci MR_CRASH_BUF_TURN_OFF = 0 53758c2ecf20Sopenharmony_ci MR_CRASH_BUF_TURN_ON = 1 53768c2ecf20Sopenharmony_ci * @return 0 on success non-zero on failure. 53778c2ecf20Sopenharmony_ci * Issues an internal command (DCMD) to set parameters for crash dump feature. 53788c2ecf20Sopenharmony_ci * Driver will send address of crash dump DMA buffer and set mbox to tell FW 53798c2ecf20Sopenharmony_ci * that driver supports crash dump feature. This DCMD will be sent only if 53808c2ecf20Sopenharmony_ci * crash dump feature is supported by the FW. 53818c2ecf20Sopenharmony_ci * 53828c2ecf20Sopenharmony_ci */ 53838c2ecf20Sopenharmony_ciint megasas_set_crash_dump_params(struct megasas_instance *instance, 53848c2ecf20Sopenharmony_ci u8 crash_buf_state) 53858c2ecf20Sopenharmony_ci{ 53868c2ecf20Sopenharmony_ci int ret = 0; 53878c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 53888c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 53898c2ecf20Sopenharmony_ci 53908c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 53918c2ecf20Sopenharmony_ci 53928c2ecf20Sopenharmony_ci if (!cmd) { 53938c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed to get a free cmd\n"); 53948c2ecf20Sopenharmony_ci return -ENOMEM; 53958c2ecf20Sopenharmony_ci } 53968c2ecf20Sopenharmony_ci 53978c2ecf20Sopenharmony_ci 53988c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 53998c2ecf20Sopenharmony_ci 54008c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 54018c2ecf20Sopenharmony_ci dcmd->mbox.b[0] = crash_buf_state; 54028c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 54038c2ecf20Sopenharmony_ci dcmd->cmd_status = MFI_STAT_INVALID_STATUS; 54048c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 54058c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_NONE; 54068c2ecf20Sopenharmony_ci dcmd->timeout = 0; 54078c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 54088c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(CRASH_DMA_BUF_SIZE); 54098c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_SET_CRASH_DUMP_PARAMS); 54108c2ecf20Sopenharmony_ci 54118c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, instance->crash_dump_h, 54128c2ecf20Sopenharmony_ci CRASH_DMA_BUF_SIZE); 54138c2ecf20Sopenharmony_ci 54148c2ecf20Sopenharmony_ci if ((instance->adapter_type != MFI_SERIES) && 54158c2ecf20Sopenharmony_ci !instance->mask_interrupts) 54168c2ecf20Sopenharmony_ci ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS); 54178c2ecf20Sopenharmony_ci else 54188c2ecf20Sopenharmony_ci ret = megasas_issue_polled(instance, cmd); 54198c2ecf20Sopenharmony_ci 54208c2ecf20Sopenharmony_ci if (ret == DCMD_TIMEOUT) { 54218c2ecf20Sopenharmony_ci switch (dcmd_timeout_ocr_possible(instance)) { 54228c2ecf20Sopenharmony_ci case INITIATE_OCR: 54238c2ecf20Sopenharmony_ci cmd->flags |= DRV_DCMD_SKIP_REFIRE; 54248c2ecf20Sopenharmony_ci megasas_reset_fusion(instance->host, 54258c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_OCR); 54268c2ecf20Sopenharmony_ci break; 54278c2ecf20Sopenharmony_ci case KILL_ADAPTER: 54288c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 54298c2ecf20Sopenharmony_ci break; 54308c2ecf20Sopenharmony_ci case IGNORE_TIMEOUT: 54318c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n", 54328c2ecf20Sopenharmony_ci __func__, __LINE__); 54338c2ecf20Sopenharmony_ci break; 54348c2ecf20Sopenharmony_ci } 54358c2ecf20Sopenharmony_ci } else 54368c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 54378c2ecf20Sopenharmony_ci 54388c2ecf20Sopenharmony_ci return ret; 54398c2ecf20Sopenharmony_ci} 54408c2ecf20Sopenharmony_ci 54418c2ecf20Sopenharmony_ci/** 54428c2ecf20Sopenharmony_ci * megasas_issue_init_mfi - Initializes the FW 54438c2ecf20Sopenharmony_ci * @instance: Adapter soft state 54448c2ecf20Sopenharmony_ci * 54458c2ecf20Sopenharmony_ci * Issues the INIT MFI cmd 54468c2ecf20Sopenharmony_ci */ 54478c2ecf20Sopenharmony_cistatic int 54488c2ecf20Sopenharmony_cimegasas_issue_init_mfi(struct megasas_instance *instance) 54498c2ecf20Sopenharmony_ci{ 54508c2ecf20Sopenharmony_ci __le32 context; 54518c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 54528c2ecf20Sopenharmony_ci struct megasas_init_frame *init_frame; 54538c2ecf20Sopenharmony_ci struct megasas_init_queue_info *initq_info; 54548c2ecf20Sopenharmony_ci dma_addr_t init_frame_h; 54558c2ecf20Sopenharmony_ci dma_addr_t initq_info_h; 54568c2ecf20Sopenharmony_ci 54578c2ecf20Sopenharmony_ci /* 54588c2ecf20Sopenharmony_ci * Prepare a init frame. Note the init frame points to queue info 54598c2ecf20Sopenharmony_ci * structure. Each frame has SGL allocated after first 64 bytes. For 54608c2ecf20Sopenharmony_ci * this frame - since we don't need any SGL - we use SGL's space as 54618c2ecf20Sopenharmony_ci * queue info structure 54628c2ecf20Sopenharmony_ci * 54638c2ecf20Sopenharmony_ci * We will not get a NULL command below. We just created the pool. 54648c2ecf20Sopenharmony_ci */ 54658c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 54668c2ecf20Sopenharmony_ci 54678c2ecf20Sopenharmony_ci init_frame = (struct megasas_init_frame *)cmd->frame; 54688c2ecf20Sopenharmony_ci initq_info = (struct megasas_init_queue_info *) 54698c2ecf20Sopenharmony_ci ((unsigned long)init_frame + 64); 54708c2ecf20Sopenharmony_ci 54718c2ecf20Sopenharmony_ci init_frame_h = cmd->frame_phys_addr; 54728c2ecf20Sopenharmony_ci initq_info_h = init_frame_h + 64; 54738c2ecf20Sopenharmony_ci 54748c2ecf20Sopenharmony_ci context = init_frame->context; 54758c2ecf20Sopenharmony_ci memset(init_frame, 0, MEGAMFI_FRAME_SIZE); 54768c2ecf20Sopenharmony_ci memset(initq_info, 0, sizeof(struct megasas_init_queue_info)); 54778c2ecf20Sopenharmony_ci init_frame->context = context; 54788c2ecf20Sopenharmony_ci 54798c2ecf20Sopenharmony_ci initq_info->reply_queue_entries = cpu_to_le32(instance->max_fw_cmds + 1); 54808c2ecf20Sopenharmony_ci initq_info->reply_queue_start_phys_addr_lo = cpu_to_le32(instance->reply_queue_h); 54818c2ecf20Sopenharmony_ci 54828c2ecf20Sopenharmony_ci initq_info->producer_index_phys_addr_lo = cpu_to_le32(instance->producer_h); 54838c2ecf20Sopenharmony_ci initq_info->consumer_index_phys_addr_lo = cpu_to_le32(instance->consumer_h); 54848c2ecf20Sopenharmony_ci 54858c2ecf20Sopenharmony_ci init_frame->cmd = MFI_CMD_INIT; 54868c2ecf20Sopenharmony_ci init_frame->cmd_status = MFI_STAT_INVALID_STATUS; 54878c2ecf20Sopenharmony_ci init_frame->queue_info_new_phys_addr_lo = 54888c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(initq_info_h)); 54898c2ecf20Sopenharmony_ci init_frame->queue_info_new_phys_addr_hi = 54908c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(initq_info_h)); 54918c2ecf20Sopenharmony_ci 54928c2ecf20Sopenharmony_ci init_frame->data_xfer_len = cpu_to_le32(sizeof(struct megasas_init_queue_info)); 54938c2ecf20Sopenharmony_ci 54948c2ecf20Sopenharmony_ci /* 54958c2ecf20Sopenharmony_ci * disable the intr before firing the init frame to FW 54968c2ecf20Sopenharmony_ci */ 54978c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 54988c2ecf20Sopenharmony_ci 54998c2ecf20Sopenharmony_ci /* 55008c2ecf20Sopenharmony_ci * Issue the init frame in polled mode 55018c2ecf20Sopenharmony_ci */ 55028c2ecf20Sopenharmony_ci 55038c2ecf20Sopenharmony_ci if (megasas_issue_polled(instance, cmd)) { 55048c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed to init firmware\n"); 55058c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 55068c2ecf20Sopenharmony_ci goto fail_fw_init; 55078c2ecf20Sopenharmony_ci } 55088c2ecf20Sopenharmony_ci 55098c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 55108c2ecf20Sopenharmony_ci 55118c2ecf20Sopenharmony_ci return 0; 55128c2ecf20Sopenharmony_ci 55138c2ecf20Sopenharmony_cifail_fw_init: 55148c2ecf20Sopenharmony_ci return -EINVAL; 55158c2ecf20Sopenharmony_ci} 55168c2ecf20Sopenharmony_ci 55178c2ecf20Sopenharmony_cistatic u32 55188c2ecf20Sopenharmony_cimegasas_init_adapter_mfi(struct megasas_instance *instance) 55198c2ecf20Sopenharmony_ci{ 55208c2ecf20Sopenharmony_ci u32 context_sz; 55218c2ecf20Sopenharmony_ci u32 reply_q_sz; 55228c2ecf20Sopenharmony_ci 55238c2ecf20Sopenharmony_ci /* 55248c2ecf20Sopenharmony_ci * Get various operational parameters from status register 55258c2ecf20Sopenharmony_ci */ 55268c2ecf20Sopenharmony_ci instance->max_fw_cmds = instance->instancet->read_fw_status_reg(instance) & 0x00FFFF; 55278c2ecf20Sopenharmony_ci /* 55288c2ecf20Sopenharmony_ci * Reduce the max supported cmds by 1. This is to ensure that the 55298c2ecf20Sopenharmony_ci * reply_q_sz (1 more than the max cmd that driver may send) 55308c2ecf20Sopenharmony_ci * does not exceed max cmds that the FW can support 55318c2ecf20Sopenharmony_ci */ 55328c2ecf20Sopenharmony_ci instance->max_fw_cmds = instance->max_fw_cmds-1; 55338c2ecf20Sopenharmony_ci instance->max_mfi_cmds = instance->max_fw_cmds; 55348c2ecf20Sopenharmony_ci instance->max_num_sge = (instance->instancet->read_fw_status_reg(instance) & 0xFF0000) >> 55358c2ecf20Sopenharmony_ci 0x10; 55368c2ecf20Sopenharmony_ci /* 55378c2ecf20Sopenharmony_ci * For MFI skinny adapters, MEGASAS_SKINNY_INT_CMDS commands 55388c2ecf20Sopenharmony_ci * are reserved for IOCTL + driver's internal DCMDs. 55398c2ecf20Sopenharmony_ci */ 55408c2ecf20Sopenharmony_ci if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || 55418c2ecf20Sopenharmony_ci (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { 55428c2ecf20Sopenharmony_ci instance->max_scsi_cmds = (instance->max_fw_cmds - 55438c2ecf20Sopenharmony_ci MEGASAS_SKINNY_INT_CMDS); 55448c2ecf20Sopenharmony_ci sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS); 55458c2ecf20Sopenharmony_ci } else { 55468c2ecf20Sopenharmony_ci instance->max_scsi_cmds = (instance->max_fw_cmds - 55478c2ecf20Sopenharmony_ci MEGASAS_INT_CMDS); 55488c2ecf20Sopenharmony_ci sema_init(&instance->ioctl_sem, (MEGASAS_MFI_IOCTL_CMDS)); 55498c2ecf20Sopenharmony_ci } 55508c2ecf20Sopenharmony_ci 55518c2ecf20Sopenharmony_ci instance->cur_can_queue = instance->max_scsi_cmds; 55528c2ecf20Sopenharmony_ci /* 55538c2ecf20Sopenharmony_ci * Create a pool of commands 55548c2ecf20Sopenharmony_ci */ 55558c2ecf20Sopenharmony_ci if (megasas_alloc_cmds(instance)) 55568c2ecf20Sopenharmony_ci goto fail_alloc_cmds; 55578c2ecf20Sopenharmony_ci 55588c2ecf20Sopenharmony_ci /* 55598c2ecf20Sopenharmony_ci * Allocate memory for reply queue. Length of reply queue should 55608c2ecf20Sopenharmony_ci * be _one_ more than the maximum commands handled by the firmware. 55618c2ecf20Sopenharmony_ci * 55628c2ecf20Sopenharmony_ci * Note: When FW completes commands, it places corresponding contex 55638c2ecf20Sopenharmony_ci * values in this circular reply queue. This circular queue is a fairly 55648c2ecf20Sopenharmony_ci * typical producer-consumer queue. FW is the producer (of completed 55658c2ecf20Sopenharmony_ci * commands) and the driver is the consumer. 55668c2ecf20Sopenharmony_ci */ 55678c2ecf20Sopenharmony_ci context_sz = sizeof(u32); 55688c2ecf20Sopenharmony_ci reply_q_sz = context_sz * (instance->max_fw_cmds + 1); 55698c2ecf20Sopenharmony_ci 55708c2ecf20Sopenharmony_ci instance->reply_queue = dma_alloc_coherent(&instance->pdev->dev, 55718c2ecf20Sopenharmony_ci reply_q_sz, &instance->reply_queue_h, GFP_KERNEL); 55728c2ecf20Sopenharmony_ci 55738c2ecf20Sopenharmony_ci if (!instance->reply_queue) { 55748c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "Out of DMA mem for reply queue\n"); 55758c2ecf20Sopenharmony_ci goto fail_reply_queue; 55768c2ecf20Sopenharmony_ci } 55778c2ecf20Sopenharmony_ci 55788c2ecf20Sopenharmony_ci if (megasas_issue_init_mfi(instance)) 55798c2ecf20Sopenharmony_ci goto fail_fw_init; 55808c2ecf20Sopenharmony_ci 55818c2ecf20Sopenharmony_ci if (megasas_get_ctrl_info(instance)) { 55828c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "(%d): Could get controller info " 55838c2ecf20Sopenharmony_ci "Fail from %s %d\n", instance->unique_id, 55848c2ecf20Sopenharmony_ci __func__, __LINE__); 55858c2ecf20Sopenharmony_ci goto fail_fw_init; 55868c2ecf20Sopenharmony_ci } 55878c2ecf20Sopenharmony_ci 55888c2ecf20Sopenharmony_ci instance->fw_support_ieee = 0; 55898c2ecf20Sopenharmony_ci instance->fw_support_ieee = 55908c2ecf20Sopenharmony_ci (instance->instancet->read_fw_status_reg(instance) & 55918c2ecf20Sopenharmony_ci 0x04000000); 55928c2ecf20Sopenharmony_ci 55938c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "megasas_init_mfi: fw_support_ieee=%d", 55948c2ecf20Sopenharmony_ci instance->fw_support_ieee); 55958c2ecf20Sopenharmony_ci 55968c2ecf20Sopenharmony_ci if (instance->fw_support_ieee) 55978c2ecf20Sopenharmony_ci instance->flag_ieee = 1; 55988c2ecf20Sopenharmony_ci 55998c2ecf20Sopenharmony_ci return 0; 56008c2ecf20Sopenharmony_ci 56018c2ecf20Sopenharmony_cifail_fw_init: 56028c2ecf20Sopenharmony_ci 56038c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, reply_q_sz, 56048c2ecf20Sopenharmony_ci instance->reply_queue, instance->reply_queue_h); 56058c2ecf20Sopenharmony_cifail_reply_queue: 56068c2ecf20Sopenharmony_ci megasas_free_cmds(instance); 56078c2ecf20Sopenharmony_ci 56088c2ecf20Sopenharmony_cifail_alloc_cmds: 56098c2ecf20Sopenharmony_ci return 1; 56108c2ecf20Sopenharmony_ci} 56118c2ecf20Sopenharmony_ci 56128c2ecf20Sopenharmony_cistatic 56138c2ecf20Sopenharmony_civoid megasas_setup_irq_poll(struct megasas_instance *instance) 56148c2ecf20Sopenharmony_ci{ 56158c2ecf20Sopenharmony_ci struct megasas_irq_context *irq_ctx; 56168c2ecf20Sopenharmony_ci u32 count, i; 56178c2ecf20Sopenharmony_ci 56188c2ecf20Sopenharmony_ci count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; 56198c2ecf20Sopenharmony_ci 56208c2ecf20Sopenharmony_ci /* Initialize IRQ poll */ 56218c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 56228c2ecf20Sopenharmony_ci irq_ctx = &instance->irq_context[i]; 56238c2ecf20Sopenharmony_ci irq_ctx->os_irq = pci_irq_vector(instance->pdev, i); 56248c2ecf20Sopenharmony_ci irq_ctx->irq_poll_scheduled = false; 56258c2ecf20Sopenharmony_ci irq_poll_init(&irq_ctx->irqpoll, 56268c2ecf20Sopenharmony_ci instance->threshold_reply_count, 56278c2ecf20Sopenharmony_ci megasas_irqpoll); 56288c2ecf20Sopenharmony_ci } 56298c2ecf20Sopenharmony_ci} 56308c2ecf20Sopenharmony_ci 56318c2ecf20Sopenharmony_ci/* 56328c2ecf20Sopenharmony_ci * megasas_setup_irqs_ioapic - register legacy interrupts. 56338c2ecf20Sopenharmony_ci * @instance: Adapter soft state 56348c2ecf20Sopenharmony_ci * 56358c2ecf20Sopenharmony_ci * Do not enable interrupt, only setup ISRs. 56368c2ecf20Sopenharmony_ci * 56378c2ecf20Sopenharmony_ci * Return 0 on success. 56388c2ecf20Sopenharmony_ci */ 56398c2ecf20Sopenharmony_cistatic int 56408c2ecf20Sopenharmony_cimegasas_setup_irqs_ioapic(struct megasas_instance *instance) 56418c2ecf20Sopenharmony_ci{ 56428c2ecf20Sopenharmony_ci struct pci_dev *pdev; 56438c2ecf20Sopenharmony_ci 56448c2ecf20Sopenharmony_ci pdev = instance->pdev; 56458c2ecf20Sopenharmony_ci instance->irq_context[0].instance = instance; 56468c2ecf20Sopenharmony_ci instance->irq_context[0].MSIxIndex = 0; 56478c2ecf20Sopenharmony_ci snprintf(instance->irq_context->name, MEGASAS_MSIX_NAME_LEN, "%s%u", 56488c2ecf20Sopenharmony_ci "megasas", instance->host->host_no); 56498c2ecf20Sopenharmony_ci if (request_irq(pci_irq_vector(pdev, 0), 56508c2ecf20Sopenharmony_ci instance->instancet->service_isr, IRQF_SHARED, 56518c2ecf20Sopenharmony_ci instance->irq_context->name, &instance->irq_context[0])) { 56528c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 56538c2ecf20Sopenharmony_ci "Failed to register IRQ from %s %d\n", 56548c2ecf20Sopenharmony_ci __func__, __LINE__); 56558c2ecf20Sopenharmony_ci return -1; 56568c2ecf20Sopenharmony_ci } 56578c2ecf20Sopenharmony_ci instance->perf_mode = MR_LATENCY_PERF_MODE; 56588c2ecf20Sopenharmony_ci instance->low_latency_index_start = 0; 56598c2ecf20Sopenharmony_ci return 0; 56608c2ecf20Sopenharmony_ci} 56618c2ecf20Sopenharmony_ci 56628c2ecf20Sopenharmony_ci/** 56638c2ecf20Sopenharmony_ci * megasas_setup_irqs_msix - register MSI-x interrupts. 56648c2ecf20Sopenharmony_ci * @instance: Adapter soft state 56658c2ecf20Sopenharmony_ci * @is_probe: Driver probe check 56668c2ecf20Sopenharmony_ci * 56678c2ecf20Sopenharmony_ci * Do not enable interrupt, only setup ISRs. 56688c2ecf20Sopenharmony_ci * 56698c2ecf20Sopenharmony_ci * Return 0 on success. 56708c2ecf20Sopenharmony_ci */ 56718c2ecf20Sopenharmony_cistatic int 56728c2ecf20Sopenharmony_cimegasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe) 56738c2ecf20Sopenharmony_ci{ 56748c2ecf20Sopenharmony_ci int i, j; 56758c2ecf20Sopenharmony_ci struct pci_dev *pdev; 56768c2ecf20Sopenharmony_ci 56778c2ecf20Sopenharmony_ci pdev = instance->pdev; 56788c2ecf20Sopenharmony_ci 56798c2ecf20Sopenharmony_ci /* Try MSI-x */ 56808c2ecf20Sopenharmony_ci for (i = 0; i < instance->msix_vectors; i++) { 56818c2ecf20Sopenharmony_ci instance->irq_context[i].instance = instance; 56828c2ecf20Sopenharmony_ci instance->irq_context[i].MSIxIndex = i; 56838c2ecf20Sopenharmony_ci snprintf(instance->irq_context[i].name, MEGASAS_MSIX_NAME_LEN, "%s%u-msix%u", 56848c2ecf20Sopenharmony_ci "megasas", instance->host->host_no, i); 56858c2ecf20Sopenharmony_ci if (request_irq(pci_irq_vector(pdev, i), 56868c2ecf20Sopenharmony_ci instance->instancet->service_isr, 0, instance->irq_context[i].name, 56878c2ecf20Sopenharmony_ci &instance->irq_context[i])) { 56888c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 56898c2ecf20Sopenharmony_ci "Failed to register IRQ for vector %d.\n", i); 56908c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) { 56918c2ecf20Sopenharmony_ci if (j < instance->low_latency_index_start) 56928c2ecf20Sopenharmony_ci irq_set_affinity_hint( 56938c2ecf20Sopenharmony_ci pci_irq_vector(pdev, j), NULL); 56948c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(pdev, j), 56958c2ecf20Sopenharmony_ci &instance->irq_context[j]); 56968c2ecf20Sopenharmony_ci } 56978c2ecf20Sopenharmony_ci /* Retry irq register for IO_APIC*/ 56988c2ecf20Sopenharmony_ci instance->msix_vectors = 0; 56998c2ecf20Sopenharmony_ci instance->msix_load_balance = false; 57008c2ecf20Sopenharmony_ci if (is_probe) { 57018c2ecf20Sopenharmony_ci pci_free_irq_vectors(instance->pdev); 57028c2ecf20Sopenharmony_ci return megasas_setup_irqs_ioapic(instance); 57038c2ecf20Sopenharmony_ci } else { 57048c2ecf20Sopenharmony_ci return -1; 57058c2ecf20Sopenharmony_ci } 57068c2ecf20Sopenharmony_ci } 57078c2ecf20Sopenharmony_ci } 57088c2ecf20Sopenharmony_ci 57098c2ecf20Sopenharmony_ci return 0; 57108c2ecf20Sopenharmony_ci} 57118c2ecf20Sopenharmony_ci 57128c2ecf20Sopenharmony_ci/* 57138c2ecf20Sopenharmony_ci * megasas_destroy_irqs- unregister interrupts. 57148c2ecf20Sopenharmony_ci * @instance: Adapter soft state 57158c2ecf20Sopenharmony_ci * return: void 57168c2ecf20Sopenharmony_ci */ 57178c2ecf20Sopenharmony_cistatic void 57188c2ecf20Sopenharmony_cimegasas_destroy_irqs(struct megasas_instance *instance) { 57198c2ecf20Sopenharmony_ci 57208c2ecf20Sopenharmony_ci int i; 57218c2ecf20Sopenharmony_ci int count; 57228c2ecf20Sopenharmony_ci struct megasas_irq_context *irq_ctx; 57238c2ecf20Sopenharmony_ci 57248c2ecf20Sopenharmony_ci count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; 57258c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) { 57268c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 57278c2ecf20Sopenharmony_ci irq_ctx = &instance->irq_context[i]; 57288c2ecf20Sopenharmony_ci irq_poll_disable(&irq_ctx->irqpoll); 57298c2ecf20Sopenharmony_ci } 57308c2ecf20Sopenharmony_ci } 57318c2ecf20Sopenharmony_ci 57328c2ecf20Sopenharmony_ci if (instance->msix_vectors) 57338c2ecf20Sopenharmony_ci for (i = 0; i < instance->msix_vectors; i++) { 57348c2ecf20Sopenharmony_ci if (i < instance->low_latency_index_start) 57358c2ecf20Sopenharmony_ci irq_set_affinity_hint( 57368c2ecf20Sopenharmony_ci pci_irq_vector(instance->pdev, i), NULL); 57378c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(instance->pdev, i), 57388c2ecf20Sopenharmony_ci &instance->irq_context[i]); 57398c2ecf20Sopenharmony_ci } 57408c2ecf20Sopenharmony_ci else 57418c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(instance->pdev, 0), 57428c2ecf20Sopenharmony_ci &instance->irq_context[0]); 57438c2ecf20Sopenharmony_ci} 57448c2ecf20Sopenharmony_ci 57458c2ecf20Sopenharmony_ci/** 57468c2ecf20Sopenharmony_ci * megasas_setup_jbod_map - setup jbod map for FP seq_number. 57478c2ecf20Sopenharmony_ci * @instance: Adapter soft state 57488c2ecf20Sopenharmony_ci * 57498c2ecf20Sopenharmony_ci * Return 0 on success. 57508c2ecf20Sopenharmony_ci */ 57518c2ecf20Sopenharmony_civoid 57528c2ecf20Sopenharmony_cimegasas_setup_jbod_map(struct megasas_instance *instance) 57538c2ecf20Sopenharmony_ci{ 57548c2ecf20Sopenharmony_ci int i; 57558c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 57568c2ecf20Sopenharmony_ci u32 pd_seq_map_sz; 57578c2ecf20Sopenharmony_ci 57588c2ecf20Sopenharmony_ci pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + 57598c2ecf20Sopenharmony_ci (sizeof(struct MR_PD_CFG_SEQ) * (MAX_PHYSICAL_DEVICES - 1)); 57608c2ecf20Sopenharmony_ci 57618c2ecf20Sopenharmony_ci instance->use_seqnum_jbod_fp = 57628c2ecf20Sopenharmony_ci instance->support_seqnum_jbod_fp; 57638c2ecf20Sopenharmony_ci if (reset_devices || !fusion || 57648c2ecf20Sopenharmony_ci !instance->support_seqnum_jbod_fp) { 57658c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 57668c2ecf20Sopenharmony_ci "JBOD sequence map is disabled %s %d\n", 57678c2ecf20Sopenharmony_ci __func__, __LINE__); 57688c2ecf20Sopenharmony_ci instance->use_seqnum_jbod_fp = false; 57698c2ecf20Sopenharmony_ci return; 57708c2ecf20Sopenharmony_ci } 57718c2ecf20Sopenharmony_ci 57728c2ecf20Sopenharmony_ci if (fusion->pd_seq_sync[0]) 57738c2ecf20Sopenharmony_ci goto skip_alloc; 57748c2ecf20Sopenharmony_ci 57758c2ecf20Sopenharmony_ci for (i = 0; i < JBOD_MAPS_COUNT; i++) { 57768c2ecf20Sopenharmony_ci fusion->pd_seq_sync[i] = dma_alloc_coherent 57778c2ecf20Sopenharmony_ci (&instance->pdev->dev, pd_seq_map_sz, 57788c2ecf20Sopenharmony_ci &fusion->pd_seq_phys[i], GFP_KERNEL); 57798c2ecf20Sopenharmony_ci if (!fusion->pd_seq_sync[i]) { 57808c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 57818c2ecf20Sopenharmony_ci "Failed to allocate memory from %s %d\n", 57828c2ecf20Sopenharmony_ci __func__, __LINE__); 57838c2ecf20Sopenharmony_ci if (i == 1) { 57848c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, 57858c2ecf20Sopenharmony_ci pd_seq_map_sz, fusion->pd_seq_sync[0], 57868c2ecf20Sopenharmony_ci fusion->pd_seq_phys[0]); 57878c2ecf20Sopenharmony_ci fusion->pd_seq_sync[0] = NULL; 57888c2ecf20Sopenharmony_ci } 57898c2ecf20Sopenharmony_ci instance->use_seqnum_jbod_fp = false; 57908c2ecf20Sopenharmony_ci return; 57918c2ecf20Sopenharmony_ci } 57928c2ecf20Sopenharmony_ci } 57938c2ecf20Sopenharmony_ci 57948c2ecf20Sopenharmony_ciskip_alloc: 57958c2ecf20Sopenharmony_ci if (!megasas_sync_pd_seq_num(instance, false) && 57968c2ecf20Sopenharmony_ci !megasas_sync_pd_seq_num(instance, true)) 57978c2ecf20Sopenharmony_ci instance->use_seqnum_jbod_fp = true; 57988c2ecf20Sopenharmony_ci else 57998c2ecf20Sopenharmony_ci instance->use_seqnum_jbod_fp = false; 58008c2ecf20Sopenharmony_ci} 58018c2ecf20Sopenharmony_ci 58028c2ecf20Sopenharmony_cistatic void megasas_setup_reply_map(struct megasas_instance *instance) 58038c2ecf20Sopenharmony_ci{ 58048c2ecf20Sopenharmony_ci const struct cpumask *mask; 58058c2ecf20Sopenharmony_ci unsigned int queue, cpu, low_latency_index_start; 58068c2ecf20Sopenharmony_ci 58078c2ecf20Sopenharmony_ci low_latency_index_start = instance->low_latency_index_start; 58088c2ecf20Sopenharmony_ci 58098c2ecf20Sopenharmony_ci for (queue = low_latency_index_start; queue < instance->msix_vectors; queue++) { 58108c2ecf20Sopenharmony_ci mask = pci_irq_get_affinity(instance->pdev, queue); 58118c2ecf20Sopenharmony_ci if (!mask) 58128c2ecf20Sopenharmony_ci goto fallback; 58138c2ecf20Sopenharmony_ci 58148c2ecf20Sopenharmony_ci for_each_cpu(cpu, mask) 58158c2ecf20Sopenharmony_ci instance->reply_map[cpu] = queue; 58168c2ecf20Sopenharmony_ci } 58178c2ecf20Sopenharmony_ci return; 58188c2ecf20Sopenharmony_ci 58198c2ecf20Sopenharmony_cifallback: 58208c2ecf20Sopenharmony_ci queue = low_latency_index_start; 58218c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 58228c2ecf20Sopenharmony_ci instance->reply_map[cpu] = queue; 58238c2ecf20Sopenharmony_ci if (queue == (instance->msix_vectors - 1)) 58248c2ecf20Sopenharmony_ci queue = low_latency_index_start; 58258c2ecf20Sopenharmony_ci else 58268c2ecf20Sopenharmony_ci queue++; 58278c2ecf20Sopenharmony_ci } 58288c2ecf20Sopenharmony_ci} 58298c2ecf20Sopenharmony_ci 58308c2ecf20Sopenharmony_ci/** 58318c2ecf20Sopenharmony_ci * megasas_get_device_list - Get the PD and LD device list from FW. 58328c2ecf20Sopenharmony_ci * @instance: Adapter soft state 58338c2ecf20Sopenharmony_ci * @return: Success or failure 58348c2ecf20Sopenharmony_ci * 58358c2ecf20Sopenharmony_ci * Issue DCMDs to Firmware to get the PD and LD list. 58368c2ecf20Sopenharmony_ci * Based on the FW support, driver sends the HOST_DEVICE_LIST or combination 58378c2ecf20Sopenharmony_ci * of PD_LIST/LD_LIST_QUERY DCMDs to get the device list. 58388c2ecf20Sopenharmony_ci */ 58398c2ecf20Sopenharmony_cistatic 58408c2ecf20Sopenharmony_ciint megasas_get_device_list(struct megasas_instance *instance) 58418c2ecf20Sopenharmony_ci{ 58428c2ecf20Sopenharmony_ci memset(instance->pd_list, 0, 58438c2ecf20Sopenharmony_ci (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list))); 58448c2ecf20Sopenharmony_ci memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); 58458c2ecf20Sopenharmony_ci 58468c2ecf20Sopenharmony_ci if (instance->enable_fw_dev_list) { 58478c2ecf20Sopenharmony_ci if (megasas_host_device_list_query(instance, true)) 58488c2ecf20Sopenharmony_ci return FAILED; 58498c2ecf20Sopenharmony_ci } else { 58508c2ecf20Sopenharmony_ci if (megasas_get_pd_list(instance) < 0) { 58518c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "failed to get PD list\n"); 58528c2ecf20Sopenharmony_ci return FAILED; 58538c2ecf20Sopenharmony_ci } 58548c2ecf20Sopenharmony_ci 58558c2ecf20Sopenharmony_ci if (megasas_ld_list_query(instance, 58568c2ecf20Sopenharmony_ci MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) { 58578c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "failed to get LD list\n"); 58588c2ecf20Sopenharmony_ci return FAILED; 58598c2ecf20Sopenharmony_ci } 58608c2ecf20Sopenharmony_ci } 58618c2ecf20Sopenharmony_ci 58628c2ecf20Sopenharmony_ci return SUCCESS; 58638c2ecf20Sopenharmony_ci} 58648c2ecf20Sopenharmony_ci 58658c2ecf20Sopenharmony_ci/** 58668c2ecf20Sopenharmony_ci * megasas_set_high_iops_queue_affinity_hint - Set affinity hint for high IOPS queues 58678c2ecf20Sopenharmony_ci * @instance: Adapter soft state 58688c2ecf20Sopenharmony_ci * return: void 58698c2ecf20Sopenharmony_ci */ 58708c2ecf20Sopenharmony_cistatic inline void 58718c2ecf20Sopenharmony_cimegasas_set_high_iops_queue_affinity_hint(struct megasas_instance *instance) 58728c2ecf20Sopenharmony_ci{ 58738c2ecf20Sopenharmony_ci int i; 58748c2ecf20Sopenharmony_ci int local_numa_node; 58758c2ecf20Sopenharmony_ci 58768c2ecf20Sopenharmony_ci if (instance->perf_mode == MR_BALANCED_PERF_MODE) { 58778c2ecf20Sopenharmony_ci local_numa_node = dev_to_node(&instance->pdev->dev); 58788c2ecf20Sopenharmony_ci 58798c2ecf20Sopenharmony_ci for (i = 0; i < instance->low_latency_index_start; i++) 58808c2ecf20Sopenharmony_ci irq_set_affinity_hint(pci_irq_vector(instance->pdev, i), 58818c2ecf20Sopenharmony_ci cpumask_of_node(local_numa_node)); 58828c2ecf20Sopenharmony_ci } 58838c2ecf20Sopenharmony_ci} 58848c2ecf20Sopenharmony_ci 58858c2ecf20Sopenharmony_cistatic int 58868c2ecf20Sopenharmony_ci__megasas_alloc_irq_vectors(struct megasas_instance *instance) 58878c2ecf20Sopenharmony_ci{ 58888c2ecf20Sopenharmony_ci int i, irq_flags; 58898c2ecf20Sopenharmony_ci struct irq_affinity desc = { .pre_vectors = instance->low_latency_index_start }; 58908c2ecf20Sopenharmony_ci struct irq_affinity *descp = &desc; 58918c2ecf20Sopenharmony_ci 58928c2ecf20Sopenharmony_ci irq_flags = PCI_IRQ_MSIX; 58938c2ecf20Sopenharmony_ci 58948c2ecf20Sopenharmony_ci if (instance->smp_affinity_enable) 58958c2ecf20Sopenharmony_ci irq_flags |= PCI_IRQ_AFFINITY; 58968c2ecf20Sopenharmony_ci else 58978c2ecf20Sopenharmony_ci descp = NULL; 58988c2ecf20Sopenharmony_ci 58998c2ecf20Sopenharmony_ci i = pci_alloc_irq_vectors_affinity(instance->pdev, 59008c2ecf20Sopenharmony_ci instance->low_latency_index_start, 59018c2ecf20Sopenharmony_ci instance->msix_vectors, irq_flags, descp); 59028c2ecf20Sopenharmony_ci 59038c2ecf20Sopenharmony_ci return i; 59048c2ecf20Sopenharmony_ci} 59058c2ecf20Sopenharmony_ci 59068c2ecf20Sopenharmony_ci/** 59078c2ecf20Sopenharmony_ci * megasas_alloc_irq_vectors - Allocate IRQ vectors/enable MSI-x vectors 59088c2ecf20Sopenharmony_ci * @instance: Adapter soft state 59098c2ecf20Sopenharmony_ci * return: void 59108c2ecf20Sopenharmony_ci */ 59118c2ecf20Sopenharmony_cistatic void 59128c2ecf20Sopenharmony_cimegasas_alloc_irq_vectors(struct megasas_instance *instance) 59138c2ecf20Sopenharmony_ci{ 59148c2ecf20Sopenharmony_ci int i; 59158c2ecf20Sopenharmony_ci unsigned int num_msix_req; 59168c2ecf20Sopenharmony_ci 59178c2ecf20Sopenharmony_ci i = __megasas_alloc_irq_vectors(instance); 59188c2ecf20Sopenharmony_ci 59198c2ecf20Sopenharmony_ci if ((instance->perf_mode == MR_BALANCED_PERF_MODE) && 59208c2ecf20Sopenharmony_ci (i != instance->msix_vectors)) { 59218c2ecf20Sopenharmony_ci if (instance->msix_vectors) 59228c2ecf20Sopenharmony_ci pci_free_irq_vectors(instance->pdev); 59238c2ecf20Sopenharmony_ci /* Disable Balanced IOPS mode and try realloc vectors */ 59248c2ecf20Sopenharmony_ci instance->perf_mode = MR_LATENCY_PERF_MODE; 59258c2ecf20Sopenharmony_ci instance->low_latency_index_start = 1; 59268c2ecf20Sopenharmony_ci num_msix_req = num_online_cpus() + instance->low_latency_index_start; 59278c2ecf20Sopenharmony_ci 59288c2ecf20Sopenharmony_ci instance->msix_vectors = min(num_msix_req, 59298c2ecf20Sopenharmony_ci instance->msix_vectors); 59308c2ecf20Sopenharmony_ci 59318c2ecf20Sopenharmony_ci i = __megasas_alloc_irq_vectors(instance); 59328c2ecf20Sopenharmony_ci 59338c2ecf20Sopenharmony_ci } 59348c2ecf20Sopenharmony_ci 59358c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 59368c2ecf20Sopenharmony_ci "requested/available msix %d/%d\n", instance->msix_vectors, i); 59378c2ecf20Sopenharmony_ci 59388c2ecf20Sopenharmony_ci if (i > 0) 59398c2ecf20Sopenharmony_ci instance->msix_vectors = i; 59408c2ecf20Sopenharmony_ci else 59418c2ecf20Sopenharmony_ci instance->msix_vectors = 0; 59428c2ecf20Sopenharmony_ci 59438c2ecf20Sopenharmony_ci if (instance->smp_affinity_enable) 59448c2ecf20Sopenharmony_ci megasas_set_high_iops_queue_affinity_hint(instance); 59458c2ecf20Sopenharmony_ci} 59468c2ecf20Sopenharmony_ci 59478c2ecf20Sopenharmony_ci/** 59488c2ecf20Sopenharmony_ci * megasas_init_fw - Initializes the FW 59498c2ecf20Sopenharmony_ci * @instance: Adapter soft state 59508c2ecf20Sopenharmony_ci * 59518c2ecf20Sopenharmony_ci * This is the main function for initializing firmware 59528c2ecf20Sopenharmony_ci */ 59538c2ecf20Sopenharmony_ci 59548c2ecf20Sopenharmony_cistatic int megasas_init_fw(struct megasas_instance *instance) 59558c2ecf20Sopenharmony_ci{ 59568c2ecf20Sopenharmony_ci u32 max_sectors_1; 59578c2ecf20Sopenharmony_ci u32 max_sectors_2, tmp_sectors, msix_enable; 59588c2ecf20Sopenharmony_ci u32 scratch_pad_1, scratch_pad_2, scratch_pad_3, status_reg; 59598c2ecf20Sopenharmony_ci resource_size_t base_addr; 59608c2ecf20Sopenharmony_ci void *base_addr_phys; 59618c2ecf20Sopenharmony_ci struct megasas_ctrl_info *ctrl_info = NULL; 59628c2ecf20Sopenharmony_ci unsigned long bar_list; 59638c2ecf20Sopenharmony_ci int i, j, loop; 59648c2ecf20Sopenharmony_ci struct IOV_111 *iovPtr; 59658c2ecf20Sopenharmony_ci struct fusion_context *fusion; 59668c2ecf20Sopenharmony_ci bool intr_coalescing; 59678c2ecf20Sopenharmony_ci unsigned int num_msix_req; 59688c2ecf20Sopenharmony_ci u16 lnksta, speed; 59698c2ecf20Sopenharmony_ci 59708c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 59718c2ecf20Sopenharmony_ci 59728c2ecf20Sopenharmony_ci /* Find first memory bar */ 59738c2ecf20Sopenharmony_ci bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM); 59748c2ecf20Sopenharmony_ci instance->bar = find_first_bit(&bar_list, BITS_PER_LONG); 59758c2ecf20Sopenharmony_ci if (pci_request_selected_regions(instance->pdev, 1<<instance->bar, 59768c2ecf20Sopenharmony_ci "megasas: LSI")) { 59778c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "IO memory region busy!\n"); 59788c2ecf20Sopenharmony_ci return -EBUSY; 59798c2ecf20Sopenharmony_ci } 59808c2ecf20Sopenharmony_ci 59818c2ecf20Sopenharmony_ci base_addr = pci_resource_start(instance->pdev, instance->bar); 59828c2ecf20Sopenharmony_ci instance->reg_set = ioremap(base_addr, 8192); 59838c2ecf20Sopenharmony_ci 59848c2ecf20Sopenharmony_ci if (!instance->reg_set) { 59858c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to map IO mem\n"); 59868c2ecf20Sopenharmony_ci goto fail_ioremap; 59878c2ecf20Sopenharmony_ci } 59888c2ecf20Sopenharmony_ci 59898c2ecf20Sopenharmony_ci base_addr_phys = &base_addr; 59908c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, 59918c2ecf20Sopenharmony_ci "BAR:0x%lx BAR's base_addr(phys):%pa mapped virt_addr:0x%p\n", 59928c2ecf20Sopenharmony_ci instance->bar, base_addr_phys, instance->reg_set); 59938c2ecf20Sopenharmony_ci 59948c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) 59958c2ecf20Sopenharmony_ci instance->instancet = &megasas_instance_template_fusion; 59968c2ecf20Sopenharmony_ci else { 59978c2ecf20Sopenharmony_ci switch (instance->pdev->device) { 59988c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_SAS1078R: 59998c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_SAS1078DE: 60008c2ecf20Sopenharmony_ci instance->instancet = &megasas_instance_template_ppc; 60018c2ecf20Sopenharmony_ci break; 60028c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_SAS1078GEN2: 60038c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_SAS0079GEN2: 60048c2ecf20Sopenharmony_ci instance->instancet = &megasas_instance_template_gen2; 60058c2ecf20Sopenharmony_ci break; 60068c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_SAS0073SKINNY: 60078c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_SAS0071SKINNY: 60088c2ecf20Sopenharmony_ci instance->instancet = &megasas_instance_template_skinny; 60098c2ecf20Sopenharmony_ci break; 60108c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_SAS1064R: 60118c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_DELL_PERC5: 60128c2ecf20Sopenharmony_ci default: 60138c2ecf20Sopenharmony_ci instance->instancet = &megasas_instance_template_xscale; 60148c2ecf20Sopenharmony_ci instance->pd_list_not_supported = 1; 60158c2ecf20Sopenharmony_ci break; 60168c2ecf20Sopenharmony_ci } 60178c2ecf20Sopenharmony_ci } 60188c2ecf20Sopenharmony_ci 60198c2ecf20Sopenharmony_ci if (megasas_transition_to_ready(instance, 0)) { 60208c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 60218c2ecf20Sopenharmony_ci "Failed to transition controller to ready from %s!\n", 60228c2ecf20Sopenharmony_ci __func__); 60238c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) { 60248c2ecf20Sopenharmony_ci status_reg = instance->instancet->read_fw_status_reg( 60258c2ecf20Sopenharmony_ci instance); 60268c2ecf20Sopenharmony_ci if (status_reg & MFI_RESET_ADAPTER) { 60278c2ecf20Sopenharmony_ci if (megasas_adp_reset_wait_for_ready 60288c2ecf20Sopenharmony_ci (instance, true, 0) == FAILED) 60298c2ecf20Sopenharmony_ci goto fail_ready_state; 60308c2ecf20Sopenharmony_ci } else { 60318c2ecf20Sopenharmony_ci goto fail_ready_state; 60328c2ecf20Sopenharmony_ci } 60338c2ecf20Sopenharmony_ci } else { 60348c2ecf20Sopenharmony_ci atomic_set(&instance->fw_reset_no_pci_access, 1); 60358c2ecf20Sopenharmony_ci instance->instancet->adp_reset 60368c2ecf20Sopenharmony_ci (instance, instance->reg_set); 60378c2ecf20Sopenharmony_ci atomic_set(&instance->fw_reset_no_pci_access, 0); 60388c2ecf20Sopenharmony_ci 60398c2ecf20Sopenharmony_ci /*waiting for about 30 second before retry*/ 60408c2ecf20Sopenharmony_ci ssleep(30); 60418c2ecf20Sopenharmony_ci 60428c2ecf20Sopenharmony_ci if (megasas_transition_to_ready(instance, 0)) 60438c2ecf20Sopenharmony_ci goto fail_ready_state; 60448c2ecf20Sopenharmony_ci } 60458c2ecf20Sopenharmony_ci 60468c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 60478c2ecf20Sopenharmony_ci "FW restarted successfully from %s!\n", 60488c2ecf20Sopenharmony_ci __func__); 60498c2ecf20Sopenharmony_ci } 60508c2ecf20Sopenharmony_ci 60518c2ecf20Sopenharmony_ci megasas_init_ctrl_params(instance); 60528c2ecf20Sopenharmony_ci 60538c2ecf20Sopenharmony_ci if (megasas_set_dma_mask(instance)) 60548c2ecf20Sopenharmony_ci goto fail_ready_state; 60558c2ecf20Sopenharmony_ci 60568c2ecf20Sopenharmony_ci if (megasas_alloc_ctrl_mem(instance)) 60578c2ecf20Sopenharmony_ci goto fail_alloc_dma_buf; 60588c2ecf20Sopenharmony_ci 60598c2ecf20Sopenharmony_ci if (megasas_alloc_ctrl_dma_buffers(instance)) 60608c2ecf20Sopenharmony_ci goto fail_alloc_dma_buf; 60618c2ecf20Sopenharmony_ci 60628c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 60638c2ecf20Sopenharmony_ci 60648c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) { 60658c2ecf20Sopenharmony_ci scratch_pad_2 = 60668c2ecf20Sopenharmony_ci megasas_readl(instance, 60678c2ecf20Sopenharmony_ci &instance->reg_set->outbound_scratch_pad_2); 60688c2ecf20Sopenharmony_ci instance->max_raid_mapsize = ((scratch_pad_2 >> 60698c2ecf20Sopenharmony_ci MR_MAX_RAID_MAP_SIZE_OFFSET_SHIFT) & 60708c2ecf20Sopenharmony_ci MR_MAX_RAID_MAP_SIZE_MASK); 60718c2ecf20Sopenharmony_ci } 60728c2ecf20Sopenharmony_ci 60738c2ecf20Sopenharmony_ci instance->enable_sdev_max_qd = enable_sdev_max_qd; 60748c2ecf20Sopenharmony_ci 60758c2ecf20Sopenharmony_ci switch (instance->adapter_type) { 60768c2ecf20Sopenharmony_ci case VENTURA_SERIES: 60778c2ecf20Sopenharmony_ci fusion->pcie_bw_limitation = true; 60788c2ecf20Sopenharmony_ci break; 60798c2ecf20Sopenharmony_ci case AERO_SERIES: 60808c2ecf20Sopenharmony_ci fusion->r56_div_offload = true; 60818c2ecf20Sopenharmony_ci break; 60828c2ecf20Sopenharmony_ci default: 60838c2ecf20Sopenharmony_ci break; 60848c2ecf20Sopenharmony_ci } 60858c2ecf20Sopenharmony_ci 60868c2ecf20Sopenharmony_ci /* Check if MSI-X is supported while in ready state */ 60878c2ecf20Sopenharmony_ci msix_enable = (instance->instancet->read_fw_status_reg(instance) & 60888c2ecf20Sopenharmony_ci 0x4000000) >> 0x1a; 60898c2ecf20Sopenharmony_ci if (msix_enable && !msix_disable) { 60908c2ecf20Sopenharmony_ci 60918c2ecf20Sopenharmony_ci scratch_pad_1 = megasas_readl 60928c2ecf20Sopenharmony_ci (instance, &instance->reg_set->outbound_scratch_pad_1); 60938c2ecf20Sopenharmony_ci /* Check max MSI-X vectors */ 60948c2ecf20Sopenharmony_ci if (fusion) { 60958c2ecf20Sopenharmony_ci if (instance->adapter_type == THUNDERBOLT_SERIES) { 60968c2ecf20Sopenharmony_ci /* Thunderbolt Series*/ 60978c2ecf20Sopenharmony_ci instance->msix_vectors = (scratch_pad_1 60988c2ecf20Sopenharmony_ci & MR_MAX_REPLY_QUEUES_OFFSET) + 1; 60998c2ecf20Sopenharmony_ci } else { 61008c2ecf20Sopenharmony_ci instance->msix_vectors = ((scratch_pad_1 61018c2ecf20Sopenharmony_ci & MR_MAX_REPLY_QUEUES_EXT_OFFSET) 61028c2ecf20Sopenharmony_ci >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1; 61038c2ecf20Sopenharmony_ci 61048c2ecf20Sopenharmony_ci /* 61058c2ecf20Sopenharmony_ci * For Invader series, > 8 MSI-x vectors 61068c2ecf20Sopenharmony_ci * supported by FW/HW implies combined 61078c2ecf20Sopenharmony_ci * reply queue mode is enabled. 61088c2ecf20Sopenharmony_ci * For Ventura series, > 16 MSI-x vectors 61098c2ecf20Sopenharmony_ci * supported by FW/HW implies combined 61108c2ecf20Sopenharmony_ci * reply queue mode is enabled. 61118c2ecf20Sopenharmony_ci */ 61128c2ecf20Sopenharmony_ci switch (instance->adapter_type) { 61138c2ecf20Sopenharmony_ci case INVADER_SERIES: 61148c2ecf20Sopenharmony_ci if (instance->msix_vectors > 8) 61158c2ecf20Sopenharmony_ci instance->msix_combined = true; 61168c2ecf20Sopenharmony_ci break; 61178c2ecf20Sopenharmony_ci case AERO_SERIES: 61188c2ecf20Sopenharmony_ci case VENTURA_SERIES: 61198c2ecf20Sopenharmony_ci if (instance->msix_vectors > 16) 61208c2ecf20Sopenharmony_ci instance->msix_combined = true; 61218c2ecf20Sopenharmony_ci break; 61228c2ecf20Sopenharmony_ci } 61238c2ecf20Sopenharmony_ci 61248c2ecf20Sopenharmony_ci if (rdpq_enable) 61258c2ecf20Sopenharmony_ci instance->is_rdpq = (scratch_pad_1 & MR_RDPQ_MODE_OFFSET) ? 61268c2ecf20Sopenharmony_ci 1 : 0; 61278c2ecf20Sopenharmony_ci 61288c2ecf20Sopenharmony_ci if (instance->adapter_type >= INVADER_SERIES && 61298c2ecf20Sopenharmony_ci !instance->msix_combined) { 61308c2ecf20Sopenharmony_ci instance->msix_load_balance = true; 61318c2ecf20Sopenharmony_ci instance->smp_affinity_enable = false; 61328c2ecf20Sopenharmony_ci } 61338c2ecf20Sopenharmony_ci 61348c2ecf20Sopenharmony_ci /* Save 1-15 reply post index address to local memory 61358c2ecf20Sopenharmony_ci * Index 0 is already saved from reg offset 61368c2ecf20Sopenharmony_ci * MPI2_REPLY_POST_HOST_INDEX_OFFSET 61378c2ecf20Sopenharmony_ci */ 61388c2ecf20Sopenharmony_ci for (loop = 1; loop < MR_MAX_MSIX_REG_ARRAY; loop++) { 61398c2ecf20Sopenharmony_ci instance->reply_post_host_index_addr[loop] = 61408c2ecf20Sopenharmony_ci (u32 __iomem *) 61418c2ecf20Sopenharmony_ci ((u8 __iomem *)instance->reg_set + 61428c2ecf20Sopenharmony_ci MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET 61438c2ecf20Sopenharmony_ci + (loop * 0x10)); 61448c2ecf20Sopenharmony_ci } 61458c2ecf20Sopenharmony_ci } 61468c2ecf20Sopenharmony_ci 61478c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 61488c2ecf20Sopenharmony_ci "firmware supports msix\t: (%d)", 61498c2ecf20Sopenharmony_ci instance->msix_vectors); 61508c2ecf20Sopenharmony_ci if (msix_vectors) 61518c2ecf20Sopenharmony_ci instance->msix_vectors = min(msix_vectors, 61528c2ecf20Sopenharmony_ci instance->msix_vectors); 61538c2ecf20Sopenharmony_ci } else /* MFI adapters */ 61548c2ecf20Sopenharmony_ci instance->msix_vectors = 1; 61558c2ecf20Sopenharmony_ci 61568c2ecf20Sopenharmony_ci 61578c2ecf20Sopenharmony_ci /* 61588c2ecf20Sopenharmony_ci * For Aero (if some conditions are met), driver will configure a 61598c2ecf20Sopenharmony_ci * few additional reply queues with interrupt coalescing enabled. 61608c2ecf20Sopenharmony_ci * These queues with interrupt coalescing enabled are called 61618c2ecf20Sopenharmony_ci * High IOPS queues and rest of reply queues (based on number of 61628c2ecf20Sopenharmony_ci * logical CPUs) are termed as Low latency queues. 61638c2ecf20Sopenharmony_ci * 61648c2ecf20Sopenharmony_ci * Total Number of reply queues = High IOPS queues + low latency queues 61658c2ecf20Sopenharmony_ci * 61668c2ecf20Sopenharmony_ci * For rest of fusion adapters, 1 additional reply queue will be 61678c2ecf20Sopenharmony_ci * reserved for management commands, rest of reply queues 61688c2ecf20Sopenharmony_ci * (based on number of logical CPUs) will be used for IOs and 61698c2ecf20Sopenharmony_ci * referenced as IO queues. 61708c2ecf20Sopenharmony_ci * Total Number of reply queues = 1 + IO queues 61718c2ecf20Sopenharmony_ci * 61728c2ecf20Sopenharmony_ci * MFI adapters supports single MSI-x so single reply queue 61738c2ecf20Sopenharmony_ci * will be used for IO and management commands. 61748c2ecf20Sopenharmony_ci */ 61758c2ecf20Sopenharmony_ci 61768c2ecf20Sopenharmony_ci intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ? 61778c2ecf20Sopenharmony_ci true : false; 61788c2ecf20Sopenharmony_ci if (intr_coalescing && 61798c2ecf20Sopenharmony_ci (num_online_cpus() >= MR_HIGH_IOPS_QUEUE_COUNT) && 61808c2ecf20Sopenharmony_ci (instance->msix_vectors == MEGASAS_MAX_MSIX_QUEUES)) 61818c2ecf20Sopenharmony_ci instance->perf_mode = MR_BALANCED_PERF_MODE; 61828c2ecf20Sopenharmony_ci else 61838c2ecf20Sopenharmony_ci instance->perf_mode = MR_LATENCY_PERF_MODE; 61848c2ecf20Sopenharmony_ci 61858c2ecf20Sopenharmony_ci 61868c2ecf20Sopenharmony_ci if (instance->adapter_type == AERO_SERIES) { 61878c2ecf20Sopenharmony_ci pcie_capability_read_word(instance->pdev, PCI_EXP_LNKSTA, &lnksta); 61888c2ecf20Sopenharmony_ci speed = lnksta & PCI_EXP_LNKSTA_CLS; 61898c2ecf20Sopenharmony_ci 61908c2ecf20Sopenharmony_ci /* 61918c2ecf20Sopenharmony_ci * For Aero, if PCIe link speed is <16 GT/s, then driver should operate 61928c2ecf20Sopenharmony_ci * in latency perf mode and enable R1 PCI bandwidth algorithm 61938c2ecf20Sopenharmony_ci */ 61948c2ecf20Sopenharmony_ci if (speed < 0x4) { 61958c2ecf20Sopenharmony_ci instance->perf_mode = MR_LATENCY_PERF_MODE; 61968c2ecf20Sopenharmony_ci fusion->pcie_bw_limitation = true; 61978c2ecf20Sopenharmony_ci } 61988c2ecf20Sopenharmony_ci 61998c2ecf20Sopenharmony_ci /* 62008c2ecf20Sopenharmony_ci * Performance mode settings provided through module parameter-perf_mode will 62018c2ecf20Sopenharmony_ci * take affect only for: 62028c2ecf20Sopenharmony_ci * 1. Aero family of adapters. 62038c2ecf20Sopenharmony_ci * 2. When user sets module parameter- perf_mode in range of 0-2. 62048c2ecf20Sopenharmony_ci */ 62058c2ecf20Sopenharmony_ci if ((perf_mode >= MR_BALANCED_PERF_MODE) && 62068c2ecf20Sopenharmony_ci (perf_mode <= MR_LATENCY_PERF_MODE)) 62078c2ecf20Sopenharmony_ci instance->perf_mode = perf_mode; 62088c2ecf20Sopenharmony_ci /* 62098c2ecf20Sopenharmony_ci * If intr coalescing is not supported by controller FW, then IOPS 62108c2ecf20Sopenharmony_ci * and Balanced modes are not feasible. 62118c2ecf20Sopenharmony_ci */ 62128c2ecf20Sopenharmony_ci if (!intr_coalescing) 62138c2ecf20Sopenharmony_ci instance->perf_mode = MR_LATENCY_PERF_MODE; 62148c2ecf20Sopenharmony_ci 62158c2ecf20Sopenharmony_ci } 62168c2ecf20Sopenharmony_ci 62178c2ecf20Sopenharmony_ci if (instance->perf_mode == MR_BALANCED_PERF_MODE) 62188c2ecf20Sopenharmony_ci instance->low_latency_index_start = 62198c2ecf20Sopenharmony_ci MR_HIGH_IOPS_QUEUE_COUNT; 62208c2ecf20Sopenharmony_ci else 62218c2ecf20Sopenharmony_ci instance->low_latency_index_start = 1; 62228c2ecf20Sopenharmony_ci 62238c2ecf20Sopenharmony_ci num_msix_req = num_online_cpus() + instance->low_latency_index_start; 62248c2ecf20Sopenharmony_ci 62258c2ecf20Sopenharmony_ci instance->msix_vectors = min(num_msix_req, 62268c2ecf20Sopenharmony_ci instance->msix_vectors); 62278c2ecf20Sopenharmony_ci 62288c2ecf20Sopenharmony_ci megasas_alloc_irq_vectors(instance); 62298c2ecf20Sopenharmony_ci if (!instance->msix_vectors) 62308c2ecf20Sopenharmony_ci instance->msix_load_balance = false; 62318c2ecf20Sopenharmony_ci } 62328c2ecf20Sopenharmony_ci /* 62338c2ecf20Sopenharmony_ci * MSI-X host index 0 is common for all adapter. 62348c2ecf20Sopenharmony_ci * It is used for all MPT based Adapters. 62358c2ecf20Sopenharmony_ci */ 62368c2ecf20Sopenharmony_ci if (instance->msix_combined) { 62378c2ecf20Sopenharmony_ci instance->reply_post_host_index_addr[0] = 62388c2ecf20Sopenharmony_ci (u32 *)((u8 *)instance->reg_set + 62398c2ecf20Sopenharmony_ci MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET); 62408c2ecf20Sopenharmony_ci } else { 62418c2ecf20Sopenharmony_ci instance->reply_post_host_index_addr[0] = 62428c2ecf20Sopenharmony_ci (u32 *)((u8 *)instance->reg_set + 62438c2ecf20Sopenharmony_ci MPI2_REPLY_POST_HOST_INDEX_OFFSET); 62448c2ecf20Sopenharmony_ci } 62458c2ecf20Sopenharmony_ci 62468c2ecf20Sopenharmony_ci if (!instance->msix_vectors) { 62478c2ecf20Sopenharmony_ci i = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_LEGACY); 62488c2ecf20Sopenharmony_ci if (i < 0) 62498c2ecf20Sopenharmony_ci goto fail_init_adapter; 62508c2ecf20Sopenharmony_ci } 62518c2ecf20Sopenharmony_ci 62528c2ecf20Sopenharmony_ci megasas_setup_reply_map(instance); 62538c2ecf20Sopenharmony_ci 62548c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 62558c2ecf20Sopenharmony_ci "current msix/online cpus\t: (%d/%d)\n", 62568c2ecf20Sopenharmony_ci instance->msix_vectors, (unsigned int)num_online_cpus()); 62578c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 62588c2ecf20Sopenharmony_ci "RDPQ mode\t: (%s)\n", instance->is_rdpq ? "enabled" : "disabled"); 62598c2ecf20Sopenharmony_ci 62608c2ecf20Sopenharmony_ci tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, 62618c2ecf20Sopenharmony_ci (unsigned long)instance); 62628c2ecf20Sopenharmony_ci 62638c2ecf20Sopenharmony_ci /* 62648c2ecf20Sopenharmony_ci * Below are default value for legacy Firmware. 62658c2ecf20Sopenharmony_ci * non-fusion based controllers 62668c2ecf20Sopenharmony_ci */ 62678c2ecf20Sopenharmony_ci instance->fw_supported_vd_count = MAX_LOGICAL_DRIVES; 62688c2ecf20Sopenharmony_ci instance->fw_supported_pd_count = MAX_PHYSICAL_DEVICES; 62698c2ecf20Sopenharmony_ci /* Get operational params, sge flags, send init cmd to controller */ 62708c2ecf20Sopenharmony_ci if (instance->instancet->init_adapter(instance)) 62718c2ecf20Sopenharmony_ci goto fail_init_adapter; 62728c2ecf20Sopenharmony_ci 62738c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) { 62748c2ecf20Sopenharmony_ci scratch_pad_3 = 62758c2ecf20Sopenharmony_ci megasas_readl(instance, 62768c2ecf20Sopenharmony_ci &instance->reg_set->outbound_scratch_pad_3); 62778c2ecf20Sopenharmony_ci if ((scratch_pad_3 & MR_NVME_PAGE_SIZE_MASK) >= 62788c2ecf20Sopenharmony_ci MR_DEFAULT_NVME_PAGE_SHIFT) 62798c2ecf20Sopenharmony_ci instance->nvme_page_size = 62808c2ecf20Sopenharmony_ci (1 << (scratch_pad_3 & MR_NVME_PAGE_SIZE_MASK)); 62818c2ecf20Sopenharmony_ci 62828c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 62838c2ecf20Sopenharmony_ci "NVME page size\t: (%d)\n", instance->nvme_page_size); 62848c2ecf20Sopenharmony_ci } 62858c2ecf20Sopenharmony_ci 62868c2ecf20Sopenharmony_ci if (instance->msix_vectors ? 62878c2ecf20Sopenharmony_ci megasas_setup_irqs_msix(instance, 1) : 62888c2ecf20Sopenharmony_ci megasas_setup_irqs_ioapic(instance)) 62898c2ecf20Sopenharmony_ci goto fail_init_adapter; 62908c2ecf20Sopenharmony_ci 62918c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) 62928c2ecf20Sopenharmony_ci megasas_setup_irq_poll(instance); 62938c2ecf20Sopenharmony_ci 62948c2ecf20Sopenharmony_ci instance->instancet->enable_intr(instance); 62958c2ecf20Sopenharmony_ci 62968c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "INIT adapter done\n"); 62978c2ecf20Sopenharmony_ci 62988c2ecf20Sopenharmony_ci megasas_setup_jbod_map(instance); 62998c2ecf20Sopenharmony_ci 63008c2ecf20Sopenharmony_ci if (megasas_get_device_list(instance) != SUCCESS) { 63018c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 63028c2ecf20Sopenharmony_ci "%s: megasas_get_device_list failed\n", 63038c2ecf20Sopenharmony_ci __func__); 63048c2ecf20Sopenharmony_ci goto fail_get_ld_pd_list; 63058c2ecf20Sopenharmony_ci } 63068c2ecf20Sopenharmony_ci 63078c2ecf20Sopenharmony_ci /* stream detection initialization */ 63088c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) { 63098c2ecf20Sopenharmony_ci fusion->stream_detect_by_ld = 63108c2ecf20Sopenharmony_ci kcalloc(MAX_LOGICAL_DRIVES_EXT, 63118c2ecf20Sopenharmony_ci sizeof(struct LD_STREAM_DETECT *), 63128c2ecf20Sopenharmony_ci GFP_KERNEL); 63138c2ecf20Sopenharmony_ci if (!fusion->stream_detect_by_ld) { 63148c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 63158c2ecf20Sopenharmony_ci "unable to allocate stream detection for pool of LDs\n"); 63168c2ecf20Sopenharmony_ci goto fail_get_ld_pd_list; 63178c2ecf20Sopenharmony_ci } 63188c2ecf20Sopenharmony_ci for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i) { 63198c2ecf20Sopenharmony_ci fusion->stream_detect_by_ld[i] = 63208c2ecf20Sopenharmony_ci kzalloc(sizeof(struct LD_STREAM_DETECT), 63218c2ecf20Sopenharmony_ci GFP_KERNEL); 63228c2ecf20Sopenharmony_ci if (!fusion->stream_detect_by_ld[i]) { 63238c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 63248c2ecf20Sopenharmony_ci "unable to allocate stream detect by LD\n "); 63258c2ecf20Sopenharmony_ci for (j = 0; j < i; ++j) 63268c2ecf20Sopenharmony_ci kfree(fusion->stream_detect_by_ld[j]); 63278c2ecf20Sopenharmony_ci kfree(fusion->stream_detect_by_ld); 63288c2ecf20Sopenharmony_ci fusion->stream_detect_by_ld = NULL; 63298c2ecf20Sopenharmony_ci goto fail_get_ld_pd_list; 63308c2ecf20Sopenharmony_ci } 63318c2ecf20Sopenharmony_ci fusion->stream_detect_by_ld[i]->mru_bit_map 63328c2ecf20Sopenharmony_ci = MR_STREAM_BITMAP; 63338c2ecf20Sopenharmony_ci } 63348c2ecf20Sopenharmony_ci } 63358c2ecf20Sopenharmony_ci 63368c2ecf20Sopenharmony_ci /* 63378c2ecf20Sopenharmony_ci * Compute the max allowed sectors per IO: The controller info has two 63388c2ecf20Sopenharmony_ci * limits on max sectors. Driver should use the minimum of these two. 63398c2ecf20Sopenharmony_ci * 63408c2ecf20Sopenharmony_ci * 1 << stripe_sz_ops.min = max sectors per strip 63418c2ecf20Sopenharmony_ci * 63428c2ecf20Sopenharmony_ci * Note that older firmwares ( < FW ver 30) didn't report information 63438c2ecf20Sopenharmony_ci * to calculate max_sectors_1. So the number ended up as zero always. 63448c2ecf20Sopenharmony_ci */ 63458c2ecf20Sopenharmony_ci tmp_sectors = 0; 63468c2ecf20Sopenharmony_ci ctrl_info = instance->ctrl_info_buf; 63478c2ecf20Sopenharmony_ci 63488c2ecf20Sopenharmony_ci max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) * 63498c2ecf20Sopenharmony_ci le16_to_cpu(ctrl_info->max_strips_per_io); 63508c2ecf20Sopenharmony_ci max_sectors_2 = le32_to_cpu(ctrl_info->max_request_size); 63518c2ecf20Sopenharmony_ci 63528c2ecf20Sopenharmony_ci tmp_sectors = min_t(u32, max_sectors_1, max_sectors_2); 63538c2ecf20Sopenharmony_ci 63548c2ecf20Sopenharmony_ci instance->peerIsPresent = ctrl_info->cluster.peerIsPresent; 63558c2ecf20Sopenharmony_ci instance->passive = ctrl_info->cluster.passive; 63568c2ecf20Sopenharmony_ci memcpy(instance->clusterId, ctrl_info->clusterId, sizeof(instance->clusterId)); 63578c2ecf20Sopenharmony_ci instance->UnevenSpanSupport = 63588c2ecf20Sopenharmony_ci ctrl_info->adapterOperations2.supportUnevenSpans; 63598c2ecf20Sopenharmony_ci if (instance->UnevenSpanSupport) { 63608c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 63618c2ecf20Sopenharmony_ci if (MR_ValidateMapInfo(instance, instance->map_id)) 63628c2ecf20Sopenharmony_ci fusion->fast_path_io = 1; 63638c2ecf20Sopenharmony_ci else 63648c2ecf20Sopenharmony_ci fusion->fast_path_io = 0; 63658c2ecf20Sopenharmony_ci 63668c2ecf20Sopenharmony_ci } 63678c2ecf20Sopenharmony_ci if (ctrl_info->host_interface.SRIOV) { 63688c2ecf20Sopenharmony_ci instance->requestorId = ctrl_info->iov.requestorId; 63698c2ecf20Sopenharmony_ci if (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) { 63708c2ecf20Sopenharmony_ci if (!ctrl_info->adapterOperations2.activePassive) 63718c2ecf20Sopenharmony_ci instance->PlasmaFW111 = 1; 63728c2ecf20Sopenharmony_ci 63738c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "SR-IOV: firmware type: %s\n", 63748c2ecf20Sopenharmony_ci instance->PlasmaFW111 ? "1.11" : "new"); 63758c2ecf20Sopenharmony_ci 63768c2ecf20Sopenharmony_ci if (instance->PlasmaFW111) { 63778c2ecf20Sopenharmony_ci iovPtr = (struct IOV_111 *) 63788c2ecf20Sopenharmony_ci ((unsigned char *)ctrl_info + IOV_111_OFFSET); 63798c2ecf20Sopenharmony_ci instance->requestorId = iovPtr->requestorId; 63808c2ecf20Sopenharmony_ci } 63818c2ecf20Sopenharmony_ci } 63828c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "SRIOV: VF requestorId %d\n", 63838c2ecf20Sopenharmony_ci instance->requestorId); 63848c2ecf20Sopenharmony_ci } 63858c2ecf20Sopenharmony_ci 63868c2ecf20Sopenharmony_ci instance->crash_dump_fw_support = 63878c2ecf20Sopenharmony_ci ctrl_info->adapterOperations3.supportCrashDump; 63888c2ecf20Sopenharmony_ci instance->crash_dump_drv_support = 63898c2ecf20Sopenharmony_ci (instance->crash_dump_fw_support && 63908c2ecf20Sopenharmony_ci instance->crash_dump_buf); 63918c2ecf20Sopenharmony_ci if (instance->crash_dump_drv_support) 63928c2ecf20Sopenharmony_ci megasas_set_crash_dump_params(instance, 63938c2ecf20Sopenharmony_ci MR_CRASH_BUF_TURN_OFF); 63948c2ecf20Sopenharmony_ci 63958c2ecf20Sopenharmony_ci else { 63968c2ecf20Sopenharmony_ci if (instance->crash_dump_buf) 63978c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, 63988c2ecf20Sopenharmony_ci CRASH_DMA_BUF_SIZE, 63998c2ecf20Sopenharmony_ci instance->crash_dump_buf, 64008c2ecf20Sopenharmony_ci instance->crash_dump_h); 64018c2ecf20Sopenharmony_ci instance->crash_dump_buf = NULL; 64028c2ecf20Sopenharmony_ci } 64038c2ecf20Sopenharmony_ci 64048c2ecf20Sopenharmony_ci if (instance->snapdump_wait_time) { 64058c2ecf20Sopenharmony_ci megasas_get_snapdump_properties(instance); 64068c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Snap dump wait time\t: %d\n", 64078c2ecf20Sopenharmony_ci instance->snapdump_wait_time); 64088c2ecf20Sopenharmony_ci } 64098c2ecf20Sopenharmony_ci 64108c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 64118c2ecf20Sopenharmony_ci "pci id\t\t: (0x%04x)/(0x%04x)/(0x%04x)/(0x%04x)\n", 64128c2ecf20Sopenharmony_ci le16_to_cpu(ctrl_info->pci.vendor_id), 64138c2ecf20Sopenharmony_ci le16_to_cpu(ctrl_info->pci.device_id), 64148c2ecf20Sopenharmony_ci le16_to_cpu(ctrl_info->pci.sub_vendor_id), 64158c2ecf20Sopenharmony_ci le16_to_cpu(ctrl_info->pci.sub_device_id)); 64168c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "unevenspan support : %s\n", 64178c2ecf20Sopenharmony_ci instance->UnevenSpanSupport ? "yes" : "no"); 64188c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "firmware crash dump : %s\n", 64198c2ecf20Sopenharmony_ci instance->crash_dump_drv_support ? "yes" : "no"); 64208c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "JBOD sequence map : %s\n", 64218c2ecf20Sopenharmony_ci instance->use_seqnum_jbod_fp ? "enabled" : "disabled"); 64228c2ecf20Sopenharmony_ci 64238c2ecf20Sopenharmony_ci instance->max_sectors_per_req = instance->max_num_sge * 64248c2ecf20Sopenharmony_ci SGE_BUFFER_SIZE / 512; 64258c2ecf20Sopenharmony_ci if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors)) 64268c2ecf20Sopenharmony_ci instance->max_sectors_per_req = tmp_sectors; 64278c2ecf20Sopenharmony_ci 64288c2ecf20Sopenharmony_ci /* Check for valid throttlequeuedepth module parameter */ 64298c2ecf20Sopenharmony_ci if (throttlequeuedepth && 64308c2ecf20Sopenharmony_ci throttlequeuedepth <= instance->max_scsi_cmds) 64318c2ecf20Sopenharmony_ci instance->throttlequeuedepth = throttlequeuedepth; 64328c2ecf20Sopenharmony_ci else 64338c2ecf20Sopenharmony_ci instance->throttlequeuedepth = 64348c2ecf20Sopenharmony_ci MEGASAS_THROTTLE_QUEUE_DEPTH; 64358c2ecf20Sopenharmony_ci 64368c2ecf20Sopenharmony_ci if ((resetwaittime < 1) || 64378c2ecf20Sopenharmony_ci (resetwaittime > MEGASAS_RESET_WAIT_TIME)) 64388c2ecf20Sopenharmony_ci resetwaittime = MEGASAS_RESET_WAIT_TIME; 64398c2ecf20Sopenharmony_ci 64408c2ecf20Sopenharmony_ci if ((scmd_timeout < 10) || (scmd_timeout > MEGASAS_DEFAULT_CMD_TIMEOUT)) 64418c2ecf20Sopenharmony_ci scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT; 64428c2ecf20Sopenharmony_ci 64438c2ecf20Sopenharmony_ci /* Launch SR-IOV heartbeat timer */ 64448c2ecf20Sopenharmony_ci if (instance->requestorId) { 64458c2ecf20Sopenharmony_ci if (!megasas_sriov_start_heartbeat(instance, 1)) { 64468c2ecf20Sopenharmony_ci megasas_start_timer(instance); 64478c2ecf20Sopenharmony_ci } else { 64488c2ecf20Sopenharmony_ci instance->skip_heartbeat_timer_del = 1; 64498c2ecf20Sopenharmony_ci goto fail_get_ld_pd_list; 64508c2ecf20Sopenharmony_ci } 64518c2ecf20Sopenharmony_ci } 64528c2ecf20Sopenharmony_ci 64538c2ecf20Sopenharmony_ci /* 64548c2ecf20Sopenharmony_ci * Create and start watchdog thread which will monitor 64558c2ecf20Sopenharmony_ci * controller state every 1 sec and trigger OCR when 64568c2ecf20Sopenharmony_ci * it enters fault state 64578c2ecf20Sopenharmony_ci */ 64588c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) 64598c2ecf20Sopenharmony_ci if (megasas_fusion_start_watchdog(instance) != SUCCESS) 64608c2ecf20Sopenharmony_ci goto fail_start_watchdog; 64618c2ecf20Sopenharmony_ci 64628c2ecf20Sopenharmony_ci return 0; 64638c2ecf20Sopenharmony_ci 64648c2ecf20Sopenharmony_cifail_start_watchdog: 64658c2ecf20Sopenharmony_ci if (instance->requestorId && !instance->skip_heartbeat_timer_del) 64668c2ecf20Sopenharmony_ci del_timer_sync(&instance->sriov_heartbeat_timer); 64678c2ecf20Sopenharmony_cifail_get_ld_pd_list: 64688c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 64698c2ecf20Sopenharmony_ci megasas_destroy_irqs(instance); 64708c2ecf20Sopenharmony_cifail_init_adapter: 64718c2ecf20Sopenharmony_ci if (instance->msix_vectors) 64728c2ecf20Sopenharmony_ci pci_free_irq_vectors(instance->pdev); 64738c2ecf20Sopenharmony_ci instance->msix_vectors = 0; 64748c2ecf20Sopenharmony_cifail_alloc_dma_buf: 64758c2ecf20Sopenharmony_ci megasas_free_ctrl_dma_buffers(instance); 64768c2ecf20Sopenharmony_ci megasas_free_ctrl_mem(instance); 64778c2ecf20Sopenharmony_cifail_ready_state: 64788c2ecf20Sopenharmony_ci iounmap(instance->reg_set); 64798c2ecf20Sopenharmony_ci 64808c2ecf20Sopenharmony_cifail_ioremap: 64818c2ecf20Sopenharmony_ci pci_release_selected_regions(instance->pdev, 1<<instance->bar); 64828c2ecf20Sopenharmony_ci 64838c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed from %s %d\n", 64848c2ecf20Sopenharmony_ci __func__, __LINE__); 64858c2ecf20Sopenharmony_ci return -EINVAL; 64868c2ecf20Sopenharmony_ci} 64878c2ecf20Sopenharmony_ci 64888c2ecf20Sopenharmony_ci/** 64898c2ecf20Sopenharmony_ci * megasas_release_mfi - Reverses the FW initialization 64908c2ecf20Sopenharmony_ci * @instance: Adapter soft state 64918c2ecf20Sopenharmony_ci */ 64928c2ecf20Sopenharmony_cistatic void megasas_release_mfi(struct megasas_instance *instance) 64938c2ecf20Sopenharmony_ci{ 64948c2ecf20Sopenharmony_ci u32 reply_q_sz = sizeof(u32) *(instance->max_mfi_cmds + 1); 64958c2ecf20Sopenharmony_ci 64968c2ecf20Sopenharmony_ci if (instance->reply_queue) 64978c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, reply_q_sz, 64988c2ecf20Sopenharmony_ci instance->reply_queue, instance->reply_queue_h); 64998c2ecf20Sopenharmony_ci 65008c2ecf20Sopenharmony_ci megasas_free_cmds(instance); 65018c2ecf20Sopenharmony_ci 65028c2ecf20Sopenharmony_ci iounmap(instance->reg_set); 65038c2ecf20Sopenharmony_ci 65048c2ecf20Sopenharmony_ci pci_release_selected_regions(instance->pdev, 1<<instance->bar); 65058c2ecf20Sopenharmony_ci} 65068c2ecf20Sopenharmony_ci 65078c2ecf20Sopenharmony_ci/** 65088c2ecf20Sopenharmony_ci * megasas_get_seq_num - Gets latest event sequence numbers 65098c2ecf20Sopenharmony_ci * @instance: Adapter soft state 65108c2ecf20Sopenharmony_ci * @eli: FW event log sequence numbers information 65118c2ecf20Sopenharmony_ci * 65128c2ecf20Sopenharmony_ci * FW maintains a log of all events in a non-volatile area. Upper layers would 65138c2ecf20Sopenharmony_ci * usually find out the latest sequence number of the events, the seq number at 65148c2ecf20Sopenharmony_ci * the boot etc. They would "read" all the events below the latest seq number 65158c2ecf20Sopenharmony_ci * by issuing a direct fw cmd (DCMD). For the future events (beyond latest seq 65168c2ecf20Sopenharmony_ci * number), they would subsribe to AEN (asynchronous event notification) and 65178c2ecf20Sopenharmony_ci * wait for the events to happen. 65188c2ecf20Sopenharmony_ci */ 65198c2ecf20Sopenharmony_cistatic int 65208c2ecf20Sopenharmony_cimegasas_get_seq_num(struct megasas_instance *instance, 65218c2ecf20Sopenharmony_ci struct megasas_evt_log_info *eli) 65228c2ecf20Sopenharmony_ci{ 65238c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 65248c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 65258c2ecf20Sopenharmony_ci struct megasas_evt_log_info *el_info; 65268c2ecf20Sopenharmony_ci dma_addr_t el_info_h = 0; 65278c2ecf20Sopenharmony_ci int ret; 65288c2ecf20Sopenharmony_ci 65298c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 65308c2ecf20Sopenharmony_ci 65318c2ecf20Sopenharmony_ci if (!cmd) { 65328c2ecf20Sopenharmony_ci return -ENOMEM; 65338c2ecf20Sopenharmony_ci } 65348c2ecf20Sopenharmony_ci 65358c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 65368c2ecf20Sopenharmony_ci el_info = dma_alloc_coherent(&instance->pdev->dev, 65378c2ecf20Sopenharmony_ci sizeof(struct megasas_evt_log_info), 65388c2ecf20Sopenharmony_ci &el_info_h, GFP_KERNEL); 65398c2ecf20Sopenharmony_ci if (!el_info) { 65408c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 65418c2ecf20Sopenharmony_ci return -ENOMEM; 65428c2ecf20Sopenharmony_ci } 65438c2ecf20Sopenharmony_ci 65448c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 65458c2ecf20Sopenharmony_ci 65468c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 65478c2ecf20Sopenharmony_ci dcmd->cmd_status = 0x0; 65488c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 65498c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_READ; 65508c2ecf20Sopenharmony_ci dcmd->timeout = 0; 65518c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 65528c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_evt_log_info)); 65538c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_EVENT_GET_INFO); 65548c2ecf20Sopenharmony_ci 65558c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, el_info_h, 65568c2ecf20Sopenharmony_ci sizeof(struct megasas_evt_log_info)); 65578c2ecf20Sopenharmony_ci 65588c2ecf20Sopenharmony_ci ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS); 65598c2ecf20Sopenharmony_ci if (ret != DCMD_SUCCESS) { 65608c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed from %s %d\n", 65618c2ecf20Sopenharmony_ci __func__, __LINE__); 65628c2ecf20Sopenharmony_ci goto dcmd_failed; 65638c2ecf20Sopenharmony_ci } 65648c2ecf20Sopenharmony_ci 65658c2ecf20Sopenharmony_ci /* 65668c2ecf20Sopenharmony_ci * Copy the data back into callers buffer 65678c2ecf20Sopenharmony_ci */ 65688c2ecf20Sopenharmony_ci eli->newest_seq_num = el_info->newest_seq_num; 65698c2ecf20Sopenharmony_ci eli->oldest_seq_num = el_info->oldest_seq_num; 65708c2ecf20Sopenharmony_ci eli->clear_seq_num = el_info->clear_seq_num; 65718c2ecf20Sopenharmony_ci eli->shutdown_seq_num = el_info->shutdown_seq_num; 65728c2ecf20Sopenharmony_ci eli->boot_seq_num = el_info->boot_seq_num; 65738c2ecf20Sopenharmony_ci 65748c2ecf20Sopenharmony_cidcmd_failed: 65758c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, 65768c2ecf20Sopenharmony_ci sizeof(struct megasas_evt_log_info), 65778c2ecf20Sopenharmony_ci el_info, el_info_h); 65788c2ecf20Sopenharmony_ci 65798c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 65808c2ecf20Sopenharmony_ci 65818c2ecf20Sopenharmony_ci return ret; 65828c2ecf20Sopenharmony_ci} 65838c2ecf20Sopenharmony_ci 65848c2ecf20Sopenharmony_ci/** 65858c2ecf20Sopenharmony_ci * megasas_register_aen - Registers for asynchronous event notification 65868c2ecf20Sopenharmony_ci * @instance: Adapter soft state 65878c2ecf20Sopenharmony_ci * @seq_num: The starting sequence number 65888c2ecf20Sopenharmony_ci * @class_locale_word: Class of the event 65898c2ecf20Sopenharmony_ci * 65908c2ecf20Sopenharmony_ci * This function subscribes for AEN for events beyond the @seq_num. It requests 65918c2ecf20Sopenharmony_ci * to be notified if and only if the event is of type @class_locale 65928c2ecf20Sopenharmony_ci */ 65938c2ecf20Sopenharmony_cistatic int 65948c2ecf20Sopenharmony_cimegasas_register_aen(struct megasas_instance *instance, u32 seq_num, 65958c2ecf20Sopenharmony_ci u32 class_locale_word) 65968c2ecf20Sopenharmony_ci{ 65978c2ecf20Sopenharmony_ci int ret_val; 65988c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 65998c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 66008c2ecf20Sopenharmony_ci union megasas_evt_class_locale curr_aen; 66018c2ecf20Sopenharmony_ci union megasas_evt_class_locale prev_aen; 66028c2ecf20Sopenharmony_ci 66038c2ecf20Sopenharmony_ci /* 66048c2ecf20Sopenharmony_ci * If there an AEN pending already (aen_cmd), check if the 66058c2ecf20Sopenharmony_ci * class_locale of that pending AEN is inclusive of the new 66068c2ecf20Sopenharmony_ci * AEN request we currently have. If it is, then we don't have 66078c2ecf20Sopenharmony_ci * to do anything. In other words, whichever events the current 66088c2ecf20Sopenharmony_ci * AEN request is subscribing to, have already been subscribed 66098c2ecf20Sopenharmony_ci * to. 66108c2ecf20Sopenharmony_ci * 66118c2ecf20Sopenharmony_ci * If the old_cmd is _not_ inclusive, then we have to abort 66128c2ecf20Sopenharmony_ci * that command, form a class_locale that is superset of both 66138c2ecf20Sopenharmony_ci * old and current and re-issue to the FW 66148c2ecf20Sopenharmony_ci */ 66158c2ecf20Sopenharmony_ci 66168c2ecf20Sopenharmony_ci curr_aen.word = class_locale_word; 66178c2ecf20Sopenharmony_ci 66188c2ecf20Sopenharmony_ci if (instance->aen_cmd) { 66198c2ecf20Sopenharmony_ci 66208c2ecf20Sopenharmony_ci prev_aen.word = 66218c2ecf20Sopenharmony_ci le32_to_cpu(instance->aen_cmd->frame->dcmd.mbox.w[1]); 66228c2ecf20Sopenharmony_ci 66238c2ecf20Sopenharmony_ci if ((curr_aen.members.class < MFI_EVT_CLASS_DEBUG) || 66248c2ecf20Sopenharmony_ci (curr_aen.members.class > MFI_EVT_CLASS_DEAD)) { 66258c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 66268c2ecf20Sopenharmony_ci "%s %d out of range class %d send by application\n", 66278c2ecf20Sopenharmony_ci __func__, __LINE__, curr_aen.members.class); 66288c2ecf20Sopenharmony_ci return 0; 66298c2ecf20Sopenharmony_ci } 66308c2ecf20Sopenharmony_ci 66318c2ecf20Sopenharmony_ci /* 66328c2ecf20Sopenharmony_ci * A class whose enum value is smaller is inclusive of all 66338c2ecf20Sopenharmony_ci * higher values. If a PROGRESS (= -1) was previously 66348c2ecf20Sopenharmony_ci * registered, then a new registration requests for higher 66358c2ecf20Sopenharmony_ci * classes need not be sent to FW. They are automatically 66368c2ecf20Sopenharmony_ci * included. 66378c2ecf20Sopenharmony_ci * 66388c2ecf20Sopenharmony_ci * Locale numbers don't have such hierarchy. They are bitmap 66398c2ecf20Sopenharmony_ci * values 66408c2ecf20Sopenharmony_ci */ 66418c2ecf20Sopenharmony_ci if ((prev_aen.members.class <= curr_aen.members.class) && 66428c2ecf20Sopenharmony_ci !((prev_aen.members.locale & curr_aen.members.locale) ^ 66438c2ecf20Sopenharmony_ci curr_aen.members.locale)) { 66448c2ecf20Sopenharmony_ci /* 66458c2ecf20Sopenharmony_ci * Previously issued event registration includes 66468c2ecf20Sopenharmony_ci * current request. Nothing to do. 66478c2ecf20Sopenharmony_ci */ 66488c2ecf20Sopenharmony_ci return 0; 66498c2ecf20Sopenharmony_ci } else { 66508c2ecf20Sopenharmony_ci curr_aen.members.locale |= prev_aen.members.locale; 66518c2ecf20Sopenharmony_ci 66528c2ecf20Sopenharmony_ci if (prev_aen.members.class < curr_aen.members.class) 66538c2ecf20Sopenharmony_ci curr_aen.members.class = prev_aen.members.class; 66548c2ecf20Sopenharmony_ci 66558c2ecf20Sopenharmony_ci instance->aen_cmd->abort_aen = 1; 66568c2ecf20Sopenharmony_ci ret_val = megasas_issue_blocked_abort_cmd(instance, 66578c2ecf20Sopenharmony_ci instance-> 66588c2ecf20Sopenharmony_ci aen_cmd, 30); 66598c2ecf20Sopenharmony_ci 66608c2ecf20Sopenharmony_ci if (ret_val) { 66618c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to abort " 66628c2ecf20Sopenharmony_ci "previous AEN command\n"); 66638c2ecf20Sopenharmony_ci return ret_val; 66648c2ecf20Sopenharmony_ci } 66658c2ecf20Sopenharmony_ci } 66668c2ecf20Sopenharmony_ci } 66678c2ecf20Sopenharmony_ci 66688c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 66698c2ecf20Sopenharmony_ci 66708c2ecf20Sopenharmony_ci if (!cmd) 66718c2ecf20Sopenharmony_ci return -ENOMEM; 66728c2ecf20Sopenharmony_ci 66738c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 66748c2ecf20Sopenharmony_ci 66758c2ecf20Sopenharmony_ci memset(instance->evt_detail, 0, sizeof(struct megasas_evt_detail)); 66768c2ecf20Sopenharmony_ci 66778c2ecf20Sopenharmony_ci /* 66788c2ecf20Sopenharmony_ci * Prepare DCMD for aen registration 66798c2ecf20Sopenharmony_ci */ 66808c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 66818c2ecf20Sopenharmony_ci 66828c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 66838c2ecf20Sopenharmony_ci dcmd->cmd_status = 0x0; 66848c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 66858c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_READ; 66868c2ecf20Sopenharmony_ci dcmd->timeout = 0; 66878c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 66888c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_evt_detail)); 66898c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_EVENT_WAIT); 66908c2ecf20Sopenharmony_ci dcmd->mbox.w[0] = cpu_to_le32(seq_num); 66918c2ecf20Sopenharmony_ci instance->last_seq_num = seq_num; 66928c2ecf20Sopenharmony_ci dcmd->mbox.w[1] = cpu_to_le32(curr_aen.word); 66938c2ecf20Sopenharmony_ci 66948c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, instance->evt_detail_h, 66958c2ecf20Sopenharmony_ci sizeof(struct megasas_evt_detail)); 66968c2ecf20Sopenharmony_ci 66978c2ecf20Sopenharmony_ci if (instance->aen_cmd != NULL) { 66988c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 66998c2ecf20Sopenharmony_ci return 0; 67008c2ecf20Sopenharmony_ci } 67018c2ecf20Sopenharmony_ci 67028c2ecf20Sopenharmony_ci /* 67038c2ecf20Sopenharmony_ci * Store reference to the cmd used to register for AEN. When an 67048c2ecf20Sopenharmony_ci * application wants us to register for AEN, we have to abort this 67058c2ecf20Sopenharmony_ci * cmd and re-register with a new EVENT LOCALE supplied by that app 67068c2ecf20Sopenharmony_ci */ 67078c2ecf20Sopenharmony_ci instance->aen_cmd = cmd; 67088c2ecf20Sopenharmony_ci 67098c2ecf20Sopenharmony_ci /* 67108c2ecf20Sopenharmony_ci * Issue the aen registration frame 67118c2ecf20Sopenharmony_ci */ 67128c2ecf20Sopenharmony_ci instance->instancet->issue_dcmd(instance, cmd); 67138c2ecf20Sopenharmony_ci 67148c2ecf20Sopenharmony_ci return 0; 67158c2ecf20Sopenharmony_ci} 67168c2ecf20Sopenharmony_ci 67178c2ecf20Sopenharmony_ci/* megasas_get_target_prop - Send DCMD with below details to firmware. 67188c2ecf20Sopenharmony_ci * 67198c2ecf20Sopenharmony_ci * This DCMD will fetch few properties of LD/system PD defined 67208c2ecf20Sopenharmony_ci * in MR_TARGET_DEV_PROPERTIES. eg. Queue Depth, MDTS value. 67218c2ecf20Sopenharmony_ci * 67228c2ecf20Sopenharmony_ci * DCMD send by drivers whenever new target is added to the OS. 67238c2ecf20Sopenharmony_ci * 67248c2ecf20Sopenharmony_ci * dcmd.opcode - MR_DCMD_DEV_GET_TARGET_PROP 67258c2ecf20Sopenharmony_ci * dcmd.mbox.b[0] - DCMD is to be fired for LD or system PD. 67268c2ecf20Sopenharmony_ci * 0 = system PD, 1 = LD. 67278c2ecf20Sopenharmony_ci * dcmd.mbox.s[1] - TargetID for LD/system PD. 67288c2ecf20Sopenharmony_ci * dcmd.sge IN - Pointer to return MR_TARGET_DEV_PROPERTIES. 67298c2ecf20Sopenharmony_ci * 67308c2ecf20Sopenharmony_ci * @instance: Adapter soft state 67318c2ecf20Sopenharmony_ci * @sdev: OS provided scsi device 67328c2ecf20Sopenharmony_ci * 67338c2ecf20Sopenharmony_ci * Returns 0 on success non-zero on failure. 67348c2ecf20Sopenharmony_ci */ 67358c2ecf20Sopenharmony_ciint 67368c2ecf20Sopenharmony_cimegasas_get_target_prop(struct megasas_instance *instance, 67378c2ecf20Sopenharmony_ci struct scsi_device *sdev) 67388c2ecf20Sopenharmony_ci{ 67398c2ecf20Sopenharmony_ci int ret; 67408c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 67418c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 67428c2ecf20Sopenharmony_ci u16 targetId = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + 67438c2ecf20Sopenharmony_ci sdev->id; 67448c2ecf20Sopenharmony_ci 67458c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 67468c2ecf20Sopenharmony_ci 67478c2ecf20Sopenharmony_ci if (!cmd) { 67488c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 67498c2ecf20Sopenharmony_ci "Failed to get cmd %s\n", __func__); 67508c2ecf20Sopenharmony_ci return -ENOMEM; 67518c2ecf20Sopenharmony_ci } 67528c2ecf20Sopenharmony_ci 67538c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 67548c2ecf20Sopenharmony_ci 67558c2ecf20Sopenharmony_ci memset(instance->tgt_prop, 0, sizeof(*instance->tgt_prop)); 67568c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 67578c2ecf20Sopenharmony_ci dcmd->mbox.b[0] = MEGASAS_IS_LOGICAL(sdev); 67588c2ecf20Sopenharmony_ci 67598c2ecf20Sopenharmony_ci dcmd->mbox.s[1] = cpu_to_le16(targetId); 67608c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 67618c2ecf20Sopenharmony_ci dcmd->cmd_status = 0xFF; 67628c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 67638c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_READ; 67648c2ecf20Sopenharmony_ci dcmd->timeout = 0; 67658c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 67668c2ecf20Sopenharmony_ci dcmd->data_xfer_len = 67678c2ecf20Sopenharmony_ci cpu_to_le32(sizeof(struct MR_TARGET_PROPERTIES)); 67688c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_DRV_GET_TARGET_PROP); 67698c2ecf20Sopenharmony_ci 67708c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, instance->tgt_prop_h, 67718c2ecf20Sopenharmony_ci sizeof(struct MR_TARGET_PROPERTIES)); 67728c2ecf20Sopenharmony_ci 67738c2ecf20Sopenharmony_ci if ((instance->adapter_type != MFI_SERIES) && 67748c2ecf20Sopenharmony_ci !instance->mask_interrupts) 67758c2ecf20Sopenharmony_ci ret = megasas_issue_blocked_cmd(instance, 67768c2ecf20Sopenharmony_ci cmd, MFI_IO_TIMEOUT_SECS); 67778c2ecf20Sopenharmony_ci else 67788c2ecf20Sopenharmony_ci ret = megasas_issue_polled(instance, cmd); 67798c2ecf20Sopenharmony_ci 67808c2ecf20Sopenharmony_ci switch (ret) { 67818c2ecf20Sopenharmony_ci case DCMD_TIMEOUT: 67828c2ecf20Sopenharmony_ci switch (dcmd_timeout_ocr_possible(instance)) { 67838c2ecf20Sopenharmony_ci case INITIATE_OCR: 67848c2ecf20Sopenharmony_ci cmd->flags |= DRV_DCMD_SKIP_REFIRE; 67858c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 67868c2ecf20Sopenharmony_ci megasas_reset_fusion(instance->host, 67878c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_OCR); 67888c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 67898c2ecf20Sopenharmony_ci break; 67908c2ecf20Sopenharmony_ci case KILL_ADAPTER: 67918c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 67928c2ecf20Sopenharmony_ci break; 67938c2ecf20Sopenharmony_ci case IGNORE_TIMEOUT: 67948c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 67958c2ecf20Sopenharmony_ci "Ignore DCMD timeout: %s %d\n", 67968c2ecf20Sopenharmony_ci __func__, __LINE__); 67978c2ecf20Sopenharmony_ci break; 67988c2ecf20Sopenharmony_ci } 67998c2ecf20Sopenharmony_ci break; 68008c2ecf20Sopenharmony_ci 68018c2ecf20Sopenharmony_ci default: 68028c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 68038c2ecf20Sopenharmony_ci } 68048c2ecf20Sopenharmony_ci if (ret != DCMD_SUCCESS) 68058c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 68068c2ecf20Sopenharmony_ci "return from %s %d return value %d\n", 68078c2ecf20Sopenharmony_ci __func__, __LINE__, ret); 68088c2ecf20Sopenharmony_ci 68098c2ecf20Sopenharmony_ci return ret; 68108c2ecf20Sopenharmony_ci} 68118c2ecf20Sopenharmony_ci 68128c2ecf20Sopenharmony_ci/** 68138c2ecf20Sopenharmony_ci * megasas_start_aen - Subscribes to AEN during driver load time 68148c2ecf20Sopenharmony_ci * @instance: Adapter soft state 68158c2ecf20Sopenharmony_ci */ 68168c2ecf20Sopenharmony_cistatic int megasas_start_aen(struct megasas_instance *instance) 68178c2ecf20Sopenharmony_ci{ 68188c2ecf20Sopenharmony_ci struct megasas_evt_log_info eli; 68198c2ecf20Sopenharmony_ci union megasas_evt_class_locale class_locale; 68208c2ecf20Sopenharmony_ci 68218c2ecf20Sopenharmony_ci /* 68228c2ecf20Sopenharmony_ci * Get the latest sequence number from FW 68238c2ecf20Sopenharmony_ci */ 68248c2ecf20Sopenharmony_ci memset(&eli, 0, sizeof(eli)); 68258c2ecf20Sopenharmony_ci 68268c2ecf20Sopenharmony_ci if (megasas_get_seq_num(instance, &eli)) 68278c2ecf20Sopenharmony_ci return -1; 68288c2ecf20Sopenharmony_ci 68298c2ecf20Sopenharmony_ci /* 68308c2ecf20Sopenharmony_ci * Register AEN with FW for latest sequence number plus 1 68318c2ecf20Sopenharmony_ci */ 68328c2ecf20Sopenharmony_ci class_locale.members.reserved = 0; 68338c2ecf20Sopenharmony_ci class_locale.members.locale = MR_EVT_LOCALE_ALL; 68348c2ecf20Sopenharmony_ci class_locale.members.class = MR_EVT_CLASS_DEBUG; 68358c2ecf20Sopenharmony_ci 68368c2ecf20Sopenharmony_ci return megasas_register_aen(instance, 68378c2ecf20Sopenharmony_ci le32_to_cpu(eli.newest_seq_num) + 1, 68388c2ecf20Sopenharmony_ci class_locale.word); 68398c2ecf20Sopenharmony_ci} 68408c2ecf20Sopenharmony_ci 68418c2ecf20Sopenharmony_ci/** 68428c2ecf20Sopenharmony_ci * megasas_io_attach - Attaches this driver to SCSI mid-layer 68438c2ecf20Sopenharmony_ci * @instance: Adapter soft state 68448c2ecf20Sopenharmony_ci */ 68458c2ecf20Sopenharmony_cistatic int megasas_io_attach(struct megasas_instance *instance) 68468c2ecf20Sopenharmony_ci{ 68478c2ecf20Sopenharmony_ci struct Scsi_Host *host = instance->host; 68488c2ecf20Sopenharmony_ci 68498c2ecf20Sopenharmony_ci /* 68508c2ecf20Sopenharmony_ci * Export parameters required by SCSI mid-layer 68518c2ecf20Sopenharmony_ci */ 68528c2ecf20Sopenharmony_ci host->unique_id = instance->unique_id; 68538c2ecf20Sopenharmony_ci host->can_queue = instance->max_scsi_cmds; 68548c2ecf20Sopenharmony_ci host->this_id = instance->init_id; 68558c2ecf20Sopenharmony_ci host->sg_tablesize = instance->max_num_sge; 68568c2ecf20Sopenharmony_ci 68578c2ecf20Sopenharmony_ci if (instance->fw_support_ieee) 68588c2ecf20Sopenharmony_ci instance->max_sectors_per_req = MEGASAS_MAX_SECTORS_IEEE; 68598c2ecf20Sopenharmony_ci 68608c2ecf20Sopenharmony_ci /* 68618c2ecf20Sopenharmony_ci * Check if the module parameter value for max_sectors can be used 68628c2ecf20Sopenharmony_ci */ 68638c2ecf20Sopenharmony_ci if (max_sectors && max_sectors < instance->max_sectors_per_req) 68648c2ecf20Sopenharmony_ci instance->max_sectors_per_req = max_sectors; 68658c2ecf20Sopenharmony_ci else { 68668c2ecf20Sopenharmony_ci if (max_sectors) { 68678c2ecf20Sopenharmony_ci if (((instance->pdev->device == 68688c2ecf20Sopenharmony_ci PCI_DEVICE_ID_LSI_SAS1078GEN2) || 68698c2ecf20Sopenharmony_ci (instance->pdev->device == 68708c2ecf20Sopenharmony_ci PCI_DEVICE_ID_LSI_SAS0079GEN2)) && 68718c2ecf20Sopenharmony_ci (max_sectors <= MEGASAS_MAX_SECTORS)) { 68728c2ecf20Sopenharmony_ci instance->max_sectors_per_req = max_sectors; 68738c2ecf20Sopenharmony_ci } else { 68748c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "max_sectors should be > 0" 68758c2ecf20Sopenharmony_ci "and <= %d (or < 1MB for GEN2 controller)\n", 68768c2ecf20Sopenharmony_ci instance->max_sectors_per_req); 68778c2ecf20Sopenharmony_ci } 68788c2ecf20Sopenharmony_ci } 68798c2ecf20Sopenharmony_ci } 68808c2ecf20Sopenharmony_ci 68818c2ecf20Sopenharmony_ci host->max_sectors = instance->max_sectors_per_req; 68828c2ecf20Sopenharmony_ci host->cmd_per_lun = MEGASAS_DEFAULT_CMD_PER_LUN; 68838c2ecf20Sopenharmony_ci host->max_channel = MEGASAS_MAX_CHANNELS - 1; 68848c2ecf20Sopenharmony_ci host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL; 68858c2ecf20Sopenharmony_ci host->max_lun = MEGASAS_MAX_LUN; 68868c2ecf20Sopenharmony_ci host->max_cmd_len = 16; 68878c2ecf20Sopenharmony_ci 68888c2ecf20Sopenharmony_ci /* Use shared host tagset only for fusion adaptors 68898c2ecf20Sopenharmony_ci * if there are managed interrupts (smp affinity enabled case). 68908c2ecf20Sopenharmony_ci * Single msix_vectors in kdump, so shared host tag is also disabled. 68918c2ecf20Sopenharmony_ci */ 68928c2ecf20Sopenharmony_ci 68938c2ecf20Sopenharmony_ci host->host_tagset = 0; 68948c2ecf20Sopenharmony_ci host->nr_hw_queues = 1; 68958c2ecf20Sopenharmony_ci 68968c2ecf20Sopenharmony_ci if ((instance->adapter_type != MFI_SERIES) && 68978c2ecf20Sopenharmony_ci (instance->msix_vectors > instance->low_latency_index_start) && 68988c2ecf20Sopenharmony_ci host_tagset_enable && 68998c2ecf20Sopenharmony_ci instance->smp_affinity_enable) { 69008c2ecf20Sopenharmony_ci host->host_tagset = 1; 69018c2ecf20Sopenharmony_ci host->nr_hw_queues = instance->msix_vectors - 69028c2ecf20Sopenharmony_ci instance->low_latency_index_start; 69038c2ecf20Sopenharmony_ci } 69048c2ecf20Sopenharmony_ci 69058c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 69068c2ecf20Sopenharmony_ci "Max firmware commands: %d shared with nr_hw_queues = %d\n", 69078c2ecf20Sopenharmony_ci instance->max_fw_cmds, host->nr_hw_queues); 69088c2ecf20Sopenharmony_ci /* 69098c2ecf20Sopenharmony_ci * Notify the mid-layer about the new controller 69108c2ecf20Sopenharmony_ci */ 69118c2ecf20Sopenharmony_ci if (scsi_add_host(host, &instance->pdev->dev)) { 69128c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 69138c2ecf20Sopenharmony_ci "Failed to add host from %s %d\n", 69148c2ecf20Sopenharmony_ci __func__, __LINE__); 69158c2ecf20Sopenharmony_ci return -ENODEV; 69168c2ecf20Sopenharmony_ci } 69178c2ecf20Sopenharmony_ci 69188c2ecf20Sopenharmony_ci return 0; 69198c2ecf20Sopenharmony_ci} 69208c2ecf20Sopenharmony_ci 69218c2ecf20Sopenharmony_ci/** 69228c2ecf20Sopenharmony_ci * megasas_set_dma_mask - Set DMA mask for supported controllers 69238c2ecf20Sopenharmony_ci * 69248c2ecf20Sopenharmony_ci * @instance: Adapter soft state 69258c2ecf20Sopenharmony_ci * Description: 69268c2ecf20Sopenharmony_ci * 69278c2ecf20Sopenharmony_ci * For Ventura, driver/FW will operate in 63bit DMA addresses. 69288c2ecf20Sopenharmony_ci * 69298c2ecf20Sopenharmony_ci * For invader- 69308c2ecf20Sopenharmony_ci * By default, driver/FW will operate in 32bit DMA addresses 69318c2ecf20Sopenharmony_ci * for consistent DMA mapping but if 32 bit consistent 69328c2ecf20Sopenharmony_ci * DMA mask fails, driver will try with 63 bit consistent 69338c2ecf20Sopenharmony_ci * mask provided FW is true 63bit DMA capable 69348c2ecf20Sopenharmony_ci * 69358c2ecf20Sopenharmony_ci * For older controllers(Thunderbolt and MFI based adapters)- 69368c2ecf20Sopenharmony_ci * driver/FW will operate in 32 bit consistent DMA addresses. 69378c2ecf20Sopenharmony_ci */ 69388c2ecf20Sopenharmony_cistatic int 69398c2ecf20Sopenharmony_cimegasas_set_dma_mask(struct megasas_instance *instance) 69408c2ecf20Sopenharmony_ci{ 69418c2ecf20Sopenharmony_ci u64 consistent_mask; 69428c2ecf20Sopenharmony_ci struct pci_dev *pdev; 69438c2ecf20Sopenharmony_ci u32 scratch_pad_1; 69448c2ecf20Sopenharmony_ci 69458c2ecf20Sopenharmony_ci pdev = instance->pdev; 69468c2ecf20Sopenharmony_ci consistent_mask = (instance->adapter_type >= VENTURA_SERIES) ? 69478c2ecf20Sopenharmony_ci DMA_BIT_MASK(63) : DMA_BIT_MASK(32); 69488c2ecf20Sopenharmony_ci 69498c2ecf20Sopenharmony_ci if (IS_DMA64) { 69508c2ecf20Sopenharmony_ci if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(63)) && 69518c2ecf20Sopenharmony_ci dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) 69528c2ecf20Sopenharmony_ci goto fail_set_dma_mask; 69538c2ecf20Sopenharmony_ci 69548c2ecf20Sopenharmony_ci if ((*pdev->dev.dma_mask == DMA_BIT_MASK(63)) && 69558c2ecf20Sopenharmony_ci (dma_set_coherent_mask(&pdev->dev, consistent_mask) && 69568c2ecf20Sopenharmony_ci dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))) { 69578c2ecf20Sopenharmony_ci /* 69588c2ecf20Sopenharmony_ci * If 32 bit DMA mask fails, then try for 64 bit mask 69598c2ecf20Sopenharmony_ci * for FW capable of handling 64 bit DMA. 69608c2ecf20Sopenharmony_ci */ 69618c2ecf20Sopenharmony_ci scratch_pad_1 = megasas_readl 69628c2ecf20Sopenharmony_ci (instance, &instance->reg_set->outbound_scratch_pad_1); 69638c2ecf20Sopenharmony_ci 69648c2ecf20Sopenharmony_ci if (!(scratch_pad_1 & MR_CAN_HANDLE_64_BIT_DMA_OFFSET)) 69658c2ecf20Sopenharmony_ci goto fail_set_dma_mask; 69668c2ecf20Sopenharmony_ci else if (dma_set_mask_and_coherent(&pdev->dev, 69678c2ecf20Sopenharmony_ci DMA_BIT_MASK(63))) 69688c2ecf20Sopenharmony_ci goto fail_set_dma_mask; 69698c2ecf20Sopenharmony_ci } 69708c2ecf20Sopenharmony_ci } else if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) 69718c2ecf20Sopenharmony_ci goto fail_set_dma_mask; 69728c2ecf20Sopenharmony_ci 69738c2ecf20Sopenharmony_ci if (pdev->dev.coherent_dma_mask == DMA_BIT_MASK(32)) 69748c2ecf20Sopenharmony_ci instance->consistent_mask_64bit = false; 69758c2ecf20Sopenharmony_ci else 69768c2ecf20Sopenharmony_ci instance->consistent_mask_64bit = true; 69778c2ecf20Sopenharmony_ci 69788c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "%s bit DMA mask and %s bit consistent mask\n", 69798c2ecf20Sopenharmony_ci ((*pdev->dev.dma_mask == DMA_BIT_MASK(63)) ? "63" : "32"), 69808c2ecf20Sopenharmony_ci (instance->consistent_mask_64bit ? "63" : "32")); 69818c2ecf20Sopenharmony_ci 69828c2ecf20Sopenharmony_ci return 0; 69838c2ecf20Sopenharmony_ci 69848c2ecf20Sopenharmony_cifail_set_dma_mask: 69858c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to set DMA mask\n"); 69868c2ecf20Sopenharmony_ci return -1; 69878c2ecf20Sopenharmony_ci 69888c2ecf20Sopenharmony_ci} 69898c2ecf20Sopenharmony_ci 69908c2ecf20Sopenharmony_ci/* 69918c2ecf20Sopenharmony_ci * megasas_set_adapter_type - Set adapter type. 69928c2ecf20Sopenharmony_ci * Supported controllers can be divided in 69938c2ecf20Sopenharmony_ci * different categories- 69948c2ecf20Sopenharmony_ci * enum MR_ADAPTER_TYPE { 69958c2ecf20Sopenharmony_ci * MFI_SERIES = 1, 69968c2ecf20Sopenharmony_ci * THUNDERBOLT_SERIES = 2, 69978c2ecf20Sopenharmony_ci * INVADER_SERIES = 3, 69988c2ecf20Sopenharmony_ci * VENTURA_SERIES = 4, 69998c2ecf20Sopenharmony_ci * AERO_SERIES = 5, 70008c2ecf20Sopenharmony_ci * }; 70018c2ecf20Sopenharmony_ci * @instance: Adapter soft state 70028c2ecf20Sopenharmony_ci * return: void 70038c2ecf20Sopenharmony_ci */ 70048c2ecf20Sopenharmony_cistatic inline void megasas_set_adapter_type(struct megasas_instance *instance) 70058c2ecf20Sopenharmony_ci{ 70068c2ecf20Sopenharmony_ci if ((instance->pdev->vendor == PCI_VENDOR_ID_DELL) && 70078c2ecf20Sopenharmony_ci (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5)) { 70088c2ecf20Sopenharmony_ci instance->adapter_type = MFI_SERIES; 70098c2ecf20Sopenharmony_ci } else { 70108c2ecf20Sopenharmony_ci switch (instance->pdev->device) { 70118c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_AERO_10E1: 70128c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_AERO_10E2: 70138c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_AERO_10E5: 70148c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_AERO_10E6: 70158c2ecf20Sopenharmony_ci instance->adapter_type = AERO_SERIES; 70168c2ecf20Sopenharmony_ci break; 70178c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_VENTURA: 70188c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_CRUSADER: 70198c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_HARPOON: 70208c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_TOMCAT: 70218c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_VENTURA_4PORT: 70228c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_CRUSADER_4PORT: 70238c2ecf20Sopenharmony_ci instance->adapter_type = VENTURA_SERIES; 70248c2ecf20Sopenharmony_ci break; 70258c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_FUSION: 70268c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_PLASMA: 70278c2ecf20Sopenharmony_ci instance->adapter_type = THUNDERBOLT_SERIES; 70288c2ecf20Sopenharmony_ci break; 70298c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_INVADER: 70308c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_INTRUDER: 70318c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_INTRUDER_24: 70328c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_CUTLASS_52: 70338c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_CUTLASS_53: 70348c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_FURY: 70358c2ecf20Sopenharmony_ci instance->adapter_type = INVADER_SERIES; 70368c2ecf20Sopenharmony_ci break; 70378c2ecf20Sopenharmony_ci default: /* For all other supported controllers */ 70388c2ecf20Sopenharmony_ci instance->adapter_type = MFI_SERIES; 70398c2ecf20Sopenharmony_ci break; 70408c2ecf20Sopenharmony_ci } 70418c2ecf20Sopenharmony_ci } 70428c2ecf20Sopenharmony_ci} 70438c2ecf20Sopenharmony_ci 70448c2ecf20Sopenharmony_cistatic inline int megasas_alloc_mfi_ctrl_mem(struct megasas_instance *instance) 70458c2ecf20Sopenharmony_ci{ 70468c2ecf20Sopenharmony_ci instance->producer = dma_alloc_coherent(&instance->pdev->dev, 70478c2ecf20Sopenharmony_ci sizeof(u32), &instance->producer_h, GFP_KERNEL); 70488c2ecf20Sopenharmony_ci instance->consumer = dma_alloc_coherent(&instance->pdev->dev, 70498c2ecf20Sopenharmony_ci sizeof(u32), &instance->consumer_h, GFP_KERNEL); 70508c2ecf20Sopenharmony_ci 70518c2ecf20Sopenharmony_ci if (!instance->producer || !instance->consumer) { 70528c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 70538c2ecf20Sopenharmony_ci "Failed to allocate memory for producer, consumer\n"); 70548c2ecf20Sopenharmony_ci return -1; 70558c2ecf20Sopenharmony_ci } 70568c2ecf20Sopenharmony_ci 70578c2ecf20Sopenharmony_ci *instance->producer = 0; 70588c2ecf20Sopenharmony_ci *instance->consumer = 0; 70598c2ecf20Sopenharmony_ci return 0; 70608c2ecf20Sopenharmony_ci} 70618c2ecf20Sopenharmony_ci 70628c2ecf20Sopenharmony_ci/** 70638c2ecf20Sopenharmony_ci * megasas_alloc_ctrl_mem - Allocate per controller memory for core data 70648c2ecf20Sopenharmony_ci * structures which are not common across MFI 70658c2ecf20Sopenharmony_ci * adapters and fusion adapters. 70668c2ecf20Sopenharmony_ci * For MFI based adapters, allocate producer and 70678c2ecf20Sopenharmony_ci * consumer buffers. For fusion adapters, allocate 70688c2ecf20Sopenharmony_ci * memory for fusion context. 70698c2ecf20Sopenharmony_ci * @instance: Adapter soft state 70708c2ecf20Sopenharmony_ci * return: 0 for SUCCESS 70718c2ecf20Sopenharmony_ci */ 70728c2ecf20Sopenharmony_cistatic int megasas_alloc_ctrl_mem(struct megasas_instance *instance) 70738c2ecf20Sopenharmony_ci{ 70748c2ecf20Sopenharmony_ci instance->reply_map = kcalloc(nr_cpu_ids, sizeof(unsigned int), 70758c2ecf20Sopenharmony_ci GFP_KERNEL); 70768c2ecf20Sopenharmony_ci if (!instance->reply_map) 70778c2ecf20Sopenharmony_ci return -ENOMEM; 70788c2ecf20Sopenharmony_ci 70798c2ecf20Sopenharmony_ci switch (instance->adapter_type) { 70808c2ecf20Sopenharmony_ci case MFI_SERIES: 70818c2ecf20Sopenharmony_ci if (megasas_alloc_mfi_ctrl_mem(instance)) 70828c2ecf20Sopenharmony_ci goto fail; 70838c2ecf20Sopenharmony_ci break; 70848c2ecf20Sopenharmony_ci case AERO_SERIES: 70858c2ecf20Sopenharmony_ci case VENTURA_SERIES: 70868c2ecf20Sopenharmony_ci case THUNDERBOLT_SERIES: 70878c2ecf20Sopenharmony_ci case INVADER_SERIES: 70888c2ecf20Sopenharmony_ci if (megasas_alloc_fusion_context(instance)) 70898c2ecf20Sopenharmony_ci goto fail; 70908c2ecf20Sopenharmony_ci break; 70918c2ecf20Sopenharmony_ci } 70928c2ecf20Sopenharmony_ci 70938c2ecf20Sopenharmony_ci return 0; 70948c2ecf20Sopenharmony_ci fail: 70958c2ecf20Sopenharmony_ci kfree(instance->reply_map); 70968c2ecf20Sopenharmony_ci instance->reply_map = NULL; 70978c2ecf20Sopenharmony_ci return -ENOMEM; 70988c2ecf20Sopenharmony_ci} 70998c2ecf20Sopenharmony_ci 71008c2ecf20Sopenharmony_ci/* 71018c2ecf20Sopenharmony_ci * megasas_free_ctrl_mem - Free fusion context for fusion adapters and 71028c2ecf20Sopenharmony_ci * producer, consumer buffers for MFI adapters 71038c2ecf20Sopenharmony_ci * 71048c2ecf20Sopenharmony_ci * @instance - Adapter soft instance 71058c2ecf20Sopenharmony_ci * 71068c2ecf20Sopenharmony_ci */ 71078c2ecf20Sopenharmony_cistatic inline void megasas_free_ctrl_mem(struct megasas_instance *instance) 71088c2ecf20Sopenharmony_ci{ 71098c2ecf20Sopenharmony_ci kfree(instance->reply_map); 71108c2ecf20Sopenharmony_ci if (instance->adapter_type == MFI_SERIES) { 71118c2ecf20Sopenharmony_ci if (instance->producer) 71128c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, sizeof(u32), 71138c2ecf20Sopenharmony_ci instance->producer, 71148c2ecf20Sopenharmony_ci instance->producer_h); 71158c2ecf20Sopenharmony_ci if (instance->consumer) 71168c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, sizeof(u32), 71178c2ecf20Sopenharmony_ci instance->consumer, 71188c2ecf20Sopenharmony_ci instance->consumer_h); 71198c2ecf20Sopenharmony_ci } else { 71208c2ecf20Sopenharmony_ci megasas_free_fusion_context(instance); 71218c2ecf20Sopenharmony_ci } 71228c2ecf20Sopenharmony_ci} 71238c2ecf20Sopenharmony_ci 71248c2ecf20Sopenharmony_ci/** 71258c2ecf20Sopenharmony_ci * megasas_alloc_ctrl_dma_buffers - Allocate consistent DMA buffers during 71268c2ecf20Sopenharmony_ci * driver load time 71278c2ecf20Sopenharmony_ci * 71288c2ecf20Sopenharmony_ci * @instance: Adapter soft instance 71298c2ecf20Sopenharmony_ci * 71308c2ecf20Sopenharmony_ci * @return: O for SUCCESS 71318c2ecf20Sopenharmony_ci */ 71328c2ecf20Sopenharmony_cistatic inline 71338c2ecf20Sopenharmony_ciint megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance) 71348c2ecf20Sopenharmony_ci{ 71358c2ecf20Sopenharmony_ci struct pci_dev *pdev = instance->pdev; 71368c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 71378c2ecf20Sopenharmony_ci 71388c2ecf20Sopenharmony_ci instance->evt_detail = dma_alloc_coherent(&pdev->dev, 71398c2ecf20Sopenharmony_ci sizeof(struct megasas_evt_detail), 71408c2ecf20Sopenharmony_ci &instance->evt_detail_h, GFP_KERNEL); 71418c2ecf20Sopenharmony_ci 71428c2ecf20Sopenharmony_ci if (!instance->evt_detail) { 71438c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 71448c2ecf20Sopenharmony_ci "Failed to allocate event detail buffer\n"); 71458c2ecf20Sopenharmony_ci return -ENOMEM; 71468c2ecf20Sopenharmony_ci } 71478c2ecf20Sopenharmony_ci 71488c2ecf20Sopenharmony_ci if (fusion) { 71498c2ecf20Sopenharmony_ci fusion->ioc_init_request = 71508c2ecf20Sopenharmony_ci dma_alloc_coherent(&pdev->dev, 71518c2ecf20Sopenharmony_ci sizeof(struct MPI2_IOC_INIT_REQUEST), 71528c2ecf20Sopenharmony_ci &fusion->ioc_init_request_phys, 71538c2ecf20Sopenharmony_ci GFP_KERNEL); 71548c2ecf20Sopenharmony_ci 71558c2ecf20Sopenharmony_ci if (!fusion->ioc_init_request) { 71568c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 71578c2ecf20Sopenharmony_ci "Failed to allocate PD list buffer\n"); 71588c2ecf20Sopenharmony_ci return -ENOMEM; 71598c2ecf20Sopenharmony_ci } 71608c2ecf20Sopenharmony_ci 71618c2ecf20Sopenharmony_ci instance->snapdump_prop = dma_alloc_coherent(&pdev->dev, 71628c2ecf20Sopenharmony_ci sizeof(struct MR_SNAPDUMP_PROPERTIES), 71638c2ecf20Sopenharmony_ci &instance->snapdump_prop_h, GFP_KERNEL); 71648c2ecf20Sopenharmony_ci 71658c2ecf20Sopenharmony_ci if (!instance->snapdump_prop) 71668c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 71678c2ecf20Sopenharmony_ci "Failed to allocate snapdump properties buffer\n"); 71688c2ecf20Sopenharmony_ci 71698c2ecf20Sopenharmony_ci instance->host_device_list_buf = dma_alloc_coherent(&pdev->dev, 71708c2ecf20Sopenharmony_ci HOST_DEVICE_LIST_SZ, 71718c2ecf20Sopenharmony_ci &instance->host_device_list_buf_h, 71728c2ecf20Sopenharmony_ci GFP_KERNEL); 71738c2ecf20Sopenharmony_ci 71748c2ecf20Sopenharmony_ci if (!instance->host_device_list_buf) { 71758c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 71768c2ecf20Sopenharmony_ci "Failed to allocate targetid list buffer\n"); 71778c2ecf20Sopenharmony_ci return -ENOMEM; 71788c2ecf20Sopenharmony_ci } 71798c2ecf20Sopenharmony_ci 71808c2ecf20Sopenharmony_ci } 71818c2ecf20Sopenharmony_ci 71828c2ecf20Sopenharmony_ci instance->pd_list_buf = 71838c2ecf20Sopenharmony_ci dma_alloc_coherent(&pdev->dev, 71848c2ecf20Sopenharmony_ci MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), 71858c2ecf20Sopenharmony_ci &instance->pd_list_buf_h, GFP_KERNEL); 71868c2ecf20Sopenharmony_ci 71878c2ecf20Sopenharmony_ci if (!instance->pd_list_buf) { 71888c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to allocate PD list buffer\n"); 71898c2ecf20Sopenharmony_ci return -ENOMEM; 71908c2ecf20Sopenharmony_ci } 71918c2ecf20Sopenharmony_ci 71928c2ecf20Sopenharmony_ci instance->ctrl_info_buf = 71938c2ecf20Sopenharmony_ci dma_alloc_coherent(&pdev->dev, 71948c2ecf20Sopenharmony_ci sizeof(struct megasas_ctrl_info), 71958c2ecf20Sopenharmony_ci &instance->ctrl_info_buf_h, GFP_KERNEL); 71968c2ecf20Sopenharmony_ci 71978c2ecf20Sopenharmony_ci if (!instance->ctrl_info_buf) { 71988c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 71998c2ecf20Sopenharmony_ci "Failed to allocate controller info buffer\n"); 72008c2ecf20Sopenharmony_ci return -ENOMEM; 72018c2ecf20Sopenharmony_ci } 72028c2ecf20Sopenharmony_ci 72038c2ecf20Sopenharmony_ci instance->ld_list_buf = 72048c2ecf20Sopenharmony_ci dma_alloc_coherent(&pdev->dev, 72058c2ecf20Sopenharmony_ci sizeof(struct MR_LD_LIST), 72068c2ecf20Sopenharmony_ci &instance->ld_list_buf_h, GFP_KERNEL); 72078c2ecf20Sopenharmony_ci 72088c2ecf20Sopenharmony_ci if (!instance->ld_list_buf) { 72098c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to allocate LD list buffer\n"); 72108c2ecf20Sopenharmony_ci return -ENOMEM; 72118c2ecf20Sopenharmony_ci } 72128c2ecf20Sopenharmony_ci 72138c2ecf20Sopenharmony_ci instance->ld_targetid_list_buf = 72148c2ecf20Sopenharmony_ci dma_alloc_coherent(&pdev->dev, 72158c2ecf20Sopenharmony_ci sizeof(struct MR_LD_TARGETID_LIST), 72168c2ecf20Sopenharmony_ci &instance->ld_targetid_list_buf_h, GFP_KERNEL); 72178c2ecf20Sopenharmony_ci 72188c2ecf20Sopenharmony_ci if (!instance->ld_targetid_list_buf) { 72198c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 72208c2ecf20Sopenharmony_ci "Failed to allocate LD targetid list buffer\n"); 72218c2ecf20Sopenharmony_ci return -ENOMEM; 72228c2ecf20Sopenharmony_ci } 72238c2ecf20Sopenharmony_ci 72248c2ecf20Sopenharmony_ci if (!reset_devices) { 72258c2ecf20Sopenharmony_ci instance->system_info_buf = 72268c2ecf20Sopenharmony_ci dma_alloc_coherent(&pdev->dev, 72278c2ecf20Sopenharmony_ci sizeof(struct MR_DRV_SYSTEM_INFO), 72288c2ecf20Sopenharmony_ci &instance->system_info_h, GFP_KERNEL); 72298c2ecf20Sopenharmony_ci instance->pd_info = 72308c2ecf20Sopenharmony_ci dma_alloc_coherent(&pdev->dev, 72318c2ecf20Sopenharmony_ci sizeof(struct MR_PD_INFO), 72328c2ecf20Sopenharmony_ci &instance->pd_info_h, GFP_KERNEL); 72338c2ecf20Sopenharmony_ci instance->tgt_prop = 72348c2ecf20Sopenharmony_ci dma_alloc_coherent(&pdev->dev, 72358c2ecf20Sopenharmony_ci sizeof(struct MR_TARGET_PROPERTIES), 72368c2ecf20Sopenharmony_ci &instance->tgt_prop_h, GFP_KERNEL); 72378c2ecf20Sopenharmony_ci instance->crash_dump_buf = 72388c2ecf20Sopenharmony_ci dma_alloc_coherent(&pdev->dev, CRASH_DMA_BUF_SIZE, 72398c2ecf20Sopenharmony_ci &instance->crash_dump_h, GFP_KERNEL); 72408c2ecf20Sopenharmony_ci 72418c2ecf20Sopenharmony_ci if (!instance->system_info_buf) 72428c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 72438c2ecf20Sopenharmony_ci "Failed to allocate system info buffer\n"); 72448c2ecf20Sopenharmony_ci 72458c2ecf20Sopenharmony_ci if (!instance->pd_info) 72468c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 72478c2ecf20Sopenharmony_ci "Failed to allocate pd_info buffer\n"); 72488c2ecf20Sopenharmony_ci 72498c2ecf20Sopenharmony_ci if (!instance->tgt_prop) 72508c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 72518c2ecf20Sopenharmony_ci "Failed to allocate tgt_prop buffer\n"); 72528c2ecf20Sopenharmony_ci 72538c2ecf20Sopenharmony_ci if (!instance->crash_dump_buf) 72548c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 72558c2ecf20Sopenharmony_ci "Failed to allocate crash dump buffer\n"); 72568c2ecf20Sopenharmony_ci } 72578c2ecf20Sopenharmony_ci 72588c2ecf20Sopenharmony_ci return 0; 72598c2ecf20Sopenharmony_ci} 72608c2ecf20Sopenharmony_ci 72618c2ecf20Sopenharmony_ci/* 72628c2ecf20Sopenharmony_ci * megasas_free_ctrl_dma_buffers - Free consistent DMA buffers allocated 72638c2ecf20Sopenharmony_ci * during driver load time 72648c2ecf20Sopenharmony_ci * 72658c2ecf20Sopenharmony_ci * @instance- Adapter soft instance 72668c2ecf20Sopenharmony_ci * 72678c2ecf20Sopenharmony_ci */ 72688c2ecf20Sopenharmony_cistatic inline 72698c2ecf20Sopenharmony_civoid megasas_free_ctrl_dma_buffers(struct megasas_instance *instance) 72708c2ecf20Sopenharmony_ci{ 72718c2ecf20Sopenharmony_ci struct pci_dev *pdev = instance->pdev; 72728c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 72738c2ecf20Sopenharmony_ci 72748c2ecf20Sopenharmony_ci if (instance->evt_detail) 72758c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(struct megasas_evt_detail), 72768c2ecf20Sopenharmony_ci instance->evt_detail, 72778c2ecf20Sopenharmony_ci instance->evt_detail_h); 72788c2ecf20Sopenharmony_ci 72798c2ecf20Sopenharmony_ci if (fusion && fusion->ioc_init_request) 72808c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 72818c2ecf20Sopenharmony_ci sizeof(struct MPI2_IOC_INIT_REQUEST), 72828c2ecf20Sopenharmony_ci fusion->ioc_init_request, 72838c2ecf20Sopenharmony_ci fusion->ioc_init_request_phys); 72848c2ecf20Sopenharmony_ci 72858c2ecf20Sopenharmony_ci if (instance->pd_list_buf) 72868c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 72878c2ecf20Sopenharmony_ci MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), 72888c2ecf20Sopenharmony_ci instance->pd_list_buf, 72898c2ecf20Sopenharmony_ci instance->pd_list_buf_h); 72908c2ecf20Sopenharmony_ci 72918c2ecf20Sopenharmony_ci if (instance->ld_list_buf) 72928c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(struct MR_LD_LIST), 72938c2ecf20Sopenharmony_ci instance->ld_list_buf, 72948c2ecf20Sopenharmony_ci instance->ld_list_buf_h); 72958c2ecf20Sopenharmony_ci 72968c2ecf20Sopenharmony_ci if (instance->ld_targetid_list_buf) 72978c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(struct MR_LD_TARGETID_LIST), 72988c2ecf20Sopenharmony_ci instance->ld_targetid_list_buf, 72998c2ecf20Sopenharmony_ci instance->ld_targetid_list_buf_h); 73008c2ecf20Sopenharmony_ci 73018c2ecf20Sopenharmony_ci if (instance->ctrl_info_buf) 73028c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(struct megasas_ctrl_info), 73038c2ecf20Sopenharmony_ci instance->ctrl_info_buf, 73048c2ecf20Sopenharmony_ci instance->ctrl_info_buf_h); 73058c2ecf20Sopenharmony_ci 73068c2ecf20Sopenharmony_ci if (instance->system_info_buf) 73078c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(struct MR_DRV_SYSTEM_INFO), 73088c2ecf20Sopenharmony_ci instance->system_info_buf, 73098c2ecf20Sopenharmony_ci instance->system_info_h); 73108c2ecf20Sopenharmony_ci 73118c2ecf20Sopenharmony_ci if (instance->pd_info) 73128c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(struct MR_PD_INFO), 73138c2ecf20Sopenharmony_ci instance->pd_info, instance->pd_info_h); 73148c2ecf20Sopenharmony_ci 73158c2ecf20Sopenharmony_ci if (instance->tgt_prop) 73168c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(struct MR_TARGET_PROPERTIES), 73178c2ecf20Sopenharmony_ci instance->tgt_prop, instance->tgt_prop_h); 73188c2ecf20Sopenharmony_ci 73198c2ecf20Sopenharmony_ci if (instance->crash_dump_buf) 73208c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, CRASH_DMA_BUF_SIZE, 73218c2ecf20Sopenharmony_ci instance->crash_dump_buf, 73228c2ecf20Sopenharmony_ci instance->crash_dump_h); 73238c2ecf20Sopenharmony_ci 73248c2ecf20Sopenharmony_ci if (instance->snapdump_prop) 73258c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 73268c2ecf20Sopenharmony_ci sizeof(struct MR_SNAPDUMP_PROPERTIES), 73278c2ecf20Sopenharmony_ci instance->snapdump_prop, 73288c2ecf20Sopenharmony_ci instance->snapdump_prop_h); 73298c2ecf20Sopenharmony_ci 73308c2ecf20Sopenharmony_ci if (instance->host_device_list_buf) 73318c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 73328c2ecf20Sopenharmony_ci HOST_DEVICE_LIST_SZ, 73338c2ecf20Sopenharmony_ci instance->host_device_list_buf, 73348c2ecf20Sopenharmony_ci instance->host_device_list_buf_h); 73358c2ecf20Sopenharmony_ci 73368c2ecf20Sopenharmony_ci} 73378c2ecf20Sopenharmony_ci 73388c2ecf20Sopenharmony_ci/* 73398c2ecf20Sopenharmony_ci * megasas_init_ctrl_params - Initialize controller's instance 73408c2ecf20Sopenharmony_ci * parameters before FW init 73418c2ecf20Sopenharmony_ci * @instance - Adapter soft instance 73428c2ecf20Sopenharmony_ci * @return - void 73438c2ecf20Sopenharmony_ci */ 73448c2ecf20Sopenharmony_cistatic inline void megasas_init_ctrl_params(struct megasas_instance *instance) 73458c2ecf20Sopenharmony_ci{ 73468c2ecf20Sopenharmony_ci instance->fw_crash_state = UNAVAILABLE; 73478c2ecf20Sopenharmony_ci 73488c2ecf20Sopenharmony_ci megasas_poll_wait_aen = 0; 73498c2ecf20Sopenharmony_ci instance->issuepend_done = 1; 73508c2ecf20Sopenharmony_ci atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL); 73518c2ecf20Sopenharmony_ci 73528c2ecf20Sopenharmony_ci /* 73538c2ecf20Sopenharmony_ci * Initialize locks and queues 73548c2ecf20Sopenharmony_ci */ 73558c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&instance->cmd_pool); 73568c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&instance->internal_reset_pending_q); 73578c2ecf20Sopenharmony_ci 73588c2ecf20Sopenharmony_ci atomic_set(&instance->fw_outstanding, 0); 73598c2ecf20Sopenharmony_ci atomic64_set(&instance->total_io_count, 0); 73608c2ecf20Sopenharmony_ci 73618c2ecf20Sopenharmony_ci init_waitqueue_head(&instance->int_cmd_wait_q); 73628c2ecf20Sopenharmony_ci init_waitqueue_head(&instance->abort_cmd_wait_q); 73638c2ecf20Sopenharmony_ci 73648c2ecf20Sopenharmony_ci mutex_init(&instance->crashdump_lock); 73658c2ecf20Sopenharmony_ci spin_lock_init(&instance->mfi_pool_lock); 73668c2ecf20Sopenharmony_ci spin_lock_init(&instance->hba_lock); 73678c2ecf20Sopenharmony_ci spin_lock_init(&instance->stream_lock); 73688c2ecf20Sopenharmony_ci spin_lock_init(&instance->completion_lock); 73698c2ecf20Sopenharmony_ci 73708c2ecf20Sopenharmony_ci mutex_init(&instance->reset_mutex); 73718c2ecf20Sopenharmony_ci 73728c2ecf20Sopenharmony_ci if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || 73738c2ecf20Sopenharmony_ci (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) 73748c2ecf20Sopenharmony_ci instance->flag_ieee = 1; 73758c2ecf20Sopenharmony_ci 73768c2ecf20Sopenharmony_ci megasas_dbg_lvl = 0; 73778c2ecf20Sopenharmony_ci instance->flag = 0; 73788c2ecf20Sopenharmony_ci instance->unload = 1; 73798c2ecf20Sopenharmony_ci instance->last_time = 0; 73808c2ecf20Sopenharmony_ci instance->disableOnlineCtrlReset = 1; 73818c2ecf20Sopenharmony_ci instance->UnevenSpanSupport = 0; 73828c2ecf20Sopenharmony_ci instance->smp_affinity_enable = smp_affinity_enable ? true : false; 73838c2ecf20Sopenharmony_ci instance->msix_load_balance = false; 73848c2ecf20Sopenharmony_ci 73858c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) 73868c2ecf20Sopenharmony_ci INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq); 73878c2ecf20Sopenharmony_ci else 73888c2ecf20Sopenharmony_ci INIT_WORK(&instance->work_init, process_fw_state_change_wq); 73898c2ecf20Sopenharmony_ci} 73908c2ecf20Sopenharmony_ci 73918c2ecf20Sopenharmony_ci/** 73928c2ecf20Sopenharmony_ci * megasas_probe_one - PCI hotplug entry point 73938c2ecf20Sopenharmony_ci * @pdev: PCI device structure 73948c2ecf20Sopenharmony_ci * @id: PCI ids of supported hotplugged adapter 73958c2ecf20Sopenharmony_ci */ 73968c2ecf20Sopenharmony_cistatic int megasas_probe_one(struct pci_dev *pdev, 73978c2ecf20Sopenharmony_ci const struct pci_device_id *id) 73988c2ecf20Sopenharmony_ci{ 73998c2ecf20Sopenharmony_ci int rval, pos; 74008c2ecf20Sopenharmony_ci struct Scsi_Host *host; 74018c2ecf20Sopenharmony_ci struct megasas_instance *instance; 74028c2ecf20Sopenharmony_ci u16 control = 0; 74038c2ecf20Sopenharmony_ci 74048c2ecf20Sopenharmony_ci switch (pdev->device) { 74058c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_AERO_10E0: 74068c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_AERO_10E3: 74078c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_AERO_10E4: 74088c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_AERO_10E7: 74098c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Adapter is in non secure mode\n"); 74108c2ecf20Sopenharmony_ci return 1; 74118c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_AERO_10E1: 74128c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_AERO_10E5: 74138c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Adapter is in configurable secure mode\n"); 74148c2ecf20Sopenharmony_ci break; 74158c2ecf20Sopenharmony_ci } 74168c2ecf20Sopenharmony_ci 74178c2ecf20Sopenharmony_ci /* Reset MSI-X in the kdump kernel */ 74188c2ecf20Sopenharmony_ci if (reset_devices) { 74198c2ecf20Sopenharmony_ci pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX); 74208c2ecf20Sopenharmony_ci if (pos) { 74218c2ecf20Sopenharmony_ci pci_read_config_word(pdev, pos + PCI_MSIX_FLAGS, 74228c2ecf20Sopenharmony_ci &control); 74238c2ecf20Sopenharmony_ci if (control & PCI_MSIX_FLAGS_ENABLE) { 74248c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "resetting MSI-X\n"); 74258c2ecf20Sopenharmony_ci pci_write_config_word(pdev, 74268c2ecf20Sopenharmony_ci pos + PCI_MSIX_FLAGS, 74278c2ecf20Sopenharmony_ci control & 74288c2ecf20Sopenharmony_ci ~PCI_MSIX_FLAGS_ENABLE); 74298c2ecf20Sopenharmony_ci } 74308c2ecf20Sopenharmony_ci } 74318c2ecf20Sopenharmony_ci } 74328c2ecf20Sopenharmony_ci 74338c2ecf20Sopenharmony_ci /* 74348c2ecf20Sopenharmony_ci * PCI prepping: enable device set bus mastering and dma mask 74358c2ecf20Sopenharmony_ci */ 74368c2ecf20Sopenharmony_ci rval = pci_enable_device_mem(pdev); 74378c2ecf20Sopenharmony_ci 74388c2ecf20Sopenharmony_ci if (rval) { 74398c2ecf20Sopenharmony_ci return rval; 74408c2ecf20Sopenharmony_ci } 74418c2ecf20Sopenharmony_ci 74428c2ecf20Sopenharmony_ci pci_set_master(pdev); 74438c2ecf20Sopenharmony_ci 74448c2ecf20Sopenharmony_ci host = scsi_host_alloc(&megasas_template, 74458c2ecf20Sopenharmony_ci sizeof(struct megasas_instance)); 74468c2ecf20Sopenharmony_ci 74478c2ecf20Sopenharmony_ci if (!host) { 74488c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &pdev->dev, "scsi_host_alloc failed\n"); 74498c2ecf20Sopenharmony_ci goto fail_alloc_instance; 74508c2ecf20Sopenharmony_ci } 74518c2ecf20Sopenharmony_ci 74528c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)host->hostdata; 74538c2ecf20Sopenharmony_ci memset(instance, 0, sizeof(*instance)); 74548c2ecf20Sopenharmony_ci atomic_set(&instance->fw_reset_no_pci_access, 0); 74558c2ecf20Sopenharmony_ci 74568c2ecf20Sopenharmony_ci /* 74578c2ecf20Sopenharmony_ci * Initialize PCI related and misc parameters 74588c2ecf20Sopenharmony_ci */ 74598c2ecf20Sopenharmony_ci instance->pdev = pdev; 74608c2ecf20Sopenharmony_ci instance->host = host; 74618c2ecf20Sopenharmony_ci instance->unique_id = pdev->bus->number << 8 | pdev->devfn; 74628c2ecf20Sopenharmony_ci instance->init_id = MEGASAS_DEFAULT_INIT_ID; 74638c2ecf20Sopenharmony_ci 74648c2ecf20Sopenharmony_ci megasas_set_adapter_type(instance); 74658c2ecf20Sopenharmony_ci 74668c2ecf20Sopenharmony_ci /* 74678c2ecf20Sopenharmony_ci * Initialize MFI Firmware 74688c2ecf20Sopenharmony_ci */ 74698c2ecf20Sopenharmony_ci if (megasas_init_fw(instance)) 74708c2ecf20Sopenharmony_ci goto fail_init_mfi; 74718c2ecf20Sopenharmony_ci 74728c2ecf20Sopenharmony_ci if (instance->requestorId) { 74738c2ecf20Sopenharmony_ci if (instance->PlasmaFW111) { 74748c2ecf20Sopenharmony_ci instance->vf_affiliation_111 = 74758c2ecf20Sopenharmony_ci dma_alloc_coherent(&pdev->dev, 74768c2ecf20Sopenharmony_ci sizeof(struct MR_LD_VF_AFFILIATION_111), 74778c2ecf20Sopenharmony_ci &instance->vf_affiliation_111_h, 74788c2ecf20Sopenharmony_ci GFP_KERNEL); 74798c2ecf20Sopenharmony_ci if (!instance->vf_affiliation_111) 74808c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Can't allocate " 74818c2ecf20Sopenharmony_ci "memory for VF affiliation buffer\n"); 74828c2ecf20Sopenharmony_ci } else { 74838c2ecf20Sopenharmony_ci instance->vf_affiliation = 74848c2ecf20Sopenharmony_ci dma_alloc_coherent(&pdev->dev, 74858c2ecf20Sopenharmony_ci (MAX_LOGICAL_DRIVES + 1) * 74868c2ecf20Sopenharmony_ci sizeof(struct MR_LD_VF_AFFILIATION), 74878c2ecf20Sopenharmony_ci &instance->vf_affiliation_h, 74888c2ecf20Sopenharmony_ci GFP_KERNEL); 74898c2ecf20Sopenharmony_ci if (!instance->vf_affiliation) 74908c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Can't allocate " 74918c2ecf20Sopenharmony_ci "memory for VF affiliation buffer\n"); 74928c2ecf20Sopenharmony_ci } 74938c2ecf20Sopenharmony_ci } 74948c2ecf20Sopenharmony_ci 74958c2ecf20Sopenharmony_ci /* 74968c2ecf20Sopenharmony_ci * Store instance in PCI softstate 74978c2ecf20Sopenharmony_ci */ 74988c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, instance); 74998c2ecf20Sopenharmony_ci 75008c2ecf20Sopenharmony_ci /* 75018c2ecf20Sopenharmony_ci * Add this controller to megasas_mgmt_info structure so that it 75028c2ecf20Sopenharmony_ci * can be exported to management applications 75038c2ecf20Sopenharmony_ci */ 75048c2ecf20Sopenharmony_ci megasas_mgmt_info.count++; 75058c2ecf20Sopenharmony_ci megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = instance; 75068c2ecf20Sopenharmony_ci megasas_mgmt_info.max_index++; 75078c2ecf20Sopenharmony_ci 75088c2ecf20Sopenharmony_ci /* 75098c2ecf20Sopenharmony_ci * Register with SCSI mid-layer 75108c2ecf20Sopenharmony_ci */ 75118c2ecf20Sopenharmony_ci if (megasas_io_attach(instance)) 75128c2ecf20Sopenharmony_ci goto fail_io_attach; 75138c2ecf20Sopenharmony_ci 75148c2ecf20Sopenharmony_ci instance->unload = 0; 75158c2ecf20Sopenharmony_ci /* 75168c2ecf20Sopenharmony_ci * Trigger SCSI to scan our drives 75178c2ecf20Sopenharmony_ci */ 75188c2ecf20Sopenharmony_ci if (!instance->enable_fw_dev_list || 75198c2ecf20Sopenharmony_ci (instance->host_device_list_buf->count > 0)) 75208c2ecf20Sopenharmony_ci scsi_scan_host(host); 75218c2ecf20Sopenharmony_ci 75228c2ecf20Sopenharmony_ci /* 75238c2ecf20Sopenharmony_ci * Initiate AEN (Asynchronous Event Notification) 75248c2ecf20Sopenharmony_ci */ 75258c2ecf20Sopenharmony_ci if (megasas_start_aen(instance)) { 75268c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &pdev->dev, "start aen failed\n"); 75278c2ecf20Sopenharmony_ci goto fail_start_aen; 75288c2ecf20Sopenharmony_ci } 75298c2ecf20Sopenharmony_ci 75308c2ecf20Sopenharmony_ci megasas_setup_debugfs(instance); 75318c2ecf20Sopenharmony_ci 75328c2ecf20Sopenharmony_ci /* Get current SR-IOV LD/VF affiliation */ 75338c2ecf20Sopenharmony_ci if (instance->requestorId) 75348c2ecf20Sopenharmony_ci megasas_get_ld_vf_affiliation(instance, 1); 75358c2ecf20Sopenharmony_ci 75368c2ecf20Sopenharmony_ci return 0; 75378c2ecf20Sopenharmony_ci 75388c2ecf20Sopenharmony_cifail_start_aen: 75398c2ecf20Sopenharmony_ci instance->unload = 1; 75408c2ecf20Sopenharmony_ci scsi_remove_host(instance->host); 75418c2ecf20Sopenharmony_cifail_io_attach: 75428c2ecf20Sopenharmony_ci megasas_mgmt_info.count--; 75438c2ecf20Sopenharmony_ci megasas_mgmt_info.max_index--; 75448c2ecf20Sopenharmony_ci megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = NULL; 75458c2ecf20Sopenharmony_ci 75468c2ecf20Sopenharmony_ci if (instance->requestorId && !instance->skip_heartbeat_timer_del) 75478c2ecf20Sopenharmony_ci del_timer_sync(&instance->sriov_heartbeat_timer); 75488c2ecf20Sopenharmony_ci 75498c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 75508c2ecf20Sopenharmony_ci megasas_destroy_irqs(instance); 75518c2ecf20Sopenharmony_ci 75528c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) 75538c2ecf20Sopenharmony_ci megasas_release_fusion(instance); 75548c2ecf20Sopenharmony_ci else 75558c2ecf20Sopenharmony_ci megasas_release_mfi(instance); 75568c2ecf20Sopenharmony_ci 75578c2ecf20Sopenharmony_ci if (instance->msix_vectors) 75588c2ecf20Sopenharmony_ci pci_free_irq_vectors(instance->pdev); 75598c2ecf20Sopenharmony_ci instance->msix_vectors = 0; 75608c2ecf20Sopenharmony_ci 75618c2ecf20Sopenharmony_ci if (instance->fw_crash_state != UNAVAILABLE) 75628c2ecf20Sopenharmony_ci megasas_free_host_crash_buffer(instance); 75638c2ecf20Sopenharmony_ci 75648c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) 75658c2ecf20Sopenharmony_ci megasas_fusion_stop_watchdog(instance); 75668c2ecf20Sopenharmony_cifail_init_mfi: 75678c2ecf20Sopenharmony_ci scsi_host_put(host); 75688c2ecf20Sopenharmony_cifail_alloc_instance: 75698c2ecf20Sopenharmony_ci pci_disable_device(pdev); 75708c2ecf20Sopenharmony_ci 75718c2ecf20Sopenharmony_ci return -ENODEV; 75728c2ecf20Sopenharmony_ci} 75738c2ecf20Sopenharmony_ci 75748c2ecf20Sopenharmony_ci/** 75758c2ecf20Sopenharmony_ci * megasas_flush_cache - Requests FW to flush all its caches 75768c2ecf20Sopenharmony_ci * @instance: Adapter soft state 75778c2ecf20Sopenharmony_ci */ 75788c2ecf20Sopenharmony_cistatic void megasas_flush_cache(struct megasas_instance *instance) 75798c2ecf20Sopenharmony_ci{ 75808c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 75818c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 75828c2ecf20Sopenharmony_ci 75838c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) 75848c2ecf20Sopenharmony_ci return; 75858c2ecf20Sopenharmony_ci 75868c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 75878c2ecf20Sopenharmony_ci 75888c2ecf20Sopenharmony_ci if (!cmd) 75898c2ecf20Sopenharmony_ci return; 75908c2ecf20Sopenharmony_ci 75918c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 75928c2ecf20Sopenharmony_ci 75938c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 75948c2ecf20Sopenharmony_ci 75958c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 75968c2ecf20Sopenharmony_ci dcmd->cmd_status = 0x0; 75978c2ecf20Sopenharmony_ci dcmd->sge_count = 0; 75988c2ecf20Sopenharmony_ci dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_NONE); 75998c2ecf20Sopenharmony_ci dcmd->timeout = 0; 76008c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 76018c2ecf20Sopenharmony_ci dcmd->data_xfer_len = 0; 76028c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_CACHE_FLUSH); 76038c2ecf20Sopenharmony_ci dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE; 76048c2ecf20Sopenharmony_ci 76058c2ecf20Sopenharmony_ci if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS) 76068c2ecf20Sopenharmony_ci != DCMD_SUCCESS) { 76078c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 76088c2ecf20Sopenharmony_ci "return from %s %d\n", __func__, __LINE__); 76098c2ecf20Sopenharmony_ci return; 76108c2ecf20Sopenharmony_ci } 76118c2ecf20Sopenharmony_ci 76128c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 76138c2ecf20Sopenharmony_ci} 76148c2ecf20Sopenharmony_ci 76158c2ecf20Sopenharmony_ci/** 76168c2ecf20Sopenharmony_ci * megasas_shutdown_controller - Instructs FW to shutdown the controller 76178c2ecf20Sopenharmony_ci * @instance: Adapter soft state 76188c2ecf20Sopenharmony_ci * @opcode: Shutdown/Hibernate 76198c2ecf20Sopenharmony_ci */ 76208c2ecf20Sopenharmony_cistatic void megasas_shutdown_controller(struct megasas_instance *instance, 76218c2ecf20Sopenharmony_ci u32 opcode) 76228c2ecf20Sopenharmony_ci{ 76238c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 76248c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 76258c2ecf20Sopenharmony_ci 76268c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) 76278c2ecf20Sopenharmony_ci return; 76288c2ecf20Sopenharmony_ci 76298c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 76308c2ecf20Sopenharmony_ci 76318c2ecf20Sopenharmony_ci if (!cmd) 76328c2ecf20Sopenharmony_ci return; 76338c2ecf20Sopenharmony_ci 76348c2ecf20Sopenharmony_ci if (instance->aen_cmd) 76358c2ecf20Sopenharmony_ci megasas_issue_blocked_abort_cmd(instance, 76368c2ecf20Sopenharmony_ci instance->aen_cmd, MFI_IO_TIMEOUT_SECS); 76378c2ecf20Sopenharmony_ci if (instance->map_update_cmd) 76388c2ecf20Sopenharmony_ci megasas_issue_blocked_abort_cmd(instance, 76398c2ecf20Sopenharmony_ci instance->map_update_cmd, MFI_IO_TIMEOUT_SECS); 76408c2ecf20Sopenharmony_ci if (instance->jbod_seq_cmd) 76418c2ecf20Sopenharmony_ci megasas_issue_blocked_abort_cmd(instance, 76428c2ecf20Sopenharmony_ci instance->jbod_seq_cmd, MFI_IO_TIMEOUT_SECS); 76438c2ecf20Sopenharmony_ci 76448c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 76458c2ecf20Sopenharmony_ci 76468c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 76478c2ecf20Sopenharmony_ci 76488c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 76498c2ecf20Sopenharmony_ci dcmd->cmd_status = 0x0; 76508c2ecf20Sopenharmony_ci dcmd->sge_count = 0; 76518c2ecf20Sopenharmony_ci dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_NONE); 76528c2ecf20Sopenharmony_ci dcmd->timeout = 0; 76538c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 76548c2ecf20Sopenharmony_ci dcmd->data_xfer_len = 0; 76558c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(opcode); 76568c2ecf20Sopenharmony_ci 76578c2ecf20Sopenharmony_ci if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS) 76588c2ecf20Sopenharmony_ci != DCMD_SUCCESS) { 76598c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 76608c2ecf20Sopenharmony_ci "return from %s %d\n", __func__, __LINE__); 76618c2ecf20Sopenharmony_ci return; 76628c2ecf20Sopenharmony_ci } 76638c2ecf20Sopenharmony_ci 76648c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 76658c2ecf20Sopenharmony_ci} 76668c2ecf20Sopenharmony_ci 76678c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 76688c2ecf20Sopenharmony_ci/** 76698c2ecf20Sopenharmony_ci * megasas_suspend - driver suspend entry point 76708c2ecf20Sopenharmony_ci * @pdev: PCI device structure 76718c2ecf20Sopenharmony_ci * @state: PCI power state to suspend routine 76728c2ecf20Sopenharmony_ci */ 76738c2ecf20Sopenharmony_cistatic int 76748c2ecf20Sopenharmony_cimegasas_suspend(struct pci_dev *pdev, pm_message_t state) 76758c2ecf20Sopenharmony_ci{ 76768c2ecf20Sopenharmony_ci struct megasas_instance *instance; 76778c2ecf20Sopenharmony_ci 76788c2ecf20Sopenharmony_ci instance = pci_get_drvdata(pdev); 76798c2ecf20Sopenharmony_ci 76808c2ecf20Sopenharmony_ci if (!instance) 76818c2ecf20Sopenharmony_ci return 0; 76828c2ecf20Sopenharmony_ci 76838c2ecf20Sopenharmony_ci instance->unload = 1; 76848c2ecf20Sopenharmony_ci 76858c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "%s is called\n", __func__); 76868c2ecf20Sopenharmony_ci 76878c2ecf20Sopenharmony_ci /* Shutdown SR-IOV heartbeat timer */ 76888c2ecf20Sopenharmony_ci if (instance->requestorId && !instance->skip_heartbeat_timer_del) 76898c2ecf20Sopenharmony_ci del_timer_sync(&instance->sriov_heartbeat_timer); 76908c2ecf20Sopenharmony_ci 76918c2ecf20Sopenharmony_ci /* Stop the FW fault detection watchdog */ 76928c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) 76938c2ecf20Sopenharmony_ci megasas_fusion_stop_watchdog(instance); 76948c2ecf20Sopenharmony_ci 76958c2ecf20Sopenharmony_ci megasas_flush_cache(instance); 76968c2ecf20Sopenharmony_ci megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN); 76978c2ecf20Sopenharmony_ci 76988c2ecf20Sopenharmony_ci /* cancel the delayed work if this work still in queue */ 76998c2ecf20Sopenharmony_ci if (instance->ev != NULL) { 77008c2ecf20Sopenharmony_ci struct megasas_aen_event *ev = instance->ev; 77018c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&ev->hotplug_work); 77028c2ecf20Sopenharmony_ci instance->ev = NULL; 77038c2ecf20Sopenharmony_ci } 77048c2ecf20Sopenharmony_ci 77058c2ecf20Sopenharmony_ci tasklet_kill(&instance->isr_tasklet); 77068c2ecf20Sopenharmony_ci 77078c2ecf20Sopenharmony_ci pci_set_drvdata(instance->pdev, instance); 77088c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 77098c2ecf20Sopenharmony_ci 77108c2ecf20Sopenharmony_ci megasas_destroy_irqs(instance); 77118c2ecf20Sopenharmony_ci 77128c2ecf20Sopenharmony_ci if (instance->msix_vectors) 77138c2ecf20Sopenharmony_ci pci_free_irq_vectors(instance->pdev); 77148c2ecf20Sopenharmony_ci 77158c2ecf20Sopenharmony_ci pci_save_state(pdev); 77168c2ecf20Sopenharmony_ci pci_disable_device(pdev); 77178c2ecf20Sopenharmony_ci 77188c2ecf20Sopenharmony_ci pci_set_power_state(pdev, pci_choose_state(pdev, state)); 77198c2ecf20Sopenharmony_ci 77208c2ecf20Sopenharmony_ci return 0; 77218c2ecf20Sopenharmony_ci} 77228c2ecf20Sopenharmony_ci 77238c2ecf20Sopenharmony_ci/** 77248c2ecf20Sopenharmony_ci * megasas_resume- driver resume entry point 77258c2ecf20Sopenharmony_ci * @pdev: PCI device structure 77268c2ecf20Sopenharmony_ci */ 77278c2ecf20Sopenharmony_cistatic int 77288c2ecf20Sopenharmony_cimegasas_resume(struct pci_dev *pdev) 77298c2ecf20Sopenharmony_ci{ 77308c2ecf20Sopenharmony_ci int rval; 77318c2ecf20Sopenharmony_ci struct Scsi_Host *host; 77328c2ecf20Sopenharmony_ci struct megasas_instance *instance; 77338c2ecf20Sopenharmony_ci u32 status_reg; 77348c2ecf20Sopenharmony_ci 77358c2ecf20Sopenharmony_ci instance = pci_get_drvdata(pdev); 77368c2ecf20Sopenharmony_ci 77378c2ecf20Sopenharmony_ci if (!instance) 77388c2ecf20Sopenharmony_ci return 0; 77398c2ecf20Sopenharmony_ci 77408c2ecf20Sopenharmony_ci host = instance->host; 77418c2ecf20Sopenharmony_ci pci_set_power_state(pdev, PCI_D0); 77428c2ecf20Sopenharmony_ci pci_enable_wake(pdev, PCI_D0, 0); 77438c2ecf20Sopenharmony_ci pci_restore_state(pdev); 77448c2ecf20Sopenharmony_ci 77458c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "%s is called\n", __func__); 77468c2ecf20Sopenharmony_ci /* 77478c2ecf20Sopenharmony_ci * PCI prepping: enable device set bus mastering and dma mask 77488c2ecf20Sopenharmony_ci */ 77498c2ecf20Sopenharmony_ci rval = pci_enable_device_mem(pdev); 77508c2ecf20Sopenharmony_ci 77518c2ecf20Sopenharmony_ci if (rval) { 77528c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Enable device failed\n"); 77538c2ecf20Sopenharmony_ci return rval; 77548c2ecf20Sopenharmony_ci } 77558c2ecf20Sopenharmony_ci 77568c2ecf20Sopenharmony_ci pci_set_master(pdev); 77578c2ecf20Sopenharmony_ci 77588c2ecf20Sopenharmony_ci /* 77598c2ecf20Sopenharmony_ci * We expect the FW state to be READY 77608c2ecf20Sopenharmony_ci */ 77618c2ecf20Sopenharmony_ci 77628c2ecf20Sopenharmony_ci if (megasas_transition_to_ready(instance, 0)) { 77638c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 77648c2ecf20Sopenharmony_ci "Failed to transition controller to ready from %s!\n", 77658c2ecf20Sopenharmony_ci __func__); 77668c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) { 77678c2ecf20Sopenharmony_ci status_reg = 77688c2ecf20Sopenharmony_ci instance->instancet->read_fw_status_reg(instance); 77698c2ecf20Sopenharmony_ci if (!(status_reg & MFI_RESET_ADAPTER) || 77708c2ecf20Sopenharmony_ci ((megasas_adp_reset_wait_for_ready 77718c2ecf20Sopenharmony_ci (instance, true, 0)) == FAILED)) 77728c2ecf20Sopenharmony_ci goto fail_ready_state; 77738c2ecf20Sopenharmony_ci } else { 77748c2ecf20Sopenharmony_ci atomic_set(&instance->fw_reset_no_pci_access, 1); 77758c2ecf20Sopenharmony_ci instance->instancet->adp_reset 77768c2ecf20Sopenharmony_ci (instance, instance->reg_set); 77778c2ecf20Sopenharmony_ci atomic_set(&instance->fw_reset_no_pci_access, 0); 77788c2ecf20Sopenharmony_ci 77798c2ecf20Sopenharmony_ci /* waiting for about 30 seconds before retry */ 77808c2ecf20Sopenharmony_ci ssleep(30); 77818c2ecf20Sopenharmony_ci 77828c2ecf20Sopenharmony_ci if (megasas_transition_to_ready(instance, 0)) 77838c2ecf20Sopenharmony_ci goto fail_ready_state; 77848c2ecf20Sopenharmony_ci } 77858c2ecf20Sopenharmony_ci 77868c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 77878c2ecf20Sopenharmony_ci "FW restarted successfully from %s!\n", 77888c2ecf20Sopenharmony_ci __func__); 77898c2ecf20Sopenharmony_ci } 77908c2ecf20Sopenharmony_ci if (megasas_set_dma_mask(instance)) 77918c2ecf20Sopenharmony_ci goto fail_set_dma_mask; 77928c2ecf20Sopenharmony_ci 77938c2ecf20Sopenharmony_ci /* 77948c2ecf20Sopenharmony_ci * Initialize MFI Firmware 77958c2ecf20Sopenharmony_ci */ 77968c2ecf20Sopenharmony_ci 77978c2ecf20Sopenharmony_ci atomic_set(&instance->fw_outstanding, 0); 77988c2ecf20Sopenharmony_ci atomic_set(&instance->ldio_outstanding, 0); 77998c2ecf20Sopenharmony_ci 78008c2ecf20Sopenharmony_ci /* Now re-enable MSI-X */ 78018c2ecf20Sopenharmony_ci if (instance->msix_vectors) 78028c2ecf20Sopenharmony_ci megasas_alloc_irq_vectors(instance); 78038c2ecf20Sopenharmony_ci 78048c2ecf20Sopenharmony_ci if (!instance->msix_vectors) { 78058c2ecf20Sopenharmony_ci rval = pci_alloc_irq_vectors(instance->pdev, 1, 1, 78068c2ecf20Sopenharmony_ci PCI_IRQ_LEGACY); 78078c2ecf20Sopenharmony_ci if (rval < 0) 78088c2ecf20Sopenharmony_ci goto fail_reenable_msix; 78098c2ecf20Sopenharmony_ci } 78108c2ecf20Sopenharmony_ci 78118c2ecf20Sopenharmony_ci megasas_setup_reply_map(instance); 78128c2ecf20Sopenharmony_ci 78138c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) { 78148c2ecf20Sopenharmony_ci megasas_reset_reply_desc(instance); 78158c2ecf20Sopenharmony_ci if (megasas_ioc_init_fusion(instance)) { 78168c2ecf20Sopenharmony_ci megasas_free_cmds(instance); 78178c2ecf20Sopenharmony_ci megasas_free_cmds_fusion(instance); 78188c2ecf20Sopenharmony_ci goto fail_init_mfi; 78198c2ecf20Sopenharmony_ci } 78208c2ecf20Sopenharmony_ci if (!megasas_get_map_info(instance)) 78218c2ecf20Sopenharmony_ci megasas_sync_map_info(instance); 78228c2ecf20Sopenharmony_ci } else { 78238c2ecf20Sopenharmony_ci *instance->producer = 0; 78248c2ecf20Sopenharmony_ci *instance->consumer = 0; 78258c2ecf20Sopenharmony_ci if (megasas_issue_init_mfi(instance)) 78268c2ecf20Sopenharmony_ci goto fail_init_mfi; 78278c2ecf20Sopenharmony_ci } 78288c2ecf20Sopenharmony_ci 78298c2ecf20Sopenharmony_ci if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS) 78308c2ecf20Sopenharmony_ci goto fail_init_mfi; 78318c2ecf20Sopenharmony_ci 78328c2ecf20Sopenharmony_ci tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, 78338c2ecf20Sopenharmony_ci (unsigned long)instance); 78348c2ecf20Sopenharmony_ci 78358c2ecf20Sopenharmony_ci if (instance->msix_vectors ? 78368c2ecf20Sopenharmony_ci megasas_setup_irqs_msix(instance, 0) : 78378c2ecf20Sopenharmony_ci megasas_setup_irqs_ioapic(instance)) 78388c2ecf20Sopenharmony_ci goto fail_init_mfi; 78398c2ecf20Sopenharmony_ci 78408c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) 78418c2ecf20Sopenharmony_ci megasas_setup_irq_poll(instance); 78428c2ecf20Sopenharmony_ci 78438c2ecf20Sopenharmony_ci /* Re-launch SR-IOV heartbeat timer */ 78448c2ecf20Sopenharmony_ci if (instance->requestorId) { 78458c2ecf20Sopenharmony_ci if (!megasas_sriov_start_heartbeat(instance, 0)) 78468c2ecf20Sopenharmony_ci megasas_start_timer(instance); 78478c2ecf20Sopenharmony_ci else { 78488c2ecf20Sopenharmony_ci instance->skip_heartbeat_timer_del = 1; 78498c2ecf20Sopenharmony_ci goto fail_init_mfi; 78508c2ecf20Sopenharmony_ci } 78518c2ecf20Sopenharmony_ci } 78528c2ecf20Sopenharmony_ci 78538c2ecf20Sopenharmony_ci instance->instancet->enable_intr(instance); 78548c2ecf20Sopenharmony_ci megasas_setup_jbod_map(instance); 78558c2ecf20Sopenharmony_ci instance->unload = 0; 78568c2ecf20Sopenharmony_ci 78578c2ecf20Sopenharmony_ci /* 78588c2ecf20Sopenharmony_ci * Initiate AEN (Asynchronous Event Notification) 78598c2ecf20Sopenharmony_ci */ 78608c2ecf20Sopenharmony_ci if (megasas_start_aen(instance)) 78618c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Start AEN failed\n"); 78628c2ecf20Sopenharmony_ci 78638c2ecf20Sopenharmony_ci /* Re-launch FW fault watchdog */ 78648c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) 78658c2ecf20Sopenharmony_ci if (megasas_fusion_start_watchdog(instance) != SUCCESS) 78668c2ecf20Sopenharmony_ci goto fail_start_watchdog; 78678c2ecf20Sopenharmony_ci 78688c2ecf20Sopenharmony_ci return 0; 78698c2ecf20Sopenharmony_ci 78708c2ecf20Sopenharmony_cifail_start_watchdog: 78718c2ecf20Sopenharmony_ci if (instance->requestorId && !instance->skip_heartbeat_timer_del) 78728c2ecf20Sopenharmony_ci del_timer_sync(&instance->sriov_heartbeat_timer); 78738c2ecf20Sopenharmony_cifail_init_mfi: 78748c2ecf20Sopenharmony_ci megasas_free_ctrl_dma_buffers(instance); 78758c2ecf20Sopenharmony_ci megasas_free_ctrl_mem(instance); 78768c2ecf20Sopenharmony_ci scsi_host_put(host); 78778c2ecf20Sopenharmony_ci 78788c2ecf20Sopenharmony_cifail_reenable_msix: 78798c2ecf20Sopenharmony_cifail_set_dma_mask: 78808c2ecf20Sopenharmony_cifail_ready_state: 78818c2ecf20Sopenharmony_ci 78828c2ecf20Sopenharmony_ci pci_disable_device(pdev); 78838c2ecf20Sopenharmony_ci 78848c2ecf20Sopenharmony_ci return -ENODEV; 78858c2ecf20Sopenharmony_ci} 78868c2ecf20Sopenharmony_ci#else 78878c2ecf20Sopenharmony_ci#define megasas_suspend NULL 78888c2ecf20Sopenharmony_ci#define megasas_resume NULL 78898c2ecf20Sopenharmony_ci#endif 78908c2ecf20Sopenharmony_ci 78918c2ecf20Sopenharmony_cistatic inline int 78928c2ecf20Sopenharmony_cimegasas_wait_for_adapter_operational(struct megasas_instance *instance) 78938c2ecf20Sopenharmony_ci{ 78948c2ecf20Sopenharmony_ci int wait_time = MEGASAS_RESET_WAIT_TIME * 2; 78958c2ecf20Sopenharmony_ci int i; 78968c2ecf20Sopenharmony_ci u8 adp_state; 78978c2ecf20Sopenharmony_ci 78988c2ecf20Sopenharmony_ci for (i = 0; i < wait_time; i++) { 78998c2ecf20Sopenharmony_ci adp_state = atomic_read(&instance->adprecovery); 79008c2ecf20Sopenharmony_ci if ((adp_state == MEGASAS_HBA_OPERATIONAL) || 79018c2ecf20Sopenharmony_ci (adp_state == MEGASAS_HW_CRITICAL_ERROR)) 79028c2ecf20Sopenharmony_ci break; 79038c2ecf20Sopenharmony_ci 79048c2ecf20Sopenharmony_ci if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) 79058c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "waiting for controller reset to finish\n"); 79068c2ecf20Sopenharmony_ci 79078c2ecf20Sopenharmony_ci msleep(1000); 79088c2ecf20Sopenharmony_ci } 79098c2ecf20Sopenharmony_ci 79108c2ecf20Sopenharmony_ci if (adp_state != MEGASAS_HBA_OPERATIONAL) { 79118c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 79128c2ecf20Sopenharmony_ci "%s HBA failed to become operational, adp_state %d\n", 79138c2ecf20Sopenharmony_ci __func__, adp_state); 79148c2ecf20Sopenharmony_ci return 1; 79158c2ecf20Sopenharmony_ci } 79168c2ecf20Sopenharmony_ci 79178c2ecf20Sopenharmony_ci return 0; 79188c2ecf20Sopenharmony_ci} 79198c2ecf20Sopenharmony_ci 79208c2ecf20Sopenharmony_ci/** 79218c2ecf20Sopenharmony_ci * megasas_detach_one - PCI hot"un"plug entry point 79228c2ecf20Sopenharmony_ci * @pdev: PCI device structure 79238c2ecf20Sopenharmony_ci */ 79248c2ecf20Sopenharmony_cistatic void megasas_detach_one(struct pci_dev *pdev) 79258c2ecf20Sopenharmony_ci{ 79268c2ecf20Sopenharmony_ci int i; 79278c2ecf20Sopenharmony_ci struct Scsi_Host *host; 79288c2ecf20Sopenharmony_ci struct megasas_instance *instance; 79298c2ecf20Sopenharmony_ci struct fusion_context *fusion; 79308c2ecf20Sopenharmony_ci u32 pd_seq_map_sz; 79318c2ecf20Sopenharmony_ci 79328c2ecf20Sopenharmony_ci instance = pci_get_drvdata(pdev); 79338c2ecf20Sopenharmony_ci 79348c2ecf20Sopenharmony_ci if (!instance) 79358c2ecf20Sopenharmony_ci return; 79368c2ecf20Sopenharmony_ci 79378c2ecf20Sopenharmony_ci host = instance->host; 79388c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 79398c2ecf20Sopenharmony_ci 79408c2ecf20Sopenharmony_ci /* Shutdown SR-IOV heartbeat timer */ 79418c2ecf20Sopenharmony_ci if (instance->requestorId && !instance->skip_heartbeat_timer_del) 79428c2ecf20Sopenharmony_ci del_timer_sync(&instance->sriov_heartbeat_timer); 79438c2ecf20Sopenharmony_ci 79448c2ecf20Sopenharmony_ci /* Stop the FW fault detection watchdog */ 79458c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) 79468c2ecf20Sopenharmony_ci megasas_fusion_stop_watchdog(instance); 79478c2ecf20Sopenharmony_ci 79488c2ecf20Sopenharmony_ci if (instance->fw_crash_state != UNAVAILABLE) 79498c2ecf20Sopenharmony_ci megasas_free_host_crash_buffer(instance); 79508c2ecf20Sopenharmony_ci scsi_remove_host(instance->host); 79518c2ecf20Sopenharmony_ci instance->unload = 1; 79528c2ecf20Sopenharmony_ci 79538c2ecf20Sopenharmony_ci if (megasas_wait_for_adapter_operational(instance)) 79548c2ecf20Sopenharmony_ci goto skip_firing_dcmds; 79558c2ecf20Sopenharmony_ci 79568c2ecf20Sopenharmony_ci megasas_flush_cache(instance); 79578c2ecf20Sopenharmony_ci megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); 79588c2ecf20Sopenharmony_ci 79598c2ecf20Sopenharmony_ciskip_firing_dcmds: 79608c2ecf20Sopenharmony_ci /* cancel the delayed work if this work still in queue*/ 79618c2ecf20Sopenharmony_ci if (instance->ev != NULL) { 79628c2ecf20Sopenharmony_ci struct megasas_aen_event *ev = instance->ev; 79638c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&ev->hotplug_work); 79648c2ecf20Sopenharmony_ci instance->ev = NULL; 79658c2ecf20Sopenharmony_ci } 79668c2ecf20Sopenharmony_ci 79678c2ecf20Sopenharmony_ci /* cancel all wait events */ 79688c2ecf20Sopenharmony_ci wake_up_all(&instance->int_cmd_wait_q); 79698c2ecf20Sopenharmony_ci 79708c2ecf20Sopenharmony_ci tasklet_kill(&instance->isr_tasklet); 79718c2ecf20Sopenharmony_ci 79728c2ecf20Sopenharmony_ci /* 79738c2ecf20Sopenharmony_ci * Take the instance off the instance array. Note that we will not 79748c2ecf20Sopenharmony_ci * decrement the max_index. We let this array be sparse array 79758c2ecf20Sopenharmony_ci */ 79768c2ecf20Sopenharmony_ci for (i = 0; i < megasas_mgmt_info.max_index; i++) { 79778c2ecf20Sopenharmony_ci if (megasas_mgmt_info.instance[i] == instance) { 79788c2ecf20Sopenharmony_ci megasas_mgmt_info.count--; 79798c2ecf20Sopenharmony_ci megasas_mgmt_info.instance[i] = NULL; 79808c2ecf20Sopenharmony_ci 79818c2ecf20Sopenharmony_ci break; 79828c2ecf20Sopenharmony_ci } 79838c2ecf20Sopenharmony_ci } 79848c2ecf20Sopenharmony_ci 79858c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 79868c2ecf20Sopenharmony_ci 79878c2ecf20Sopenharmony_ci megasas_destroy_irqs(instance); 79888c2ecf20Sopenharmony_ci 79898c2ecf20Sopenharmony_ci if (instance->msix_vectors) 79908c2ecf20Sopenharmony_ci pci_free_irq_vectors(instance->pdev); 79918c2ecf20Sopenharmony_ci 79928c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) { 79938c2ecf20Sopenharmony_ci for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i) 79948c2ecf20Sopenharmony_ci kfree(fusion->stream_detect_by_ld[i]); 79958c2ecf20Sopenharmony_ci kfree(fusion->stream_detect_by_ld); 79968c2ecf20Sopenharmony_ci fusion->stream_detect_by_ld = NULL; 79978c2ecf20Sopenharmony_ci } 79988c2ecf20Sopenharmony_ci 79998c2ecf20Sopenharmony_ci 80008c2ecf20Sopenharmony_ci if (instance->adapter_type != MFI_SERIES) { 80018c2ecf20Sopenharmony_ci megasas_release_fusion(instance); 80028c2ecf20Sopenharmony_ci pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + 80038c2ecf20Sopenharmony_ci (sizeof(struct MR_PD_CFG_SEQ) * 80048c2ecf20Sopenharmony_ci (MAX_PHYSICAL_DEVICES - 1)); 80058c2ecf20Sopenharmony_ci for (i = 0; i < 2 ; i++) { 80068c2ecf20Sopenharmony_ci if (fusion->ld_map[i]) 80078c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, 80088c2ecf20Sopenharmony_ci fusion->max_map_sz, 80098c2ecf20Sopenharmony_ci fusion->ld_map[i], 80108c2ecf20Sopenharmony_ci fusion->ld_map_phys[i]); 80118c2ecf20Sopenharmony_ci if (fusion->ld_drv_map[i]) { 80128c2ecf20Sopenharmony_ci if (is_vmalloc_addr(fusion->ld_drv_map[i])) 80138c2ecf20Sopenharmony_ci vfree(fusion->ld_drv_map[i]); 80148c2ecf20Sopenharmony_ci else 80158c2ecf20Sopenharmony_ci free_pages((ulong)fusion->ld_drv_map[i], 80168c2ecf20Sopenharmony_ci fusion->drv_map_pages); 80178c2ecf20Sopenharmony_ci } 80188c2ecf20Sopenharmony_ci 80198c2ecf20Sopenharmony_ci if (fusion->pd_seq_sync[i]) 80208c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, 80218c2ecf20Sopenharmony_ci pd_seq_map_sz, 80228c2ecf20Sopenharmony_ci fusion->pd_seq_sync[i], 80238c2ecf20Sopenharmony_ci fusion->pd_seq_phys[i]); 80248c2ecf20Sopenharmony_ci } 80258c2ecf20Sopenharmony_ci } else { 80268c2ecf20Sopenharmony_ci megasas_release_mfi(instance); 80278c2ecf20Sopenharmony_ci } 80288c2ecf20Sopenharmony_ci 80298c2ecf20Sopenharmony_ci if (instance->vf_affiliation) 80308c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, (MAX_LOGICAL_DRIVES + 1) * 80318c2ecf20Sopenharmony_ci sizeof(struct MR_LD_VF_AFFILIATION), 80328c2ecf20Sopenharmony_ci instance->vf_affiliation, 80338c2ecf20Sopenharmony_ci instance->vf_affiliation_h); 80348c2ecf20Sopenharmony_ci 80358c2ecf20Sopenharmony_ci if (instance->vf_affiliation_111) 80368c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 80378c2ecf20Sopenharmony_ci sizeof(struct MR_LD_VF_AFFILIATION_111), 80388c2ecf20Sopenharmony_ci instance->vf_affiliation_111, 80398c2ecf20Sopenharmony_ci instance->vf_affiliation_111_h); 80408c2ecf20Sopenharmony_ci 80418c2ecf20Sopenharmony_ci if (instance->hb_host_mem) 80428c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(struct MR_CTRL_HB_HOST_MEM), 80438c2ecf20Sopenharmony_ci instance->hb_host_mem, 80448c2ecf20Sopenharmony_ci instance->hb_host_mem_h); 80458c2ecf20Sopenharmony_ci 80468c2ecf20Sopenharmony_ci megasas_free_ctrl_dma_buffers(instance); 80478c2ecf20Sopenharmony_ci 80488c2ecf20Sopenharmony_ci megasas_free_ctrl_mem(instance); 80498c2ecf20Sopenharmony_ci 80508c2ecf20Sopenharmony_ci megasas_destroy_debugfs(instance); 80518c2ecf20Sopenharmony_ci 80528c2ecf20Sopenharmony_ci scsi_host_put(host); 80538c2ecf20Sopenharmony_ci 80548c2ecf20Sopenharmony_ci pci_disable_device(pdev); 80558c2ecf20Sopenharmony_ci} 80568c2ecf20Sopenharmony_ci 80578c2ecf20Sopenharmony_ci/** 80588c2ecf20Sopenharmony_ci * megasas_shutdown - Shutdown entry point 80598c2ecf20Sopenharmony_ci * @pdev: Generic device structure 80608c2ecf20Sopenharmony_ci */ 80618c2ecf20Sopenharmony_cistatic void megasas_shutdown(struct pci_dev *pdev) 80628c2ecf20Sopenharmony_ci{ 80638c2ecf20Sopenharmony_ci struct megasas_instance *instance = pci_get_drvdata(pdev); 80648c2ecf20Sopenharmony_ci 80658c2ecf20Sopenharmony_ci if (!instance) 80668c2ecf20Sopenharmony_ci return; 80678c2ecf20Sopenharmony_ci 80688c2ecf20Sopenharmony_ci instance->unload = 1; 80698c2ecf20Sopenharmony_ci 80708c2ecf20Sopenharmony_ci if (megasas_wait_for_adapter_operational(instance)) 80718c2ecf20Sopenharmony_ci goto skip_firing_dcmds; 80728c2ecf20Sopenharmony_ci 80738c2ecf20Sopenharmony_ci megasas_flush_cache(instance); 80748c2ecf20Sopenharmony_ci megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); 80758c2ecf20Sopenharmony_ci 80768c2ecf20Sopenharmony_ciskip_firing_dcmds: 80778c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 80788c2ecf20Sopenharmony_ci megasas_destroy_irqs(instance); 80798c2ecf20Sopenharmony_ci 80808c2ecf20Sopenharmony_ci if (instance->msix_vectors) 80818c2ecf20Sopenharmony_ci pci_free_irq_vectors(instance->pdev); 80828c2ecf20Sopenharmony_ci} 80838c2ecf20Sopenharmony_ci 80848c2ecf20Sopenharmony_ci/* 80858c2ecf20Sopenharmony_ci * megasas_mgmt_open - char node "open" entry point 80868c2ecf20Sopenharmony_ci * @inode: char node inode 80878c2ecf20Sopenharmony_ci * @filep: char node file 80888c2ecf20Sopenharmony_ci */ 80898c2ecf20Sopenharmony_cistatic int megasas_mgmt_open(struct inode *inode, struct file *filep) 80908c2ecf20Sopenharmony_ci{ 80918c2ecf20Sopenharmony_ci /* 80928c2ecf20Sopenharmony_ci * Allow only those users with admin rights 80938c2ecf20Sopenharmony_ci */ 80948c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 80958c2ecf20Sopenharmony_ci return -EACCES; 80968c2ecf20Sopenharmony_ci 80978c2ecf20Sopenharmony_ci return 0; 80988c2ecf20Sopenharmony_ci} 80998c2ecf20Sopenharmony_ci 81008c2ecf20Sopenharmony_ci/* 81018c2ecf20Sopenharmony_ci * megasas_mgmt_fasync - Async notifier registration from applications 81028c2ecf20Sopenharmony_ci * @fd: char node file descriptor number 81038c2ecf20Sopenharmony_ci * @filep: char node file 81048c2ecf20Sopenharmony_ci * @mode: notifier on/off 81058c2ecf20Sopenharmony_ci * 81068c2ecf20Sopenharmony_ci * This function adds the calling process to a driver global queue. When an 81078c2ecf20Sopenharmony_ci * event occurs, SIGIO will be sent to all processes in this queue. 81088c2ecf20Sopenharmony_ci */ 81098c2ecf20Sopenharmony_cistatic int megasas_mgmt_fasync(int fd, struct file *filep, int mode) 81108c2ecf20Sopenharmony_ci{ 81118c2ecf20Sopenharmony_ci int rc; 81128c2ecf20Sopenharmony_ci 81138c2ecf20Sopenharmony_ci mutex_lock(&megasas_async_queue_mutex); 81148c2ecf20Sopenharmony_ci 81158c2ecf20Sopenharmony_ci rc = fasync_helper(fd, filep, mode, &megasas_async_queue); 81168c2ecf20Sopenharmony_ci 81178c2ecf20Sopenharmony_ci mutex_unlock(&megasas_async_queue_mutex); 81188c2ecf20Sopenharmony_ci 81198c2ecf20Sopenharmony_ci if (rc >= 0) { 81208c2ecf20Sopenharmony_ci /* For sanity check when we get ioctl */ 81218c2ecf20Sopenharmony_ci filep->private_data = filep; 81228c2ecf20Sopenharmony_ci return 0; 81238c2ecf20Sopenharmony_ci } 81248c2ecf20Sopenharmony_ci 81258c2ecf20Sopenharmony_ci printk(KERN_DEBUG "megasas: fasync_helper failed [%d]\n", rc); 81268c2ecf20Sopenharmony_ci 81278c2ecf20Sopenharmony_ci return rc; 81288c2ecf20Sopenharmony_ci} 81298c2ecf20Sopenharmony_ci 81308c2ecf20Sopenharmony_ci/* 81318c2ecf20Sopenharmony_ci * megasas_mgmt_poll - char node "poll" entry point 81328c2ecf20Sopenharmony_ci * @filep: char node file 81338c2ecf20Sopenharmony_ci * @wait: Events to poll for 81348c2ecf20Sopenharmony_ci */ 81358c2ecf20Sopenharmony_cistatic __poll_t megasas_mgmt_poll(struct file *file, poll_table *wait) 81368c2ecf20Sopenharmony_ci{ 81378c2ecf20Sopenharmony_ci __poll_t mask; 81388c2ecf20Sopenharmony_ci unsigned long flags; 81398c2ecf20Sopenharmony_ci 81408c2ecf20Sopenharmony_ci poll_wait(file, &megasas_poll_wait, wait); 81418c2ecf20Sopenharmony_ci spin_lock_irqsave(&poll_aen_lock, flags); 81428c2ecf20Sopenharmony_ci if (megasas_poll_wait_aen) 81438c2ecf20Sopenharmony_ci mask = (EPOLLIN | EPOLLRDNORM); 81448c2ecf20Sopenharmony_ci else 81458c2ecf20Sopenharmony_ci mask = 0; 81468c2ecf20Sopenharmony_ci megasas_poll_wait_aen = 0; 81478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&poll_aen_lock, flags); 81488c2ecf20Sopenharmony_ci return mask; 81498c2ecf20Sopenharmony_ci} 81508c2ecf20Sopenharmony_ci 81518c2ecf20Sopenharmony_ci/* 81528c2ecf20Sopenharmony_ci * megasas_set_crash_dump_params_ioctl: 81538c2ecf20Sopenharmony_ci * Send CRASH_DUMP_MODE DCMD to all controllers 81548c2ecf20Sopenharmony_ci * @cmd: MFI command frame 81558c2ecf20Sopenharmony_ci */ 81568c2ecf20Sopenharmony_ci 81578c2ecf20Sopenharmony_cistatic int megasas_set_crash_dump_params_ioctl(struct megasas_cmd *cmd) 81588c2ecf20Sopenharmony_ci{ 81598c2ecf20Sopenharmony_ci struct megasas_instance *local_instance; 81608c2ecf20Sopenharmony_ci int i, error = 0; 81618c2ecf20Sopenharmony_ci int crash_support; 81628c2ecf20Sopenharmony_ci 81638c2ecf20Sopenharmony_ci crash_support = cmd->frame->dcmd.mbox.w[0]; 81648c2ecf20Sopenharmony_ci 81658c2ecf20Sopenharmony_ci for (i = 0; i < megasas_mgmt_info.max_index; i++) { 81668c2ecf20Sopenharmony_ci local_instance = megasas_mgmt_info.instance[i]; 81678c2ecf20Sopenharmony_ci if (local_instance && local_instance->crash_dump_drv_support) { 81688c2ecf20Sopenharmony_ci if ((atomic_read(&local_instance->adprecovery) == 81698c2ecf20Sopenharmony_ci MEGASAS_HBA_OPERATIONAL) && 81708c2ecf20Sopenharmony_ci !megasas_set_crash_dump_params(local_instance, 81718c2ecf20Sopenharmony_ci crash_support)) { 81728c2ecf20Sopenharmony_ci local_instance->crash_dump_app_support = 81738c2ecf20Sopenharmony_ci crash_support; 81748c2ecf20Sopenharmony_ci dev_info(&local_instance->pdev->dev, 81758c2ecf20Sopenharmony_ci "Application firmware crash " 81768c2ecf20Sopenharmony_ci "dump mode set success\n"); 81778c2ecf20Sopenharmony_ci error = 0; 81788c2ecf20Sopenharmony_ci } else { 81798c2ecf20Sopenharmony_ci dev_info(&local_instance->pdev->dev, 81808c2ecf20Sopenharmony_ci "Application firmware crash " 81818c2ecf20Sopenharmony_ci "dump mode set failed\n"); 81828c2ecf20Sopenharmony_ci error = -1; 81838c2ecf20Sopenharmony_ci } 81848c2ecf20Sopenharmony_ci } 81858c2ecf20Sopenharmony_ci } 81868c2ecf20Sopenharmony_ci return error; 81878c2ecf20Sopenharmony_ci} 81888c2ecf20Sopenharmony_ci 81898c2ecf20Sopenharmony_ci/** 81908c2ecf20Sopenharmony_ci * megasas_mgmt_fw_ioctl - Issues management ioctls to FW 81918c2ecf20Sopenharmony_ci * @instance: Adapter soft state 81928c2ecf20Sopenharmony_ci * @user_ioc: User's ioctl packet 81938c2ecf20Sopenharmony_ci * @ioc: ioctl packet 81948c2ecf20Sopenharmony_ci */ 81958c2ecf20Sopenharmony_cistatic int 81968c2ecf20Sopenharmony_cimegasas_mgmt_fw_ioctl(struct megasas_instance *instance, 81978c2ecf20Sopenharmony_ci struct megasas_iocpacket __user * user_ioc, 81988c2ecf20Sopenharmony_ci struct megasas_iocpacket *ioc) 81998c2ecf20Sopenharmony_ci{ 82008c2ecf20Sopenharmony_ci struct megasas_sge64 *kern_sge64 = NULL; 82018c2ecf20Sopenharmony_ci struct megasas_sge32 *kern_sge32 = NULL; 82028c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 82038c2ecf20Sopenharmony_ci void *kbuff_arr[MAX_IOCTL_SGE]; 82048c2ecf20Sopenharmony_ci dma_addr_t buf_handle = 0; 82058c2ecf20Sopenharmony_ci int error = 0, i; 82068c2ecf20Sopenharmony_ci void *sense = NULL; 82078c2ecf20Sopenharmony_ci dma_addr_t sense_handle; 82088c2ecf20Sopenharmony_ci void *sense_ptr; 82098c2ecf20Sopenharmony_ci u32 opcode = 0; 82108c2ecf20Sopenharmony_ci int ret = DCMD_SUCCESS; 82118c2ecf20Sopenharmony_ci 82128c2ecf20Sopenharmony_ci memset(kbuff_arr, 0, sizeof(kbuff_arr)); 82138c2ecf20Sopenharmony_ci 82148c2ecf20Sopenharmony_ci if (ioc->sge_count > MAX_IOCTL_SGE) { 82158c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "SGE count [%d] > max limit [%d]\n", 82168c2ecf20Sopenharmony_ci ioc->sge_count, MAX_IOCTL_SGE); 82178c2ecf20Sopenharmony_ci return -EINVAL; 82188c2ecf20Sopenharmony_ci } 82198c2ecf20Sopenharmony_ci 82208c2ecf20Sopenharmony_ci if ((ioc->frame.hdr.cmd >= MFI_CMD_OP_COUNT) || 82218c2ecf20Sopenharmony_ci ((ioc->frame.hdr.cmd == MFI_CMD_NVME) && 82228c2ecf20Sopenharmony_ci !instance->support_nvme_passthru) || 82238c2ecf20Sopenharmony_ci ((ioc->frame.hdr.cmd == MFI_CMD_TOOLBOX) && 82248c2ecf20Sopenharmony_ci !instance->support_pci_lane_margining)) { 82258c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 82268c2ecf20Sopenharmony_ci "Received invalid ioctl command 0x%x\n", 82278c2ecf20Sopenharmony_ci ioc->frame.hdr.cmd); 82288c2ecf20Sopenharmony_ci return -ENOTSUPP; 82298c2ecf20Sopenharmony_ci } 82308c2ecf20Sopenharmony_ci 82318c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 82328c2ecf20Sopenharmony_ci if (!cmd) { 82338c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get a cmd packet\n"); 82348c2ecf20Sopenharmony_ci return -ENOMEM; 82358c2ecf20Sopenharmony_ci } 82368c2ecf20Sopenharmony_ci 82378c2ecf20Sopenharmony_ci /* 82388c2ecf20Sopenharmony_ci * User's IOCTL packet has 2 frames (maximum). Copy those two 82398c2ecf20Sopenharmony_ci * frames into our cmd's frames. cmd->frame's context will get 82408c2ecf20Sopenharmony_ci * overwritten when we copy from user's frames. So set that value 82418c2ecf20Sopenharmony_ci * alone separately 82428c2ecf20Sopenharmony_ci */ 82438c2ecf20Sopenharmony_ci memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE); 82448c2ecf20Sopenharmony_ci cmd->frame->hdr.context = cpu_to_le32(cmd->index); 82458c2ecf20Sopenharmony_ci cmd->frame->hdr.pad_0 = 0; 82468c2ecf20Sopenharmony_ci 82478c2ecf20Sopenharmony_ci cmd->frame->hdr.flags &= (~MFI_FRAME_IEEE); 82488c2ecf20Sopenharmony_ci 82498c2ecf20Sopenharmony_ci if (instance->consistent_mask_64bit) 82508c2ecf20Sopenharmony_ci cmd->frame->hdr.flags |= cpu_to_le16((MFI_FRAME_SGL64 | 82518c2ecf20Sopenharmony_ci MFI_FRAME_SENSE64)); 82528c2ecf20Sopenharmony_ci else 82538c2ecf20Sopenharmony_ci cmd->frame->hdr.flags &= cpu_to_le16(~(MFI_FRAME_SGL64 | 82548c2ecf20Sopenharmony_ci MFI_FRAME_SENSE64)); 82558c2ecf20Sopenharmony_ci 82568c2ecf20Sopenharmony_ci if (cmd->frame->hdr.cmd == MFI_CMD_DCMD) 82578c2ecf20Sopenharmony_ci opcode = le32_to_cpu(cmd->frame->dcmd.opcode); 82588c2ecf20Sopenharmony_ci 82598c2ecf20Sopenharmony_ci if (opcode == MR_DCMD_CTRL_SHUTDOWN) { 82608c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 82618c2ecf20Sopenharmony_ci if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS) { 82628c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 82638c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 82648c2ecf20Sopenharmony_ci return -1; 82658c2ecf20Sopenharmony_ci } 82668c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 82678c2ecf20Sopenharmony_ci } 82688c2ecf20Sopenharmony_ci 82698c2ecf20Sopenharmony_ci if (opcode == MR_DRIVER_SET_APP_CRASHDUMP_MODE) { 82708c2ecf20Sopenharmony_ci error = megasas_set_crash_dump_params_ioctl(cmd); 82718c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 82728c2ecf20Sopenharmony_ci return error; 82738c2ecf20Sopenharmony_ci } 82748c2ecf20Sopenharmony_ci 82758c2ecf20Sopenharmony_ci /* 82768c2ecf20Sopenharmony_ci * The management interface between applications and the fw uses 82778c2ecf20Sopenharmony_ci * MFI frames. E.g, RAID configuration changes, LD property changes 82788c2ecf20Sopenharmony_ci * etc are accomplishes through different kinds of MFI frames. The 82798c2ecf20Sopenharmony_ci * driver needs to care only about substituting user buffers with 82808c2ecf20Sopenharmony_ci * kernel buffers in SGLs. The location of SGL is embedded in the 82818c2ecf20Sopenharmony_ci * struct iocpacket itself. 82828c2ecf20Sopenharmony_ci */ 82838c2ecf20Sopenharmony_ci if (instance->consistent_mask_64bit) 82848c2ecf20Sopenharmony_ci kern_sge64 = (struct megasas_sge64 *) 82858c2ecf20Sopenharmony_ci ((unsigned long)cmd->frame + ioc->sgl_off); 82868c2ecf20Sopenharmony_ci else 82878c2ecf20Sopenharmony_ci kern_sge32 = (struct megasas_sge32 *) 82888c2ecf20Sopenharmony_ci ((unsigned long)cmd->frame + ioc->sgl_off); 82898c2ecf20Sopenharmony_ci 82908c2ecf20Sopenharmony_ci /* 82918c2ecf20Sopenharmony_ci * For each user buffer, create a mirror buffer and copy in 82928c2ecf20Sopenharmony_ci */ 82938c2ecf20Sopenharmony_ci for (i = 0; i < ioc->sge_count; i++) { 82948c2ecf20Sopenharmony_ci if (!ioc->sgl[i].iov_len) 82958c2ecf20Sopenharmony_ci continue; 82968c2ecf20Sopenharmony_ci 82978c2ecf20Sopenharmony_ci kbuff_arr[i] = dma_alloc_coherent(&instance->pdev->dev, 82988c2ecf20Sopenharmony_ci ioc->sgl[i].iov_len, 82998c2ecf20Sopenharmony_ci &buf_handle, GFP_KERNEL); 83008c2ecf20Sopenharmony_ci if (!kbuff_arr[i]) { 83018c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to alloc " 83028c2ecf20Sopenharmony_ci "kernel SGL buffer for IOCTL\n"); 83038c2ecf20Sopenharmony_ci error = -ENOMEM; 83048c2ecf20Sopenharmony_ci goto out; 83058c2ecf20Sopenharmony_ci } 83068c2ecf20Sopenharmony_ci 83078c2ecf20Sopenharmony_ci /* 83088c2ecf20Sopenharmony_ci * We don't change the dma_coherent_mask, so 83098c2ecf20Sopenharmony_ci * dma_alloc_coherent only returns 32bit addresses 83108c2ecf20Sopenharmony_ci */ 83118c2ecf20Sopenharmony_ci if (instance->consistent_mask_64bit) { 83128c2ecf20Sopenharmony_ci kern_sge64[i].phys_addr = cpu_to_le64(buf_handle); 83138c2ecf20Sopenharmony_ci kern_sge64[i].length = cpu_to_le32(ioc->sgl[i].iov_len); 83148c2ecf20Sopenharmony_ci } else { 83158c2ecf20Sopenharmony_ci kern_sge32[i].phys_addr = cpu_to_le32(buf_handle); 83168c2ecf20Sopenharmony_ci kern_sge32[i].length = cpu_to_le32(ioc->sgl[i].iov_len); 83178c2ecf20Sopenharmony_ci } 83188c2ecf20Sopenharmony_ci 83198c2ecf20Sopenharmony_ci /* 83208c2ecf20Sopenharmony_ci * We created a kernel buffer corresponding to the 83218c2ecf20Sopenharmony_ci * user buffer. Now copy in from the user buffer 83228c2ecf20Sopenharmony_ci */ 83238c2ecf20Sopenharmony_ci if (copy_from_user(kbuff_arr[i], ioc->sgl[i].iov_base, 83248c2ecf20Sopenharmony_ci (u32) (ioc->sgl[i].iov_len))) { 83258c2ecf20Sopenharmony_ci error = -EFAULT; 83268c2ecf20Sopenharmony_ci goto out; 83278c2ecf20Sopenharmony_ci } 83288c2ecf20Sopenharmony_ci } 83298c2ecf20Sopenharmony_ci 83308c2ecf20Sopenharmony_ci if (ioc->sense_len) { 83318c2ecf20Sopenharmony_ci /* make sure the pointer is part of the frame */ 83328c2ecf20Sopenharmony_ci if (ioc->sense_off > 83338c2ecf20Sopenharmony_ci (sizeof(union megasas_frame) - sizeof(__le64))) { 83348c2ecf20Sopenharmony_ci error = -EINVAL; 83358c2ecf20Sopenharmony_ci goto out; 83368c2ecf20Sopenharmony_ci } 83378c2ecf20Sopenharmony_ci 83388c2ecf20Sopenharmony_ci sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len, 83398c2ecf20Sopenharmony_ci &sense_handle, GFP_KERNEL); 83408c2ecf20Sopenharmony_ci if (!sense) { 83418c2ecf20Sopenharmony_ci error = -ENOMEM; 83428c2ecf20Sopenharmony_ci goto out; 83438c2ecf20Sopenharmony_ci } 83448c2ecf20Sopenharmony_ci 83458c2ecf20Sopenharmony_ci /* always store 64 bits regardless of addressing */ 83468c2ecf20Sopenharmony_ci sense_ptr = (void *)cmd->frame + ioc->sense_off; 83478c2ecf20Sopenharmony_ci put_unaligned_le64(sense_handle, sense_ptr); 83488c2ecf20Sopenharmony_ci } 83498c2ecf20Sopenharmony_ci 83508c2ecf20Sopenharmony_ci /* 83518c2ecf20Sopenharmony_ci * Set the sync_cmd flag so that the ISR knows not to complete this 83528c2ecf20Sopenharmony_ci * cmd to the SCSI mid-layer 83538c2ecf20Sopenharmony_ci */ 83548c2ecf20Sopenharmony_ci cmd->sync_cmd = 1; 83558c2ecf20Sopenharmony_ci 83568c2ecf20Sopenharmony_ci ret = megasas_issue_blocked_cmd(instance, cmd, 0); 83578c2ecf20Sopenharmony_ci switch (ret) { 83588c2ecf20Sopenharmony_ci case DCMD_INIT: 83598c2ecf20Sopenharmony_ci case DCMD_BUSY: 83608c2ecf20Sopenharmony_ci cmd->sync_cmd = 0; 83618c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 83628c2ecf20Sopenharmony_ci "return -EBUSY from %s %d cmd 0x%x opcode 0x%x cmd->cmd_status_drv 0x%x\n", 83638c2ecf20Sopenharmony_ci __func__, __LINE__, cmd->frame->hdr.cmd, opcode, 83648c2ecf20Sopenharmony_ci cmd->cmd_status_drv); 83658c2ecf20Sopenharmony_ci error = -EBUSY; 83668c2ecf20Sopenharmony_ci goto out; 83678c2ecf20Sopenharmony_ci } 83688c2ecf20Sopenharmony_ci 83698c2ecf20Sopenharmony_ci cmd->sync_cmd = 0; 83708c2ecf20Sopenharmony_ci 83718c2ecf20Sopenharmony_ci if (instance->unload == 1) { 83728c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Driver unload is in progress " 83738c2ecf20Sopenharmony_ci "don't submit data to application\n"); 83748c2ecf20Sopenharmony_ci goto out; 83758c2ecf20Sopenharmony_ci } 83768c2ecf20Sopenharmony_ci /* 83778c2ecf20Sopenharmony_ci * copy out the kernel buffers to user buffers 83788c2ecf20Sopenharmony_ci */ 83798c2ecf20Sopenharmony_ci for (i = 0; i < ioc->sge_count; i++) { 83808c2ecf20Sopenharmony_ci if (copy_to_user(ioc->sgl[i].iov_base, kbuff_arr[i], 83818c2ecf20Sopenharmony_ci ioc->sgl[i].iov_len)) { 83828c2ecf20Sopenharmony_ci error = -EFAULT; 83838c2ecf20Sopenharmony_ci goto out; 83848c2ecf20Sopenharmony_ci } 83858c2ecf20Sopenharmony_ci } 83868c2ecf20Sopenharmony_ci 83878c2ecf20Sopenharmony_ci /* 83888c2ecf20Sopenharmony_ci * copy out the sense 83898c2ecf20Sopenharmony_ci */ 83908c2ecf20Sopenharmony_ci if (ioc->sense_len) { 83918c2ecf20Sopenharmony_ci /* 83928c2ecf20Sopenharmony_ci * sense_ptr points to the location that has the user 83938c2ecf20Sopenharmony_ci * sense buffer address 83948c2ecf20Sopenharmony_ci */ 83958c2ecf20Sopenharmony_ci sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw + 83968c2ecf20Sopenharmony_ci ioc->sense_off); 83978c2ecf20Sopenharmony_ci 83988c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)((unsigned long) 83998c2ecf20Sopenharmony_ci get_unaligned((unsigned long *)sense_ptr)), 84008c2ecf20Sopenharmony_ci sense, ioc->sense_len)) { 84018c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed to copy out to user " 84028c2ecf20Sopenharmony_ci "sense data\n"); 84038c2ecf20Sopenharmony_ci error = -EFAULT; 84048c2ecf20Sopenharmony_ci goto out; 84058c2ecf20Sopenharmony_ci } 84068c2ecf20Sopenharmony_ci } 84078c2ecf20Sopenharmony_ci 84088c2ecf20Sopenharmony_ci /* 84098c2ecf20Sopenharmony_ci * copy the status codes returned by the fw 84108c2ecf20Sopenharmony_ci */ 84118c2ecf20Sopenharmony_ci if (copy_to_user(&user_ioc->frame.hdr.cmd_status, 84128c2ecf20Sopenharmony_ci &cmd->frame->hdr.cmd_status, sizeof(u8))) { 84138c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error copying out cmd_status\n"); 84148c2ecf20Sopenharmony_ci error = -EFAULT; 84158c2ecf20Sopenharmony_ci } 84168c2ecf20Sopenharmony_ci 84178c2ecf20Sopenharmony_ciout: 84188c2ecf20Sopenharmony_ci if (sense) { 84198c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, ioc->sense_len, 84208c2ecf20Sopenharmony_ci sense, sense_handle); 84218c2ecf20Sopenharmony_ci } 84228c2ecf20Sopenharmony_ci 84238c2ecf20Sopenharmony_ci for (i = 0; i < ioc->sge_count; i++) { 84248c2ecf20Sopenharmony_ci if (kbuff_arr[i]) { 84258c2ecf20Sopenharmony_ci if (instance->consistent_mask_64bit) 84268c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, 84278c2ecf20Sopenharmony_ci le32_to_cpu(kern_sge64[i].length), 84288c2ecf20Sopenharmony_ci kbuff_arr[i], 84298c2ecf20Sopenharmony_ci le64_to_cpu(kern_sge64[i].phys_addr)); 84308c2ecf20Sopenharmony_ci else 84318c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, 84328c2ecf20Sopenharmony_ci le32_to_cpu(kern_sge32[i].length), 84338c2ecf20Sopenharmony_ci kbuff_arr[i], 84348c2ecf20Sopenharmony_ci le32_to_cpu(kern_sge32[i].phys_addr)); 84358c2ecf20Sopenharmony_ci kbuff_arr[i] = NULL; 84368c2ecf20Sopenharmony_ci } 84378c2ecf20Sopenharmony_ci } 84388c2ecf20Sopenharmony_ci 84398c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 84408c2ecf20Sopenharmony_ci return error; 84418c2ecf20Sopenharmony_ci} 84428c2ecf20Sopenharmony_ci 84438c2ecf20Sopenharmony_cistatic int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) 84448c2ecf20Sopenharmony_ci{ 84458c2ecf20Sopenharmony_ci struct megasas_iocpacket __user *user_ioc = 84468c2ecf20Sopenharmony_ci (struct megasas_iocpacket __user *)arg; 84478c2ecf20Sopenharmony_ci struct megasas_iocpacket *ioc; 84488c2ecf20Sopenharmony_ci struct megasas_instance *instance; 84498c2ecf20Sopenharmony_ci int error; 84508c2ecf20Sopenharmony_ci 84518c2ecf20Sopenharmony_ci ioc = memdup_user(user_ioc, sizeof(*ioc)); 84528c2ecf20Sopenharmony_ci if (IS_ERR(ioc)) 84538c2ecf20Sopenharmony_ci return PTR_ERR(ioc); 84548c2ecf20Sopenharmony_ci 84558c2ecf20Sopenharmony_ci instance = megasas_lookup_instance(ioc->host_no); 84568c2ecf20Sopenharmony_ci if (!instance) { 84578c2ecf20Sopenharmony_ci error = -ENODEV; 84588c2ecf20Sopenharmony_ci goto out_kfree_ioc; 84598c2ecf20Sopenharmony_ci } 84608c2ecf20Sopenharmony_ci 84618c2ecf20Sopenharmony_ci /* Block ioctls in VF mode */ 84628c2ecf20Sopenharmony_ci if (instance->requestorId && !allow_vf_ioctls) { 84638c2ecf20Sopenharmony_ci error = -ENODEV; 84648c2ecf20Sopenharmony_ci goto out_kfree_ioc; 84658c2ecf20Sopenharmony_ci } 84668c2ecf20Sopenharmony_ci 84678c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) { 84688c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Controller in crit error\n"); 84698c2ecf20Sopenharmony_ci error = -ENODEV; 84708c2ecf20Sopenharmony_ci goto out_kfree_ioc; 84718c2ecf20Sopenharmony_ci } 84728c2ecf20Sopenharmony_ci 84738c2ecf20Sopenharmony_ci if (instance->unload == 1) { 84748c2ecf20Sopenharmony_ci error = -ENODEV; 84758c2ecf20Sopenharmony_ci goto out_kfree_ioc; 84768c2ecf20Sopenharmony_ci } 84778c2ecf20Sopenharmony_ci 84788c2ecf20Sopenharmony_ci if (down_interruptible(&instance->ioctl_sem)) { 84798c2ecf20Sopenharmony_ci error = -ERESTARTSYS; 84808c2ecf20Sopenharmony_ci goto out_kfree_ioc; 84818c2ecf20Sopenharmony_ci } 84828c2ecf20Sopenharmony_ci 84838c2ecf20Sopenharmony_ci if (megasas_wait_for_adapter_operational(instance)) { 84848c2ecf20Sopenharmony_ci error = -ENODEV; 84858c2ecf20Sopenharmony_ci goto out_up; 84868c2ecf20Sopenharmony_ci } 84878c2ecf20Sopenharmony_ci 84888c2ecf20Sopenharmony_ci error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc); 84898c2ecf20Sopenharmony_ciout_up: 84908c2ecf20Sopenharmony_ci up(&instance->ioctl_sem); 84918c2ecf20Sopenharmony_ci 84928c2ecf20Sopenharmony_ciout_kfree_ioc: 84938c2ecf20Sopenharmony_ci kfree(ioc); 84948c2ecf20Sopenharmony_ci return error; 84958c2ecf20Sopenharmony_ci} 84968c2ecf20Sopenharmony_ci 84978c2ecf20Sopenharmony_cistatic int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg) 84988c2ecf20Sopenharmony_ci{ 84998c2ecf20Sopenharmony_ci struct megasas_instance *instance; 85008c2ecf20Sopenharmony_ci struct megasas_aen aen; 85018c2ecf20Sopenharmony_ci int error; 85028c2ecf20Sopenharmony_ci 85038c2ecf20Sopenharmony_ci if (file->private_data != file) { 85048c2ecf20Sopenharmony_ci printk(KERN_DEBUG "megasas: fasync_helper was not " 85058c2ecf20Sopenharmony_ci "called first\n"); 85068c2ecf20Sopenharmony_ci return -EINVAL; 85078c2ecf20Sopenharmony_ci } 85088c2ecf20Sopenharmony_ci 85098c2ecf20Sopenharmony_ci if (copy_from_user(&aen, (void __user *)arg, sizeof(aen))) 85108c2ecf20Sopenharmony_ci return -EFAULT; 85118c2ecf20Sopenharmony_ci 85128c2ecf20Sopenharmony_ci instance = megasas_lookup_instance(aen.host_no); 85138c2ecf20Sopenharmony_ci 85148c2ecf20Sopenharmony_ci if (!instance) 85158c2ecf20Sopenharmony_ci return -ENODEV; 85168c2ecf20Sopenharmony_ci 85178c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) { 85188c2ecf20Sopenharmony_ci return -ENODEV; 85198c2ecf20Sopenharmony_ci } 85208c2ecf20Sopenharmony_ci 85218c2ecf20Sopenharmony_ci if (instance->unload == 1) { 85228c2ecf20Sopenharmony_ci return -ENODEV; 85238c2ecf20Sopenharmony_ci } 85248c2ecf20Sopenharmony_ci 85258c2ecf20Sopenharmony_ci if (megasas_wait_for_adapter_operational(instance)) 85268c2ecf20Sopenharmony_ci return -ENODEV; 85278c2ecf20Sopenharmony_ci 85288c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 85298c2ecf20Sopenharmony_ci error = megasas_register_aen(instance, aen.seq_num, 85308c2ecf20Sopenharmony_ci aen.class_locale_word); 85318c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 85328c2ecf20Sopenharmony_ci return error; 85338c2ecf20Sopenharmony_ci} 85348c2ecf20Sopenharmony_ci 85358c2ecf20Sopenharmony_ci/** 85368c2ecf20Sopenharmony_ci * megasas_mgmt_ioctl - char node ioctl entry point 85378c2ecf20Sopenharmony_ci * @file: char device file pointer 85388c2ecf20Sopenharmony_ci * @cmd: ioctl command 85398c2ecf20Sopenharmony_ci * @arg: ioctl command arguments address 85408c2ecf20Sopenharmony_ci */ 85418c2ecf20Sopenharmony_cistatic long 85428c2ecf20Sopenharmony_cimegasas_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 85438c2ecf20Sopenharmony_ci{ 85448c2ecf20Sopenharmony_ci switch (cmd) { 85458c2ecf20Sopenharmony_ci case MEGASAS_IOC_FIRMWARE: 85468c2ecf20Sopenharmony_ci return megasas_mgmt_ioctl_fw(file, arg); 85478c2ecf20Sopenharmony_ci 85488c2ecf20Sopenharmony_ci case MEGASAS_IOC_GET_AEN: 85498c2ecf20Sopenharmony_ci return megasas_mgmt_ioctl_aen(file, arg); 85508c2ecf20Sopenharmony_ci } 85518c2ecf20Sopenharmony_ci 85528c2ecf20Sopenharmony_ci return -ENOTTY; 85538c2ecf20Sopenharmony_ci} 85548c2ecf20Sopenharmony_ci 85558c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 85568c2ecf20Sopenharmony_cistatic int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) 85578c2ecf20Sopenharmony_ci{ 85588c2ecf20Sopenharmony_ci struct compat_megasas_iocpacket __user *cioc = 85598c2ecf20Sopenharmony_ci (struct compat_megasas_iocpacket __user *)arg; 85608c2ecf20Sopenharmony_ci struct megasas_iocpacket __user *ioc = 85618c2ecf20Sopenharmony_ci compat_alloc_user_space(sizeof(struct megasas_iocpacket)); 85628c2ecf20Sopenharmony_ci int i; 85638c2ecf20Sopenharmony_ci int error = 0; 85648c2ecf20Sopenharmony_ci compat_uptr_t ptr; 85658c2ecf20Sopenharmony_ci u32 local_sense_off; 85668c2ecf20Sopenharmony_ci u32 local_sense_len; 85678c2ecf20Sopenharmony_ci u32 user_sense_off; 85688c2ecf20Sopenharmony_ci 85698c2ecf20Sopenharmony_ci if (clear_user(ioc, sizeof(*ioc))) 85708c2ecf20Sopenharmony_ci return -EFAULT; 85718c2ecf20Sopenharmony_ci 85728c2ecf20Sopenharmony_ci if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) || 85738c2ecf20Sopenharmony_ci copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) || 85748c2ecf20Sopenharmony_ci copy_in_user(&ioc->sense_off, &cioc->sense_off, sizeof(u32)) || 85758c2ecf20Sopenharmony_ci copy_in_user(&ioc->sense_len, &cioc->sense_len, sizeof(u32)) || 85768c2ecf20Sopenharmony_ci copy_in_user(ioc->frame.raw, cioc->frame.raw, 128) || 85778c2ecf20Sopenharmony_ci copy_in_user(&ioc->sge_count, &cioc->sge_count, sizeof(u32))) 85788c2ecf20Sopenharmony_ci return -EFAULT; 85798c2ecf20Sopenharmony_ci 85808c2ecf20Sopenharmony_ci /* 85818c2ecf20Sopenharmony_ci * The sense_ptr is used in megasas_mgmt_fw_ioctl only when 85828c2ecf20Sopenharmony_ci * sense_len is not null, so prepare the 64bit value under 85838c2ecf20Sopenharmony_ci * the same condition. 85848c2ecf20Sopenharmony_ci */ 85858c2ecf20Sopenharmony_ci if (get_user(local_sense_off, &ioc->sense_off) || 85868c2ecf20Sopenharmony_ci get_user(local_sense_len, &ioc->sense_len) || 85878c2ecf20Sopenharmony_ci get_user(user_sense_off, &cioc->sense_off)) 85888c2ecf20Sopenharmony_ci return -EFAULT; 85898c2ecf20Sopenharmony_ci 85908c2ecf20Sopenharmony_ci if (local_sense_off != user_sense_off) 85918c2ecf20Sopenharmony_ci return -EINVAL; 85928c2ecf20Sopenharmony_ci 85938c2ecf20Sopenharmony_ci if (local_sense_len) { 85948c2ecf20Sopenharmony_ci void __user **sense_ioc_ptr = 85958c2ecf20Sopenharmony_ci (void __user **)((u8 *)((unsigned long)&ioc->frame.raw) + local_sense_off); 85968c2ecf20Sopenharmony_ci compat_uptr_t *sense_cioc_ptr = 85978c2ecf20Sopenharmony_ci (compat_uptr_t *)(((unsigned long)&cioc->frame.raw) + user_sense_off); 85988c2ecf20Sopenharmony_ci if (get_user(ptr, sense_cioc_ptr) || 85998c2ecf20Sopenharmony_ci put_user(compat_ptr(ptr), sense_ioc_ptr)) 86008c2ecf20Sopenharmony_ci return -EFAULT; 86018c2ecf20Sopenharmony_ci } 86028c2ecf20Sopenharmony_ci 86038c2ecf20Sopenharmony_ci for (i = 0; i < MAX_IOCTL_SGE; i++) { 86048c2ecf20Sopenharmony_ci if (get_user(ptr, &cioc->sgl[i].iov_base) || 86058c2ecf20Sopenharmony_ci put_user(compat_ptr(ptr), &ioc->sgl[i].iov_base) || 86068c2ecf20Sopenharmony_ci copy_in_user(&ioc->sgl[i].iov_len, 86078c2ecf20Sopenharmony_ci &cioc->sgl[i].iov_len, sizeof(compat_size_t))) 86088c2ecf20Sopenharmony_ci return -EFAULT; 86098c2ecf20Sopenharmony_ci } 86108c2ecf20Sopenharmony_ci 86118c2ecf20Sopenharmony_ci error = megasas_mgmt_ioctl_fw(file, (unsigned long)ioc); 86128c2ecf20Sopenharmony_ci 86138c2ecf20Sopenharmony_ci if (copy_in_user(&cioc->frame.hdr.cmd_status, 86148c2ecf20Sopenharmony_ci &ioc->frame.hdr.cmd_status, sizeof(u8))) { 86158c2ecf20Sopenharmony_ci printk(KERN_DEBUG "megasas: error copy_in_user cmd_status\n"); 86168c2ecf20Sopenharmony_ci return -EFAULT; 86178c2ecf20Sopenharmony_ci } 86188c2ecf20Sopenharmony_ci return error; 86198c2ecf20Sopenharmony_ci} 86208c2ecf20Sopenharmony_ci 86218c2ecf20Sopenharmony_cistatic long 86228c2ecf20Sopenharmony_cimegasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd, 86238c2ecf20Sopenharmony_ci unsigned long arg) 86248c2ecf20Sopenharmony_ci{ 86258c2ecf20Sopenharmony_ci switch (cmd) { 86268c2ecf20Sopenharmony_ci case MEGASAS_IOC_FIRMWARE32: 86278c2ecf20Sopenharmony_ci return megasas_mgmt_compat_ioctl_fw(file, arg); 86288c2ecf20Sopenharmony_ci case MEGASAS_IOC_GET_AEN: 86298c2ecf20Sopenharmony_ci return megasas_mgmt_ioctl_aen(file, arg); 86308c2ecf20Sopenharmony_ci } 86318c2ecf20Sopenharmony_ci 86328c2ecf20Sopenharmony_ci return -ENOTTY; 86338c2ecf20Sopenharmony_ci} 86348c2ecf20Sopenharmony_ci#endif 86358c2ecf20Sopenharmony_ci 86368c2ecf20Sopenharmony_ci/* 86378c2ecf20Sopenharmony_ci * File operations structure for management interface 86388c2ecf20Sopenharmony_ci */ 86398c2ecf20Sopenharmony_cistatic const struct file_operations megasas_mgmt_fops = { 86408c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 86418c2ecf20Sopenharmony_ci .open = megasas_mgmt_open, 86428c2ecf20Sopenharmony_ci .fasync = megasas_mgmt_fasync, 86438c2ecf20Sopenharmony_ci .unlocked_ioctl = megasas_mgmt_ioctl, 86448c2ecf20Sopenharmony_ci .poll = megasas_mgmt_poll, 86458c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 86468c2ecf20Sopenharmony_ci .compat_ioctl = megasas_mgmt_compat_ioctl, 86478c2ecf20Sopenharmony_ci#endif 86488c2ecf20Sopenharmony_ci .llseek = noop_llseek, 86498c2ecf20Sopenharmony_ci}; 86508c2ecf20Sopenharmony_ci 86518c2ecf20Sopenharmony_ci/* 86528c2ecf20Sopenharmony_ci * PCI hotplug support registration structure 86538c2ecf20Sopenharmony_ci */ 86548c2ecf20Sopenharmony_cistatic struct pci_driver megasas_pci_driver = { 86558c2ecf20Sopenharmony_ci 86568c2ecf20Sopenharmony_ci .name = "megaraid_sas", 86578c2ecf20Sopenharmony_ci .id_table = megasas_pci_table, 86588c2ecf20Sopenharmony_ci .probe = megasas_probe_one, 86598c2ecf20Sopenharmony_ci .remove = megasas_detach_one, 86608c2ecf20Sopenharmony_ci .suspend = megasas_suspend, 86618c2ecf20Sopenharmony_ci .resume = megasas_resume, 86628c2ecf20Sopenharmony_ci .shutdown = megasas_shutdown, 86638c2ecf20Sopenharmony_ci}; 86648c2ecf20Sopenharmony_ci 86658c2ecf20Sopenharmony_ci/* 86668c2ecf20Sopenharmony_ci * Sysfs driver attributes 86678c2ecf20Sopenharmony_ci */ 86688c2ecf20Sopenharmony_cistatic ssize_t version_show(struct device_driver *dd, char *buf) 86698c2ecf20Sopenharmony_ci{ 86708c2ecf20Sopenharmony_ci return snprintf(buf, strlen(MEGASAS_VERSION) + 2, "%s\n", 86718c2ecf20Sopenharmony_ci MEGASAS_VERSION); 86728c2ecf20Sopenharmony_ci} 86738c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(version); 86748c2ecf20Sopenharmony_ci 86758c2ecf20Sopenharmony_cistatic ssize_t release_date_show(struct device_driver *dd, char *buf) 86768c2ecf20Sopenharmony_ci{ 86778c2ecf20Sopenharmony_ci return snprintf(buf, strlen(MEGASAS_RELDATE) + 2, "%s\n", 86788c2ecf20Sopenharmony_ci MEGASAS_RELDATE); 86798c2ecf20Sopenharmony_ci} 86808c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(release_date); 86818c2ecf20Sopenharmony_ci 86828c2ecf20Sopenharmony_cistatic ssize_t support_poll_for_event_show(struct device_driver *dd, char *buf) 86838c2ecf20Sopenharmony_ci{ 86848c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", support_poll_for_event); 86858c2ecf20Sopenharmony_ci} 86868c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(support_poll_for_event); 86878c2ecf20Sopenharmony_ci 86888c2ecf20Sopenharmony_cistatic ssize_t support_device_change_show(struct device_driver *dd, char *buf) 86898c2ecf20Sopenharmony_ci{ 86908c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", support_device_change); 86918c2ecf20Sopenharmony_ci} 86928c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(support_device_change); 86938c2ecf20Sopenharmony_ci 86948c2ecf20Sopenharmony_cistatic ssize_t dbg_lvl_show(struct device_driver *dd, char *buf) 86958c2ecf20Sopenharmony_ci{ 86968c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", megasas_dbg_lvl); 86978c2ecf20Sopenharmony_ci} 86988c2ecf20Sopenharmony_ci 86998c2ecf20Sopenharmony_cistatic ssize_t dbg_lvl_store(struct device_driver *dd, const char *buf, 87008c2ecf20Sopenharmony_ci size_t count) 87018c2ecf20Sopenharmony_ci{ 87028c2ecf20Sopenharmony_ci int retval = count; 87038c2ecf20Sopenharmony_ci 87048c2ecf20Sopenharmony_ci if (sscanf(buf, "%u", &megasas_dbg_lvl) < 1) { 87058c2ecf20Sopenharmony_ci printk(KERN_ERR "megasas: could not set dbg_lvl\n"); 87068c2ecf20Sopenharmony_ci retval = -EINVAL; 87078c2ecf20Sopenharmony_ci } 87088c2ecf20Sopenharmony_ci return retval; 87098c2ecf20Sopenharmony_ci} 87108c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(dbg_lvl); 87118c2ecf20Sopenharmony_ci 87128c2ecf20Sopenharmony_cistatic ssize_t 87138c2ecf20Sopenharmony_cisupport_nvme_encapsulation_show(struct device_driver *dd, char *buf) 87148c2ecf20Sopenharmony_ci{ 87158c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", support_nvme_encapsulation); 87168c2ecf20Sopenharmony_ci} 87178c2ecf20Sopenharmony_ci 87188c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(support_nvme_encapsulation); 87198c2ecf20Sopenharmony_ci 87208c2ecf20Sopenharmony_cistatic ssize_t 87218c2ecf20Sopenharmony_cisupport_pci_lane_margining_show(struct device_driver *dd, char *buf) 87228c2ecf20Sopenharmony_ci{ 87238c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", support_pci_lane_margining); 87248c2ecf20Sopenharmony_ci} 87258c2ecf20Sopenharmony_ci 87268c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(support_pci_lane_margining); 87278c2ecf20Sopenharmony_ci 87288c2ecf20Sopenharmony_cistatic inline void megasas_remove_scsi_device(struct scsi_device *sdev) 87298c2ecf20Sopenharmony_ci{ 87308c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, sdev, "SCSI device is removed\n"); 87318c2ecf20Sopenharmony_ci scsi_remove_device(sdev); 87328c2ecf20Sopenharmony_ci scsi_device_put(sdev); 87338c2ecf20Sopenharmony_ci} 87348c2ecf20Sopenharmony_ci 87358c2ecf20Sopenharmony_ci/** 87368c2ecf20Sopenharmony_ci * megasas_update_device_list - Update the PD and LD device list from FW 87378c2ecf20Sopenharmony_ci * after an AEN event notification 87388c2ecf20Sopenharmony_ci * @instance: Adapter soft state 87398c2ecf20Sopenharmony_ci * @event_type: Indicates type of event (PD or LD event) 87408c2ecf20Sopenharmony_ci * 87418c2ecf20Sopenharmony_ci * @return: Success or failure 87428c2ecf20Sopenharmony_ci * 87438c2ecf20Sopenharmony_ci * Issue DCMDs to Firmware to update the internal device list in driver. 87448c2ecf20Sopenharmony_ci * Based on the FW support, driver sends the HOST_DEVICE_LIST or combination 87458c2ecf20Sopenharmony_ci * of PD_LIST/LD_LIST_QUERY DCMDs to get the device list. 87468c2ecf20Sopenharmony_ci */ 87478c2ecf20Sopenharmony_cistatic 87488c2ecf20Sopenharmony_ciint megasas_update_device_list(struct megasas_instance *instance, 87498c2ecf20Sopenharmony_ci int event_type) 87508c2ecf20Sopenharmony_ci{ 87518c2ecf20Sopenharmony_ci int dcmd_ret = DCMD_SUCCESS; 87528c2ecf20Sopenharmony_ci 87538c2ecf20Sopenharmony_ci if (instance->enable_fw_dev_list) { 87548c2ecf20Sopenharmony_ci dcmd_ret = megasas_host_device_list_query(instance, false); 87558c2ecf20Sopenharmony_ci if (dcmd_ret != DCMD_SUCCESS) 87568c2ecf20Sopenharmony_ci goto out; 87578c2ecf20Sopenharmony_ci } else { 87588c2ecf20Sopenharmony_ci if (event_type & SCAN_PD_CHANNEL) { 87598c2ecf20Sopenharmony_ci dcmd_ret = megasas_get_pd_list(instance); 87608c2ecf20Sopenharmony_ci 87618c2ecf20Sopenharmony_ci if (dcmd_ret != DCMD_SUCCESS) 87628c2ecf20Sopenharmony_ci goto out; 87638c2ecf20Sopenharmony_ci } 87648c2ecf20Sopenharmony_ci 87658c2ecf20Sopenharmony_ci if (event_type & SCAN_VD_CHANNEL) { 87668c2ecf20Sopenharmony_ci if (!instance->requestorId || 87678c2ecf20Sopenharmony_ci (instance->requestorId && 87688c2ecf20Sopenharmony_ci megasas_get_ld_vf_affiliation(instance, 0))) { 87698c2ecf20Sopenharmony_ci dcmd_ret = megasas_ld_list_query(instance, 87708c2ecf20Sopenharmony_ci MR_LD_QUERY_TYPE_EXPOSED_TO_HOST); 87718c2ecf20Sopenharmony_ci if (dcmd_ret != DCMD_SUCCESS) 87728c2ecf20Sopenharmony_ci goto out; 87738c2ecf20Sopenharmony_ci } 87748c2ecf20Sopenharmony_ci } 87758c2ecf20Sopenharmony_ci } 87768c2ecf20Sopenharmony_ci 87778c2ecf20Sopenharmony_ciout: 87788c2ecf20Sopenharmony_ci return dcmd_ret; 87798c2ecf20Sopenharmony_ci} 87808c2ecf20Sopenharmony_ci 87818c2ecf20Sopenharmony_ci/** 87828c2ecf20Sopenharmony_ci * megasas_add_remove_devices - Add/remove devices to SCSI mid-layer 87838c2ecf20Sopenharmony_ci * after an AEN event notification 87848c2ecf20Sopenharmony_ci * @instance: Adapter soft state 87858c2ecf20Sopenharmony_ci * @scan_type: Indicates type of devices (PD/LD) to add 87868c2ecf20Sopenharmony_ci * @return void 87878c2ecf20Sopenharmony_ci */ 87888c2ecf20Sopenharmony_cistatic 87898c2ecf20Sopenharmony_civoid megasas_add_remove_devices(struct megasas_instance *instance, 87908c2ecf20Sopenharmony_ci int scan_type) 87918c2ecf20Sopenharmony_ci{ 87928c2ecf20Sopenharmony_ci int i, j; 87938c2ecf20Sopenharmony_ci u16 pd_index = 0; 87948c2ecf20Sopenharmony_ci u16 ld_index = 0; 87958c2ecf20Sopenharmony_ci u16 channel = 0, id = 0; 87968c2ecf20Sopenharmony_ci struct Scsi_Host *host; 87978c2ecf20Sopenharmony_ci struct scsi_device *sdev1; 87988c2ecf20Sopenharmony_ci struct MR_HOST_DEVICE_LIST *targetid_list = NULL; 87998c2ecf20Sopenharmony_ci struct MR_HOST_DEVICE_LIST_ENTRY *targetid_entry = NULL; 88008c2ecf20Sopenharmony_ci 88018c2ecf20Sopenharmony_ci host = instance->host; 88028c2ecf20Sopenharmony_ci 88038c2ecf20Sopenharmony_ci if (instance->enable_fw_dev_list) { 88048c2ecf20Sopenharmony_ci targetid_list = instance->host_device_list_buf; 88058c2ecf20Sopenharmony_ci for (i = 0; i < targetid_list->count; i++) { 88068c2ecf20Sopenharmony_ci targetid_entry = &targetid_list->host_device_list[i]; 88078c2ecf20Sopenharmony_ci if (targetid_entry->flags.u.bits.is_sys_pd) { 88088c2ecf20Sopenharmony_ci channel = le16_to_cpu(targetid_entry->target_id) / 88098c2ecf20Sopenharmony_ci MEGASAS_MAX_DEV_PER_CHANNEL; 88108c2ecf20Sopenharmony_ci id = le16_to_cpu(targetid_entry->target_id) % 88118c2ecf20Sopenharmony_ci MEGASAS_MAX_DEV_PER_CHANNEL; 88128c2ecf20Sopenharmony_ci } else { 88138c2ecf20Sopenharmony_ci channel = MEGASAS_MAX_PD_CHANNELS + 88148c2ecf20Sopenharmony_ci (le16_to_cpu(targetid_entry->target_id) / 88158c2ecf20Sopenharmony_ci MEGASAS_MAX_DEV_PER_CHANNEL); 88168c2ecf20Sopenharmony_ci id = le16_to_cpu(targetid_entry->target_id) % 88178c2ecf20Sopenharmony_ci MEGASAS_MAX_DEV_PER_CHANNEL; 88188c2ecf20Sopenharmony_ci } 88198c2ecf20Sopenharmony_ci sdev1 = scsi_device_lookup(host, channel, id, 0); 88208c2ecf20Sopenharmony_ci if (!sdev1) { 88218c2ecf20Sopenharmony_ci scsi_add_device(host, channel, id, 0); 88228c2ecf20Sopenharmony_ci } else { 88238c2ecf20Sopenharmony_ci scsi_device_put(sdev1); 88248c2ecf20Sopenharmony_ci } 88258c2ecf20Sopenharmony_ci } 88268c2ecf20Sopenharmony_ci } 88278c2ecf20Sopenharmony_ci 88288c2ecf20Sopenharmony_ci if (scan_type & SCAN_PD_CHANNEL) { 88298c2ecf20Sopenharmony_ci for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) { 88308c2ecf20Sopenharmony_ci for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) { 88318c2ecf20Sopenharmony_ci pd_index = i * MEGASAS_MAX_DEV_PER_CHANNEL + j; 88328c2ecf20Sopenharmony_ci sdev1 = scsi_device_lookup(host, i, j, 0); 88338c2ecf20Sopenharmony_ci if (instance->pd_list[pd_index].driveState == 88348c2ecf20Sopenharmony_ci MR_PD_STATE_SYSTEM) { 88358c2ecf20Sopenharmony_ci if (!sdev1) 88368c2ecf20Sopenharmony_ci scsi_add_device(host, i, j, 0); 88378c2ecf20Sopenharmony_ci else 88388c2ecf20Sopenharmony_ci scsi_device_put(sdev1); 88398c2ecf20Sopenharmony_ci } else { 88408c2ecf20Sopenharmony_ci if (sdev1) 88418c2ecf20Sopenharmony_ci megasas_remove_scsi_device(sdev1); 88428c2ecf20Sopenharmony_ci } 88438c2ecf20Sopenharmony_ci } 88448c2ecf20Sopenharmony_ci } 88458c2ecf20Sopenharmony_ci } 88468c2ecf20Sopenharmony_ci 88478c2ecf20Sopenharmony_ci if (scan_type & SCAN_VD_CHANNEL) { 88488c2ecf20Sopenharmony_ci for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) { 88498c2ecf20Sopenharmony_ci for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) { 88508c2ecf20Sopenharmony_ci ld_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; 88518c2ecf20Sopenharmony_ci sdev1 = scsi_device_lookup(host, 88528c2ecf20Sopenharmony_ci MEGASAS_MAX_PD_CHANNELS + i, j, 0); 88538c2ecf20Sopenharmony_ci if (instance->ld_ids[ld_index] != 0xff) { 88548c2ecf20Sopenharmony_ci if (!sdev1) 88558c2ecf20Sopenharmony_ci scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0); 88568c2ecf20Sopenharmony_ci else 88578c2ecf20Sopenharmony_ci scsi_device_put(sdev1); 88588c2ecf20Sopenharmony_ci } else { 88598c2ecf20Sopenharmony_ci if (sdev1) 88608c2ecf20Sopenharmony_ci megasas_remove_scsi_device(sdev1); 88618c2ecf20Sopenharmony_ci } 88628c2ecf20Sopenharmony_ci } 88638c2ecf20Sopenharmony_ci } 88648c2ecf20Sopenharmony_ci } 88658c2ecf20Sopenharmony_ci 88668c2ecf20Sopenharmony_ci} 88678c2ecf20Sopenharmony_ci 88688c2ecf20Sopenharmony_cistatic void 88698c2ecf20Sopenharmony_cimegasas_aen_polling(struct work_struct *work) 88708c2ecf20Sopenharmony_ci{ 88718c2ecf20Sopenharmony_ci struct megasas_aen_event *ev = 88728c2ecf20Sopenharmony_ci container_of(work, struct megasas_aen_event, hotplug_work.work); 88738c2ecf20Sopenharmony_ci struct megasas_instance *instance = ev->instance; 88748c2ecf20Sopenharmony_ci union megasas_evt_class_locale class_locale; 88758c2ecf20Sopenharmony_ci int event_type = 0; 88768c2ecf20Sopenharmony_ci u32 seq_num; 88778c2ecf20Sopenharmony_ci u16 ld_target_id; 88788c2ecf20Sopenharmony_ci int error; 88798c2ecf20Sopenharmony_ci u8 dcmd_ret = DCMD_SUCCESS; 88808c2ecf20Sopenharmony_ci struct scsi_device *sdev1; 88818c2ecf20Sopenharmony_ci 88828c2ecf20Sopenharmony_ci if (!instance) { 88838c2ecf20Sopenharmony_ci printk(KERN_ERR "invalid instance!\n"); 88848c2ecf20Sopenharmony_ci kfree(ev); 88858c2ecf20Sopenharmony_ci return; 88868c2ecf20Sopenharmony_ci } 88878c2ecf20Sopenharmony_ci 88888c2ecf20Sopenharmony_ci /* Don't run the event workqueue thread if OCR is running */ 88898c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 88908c2ecf20Sopenharmony_ci 88918c2ecf20Sopenharmony_ci instance->ev = NULL; 88928c2ecf20Sopenharmony_ci if (instance->evt_detail) { 88938c2ecf20Sopenharmony_ci megasas_decode_evt(instance); 88948c2ecf20Sopenharmony_ci 88958c2ecf20Sopenharmony_ci switch (le32_to_cpu(instance->evt_detail->code)) { 88968c2ecf20Sopenharmony_ci 88978c2ecf20Sopenharmony_ci case MR_EVT_PD_INSERTED: 88988c2ecf20Sopenharmony_ci case MR_EVT_PD_REMOVED: 88998c2ecf20Sopenharmony_ci event_type = SCAN_PD_CHANNEL; 89008c2ecf20Sopenharmony_ci break; 89018c2ecf20Sopenharmony_ci 89028c2ecf20Sopenharmony_ci case MR_EVT_LD_OFFLINE: 89038c2ecf20Sopenharmony_ci case MR_EVT_LD_DELETED: 89048c2ecf20Sopenharmony_ci ld_target_id = instance->evt_detail->args.ld.target_id; 89058c2ecf20Sopenharmony_ci sdev1 = scsi_device_lookup(instance->host, 89068c2ecf20Sopenharmony_ci MEGASAS_MAX_PD_CHANNELS + 89078c2ecf20Sopenharmony_ci (ld_target_id / MEGASAS_MAX_DEV_PER_CHANNEL), 89088c2ecf20Sopenharmony_ci (ld_target_id - MEGASAS_MAX_DEV_PER_CHANNEL), 89098c2ecf20Sopenharmony_ci 0); 89108c2ecf20Sopenharmony_ci if (sdev1) 89118c2ecf20Sopenharmony_ci megasas_remove_scsi_device(sdev1); 89128c2ecf20Sopenharmony_ci 89138c2ecf20Sopenharmony_ci event_type = SCAN_VD_CHANNEL; 89148c2ecf20Sopenharmony_ci break; 89158c2ecf20Sopenharmony_ci case MR_EVT_LD_CREATED: 89168c2ecf20Sopenharmony_ci event_type = SCAN_VD_CHANNEL; 89178c2ecf20Sopenharmony_ci break; 89188c2ecf20Sopenharmony_ci 89198c2ecf20Sopenharmony_ci case MR_EVT_CFG_CLEARED: 89208c2ecf20Sopenharmony_ci case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED: 89218c2ecf20Sopenharmony_ci case MR_EVT_FOREIGN_CFG_IMPORTED: 89228c2ecf20Sopenharmony_ci case MR_EVT_LD_STATE_CHANGE: 89238c2ecf20Sopenharmony_ci event_type = SCAN_PD_CHANNEL | SCAN_VD_CHANNEL; 89248c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "scanning for scsi%d...\n", 89258c2ecf20Sopenharmony_ci instance->host->host_no); 89268c2ecf20Sopenharmony_ci break; 89278c2ecf20Sopenharmony_ci 89288c2ecf20Sopenharmony_ci case MR_EVT_CTRL_PROP_CHANGED: 89298c2ecf20Sopenharmony_ci dcmd_ret = megasas_get_ctrl_info(instance); 89308c2ecf20Sopenharmony_ci if (dcmd_ret == DCMD_SUCCESS && 89318c2ecf20Sopenharmony_ci instance->snapdump_wait_time) { 89328c2ecf20Sopenharmony_ci megasas_get_snapdump_properties(instance); 89338c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 89348c2ecf20Sopenharmony_ci "Snap dump wait time\t: %d\n", 89358c2ecf20Sopenharmony_ci instance->snapdump_wait_time); 89368c2ecf20Sopenharmony_ci } 89378c2ecf20Sopenharmony_ci break; 89388c2ecf20Sopenharmony_ci default: 89398c2ecf20Sopenharmony_ci event_type = 0; 89408c2ecf20Sopenharmony_ci break; 89418c2ecf20Sopenharmony_ci } 89428c2ecf20Sopenharmony_ci } else { 89438c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "invalid evt_detail!\n"); 89448c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 89458c2ecf20Sopenharmony_ci kfree(ev); 89468c2ecf20Sopenharmony_ci return; 89478c2ecf20Sopenharmony_ci } 89488c2ecf20Sopenharmony_ci 89498c2ecf20Sopenharmony_ci if (event_type) 89508c2ecf20Sopenharmony_ci dcmd_ret = megasas_update_device_list(instance, event_type); 89518c2ecf20Sopenharmony_ci 89528c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 89538c2ecf20Sopenharmony_ci 89548c2ecf20Sopenharmony_ci if (event_type && dcmd_ret == DCMD_SUCCESS) 89558c2ecf20Sopenharmony_ci megasas_add_remove_devices(instance, event_type); 89568c2ecf20Sopenharmony_ci 89578c2ecf20Sopenharmony_ci if (dcmd_ret == DCMD_SUCCESS) 89588c2ecf20Sopenharmony_ci seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1; 89598c2ecf20Sopenharmony_ci else 89608c2ecf20Sopenharmony_ci seq_num = instance->last_seq_num; 89618c2ecf20Sopenharmony_ci 89628c2ecf20Sopenharmony_ci /* Register AEN with FW for latest sequence number plus 1 */ 89638c2ecf20Sopenharmony_ci class_locale.members.reserved = 0; 89648c2ecf20Sopenharmony_ci class_locale.members.locale = MR_EVT_LOCALE_ALL; 89658c2ecf20Sopenharmony_ci class_locale.members.class = MR_EVT_CLASS_DEBUG; 89668c2ecf20Sopenharmony_ci 89678c2ecf20Sopenharmony_ci if (instance->aen_cmd != NULL) { 89688c2ecf20Sopenharmony_ci kfree(ev); 89698c2ecf20Sopenharmony_ci return; 89708c2ecf20Sopenharmony_ci } 89718c2ecf20Sopenharmony_ci 89728c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 89738c2ecf20Sopenharmony_ci error = megasas_register_aen(instance, seq_num, 89748c2ecf20Sopenharmony_ci class_locale.word); 89758c2ecf20Sopenharmony_ci if (error) 89768c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 89778c2ecf20Sopenharmony_ci "register aen failed error %x\n", error); 89788c2ecf20Sopenharmony_ci 89798c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 89808c2ecf20Sopenharmony_ci kfree(ev); 89818c2ecf20Sopenharmony_ci} 89828c2ecf20Sopenharmony_ci 89838c2ecf20Sopenharmony_ci/** 89848c2ecf20Sopenharmony_ci * megasas_init - Driver load entry point 89858c2ecf20Sopenharmony_ci */ 89868c2ecf20Sopenharmony_cistatic int __init megasas_init(void) 89878c2ecf20Sopenharmony_ci{ 89888c2ecf20Sopenharmony_ci int rval; 89898c2ecf20Sopenharmony_ci 89908c2ecf20Sopenharmony_ci /* 89918c2ecf20Sopenharmony_ci * Booted in kdump kernel, minimize memory footprints by 89928c2ecf20Sopenharmony_ci * disabling few features 89938c2ecf20Sopenharmony_ci */ 89948c2ecf20Sopenharmony_ci if (reset_devices) { 89958c2ecf20Sopenharmony_ci msix_vectors = 1; 89968c2ecf20Sopenharmony_ci rdpq_enable = 0; 89978c2ecf20Sopenharmony_ci dual_qdepth_disable = 1; 89988c2ecf20Sopenharmony_ci } 89998c2ecf20Sopenharmony_ci 90008c2ecf20Sopenharmony_ci /* 90018c2ecf20Sopenharmony_ci * Announce driver version and other information 90028c2ecf20Sopenharmony_ci */ 90038c2ecf20Sopenharmony_ci pr_info("megasas: %s\n", MEGASAS_VERSION); 90048c2ecf20Sopenharmony_ci 90058c2ecf20Sopenharmony_ci spin_lock_init(&poll_aen_lock); 90068c2ecf20Sopenharmony_ci 90078c2ecf20Sopenharmony_ci support_poll_for_event = 2; 90088c2ecf20Sopenharmony_ci support_device_change = 1; 90098c2ecf20Sopenharmony_ci support_nvme_encapsulation = true; 90108c2ecf20Sopenharmony_ci support_pci_lane_margining = true; 90118c2ecf20Sopenharmony_ci 90128c2ecf20Sopenharmony_ci memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info)); 90138c2ecf20Sopenharmony_ci 90148c2ecf20Sopenharmony_ci /* 90158c2ecf20Sopenharmony_ci * Register character device node 90168c2ecf20Sopenharmony_ci */ 90178c2ecf20Sopenharmony_ci rval = register_chrdev(0, "megaraid_sas_ioctl", &megasas_mgmt_fops); 90188c2ecf20Sopenharmony_ci 90198c2ecf20Sopenharmony_ci if (rval < 0) { 90208c2ecf20Sopenharmony_ci printk(KERN_DEBUG "megasas: failed to open device node\n"); 90218c2ecf20Sopenharmony_ci return rval; 90228c2ecf20Sopenharmony_ci } 90238c2ecf20Sopenharmony_ci 90248c2ecf20Sopenharmony_ci megasas_mgmt_majorno = rval; 90258c2ecf20Sopenharmony_ci 90268c2ecf20Sopenharmony_ci megasas_init_debugfs(); 90278c2ecf20Sopenharmony_ci 90288c2ecf20Sopenharmony_ci /* 90298c2ecf20Sopenharmony_ci * Register ourselves as PCI hotplug module 90308c2ecf20Sopenharmony_ci */ 90318c2ecf20Sopenharmony_ci rval = pci_register_driver(&megasas_pci_driver); 90328c2ecf20Sopenharmony_ci 90338c2ecf20Sopenharmony_ci if (rval) { 90348c2ecf20Sopenharmony_ci printk(KERN_DEBUG "megasas: PCI hotplug registration failed \n"); 90358c2ecf20Sopenharmony_ci goto err_pcidrv; 90368c2ecf20Sopenharmony_ci } 90378c2ecf20Sopenharmony_ci 90388c2ecf20Sopenharmony_ci if ((event_log_level < MFI_EVT_CLASS_DEBUG) || 90398c2ecf20Sopenharmony_ci (event_log_level > MFI_EVT_CLASS_DEAD)) { 90408c2ecf20Sopenharmony_ci pr_warn("megaraid_sas: provided event log level is out of range, setting it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n"); 90418c2ecf20Sopenharmony_ci event_log_level = MFI_EVT_CLASS_CRITICAL; 90428c2ecf20Sopenharmony_ci } 90438c2ecf20Sopenharmony_ci 90448c2ecf20Sopenharmony_ci rval = driver_create_file(&megasas_pci_driver.driver, 90458c2ecf20Sopenharmony_ci &driver_attr_version); 90468c2ecf20Sopenharmony_ci if (rval) 90478c2ecf20Sopenharmony_ci goto err_dcf_attr_ver; 90488c2ecf20Sopenharmony_ci 90498c2ecf20Sopenharmony_ci rval = driver_create_file(&megasas_pci_driver.driver, 90508c2ecf20Sopenharmony_ci &driver_attr_release_date); 90518c2ecf20Sopenharmony_ci if (rval) 90528c2ecf20Sopenharmony_ci goto err_dcf_rel_date; 90538c2ecf20Sopenharmony_ci 90548c2ecf20Sopenharmony_ci rval = driver_create_file(&megasas_pci_driver.driver, 90558c2ecf20Sopenharmony_ci &driver_attr_support_poll_for_event); 90568c2ecf20Sopenharmony_ci if (rval) 90578c2ecf20Sopenharmony_ci goto err_dcf_support_poll_for_event; 90588c2ecf20Sopenharmony_ci 90598c2ecf20Sopenharmony_ci rval = driver_create_file(&megasas_pci_driver.driver, 90608c2ecf20Sopenharmony_ci &driver_attr_dbg_lvl); 90618c2ecf20Sopenharmony_ci if (rval) 90628c2ecf20Sopenharmony_ci goto err_dcf_dbg_lvl; 90638c2ecf20Sopenharmony_ci rval = driver_create_file(&megasas_pci_driver.driver, 90648c2ecf20Sopenharmony_ci &driver_attr_support_device_change); 90658c2ecf20Sopenharmony_ci if (rval) 90668c2ecf20Sopenharmony_ci goto err_dcf_support_device_change; 90678c2ecf20Sopenharmony_ci 90688c2ecf20Sopenharmony_ci rval = driver_create_file(&megasas_pci_driver.driver, 90698c2ecf20Sopenharmony_ci &driver_attr_support_nvme_encapsulation); 90708c2ecf20Sopenharmony_ci if (rval) 90718c2ecf20Sopenharmony_ci goto err_dcf_support_nvme_encapsulation; 90728c2ecf20Sopenharmony_ci 90738c2ecf20Sopenharmony_ci rval = driver_create_file(&megasas_pci_driver.driver, 90748c2ecf20Sopenharmony_ci &driver_attr_support_pci_lane_margining); 90758c2ecf20Sopenharmony_ci if (rval) 90768c2ecf20Sopenharmony_ci goto err_dcf_support_pci_lane_margining; 90778c2ecf20Sopenharmony_ci 90788c2ecf20Sopenharmony_ci return rval; 90798c2ecf20Sopenharmony_ci 90808c2ecf20Sopenharmony_cierr_dcf_support_pci_lane_margining: 90818c2ecf20Sopenharmony_ci driver_remove_file(&megasas_pci_driver.driver, 90828c2ecf20Sopenharmony_ci &driver_attr_support_nvme_encapsulation); 90838c2ecf20Sopenharmony_ci 90848c2ecf20Sopenharmony_cierr_dcf_support_nvme_encapsulation: 90858c2ecf20Sopenharmony_ci driver_remove_file(&megasas_pci_driver.driver, 90868c2ecf20Sopenharmony_ci &driver_attr_support_device_change); 90878c2ecf20Sopenharmony_ci 90888c2ecf20Sopenharmony_cierr_dcf_support_device_change: 90898c2ecf20Sopenharmony_ci driver_remove_file(&megasas_pci_driver.driver, 90908c2ecf20Sopenharmony_ci &driver_attr_dbg_lvl); 90918c2ecf20Sopenharmony_cierr_dcf_dbg_lvl: 90928c2ecf20Sopenharmony_ci driver_remove_file(&megasas_pci_driver.driver, 90938c2ecf20Sopenharmony_ci &driver_attr_support_poll_for_event); 90948c2ecf20Sopenharmony_cierr_dcf_support_poll_for_event: 90958c2ecf20Sopenharmony_ci driver_remove_file(&megasas_pci_driver.driver, 90968c2ecf20Sopenharmony_ci &driver_attr_release_date); 90978c2ecf20Sopenharmony_cierr_dcf_rel_date: 90988c2ecf20Sopenharmony_ci driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version); 90998c2ecf20Sopenharmony_cierr_dcf_attr_ver: 91008c2ecf20Sopenharmony_ci pci_unregister_driver(&megasas_pci_driver); 91018c2ecf20Sopenharmony_cierr_pcidrv: 91028c2ecf20Sopenharmony_ci megasas_exit_debugfs(); 91038c2ecf20Sopenharmony_ci unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl"); 91048c2ecf20Sopenharmony_ci return rval; 91058c2ecf20Sopenharmony_ci} 91068c2ecf20Sopenharmony_ci 91078c2ecf20Sopenharmony_ci/** 91088c2ecf20Sopenharmony_ci * megasas_exit - Driver unload entry point 91098c2ecf20Sopenharmony_ci */ 91108c2ecf20Sopenharmony_cistatic void __exit megasas_exit(void) 91118c2ecf20Sopenharmony_ci{ 91128c2ecf20Sopenharmony_ci driver_remove_file(&megasas_pci_driver.driver, 91138c2ecf20Sopenharmony_ci &driver_attr_dbg_lvl); 91148c2ecf20Sopenharmony_ci driver_remove_file(&megasas_pci_driver.driver, 91158c2ecf20Sopenharmony_ci &driver_attr_support_poll_for_event); 91168c2ecf20Sopenharmony_ci driver_remove_file(&megasas_pci_driver.driver, 91178c2ecf20Sopenharmony_ci &driver_attr_support_device_change); 91188c2ecf20Sopenharmony_ci driver_remove_file(&megasas_pci_driver.driver, 91198c2ecf20Sopenharmony_ci &driver_attr_release_date); 91208c2ecf20Sopenharmony_ci driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version); 91218c2ecf20Sopenharmony_ci driver_remove_file(&megasas_pci_driver.driver, 91228c2ecf20Sopenharmony_ci &driver_attr_support_nvme_encapsulation); 91238c2ecf20Sopenharmony_ci driver_remove_file(&megasas_pci_driver.driver, 91248c2ecf20Sopenharmony_ci &driver_attr_support_pci_lane_margining); 91258c2ecf20Sopenharmony_ci 91268c2ecf20Sopenharmony_ci pci_unregister_driver(&megasas_pci_driver); 91278c2ecf20Sopenharmony_ci megasas_exit_debugfs(); 91288c2ecf20Sopenharmony_ci unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl"); 91298c2ecf20Sopenharmony_ci} 91308c2ecf20Sopenharmony_ci 91318c2ecf20Sopenharmony_cimodule_init(megasas_init); 91328c2ecf20Sopenharmony_cimodule_exit(megasas_exit); 9133