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) 2009-2013 LSI Corporation 68c2ecf20Sopenharmony_ci * Copyright (c) 2013-2016 Avago Technologies 78c2ecf20Sopenharmony_ci * Copyright (c) 2016-2018 Broadcom Inc. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * FILE: megaraid_sas_fusion.c 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Authors: Broadcom Inc. 128c2ecf20Sopenharmony_ci * Sumant Patro 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/uaccess.h> 318c2ecf20Sopenharmony_ci#include <linux/fs.h> 328c2ecf20Sopenharmony_ci#include <linux/compat.h> 338c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 348c2ecf20Sopenharmony_ci#include <linux/mutex.h> 358c2ecf20Sopenharmony_ci#include <linux/poll.h> 368c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 378c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 388c2ecf20Sopenharmony_ci#include <linux/irq_poll.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 418c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 428c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 438c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 448c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h> 458c2ecf20Sopenharmony_ci#include <linux/dmi.h> 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include "megaraid_sas_fusion.h" 488c2ecf20Sopenharmony_ci#include "megaraid_sas.h" 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ciextern void 528c2ecf20Sopenharmony_cimegasas_complete_cmd(struct megasas_instance *instance, 538c2ecf20Sopenharmony_ci struct megasas_cmd *cmd, u8 alt_status); 548c2ecf20Sopenharmony_ciint 558c2ecf20Sopenharmony_ciwait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd, 568c2ecf20Sopenharmony_ci int seconds); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ciint 598c2ecf20Sopenharmony_cimegasas_clear_intr_fusion(struct megasas_instance *instance); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ciint megasas_transition_to_ready(struct megasas_instance *instance, int ocr); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ciextern u32 megasas_dbg_lvl; 648c2ecf20Sopenharmony_ciint megasas_sriov_start_heartbeat(struct megasas_instance *instance, 658c2ecf20Sopenharmony_ci int initial); 668c2ecf20Sopenharmony_ciextern struct megasas_mgmt_info megasas_mgmt_info; 678c2ecf20Sopenharmony_ciextern unsigned int resetwaittime; 688c2ecf20Sopenharmony_ciextern unsigned int dual_qdepth_disable; 698c2ecf20Sopenharmony_cistatic void megasas_free_rdpq_fusion(struct megasas_instance *instance); 708c2ecf20Sopenharmony_cistatic void megasas_free_reply_fusion(struct megasas_instance *instance); 718c2ecf20Sopenharmony_cistatic inline 728c2ecf20Sopenharmony_civoid megasas_configure_queue_sizes(struct megasas_instance *instance); 738c2ecf20Sopenharmony_cistatic void megasas_fusion_crash_dump(struct megasas_instance *instance); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/** 768c2ecf20Sopenharmony_ci * megasas_adp_reset_wait_for_ready - initiate chip reset and wait for 778c2ecf20Sopenharmony_ci * controller to come to ready state 788c2ecf20Sopenharmony_ci * @instance: adapter's soft state 798c2ecf20Sopenharmony_ci * @do_adp_reset: If true, do a chip reset 808c2ecf20Sopenharmony_ci * @ocr_context: If called from OCR context this will 818c2ecf20Sopenharmony_ci * be set to 1, else 0 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * This function initates a chip reset followed by a wait for controller to 848c2ecf20Sopenharmony_ci * transition to ready state. 858c2ecf20Sopenharmony_ci * During this, driver will block all access to PCI config space from userspace 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ciint 888c2ecf20Sopenharmony_cimegasas_adp_reset_wait_for_ready(struct megasas_instance *instance, 898c2ecf20Sopenharmony_ci bool do_adp_reset, 908c2ecf20Sopenharmony_ci int ocr_context) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci int ret = FAILED; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* 958c2ecf20Sopenharmony_ci * Block access to PCI config space from userspace 968c2ecf20Sopenharmony_ci * when diag reset is initiated from driver 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & OCR_DEBUG) 998c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 1008c2ecf20Sopenharmony_ci "Block access to PCI config space %s %d\n", 1018c2ecf20Sopenharmony_ci __func__, __LINE__); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci pci_cfg_access_lock(instance->pdev); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (do_adp_reset) { 1068c2ecf20Sopenharmony_ci if (instance->instancet->adp_reset 1078c2ecf20Sopenharmony_ci (instance, instance->reg_set)) 1088c2ecf20Sopenharmony_ci goto out; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* Wait for FW to become ready */ 1128c2ecf20Sopenharmony_ci if (megasas_transition_to_ready(instance, ocr_context)) { 1138c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, 1148c2ecf20Sopenharmony_ci "Failed to transition controller to ready for scsi%d.\n", 1158c2ecf20Sopenharmony_ci instance->host->host_no); 1168c2ecf20Sopenharmony_ci goto out; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci ret = SUCCESS; 1208c2ecf20Sopenharmony_ciout: 1218c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & OCR_DEBUG) 1228c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 1238c2ecf20Sopenharmony_ci "Unlock access to PCI config space %s %d\n", 1248c2ecf20Sopenharmony_ci __func__, __LINE__); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci pci_cfg_access_unlock(instance->pdev); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci return ret; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/** 1328c2ecf20Sopenharmony_ci * megasas_check_same_4gb_region - check if allocation 1338c2ecf20Sopenharmony_ci * crosses same 4GB boundary or not 1348c2ecf20Sopenharmony_ci * @instance: adapter's soft instance 1358c2ecf20Sopenharmony_ci * @start_addr: start address of DMA allocation 1368c2ecf20Sopenharmony_ci * @size: size of allocation in bytes 1378c2ecf20Sopenharmony_ci * @return: true : allocation does not cross same 1388c2ecf20Sopenharmony_ci * 4GB boundary 1398c2ecf20Sopenharmony_ci * false: allocation crosses same 1408c2ecf20Sopenharmony_ci * 4GB boundary 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_cistatic inline bool megasas_check_same_4gb_region 1438c2ecf20Sopenharmony_ci (struct megasas_instance *instance, dma_addr_t start_addr, size_t size) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci dma_addr_t end_addr; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci end_addr = start_addr + size; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (upper_32_bits(start_addr) != upper_32_bits(end_addr)) { 1508c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 1518c2ecf20Sopenharmony_ci "Failed to get same 4GB boundary: start_addr: 0x%llx end_addr: 0x%llx\n", 1528c2ecf20Sopenharmony_ci (unsigned long long)start_addr, 1538c2ecf20Sopenharmony_ci (unsigned long long)end_addr); 1548c2ecf20Sopenharmony_ci return false; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return true; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/** 1618c2ecf20Sopenharmony_ci * megasas_enable_intr_fusion - Enables interrupts 1628c2ecf20Sopenharmony_ci * @instance: adapter's soft instance 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_cistatic void 1658c2ecf20Sopenharmony_cimegasas_enable_intr_fusion(struct megasas_instance *instance) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 1688c2ecf20Sopenharmony_ci regs = instance->reg_set; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci instance->mask_interrupts = 0; 1718c2ecf20Sopenharmony_ci /* For Thunderbolt/Invader also clear intr on enable */ 1728c2ecf20Sopenharmony_ci writel(~0, ®s->outbound_intr_status); 1738c2ecf20Sopenharmony_ci readl(®s->outbound_intr_status); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci writel(~MFI_FUSION_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* Dummy readl to force pci flush */ 1788c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n", 1798c2ecf20Sopenharmony_ci __func__, readl(®s->outbound_intr_mask)); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/** 1838c2ecf20Sopenharmony_ci * megasas_disable_intr_fusion - Disables interrupt 1848c2ecf20Sopenharmony_ci * @instance: adapter's soft instance 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_cistatic void 1878c2ecf20Sopenharmony_cimegasas_disable_intr_fusion(struct megasas_instance *instance) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci u32 mask = 0xFFFFFFFF; 1908c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 1918c2ecf20Sopenharmony_ci regs = instance->reg_set; 1928c2ecf20Sopenharmony_ci instance->mask_interrupts = 1; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci writel(mask, ®s->outbound_intr_mask); 1958c2ecf20Sopenharmony_ci /* Dummy readl to force pci flush */ 1968c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n", 1978c2ecf20Sopenharmony_ci __func__, readl(®s->outbound_intr_mask)); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ciint 2018c2ecf20Sopenharmony_cimegasas_clear_intr_fusion(struct megasas_instance *instance) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci u32 status; 2048c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs; 2058c2ecf20Sopenharmony_ci regs = instance->reg_set; 2068c2ecf20Sopenharmony_ci /* 2078c2ecf20Sopenharmony_ci * Check if it is our interrupt 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci status = megasas_readl(instance, 2108c2ecf20Sopenharmony_ci ®s->outbound_intr_status); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (status & 1) { 2138c2ecf20Sopenharmony_ci writel(status, ®s->outbound_intr_status); 2148c2ecf20Sopenharmony_ci readl(®s->outbound_intr_status); 2158c2ecf20Sopenharmony_ci return 1; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK)) 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return 1; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/** 2248c2ecf20Sopenharmony_ci * megasas_get_cmd_fusion - Get a command from the free pool 2258c2ecf20Sopenharmony_ci * @instance: Adapter soft state 2268c2ecf20Sopenharmony_ci * @blk_tag: Command tag 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * Returns a blk_tag indexed mpt frame 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ciinline struct megasas_cmd_fusion *megasas_get_cmd_fusion(struct megasas_instance 2318c2ecf20Sopenharmony_ci *instance, u32 blk_tag) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct fusion_context *fusion; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 2368c2ecf20Sopenharmony_ci return fusion->cmd_list[blk_tag]; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/** 2408c2ecf20Sopenharmony_ci * megasas_return_cmd_fusion - Return a cmd to free command pool 2418c2ecf20Sopenharmony_ci * @instance: Adapter soft state 2428c2ecf20Sopenharmony_ci * @cmd: Command packet to be returned to free command pool 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_ciinline void megasas_return_cmd_fusion(struct megasas_instance *instance, 2458c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci cmd->scmd = NULL; 2488c2ecf20Sopenharmony_ci memset(cmd->io_request, 0, MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE); 2498c2ecf20Sopenharmony_ci cmd->r1_alt_dev_handle = MR_DEVHANDLE_INVALID; 2508c2ecf20Sopenharmony_ci cmd->cmd_completed = false; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/** 2548c2ecf20Sopenharmony_ci * megasas_write_64bit_req_desc - PCI writes 64bit request descriptor 2558c2ecf20Sopenharmony_ci * @instance: Adapter soft state 2568c2ecf20Sopenharmony_ci * @req_desc: 64bit Request descriptor 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_cistatic void 2598c2ecf20Sopenharmony_cimegasas_write_64bit_req_desc(struct megasas_instance *instance, 2608c2ecf20Sopenharmony_ci union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci#if defined(writeq) && defined(CONFIG_64BIT) 2638c2ecf20Sopenharmony_ci u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) | 2648c2ecf20Sopenharmony_ci le32_to_cpu(req_desc->u.low)); 2658c2ecf20Sopenharmony_ci writeq(req_data, &instance->reg_set->inbound_low_queue_port); 2668c2ecf20Sopenharmony_ci#else 2678c2ecf20Sopenharmony_ci unsigned long flags; 2688c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->hba_lock, flags); 2698c2ecf20Sopenharmony_ci writel(le32_to_cpu(req_desc->u.low), 2708c2ecf20Sopenharmony_ci &instance->reg_set->inbound_low_queue_port); 2718c2ecf20Sopenharmony_ci writel(le32_to_cpu(req_desc->u.high), 2728c2ecf20Sopenharmony_ci &instance->reg_set->inbound_high_queue_port); 2738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->hba_lock, flags); 2748c2ecf20Sopenharmony_ci#endif 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci/** 2788c2ecf20Sopenharmony_ci * megasas_fire_cmd_fusion - Sends command to the FW 2798c2ecf20Sopenharmony_ci * @instance: Adapter soft state 2808c2ecf20Sopenharmony_ci * @req_desc: 32bit or 64bit Request descriptor 2818c2ecf20Sopenharmony_ci * 2828c2ecf20Sopenharmony_ci * Perform PCI Write. AERO SERIES supports 32 bit Descriptor. 2838c2ecf20Sopenharmony_ci * Prior to AERO_SERIES support 64 bit Descriptor. 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistatic void 2868c2ecf20Sopenharmony_cimegasas_fire_cmd_fusion(struct megasas_instance *instance, 2878c2ecf20Sopenharmony_ci union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci if (instance->atomic_desc_support) 2908c2ecf20Sopenharmony_ci writel(le32_to_cpu(req_desc->u.low), 2918c2ecf20Sopenharmony_ci &instance->reg_set->inbound_single_queue_port); 2928c2ecf20Sopenharmony_ci else 2938c2ecf20Sopenharmony_ci megasas_write_64bit_req_desc(instance, req_desc); 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci/** 2978c2ecf20Sopenharmony_ci * megasas_fusion_update_can_queue - Do all Adapter Queue depth related calculations here 2988c2ecf20Sopenharmony_ci * @instance: Adapter soft state 2998c2ecf20Sopenharmony_ci * @fw_boot_context: Whether this function called during probe or after OCR 3008c2ecf20Sopenharmony_ci * 3018c2ecf20Sopenharmony_ci * This function is only for fusion controllers. 3028c2ecf20Sopenharmony_ci * Update host can queue, if firmware downgrade max supported firmware commands. 3038c2ecf20Sopenharmony_ci * Firmware upgrade case will be skiped because underlying firmware has 3048c2ecf20Sopenharmony_ci * more resource than exposed to the OS. 3058c2ecf20Sopenharmony_ci * 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_cistatic void 3088c2ecf20Sopenharmony_cimegasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_context) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci u16 cur_max_fw_cmds = 0; 3118c2ecf20Sopenharmony_ci u16 ldio_threshold = 0; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* ventura FW does not fill outbound_scratch_pad_2 with queue depth */ 3148c2ecf20Sopenharmony_ci if (instance->adapter_type < VENTURA_SERIES) 3158c2ecf20Sopenharmony_ci cur_max_fw_cmds = 3168c2ecf20Sopenharmony_ci megasas_readl(instance, 3178c2ecf20Sopenharmony_ci &instance->reg_set->outbound_scratch_pad_2) & 0x00FFFF; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (dual_qdepth_disable || !cur_max_fw_cmds) 3208c2ecf20Sopenharmony_ci cur_max_fw_cmds = instance->instancet->read_fw_status_reg(instance) & 0x00FFFF; 3218c2ecf20Sopenharmony_ci else 3228c2ecf20Sopenharmony_ci ldio_threshold = 3238c2ecf20Sopenharmony_ci (instance->instancet->read_fw_status_reg(instance) & 0x00FFFF) - MEGASAS_FUSION_IOCTL_CMDS; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 3268c2ecf20Sopenharmony_ci "Current firmware supports maximum commands: %d\t LDIO threshold: %d\n", 3278c2ecf20Sopenharmony_ci cur_max_fw_cmds, ldio_threshold); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (fw_boot_context == OCR_CONTEXT) { 3308c2ecf20Sopenharmony_ci cur_max_fw_cmds = cur_max_fw_cmds - 1; 3318c2ecf20Sopenharmony_ci if (cur_max_fw_cmds < instance->max_fw_cmds) { 3328c2ecf20Sopenharmony_ci instance->cur_can_queue = 3338c2ecf20Sopenharmony_ci cur_max_fw_cmds - (MEGASAS_FUSION_INTERNAL_CMDS + 3348c2ecf20Sopenharmony_ci MEGASAS_FUSION_IOCTL_CMDS); 3358c2ecf20Sopenharmony_ci instance->host->can_queue = instance->cur_can_queue; 3368c2ecf20Sopenharmony_ci instance->ldio_threshold = ldio_threshold; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci } else { 3398c2ecf20Sopenharmony_ci instance->max_fw_cmds = cur_max_fw_cmds; 3408c2ecf20Sopenharmony_ci instance->ldio_threshold = ldio_threshold; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (reset_devices) 3438c2ecf20Sopenharmony_ci instance->max_fw_cmds = min(instance->max_fw_cmds, 3448c2ecf20Sopenharmony_ci (u16)MEGASAS_KDUMP_QUEUE_DEPTH); 3458c2ecf20Sopenharmony_ci /* 3468c2ecf20Sopenharmony_ci * Reduce the max supported cmds by 1. This is to ensure that the 3478c2ecf20Sopenharmony_ci * reply_q_sz (1 more than the max cmd that driver may send) 3488c2ecf20Sopenharmony_ci * does not exceed max cmds that the FW can support 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci instance->max_fw_cmds = instance->max_fw_cmds-1; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic inline void 3558c2ecf20Sopenharmony_cimegasas_get_msix_index(struct megasas_instance *instance, 3568c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd, 3578c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd, 3588c2ecf20Sopenharmony_ci u8 data_arms) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci int sdev_busy; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* TBD - if sml remove device_busy in future, driver 3638c2ecf20Sopenharmony_ci * should track counter in internal structure. 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_ci sdev_busy = atomic_read(&scmd->device->device_busy); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (instance->perf_mode == MR_BALANCED_PERF_MODE && 3688c2ecf20Sopenharmony_ci sdev_busy > (data_arms * MR_DEVICE_HIGH_IOPS_DEPTH)) { 3698c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.MSIxIndex = 3708c2ecf20Sopenharmony_ci mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) / 3718c2ecf20Sopenharmony_ci MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start); 3728c2ecf20Sopenharmony_ci } else if (instance->msix_load_balance) { 3738c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.MSIxIndex = 3748c2ecf20Sopenharmony_ci (mega_mod64(atomic64_add_return(1, &instance->total_io_count), 3758c2ecf20Sopenharmony_ci instance->msix_vectors)); 3768c2ecf20Sopenharmony_ci } else if (instance->host->nr_hw_queues > 1) { 3778c2ecf20Sopenharmony_ci u32 tag = blk_mq_unique_tag(scmd->request); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.MSIxIndex = blk_mq_unique_tag_to_hwq(tag) + 3808c2ecf20Sopenharmony_ci instance->low_latency_index_start; 3818c2ecf20Sopenharmony_ci } else { 3828c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.MSIxIndex = 3838c2ecf20Sopenharmony_ci instance->reply_map[raw_smp_processor_id()]; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci/** 3888c2ecf20Sopenharmony_ci * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool 3898c2ecf20Sopenharmony_ci * @instance: Adapter soft state 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_civoid 3928c2ecf20Sopenharmony_cimegasas_free_cmds_fusion(struct megasas_instance *instance) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci int i; 3958c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 3968c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (fusion->sense) 3998c2ecf20Sopenharmony_ci dma_pool_free(fusion->sense_dma_pool, fusion->sense, 4008c2ecf20Sopenharmony_ci fusion->sense_phys_addr); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /* SG */ 4038c2ecf20Sopenharmony_ci if (fusion->cmd_list) { 4048c2ecf20Sopenharmony_ci for (i = 0; i < instance->max_mpt_cmds; i++) { 4058c2ecf20Sopenharmony_ci cmd = fusion->cmd_list[i]; 4068c2ecf20Sopenharmony_ci if (cmd) { 4078c2ecf20Sopenharmony_ci if (cmd->sg_frame) 4088c2ecf20Sopenharmony_ci dma_pool_free(fusion->sg_dma_pool, 4098c2ecf20Sopenharmony_ci cmd->sg_frame, 4108c2ecf20Sopenharmony_ci cmd->sg_frame_phys_addr); 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci kfree(cmd); 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci kfree(fusion->cmd_list); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (fusion->sg_dma_pool) { 4188c2ecf20Sopenharmony_ci dma_pool_destroy(fusion->sg_dma_pool); 4198c2ecf20Sopenharmony_ci fusion->sg_dma_pool = NULL; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci if (fusion->sense_dma_pool) { 4228c2ecf20Sopenharmony_ci dma_pool_destroy(fusion->sense_dma_pool); 4238c2ecf20Sopenharmony_ci fusion->sense_dma_pool = NULL; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* Reply Frame, Desc*/ 4288c2ecf20Sopenharmony_ci if (instance->is_rdpq) 4298c2ecf20Sopenharmony_ci megasas_free_rdpq_fusion(instance); 4308c2ecf20Sopenharmony_ci else 4318c2ecf20Sopenharmony_ci megasas_free_reply_fusion(instance); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* Request Frame, Desc*/ 4348c2ecf20Sopenharmony_ci if (fusion->req_frames_desc) 4358c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, 4368c2ecf20Sopenharmony_ci fusion->request_alloc_sz, fusion->req_frames_desc, 4378c2ecf20Sopenharmony_ci fusion->req_frames_desc_phys); 4388c2ecf20Sopenharmony_ci if (fusion->io_request_frames) 4398c2ecf20Sopenharmony_ci dma_pool_free(fusion->io_request_frames_pool, 4408c2ecf20Sopenharmony_ci fusion->io_request_frames, 4418c2ecf20Sopenharmony_ci fusion->io_request_frames_phys); 4428c2ecf20Sopenharmony_ci if (fusion->io_request_frames_pool) { 4438c2ecf20Sopenharmony_ci dma_pool_destroy(fusion->io_request_frames_pool); 4448c2ecf20Sopenharmony_ci fusion->io_request_frames_pool = NULL; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/** 4498c2ecf20Sopenharmony_ci * megasas_create_sg_sense_fusion - Creates DMA pool for cmd frames 4508c2ecf20Sopenharmony_ci * @instance: Adapter soft state 4518c2ecf20Sopenharmony_ci * 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_cistatic int megasas_create_sg_sense_fusion(struct megasas_instance *instance) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci int i; 4568c2ecf20Sopenharmony_ci u16 max_cmd; 4578c2ecf20Sopenharmony_ci struct fusion_context *fusion; 4588c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd; 4598c2ecf20Sopenharmony_ci int sense_sz; 4608c2ecf20Sopenharmony_ci u32 offset; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 4638c2ecf20Sopenharmony_ci max_cmd = instance->max_fw_cmds; 4648c2ecf20Sopenharmony_ci sense_sz = instance->max_mpt_cmds * SCSI_SENSE_BUFFERSIZE; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci fusion->sg_dma_pool = 4678c2ecf20Sopenharmony_ci dma_pool_create("mr_sg", &instance->pdev->dev, 4688c2ecf20Sopenharmony_ci instance->max_chain_frame_sz, 4698c2ecf20Sopenharmony_ci MR_DEFAULT_NVME_PAGE_SIZE, 0); 4708c2ecf20Sopenharmony_ci /* SCSI_SENSE_BUFFERSIZE = 96 bytes */ 4718c2ecf20Sopenharmony_ci fusion->sense_dma_pool = 4728c2ecf20Sopenharmony_ci dma_pool_create("mr_sense", &instance->pdev->dev, 4738c2ecf20Sopenharmony_ci sense_sz, 64, 0); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (!fusion->sense_dma_pool || !fusion->sg_dma_pool) { 4768c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 4778c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 4788c2ecf20Sopenharmony_ci return -ENOMEM; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci fusion->sense = dma_pool_alloc(fusion->sense_dma_pool, 4828c2ecf20Sopenharmony_ci GFP_KERNEL, &fusion->sense_phys_addr); 4838c2ecf20Sopenharmony_ci if (!fusion->sense) { 4848c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 4858c2ecf20Sopenharmony_ci "failed from %s %d\n", __func__, __LINE__); 4868c2ecf20Sopenharmony_ci return -ENOMEM; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* sense buffer, request frame and reply desc pool requires to be in 4908c2ecf20Sopenharmony_ci * same 4 gb region. Below function will check this. 4918c2ecf20Sopenharmony_ci * In case of failure, new pci pool will be created with updated 4928c2ecf20Sopenharmony_ci * alignment. 4938c2ecf20Sopenharmony_ci * Older allocation and pool will be destroyed. 4948c2ecf20Sopenharmony_ci * Alignment will be used such a way that next allocation if success, 4958c2ecf20Sopenharmony_ci * will always meet same 4gb region requirement. 4968c2ecf20Sopenharmony_ci * Actual requirement is not alignment, but we need start and end of 4978c2ecf20Sopenharmony_ci * DMA address must have same upper 32 bit address. 4988c2ecf20Sopenharmony_ci */ 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (!megasas_check_same_4gb_region(instance, fusion->sense_phys_addr, 5018c2ecf20Sopenharmony_ci sense_sz)) { 5028c2ecf20Sopenharmony_ci dma_pool_free(fusion->sense_dma_pool, fusion->sense, 5038c2ecf20Sopenharmony_ci fusion->sense_phys_addr); 5048c2ecf20Sopenharmony_ci fusion->sense = NULL; 5058c2ecf20Sopenharmony_ci dma_pool_destroy(fusion->sense_dma_pool); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci fusion->sense_dma_pool = 5088c2ecf20Sopenharmony_ci dma_pool_create("mr_sense_align", &instance->pdev->dev, 5098c2ecf20Sopenharmony_ci sense_sz, roundup_pow_of_two(sense_sz), 5108c2ecf20Sopenharmony_ci 0); 5118c2ecf20Sopenharmony_ci if (!fusion->sense_dma_pool) { 5128c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 5138c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 5148c2ecf20Sopenharmony_ci return -ENOMEM; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci fusion->sense = dma_pool_alloc(fusion->sense_dma_pool, 5178c2ecf20Sopenharmony_ci GFP_KERNEL, 5188c2ecf20Sopenharmony_ci &fusion->sense_phys_addr); 5198c2ecf20Sopenharmony_ci if (!fusion->sense) { 5208c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 5218c2ecf20Sopenharmony_ci "failed from %s %d\n", __func__, __LINE__); 5228c2ecf20Sopenharmony_ci return -ENOMEM; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci /* 5278c2ecf20Sopenharmony_ci * Allocate and attach a frame to each of the commands in cmd_list 5288c2ecf20Sopenharmony_ci */ 5298c2ecf20Sopenharmony_ci for (i = 0; i < max_cmd; i++) { 5308c2ecf20Sopenharmony_ci cmd = fusion->cmd_list[i]; 5318c2ecf20Sopenharmony_ci cmd->sg_frame = dma_pool_alloc(fusion->sg_dma_pool, 5328c2ecf20Sopenharmony_ci GFP_KERNEL, &cmd->sg_frame_phys_addr); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci offset = SCSI_SENSE_BUFFERSIZE * i; 5358c2ecf20Sopenharmony_ci cmd->sense = (u8 *)fusion->sense + offset; 5368c2ecf20Sopenharmony_ci cmd->sense_phys_addr = fusion->sense_phys_addr + offset; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (!cmd->sg_frame) { 5398c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 5408c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 5418c2ecf20Sopenharmony_ci return -ENOMEM; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* create sense buffer for the raid 1/10 fp */ 5468c2ecf20Sopenharmony_ci for (i = max_cmd; i < instance->max_mpt_cmds; i++) { 5478c2ecf20Sopenharmony_ci cmd = fusion->cmd_list[i]; 5488c2ecf20Sopenharmony_ci offset = SCSI_SENSE_BUFFERSIZE * i; 5498c2ecf20Sopenharmony_ci cmd->sense = (u8 *)fusion->sense + offset; 5508c2ecf20Sopenharmony_ci cmd->sense_phys_addr = fusion->sense_phys_addr + offset; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return 0; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic int 5588c2ecf20Sopenharmony_cimegasas_alloc_cmdlist_fusion(struct megasas_instance *instance) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci u32 max_mpt_cmd, i, j; 5618c2ecf20Sopenharmony_ci struct fusion_context *fusion; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci max_mpt_cmd = instance->max_mpt_cmds; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* 5688c2ecf20Sopenharmony_ci * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers. 5698c2ecf20Sopenharmony_ci * Allocate the dynamic array first and then allocate individual 5708c2ecf20Sopenharmony_ci * commands. 5718c2ecf20Sopenharmony_ci */ 5728c2ecf20Sopenharmony_ci fusion->cmd_list = 5738c2ecf20Sopenharmony_ci kcalloc(max_mpt_cmd, sizeof(struct megasas_cmd_fusion *), 5748c2ecf20Sopenharmony_ci GFP_KERNEL); 5758c2ecf20Sopenharmony_ci if (!fusion->cmd_list) { 5768c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 5778c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 5788c2ecf20Sopenharmony_ci return -ENOMEM; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci for (i = 0; i < max_mpt_cmd; i++) { 5828c2ecf20Sopenharmony_ci fusion->cmd_list[i] = kzalloc(sizeof(struct megasas_cmd_fusion), 5838c2ecf20Sopenharmony_ci GFP_KERNEL); 5848c2ecf20Sopenharmony_ci if (!fusion->cmd_list[i]) { 5858c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) 5868c2ecf20Sopenharmony_ci kfree(fusion->cmd_list[j]); 5878c2ecf20Sopenharmony_ci kfree(fusion->cmd_list); 5888c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 5898c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 5908c2ecf20Sopenharmony_ci return -ENOMEM; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return 0; 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int 5988c2ecf20Sopenharmony_cimegasas_alloc_request_fusion(struct megasas_instance *instance) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci struct fusion_context *fusion; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ciretry_alloc: 6058c2ecf20Sopenharmony_ci fusion->io_request_frames_pool = 6068c2ecf20Sopenharmony_ci dma_pool_create("mr_ioreq", &instance->pdev->dev, 6078c2ecf20Sopenharmony_ci fusion->io_frames_alloc_sz, 16, 0); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (!fusion->io_request_frames_pool) { 6108c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 6118c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 6128c2ecf20Sopenharmony_ci return -ENOMEM; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci fusion->io_request_frames = 6168c2ecf20Sopenharmony_ci dma_pool_alloc(fusion->io_request_frames_pool, 6178c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_NOWARN, 6188c2ecf20Sopenharmony_ci &fusion->io_request_frames_phys); 6198c2ecf20Sopenharmony_ci if (!fusion->io_request_frames) { 6208c2ecf20Sopenharmony_ci if (instance->max_fw_cmds >= (MEGASAS_REDUCE_QD_COUNT * 2)) { 6218c2ecf20Sopenharmony_ci instance->max_fw_cmds -= MEGASAS_REDUCE_QD_COUNT; 6228c2ecf20Sopenharmony_ci dma_pool_destroy(fusion->io_request_frames_pool); 6238c2ecf20Sopenharmony_ci megasas_configure_queue_sizes(instance); 6248c2ecf20Sopenharmony_ci goto retry_alloc; 6258c2ecf20Sopenharmony_ci } else { 6268c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 6278c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 6288c2ecf20Sopenharmony_ci return -ENOMEM; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (!megasas_check_same_4gb_region(instance, 6338c2ecf20Sopenharmony_ci fusion->io_request_frames_phys, 6348c2ecf20Sopenharmony_ci fusion->io_frames_alloc_sz)) { 6358c2ecf20Sopenharmony_ci dma_pool_free(fusion->io_request_frames_pool, 6368c2ecf20Sopenharmony_ci fusion->io_request_frames, 6378c2ecf20Sopenharmony_ci fusion->io_request_frames_phys); 6388c2ecf20Sopenharmony_ci fusion->io_request_frames = NULL; 6398c2ecf20Sopenharmony_ci dma_pool_destroy(fusion->io_request_frames_pool); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci fusion->io_request_frames_pool = 6428c2ecf20Sopenharmony_ci dma_pool_create("mr_ioreq_align", 6438c2ecf20Sopenharmony_ci &instance->pdev->dev, 6448c2ecf20Sopenharmony_ci fusion->io_frames_alloc_sz, 6458c2ecf20Sopenharmony_ci roundup_pow_of_two(fusion->io_frames_alloc_sz), 6468c2ecf20Sopenharmony_ci 0); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (!fusion->io_request_frames_pool) { 6498c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 6508c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 6518c2ecf20Sopenharmony_ci return -ENOMEM; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci fusion->io_request_frames = 6558c2ecf20Sopenharmony_ci dma_pool_alloc(fusion->io_request_frames_pool, 6568c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_NOWARN, 6578c2ecf20Sopenharmony_ci &fusion->io_request_frames_phys); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (!fusion->io_request_frames) { 6608c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 6618c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 6628c2ecf20Sopenharmony_ci return -ENOMEM; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci fusion->req_frames_desc = 6678c2ecf20Sopenharmony_ci dma_alloc_coherent(&instance->pdev->dev, 6688c2ecf20Sopenharmony_ci fusion->request_alloc_sz, 6698c2ecf20Sopenharmony_ci &fusion->req_frames_desc_phys, GFP_KERNEL); 6708c2ecf20Sopenharmony_ci if (!fusion->req_frames_desc) { 6718c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 6728c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 6738c2ecf20Sopenharmony_ci return -ENOMEM; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci return 0; 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cistatic int 6808c2ecf20Sopenharmony_cimegasas_alloc_reply_fusion(struct megasas_instance *instance) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci int i, count; 6838c2ecf20Sopenharmony_ci struct fusion_context *fusion; 6848c2ecf20Sopenharmony_ci union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; 6858c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; 6888c2ecf20Sopenharmony_ci fusion->reply_frames_desc_pool = 6898c2ecf20Sopenharmony_ci dma_pool_create("mr_reply", &instance->pdev->dev, 6908c2ecf20Sopenharmony_ci fusion->reply_alloc_sz * count, 16, 0); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (!fusion->reply_frames_desc_pool) { 6938c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 6948c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 6958c2ecf20Sopenharmony_ci return -ENOMEM; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci fusion->reply_frames_desc[0] = 6998c2ecf20Sopenharmony_ci dma_pool_alloc(fusion->reply_frames_desc_pool, 7008c2ecf20Sopenharmony_ci GFP_KERNEL, &fusion->reply_frames_desc_phys[0]); 7018c2ecf20Sopenharmony_ci if (!fusion->reply_frames_desc[0]) { 7028c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 7038c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 7048c2ecf20Sopenharmony_ci return -ENOMEM; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (!megasas_check_same_4gb_region(instance, 7088c2ecf20Sopenharmony_ci fusion->reply_frames_desc_phys[0], 7098c2ecf20Sopenharmony_ci (fusion->reply_alloc_sz * count))) { 7108c2ecf20Sopenharmony_ci dma_pool_free(fusion->reply_frames_desc_pool, 7118c2ecf20Sopenharmony_ci fusion->reply_frames_desc[0], 7128c2ecf20Sopenharmony_ci fusion->reply_frames_desc_phys[0]); 7138c2ecf20Sopenharmony_ci fusion->reply_frames_desc[0] = NULL; 7148c2ecf20Sopenharmony_ci dma_pool_destroy(fusion->reply_frames_desc_pool); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci fusion->reply_frames_desc_pool = 7178c2ecf20Sopenharmony_ci dma_pool_create("mr_reply_align", 7188c2ecf20Sopenharmony_ci &instance->pdev->dev, 7198c2ecf20Sopenharmony_ci fusion->reply_alloc_sz * count, 7208c2ecf20Sopenharmony_ci roundup_pow_of_two(fusion->reply_alloc_sz * count), 7218c2ecf20Sopenharmony_ci 0); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (!fusion->reply_frames_desc_pool) { 7248c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 7258c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 7268c2ecf20Sopenharmony_ci return -ENOMEM; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci fusion->reply_frames_desc[0] = 7308c2ecf20Sopenharmony_ci dma_pool_alloc(fusion->reply_frames_desc_pool, 7318c2ecf20Sopenharmony_ci GFP_KERNEL, 7328c2ecf20Sopenharmony_ci &fusion->reply_frames_desc_phys[0]); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci if (!fusion->reply_frames_desc[0]) { 7358c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 7368c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 7378c2ecf20Sopenharmony_ci return -ENOMEM; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci reply_desc = fusion->reply_frames_desc[0]; 7428c2ecf20Sopenharmony_ci for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++) 7438c2ecf20Sopenharmony_ci reply_desc->Words = cpu_to_le64(ULLONG_MAX); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* This is not a rdpq mode, but driver still populate 7468c2ecf20Sopenharmony_ci * reply_frame_desc array to use same msix index in ISR path. 7478c2ecf20Sopenharmony_ci */ 7488c2ecf20Sopenharmony_ci for (i = 0; i < (count - 1); i++) 7498c2ecf20Sopenharmony_ci fusion->reply_frames_desc[i + 1] = 7508c2ecf20Sopenharmony_ci fusion->reply_frames_desc[i] + 7518c2ecf20Sopenharmony_ci (fusion->reply_alloc_sz)/sizeof(union MPI2_REPLY_DESCRIPTORS_UNION); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci return 0; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic int 7578c2ecf20Sopenharmony_cimegasas_alloc_rdpq_fusion(struct megasas_instance *instance) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci int i, j, k, msix_count; 7608c2ecf20Sopenharmony_ci struct fusion_context *fusion; 7618c2ecf20Sopenharmony_ci union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; 7628c2ecf20Sopenharmony_ci union MPI2_REPLY_DESCRIPTORS_UNION *rdpq_chunk_virt[RDPQ_MAX_CHUNK_COUNT]; 7638c2ecf20Sopenharmony_ci dma_addr_t rdpq_chunk_phys[RDPQ_MAX_CHUNK_COUNT]; 7648c2ecf20Sopenharmony_ci u8 dma_alloc_count, abs_index; 7658c2ecf20Sopenharmony_ci u32 chunk_size, array_size, offset; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 7688c2ecf20Sopenharmony_ci chunk_size = fusion->reply_alloc_sz * RDPQ_MAX_INDEX_IN_ONE_CHUNK; 7698c2ecf20Sopenharmony_ci array_size = sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * 7708c2ecf20Sopenharmony_ci MAX_MSIX_QUEUES_FUSION; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci fusion->rdpq_virt = dma_alloc_coherent(&instance->pdev->dev, 7738c2ecf20Sopenharmony_ci array_size, &fusion->rdpq_phys, 7748c2ecf20Sopenharmony_ci GFP_KERNEL); 7758c2ecf20Sopenharmony_ci if (!fusion->rdpq_virt) { 7768c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 7778c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 7788c2ecf20Sopenharmony_ci return -ENOMEM; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci msix_count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci fusion->reply_frames_desc_pool = dma_pool_create("mr_rdpq", 7848c2ecf20Sopenharmony_ci &instance->pdev->dev, 7858c2ecf20Sopenharmony_ci chunk_size, 16, 0); 7868c2ecf20Sopenharmony_ci fusion->reply_frames_desc_pool_align = 7878c2ecf20Sopenharmony_ci dma_pool_create("mr_rdpq_align", 7888c2ecf20Sopenharmony_ci &instance->pdev->dev, 7898c2ecf20Sopenharmony_ci chunk_size, 7908c2ecf20Sopenharmony_ci roundup_pow_of_two(chunk_size), 7918c2ecf20Sopenharmony_ci 0); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (!fusion->reply_frames_desc_pool || 7948c2ecf20Sopenharmony_ci !fusion->reply_frames_desc_pool_align) { 7958c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 7968c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 7978c2ecf20Sopenharmony_ci return -ENOMEM; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci/* 8018c2ecf20Sopenharmony_ci * For INVADER_SERIES each set of 8 reply queues(0-7, 8-15, ..) and 8028c2ecf20Sopenharmony_ci * VENTURA_SERIES each set of 16 reply queues(0-15, 16-31, ..) should be 8038c2ecf20Sopenharmony_ci * within 4GB boundary and also reply queues in a set must have same 8048c2ecf20Sopenharmony_ci * upper 32-bits in their memory address. so here driver is allocating the 8058c2ecf20Sopenharmony_ci * DMA'able memory for reply queues according. Driver uses limitation of 8068c2ecf20Sopenharmony_ci * VENTURA_SERIES to manage INVADER_SERIES as well. 8078c2ecf20Sopenharmony_ci */ 8088c2ecf20Sopenharmony_ci dma_alloc_count = DIV_ROUND_UP(msix_count, RDPQ_MAX_INDEX_IN_ONE_CHUNK); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci for (i = 0; i < dma_alloc_count; i++) { 8118c2ecf20Sopenharmony_ci rdpq_chunk_virt[i] = 8128c2ecf20Sopenharmony_ci dma_pool_alloc(fusion->reply_frames_desc_pool, 8138c2ecf20Sopenharmony_ci GFP_KERNEL, &rdpq_chunk_phys[i]); 8148c2ecf20Sopenharmony_ci if (!rdpq_chunk_virt[i]) { 8158c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 8168c2ecf20Sopenharmony_ci "Failed from %s %d\n", __func__, __LINE__); 8178c2ecf20Sopenharmony_ci return -ENOMEM; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci /* reply desc pool requires to be in same 4 gb region. 8208c2ecf20Sopenharmony_ci * Below function will check this. 8218c2ecf20Sopenharmony_ci * In case of failure, new pci pool will be created with updated 8228c2ecf20Sopenharmony_ci * alignment. 8238c2ecf20Sopenharmony_ci * For RDPQ buffers, driver always allocate two separate pci pool. 8248c2ecf20Sopenharmony_ci * Alignment will be used such a way that next allocation if 8258c2ecf20Sopenharmony_ci * success, will always meet same 4gb region requirement. 8268c2ecf20Sopenharmony_ci * rdpq_tracker keep track of each buffer's physical, 8278c2ecf20Sopenharmony_ci * virtual address and pci pool descriptor. It will help driver 8288c2ecf20Sopenharmony_ci * while freeing the resources. 8298c2ecf20Sopenharmony_ci * 8308c2ecf20Sopenharmony_ci */ 8318c2ecf20Sopenharmony_ci if (!megasas_check_same_4gb_region(instance, rdpq_chunk_phys[i], 8328c2ecf20Sopenharmony_ci chunk_size)) { 8338c2ecf20Sopenharmony_ci dma_pool_free(fusion->reply_frames_desc_pool, 8348c2ecf20Sopenharmony_ci rdpq_chunk_virt[i], 8358c2ecf20Sopenharmony_ci rdpq_chunk_phys[i]); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci rdpq_chunk_virt[i] = 8388c2ecf20Sopenharmony_ci dma_pool_alloc(fusion->reply_frames_desc_pool_align, 8398c2ecf20Sopenharmony_ci GFP_KERNEL, &rdpq_chunk_phys[i]); 8408c2ecf20Sopenharmony_ci if (!rdpq_chunk_virt[i]) { 8418c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 8428c2ecf20Sopenharmony_ci "Failed from %s %d\n", 8438c2ecf20Sopenharmony_ci __func__, __LINE__); 8448c2ecf20Sopenharmony_ci return -ENOMEM; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci fusion->rdpq_tracker[i].dma_pool_ptr = 8478c2ecf20Sopenharmony_ci fusion->reply_frames_desc_pool_align; 8488c2ecf20Sopenharmony_ci } else { 8498c2ecf20Sopenharmony_ci fusion->rdpq_tracker[i].dma_pool_ptr = 8508c2ecf20Sopenharmony_ci fusion->reply_frames_desc_pool; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci fusion->rdpq_tracker[i].pool_entry_phys = rdpq_chunk_phys[i]; 8548c2ecf20Sopenharmony_ci fusion->rdpq_tracker[i].pool_entry_virt = rdpq_chunk_virt[i]; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci for (k = 0; k < dma_alloc_count; k++) { 8588c2ecf20Sopenharmony_ci for (i = 0; i < RDPQ_MAX_INDEX_IN_ONE_CHUNK; i++) { 8598c2ecf20Sopenharmony_ci abs_index = (k * RDPQ_MAX_INDEX_IN_ONE_CHUNK) + i; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (abs_index == msix_count) 8628c2ecf20Sopenharmony_ci break; 8638c2ecf20Sopenharmony_ci offset = fusion->reply_alloc_sz * i; 8648c2ecf20Sopenharmony_ci fusion->rdpq_virt[abs_index].RDPQBaseAddress = 8658c2ecf20Sopenharmony_ci cpu_to_le64(rdpq_chunk_phys[k] + offset); 8668c2ecf20Sopenharmony_ci fusion->reply_frames_desc_phys[abs_index] = 8678c2ecf20Sopenharmony_ci rdpq_chunk_phys[k] + offset; 8688c2ecf20Sopenharmony_ci fusion->reply_frames_desc[abs_index] = 8698c2ecf20Sopenharmony_ci (union MPI2_REPLY_DESCRIPTORS_UNION *)((u8 *)rdpq_chunk_virt[k] + offset); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci reply_desc = fusion->reply_frames_desc[abs_index]; 8728c2ecf20Sopenharmony_ci for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++) 8738c2ecf20Sopenharmony_ci reply_desc->Words = ULLONG_MAX; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci return 0; 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cistatic void 8818c2ecf20Sopenharmony_cimegasas_free_rdpq_fusion(struct megasas_instance *instance) { 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci int i; 8848c2ecf20Sopenharmony_ci struct fusion_context *fusion; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci for (i = 0; i < RDPQ_MAX_CHUNK_COUNT; i++) { 8898c2ecf20Sopenharmony_ci if (fusion->rdpq_tracker[i].pool_entry_virt) 8908c2ecf20Sopenharmony_ci dma_pool_free(fusion->rdpq_tracker[i].dma_pool_ptr, 8918c2ecf20Sopenharmony_ci fusion->rdpq_tracker[i].pool_entry_virt, 8928c2ecf20Sopenharmony_ci fusion->rdpq_tracker[i].pool_entry_phys); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci dma_pool_destroy(fusion->reply_frames_desc_pool); 8978c2ecf20Sopenharmony_ci dma_pool_destroy(fusion->reply_frames_desc_pool_align); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci if (fusion->rdpq_virt) 9008c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, 9018c2ecf20Sopenharmony_ci sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION, 9028c2ecf20Sopenharmony_ci fusion->rdpq_virt, fusion->rdpq_phys); 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic void 9068c2ecf20Sopenharmony_cimegasas_free_reply_fusion(struct megasas_instance *instance) { 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci struct fusion_context *fusion; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if (fusion->reply_frames_desc[0]) 9138c2ecf20Sopenharmony_ci dma_pool_free(fusion->reply_frames_desc_pool, 9148c2ecf20Sopenharmony_ci fusion->reply_frames_desc[0], 9158c2ecf20Sopenharmony_ci fusion->reply_frames_desc_phys[0]); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci dma_pool_destroy(fusion->reply_frames_desc_pool); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci/** 9238c2ecf20Sopenharmony_ci * megasas_alloc_cmds_fusion - Allocates the command packets 9248c2ecf20Sopenharmony_ci * @instance: Adapter soft state 9258c2ecf20Sopenharmony_ci * 9268c2ecf20Sopenharmony_ci * 9278c2ecf20Sopenharmony_ci * Each frame has a 32-bit field called context. This context is used to get 9288c2ecf20Sopenharmony_ci * back the megasas_cmd_fusion from the frame when a frame gets completed 9298c2ecf20Sopenharmony_ci * In this driver, the 32 bit values are the indices into an array cmd_list. 9308c2ecf20Sopenharmony_ci * This array is used only to look up the megasas_cmd_fusion given the context. 9318c2ecf20Sopenharmony_ci * The free commands themselves are maintained in a linked list called cmd_pool. 9328c2ecf20Sopenharmony_ci * 9338c2ecf20Sopenharmony_ci * cmds are formed in the io_request and sg_frame members of the 9348c2ecf20Sopenharmony_ci * megasas_cmd_fusion. The context field is used to get a request descriptor 9358c2ecf20Sopenharmony_ci * and is used as SMID of the cmd. 9368c2ecf20Sopenharmony_ci * SMID value range is from 1 to max_fw_cmds. 9378c2ecf20Sopenharmony_ci */ 9388c2ecf20Sopenharmony_cistatic int 9398c2ecf20Sopenharmony_cimegasas_alloc_cmds_fusion(struct megasas_instance *instance) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci int i; 9428c2ecf20Sopenharmony_ci struct fusion_context *fusion; 9438c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd; 9448c2ecf20Sopenharmony_ci u32 offset; 9458c2ecf20Sopenharmony_ci dma_addr_t io_req_base_phys; 9468c2ecf20Sopenharmony_ci u8 *io_req_base; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (megasas_alloc_request_fusion(instance)) 9528c2ecf20Sopenharmony_ci goto fail_exit; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (instance->is_rdpq) { 9558c2ecf20Sopenharmony_ci if (megasas_alloc_rdpq_fusion(instance)) 9568c2ecf20Sopenharmony_ci goto fail_exit; 9578c2ecf20Sopenharmony_ci } else 9588c2ecf20Sopenharmony_ci if (megasas_alloc_reply_fusion(instance)) 9598c2ecf20Sopenharmony_ci goto fail_exit; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (megasas_alloc_cmdlist_fusion(instance)) 9628c2ecf20Sopenharmony_ci goto fail_exit; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci /* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */ 9658c2ecf20Sopenharmony_ci io_req_base = fusion->io_request_frames + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; 9668c2ecf20Sopenharmony_ci io_req_base_phys = fusion->io_request_frames_phys + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* 9698c2ecf20Sopenharmony_ci * Add all the commands to command pool (fusion->cmd_pool) 9708c2ecf20Sopenharmony_ci */ 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* SMID 0 is reserved. Set SMID/index from 1 */ 9738c2ecf20Sopenharmony_ci for (i = 0; i < instance->max_mpt_cmds; i++) { 9748c2ecf20Sopenharmony_ci cmd = fusion->cmd_list[i]; 9758c2ecf20Sopenharmony_ci offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i; 9768c2ecf20Sopenharmony_ci memset(cmd, 0, sizeof(struct megasas_cmd_fusion)); 9778c2ecf20Sopenharmony_ci cmd->index = i + 1; 9788c2ecf20Sopenharmony_ci cmd->scmd = NULL; 9798c2ecf20Sopenharmony_ci cmd->sync_cmd_idx = 9808c2ecf20Sopenharmony_ci (i >= instance->max_scsi_cmds && i < instance->max_fw_cmds) ? 9818c2ecf20Sopenharmony_ci (i - instance->max_scsi_cmds) : 9828c2ecf20Sopenharmony_ci (u32)ULONG_MAX; /* Set to Invalid */ 9838c2ecf20Sopenharmony_ci cmd->instance = instance; 9848c2ecf20Sopenharmony_ci cmd->io_request = 9858c2ecf20Sopenharmony_ci (struct MPI2_RAID_SCSI_IO_REQUEST *) 9868c2ecf20Sopenharmony_ci (io_req_base + offset); 9878c2ecf20Sopenharmony_ci memset(cmd->io_request, 0, 9888c2ecf20Sopenharmony_ci sizeof(struct MPI2_RAID_SCSI_IO_REQUEST)); 9898c2ecf20Sopenharmony_ci cmd->io_request_phys_addr = io_req_base_phys + offset; 9908c2ecf20Sopenharmony_ci cmd->r1_alt_dev_handle = MR_DEVHANDLE_INVALID; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (megasas_create_sg_sense_fusion(instance)) 9948c2ecf20Sopenharmony_ci goto fail_exit; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci return 0; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cifail_exit: 9998c2ecf20Sopenharmony_ci megasas_free_cmds_fusion(instance); 10008c2ecf20Sopenharmony_ci return -ENOMEM; 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci/** 10048c2ecf20Sopenharmony_ci * wait_and_poll - Issues a polling command 10058c2ecf20Sopenharmony_ci * @instance: Adapter soft state 10068c2ecf20Sopenharmony_ci * @cmd: Command packet to be issued 10078c2ecf20Sopenharmony_ci * @seconds: Maximum poll time 10088c2ecf20Sopenharmony_ci * 10098c2ecf20Sopenharmony_ci * For polling, MFI requires the cmd_status to be set to 0xFF before posting. 10108c2ecf20Sopenharmony_ci */ 10118c2ecf20Sopenharmony_ciint 10128c2ecf20Sopenharmony_ciwait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd, 10138c2ecf20Sopenharmony_ci int seconds) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci int i; 10168c2ecf20Sopenharmony_ci struct megasas_header *frame_hdr = &cmd->frame->hdr; 10178c2ecf20Sopenharmony_ci u32 status_reg; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci u32 msecs = seconds * 1000; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci /* 10228c2ecf20Sopenharmony_ci * Wait for cmd_status to change 10238c2ecf20Sopenharmony_ci */ 10248c2ecf20Sopenharmony_ci for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i += 20) { 10258c2ecf20Sopenharmony_ci rmb(); 10268c2ecf20Sopenharmony_ci msleep(20); 10278c2ecf20Sopenharmony_ci if (!(i % 5000)) { 10288c2ecf20Sopenharmony_ci status_reg = instance->instancet->read_fw_status_reg(instance) 10298c2ecf20Sopenharmony_ci & MFI_STATE_MASK; 10308c2ecf20Sopenharmony_ci if (status_reg == MFI_STATE_FAULT) 10318c2ecf20Sopenharmony_ci break; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (frame_hdr->cmd_status == MFI_STAT_INVALID_STATUS) 10368c2ecf20Sopenharmony_ci return DCMD_TIMEOUT; 10378c2ecf20Sopenharmony_ci else if (frame_hdr->cmd_status == MFI_STAT_OK) 10388c2ecf20Sopenharmony_ci return DCMD_SUCCESS; 10398c2ecf20Sopenharmony_ci else 10408c2ecf20Sopenharmony_ci return DCMD_FAILED; 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci/** 10448c2ecf20Sopenharmony_ci * megasas_ioc_init_fusion - Initializes the FW 10458c2ecf20Sopenharmony_ci * @instance: Adapter soft state 10468c2ecf20Sopenharmony_ci * 10478c2ecf20Sopenharmony_ci * Issues the IOC Init cmd 10488c2ecf20Sopenharmony_ci */ 10498c2ecf20Sopenharmony_ciint 10508c2ecf20Sopenharmony_cimegasas_ioc_init_fusion(struct megasas_instance *instance) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci struct megasas_init_frame *init_frame; 10538c2ecf20Sopenharmony_ci struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL; 10548c2ecf20Sopenharmony_ci dma_addr_t ioc_init_handle; 10558c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 10568c2ecf20Sopenharmony_ci u8 ret, cur_rdpq_mode; 10578c2ecf20Sopenharmony_ci struct fusion_context *fusion; 10588c2ecf20Sopenharmony_ci union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc; 10598c2ecf20Sopenharmony_ci int i; 10608c2ecf20Sopenharmony_ci struct megasas_header *frame_hdr; 10618c2ecf20Sopenharmony_ci const char *sys_info; 10628c2ecf20Sopenharmony_ci MFI_CAPABILITIES *drv_ops; 10638c2ecf20Sopenharmony_ci u32 scratch_pad_1; 10648c2ecf20Sopenharmony_ci ktime_t time; 10658c2ecf20Sopenharmony_ci bool cur_fw_64bit_dma_capable; 10668c2ecf20Sopenharmony_ci bool cur_intr_coalescing; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci ioc_init_handle = fusion->ioc_init_request_phys; 10718c2ecf20Sopenharmony_ci IOCInitMessage = fusion->ioc_init_request; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci cmd = fusion->ioc_init_cmd; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci scratch_pad_1 = megasas_readl 10768c2ecf20Sopenharmony_ci (instance, &instance->reg_set->outbound_scratch_pad_1); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci cur_rdpq_mode = (scratch_pad_1 & MR_RDPQ_MODE_OFFSET) ? 1 : 0; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci if (instance->adapter_type == INVADER_SERIES) { 10818c2ecf20Sopenharmony_ci cur_fw_64bit_dma_capable = 10828c2ecf20Sopenharmony_ci (scratch_pad_1 & MR_CAN_HANDLE_64_BIT_DMA_OFFSET) ? true : false; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (instance->consistent_mask_64bit && !cur_fw_64bit_dma_capable) { 10858c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Driver was operating on 64bit " 10868c2ecf20Sopenharmony_ci "DMA mask, but upcoming FW does not support 64bit DMA mask\n"); 10878c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 10888c2ecf20Sopenharmony_ci ret = 1; 10898c2ecf20Sopenharmony_ci goto fail_fw_init; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (instance->is_rdpq && !cur_rdpq_mode) { 10948c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Firmware downgrade *NOT SUPPORTED*" 10958c2ecf20Sopenharmony_ci " from RDPQ mode to non RDPQ mode\n"); 10968c2ecf20Sopenharmony_ci ret = 1; 10978c2ecf20Sopenharmony_ci goto fail_fw_init; 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci cur_intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ? 11018c2ecf20Sopenharmony_ci true : false; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if ((instance->low_latency_index_start == 11048c2ecf20Sopenharmony_ci MR_HIGH_IOPS_QUEUE_COUNT) && cur_intr_coalescing) 11058c2ecf20Sopenharmony_ci instance->perf_mode = MR_BALANCED_PERF_MODE; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Performance mode :%s (latency index = %d)\n", 11088c2ecf20Sopenharmony_ci MEGASAS_PERF_MODE_2STR(instance->perf_mode), 11098c2ecf20Sopenharmony_ci instance->low_latency_index_start); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci instance->fw_sync_cache_support = (scratch_pad_1 & 11128c2ecf20Sopenharmony_ci MR_CAN_HANDLE_SYNC_CACHE_OFFSET) ? 1 : 0; 11138c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "FW supports sync cache\t: %s\n", 11148c2ecf20Sopenharmony_ci instance->fw_sync_cache_support ? "Yes" : "No"); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci memset(IOCInitMessage, 0, sizeof(struct MPI2_IOC_INIT_REQUEST)); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci IOCInitMessage->Function = MPI2_FUNCTION_IOC_INIT; 11198c2ecf20Sopenharmony_ci IOCInitMessage->WhoInit = MPI2_WHOINIT_HOST_DRIVER; 11208c2ecf20Sopenharmony_ci IOCInitMessage->MsgVersion = cpu_to_le16(MPI2_VERSION); 11218c2ecf20Sopenharmony_ci IOCInitMessage->HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); 11228c2ecf20Sopenharmony_ci IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth); 11258c2ecf20Sopenharmony_ci IOCInitMessage->ReplyDescriptorPostQueueAddress = instance->is_rdpq ? 11268c2ecf20Sopenharmony_ci cpu_to_le64(fusion->rdpq_phys) : 11278c2ecf20Sopenharmony_ci cpu_to_le64(fusion->reply_frames_desc_phys[0]); 11288c2ecf20Sopenharmony_ci IOCInitMessage->MsgFlags = instance->is_rdpq ? 11298c2ecf20Sopenharmony_ci MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0; 11308c2ecf20Sopenharmony_ci IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys); 11318c2ecf20Sopenharmony_ci IOCInitMessage->SenseBufferAddressHigh = cpu_to_le32(upper_32_bits(fusion->sense_phys_addr)); 11328c2ecf20Sopenharmony_ci IOCInitMessage->HostMSIxVectors = instance->msix_vectors; 11338c2ecf20Sopenharmony_ci IOCInitMessage->HostPageSize = MR_DEFAULT_NVME_PAGE_SHIFT; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci time = ktime_get_real(); 11368c2ecf20Sopenharmony_ci /* Convert to milliseconds as per FW requirement */ 11378c2ecf20Sopenharmony_ci IOCInitMessage->TimeStamp = cpu_to_le64(ktime_to_ms(time)); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci init_frame = (struct megasas_init_frame *)cmd->frame; 11408c2ecf20Sopenharmony_ci memset(init_frame, 0, IOC_INIT_FRAME_SIZE); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci frame_hdr = &cmd->frame->hdr; 11438c2ecf20Sopenharmony_ci frame_hdr->cmd_status = 0xFF; 11448c2ecf20Sopenharmony_ci frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE); 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci init_frame->cmd = MFI_CMD_INIT; 11478c2ecf20Sopenharmony_ci init_frame->cmd_status = 0xFF; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci drv_ops = (MFI_CAPABILITIES *) &(init_frame->driver_operations); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci /* driver support Extended MSIX */ 11528c2ecf20Sopenharmony_ci if (instance->adapter_type >= INVADER_SERIES) 11538c2ecf20Sopenharmony_ci drv_ops->mfi_capabilities.support_additional_msix = 1; 11548c2ecf20Sopenharmony_ci /* driver supports HA / Remote LUN over Fast Path interface */ 11558c2ecf20Sopenharmony_ci drv_ops->mfi_capabilities.support_fp_remote_lun = 1; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci drv_ops->mfi_capabilities.support_max_255lds = 1; 11588c2ecf20Sopenharmony_ci drv_ops->mfi_capabilities.support_ndrive_r1_lb = 1; 11598c2ecf20Sopenharmony_ci drv_ops->mfi_capabilities.security_protocol_cmds_fw = 1; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci if (instance->max_chain_frame_sz > MEGASAS_CHAIN_FRAME_SZ_MIN) 11628c2ecf20Sopenharmony_ci drv_ops->mfi_capabilities.support_ext_io_size = 1; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci drv_ops->mfi_capabilities.support_fp_rlbypass = 1; 11658c2ecf20Sopenharmony_ci if (!dual_qdepth_disable) 11668c2ecf20Sopenharmony_ci drv_ops->mfi_capabilities.support_ext_queue_depth = 1; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci drv_ops->mfi_capabilities.support_qd_throttling = 1; 11698c2ecf20Sopenharmony_ci drv_ops->mfi_capabilities.support_pd_map_target_id = 1; 11708c2ecf20Sopenharmony_ci drv_ops->mfi_capabilities.support_nvme_passthru = 1; 11718c2ecf20Sopenharmony_ci drv_ops->mfi_capabilities.support_fw_exposed_dev_list = 1; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci if (instance->consistent_mask_64bit) 11748c2ecf20Sopenharmony_ci drv_ops->mfi_capabilities.support_64bit_mode = 1; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci /* Convert capability to LE32 */ 11778c2ecf20Sopenharmony_ci cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci sys_info = dmi_get_system_info(DMI_PRODUCT_UUID); 11808c2ecf20Sopenharmony_ci if (instance->system_info_buf && sys_info) { 11818c2ecf20Sopenharmony_ci memcpy(instance->system_info_buf->systemId, sys_info, 11828c2ecf20Sopenharmony_ci strlen(sys_info) > 64 ? 64 : strlen(sys_info)); 11838c2ecf20Sopenharmony_ci instance->system_info_buf->systemIdLength = 11848c2ecf20Sopenharmony_ci strlen(sys_info) > 64 ? 64 : strlen(sys_info); 11858c2ecf20Sopenharmony_ci init_frame->system_info_lo = cpu_to_le32(lower_32_bits(instance->system_info_h)); 11868c2ecf20Sopenharmony_ci init_frame->system_info_hi = cpu_to_le32(upper_32_bits(instance->system_info_h)); 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci init_frame->queue_info_new_phys_addr_hi = 11908c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(ioc_init_handle)); 11918c2ecf20Sopenharmony_ci init_frame->queue_info_new_phys_addr_lo = 11928c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(ioc_init_handle)); 11938c2ecf20Sopenharmony_ci init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST)); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci /* 11968c2ecf20Sopenharmony_ci * Each bit in replyqueue_mask represents one group of MSI-x vectors 11978c2ecf20Sopenharmony_ci * (each group has 8 vectors) 11988c2ecf20Sopenharmony_ci */ 11998c2ecf20Sopenharmony_ci switch (instance->perf_mode) { 12008c2ecf20Sopenharmony_ci case MR_BALANCED_PERF_MODE: 12018c2ecf20Sopenharmony_ci init_frame->replyqueue_mask = 12028c2ecf20Sopenharmony_ci cpu_to_le16(~(~0 << instance->low_latency_index_start/8)); 12038c2ecf20Sopenharmony_ci break; 12048c2ecf20Sopenharmony_ci case MR_IOPS_PERF_MODE: 12058c2ecf20Sopenharmony_ci init_frame->replyqueue_mask = 12068c2ecf20Sopenharmony_ci cpu_to_le16(~(~0 << instance->msix_vectors/8)); 12078c2ecf20Sopenharmony_ci break; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci req_desc.u.low = cpu_to_le32(lower_32_bits(cmd->frame_phys_addr)); 12128c2ecf20Sopenharmony_ci req_desc.u.high = cpu_to_le32(upper_32_bits(cmd->frame_phys_addr)); 12138c2ecf20Sopenharmony_ci req_desc.MFAIo.RequestFlags = 12148c2ecf20Sopenharmony_ci (MEGASAS_REQ_DESCRIPT_FLAGS_MFA << 12158c2ecf20Sopenharmony_ci MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci /* 12188c2ecf20Sopenharmony_ci * disable the intr before firing the init frame 12198c2ecf20Sopenharmony_ci */ 12208c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci for (i = 0; i < (10 * 1000); i += 20) { 12238c2ecf20Sopenharmony_ci if (megasas_readl(instance, &instance->reg_set->doorbell) & 1) 12248c2ecf20Sopenharmony_ci msleep(20); 12258c2ecf20Sopenharmony_ci else 12268c2ecf20Sopenharmony_ci break; 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci /* For AERO also, IOC_INIT requires 64 bit descriptor write */ 12308c2ecf20Sopenharmony_ci megasas_write_64bit_req_desc(instance, &req_desc); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci wait_and_poll(instance, cmd, MFI_IO_TIMEOUT_SECS); 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci frame_hdr = &cmd->frame->hdr; 12358c2ecf20Sopenharmony_ci if (frame_hdr->cmd_status != 0) { 12368c2ecf20Sopenharmony_ci ret = 1; 12378c2ecf20Sopenharmony_ci goto fail_fw_init; 12388c2ecf20Sopenharmony_ci } 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (instance->adapter_type >= AERO_SERIES) { 12418c2ecf20Sopenharmony_ci scratch_pad_1 = megasas_readl 12428c2ecf20Sopenharmony_ci (instance, &instance->reg_set->outbound_scratch_pad_1); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci instance->atomic_desc_support = 12458c2ecf20Sopenharmony_ci (scratch_pad_1 & MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET) ? 1 : 0; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "FW supports atomic descriptor\t: %s\n", 12488c2ecf20Sopenharmony_ci instance->atomic_desc_support ? "Yes" : "No"); 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci return 0; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_cifail_fw_init: 12548c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 12558c2ecf20Sopenharmony_ci "Init cmd return status FAILED for SCSI host %d\n", 12568c2ecf20Sopenharmony_ci instance->host->host_no); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci return ret; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci/** 12628c2ecf20Sopenharmony_ci * megasas_sync_pd_seq_num - JBOD SEQ MAP 12638c2ecf20Sopenharmony_ci * @instance: Adapter soft state 12648c2ecf20Sopenharmony_ci * @pend: set to 1, if it is pended jbod map. 12658c2ecf20Sopenharmony_ci * 12668c2ecf20Sopenharmony_ci * Issue Jbod map to the firmware. If it is pended command, 12678c2ecf20Sopenharmony_ci * issue command and return. If it is first instance of jbod map 12688c2ecf20Sopenharmony_ci * issue and receive command. 12698c2ecf20Sopenharmony_ci */ 12708c2ecf20Sopenharmony_ciint 12718c2ecf20Sopenharmony_cimegasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) { 12728c2ecf20Sopenharmony_ci int ret = 0; 12738c2ecf20Sopenharmony_ci size_t pd_seq_map_sz; 12748c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 12758c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 12768c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 12778c2ecf20Sopenharmony_ci struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; 12788c2ecf20Sopenharmony_ci dma_addr_t pd_seq_h; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id & 1)]; 12818c2ecf20Sopenharmony_ci pd_seq_h = fusion->pd_seq_phys[(instance->pd_seq_map_id & 1)]; 12828c2ecf20Sopenharmony_ci pd_seq_map_sz = struct_size(pd_sync, seq, MAX_PHYSICAL_DEVICES - 1); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 12858c2ecf20Sopenharmony_ci if (!cmd) { 12868c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 12878c2ecf20Sopenharmony_ci "Could not get mfi cmd. Fail from %s %d\n", 12888c2ecf20Sopenharmony_ci __func__, __LINE__); 12898c2ecf20Sopenharmony_ci return -ENOMEM; 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci memset(pd_sync, 0, pd_seq_map_sz); 12958c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci if (pend) { 12988c2ecf20Sopenharmony_ci dcmd->mbox.b[0] = MEGASAS_DCMD_MBOX_PEND_FLAG; 12998c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_WRITE; 13008c2ecf20Sopenharmony_ci instance->jbod_seq_cmd = cmd; 13018c2ecf20Sopenharmony_ci } else { 13028c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_READ; 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 13068c2ecf20Sopenharmony_ci dcmd->cmd_status = 0xFF; 13078c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 13088c2ecf20Sopenharmony_ci dcmd->timeout = 0; 13098c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 13108c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(pd_seq_map_sz); 13118c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, pd_seq_h, pd_seq_map_sz); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci if (pend) { 13168c2ecf20Sopenharmony_ci instance->instancet->issue_dcmd(instance, cmd); 13178c2ecf20Sopenharmony_ci return 0; 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci /* Below code is only for non pended DCMD */ 13218c2ecf20Sopenharmony_ci if (!instance->mask_interrupts) 13228c2ecf20Sopenharmony_ci ret = megasas_issue_blocked_cmd(instance, cmd, 13238c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_SECS); 13248c2ecf20Sopenharmony_ci else 13258c2ecf20Sopenharmony_ci ret = megasas_issue_polled(instance, cmd); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci if (le32_to_cpu(pd_sync->count) > MAX_PHYSICAL_DEVICES) { 13288c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, 13298c2ecf20Sopenharmony_ci "driver supports max %d JBOD, but FW reports %d\n", 13308c2ecf20Sopenharmony_ci MAX_PHYSICAL_DEVICES, le32_to_cpu(pd_sync->count)); 13318c2ecf20Sopenharmony_ci ret = -EINVAL; 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci if (ret == DCMD_TIMEOUT) 13358c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, 13368c2ecf20Sopenharmony_ci "%s DCMD timed out, continue without JBOD sequence map\n", 13378c2ecf20Sopenharmony_ci __func__); 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci if (ret == DCMD_SUCCESS) 13408c2ecf20Sopenharmony_ci instance->pd_seq_map_id++; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 13438c2ecf20Sopenharmony_ci return ret; 13448c2ecf20Sopenharmony_ci} 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci/* 13478c2ecf20Sopenharmony_ci * megasas_get_ld_map_info - Returns FW's ld_map structure 13488c2ecf20Sopenharmony_ci * @instance: Adapter soft state 13498c2ecf20Sopenharmony_ci * @pend: Pend the command or not 13508c2ecf20Sopenharmony_ci * Issues an internal command (DCMD) to get the FW's controller PD 13518c2ecf20Sopenharmony_ci * list structure. This information is mainly used to find out SYSTEM 13528c2ecf20Sopenharmony_ci * supported by the FW. 13538c2ecf20Sopenharmony_ci * dcmd.mbox value setting for MR_DCMD_LD_MAP_GET_INFO 13548c2ecf20Sopenharmony_ci * dcmd.mbox.b[0] - number of LDs being sync'd 13558c2ecf20Sopenharmony_ci * dcmd.mbox.b[1] - 0 - complete command immediately. 13568c2ecf20Sopenharmony_ci * - 1 - pend till config change 13578c2ecf20Sopenharmony_ci * dcmd.mbox.b[2] - 0 - supports max 64 lds and uses legacy MR_FW_RAID_MAP 13588c2ecf20Sopenharmony_ci * - 1 - supports max MAX_LOGICAL_DRIVES_EXT lds and 13598c2ecf20Sopenharmony_ci * uses extended struct MR_FW_RAID_MAP_EXT 13608c2ecf20Sopenharmony_ci */ 13618c2ecf20Sopenharmony_cistatic int 13628c2ecf20Sopenharmony_cimegasas_get_ld_map_info(struct megasas_instance *instance) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci int ret = 0; 13658c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 13668c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 13678c2ecf20Sopenharmony_ci void *ci; 13688c2ecf20Sopenharmony_ci dma_addr_t ci_h = 0; 13698c2ecf20Sopenharmony_ci u32 size_map_info; 13708c2ecf20Sopenharmony_ci struct fusion_context *fusion; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci if (!cmd) { 13758c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get cmd for map info\n"); 13768c2ecf20Sopenharmony_ci return -ENOMEM; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (!fusion) { 13828c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 13838c2ecf20Sopenharmony_ci return -ENXIO; 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci size_map_info = fusion->current_map_sz; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci ci = (void *) fusion->ld_map[(instance->map_id & 1)]; 13918c2ecf20Sopenharmony_ci ci_h = fusion->ld_map_phys[(instance->map_id & 1)]; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci if (!ci) { 13948c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to alloc mem for ld_map_info\n"); 13958c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 13968c2ecf20Sopenharmony_ci return -ENOMEM; 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci memset(ci, 0, fusion->max_map_sz); 14008c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 14018c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 14028c2ecf20Sopenharmony_ci dcmd->cmd_status = 0xFF; 14038c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 14048c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_READ; 14058c2ecf20Sopenharmony_ci dcmd->timeout = 0; 14068c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 14078c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(size_map_info); 14088c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO); 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, ci_h, size_map_info); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci if (!instance->mask_interrupts) 14138c2ecf20Sopenharmony_ci ret = megasas_issue_blocked_cmd(instance, cmd, 14148c2ecf20Sopenharmony_ci MFI_IO_TIMEOUT_SECS); 14158c2ecf20Sopenharmony_ci else 14168c2ecf20Sopenharmony_ci ret = megasas_issue_polled(instance, cmd); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci if (ret == DCMD_TIMEOUT) 14198c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, 14208c2ecf20Sopenharmony_ci "%s DCMD timed out, RAID map is disabled\n", 14218c2ecf20Sopenharmony_ci __func__); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci return ret; 14268c2ecf20Sopenharmony_ci} 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ciu8 14298c2ecf20Sopenharmony_cimegasas_get_map_info(struct megasas_instance *instance) 14308c2ecf20Sopenharmony_ci{ 14318c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci fusion->fast_path_io = 0; 14348c2ecf20Sopenharmony_ci if (!megasas_get_ld_map_info(instance)) { 14358c2ecf20Sopenharmony_ci if (MR_ValidateMapInfo(instance, instance->map_id)) { 14368c2ecf20Sopenharmony_ci fusion->fast_path_io = 1; 14378c2ecf20Sopenharmony_ci return 0; 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci return 1; 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci/* 14448c2ecf20Sopenharmony_ci * megasas_sync_map_info - Returns FW's ld_map structure 14458c2ecf20Sopenharmony_ci * @instance: Adapter soft state 14468c2ecf20Sopenharmony_ci * 14478c2ecf20Sopenharmony_ci * Issues an internal command (DCMD) to get the FW's controller PD 14488c2ecf20Sopenharmony_ci * list structure. This information is mainly used to find out SYSTEM 14498c2ecf20Sopenharmony_ci * supported by the FW. 14508c2ecf20Sopenharmony_ci */ 14518c2ecf20Sopenharmony_ciint 14528c2ecf20Sopenharmony_cimegasas_sync_map_info(struct megasas_instance *instance) 14538c2ecf20Sopenharmony_ci{ 14548c2ecf20Sopenharmony_ci int i; 14558c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 14568c2ecf20Sopenharmony_ci struct megasas_dcmd_frame *dcmd; 14578c2ecf20Sopenharmony_ci u16 num_lds; 14588c2ecf20Sopenharmony_ci struct fusion_context *fusion; 14598c2ecf20Sopenharmony_ci struct MR_LD_TARGET_SYNC *ci = NULL; 14608c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map; 14618c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid; 14628c2ecf20Sopenharmony_ci struct MR_LD_TARGET_SYNC *ld_sync; 14638c2ecf20Sopenharmony_ci dma_addr_t ci_h = 0; 14648c2ecf20Sopenharmony_ci u32 size_map_info; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci cmd = megasas_get_cmd(instance); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci if (!cmd) { 14698c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get cmd for sync info\n"); 14708c2ecf20Sopenharmony_ci return -ENOMEM; 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci if (!fusion) { 14768c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd); 14778c2ecf20Sopenharmony_ci return 1; 14788c2ecf20Sopenharmony_ci } 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci map = fusion->ld_drv_map[instance->map_id & 1]; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci num_lds = le16_to_cpu(map->raidMap.ldCount); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci dcmd = &cmd->frame->dcmd; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci ci = (struct MR_LD_TARGET_SYNC *) 14898c2ecf20Sopenharmony_ci fusion->ld_map[(instance->map_id - 1) & 1]; 14908c2ecf20Sopenharmony_ci memset(ci, 0, fusion->max_map_sz); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci ci_h = fusion->ld_map_phys[(instance->map_id - 1) & 1]; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci ld_sync = (struct MR_LD_TARGET_SYNC *)ci; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci for (i = 0; i < num_lds; i++, ld_sync++) { 14978c2ecf20Sopenharmony_ci raid = MR_LdRaidGet(i, map); 14988c2ecf20Sopenharmony_ci ld_sync->targetId = MR_GetLDTgtId(i, map); 14998c2ecf20Sopenharmony_ci ld_sync->seqNum = raid->seqNum; 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci size_map_info = fusion->current_map_sz; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci dcmd->cmd = MFI_CMD_DCMD; 15058c2ecf20Sopenharmony_ci dcmd->cmd_status = 0xFF; 15068c2ecf20Sopenharmony_ci dcmd->sge_count = 1; 15078c2ecf20Sopenharmony_ci dcmd->flags = MFI_FRAME_DIR_WRITE; 15088c2ecf20Sopenharmony_ci dcmd->timeout = 0; 15098c2ecf20Sopenharmony_ci dcmd->pad_0 = 0; 15108c2ecf20Sopenharmony_ci dcmd->data_xfer_len = cpu_to_le32(size_map_info); 15118c2ecf20Sopenharmony_ci dcmd->mbox.b[0] = num_lds; 15128c2ecf20Sopenharmony_ci dcmd->mbox.b[1] = MEGASAS_DCMD_MBOX_PEND_FLAG; 15138c2ecf20Sopenharmony_ci dcmd->opcode = cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci megasas_set_dma_settings(instance, dcmd, ci_h, size_map_info); 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci instance->map_update_cmd = cmd; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci instance->instancet->issue_dcmd(instance, cmd); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci return 0; 15228c2ecf20Sopenharmony_ci} 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci/* 15258c2ecf20Sopenharmony_ci * meagasas_display_intel_branding - Display branding string 15268c2ecf20Sopenharmony_ci * @instance: per adapter object 15278c2ecf20Sopenharmony_ci * 15288c2ecf20Sopenharmony_ci * Return nothing. 15298c2ecf20Sopenharmony_ci */ 15308c2ecf20Sopenharmony_cistatic void 15318c2ecf20Sopenharmony_cimegasas_display_intel_branding(struct megasas_instance *instance) 15328c2ecf20Sopenharmony_ci{ 15338c2ecf20Sopenharmony_ci if (instance->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL) 15348c2ecf20Sopenharmony_ci return; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci switch (instance->pdev->device) { 15378c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_INVADER: 15388c2ecf20Sopenharmony_ci switch (instance->pdev->subsystem_device) { 15398c2ecf20Sopenharmony_ci case MEGARAID_INTEL_RS3DC080_SSDID: 15408c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "scsi host %d: %s\n", 15418c2ecf20Sopenharmony_ci instance->host->host_no, 15428c2ecf20Sopenharmony_ci MEGARAID_INTEL_RS3DC080_BRANDING); 15438c2ecf20Sopenharmony_ci break; 15448c2ecf20Sopenharmony_ci case MEGARAID_INTEL_RS3DC040_SSDID: 15458c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "scsi host %d: %s\n", 15468c2ecf20Sopenharmony_ci instance->host->host_no, 15478c2ecf20Sopenharmony_ci MEGARAID_INTEL_RS3DC040_BRANDING); 15488c2ecf20Sopenharmony_ci break; 15498c2ecf20Sopenharmony_ci case MEGARAID_INTEL_RS3SC008_SSDID: 15508c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "scsi host %d: %s\n", 15518c2ecf20Sopenharmony_ci instance->host->host_no, 15528c2ecf20Sopenharmony_ci MEGARAID_INTEL_RS3SC008_BRANDING); 15538c2ecf20Sopenharmony_ci break; 15548c2ecf20Sopenharmony_ci case MEGARAID_INTEL_RS3MC044_SSDID: 15558c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "scsi host %d: %s\n", 15568c2ecf20Sopenharmony_ci instance->host->host_no, 15578c2ecf20Sopenharmony_ci MEGARAID_INTEL_RS3MC044_BRANDING); 15588c2ecf20Sopenharmony_ci break; 15598c2ecf20Sopenharmony_ci default: 15608c2ecf20Sopenharmony_ci break; 15618c2ecf20Sopenharmony_ci } 15628c2ecf20Sopenharmony_ci break; 15638c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_FURY: 15648c2ecf20Sopenharmony_ci switch (instance->pdev->subsystem_device) { 15658c2ecf20Sopenharmony_ci case MEGARAID_INTEL_RS3WC080_SSDID: 15668c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "scsi host %d: %s\n", 15678c2ecf20Sopenharmony_ci instance->host->host_no, 15688c2ecf20Sopenharmony_ci MEGARAID_INTEL_RS3WC080_BRANDING); 15698c2ecf20Sopenharmony_ci break; 15708c2ecf20Sopenharmony_ci case MEGARAID_INTEL_RS3WC040_SSDID: 15718c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "scsi host %d: %s\n", 15728c2ecf20Sopenharmony_ci instance->host->host_no, 15738c2ecf20Sopenharmony_ci MEGARAID_INTEL_RS3WC040_BRANDING); 15748c2ecf20Sopenharmony_ci break; 15758c2ecf20Sopenharmony_ci default: 15768c2ecf20Sopenharmony_ci break; 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci break; 15798c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_CUTLASS_52: 15808c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_LSI_CUTLASS_53: 15818c2ecf20Sopenharmony_ci switch (instance->pdev->subsystem_device) { 15828c2ecf20Sopenharmony_ci case MEGARAID_INTEL_RMS3BC160_SSDID: 15838c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "scsi host %d: %s\n", 15848c2ecf20Sopenharmony_ci instance->host->host_no, 15858c2ecf20Sopenharmony_ci MEGARAID_INTEL_RMS3BC160_BRANDING); 15868c2ecf20Sopenharmony_ci break; 15878c2ecf20Sopenharmony_ci default: 15888c2ecf20Sopenharmony_ci break; 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci break; 15918c2ecf20Sopenharmony_ci default: 15928c2ecf20Sopenharmony_ci break; 15938c2ecf20Sopenharmony_ci } 15948c2ecf20Sopenharmony_ci} 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci/** 15978c2ecf20Sopenharmony_ci * megasas_allocate_raid_maps - Allocate memory for RAID maps 15988c2ecf20Sopenharmony_ci * @instance: Adapter soft state 15998c2ecf20Sopenharmony_ci * 16008c2ecf20Sopenharmony_ci * return: if success: return 0 16018c2ecf20Sopenharmony_ci * failed: return -ENOMEM 16028c2ecf20Sopenharmony_ci */ 16038c2ecf20Sopenharmony_cistatic inline int megasas_allocate_raid_maps(struct megasas_instance *instance) 16048c2ecf20Sopenharmony_ci{ 16058c2ecf20Sopenharmony_ci struct fusion_context *fusion; 16068c2ecf20Sopenharmony_ci int i = 0; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci fusion->drv_map_pages = get_order(fusion->drv_map_sz); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 16138c2ecf20Sopenharmony_ci fusion->ld_map[i] = NULL; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci fusion->ld_drv_map[i] = (void *) 16168c2ecf20Sopenharmony_ci __get_free_pages(__GFP_ZERO | GFP_KERNEL, 16178c2ecf20Sopenharmony_ci fusion->drv_map_pages); 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci if (!fusion->ld_drv_map[i]) { 16208c2ecf20Sopenharmony_ci fusion->ld_drv_map[i] = vzalloc(fusion->drv_map_sz); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci if (!fusion->ld_drv_map[i]) { 16238c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 16248c2ecf20Sopenharmony_ci "Could not allocate memory for local map" 16258c2ecf20Sopenharmony_ci " size requested: %d\n", 16268c2ecf20Sopenharmony_ci fusion->drv_map_sz); 16278c2ecf20Sopenharmony_ci goto ld_drv_map_alloc_fail; 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 16338c2ecf20Sopenharmony_ci fusion->ld_map[i] = dma_alloc_coherent(&instance->pdev->dev, 16348c2ecf20Sopenharmony_ci fusion->max_map_sz, 16358c2ecf20Sopenharmony_ci &fusion->ld_map_phys[i], 16368c2ecf20Sopenharmony_ci GFP_KERNEL); 16378c2ecf20Sopenharmony_ci if (!fusion->ld_map[i]) { 16388c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 16398c2ecf20Sopenharmony_ci "Could not allocate memory for map info %s:%d\n", 16408c2ecf20Sopenharmony_ci __func__, __LINE__); 16418c2ecf20Sopenharmony_ci goto ld_map_alloc_fail; 16428c2ecf20Sopenharmony_ci } 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci return 0; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_cild_map_alloc_fail: 16488c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 16498c2ecf20Sopenharmony_ci if (fusion->ld_map[i]) 16508c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, 16518c2ecf20Sopenharmony_ci fusion->max_map_sz, 16528c2ecf20Sopenharmony_ci fusion->ld_map[i], 16538c2ecf20Sopenharmony_ci fusion->ld_map_phys[i]); 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_cild_drv_map_alloc_fail: 16578c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 16588c2ecf20Sopenharmony_ci if (fusion->ld_drv_map[i]) { 16598c2ecf20Sopenharmony_ci if (is_vmalloc_addr(fusion->ld_drv_map[i])) 16608c2ecf20Sopenharmony_ci vfree(fusion->ld_drv_map[i]); 16618c2ecf20Sopenharmony_ci else 16628c2ecf20Sopenharmony_ci free_pages((ulong)fusion->ld_drv_map[i], 16638c2ecf20Sopenharmony_ci fusion->drv_map_pages); 16648c2ecf20Sopenharmony_ci } 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci return -ENOMEM; 16688c2ecf20Sopenharmony_ci} 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci/** 16718c2ecf20Sopenharmony_ci * megasas_configure_queue_sizes - Calculate size of request desc queue, 16728c2ecf20Sopenharmony_ci * reply desc queue, 16738c2ecf20Sopenharmony_ci * IO request frame queue, set can_queue. 16748c2ecf20Sopenharmony_ci * @instance: Adapter soft state 16758c2ecf20Sopenharmony_ci * @return: void 16768c2ecf20Sopenharmony_ci */ 16778c2ecf20Sopenharmony_cistatic inline 16788c2ecf20Sopenharmony_civoid megasas_configure_queue_sizes(struct megasas_instance *instance) 16798c2ecf20Sopenharmony_ci{ 16808c2ecf20Sopenharmony_ci struct fusion_context *fusion; 16818c2ecf20Sopenharmony_ci u16 max_cmd; 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 16848c2ecf20Sopenharmony_ci max_cmd = instance->max_fw_cmds; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) 16878c2ecf20Sopenharmony_ci instance->max_mpt_cmds = instance->max_fw_cmds * RAID_1_PEER_CMDS; 16888c2ecf20Sopenharmony_ci else 16898c2ecf20Sopenharmony_ci instance->max_mpt_cmds = instance->max_fw_cmds; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci instance->max_scsi_cmds = instance->max_fw_cmds - instance->max_mfi_cmds; 16928c2ecf20Sopenharmony_ci instance->cur_can_queue = instance->max_scsi_cmds; 16938c2ecf20Sopenharmony_ci instance->host->can_queue = instance->cur_can_queue; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci fusion->reply_q_depth = 2 * ((max_cmd + 1 + 15) / 16) * 16; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci fusion->request_alloc_sz = sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) * 16988c2ecf20Sopenharmony_ci instance->max_mpt_cmds; 16998c2ecf20Sopenharmony_ci fusion->reply_alloc_sz = sizeof(union MPI2_REPLY_DESCRIPTORS_UNION) * 17008c2ecf20Sopenharmony_ci (fusion->reply_q_depth); 17018c2ecf20Sopenharmony_ci fusion->io_frames_alloc_sz = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE + 17028c2ecf20Sopenharmony_ci (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE 17038c2ecf20Sopenharmony_ci * (instance->max_mpt_cmds + 1)); /* Extra 1 for SMID 0 */ 17048c2ecf20Sopenharmony_ci} 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_cistatic int megasas_alloc_ioc_init_frame(struct megasas_instance *instance) 17078c2ecf20Sopenharmony_ci{ 17088c2ecf20Sopenharmony_ci struct fusion_context *fusion; 17098c2ecf20Sopenharmony_ci struct megasas_cmd *cmd; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(struct megasas_cmd), GFP_KERNEL); 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci if (!cmd) { 17168c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed from func: %s line: %d\n", 17178c2ecf20Sopenharmony_ci __func__, __LINE__); 17188c2ecf20Sopenharmony_ci return -ENOMEM; 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci cmd->frame = dma_alloc_coherent(&instance->pdev->dev, 17228c2ecf20Sopenharmony_ci IOC_INIT_FRAME_SIZE, 17238c2ecf20Sopenharmony_ci &cmd->frame_phys_addr, GFP_KERNEL); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci if (!cmd->frame) { 17268c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed from func: %s line: %d\n", 17278c2ecf20Sopenharmony_ci __func__, __LINE__); 17288c2ecf20Sopenharmony_ci kfree(cmd); 17298c2ecf20Sopenharmony_ci return -ENOMEM; 17308c2ecf20Sopenharmony_ci } 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci fusion->ioc_init_cmd = cmd; 17338c2ecf20Sopenharmony_ci return 0; 17348c2ecf20Sopenharmony_ci} 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci/** 17378c2ecf20Sopenharmony_ci * megasas_free_ioc_init_cmd - Free IOC INIT command frame 17388c2ecf20Sopenharmony_ci * @instance: Adapter soft state 17398c2ecf20Sopenharmony_ci */ 17408c2ecf20Sopenharmony_cistatic inline void megasas_free_ioc_init_cmd(struct megasas_instance *instance) 17418c2ecf20Sopenharmony_ci{ 17428c2ecf20Sopenharmony_ci struct fusion_context *fusion; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci if (fusion->ioc_init_cmd && fusion->ioc_init_cmd->frame) 17478c2ecf20Sopenharmony_ci dma_free_coherent(&instance->pdev->dev, 17488c2ecf20Sopenharmony_ci IOC_INIT_FRAME_SIZE, 17498c2ecf20Sopenharmony_ci fusion->ioc_init_cmd->frame, 17508c2ecf20Sopenharmony_ci fusion->ioc_init_cmd->frame_phys_addr); 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci kfree(fusion->ioc_init_cmd); 17538c2ecf20Sopenharmony_ci} 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci/** 17568c2ecf20Sopenharmony_ci * megasas_init_adapter_fusion - Initializes the FW 17578c2ecf20Sopenharmony_ci * @instance: Adapter soft state 17588c2ecf20Sopenharmony_ci * 17598c2ecf20Sopenharmony_ci * This is the main function for initializing firmware. 17608c2ecf20Sopenharmony_ci */ 17618c2ecf20Sopenharmony_cistatic u32 17628c2ecf20Sopenharmony_cimegasas_init_adapter_fusion(struct megasas_instance *instance) 17638c2ecf20Sopenharmony_ci{ 17648c2ecf20Sopenharmony_ci struct fusion_context *fusion; 17658c2ecf20Sopenharmony_ci u32 scratch_pad_1; 17668c2ecf20Sopenharmony_ci int i = 0, count; 17678c2ecf20Sopenharmony_ci u32 status_reg; 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci megasas_fusion_update_can_queue(instance, PROBE_CONTEXT); 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci /* 17748c2ecf20Sopenharmony_ci * Only Driver's internal DCMDs and IOCTL DCMDs needs to have MFI frames 17758c2ecf20Sopenharmony_ci */ 17768c2ecf20Sopenharmony_ci instance->max_mfi_cmds = 17778c2ecf20Sopenharmony_ci MEGASAS_FUSION_INTERNAL_CMDS + MEGASAS_FUSION_IOCTL_CMDS; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci megasas_configure_queue_sizes(instance); 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci scratch_pad_1 = megasas_readl(instance, 17828c2ecf20Sopenharmony_ci &instance->reg_set->outbound_scratch_pad_1); 17838c2ecf20Sopenharmony_ci /* If scratch_pad_1 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK is set, 17848c2ecf20Sopenharmony_ci * Firmware support extended IO chain frame which is 4 times more than 17858c2ecf20Sopenharmony_ci * legacy Firmware. 17868c2ecf20Sopenharmony_ci * Legacy Firmware - Frame size is (8 * 128) = 1K 17878c2ecf20Sopenharmony_ci * 1M IO Firmware - Frame size is (8 * 128 * 4) = 4K 17888c2ecf20Sopenharmony_ci */ 17898c2ecf20Sopenharmony_ci if (scratch_pad_1 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK) 17908c2ecf20Sopenharmony_ci instance->max_chain_frame_sz = 17918c2ecf20Sopenharmony_ci ((scratch_pad_1 & MEGASAS_MAX_CHAIN_SIZE_MASK) >> 17928c2ecf20Sopenharmony_ci MEGASAS_MAX_CHAIN_SHIFT) * MEGASAS_1MB_IO; 17938c2ecf20Sopenharmony_ci else 17948c2ecf20Sopenharmony_ci instance->max_chain_frame_sz = 17958c2ecf20Sopenharmony_ci ((scratch_pad_1 & MEGASAS_MAX_CHAIN_SIZE_MASK) >> 17968c2ecf20Sopenharmony_ci MEGASAS_MAX_CHAIN_SHIFT) * MEGASAS_256K_IO; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci if (instance->max_chain_frame_sz < MEGASAS_CHAIN_FRAME_SZ_MIN) { 17998c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "frame size %d invalid, fall back to legacy max frame size %d\n", 18008c2ecf20Sopenharmony_ci instance->max_chain_frame_sz, 18018c2ecf20Sopenharmony_ci MEGASAS_CHAIN_FRAME_SZ_MIN); 18028c2ecf20Sopenharmony_ci instance->max_chain_frame_sz = MEGASAS_CHAIN_FRAME_SZ_MIN; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci fusion->max_sge_in_main_msg = 18068c2ecf20Sopenharmony_ci (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE 18078c2ecf20Sopenharmony_ci - offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci fusion->max_sge_in_chain = 18108c2ecf20Sopenharmony_ci instance->max_chain_frame_sz 18118c2ecf20Sopenharmony_ci / sizeof(union MPI2_SGE_IO_UNION); 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci instance->max_num_sge = 18148c2ecf20Sopenharmony_ci rounddown_pow_of_two(fusion->max_sge_in_main_msg 18158c2ecf20Sopenharmony_ci + fusion->max_sge_in_chain - 2); 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci /* Used for pass thru MFI frame (DCMD) */ 18188c2ecf20Sopenharmony_ci fusion->chain_offset_mfi_pthru = 18198c2ecf20Sopenharmony_ci offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL)/16; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci fusion->chain_offset_io_request = 18228c2ecf20Sopenharmony_ci (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE - 18238c2ecf20Sopenharmony_ci sizeof(union MPI2_SGE_IO_UNION))/16; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; 18268c2ecf20Sopenharmony_ci for (i = 0 ; i < count; i++) 18278c2ecf20Sopenharmony_ci fusion->last_reply_idx[i] = 0; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci /* 18308c2ecf20Sopenharmony_ci * For fusion adapters, 3 commands for IOCTL and 8 commands 18318c2ecf20Sopenharmony_ci * for driver's internal DCMDs. 18328c2ecf20Sopenharmony_ci */ 18338c2ecf20Sopenharmony_ci instance->max_scsi_cmds = instance->max_fw_cmds - 18348c2ecf20Sopenharmony_ci (MEGASAS_FUSION_INTERNAL_CMDS + 18358c2ecf20Sopenharmony_ci MEGASAS_FUSION_IOCTL_CMDS); 18368c2ecf20Sopenharmony_ci sema_init(&instance->ioctl_sem, MEGASAS_FUSION_IOCTL_CMDS); 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci if (megasas_alloc_ioc_init_frame(instance)) 18398c2ecf20Sopenharmony_ci return 1; 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci /* 18428c2ecf20Sopenharmony_ci * Allocate memory for descriptors 18438c2ecf20Sopenharmony_ci * Create a pool of commands 18448c2ecf20Sopenharmony_ci */ 18458c2ecf20Sopenharmony_ci if (megasas_alloc_cmds(instance)) 18468c2ecf20Sopenharmony_ci goto fail_alloc_mfi_cmds; 18478c2ecf20Sopenharmony_ci if (megasas_alloc_cmds_fusion(instance)) 18488c2ecf20Sopenharmony_ci goto fail_alloc_cmds; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci if (megasas_ioc_init_fusion(instance)) { 18518c2ecf20Sopenharmony_ci status_reg = instance->instancet->read_fw_status_reg(instance); 18528c2ecf20Sopenharmony_ci if (((status_reg & MFI_STATE_MASK) == MFI_STATE_FAULT) && 18538c2ecf20Sopenharmony_ci (status_reg & MFI_RESET_ADAPTER)) { 18548c2ecf20Sopenharmony_ci /* Do a chip reset and then retry IOC INIT once */ 18558c2ecf20Sopenharmony_ci if (megasas_adp_reset_wait_for_ready 18568c2ecf20Sopenharmony_ci (instance, true, 0) == FAILED) 18578c2ecf20Sopenharmony_ci goto fail_ioc_init; 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci if (megasas_ioc_init_fusion(instance)) 18608c2ecf20Sopenharmony_ci goto fail_ioc_init; 18618c2ecf20Sopenharmony_ci } else { 18628c2ecf20Sopenharmony_ci goto fail_ioc_init; 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci megasas_display_intel_branding(instance); 18678c2ecf20Sopenharmony_ci if (megasas_get_ctrl_info(instance)) { 18688c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 18698c2ecf20Sopenharmony_ci "Could not get controller info. Fail from %s %d\n", 18708c2ecf20Sopenharmony_ci __func__, __LINE__); 18718c2ecf20Sopenharmony_ci goto fail_ioc_init; 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci instance->flag_ieee = 1; 18758c2ecf20Sopenharmony_ci instance->r1_ldio_hint_default = MR_R1_LDIO_PIGGYBACK_DEFAULT; 18768c2ecf20Sopenharmony_ci instance->threshold_reply_count = instance->max_fw_cmds / 4; 18778c2ecf20Sopenharmony_ci fusion->fast_path_io = 0; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci if (megasas_allocate_raid_maps(instance)) 18808c2ecf20Sopenharmony_ci goto fail_ioc_init; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci if (!megasas_get_map_info(instance)) 18838c2ecf20Sopenharmony_ci megasas_sync_map_info(instance); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci return 0; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_cifail_ioc_init: 18888c2ecf20Sopenharmony_ci megasas_free_cmds_fusion(instance); 18898c2ecf20Sopenharmony_cifail_alloc_cmds: 18908c2ecf20Sopenharmony_ci megasas_free_cmds(instance); 18918c2ecf20Sopenharmony_cifail_alloc_mfi_cmds: 18928c2ecf20Sopenharmony_ci megasas_free_ioc_init_cmd(instance); 18938c2ecf20Sopenharmony_ci return 1; 18948c2ecf20Sopenharmony_ci} 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci/** 18978c2ecf20Sopenharmony_ci * megasas_fault_detect_work - Worker function of 18988c2ecf20Sopenharmony_ci * FW fault handling workqueue. 18998c2ecf20Sopenharmony_ci * @work: FW fault work struct 19008c2ecf20Sopenharmony_ci */ 19018c2ecf20Sopenharmony_cistatic void 19028c2ecf20Sopenharmony_cimegasas_fault_detect_work(struct work_struct *work) 19038c2ecf20Sopenharmony_ci{ 19048c2ecf20Sopenharmony_ci struct megasas_instance *instance = 19058c2ecf20Sopenharmony_ci container_of(work, struct megasas_instance, 19068c2ecf20Sopenharmony_ci fw_fault_work.work); 19078c2ecf20Sopenharmony_ci u32 fw_state, dma_state, status; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci /* Check the fw state */ 19108c2ecf20Sopenharmony_ci fw_state = instance->instancet->read_fw_status_reg(instance) & 19118c2ecf20Sopenharmony_ci MFI_STATE_MASK; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci if (fw_state == MFI_STATE_FAULT) { 19148c2ecf20Sopenharmony_ci dma_state = instance->instancet->read_fw_status_reg(instance) & 19158c2ecf20Sopenharmony_ci MFI_STATE_DMADONE; 19168c2ecf20Sopenharmony_ci /* Start collecting crash, if DMA bit is done */ 19178c2ecf20Sopenharmony_ci if (instance->crash_dump_drv_support && 19188c2ecf20Sopenharmony_ci instance->crash_dump_app_support && dma_state) { 19198c2ecf20Sopenharmony_ci megasas_fusion_crash_dump(instance); 19208c2ecf20Sopenharmony_ci } else { 19218c2ecf20Sopenharmony_ci if (instance->unload == 0) { 19228c2ecf20Sopenharmony_ci status = megasas_reset_fusion(instance->host, 0); 19238c2ecf20Sopenharmony_ci if (status != SUCCESS) { 19248c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 19258c2ecf20Sopenharmony_ci "Failed from %s %d, do not re-arm timer\n", 19268c2ecf20Sopenharmony_ci __func__, __LINE__); 19278c2ecf20Sopenharmony_ci return; 19288c2ecf20Sopenharmony_ci } 19298c2ecf20Sopenharmony_ci } 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci } 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci if (instance->fw_fault_work_q) 19348c2ecf20Sopenharmony_ci queue_delayed_work(instance->fw_fault_work_q, 19358c2ecf20Sopenharmony_ci &instance->fw_fault_work, 19368c2ecf20Sopenharmony_ci msecs_to_jiffies(MEGASAS_WATCHDOG_THREAD_INTERVAL)); 19378c2ecf20Sopenharmony_ci} 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ciint 19408c2ecf20Sopenharmony_cimegasas_fusion_start_watchdog(struct megasas_instance *instance) 19418c2ecf20Sopenharmony_ci{ 19428c2ecf20Sopenharmony_ci /* Check if the Fault WQ is already started */ 19438c2ecf20Sopenharmony_ci if (instance->fw_fault_work_q) 19448c2ecf20Sopenharmony_ci return SUCCESS; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&instance->fw_fault_work, megasas_fault_detect_work); 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci snprintf(instance->fault_handler_work_q_name, 19498c2ecf20Sopenharmony_ci sizeof(instance->fault_handler_work_q_name), 19508c2ecf20Sopenharmony_ci "poll_megasas%d_status", instance->host->host_no); 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci instance->fw_fault_work_q = 19538c2ecf20Sopenharmony_ci create_singlethread_workqueue(instance->fault_handler_work_q_name); 19548c2ecf20Sopenharmony_ci if (!instance->fw_fault_work_q) { 19558c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed from %s %d\n", 19568c2ecf20Sopenharmony_ci __func__, __LINE__); 19578c2ecf20Sopenharmony_ci return FAILED; 19588c2ecf20Sopenharmony_ci } 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci queue_delayed_work(instance->fw_fault_work_q, 19618c2ecf20Sopenharmony_ci &instance->fw_fault_work, 19628c2ecf20Sopenharmony_ci msecs_to_jiffies(MEGASAS_WATCHDOG_THREAD_INTERVAL)); 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci return SUCCESS; 19658c2ecf20Sopenharmony_ci} 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_civoid 19688c2ecf20Sopenharmony_cimegasas_fusion_stop_watchdog(struct megasas_instance *instance) 19698c2ecf20Sopenharmony_ci{ 19708c2ecf20Sopenharmony_ci struct workqueue_struct *wq; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci if (instance->fw_fault_work_q) { 19738c2ecf20Sopenharmony_ci wq = instance->fw_fault_work_q; 19748c2ecf20Sopenharmony_ci instance->fw_fault_work_q = NULL; 19758c2ecf20Sopenharmony_ci if (!cancel_delayed_work_sync(&instance->fw_fault_work)) 19768c2ecf20Sopenharmony_ci flush_workqueue(wq); 19778c2ecf20Sopenharmony_ci destroy_workqueue(wq); 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci} 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci/** 19828c2ecf20Sopenharmony_ci * map_cmd_status - Maps FW cmd status to OS cmd status 19838c2ecf20Sopenharmony_ci * @fusion: fusion context 19848c2ecf20Sopenharmony_ci * @scmd: Pointer to cmd 19858c2ecf20Sopenharmony_ci * @status: status of cmd returned by FW 19868c2ecf20Sopenharmony_ci * @ext_status: ext status of cmd returned by FW 19878c2ecf20Sopenharmony_ci * @data_length: command data length 19888c2ecf20Sopenharmony_ci * @sense: command sense data 19898c2ecf20Sopenharmony_ci */ 19908c2ecf20Sopenharmony_cistatic void 19918c2ecf20Sopenharmony_cimap_cmd_status(struct fusion_context *fusion, 19928c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd, u8 status, u8 ext_status, 19938c2ecf20Sopenharmony_ci u32 data_length, u8 *sense) 19948c2ecf20Sopenharmony_ci{ 19958c2ecf20Sopenharmony_ci u8 cmd_type; 19968c2ecf20Sopenharmony_ci int resid; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci cmd_type = megasas_cmd_type(scmd); 19998c2ecf20Sopenharmony_ci switch (status) { 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci case MFI_STAT_OK: 20028c2ecf20Sopenharmony_ci scmd->result = DID_OK << 16; 20038c2ecf20Sopenharmony_ci break; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci case MFI_STAT_SCSI_IO_FAILED: 20068c2ecf20Sopenharmony_ci case MFI_STAT_LD_INIT_IN_PROGRESS: 20078c2ecf20Sopenharmony_ci scmd->result = (DID_ERROR << 16) | ext_status; 20088c2ecf20Sopenharmony_ci break; 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci case MFI_STAT_SCSI_DONE_WITH_ERROR: 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci scmd->result = (DID_OK << 16) | ext_status; 20138c2ecf20Sopenharmony_ci if (ext_status == SAM_STAT_CHECK_CONDITION) { 20148c2ecf20Sopenharmony_ci memset(scmd->sense_buffer, 0, 20158c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE); 20168c2ecf20Sopenharmony_ci memcpy(scmd->sense_buffer, sense, 20178c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE); 20188c2ecf20Sopenharmony_ci scmd->result |= DRIVER_SENSE << 24; 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci /* 20228c2ecf20Sopenharmony_ci * If the IO request is partially completed, then MR FW will 20238c2ecf20Sopenharmony_ci * update "io_request->DataLength" field with actual number of 20248c2ecf20Sopenharmony_ci * bytes transferred.Driver will set residual bytes count in 20258c2ecf20Sopenharmony_ci * SCSI command structure. 20268c2ecf20Sopenharmony_ci */ 20278c2ecf20Sopenharmony_ci resid = (scsi_bufflen(scmd) - data_length); 20288c2ecf20Sopenharmony_ci scsi_set_resid(scmd, resid); 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci if (resid && 20318c2ecf20Sopenharmony_ci ((cmd_type == READ_WRITE_LDIO) || 20328c2ecf20Sopenharmony_ci (cmd_type == READ_WRITE_SYSPDIO))) 20338c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, scmd, "BRCM Debug mfi stat 0x%x, data len" 20348c2ecf20Sopenharmony_ci " requested/completed 0x%x/0x%x\n", 20358c2ecf20Sopenharmony_ci status, scsi_bufflen(scmd), data_length); 20368c2ecf20Sopenharmony_ci break; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci case MFI_STAT_LD_OFFLINE: 20398c2ecf20Sopenharmony_ci case MFI_STAT_DEVICE_NOT_FOUND: 20408c2ecf20Sopenharmony_ci scmd->result = DID_BAD_TARGET << 16; 20418c2ecf20Sopenharmony_ci break; 20428c2ecf20Sopenharmony_ci case MFI_STAT_CONFIG_SEQ_MISMATCH: 20438c2ecf20Sopenharmony_ci scmd->result = DID_IMM_RETRY << 16; 20448c2ecf20Sopenharmony_ci break; 20458c2ecf20Sopenharmony_ci default: 20468c2ecf20Sopenharmony_ci scmd->result = DID_ERROR << 16; 20478c2ecf20Sopenharmony_ci break; 20488c2ecf20Sopenharmony_ci } 20498c2ecf20Sopenharmony_ci} 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci/** 20528c2ecf20Sopenharmony_ci * megasas_is_prp_possible - 20538c2ecf20Sopenharmony_ci * Checks if native NVMe PRPs can be built for the IO 20548c2ecf20Sopenharmony_ci * 20558c2ecf20Sopenharmony_ci * @instance: Adapter soft state 20568c2ecf20Sopenharmony_ci * @scmd: SCSI command from the mid-layer 20578c2ecf20Sopenharmony_ci * @sge_count: scatter gather element count. 20588c2ecf20Sopenharmony_ci * 20598c2ecf20Sopenharmony_ci * Returns: true: PRPs can be built 20608c2ecf20Sopenharmony_ci * false: IEEE SGLs needs to be built 20618c2ecf20Sopenharmony_ci */ 20628c2ecf20Sopenharmony_cistatic bool 20638c2ecf20Sopenharmony_cimegasas_is_prp_possible(struct megasas_instance *instance, 20648c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd, int sge_count) 20658c2ecf20Sopenharmony_ci{ 20668c2ecf20Sopenharmony_ci u32 data_length = 0; 20678c2ecf20Sopenharmony_ci struct scatterlist *sg_scmd; 20688c2ecf20Sopenharmony_ci bool build_prp = false; 20698c2ecf20Sopenharmony_ci u32 mr_nvme_pg_size; 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci mr_nvme_pg_size = max_t(u32, instance->nvme_page_size, 20728c2ecf20Sopenharmony_ci MR_DEFAULT_NVME_PAGE_SIZE); 20738c2ecf20Sopenharmony_ci data_length = scsi_bufflen(scmd); 20748c2ecf20Sopenharmony_ci sg_scmd = scsi_sglist(scmd); 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci /* 20778c2ecf20Sopenharmony_ci * NVMe uses one PRP for each page (or part of a page) 20788c2ecf20Sopenharmony_ci * look at the data length - if 4 pages or less then IEEE is OK 20798c2ecf20Sopenharmony_ci * if > 5 pages then we need to build a native SGL 20808c2ecf20Sopenharmony_ci * if > 4 and <= 5 pages, then check physical address of 1st SG entry 20818c2ecf20Sopenharmony_ci * if this first size in the page is >= the residual beyond 4 pages 20828c2ecf20Sopenharmony_ci * then use IEEE, otherwise use native SGL 20838c2ecf20Sopenharmony_ci */ 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci if (data_length > (mr_nvme_pg_size * 5)) { 20868c2ecf20Sopenharmony_ci build_prp = true; 20878c2ecf20Sopenharmony_ci } else if ((data_length > (mr_nvme_pg_size * 4)) && 20888c2ecf20Sopenharmony_ci (data_length <= (mr_nvme_pg_size * 5))) { 20898c2ecf20Sopenharmony_ci /* check if 1st SG entry size is < residual beyond 4 pages */ 20908c2ecf20Sopenharmony_ci if (sg_dma_len(sg_scmd) < (data_length - (mr_nvme_pg_size * 4))) 20918c2ecf20Sopenharmony_ci build_prp = true; 20928c2ecf20Sopenharmony_ci } 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci return build_prp; 20958c2ecf20Sopenharmony_ci} 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci/** 20988c2ecf20Sopenharmony_ci * megasas_make_prp_nvme - 20998c2ecf20Sopenharmony_ci * Prepare PRPs(Physical Region Page)- SGLs specific to NVMe drives only 21008c2ecf20Sopenharmony_ci * 21018c2ecf20Sopenharmony_ci * @instance: Adapter soft state 21028c2ecf20Sopenharmony_ci * @scmd: SCSI command from the mid-layer 21038c2ecf20Sopenharmony_ci * @sgl_ptr: SGL to be filled in 21048c2ecf20Sopenharmony_ci * @cmd: Fusion command frame 21058c2ecf20Sopenharmony_ci * @sge_count: scatter gather element count. 21068c2ecf20Sopenharmony_ci * 21078c2ecf20Sopenharmony_ci * Returns: true: PRPs are built 21088c2ecf20Sopenharmony_ci * false: IEEE SGLs needs to be built 21098c2ecf20Sopenharmony_ci */ 21108c2ecf20Sopenharmony_cistatic bool 21118c2ecf20Sopenharmony_cimegasas_make_prp_nvme(struct megasas_instance *instance, struct scsi_cmnd *scmd, 21128c2ecf20Sopenharmony_ci struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr, 21138c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd, int sge_count) 21148c2ecf20Sopenharmony_ci{ 21158c2ecf20Sopenharmony_ci int sge_len, offset, num_prp_in_chain = 0; 21168c2ecf20Sopenharmony_ci struct MPI25_IEEE_SGE_CHAIN64 *main_chain_element, *ptr_first_sgl; 21178c2ecf20Sopenharmony_ci u64 *ptr_sgl; 21188c2ecf20Sopenharmony_ci dma_addr_t ptr_sgl_phys; 21198c2ecf20Sopenharmony_ci u64 sge_addr; 21208c2ecf20Sopenharmony_ci u32 page_mask, page_mask_result; 21218c2ecf20Sopenharmony_ci struct scatterlist *sg_scmd; 21228c2ecf20Sopenharmony_ci u32 first_prp_len; 21238c2ecf20Sopenharmony_ci bool build_prp = false; 21248c2ecf20Sopenharmony_ci int data_len = scsi_bufflen(scmd); 21258c2ecf20Sopenharmony_ci u32 mr_nvme_pg_size = max_t(u32, instance->nvme_page_size, 21268c2ecf20Sopenharmony_ci MR_DEFAULT_NVME_PAGE_SIZE); 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci build_prp = megasas_is_prp_possible(instance, scmd, sge_count); 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci if (!build_prp) 21318c2ecf20Sopenharmony_ci return false; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci /* 21348c2ecf20Sopenharmony_ci * Nvme has a very convoluted prp format. One prp is required 21358c2ecf20Sopenharmony_ci * for each page or partial page. Driver need to split up OS sg_list 21368c2ecf20Sopenharmony_ci * entries if it is longer than one page or cross a page 21378c2ecf20Sopenharmony_ci * boundary. Driver also have to insert a PRP list pointer entry as 21388c2ecf20Sopenharmony_ci * the last entry in each physical page of the PRP list. 21398c2ecf20Sopenharmony_ci * 21408c2ecf20Sopenharmony_ci * NOTE: The first PRP "entry" is actually placed in the first 21418c2ecf20Sopenharmony_ci * SGL entry in the main message as IEEE 64 format. The 2nd 21428c2ecf20Sopenharmony_ci * entry in the main message is the chain element, and the rest 21438c2ecf20Sopenharmony_ci * of the PRP entries are built in the contiguous pcie buffer. 21448c2ecf20Sopenharmony_ci */ 21458c2ecf20Sopenharmony_ci page_mask = mr_nvme_pg_size - 1; 21468c2ecf20Sopenharmony_ci ptr_sgl = (u64 *)cmd->sg_frame; 21478c2ecf20Sopenharmony_ci ptr_sgl_phys = cmd->sg_frame_phys_addr; 21488c2ecf20Sopenharmony_ci memset(ptr_sgl, 0, instance->max_chain_frame_sz); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci /* Build chain frame element which holds all prps except first*/ 21518c2ecf20Sopenharmony_ci main_chain_element = (struct MPI25_IEEE_SGE_CHAIN64 *) 21528c2ecf20Sopenharmony_ci ((u8 *)sgl_ptr + sizeof(struct MPI25_IEEE_SGE_CHAIN64)); 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci main_chain_element->Address = cpu_to_le64(ptr_sgl_phys); 21558c2ecf20Sopenharmony_ci main_chain_element->NextChainOffset = 0; 21568c2ecf20Sopenharmony_ci main_chain_element->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT | 21578c2ecf20Sopenharmony_ci IEEE_SGE_FLAGS_SYSTEM_ADDR | 21588c2ecf20Sopenharmony_ci MPI26_IEEE_SGE_FLAGS_NSF_NVME_PRP; 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci /* Build first prp, sge need not to be page aligned*/ 21618c2ecf20Sopenharmony_ci ptr_first_sgl = sgl_ptr; 21628c2ecf20Sopenharmony_ci sg_scmd = scsi_sglist(scmd); 21638c2ecf20Sopenharmony_ci sge_addr = sg_dma_address(sg_scmd); 21648c2ecf20Sopenharmony_ci sge_len = sg_dma_len(sg_scmd); 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci offset = (u32)(sge_addr & page_mask); 21678c2ecf20Sopenharmony_ci first_prp_len = mr_nvme_pg_size - offset; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci ptr_first_sgl->Address = cpu_to_le64(sge_addr); 21708c2ecf20Sopenharmony_ci ptr_first_sgl->Length = cpu_to_le32(first_prp_len); 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci data_len -= first_prp_len; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci if (sge_len > first_prp_len) { 21758c2ecf20Sopenharmony_ci sge_addr += first_prp_len; 21768c2ecf20Sopenharmony_ci sge_len -= first_prp_len; 21778c2ecf20Sopenharmony_ci } else if (sge_len == first_prp_len) { 21788c2ecf20Sopenharmony_ci sg_scmd = sg_next(sg_scmd); 21798c2ecf20Sopenharmony_ci sge_addr = sg_dma_address(sg_scmd); 21808c2ecf20Sopenharmony_ci sge_len = sg_dma_len(sg_scmd); 21818c2ecf20Sopenharmony_ci } 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci for (;;) { 21848c2ecf20Sopenharmony_ci offset = (u32)(sge_addr & page_mask); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci /* Put PRP pointer due to page boundary*/ 21878c2ecf20Sopenharmony_ci page_mask_result = (uintptr_t)(ptr_sgl + 1) & page_mask; 21888c2ecf20Sopenharmony_ci if (unlikely(!page_mask_result)) { 21898c2ecf20Sopenharmony_ci scmd_printk(KERN_NOTICE, 21908c2ecf20Sopenharmony_ci scmd, "page boundary ptr_sgl: 0x%p\n", 21918c2ecf20Sopenharmony_ci ptr_sgl); 21928c2ecf20Sopenharmony_ci ptr_sgl_phys += 8; 21938c2ecf20Sopenharmony_ci *ptr_sgl = cpu_to_le64(ptr_sgl_phys); 21948c2ecf20Sopenharmony_ci ptr_sgl++; 21958c2ecf20Sopenharmony_ci num_prp_in_chain++; 21968c2ecf20Sopenharmony_ci } 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci *ptr_sgl = cpu_to_le64(sge_addr); 21998c2ecf20Sopenharmony_ci ptr_sgl++; 22008c2ecf20Sopenharmony_ci ptr_sgl_phys += 8; 22018c2ecf20Sopenharmony_ci num_prp_in_chain++; 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci sge_addr += mr_nvme_pg_size; 22048c2ecf20Sopenharmony_ci sge_len -= mr_nvme_pg_size; 22058c2ecf20Sopenharmony_ci data_len -= mr_nvme_pg_size; 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci if (data_len <= 0) 22088c2ecf20Sopenharmony_ci break; 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci if (sge_len > 0) 22118c2ecf20Sopenharmony_ci continue; 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci sg_scmd = sg_next(sg_scmd); 22148c2ecf20Sopenharmony_ci sge_addr = sg_dma_address(sg_scmd); 22158c2ecf20Sopenharmony_ci sge_len = sg_dma_len(sg_scmd); 22168c2ecf20Sopenharmony_ci } 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci main_chain_element->Length = 22198c2ecf20Sopenharmony_ci cpu_to_le32(num_prp_in_chain * sizeof(u64)); 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci return build_prp; 22228c2ecf20Sopenharmony_ci} 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci/** 22258c2ecf20Sopenharmony_ci * megasas_make_sgl_fusion - Prepares 32-bit SGL 22268c2ecf20Sopenharmony_ci * @instance: Adapter soft state 22278c2ecf20Sopenharmony_ci * @scp: SCSI command from the mid-layer 22288c2ecf20Sopenharmony_ci * @sgl_ptr: SGL to be filled in 22298c2ecf20Sopenharmony_ci * @cmd: cmd we are working on 22308c2ecf20Sopenharmony_ci * @sge_count: sge count 22318c2ecf20Sopenharmony_ci * 22328c2ecf20Sopenharmony_ci */ 22338c2ecf20Sopenharmony_cistatic void 22348c2ecf20Sopenharmony_cimegasas_make_sgl_fusion(struct megasas_instance *instance, 22358c2ecf20Sopenharmony_ci struct scsi_cmnd *scp, 22368c2ecf20Sopenharmony_ci struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr, 22378c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd, int sge_count) 22388c2ecf20Sopenharmony_ci{ 22398c2ecf20Sopenharmony_ci int i, sg_processed; 22408c2ecf20Sopenharmony_ci struct scatterlist *os_sgl; 22418c2ecf20Sopenharmony_ci struct fusion_context *fusion; 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci if (instance->adapter_type >= INVADER_SERIES) { 22468c2ecf20Sopenharmony_ci struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = sgl_ptr; 22478c2ecf20Sopenharmony_ci sgl_ptr_end += fusion->max_sge_in_main_msg - 1; 22488c2ecf20Sopenharmony_ci sgl_ptr_end->Flags = 0; 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci scsi_for_each_sg(scp, os_sgl, sge_count, i) { 22528c2ecf20Sopenharmony_ci sgl_ptr->Length = cpu_to_le32(sg_dma_len(os_sgl)); 22538c2ecf20Sopenharmony_ci sgl_ptr->Address = cpu_to_le64(sg_dma_address(os_sgl)); 22548c2ecf20Sopenharmony_ci sgl_ptr->Flags = 0; 22558c2ecf20Sopenharmony_ci if (instance->adapter_type >= INVADER_SERIES) 22568c2ecf20Sopenharmony_ci if (i == sge_count - 1) 22578c2ecf20Sopenharmony_ci sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST; 22588c2ecf20Sopenharmony_ci sgl_ptr++; 22598c2ecf20Sopenharmony_ci sg_processed = i + 1; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci if ((sg_processed == (fusion->max_sge_in_main_msg - 1)) && 22628c2ecf20Sopenharmony_ci (sge_count > fusion->max_sge_in_main_msg)) { 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci struct MPI25_IEEE_SGE_CHAIN64 *sg_chain; 22658c2ecf20Sopenharmony_ci if (instance->adapter_type >= INVADER_SERIES) { 22668c2ecf20Sopenharmony_ci if ((le16_to_cpu(cmd->io_request->IoFlags) & 22678c2ecf20Sopenharmony_ci MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) != 22688c2ecf20Sopenharmony_ci MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) 22698c2ecf20Sopenharmony_ci cmd->io_request->ChainOffset = 22708c2ecf20Sopenharmony_ci fusion-> 22718c2ecf20Sopenharmony_ci chain_offset_io_request; 22728c2ecf20Sopenharmony_ci else 22738c2ecf20Sopenharmony_ci cmd->io_request->ChainOffset = 0; 22748c2ecf20Sopenharmony_ci } else 22758c2ecf20Sopenharmony_ci cmd->io_request->ChainOffset = 22768c2ecf20Sopenharmony_ci fusion->chain_offset_io_request; 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci sg_chain = sgl_ptr; 22798c2ecf20Sopenharmony_ci /* Prepare chain element */ 22808c2ecf20Sopenharmony_ci sg_chain->NextChainOffset = 0; 22818c2ecf20Sopenharmony_ci if (instance->adapter_type >= INVADER_SERIES) 22828c2ecf20Sopenharmony_ci sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT; 22838c2ecf20Sopenharmony_ci else 22848c2ecf20Sopenharmony_ci sg_chain->Flags = 22858c2ecf20Sopenharmony_ci (IEEE_SGE_FLAGS_CHAIN_ELEMENT | 22868c2ecf20Sopenharmony_ci MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR); 22878c2ecf20Sopenharmony_ci sg_chain->Length = cpu_to_le32((sizeof(union MPI2_SGE_IO_UNION) * (sge_count - sg_processed))); 22888c2ecf20Sopenharmony_ci sg_chain->Address = cpu_to_le64(cmd->sg_frame_phys_addr); 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci sgl_ptr = 22918c2ecf20Sopenharmony_ci (struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame; 22928c2ecf20Sopenharmony_ci memset(sgl_ptr, 0, instance->max_chain_frame_sz); 22938c2ecf20Sopenharmony_ci } 22948c2ecf20Sopenharmony_ci } 22958c2ecf20Sopenharmony_ci} 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci/** 22988c2ecf20Sopenharmony_ci * megasas_make_sgl - Build Scatter Gather List(SGLs) 22998c2ecf20Sopenharmony_ci * @scp: SCSI command pointer 23008c2ecf20Sopenharmony_ci * @instance: Soft instance of controller 23018c2ecf20Sopenharmony_ci * @cmd: Fusion command pointer 23028c2ecf20Sopenharmony_ci * 23038c2ecf20Sopenharmony_ci * This function will build sgls based on device type. 23048c2ecf20Sopenharmony_ci * For nvme drives, there is different way of building sgls in nvme native 23058c2ecf20Sopenharmony_ci * format- PRPs(Physical Region Page). 23068c2ecf20Sopenharmony_ci * 23078c2ecf20Sopenharmony_ci * Returns the number of sg lists actually used, zero if the sg lists 23088c2ecf20Sopenharmony_ci * is NULL, or -ENOMEM if the mapping failed 23098c2ecf20Sopenharmony_ci */ 23108c2ecf20Sopenharmony_cistatic 23118c2ecf20Sopenharmony_ciint megasas_make_sgl(struct megasas_instance *instance, struct scsi_cmnd *scp, 23128c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd) 23138c2ecf20Sopenharmony_ci{ 23148c2ecf20Sopenharmony_ci int sge_count; 23158c2ecf20Sopenharmony_ci bool build_prp = false; 23168c2ecf20Sopenharmony_ci struct MPI25_IEEE_SGE_CHAIN64 *sgl_chain64; 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci sge_count = scsi_dma_map(scp); 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci if ((sge_count > instance->max_num_sge) || (sge_count <= 0)) 23218c2ecf20Sopenharmony_ci return sge_count; 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci sgl_chain64 = (struct MPI25_IEEE_SGE_CHAIN64 *)&cmd->io_request->SGL; 23248c2ecf20Sopenharmony_ci if ((le16_to_cpu(cmd->io_request->IoFlags) & 23258c2ecf20Sopenharmony_ci MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) && 23268c2ecf20Sopenharmony_ci (cmd->pd_interface == NVME_PD)) 23278c2ecf20Sopenharmony_ci build_prp = megasas_make_prp_nvme(instance, scp, sgl_chain64, 23288c2ecf20Sopenharmony_ci cmd, sge_count); 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci if (!build_prp) 23318c2ecf20Sopenharmony_ci megasas_make_sgl_fusion(instance, scp, sgl_chain64, 23328c2ecf20Sopenharmony_ci cmd, sge_count); 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci return sge_count; 23358c2ecf20Sopenharmony_ci} 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci/** 23388c2ecf20Sopenharmony_ci * megasas_set_pd_lba - Sets PD LBA 23398c2ecf20Sopenharmony_ci * @io_request: IO request 23408c2ecf20Sopenharmony_ci * @cdb_len: cdb length 23418c2ecf20Sopenharmony_ci * @io_info: IO information 23428c2ecf20Sopenharmony_ci * @scp: SCSI command 23438c2ecf20Sopenharmony_ci * @local_map_ptr: Raid map 23448c2ecf20Sopenharmony_ci * @ref_tag: Primary reference tag 23458c2ecf20Sopenharmony_ci * 23468c2ecf20Sopenharmony_ci * Used to set the PD LBA in CDB for FP IOs 23478c2ecf20Sopenharmony_ci */ 23488c2ecf20Sopenharmony_cistatic void 23498c2ecf20Sopenharmony_cimegasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len, 23508c2ecf20Sopenharmony_ci struct IO_REQUEST_INFO *io_info, struct scsi_cmnd *scp, 23518c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *local_map_ptr, u32 ref_tag) 23528c2ecf20Sopenharmony_ci{ 23538c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid; 23548c2ecf20Sopenharmony_ci u16 ld; 23558c2ecf20Sopenharmony_ci u64 start_blk = io_info->pdBlock; 23568c2ecf20Sopenharmony_ci u8 *cdb = io_request->CDB.CDB32; 23578c2ecf20Sopenharmony_ci u32 num_blocks = io_info->numBlocks; 23588c2ecf20Sopenharmony_ci u8 opcode = 0, flagvals = 0, groupnum = 0, control = 0; 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci /* Check if T10 PI (DIF) is enabled for this LD */ 23618c2ecf20Sopenharmony_ci ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr); 23628c2ecf20Sopenharmony_ci raid = MR_LdRaidGet(ld, local_map_ptr); 23638c2ecf20Sopenharmony_ci if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) { 23648c2ecf20Sopenharmony_ci memset(cdb, 0, sizeof(io_request->CDB.CDB32)); 23658c2ecf20Sopenharmony_ci cdb[0] = MEGASAS_SCSI_VARIABLE_LENGTH_CMD; 23668c2ecf20Sopenharmony_ci cdb[7] = MEGASAS_SCSI_ADDL_CDB_LEN; 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci if (scp->sc_data_direction == DMA_FROM_DEVICE) 23698c2ecf20Sopenharmony_ci cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_READ32; 23708c2ecf20Sopenharmony_ci else 23718c2ecf20Sopenharmony_ci cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_WRITE32; 23728c2ecf20Sopenharmony_ci cdb[10] = MEGASAS_RD_WR_PROTECT_CHECK_ALL; 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci /* LBA */ 23758c2ecf20Sopenharmony_ci cdb[12] = (u8)((start_blk >> 56) & 0xff); 23768c2ecf20Sopenharmony_ci cdb[13] = (u8)((start_blk >> 48) & 0xff); 23778c2ecf20Sopenharmony_ci cdb[14] = (u8)((start_blk >> 40) & 0xff); 23788c2ecf20Sopenharmony_ci cdb[15] = (u8)((start_blk >> 32) & 0xff); 23798c2ecf20Sopenharmony_ci cdb[16] = (u8)((start_blk >> 24) & 0xff); 23808c2ecf20Sopenharmony_ci cdb[17] = (u8)((start_blk >> 16) & 0xff); 23818c2ecf20Sopenharmony_ci cdb[18] = (u8)((start_blk >> 8) & 0xff); 23828c2ecf20Sopenharmony_ci cdb[19] = (u8)(start_blk & 0xff); 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci /* Logical block reference tag */ 23858c2ecf20Sopenharmony_ci io_request->CDB.EEDP32.PrimaryReferenceTag = 23868c2ecf20Sopenharmony_ci cpu_to_be32(ref_tag); 23878c2ecf20Sopenharmony_ci io_request->CDB.EEDP32.PrimaryApplicationTagMask = cpu_to_be16(0xffff); 23888c2ecf20Sopenharmony_ci io_request->IoFlags = cpu_to_le16(32); /* Specify 32-byte cdb */ 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci /* Transfer length */ 23918c2ecf20Sopenharmony_ci cdb[28] = (u8)((num_blocks >> 24) & 0xff); 23928c2ecf20Sopenharmony_ci cdb[29] = (u8)((num_blocks >> 16) & 0xff); 23938c2ecf20Sopenharmony_ci cdb[30] = (u8)((num_blocks >> 8) & 0xff); 23948c2ecf20Sopenharmony_ci cdb[31] = (u8)(num_blocks & 0xff); 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci /* set SCSI IO EEDPFlags */ 23978c2ecf20Sopenharmony_ci if (scp->sc_data_direction == DMA_FROM_DEVICE) { 23988c2ecf20Sopenharmony_ci io_request->EEDPFlags = cpu_to_le16( 23998c2ecf20Sopenharmony_ci MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | 24008c2ecf20Sopenharmony_ci MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | 24018c2ecf20Sopenharmony_ci MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP | 24028c2ecf20Sopenharmony_ci MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG | 24038c2ecf20Sopenharmony_ci MPI25_SCSIIO_EEDPFLAGS_DO_NOT_DISABLE_MODE | 24048c2ecf20Sopenharmony_ci MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD); 24058c2ecf20Sopenharmony_ci } else { 24068c2ecf20Sopenharmony_ci io_request->EEDPFlags = cpu_to_le16( 24078c2ecf20Sopenharmony_ci MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | 24088c2ecf20Sopenharmony_ci MPI2_SCSIIO_EEDPFLAGS_INSERT_OP); 24098c2ecf20Sopenharmony_ci } 24108c2ecf20Sopenharmony_ci io_request->Control |= cpu_to_le32((0x4 << 26)); 24118c2ecf20Sopenharmony_ci io_request->EEDPBlockSize = cpu_to_le32(scp->device->sector_size); 24128c2ecf20Sopenharmony_ci } else { 24138c2ecf20Sopenharmony_ci /* Some drives don't support 16/12 byte CDB's, convert to 10 */ 24148c2ecf20Sopenharmony_ci if (((cdb_len == 12) || (cdb_len == 16)) && 24158c2ecf20Sopenharmony_ci (start_blk <= 0xffffffff)) { 24168c2ecf20Sopenharmony_ci if (cdb_len == 16) { 24178c2ecf20Sopenharmony_ci opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10; 24188c2ecf20Sopenharmony_ci flagvals = cdb[1]; 24198c2ecf20Sopenharmony_ci groupnum = cdb[14]; 24208c2ecf20Sopenharmony_ci control = cdb[15]; 24218c2ecf20Sopenharmony_ci } else { 24228c2ecf20Sopenharmony_ci opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10; 24238c2ecf20Sopenharmony_ci flagvals = cdb[1]; 24248c2ecf20Sopenharmony_ci groupnum = cdb[10]; 24258c2ecf20Sopenharmony_ci control = cdb[11]; 24268c2ecf20Sopenharmony_ci } 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci memset(cdb, 0, sizeof(io_request->CDB.CDB32)); 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci cdb[0] = opcode; 24318c2ecf20Sopenharmony_ci cdb[1] = flagvals; 24328c2ecf20Sopenharmony_ci cdb[6] = groupnum; 24338c2ecf20Sopenharmony_ci cdb[9] = control; 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci /* Transfer length */ 24368c2ecf20Sopenharmony_ci cdb[8] = (u8)(num_blocks & 0xff); 24378c2ecf20Sopenharmony_ci cdb[7] = (u8)((num_blocks >> 8) & 0xff); 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci io_request->IoFlags = cpu_to_le16(10); /* Specify 10-byte cdb */ 24408c2ecf20Sopenharmony_ci cdb_len = 10; 24418c2ecf20Sopenharmony_ci } else if ((cdb_len < 16) && (start_blk > 0xffffffff)) { 24428c2ecf20Sopenharmony_ci /* Convert to 16 byte CDB for large LBA's */ 24438c2ecf20Sopenharmony_ci switch (cdb_len) { 24448c2ecf20Sopenharmony_ci case 6: 24458c2ecf20Sopenharmony_ci opcode = cdb[0] == READ_6 ? READ_16 : WRITE_16; 24468c2ecf20Sopenharmony_ci control = cdb[5]; 24478c2ecf20Sopenharmony_ci break; 24488c2ecf20Sopenharmony_ci case 10: 24498c2ecf20Sopenharmony_ci opcode = 24508c2ecf20Sopenharmony_ci cdb[0] == READ_10 ? READ_16 : WRITE_16; 24518c2ecf20Sopenharmony_ci flagvals = cdb[1]; 24528c2ecf20Sopenharmony_ci groupnum = cdb[6]; 24538c2ecf20Sopenharmony_ci control = cdb[9]; 24548c2ecf20Sopenharmony_ci break; 24558c2ecf20Sopenharmony_ci case 12: 24568c2ecf20Sopenharmony_ci opcode = 24578c2ecf20Sopenharmony_ci cdb[0] == READ_12 ? READ_16 : WRITE_16; 24588c2ecf20Sopenharmony_ci flagvals = cdb[1]; 24598c2ecf20Sopenharmony_ci groupnum = cdb[10]; 24608c2ecf20Sopenharmony_ci control = cdb[11]; 24618c2ecf20Sopenharmony_ci break; 24628c2ecf20Sopenharmony_ci } 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci memset(cdb, 0, sizeof(io_request->CDB.CDB32)); 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci cdb[0] = opcode; 24678c2ecf20Sopenharmony_ci cdb[1] = flagvals; 24688c2ecf20Sopenharmony_ci cdb[14] = groupnum; 24698c2ecf20Sopenharmony_ci cdb[15] = control; 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci /* Transfer length */ 24728c2ecf20Sopenharmony_ci cdb[13] = (u8)(num_blocks & 0xff); 24738c2ecf20Sopenharmony_ci cdb[12] = (u8)((num_blocks >> 8) & 0xff); 24748c2ecf20Sopenharmony_ci cdb[11] = (u8)((num_blocks >> 16) & 0xff); 24758c2ecf20Sopenharmony_ci cdb[10] = (u8)((num_blocks >> 24) & 0xff); 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci io_request->IoFlags = cpu_to_le16(16); /* Specify 16-byte cdb */ 24788c2ecf20Sopenharmony_ci cdb_len = 16; 24798c2ecf20Sopenharmony_ci } 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci /* Normal case, just load LBA here */ 24828c2ecf20Sopenharmony_ci switch (cdb_len) { 24838c2ecf20Sopenharmony_ci case 6: 24848c2ecf20Sopenharmony_ci { 24858c2ecf20Sopenharmony_ci u8 val = cdb[1] & 0xE0; 24868c2ecf20Sopenharmony_ci cdb[3] = (u8)(start_blk & 0xff); 24878c2ecf20Sopenharmony_ci cdb[2] = (u8)((start_blk >> 8) & 0xff); 24888c2ecf20Sopenharmony_ci cdb[1] = val | ((u8)(start_blk >> 16) & 0x1f); 24898c2ecf20Sopenharmony_ci break; 24908c2ecf20Sopenharmony_ci } 24918c2ecf20Sopenharmony_ci case 10: 24928c2ecf20Sopenharmony_ci cdb[5] = (u8)(start_blk & 0xff); 24938c2ecf20Sopenharmony_ci cdb[4] = (u8)((start_blk >> 8) & 0xff); 24948c2ecf20Sopenharmony_ci cdb[3] = (u8)((start_blk >> 16) & 0xff); 24958c2ecf20Sopenharmony_ci cdb[2] = (u8)((start_blk >> 24) & 0xff); 24968c2ecf20Sopenharmony_ci break; 24978c2ecf20Sopenharmony_ci case 12: 24988c2ecf20Sopenharmony_ci cdb[5] = (u8)(start_blk & 0xff); 24998c2ecf20Sopenharmony_ci cdb[4] = (u8)((start_blk >> 8) & 0xff); 25008c2ecf20Sopenharmony_ci cdb[3] = (u8)((start_blk >> 16) & 0xff); 25018c2ecf20Sopenharmony_ci cdb[2] = (u8)((start_blk >> 24) & 0xff); 25028c2ecf20Sopenharmony_ci break; 25038c2ecf20Sopenharmony_ci case 16: 25048c2ecf20Sopenharmony_ci cdb[9] = (u8)(start_blk & 0xff); 25058c2ecf20Sopenharmony_ci cdb[8] = (u8)((start_blk >> 8) & 0xff); 25068c2ecf20Sopenharmony_ci cdb[7] = (u8)((start_blk >> 16) & 0xff); 25078c2ecf20Sopenharmony_ci cdb[6] = (u8)((start_blk >> 24) & 0xff); 25088c2ecf20Sopenharmony_ci cdb[5] = (u8)((start_blk >> 32) & 0xff); 25098c2ecf20Sopenharmony_ci cdb[4] = (u8)((start_blk >> 40) & 0xff); 25108c2ecf20Sopenharmony_ci cdb[3] = (u8)((start_blk >> 48) & 0xff); 25118c2ecf20Sopenharmony_ci cdb[2] = (u8)((start_blk >> 56) & 0xff); 25128c2ecf20Sopenharmony_ci break; 25138c2ecf20Sopenharmony_ci } 25148c2ecf20Sopenharmony_ci } 25158c2ecf20Sopenharmony_ci} 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci/** 25188c2ecf20Sopenharmony_ci * megasas_stream_detect - stream detection on read and and write IOs 25198c2ecf20Sopenharmony_ci * @instance: Adapter soft state 25208c2ecf20Sopenharmony_ci * @cmd: Command to be prepared 25218c2ecf20Sopenharmony_ci * @io_info: IO Request info 25228c2ecf20Sopenharmony_ci * 25238c2ecf20Sopenharmony_ci */ 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci/** stream detection on read and and write IOs */ 25268c2ecf20Sopenharmony_cistatic void megasas_stream_detect(struct megasas_instance *instance, 25278c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd, 25288c2ecf20Sopenharmony_ci struct IO_REQUEST_INFO *io_info) 25298c2ecf20Sopenharmony_ci{ 25308c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 25318c2ecf20Sopenharmony_ci u32 device_id = io_info->ldTgtId; 25328c2ecf20Sopenharmony_ci struct LD_STREAM_DETECT *current_ld_sd 25338c2ecf20Sopenharmony_ci = fusion->stream_detect_by_ld[device_id]; 25348c2ecf20Sopenharmony_ci u32 *track_stream = ¤t_ld_sd->mru_bit_map, stream_num; 25358c2ecf20Sopenharmony_ci u32 shifted_values, unshifted_values; 25368c2ecf20Sopenharmony_ci u32 index_value_mask, shifted_values_mask; 25378c2ecf20Sopenharmony_ci int i; 25388c2ecf20Sopenharmony_ci bool is_read_ahead = false; 25398c2ecf20Sopenharmony_ci struct STREAM_DETECT *current_sd; 25408c2ecf20Sopenharmony_ci /* find possible stream */ 25418c2ecf20Sopenharmony_ci for (i = 0; i < MAX_STREAMS_TRACKED; ++i) { 25428c2ecf20Sopenharmony_ci stream_num = (*track_stream >> 25438c2ecf20Sopenharmony_ci (i * BITS_PER_INDEX_STREAM)) & 25448c2ecf20Sopenharmony_ci STREAM_MASK; 25458c2ecf20Sopenharmony_ci current_sd = ¤t_ld_sd->stream_track[stream_num]; 25468c2ecf20Sopenharmony_ci /* if we found a stream, update the raid 25478c2ecf20Sopenharmony_ci * context and also update the mruBitMap 25488c2ecf20Sopenharmony_ci */ 25498c2ecf20Sopenharmony_ci /* boundary condition */ 25508c2ecf20Sopenharmony_ci if ((current_sd->next_seq_lba) && 25518c2ecf20Sopenharmony_ci (io_info->ldStartBlock >= current_sd->next_seq_lba) && 25528c2ecf20Sopenharmony_ci (io_info->ldStartBlock <= (current_sd->next_seq_lba + 32)) && 25538c2ecf20Sopenharmony_ci (current_sd->is_read == io_info->isRead)) { 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci if ((io_info->ldStartBlock != current_sd->next_seq_lba) && 25568c2ecf20Sopenharmony_ci ((!io_info->isRead) || (!is_read_ahead))) 25578c2ecf20Sopenharmony_ci /* 25588c2ecf20Sopenharmony_ci * Once the API availible we need to change this. 25598c2ecf20Sopenharmony_ci * At this point we are not allowing any gap 25608c2ecf20Sopenharmony_ci */ 25618c2ecf20Sopenharmony_ci continue; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci SET_STREAM_DETECTED(cmd->io_request->RaidContext.raid_context_g35); 25648c2ecf20Sopenharmony_ci current_sd->next_seq_lba = 25658c2ecf20Sopenharmony_ci io_info->ldStartBlock + io_info->numBlocks; 25668c2ecf20Sopenharmony_ci /* 25678c2ecf20Sopenharmony_ci * update the mruBitMap LRU 25688c2ecf20Sopenharmony_ci */ 25698c2ecf20Sopenharmony_ci shifted_values_mask = 25708c2ecf20Sopenharmony_ci (1 << i * BITS_PER_INDEX_STREAM) - 1; 25718c2ecf20Sopenharmony_ci shifted_values = ((*track_stream & shifted_values_mask) 25728c2ecf20Sopenharmony_ci << BITS_PER_INDEX_STREAM); 25738c2ecf20Sopenharmony_ci index_value_mask = 25748c2ecf20Sopenharmony_ci STREAM_MASK << i * BITS_PER_INDEX_STREAM; 25758c2ecf20Sopenharmony_ci unshifted_values = 25768c2ecf20Sopenharmony_ci *track_stream & ~(shifted_values_mask | 25778c2ecf20Sopenharmony_ci index_value_mask); 25788c2ecf20Sopenharmony_ci *track_stream = 25798c2ecf20Sopenharmony_ci unshifted_values | shifted_values | stream_num; 25808c2ecf20Sopenharmony_ci return; 25818c2ecf20Sopenharmony_ci } 25828c2ecf20Sopenharmony_ci } 25838c2ecf20Sopenharmony_ci /* 25848c2ecf20Sopenharmony_ci * if we did not find any stream, create a new one 25858c2ecf20Sopenharmony_ci * from the least recently used 25868c2ecf20Sopenharmony_ci */ 25878c2ecf20Sopenharmony_ci stream_num = (*track_stream >> 25888c2ecf20Sopenharmony_ci ((MAX_STREAMS_TRACKED - 1) * BITS_PER_INDEX_STREAM)) & 25898c2ecf20Sopenharmony_ci STREAM_MASK; 25908c2ecf20Sopenharmony_ci current_sd = ¤t_ld_sd->stream_track[stream_num]; 25918c2ecf20Sopenharmony_ci current_sd->is_read = io_info->isRead; 25928c2ecf20Sopenharmony_ci current_sd->next_seq_lba = io_info->ldStartBlock + io_info->numBlocks; 25938c2ecf20Sopenharmony_ci *track_stream = (((*track_stream & ZERO_LAST_STREAM) << 4) | stream_num); 25948c2ecf20Sopenharmony_ci return; 25958c2ecf20Sopenharmony_ci} 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci/** 25988c2ecf20Sopenharmony_ci * megasas_set_raidflag_cpu_affinity - This function sets the cpu 25998c2ecf20Sopenharmony_ci * affinity (cpu of the controller) and raid_flags in the raid context 26008c2ecf20Sopenharmony_ci * based on IO type. 26018c2ecf20Sopenharmony_ci * 26028c2ecf20Sopenharmony_ci * @fusion: Fusion context 26038c2ecf20Sopenharmony_ci * @praid_context: IO RAID context 26048c2ecf20Sopenharmony_ci * @raid: LD raid map 26058c2ecf20Sopenharmony_ci * @fp_possible: Is fast path possible? 26068c2ecf20Sopenharmony_ci * @is_read: Is read IO? 26078c2ecf20Sopenharmony_ci * @scsi_buff_len: SCSI command buffer length 26088c2ecf20Sopenharmony_ci * 26098c2ecf20Sopenharmony_ci */ 26108c2ecf20Sopenharmony_cistatic void 26118c2ecf20Sopenharmony_cimegasas_set_raidflag_cpu_affinity(struct fusion_context *fusion, 26128c2ecf20Sopenharmony_ci union RAID_CONTEXT_UNION *praid_context, 26138c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid, bool fp_possible, 26148c2ecf20Sopenharmony_ci u8 is_read, u32 scsi_buff_len) 26158c2ecf20Sopenharmony_ci{ 26168c2ecf20Sopenharmony_ci u8 cpu_sel = MR_RAID_CTX_CPUSEL_0; 26178c2ecf20Sopenharmony_ci struct RAID_CONTEXT_G35 *rctx_g35; 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci rctx_g35 = &praid_context->raid_context_g35; 26208c2ecf20Sopenharmony_ci if (fp_possible) { 26218c2ecf20Sopenharmony_ci if (is_read) { 26228c2ecf20Sopenharmony_ci if ((raid->cpuAffinity.pdRead.cpu0) && 26238c2ecf20Sopenharmony_ci (raid->cpuAffinity.pdRead.cpu1)) 26248c2ecf20Sopenharmony_ci cpu_sel = MR_RAID_CTX_CPUSEL_FCFS; 26258c2ecf20Sopenharmony_ci else if (raid->cpuAffinity.pdRead.cpu1) 26268c2ecf20Sopenharmony_ci cpu_sel = MR_RAID_CTX_CPUSEL_1; 26278c2ecf20Sopenharmony_ci } else { 26288c2ecf20Sopenharmony_ci if ((raid->cpuAffinity.pdWrite.cpu0) && 26298c2ecf20Sopenharmony_ci (raid->cpuAffinity.pdWrite.cpu1)) 26308c2ecf20Sopenharmony_ci cpu_sel = MR_RAID_CTX_CPUSEL_FCFS; 26318c2ecf20Sopenharmony_ci else if (raid->cpuAffinity.pdWrite.cpu1) 26328c2ecf20Sopenharmony_ci cpu_sel = MR_RAID_CTX_CPUSEL_1; 26338c2ecf20Sopenharmony_ci /* Fast path cache by pass capable R0/R1 VD */ 26348c2ecf20Sopenharmony_ci if ((raid->level <= 1) && 26358c2ecf20Sopenharmony_ci (raid->capability.fp_cache_bypass_capable)) { 26368c2ecf20Sopenharmony_ci rctx_g35->routing_flags |= 26378c2ecf20Sopenharmony_ci (1 << MR_RAID_CTX_ROUTINGFLAGS_SLD_SHIFT); 26388c2ecf20Sopenharmony_ci rctx_g35->raid_flags = 26398c2ecf20Sopenharmony_ci (MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS 26408c2ecf20Sopenharmony_ci << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT); 26418c2ecf20Sopenharmony_ci } 26428c2ecf20Sopenharmony_ci } 26438c2ecf20Sopenharmony_ci } else { 26448c2ecf20Sopenharmony_ci if (is_read) { 26458c2ecf20Sopenharmony_ci if ((raid->cpuAffinity.ldRead.cpu0) && 26468c2ecf20Sopenharmony_ci (raid->cpuAffinity.ldRead.cpu1)) 26478c2ecf20Sopenharmony_ci cpu_sel = MR_RAID_CTX_CPUSEL_FCFS; 26488c2ecf20Sopenharmony_ci else if (raid->cpuAffinity.ldRead.cpu1) 26498c2ecf20Sopenharmony_ci cpu_sel = MR_RAID_CTX_CPUSEL_1; 26508c2ecf20Sopenharmony_ci } else { 26518c2ecf20Sopenharmony_ci if ((raid->cpuAffinity.ldWrite.cpu0) && 26528c2ecf20Sopenharmony_ci (raid->cpuAffinity.ldWrite.cpu1)) 26538c2ecf20Sopenharmony_ci cpu_sel = MR_RAID_CTX_CPUSEL_FCFS; 26548c2ecf20Sopenharmony_ci else if (raid->cpuAffinity.ldWrite.cpu1) 26558c2ecf20Sopenharmony_ci cpu_sel = MR_RAID_CTX_CPUSEL_1; 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci if (is_stream_detected(rctx_g35) && 26588c2ecf20Sopenharmony_ci ((raid->level == 5) || (raid->level == 6)) && 26598c2ecf20Sopenharmony_ci (raid->writeMode == MR_RL_WRITE_THROUGH_MODE) && 26608c2ecf20Sopenharmony_ci (cpu_sel == MR_RAID_CTX_CPUSEL_FCFS)) 26618c2ecf20Sopenharmony_ci cpu_sel = MR_RAID_CTX_CPUSEL_0; 26628c2ecf20Sopenharmony_ci } 26638c2ecf20Sopenharmony_ci } 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci rctx_g35->routing_flags |= 26668c2ecf20Sopenharmony_ci (cpu_sel << MR_RAID_CTX_ROUTINGFLAGS_CPUSEL_SHIFT); 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci /* Always give priority to MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT 26698c2ecf20Sopenharmony_ci * vs MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS. 26708c2ecf20Sopenharmony_ci * IO Subtype is not bitmap. 26718c2ecf20Sopenharmony_ci */ 26728c2ecf20Sopenharmony_ci if ((fusion->pcie_bw_limitation) && (raid->level == 1) && (!is_read) && 26738c2ecf20Sopenharmony_ci (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)) { 26748c2ecf20Sopenharmony_ci praid_context->raid_context_g35.raid_flags = 26758c2ecf20Sopenharmony_ci (MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT 26768c2ecf20Sopenharmony_ci << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT); 26778c2ecf20Sopenharmony_ci } 26788c2ecf20Sopenharmony_ci} 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci/** 26818c2ecf20Sopenharmony_ci * megasas_build_ldio_fusion - Prepares IOs to devices 26828c2ecf20Sopenharmony_ci * @instance: Adapter soft state 26838c2ecf20Sopenharmony_ci * @scp: SCSI command 26848c2ecf20Sopenharmony_ci * @cmd: Command to be prepared 26858c2ecf20Sopenharmony_ci * 26868c2ecf20Sopenharmony_ci * Prepares the io_request and chain elements (sg_frame) for IO 26878c2ecf20Sopenharmony_ci * The IO can be for PD (Fast Path) or LD 26888c2ecf20Sopenharmony_ci */ 26898c2ecf20Sopenharmony_cistatic void 26908c2ecf20Sopenharmony_cimegasas_build_ldio_fusion(struct megasas_instance *instance, 26918c2ecf20Sopenharmony_ci struct scsi_cmnd *scp, 26928c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd) 26938c2ecf20Sopenharmony_ci{ 26948c2ecf20Sopenharmony_ci bool fp_possible; 26958c2ecf20Sopenharmony_ci u16 ld; 26968c2ecf20Sopenharmony_ci u32 start_lba_lo, start_lba_hi, device_id, datalength = 0; 26978c2ecf20Sopenharmony_ci u32 scsi_buff_len; 26988c2ecf20Sopenharmony_ci struct MPI2_RAID_SCSI_IO_REQUEST *io_request; 26998c2ecf20Sopenharmony_ci struct IO_REQUEST_INFO io_info; 27008c2ecf20Sopenharmony_ci struct fusion_context *fusion; 27018c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *local_map_ptr; 27028c2ecf20Sopenharmony_ci u8 *raidLUN; 27038c2ecf20Sopenharmony_ci unsigned long spinlock_flags; 27048c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid = NULL; 27058c2ecf20Sopenharmony_ci struct MR_PRIV_DEVICE *mrdev_priv; 27068c2ecf20Sopenharmony_ci struct RAID_CONTEXT *rctx; 27078c2ecf20Sopenharmony_ci struct RAID_CONTEXT_G35 *rctx_g35; 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_ci device_id = MEGASAS_DEV_INDEX(scp); 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci io_request = cmd->io_request; 27148c2ecf20Sopenharmony_ci rctx = &io_request->RaidContext.raid_context; 27158c2ecf20Sopenharmony_ci rctx_g35 = &io_request->RaidContext.raid_context_g35; 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci rctx->virtual_disk_tgt_id = cpu_to_le16(device_id); 27188c2ecf20Sopenharmony_ci rctx->status = 0; 27198c2ecf20Sopenharmony_ci rctx->ex_status = 0; 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci start_lba_lo = 0; 27228c2ecf20Sopenharmony_ci start_lba_hi = 0; 27238c2ecf20Sopenharmony_ci fp_possible = false; 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci /* 27268c2ecf20Sopenharmony_ci * 6-byte READ(0x08) or WRITE(0x0A) cdb 27278c2ecf20Sopenharmony_ci */ 27288c2ecf20Sopenharmony_ci if (scp->cmd_len == 6) { 27298c2ecf20Sopenharmony_ci datalength = (u32) scp->cmnd[4]; 27308c2ecf20Sopenharmony_ci start_lba_lo = ((u32) scp->cmnd[1] << 16) | 27318c2ecf20Sopenharmony_ci ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3]; 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci start_lba_lo &= 0x1FFFFF; 27348c2ecf20Sopenharmony_ci } 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci /* 27378c2ecf20Sopenharmony_ci * 10-byte READ(0x28) or WRITE(0x2A) cdb 27388c2ecf20Sopenharmony_ci */ 27398c2ecf20Sopenharmony_ci else if (scp->cmd_len == 10) { 27408c2ecf20Sopenharmony_ci datalength = (u32) scp->cmnd[8] | 27418c2ecf20Sopenharmony_ci ((u32) scp->cmnd[7] << 8); 27428c2ecf20Sopenharmony_ci start_lba_lo = ((u32) scp->cmnd[2] << 24) | 27438c2ecf20Sopenharmony_ci ((u32) scp->cmnd[3] << 16) | 27448c2ecf20Sopenharmony_ci ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5]; 27458c2ecf20Sopenharmony_ci } 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci /* 27488c2ecf20Sopenharmony_ci * 12-byte READ(0xA8) or WRITE(0xAA) cdb 27498c2ecf20Sopenharmony_ci */ 27508c2ecf20Sopenharmony_ci else if (scp->cmd_len == 12) { 27518c2ecf20Sopenharmony_ci datalength = ((u32) scp->cmnd[6] << 24) | 27528c2ecf20Sopenharmony_ci ((u32) scp->cmnd[7] << 16) | 27538c2ecf20Sopenharmony_ci ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9]; 27548c2ecf20Sopenharmony_ci start_lba_lo = ((u32) scp->cmnd[2] << 24) | 27558c2ecf20Sopenharmony_ci ((u32) scp->cmnd[3] << 16) | 27568c2ecf20Sopenharmony_ci ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5]; 27578c2ecf20Sopenharmony_ci } 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci /* 27608c2ecf20Sopenharmony_ci * 16-byte READ(0x88) or WRITE(0x8A) cdb 27618c2ecf20Sopenharmony_ci */ 27628c2ecf20Sopenharmony_ci else if (scp->cmd_len == 16) { 27638c2ecf20Sopenharmony_ci datalength = ((u32) scp->cmnd[10] << 24) | 27648c2ecf20Sopenharmony_ci ((u32) scp->cmnd[11] << 16) | 27658c2ecf20Sopenharmony_ci ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13]; 27668c2ecf20Sopenharmony_ci start_lba_lo = ((u32) scp->cmnd[6] << 24) | 27678c2ecf20Sopenharmony_ci ((u32) scp->cmnd[7] << 16) | 27688c2ecf20Sopenharmony_ci ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9]; 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci start_lba_hi = ((u32) scp->cmnd[2] << 24) | 27718c2ecf20Sopenharmony_ci ((u32) scp->cmnd[3] << 16) | 27728c2ecf20Sopenharmony_ci ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5]; 27738c2ecf20Sopenharmony_ci } 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO)); 27768c2ecf20Sopenharmony_ci io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo; 27778c2ecf20Sopenharmony_ci io_info.numBlocks = datalength; 27788c2ecf20Sopenharmony_ci io_info.ldTgtId = device_id; 27798c2ecf20Sopenharmony_ci io_info.r1_alt_dev_handle = MR_DEVHANDLE_INVALID; 27808c2ecf20Sopenharmony_ci scsi_buff_len = scsi_bufflen(scp); 27818c2ecf20Sopenharmony_ci io_request->DataLength = cpu_to_le32(scsi_buff_len); 27828c2ecf20Sopenharmony_ci io_info.data_arms = 1; 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci if (scp->sc_data_direction == DMA_FROM_DEVICE) 27858c2ecf20Sopenharmony_ci io_info.isRead = 1; 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; 27888c2ecf20Sopenharmony_ci ld = MR_TargetIdToLdGet(device_id, local_map_ptr); 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci if (ld < instance->fw_supported_vd_count) 27918c2ecf20Sopenharmony_ci raid = MR_LdRaidGet(ld, local_map_ptr); 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci if (!raid || (!fusion->fast_path_io)) { 27948c2ecf20Sopenharmony_ci rctx->reg_lock_flags = 0; 27958c2ecf20Sopenharmony_ci fp_possible = false; 27968c2ecf20Sopenharmony_ci } else { 27978c2ecf20Sopenharmony_ci if (MR_BuildRaidContext(instance, &io_info, rctx, 27988c2ecf20Sopenharmony_ci local_map_ptr, &raidLUN)) 27998c2ecf20Sopenharmony_ci fp_possible = (io_info.fpOkForIo > 0) ? true : false; 28008c2ecf20Sopenharmony_ci } 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci megasas_get_msix_index(instance, scp, cmd, io_info.data_arms); 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) { 28058c2ecf20Sopenharmony_ci /* FP for Optimal raid level 1. 28068c2ecf20Sopenharmony_ci * All large RAID-1 writes (> 32 KiB, both WT and WB modes) 28078c2ecf20Sopenharmony_ci * are built by the driver as LD I/Os. 28088c2ecf20Sopenharmony_ci * All small RAID-1 WT writes (<= 32 KiB) are built as FP I/Os 28098c2ecf20Sopenharmony_ci * (there is never a reason to process these as buffered writes) 28108c2ecf20Sopenharmony_ci * All small RAID-1 WB writes (<= 32 KiB) are built as FP I/Os 28118c2ecf20Sopenharmony_ci * with the SLD bit asserted. 28128c2ecf20Sopenharmony_ci */ 28138c2ecf20Sopenharmony_ci if (io_info.r1_alt_dev_handle != MR_DEVHANDLE_INVALID) { 28148c2ecf20Sopenharmony_ci mrdev_priv = scp->device->hostdata; 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci if (atomic_inc_return(&instance->fw_outstanding) > 28178c2ecf20Sopenharmony_ci (instance->host->can_queue)) { 28188c2ecf20Sopenharmony_ci fp_possible = false; 28198c2ecf20Sopenharmony_ci atomic_dec(&instance->fw_outstanding); 28208c2ecf20Sopenharmony_ci } else if (fusion->pcie_bw_limitation && 28218c2ecf20Sopenharmony_ci ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) || 28228c2ecf20Sopenharmony_ci (atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0))) { 28238c2ecf20Sopenharmony_ci fp_possible = false; 28248c2ecf20Sopenharmony_ci atomic_dec(&instance->fw_outstanding); 28258c2ecf20Sopenharmony_ci if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE) 28268c2ecf20Sopenharmony_ci atomic_set(&mrdev_priv->r1_ldio_hint, 28278c2ecf20Sopenharmony_ci instance->r1_ldio_hint_default); 28288c2ecf20Sopenharmony_ci } 28298c2ecf20Sopenharmony_ci } 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci if (!fp_possible || 28328c2ecf20Sopenharmony_ci (io_info.isRead && io_info.ra_capable)) { 28338c2ecf20Sopenharmony_ci spin_lock_irqsave(&instance->stream_lock, 28348c2ecf20Sopenharmony_ci spinlock_flags); 28358c2ecf20Sopenharmony_ci megasas_stream_detect(instance, cmd, &io_info); 28368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&instance->stream_lock, 28378c2ecf20Sopenharmony_ci spinlock_flags); 28388c2ecf20Sopenharmony_ci /* In ventura if stream detected for a read and it is 28398c2ecf20Sopenharmony_ci * read ahead capable make this IO as LDIO 28408c2ecf20Sopenharmony_ci */ 28418c2ecf20Sopenharmony_ci if (is_stream_detected(rctx_g35)) 28428c2ecf20Sopenharmony_ci fp_possible = false; 28438c2ecf20Sopenharmony_ci } 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_ci /* If raid is NULL, set CPU affinity to default CPU0 */ 28468c2ecf20Sopenharmony_ci if (raid) 28478c2ecf20Sopenharmony_ci megasas_set_raidflag_cpu_affinity(fusion, &io_request->RaidContext, 28488c2ecf20Sopenharmony_ci raid, fp_possible, io_info.isRead, 28498c2ecf20Sopenharmony_ci scsi_buff_len); 28508c2ecf20Sopenharmony_ci else 28518c2ecf20Sopenharmony_ci rctx_g35->routing_flags |= 28528c2ecf20Sopenharmony_ci (MR_RAID_CTX_CPUSEL_0 << MR_RAID_CTX_ROUTINGFLAGS_CPUSEL_SHIFT); 28538c2ecf20Sopenharmony_ci } 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci if (fp_possible) { 28568c2ecf20Sopenharmony_ci megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp, 28578c2ecf20Sopenharmony_ci local_map_ptr, start_lba_lo); 28588c2ecf20Sopenharmony_ci io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; 28598c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.RequestFlags = 28608c2ecf20Sopenharmony_ci (MPI2_REQ_DESCRIPT_FLAGS_FP_IO 28618c2ecf20Sopenharmony_ci << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 28628c2ecf20Sopenharmony_ci if (instance->adapter_type == INVADER_SERIES) { 28638c2ecf20Sopenharmony_ci rctx->type = MPI2_TYPE_CUDA; 28648c2ecf20Sopenharmony_ci rctx->nseg = 0x1; 28658c2ecf20Sopenharmony_ci io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); 28668c2ecf20Sopenharmony_ci rctx->reg_lock_flags |= 28678c2ecf20Sopenharmony_ci (MR_RL_FLAGS_GRANT_DESTINATION_CUDA | 28688c2ecf20Sopenharmony_ci MR_RL_FLAGS_SEQ_NUM_ENABLE); 28698c2ecf20Sopenharmony_ci } else if (instance->adapter_type >= VENTURA_SERIES) { 28708c2ecf20Sopenharmony_ci rctx_g35->nseg_type |= (1 << RAID_CONTEXT_NSEG_SHIFT); 28718c2ecf20Sopenharmony_ci rctx_g35->nseg_type |= (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT); 28728c2ecf20Sopenharmony_ci rctx_g35->routing_flags |= (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT); 28738c2ecf20Sopenharmony_ci io_request->IoFlags |= 28748c2ecf20Sopenharmony_ci cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); 28758c2ecf20Sopenharmony_ci } 28768c2ecf20Sopenharmony_ci if (fusion->load_balance_info && 28778c2ecf20Sopenharmony_ci (fusion->load_balance_info[device_id].loadBalanceFlag) && 28788c2ecf20Sopenharmony_ci (io_info.isRead)) { 28798c2ecf20Sopenharmony_ci io_info.devHandle = 28808c2ecf20Sopenharmony_ci get_updated_dev_handle(instance, 28818c2ecf20Sopenharmony_ci &fusion->load_balance_info[device_id], 28828c2ecf20Sopenharmony_ci &io_info, local_map_ptr); 28838c2ecf20Sopenharmony_ci scp->SCp.Status |= MEGASAS_LOAD_BALANCE_FLAG; 28848c2ecf20Sopenharmony_ci cmd->pd_r1_lb = io_info.pd_after_lb; 28858c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) 28868c2ecf20Sopenharmony_ci rctx_g35->span_arm = io_info.span_arm; 28878c2ecf20Sopenharmony_ci else 28888c2ecf20Sopenharmony_ci rctx->span_arm = io_info.span_arm; 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci } else 28918c2ecf20Sopenharmony_ci scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG; 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) 28948c2ecf20Sopenharmony_ci cmd->r1_alt_dev_handle = io_info.r1_alt_dev_handle; 28958c2ecf20Sopenharmony_ci else 28968c2ecf20Sopenharmony_ci cmd->r1_alt_dev_handle = MR_DEVHANDLE_INVALID; 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci if ((raidLUN[0] == 1) && 28998c2ecf20Sopenharmony_ci (local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 1)) { 29008c2ecf20Sopenharmony_ci instance->dev_handle = !(instance->dev_handle); 29018c2ecf20Sopenharmony_ci io_info.devHandle = 29028c2ecf20Sopenharmony_ci local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].devHandle[instance->dev_handle]; 29038c2ecf20Sopenharmony_ci } 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle; 29068c2ecf20Sopenharmony_ci io_request->DevHandle = io_info.devHandle; 29078c2ecf20Sopenharmony_ci cmd->pd_interface = io_info.pd_interface; 29088c2ecf20Sopenharmony_ci /* populate the LUN field */ 29098c2ecf20Sopenharmony_ci memcpy(io_request->LUN, raidLUN, 8); 29108c2ecf20Sopenharmony_ci } else { 29118c2ecf20Sopenharmony_ci rctx->timeout_value = 29128c2ecf20Sopenharmony_ci cpu_to_le16(local_map_ptr->raidMap.fpPdIoTimeoutSec); 29138c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.RequestFlags = 29148c2ecf20Sopenharmony_ci (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO 29158c2ecf20Sopenharmony_ci << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 29168c2ecf20Sopenharmony_ci if (instance->adapter_type == INVADER_SERIES) { 29178c2ecf20Sopenharmony_ci if (io_info.do_fp_rlbypass || 29188c2ecf20Sopenharmony_ci (rctx->reg_lock_flags == REGION_TYPE_UNUSED)) 29198c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.RequestFlags = 29208c2ecf20Sopenharmony_ci (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK << 29218c2ecf20Sopenharmony_ci MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 29228c2ecf20Sopenharmony_ci rctx->type = MPI2_TYPE_CUDA; 29238c2ecf20Sopenharmony_ci rctx->reg_lock_flags |= 29248c2ecf20Sopenharmony_ci (MR_RL_FLAGS_GRANT_DESTINATION_CPU0 | 29258c2ecf20Sopenharmony_ci MR_RL_FLAGS_SEQ_NUM_ENABLE); 29268c2ecf20Sopenharmony_ci rctx->nseg = 0x1; 29278c2ecf20Sopenharmony_ci } else if (instance->adapter_type >= VENTURA_SERIES) { 29288c2ecf20Sopenharmony_ci rctx_g35->routing_flags |= (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT); 29298c2ecf20Sopenharmony_ci rctx_g35->nseg_type |= (1 << RAID_CONTEXT_NSEG_SHIFT); 29308c2ecf20Sopenharmony_ci rctx_g35->nseg_type |= (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT); 29318c2ecf20Sopenharmony_ci } 29328c2ecf20Sopenharmony_ci io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; 29338c2ecf20Sopenharmony_ci io_request->DevHandle = cpu_to_le16(device_id); 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci } /* Not FP */ 29368c2ecf20Sopenharmony_ci} 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci/** 29398c2ecf20Sopenharmony_ci * megasas_build_ld_nonrw_fusion - prepares non rw ios for virtual disk 29408c2ecf20Sopenharmony_ci * @instance: Adapter soft state 29418c2ecf20Sopenharmony_ci * @scmd: SCSI command 29428c2ecf20Sopenharmony_ci * @cmd: Command to be prepared 29438c2ecf20Sopenharmony_ci * 29448c2ecf20Sopenharmony_ci * Prepares the io_request frame for non-rw io cmds for vd. 29458c2ecf20Sopenharmony_ci */ 29468c2ecf20Sopenharmony_cistatic void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance, 29478c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd, struct megasas_cmd_fusion *cmd) 29488c2ecf20Sopenharmony_ci{ 29498c2ecf20Sopenharmony_ci u32 device_id; 29508c2ecf20Sopenharmony_ci struct MPI2_RAID_SCSI_IO_REQUEST *io_request; 29518c2ecf20Sopenharmony_ci u16 ld; 29528c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *local_map_ptr; 29538c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 29548c2ecf20Sopenharmony_ci u8 span, physArm; 29558c2ecf20Sopenharmony_ci __le16 devHandle; 29568c2ecf20Sopenharmony_ci u32 arRef, pd; 29578c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid; 29588c2ecf20Sopenharmony_ci struct RAID_CONTEXT *pRAID_Context; 29598c2ecf20Sopenharmony_ci u8 fp_possible = 1; 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci io_request = cmd->io_request; 29628c2ecf20Sopenharmony_ci device_id = MEGASAS_DEV_INDEX(scmd); 29638c2ecf20Sopenharmony_ci local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; 29648c2ecf20Sopenharmony_ci io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); 29658c2ecf20Sopenharmony_ci /* get RAID_Context pointer */ 29668c2ecf20Sopenharmony_ci pRAID_Context = &io_request->RaidContext.raid_context; 29678c2ecf20Sopenharmony_ci /* Check with FW team */ 29688c2ecf20Sopenharmony_ci pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); 29698c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_row_lba = 0; 29708c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_length = 0; 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci if (fusion->fast_path_io && ( 29738c2ecf20Sopenharmony_ci device_id < instance->fw_supported_vd_count)) { 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci ld = MR_TargetIdToLdGet(device_id, local_map_ptr); 29768c2ecf20Sopenharmony_ci if (ld >= instance->fw_supported_vd_count - 1) 29778c2ecf20Sopenharmony_ci fp_possible = 0; 29788c2ecf20Sopenharmony_ci else { 29798c2ecf20Sopenharmony_ci raid = MR_LdRaidGet(ld, local_map_ptr); 29808c2ecf20Sopenharmony_ci if (!(raid->capability.fpNonRWCapable)) 29818c2ecf20Sopenharmony_ci fp_possible = 0; 29828c2ecf20Sopenharmony_ci } 29838c2ecf20Sopenharmony_ci } else 29848c2ecf20Sopenharmony_ci fp_possible = 0; 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci if (!fp_possible) { 29878c2ecf20Sopenharmony_ci io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; 29888c2ecf20Sopenharmony_ci io_request->DevHandle = cpu_to_le16(device_id); 29898c2ecf20Sopenharmony_ci io_request->LUN[1] = scmd->device->lun; 29908c2ecf20Sopenharmony_ci pRAID_Context->timeout_value = 29918c2ecf20Sopenharmony_ci cpu_to_le16 (scmd->request->timeout / HZ); 29928c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.RequestFlags = 29938c2ecf20Sopenharmony_ci (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << 29948c2ecf20Sopenharmony_ci MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 29958c2ecf20Sopenharmony_ci } else { 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci /* set RAID context values */ 29988c2ecf20Sopenharmony_ci pRAID_Context->config_seq_num = raid->seqNum; 29998c2ecf20Sopenharmony_ci if (instance->adapter_type < VENTURA_SERIES) 30008c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_flags = REGION_TYPE_SHARED_READ; 30018c2ecf20Sopenharmony_ci pRAID_Context->timeout_value = 30028c2ecf20Sopenharmony_ci cpu_to_le16(raid->fpIoTimeoutForLd); 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci /* get the DevHandle for the PD (since this is 30058c2ecf20Sopenharmony_ci fpNonRWCapable, this is a single disk RAID0) */ 30068c2ecf20Sopenharmony_ci span = physArm = 0; 30078c2ecf20Sopenharmony_ci arRef = MR_LdSpanArrayGet(ld, span, local_map_ptr); 30088c2ecf20Sopenharmony_ci pd = MR_ArPdGet(arRef, physArm, local_map_ptr); 30098c2ecf20Sopenharmony_ci devHandle = MR_PdDevHandleGet(pd, local_map_ptr); 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_ci /* build request descriptor */ 30128c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.RequestFlags = 30138c2ecf20Sopenharmony_ci (MPI2_REQ_DESCRIPT_FLAGS_FP_IO << 30148c2ecf20Sopenharmony_ci MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 30158c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.DevHandle = devHandle; 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci /* populate the LUN field */ 30188c2ecf20Sopenharmony_ci memcpy(io_request->LUN, raid->LUN, 8); 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci /* build the raidScsiIO structure */ 30218c2ecf20Sopenharmony_ci io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; 30228c2ecf20Sopenharmony_ci io_request->DevHandle = devHandle; 30238c2ecf20Sopenharmony_ci } 30248c2ecf20Sopenharmony_ci} 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_ci/** 30278c2ecf20Sopenharmony_ci * megasas_build_syspd_fusion - prepares rw/non-rw ios for syspd 30288c2ecf20Sopenharmony_ci * @instance: Adapter soft state 30298c2ecf20Sopenharmony_ci * @scmd: SCSI command 30308c2ecf20Sopenharmony_ci * @cmd: Command to be prepared 30318c2ecf20Sopenharmony_ci * @fp_possible: parameter to detect fast path or firmware path io. 30328c2ecf20Sopenharmony_ci * 30338c2ecf20Sopenharmony_ci * Prepares the io_request frame for rw/non-rw io cmds for syspds 30348c2ecf20Sopenharmony_ci */ 30358c2ecf20Sopenharmony_cistatic void 30368c2ecf20Sopenharmony_cimegasas_build_syspd_fusion(struct megasas_instance *instance, 30378c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd, struct megasas_cmd_fusion *cmd, 30388c2ecf20Sopenharmony_ci bool fp_possible) 30398c2ecf20Sopenharmony_ci{ 30408c2ecf20Sopenharmony_ci u32 device_id; 30418c2ecf20Sopenharmony_ci struct MPI2_RAID_SCSI_IO_REQUEST *io_request; 30428c2ecf20Sopenharmony_ci u16 pd_index = 0; 30438c2ecf20Sopenharmony_ci u16 os_timeout_value; 30448c2ecf20Sopenharmony_ci u16 timeout_limit; 30458c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *local_map_ptr; 30468c2ecf20Sopenharmony_ci struct RAID_CONTEXT *pRAID_Context; 30478c2ecf20Sopenharmony_ci struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; 30488c2ecf20Sopenharmony_ci struct MR_PRIV_DEVICE *mr_device_priv_data; 30498c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 30508c2ecf20Sopenharmony_ci pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id - 1) & 1]; 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_ci device_id = MEGASAS_DEV_INDEX(scmd); 30538c2ecf20Sopenharmony_ci pd_index = MEGASAS_PD_INDEX(scmd); 30548c2ecf20Sopenharmony_ci os_timeout_value = scmd->request->timeout / HZ; 30558c2ecf20Sopenharmony_ci mr_device_priv_data = scmd->device->hostdata; 30568c2ecf20Sopenharmony_ci cmd->pd_interface = mr_device_priv_data->interface_type; 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci io_request = cmd->io_request; 30598c2ecf20Sopenharmony_ci /* get RAID_Context pointer */ 30608c2ecf20Sopenharmony_ci pRAID_Context = &io_request->RaidContext.raid_context; 30618c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_flags = 0; 30628c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_row_lba = 0; 30638c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_length = 0; 30648c2ecf20Sopenharmony_ci io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); 30658c2ecf20Sopenharmony_ci io_request->LUN[1] = scmd->device->lun; 30668c2ecf20Sopenharmony_ci pRAID_Context->raid_flags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD 30678c2ecf20Sopenharmony_ci << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci /* If FW supports PD sequence number */ 30708c2ecf20Sopenharmony_ci if (instance->support_seqnum_jbod_fp) { 30718c2ecf20Sopenharmony_ci if (instance->use_seqnum_jbod_fp && 30728c2ecf20Sopenharmony_ci instance->pd_list[pd_index].driveType == TYPE_DISK) { 30738c2ecf20Sopenharmony_ci 30748c2ecf20Sopenharmony_ci /* More than 256 PD/JBOD support for Ventura */ 30758c2ecf20Sopenharmony_ci if (instance->support_morethan256jbod) 30768c2ecf20Sopenharmony_ci pRAID_Context->virtual_disk_tgt_id = 30778c2ecf20Sopenharmony_ci pd_sync->seq[pd_index].pd_target_id; 30788c2ecf20Sopenharmony_ci else 30798c2ecf20Sopenharmony_ci pRAID_Context->virtual_disk_tgt_id = 30808c2ecf20Sopenharmony_ci cpu_to_le16(device_id + 30818c2ecf20Sopenharmony_ci (MAX_PHYSICAL_DEVICES - 1)); 30828c2ecf20Sopenharmony_ci pRAID_Context->config_seq_num = 30838c2ecf20Sopenharmony_ci pd_sync->seq[pd_index].seqNum; 30848c2ecf20Sopenharmony_ci io_request->DevHandle = 30858c2ecf20Sopenharmony_ci pd_sync->seq[pd_index].devHandle; 30868c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) { 30878c2ecf20Sopenharmony_ci io_request->RaidContext.raid_context_g35.routing_flags |= 30888c2ecf20Sopenharmony_ci (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT); 30898c2ecf20Sopenharmony_ci io_request->RaidContext.raid_context_g35.nseg_type |= 30908c2ecf20Sopenharmony_ci (1 << RAID_CONTEXT_NSEG_SHIFT); 30918c2ecf20Sopenharmony_ci io_request->RaidContext.raid_context_g35.nseg_type |= 30928c2ecf20Sopenharmony_ci (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT); 30938c2ecf20Sopenharmony_ci } else { 30948c2ecf20Sopenharmony_ci pRAID_Context->type = MPI2_TYPE_CUDA; 30958c2ecf20Sopenharmony_ci pRAID_Context->nseg = 0x1; 30968c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_flags |= 30978c2ecf20Sopenharmony_ci (MR_RL_FLAGS_SEQ_NUM_ENABLE | 30988c2ecf20Sopenharmony_ci MR_RL_FLAGS_GRANT_DESTINATION_CUDA); 30998c2ecf20Sopenharmony_ci } 31008c2ecf20Sopenharmony_ci } else { 31018c2ecf20Sopenharmony_ci pRAID_Context->virtual_disk_tgt_id = 31028c2ecf20Sopenharmony_ci cpu_to_le16(device_id + 31038c2ecf20Sopenharmony_ci (MAX_PHYSICAL_DEVICES - 1)); 31048c2ecf20Sopenharmony_ci pRAID_Context->config_seq_num = 0; 31058c2ecf20Sopenharmony_ci io_request->DevHandle = cpu_to_le16(0xFFFF); 31068c2ecf20Sopenharmony_ci } 31078c2ecf20Sopenharmony_ci } else { 31088c2ecf20Sopenharmony_ci pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); 31098c2ecf20Sopenharmony_ci pRAID_Context->config_seq_num = 0; 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci if (fusion->fast_path_io) { 31128c2ecf20Sopenharmony_ci local_map_ptr = 31138c2ecf20Sopenharmony_ci fusion->ld_drv_map[(instance->map_id & 1)]; 31148c2ecf20Sopenharmony_ci io_request->DevHandle = 31158c2ecf20Sopenharmony_ci local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; 31168c2ecf20Sopenharmony_ci } else { 31178c2ecf20Sopenharmony_ci io_request->DevHandle = cpu_to_le16(0xFFFF); 31188c2ecf20Sopenharmony_ci } 31198c2ecf20Sopenharmony_ci } 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle; 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci megasas_get_msix_index(instance, scmd, cmd, 1); 31248c2ecf20Sopenharmony_ci 31258c2ecf20Sopenharmony_ci if (!fp_possible) { 31268c2ecf20Sopenharmony_ci /* system pd firmware path */ 31278c2ecf20Sopenharmony_ci io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; 31288c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.RequestFlags = 31298c2ecf20Sopenharmony_ci (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << 31308c2ecf20Sopenharmony_ci MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 31318c2ecf20Sopenharmony_ci pRAID_Context->timeout_value = cpu_to_le16(os_timeout_value); 31328c2ecf20Sopenharmony_ci pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); 31338c2ecf20Sopenharmony_ci } else { 31348c2ecf20Sopenharmony_ci if (os_timeout_value) 31358c2ecf20Sopenharmony_ci os_timeout_value++; 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_ci /* system pd Fast Path */ 31388c2ecf20Sopenharmony_ci io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; 31398c2ecf20Sopenharmony_ci timeout_limit = (scmd->device->type == TYPE_DISK) ? 31408c2ecf20Sopenharmony_ci 255 : 0xFFFF; 31418c2ecf20Sopenharmony_ci pRAID_Context->timeout_value = 31428c2ecf20Sopenharmony_ci cpu_to_le16((os_timeout_value > timeout_limit) ? 31438c2ecf20Sopenharmony_ci timeout_limit : os_timeout_value); 31448c2ecf20Sopenharmony_ci if (instance->adapter_type >= INVADER_SERIES) 31458c2ecf20Sopenharmony_ci io_request->IoFlags |= 31468c2ecf20Sopenharmony_ci cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.RequestFlags = 31498c2ecf20Sopenharmony_ci (MPI2_REQ_DESCRIPT_FLAGS_FP_IO << 31508c2ecf20Sopenharmony_ci MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 31518c2ecf20Sopenharmony_ci } 31528c2ecf20Sopenharmony_ci} 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci/** 31558c2ecf20Sopenharmony_ci * megasas_build_io_fusion - Prepares IOs to devices 31568c2ecf20Sopenharmony_ci * @instance: Adapter soft state 31578c2ecf20Sopenharmony_ci * @scp: SCSI command 31588c2ecf20Sopenharmony_ci * @cmd: Command to be prepared 31598c2ecf20Sopenharmony_ci * 31608c2ecf20Sopenharmony_ci * Invokes helper functions to prepare request frames 31618c2ecf20Sopenharmony_ci * and sets flags appropriate for IO/Non-IO cmd 31628c2ecf20Sopenharmony_ci */ 31638c2ecf20Sopenharmony_cistatic int 31648c2ecf20Sopenharmony_cimegasas_build_io_fusion(struct megasas_instance *instance, 31658c2ecf20Sopenharmony_ci struct scsi_cmnd *scp, 31668c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd) 31678c2ecf20Sopenharmony_ci{ 31688c2ecf20Sopenharmony_ci int sge_count; 31698c2ecf20Sopenharmony_ci u8 cmd_type; 31708c2ecf20Sopenharmony_ci struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request; 31718c2ecf20Sopenharmony_ci struct MR_PRIV_DEVICE *mr_device_priv_data; 31728c2ecf20Sopenharmony_ci mr_device_priv_data = scp->device->hostdata; 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci /* Zero out some fields so they don't get reused */ 31758c2ecf20Sopenharmony_ci memset(io_request->LUN, 0x0, 8); 31768c2ecf20Sopenharmony_ci io_request->CDB.EEDP32.PrimaryReferenceTag = 0; 31778c2ecf20Sopenharmony_ci io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0; 31788c2ecf20Sopenharmony_ci io_request->EEDPFlags = 0; 31798c2ecf20Sopenharmony_ci io_request->Control = 0; 31808c2ecf20Sopenharmony_ci io_request->EEDPBlockSize = 0; 31818c2ecf20Sopenharmony_ci io_request->ChainOffset = 0; 31828c2ecf20Sopenharmony_ci io_request->RaidContext.raid_context.raid_flags = 0; 31838c2ecf20Sopenharmony_ci io_request->RaidContext.raid_context.type = 0; 31848c2ecf20Sopenharmony_ci io_request->RaidContext.raid_context.nseg = 0; 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_ci memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len); 31878c2ecf20Sopenharmony_ci /* 31888c2ecf20Sopenharmony_ci * Just the CDB length,rest of the Flags are zero 31898c2ecf20Sopenharmony_ci * This will be modified for FP in build_ldio_fusion 31908c2ecf20Sopenharmony_ci */ 31918c2ecf20Sopenharmony_ci io_request->IoFlags = cpu_to_le16(scp->cmd_len); 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci switch (cmd_type = megasas_cmd_type(scp)) { 31948c2ecf20Sopenharmony_ci case READ_WRITE_LDIO: 31958c2ecf20Sopenharmony_ci megasas_build_ldio_fusion(instance, scp, cmd); 31968c2ecf20Sopenharmony_ci break; 31978c2ecf20Sopenharmony_ci case NON_READ_WRITE_LDIO: 31988c2ecf20Sopenharmony_ci megasas_build_ld_nonrw_fusion(instance, scp, cmd); 31998c2ecf20Sopenharmony_ci break; 32008c2ecf20Sopenharmony_ci case READ_WRITE_SYSPDIO: 32018c2ecf20Sopenharmony_ci megasas_build_syspd_fusion(instance, scp, cmd, true); 32028c2ecf20Sopenharmony_ci break; 32038c2ecf20Sopenharmony_ci case NON_READ_WRITE_SYSPDIO: 32048c2ecf20Sopenharmony_ci if (instance->secure_jbod_support || 32058c2ecf20Sopenharmony_ci mr_device_priv_data->is_tm_capable) 32068c2ecf20Sopenharmony_ci megasas_build_syspd_fusion(instance, scp, cmd, false); 32078c2ecf20Sopenharmony_ci else 32088c2ecf20Sopenharmony_ci megasas_build_syspd_fusion(instance, scp, cmd, true); 32098c2ecf20Sopenharmony_ci break; 32108c2ecf20Sopenharmony_ci default: 32118c2ecf20Sopenharmony_ci break; 32128c2ecf20Sopenharmony_ci } 32138c2ecf20Sopenharmony_ci 32148c2ecf20Sopenharmony_ci /* 32158c2ecf20Sopenharmony_ci * Construct SGL 32168c2ecf20Sopenharmony_ci */ 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci sge_count = megasas_make_sgl(instance, scp, cmd); 32198c2ecf20Sopenharmony_ci 32208c2ecf20Sopenharmony_ci if (sge_count > instance->max_num_sge || (sge_count < 0)) { 32218c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 32228c2ecf20Sopenharmony_ci "%s %d sge_count (%d) is out of range. Range is: 0-%d\n", 32238c2ecf20Sopenharmony_ci __func__, __LINE__, sge_count, instance->max_num_sge); 32248c2ecf20Sopenharmony_ci return 1; 32258c2ecf20Sopenharmony_ci } 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) { 32288c2ecf20Sopenharmony_ci set_num_sge(&io_request->RaidContext.raid_context_g35, sge_count); 32298c2ecf20Sopenharmony_ci cpu_to_le16s(&io_request->RaidContext.raid_context_g35.routing_flags); 32308c2ecf20Sopenharmony_ci cpu_to_le16s(&io_request->RaidContext.raid_context_g35.nseg_type); 32318c2ecf20Sopenharmony_ci } else { 32328c2ecf20Sopenharmony_ci /* numSGE store lower 8 bit of sge_count. 32338c2ecf20Sopenharmony_ci * numSGEExt store higher 8 bit of sge_count 32348c2ecf20Sopenharmony_ci */ 32358c2ecf20Sopenharmony_ci io_request->RaidContext.raid_context.num_sge = sge_count; 32368c2ecf20Sopenharmony_ci io_request->RaidContext.raid_context.num_sge_ext = 32378c2ecf20Sopenharmony_ci (u8)(sge_count >> 8); 32388c2ecf20Sopenharmony_ci } 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING); 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci if (scp->sc_data_direction == DMA_TO_DEVICE) 32438c2ecf20Sopenharmony_ci io_request->Control |= cpu_to_le32(MPI2_SCSIIO_CONTROL_WRITE); 32448c2ecf20Sopenharmony_ci else if (scp->sc_data_direction == DMA_FROM_DEVICE) 32458c2ecf20Sopenharmony_ci io_request->Control |= cpu_to_le32(MPI2_SCSIIO_CONTROL_READ); 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci io_request->SGLOffset0 = 32488c2ecf20Sopenharmony_ci offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL) / 4; 32498c2ecf20Sopenharmony_ci 32508c2ecf20Sopenharmony_ci io_request->SenseBufferLowAddress = 32518c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(cmd->sense_phys_addr)); 32528c2ecf20Sopenharmony_ci io_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci cmd->scmd = scp; 32558c2ecf20Sopenharmony_ci scp->SCp.ptr = (char *)cmd; 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci return 0; 32588c2ecf20Sopenharmony_ci} 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_cistatic union MEGASAS_REQUEST_DESCRIPTOR_UNION * 32618c2ecf20Sopenharmony_cimegasas_get_request_descriptor(struct megasas_instance *instance, u16 index) 32628c2ecf20Sopenharmony_ci{ 32638c2ecf20Sopenharmony_ci u8 *p; 32648c2ecf20Sopenharmony_ci struct fusion_context *fusion; 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 32678c2ecf20Sopenharmony_ci p = fusion->req_frames_desc + 32688c2ecf20Sopenharmony_ci sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) * index; 32698c2ecf20Sopenharmony_ci 32708c2ecf20Sopenharmony_ci return (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)p; 32718c2ecf20Sopenharmony_ci} 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_ci/* megasas_prepate_secondRaid1_IO 32758c2ecf20Sopenharmony_ci * It prepares the raid 1 second IO 32768c2ecf20Sopenharmony_ci */ 32778c2ecf20Sopenharmony_cistatic void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance, 32788c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd, 32798c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *r1_cmd) 32808c2ecf20Sopenharmony_ci{ 32818c2ecf20Sopenharmony_ci union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc, *req_desc2 = NULL; 32828c2ecf20Sopenharmony_ci struct fusion_context *fusion; 32838c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 32848c2ecf20Sopenharmony_ci req_desc = cmd->request_desc; 32858c2ecf20Sopenharmony_ci /* copy the io request frame as well as 8 SGEs data for r1 command*/ 32868c2ecf20Sopenharmony_ci memcpy(r1_cmd->io_request, cmd->io_request, 32878c2ecf20Sopenharmony_ci (sizeof(struct MPI2_RAID_SCSI_IO_REQUEST))); 32888c2ecf20Sopenharmony_ci memcpy(&r1_cmd->io_request->SGL, &cmd->io_request->SGL, 32898c2ecf20Sopenharmony_ci (fusion->max_sge_in_main_msg * sizeof(union MPI2_SGE_IO_UNION))); 32908c2ecf20Sopenharmony_ci /*sense buffer is different for r1 command*/ 32918c2ecf20Sopenharmony_ci r1_cmd->io_request->SenseBufferLowAddress = 32928c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(r1_cmd->sense_phys_addr)); 32938c2ecf20Sopenharmony_ci r1_cmd->scmd = cmd->scmd; 32948c2ecf20Sopenharmony_ci req_desc2 = megasas_get_request_descriptor(instance, 32958c2ecf20Sopenharmony_ci (r1_cmd->index - 1)); 32968c2ecf20Sopenharmony_ci req_desc2->Words = 0; 32978c2ecf20Sopenharmony_ci r1_cmd->request_desc = req_desc2; 32988c2ecf20Sopenharmony_ci req_desc2->SCSIIO.SMID = cpu_to_le16(r1_cmd->index); 32998c2ecf20Sopenharmony_ci req_desc2->SCSIIO.RequestFlags = req_desc->SCSIIO.RequestFlags; 33008c2ecf20Sopenharmony_ci r1_cmd->request_desc->SCSIIO.DevHandle = cmd->r1_alt_dev_handle; 33018c2ecf20Sopenharmony_ci r1_cmd->io_request->DevHandle = cmd->r1_alt_dev_handle; 33028c2ecf20Sopenharmony_ci r1_cmd->r1_alt_dev_handle = cmd->io_request->DevHandle; 33038c2ecf20Sopenharmony_ci cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid = 33048c2ecf20Sopenharmony_ci cpu_to_le16(r1_cmd->index); 33058c2ecf20Sopenharmony_ci r1_cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid = 33068c2ecf20Sopenharmony_ci cpu_to_le16(cmd->index); 33078c2ecf20Sopenharmony_ci /*MSIxIndex of both commands request descriptors should be same*/ 33088c2ecf20Sopenharmony_ci r1_cmd->request_desc->SCSIIO.MSIxIndex = 33098c2ecf20Sopenharmony_ci cmd->request_desc->SCSIIO.MSIxIndex; 33108c2ecf20Sopenharmony_ci /*span arm is different for r1 cmd*/ 33118c2ecf20Sopenharmony_ci r1_cmd->io_request->RaidContext.raid_context_g35.span_arm = 33128c2ecf20Sopenharmony_ci cmd->io_request->RaidContext.raid_context_g35.span_arm + 1; 33138c2ecf20Sopenharmony_ci} 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci/** 33168c2ecf20Sopenharmony_ci * megasas_build_and_issue_cmd_fusion -Main routine for building and 33178c2ecf20Sopenharmony_ci * issuing non IOCTL cmd 33188c2ecf20Sopenharmony_ci * @instance: Adapter soft state 33198c2ecf20Sopenharmony_ci * @scmd: pointer to scsi cmd from OS 33208c2ecf20Sopenharmony_ci */ 33218c2ecf20Sopenharmony_cistatic u32 33228c2ecf20Sopenharmony_cimegasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, 33238c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd) 33248c2ecf20Sopenharmony_ci{ 33258c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd, *r1_cmd = NULL; 33268c2ecf20Sopenharmony_ci union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; 33278c2ecf20Sopenharmony_ci u32 index; 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_ci if ((megasas_cmd_type(scmd) == READ_WRITE_LDIO) && 33308c2ecf20Sopenharmony_ci instance->ldio_threshold && 33318c2ecf20Sopenharmony_ci (atomic_inc_return(&instance->ldio_outstanding) > 33328c2ecf20Sopenharmony_ci instance->ldio_threshold)) { 33338c2ecf20Sopenharmony_ci atomic_dec(&instance->ldio_outstanding); 33348c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 33358c2ecf20Sopenharmony_ci } 33368c2ecf20Sopenharmony_ci 33378c2ecf20Sopenharmony_ci if (atomic_inc_return(&instance->fw_outstanding) > 33388c2ecf20Sopenharmony_ci instance->host->can_queue) { 33398c2ecf20Sopenharmony_ci atomic_dec(&instance->fw_outstanding); 33408c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 33418c2ecf20Sopenharmony_ci } 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci cmd = megasas_get_cmd_fusion(instance, scmd->request->tag); 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_ci if (!cmd) { 33468c2ecf20Sopenharmony_ci atomic_dec(&instance->fw_outstanding); 33478c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 33488c2ecf20Sopenharmony_ci } 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_ci index = cmd->index; 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_ci req_desc = megasas_get_request_descriptor(instance, index-1); 33538c2ecf20Sopenharmony_ci 33548c2ecf20Sopenharmony_ci req_desc->Words = 0; 33558c2ecf20Sopenharmony_ci cmd->request_desc = req_desc; 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_ci if (megasas_build_io_fusion(instance, scmd, cmd)) { 33588c2ecf20Sopenharmony_ci megasas_return_cmd_fusion(instance, cmd); 33598c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Error building command\n"); 33608c2ecf20Sopenharmony_ci cmd->request_desc = NULL; 33618c2ecf20Sopenharmony_ci atomic_dec(&instance->fw_outstanding); 33628c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 33638c2ecf20Sopenharmony_ci } 33648c2ecf20Sopenharmony_ci 33658c2ecf20Sopenharmony_ci req_desc = cmd->request_desc; 33668c2ecf20Sopenharmony_ci req_desc->SCSIIO.SMID = cpu_to_le16(index); 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_ci if (cmd->io_request->ChainOffset != 0 && 33698c2ecf20Sopenharmony_ci cmd->io_request->ChainOffset != 0xF) 33708c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "The chain offset value is not " 33718c2ecf20Sopenharmony_ci "correct : %x\n", cmd->io_request->ChainOffset); 33728c2ecf20Sopenharmony_ci /* 33738c2ecf20Sopenharmony_ci * if it is raid 1/10 fp write capable. 33748c2ecf20Sopenharmony_ci * try to get second command from pool and construct it. 33758c2ecf20Sopenharmony_ci * From FW, it has confirmed that lba values of two PDs 33768c2ecf20Sopenharmony_ci * corresponds to single R1/10 LD are always same 33778c2ecf20Sopenharmony_ci * 33788c2ecf20Sopenharmony_ci */ 33798c2ecf20Sopenharmony_ci /* driver side count always should be less than max_fw_cmds 33808c2ecf20Sopenharmony_ci * to get new command 33818c2ecf20Sopenharmony_ci */ 33828c2ecf20Sopenharmony_ci if (cmd->r1_alt_dev_handle != MR_DEVHANDLE_INVALID) { 33838c2ecf20Sopenharmony_ci r1_cmd = megasas_get_cmd_fusion(instance, 33848c2ecf20Sopenharmony_ci (scmd->request->tag + instance->max_fw_cmds)); 33858c2ecf20Sopenharmony_ci megasas_prepare_secondRaid1_IO(instance, cmd, r1_cmd); 33868c2ecf20Sopenharmony_ci } 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ci 33898c2ecf20Sopenharmony_ci /* 33908c2ecf20Sopenharmony_ci * Issue the command to the FW 33918c2ecf20Sopenharmony_ci */ 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_ci megasas_fire_cmd_fusion(instance, req_desc); 33948c2ecf20Sopenharmony_ci 33958c2ecf20Sopenharmony_ci if (r1_cmd) 33968c2ecf20Sopenharmony_ci megasas_fire_cmd_fusion(instance, r1_cmd->request_desc); 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ci 33998c2ecf20Sopenharmony_ci return 0; 34008c2ecf20Sopenharmony_ci} 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci/** 34038c2ecf20Sopenharmony_ci * megasas_complete_r1_command - 34048c2ecf20Sopenharmony_ci * completes R1 FP write commands which has valid peer smid 34058c2ecf20Sopenharmony_ci * @instance: Adapter soft state 34068c2ecf20Sopenharmony_ci * @cmd: MPT command frame 34078c2ecf20Sopenharmony_ci * 34088c2ecf20Sopenharmony_ci */ 34098c2ecf20Sopenharmony_cistatic inline void 34108c2ecf20Sopenharmony_cimegasas_complete_r1_command(struct megasas_instance *instance, 34118c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd) 34128c2ecf20Sopenharmony_ci{ 34138c2ecf20Sopenharmony_ci u8 *sense, status, ex_status; 34148c2ecf20Sopenharmony_ci u32 data_length; 34158c2ecf20Sopenharmony_ci u16 peer_smid; 34168c2ecf20Sopenharmony_ci struct fusion_context *fusion; 34178c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *r1_cmd = NULL; 34188c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd_local = NULL; 34198c2ecf20Sopenharmony_ci struct RAID_CONTEXT_G35 *rctx_g35; 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci rctx_g35 = &cmd->io_request->RaidContext.raid_context_g35; 34228c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 34238c2ecf20Sopenharmony_ci peer_smid = le16_to_cpu(rctx_g35->flow_specific.peer_smid); 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_ci r1_cmd = fusion->cmd_list[peer_smid - 1]; 34268c2ecf20Sopenharmony_ci scmd_local = cmd->scmd; 34278c2ecf20Sopenharmony_ci status = rctx_g35->status; 34288c2ecf20Sopenharmony_ci ex_status = rctx_g35->ex_status; 34298c2ecf20Sopenharmony_ci data_length = cmd->io_request->DataLength; 34308c2ecf20Sopenharmony_ci sense = cmd->sense; 34318c2ecf20Sopenharmony_ci 34328c2ecf20Sopenharmony_ci cmd->cmd_completed = true; 34338c2ecf20Sopenharmony_ci 34348c2ecf20Sopenharmony_ci /* Check if peer command is completed or not*/ 34358c2ecf20Sopenharmony_ci if (r1_cmd->cmd_completed) { 34368c2ecf20Sopenharmony_ci rctx_g35 = &r1_cmd->io_request->RaidContext.raid_context_g35; 34378c2ecf20Sopenharmony_ci if (rctx_g35->status != MFI_STAT_OK) { 34388c2ecf20Sopenharmony_ci status = rctx_g35->status; 34398c2ecf20Sopenharmony_ci ex_status = rctx_g35->ex_status; 34408c2ecf20Sopenharmony_ci data_length = r1_cmd->io_request->DataLength; 34418c2ecf20Sopenharmony_ci sense = r1_cmd->sense; 34428c2ecf20Sopenharmony_ci } 34438c2ecf20Sopenharmony_ci 34448c2ecf20Sopenharmony_ci megasas_return_cmd_fusion(instance, r1_cmd); 34458c2ecf20Sopenharmony_ci map_cmd_status(fusion, scmd_local, status, ex_status, 34468c2ecf20Sopenharmony_ci le32_to_cpu(data_length), sense); 34478c2ecf20Sopenharmony_ci if (instance->ldio_threshold && 34488c2ecf20Sopenharmony_ci megasas_cmd_type(scmd_local) == READ_WRITE_LDIO) 34498c2ecf20Sopenharmony_ci atomic_dec(&instance->ldio_outstanding); 34508c2ecf20Sopenharmony_ci scmd_local->SCp.ptr = NULL; 34518c2ecf20Sopenharmony_ci megasas_return_cmd_fusion(instance, cmd); 34528c2ecf20Sopenharmony_ci scsi_dma_unmap(scmd_local); 34538c2ecf20Sopenharmony_ci scmd_local->scsi_done(scmd_local); 34548c2ecf20Sopenharmony_ci } 34558c2ecf20Sopenharmony_ci} 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci/** 34588c2ecf20Sopenharmony_ci * complete_cmd_fusion - Completes command 34598c2ecf20Sopenharmony_ci * @instance: Adapter soft state 34608c2ecf20Sopenharmony_ci * @MSIxIndex: MSI number 34618c2ecf20Sopenharmony_ci * @irq_context: IRQ context 34628c2ecf20Sopenharmony_ci * 34638c2ecf20Sopenharmony_ci * Completes all commands that is in reply descriptor queue 34648c2ecf20Sopenharmony_ci */ 34658c2ecf20Sopenharmony_cistatic int 34668c2ecf20Sopenharmony_cicomplete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex, 34678c2ecf20Sopenharmony_ci struct megasas_irq_context *irq_context) 34688c2ecf20Sopenharmony_ci{ 34698c2ecf20Sopenharmony_ci union MPI2_REPLY_DESCRIPTORS_UNION *desc; 34708c2ecf20Sopenharmony_ci struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc; 34718c2ecf20Sopenharmony_ci struct MPI2_RAID_SCSI_IO_REQUEST *scsi_io_req; 34728c2ecf20Sopenharmony_ci struct fusion_context *fusion; 34738c2ecf20Sopenharmony_ci struct megasas_cmd *cmd_mfi; 34748c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd_fusion; 34758c2ecf20Sopenharmony_ci u16 smid, num_completed; 34768c2ecf20Sopenharmony_ci u8 reply_descript_type, *sense, status, extStatus; 34778c2ecf20Sopenharmony_ci u32 device_id, data_length; 34788c2ecf20Sopenharmony_ci union desc_value d_val; 34798c2ecf20Sopenharmony_ci struct LD_LOAD_BALANCE_INFO *lbinfo; 34808c2ecf20Sopenharmony_ci int threshold_reply_count = 0; 34818c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd_local = NULL; 34828c2ecf20Sopenharmony_ci struct MR_TASK_MANAGE_REQUEST *mr_tm_req; 34838c2ecf20Sopenharmony_ci struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_tm_req; 34848c2ecf20Sopenharmony_ci 34858c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 34868c2ecf20Sopenharmony_ci 34878c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) 34888c2ecf20Sopenharmony_ci return IRQ_HANDLED; 34898c2ecf20Sopenharmony_ci 34908c2ecf20Sopenharmony_ci desc = fusion->reply_frames_desc[MSIxIndex] + 34918c2ecf20Sopenharmony_ci fusion->last_reply_idx[MSIxIndex]; 34928c2ecf20Sopenharmony_ci 34938c2ecf20Sopenharmony_ci reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc; 34948c2ecf20Sopenharmony_ci 34958c2ecf20Sopenharmony_ci d_val.word = desc->Words; 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci reply_descript_type = reply_desc->ReplyFlags & 34988c2ecf20Sopenharmony_ci MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; 34998c2ecf20Sopenharmony_ci 35008c2ecf20Sopenharmony_ci if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) 35018c2ecf20Sopenharmony_ci return IRQ_NONE; 35028c2ecf20Sopenharmony_ci 35038c2ecf20Sopenharmony_ci num_completed = 0; 35048c2ecf20Sopenharmony_ci 35058c2ecf20Sopenharmony_ci while (d_val.u.low != cpu_to_le32(UINT_MAX) && 35068c2ecf20Sopenharmony_ci d_val.u.high != cpu_to_le32(UINT_MAX)) { 35078c2ecf20Sopenharmony_ci 35088c2ecf20Sopenharmony_ci smid = le16_to_cpu(reply_desc->SMID); 35098c2ecf20Sopenharmony_ci cmd_fusion = fusion->cmd_list[smid - 1]; 35108c2ecf20Sopenharmony_ci scsi_io_req = (struct MPI2_RAID_SCSI_IO_REQUEST *) 35118c2ecf20Sopenharmony_ci cmd_fusion->io_request; 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_ci scmd_local = cmd_fusion->scmd; 35148c2ecf20Sopenharmony_ci status = scsi_io_req->RaidContext.raid_context.status; 35158c2ecf20Sopenharmony_ci extStatus = scsi_io_req->RaidContext.raid_context.ex_status; 35168c2ecf20Sopenharmony_ci sense = cmd_fusion->sense; 35178c2ecf20Sopenharmony_ci data_length = scsi_io_req->DataLength; 35188c2ecf20Sopenharmony_ci 35198c2ecf20Sopenharmony_ci switch (scsi_io_req->Function) { 35208c2ecf20Sopenharmony_ci case MPI2_FUNCTION_SCSI_TASK_MGMT: 35218c2ecf20Sopenharmony_ci mr_tm_req = (struct MR_TASK_MANAGE_REQUEST *) 35228c2ecf20Sopenharmony_ci cmd_fusion->io_request; 35238c2ecf20Sopenharmony_ci mpi_tm_req = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *) 35248c2ecf20Sopenharmony_ci &mr_tm_req->TmRequest; 35258c2ecf20Sopenharmony_ci dev_dbg(&instance->pdev->dev, "TM completion:" 35268c2ecf20Sopenharmony_ci "type: 0x%x TaskMID: 0x%x\n", 35278c2ecf20Sopenharmony_ci mpi_tm_req->TaskType, mpi_tm_req->TaskMID); 35288c2ecf20Sopenharmony_ci complete(&cmd_fusion->done); 35298c2ecf20Sopenharmony_ci break; 35308c2ecf20Sopenharmony_ci case MPI2_FUNCTION_SCSI_IO_REQUEST: /*Fast Path IO.*/ 35318c2ecf20Sopenharmony_ci /* Update load balancing info */ 35328c2ecf20Sopenharmony_ci if (fusion->load_balance_info && 35338c2ecf20Sopenharmony_ci (cmd_fusion->scmd->SCp.Status & 35348c2ecf20Sopenharmony_ci MEGASAS_LOAD_BALANCE_FLAG)) { 35358c2ecf20Sopenharmony_ci device_id = MEGASAS_DEV_INDEX(scmd_local); 35368c2ecf20Sopenharmony_ci lbinfo = &fusion->load_balance_info[device_id]; 35378c2ecf20Sopenharmony_ci atomic_dec(&lbinfo->scsi_pending_cmds[cmd_fusion->pd_r1_lb]); 35388c2ecf20Sopenharmony_ci cmd_fusion->scmd->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG; 35398c2ecf20Sopenharmony_ci } 35408c2ecf20Sopenharmony_ci fallthrough; /* and complete IO */ 35418c2ecf20Sopenharmony_ci case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */ 35428c2ecf20Sopenharmony_ci atomic_dec(&instance->fw_outstanding); 35438c2ecf20Sopenharmony_ci if (cmd_fusion->r1_alt_dev_handle == MR_DEVHANDLE_INVALID) { 35448c2ecf20Sopenharmony_ci map_cmd_status(fusion, scmd_local, status, 35458c2ecf20Sopenharmony_ci extStatus, le32_to_cpu(data_length), 35468c2ecf20Sopenharmony_ci sense); 35478c2ecf20Sopenharmony_ci if (instance->ldio_threshold && 35488c2ecf20Sopenharmony_ci (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)) 35498c2ecf20Sopenharmony_ci atomic_dec(&instance->ldio_outstanding); 35508c2ecf20Sopenharmony_ci scmd_local->SCp.ptr = NULL; 35518c2ecf20Sopenharmony_ci megasas_return_cmd_fusion(instance, cmd_fusion); 35528c2ecf20Sopenharmony_ci scsi_dma_unmap(scmd_local); 35538c2ecf20Sopenharmony_ci scmd_local->scsi_done(scmd_local); 35548c2ecf20Sopenharmony_ci } else /* Optimal VD - R1 FP command completion. */ 35558c2ecf20Sopenharmony_ci megasas_complete_r1_command(instance, cmd_fusion); 35568c2ecf20Sopenharmony_ci break; 35578c2ecf20Sopenharmony_ci case MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST: /*MFI command */ 35588c2ecf20Sopenharmony_ci cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx]; 35598c2ecf20Sopenharmony_ci /* Poll mode. Dummy free. 35608c2ecf20Sopenharmony_ci * In case of Interrupt mode, caller has reverse check. 35618c2ecf20Sopenharmony_ci */ 35628c2ecf20Sopenharmony_ci if (cmd_mfi->flags & DRV_DCMD_POLLED_MODE) { 35638c2ecf20Sopenharmony_ci cmd_mfi->flags &= ~DRV_DCMD_POLLED_MODE; 35648c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd_mfi); 35658c2ecf20Sopenharmony_ci } else 35668c2ecf20Sopenharmony_ci megasas_complete_cmd(instance, cmd_mfi, DID_OK); 35678c2ecf20Sopenharmony_ci break; 35688c2ecf20Sopenharmony_ci } 35698c2ecf20Sopenharmony_ci 35708c2ecf20Sopenharmony_ci fusion->last_reply_idx[MSIxIndex]++; 35718c2ecf20Sopenharmony_ci if (fusion->last_reply_idx[MSIxIndex] >= 35728c2ecf20Sopenharmony_ci fusion->reply_q_depth) 35738c2ecf20Sopenharmony_ci fusion->last_reply_idx[MSIxIndex] = 0; 35748c2ecf20Sopenharmony_ci 35758c2ecf20Sopenharmony_ci desc->Words = cpu_to_le64(ULLONG_MAX); 35768c2ecf20Sopenharmony_ci num_completed++; 35778c2ecf20Sopenharmony_ci threshold_reply_count++; 35788c2ecf20Sopenharmony_ci 35798c2ecf20Sopenharmony_ci /* Get the next reply descriptor */ 35808c2ecf20Sopenharmony_ci if (!fusion->last_reply_idx[MSIxIndex]) 35818c2ecf20Sopenharmony_ci desc = fusion->reply_frames_desc[MSIxIndex]; 35828c2ecf20Sopenharmony_ci else 35838c2ecf20Sopenharmony_ci desc++; 35848c2ecf20Sopenharmony_ci 35858c2ecf20Sopenharmony_ci reply_desc = 35868c2ecf20Sopenharmony_ci (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc; 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci d_val.word = desc->Words; 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci reply_descript_type = reply_desc->ReplyFlags & 35918c2ecf20Sopenharmony_ci MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; 35928c2ecf20Sopenharmony_ci 35938c2ecf20Sopenharmony_ci if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) 35948c2ecf20Sopenharmony_ci break; 35958c2ecf20Sopenharmony_ci /* 35968c2ecf20Sopenharmony_ci * Write to reply post host index register after completing threshold 35978c2ecf20Sopenharmony_ci * number of reply counts and still there are more replies in reply queue 35988c2ecf20Sopenharmony_ci * pending to be completed 35998c2ecf20Sopenharmony_ci */ 36008c2ecf20Sopenharmony_ci if (threshold_reply_count >= instance->threshold_reply_count) { 36018c2ecf20Sopenharmony_ci if (instance->msix_combined) 36028c2ecf20Sopenharmony_ci writel(((MSIxIndex & 0x7) << 24) | 36038c2ecf20Sopenharmony_ci fusion->last_reply_idx[MSIxIndex], 36048c2ecf20Sopenharmony_ci instance->reply_post_host_index_addr[MSIxIndex/8]); 36058c2ecf20Sopenharmony_ci else 36068c2ecf20Sopenharmony_ci writel((MSIxIndex << 24) | 36078c2ecf20Sopenharmony_ci fusion->last_reply_idx[MSIxIndex], 36088c2ecf20Sopenharmony_ci instance->reply_post_host_index_addr[0]); 36098c2ecf20Sopenharmony_ci threshold_reply_count = 0; 36108c2ecf20Sopenharmony_ci if (irq_context) { 36118c2ecf20Sopenharmony_ci if (!irq_context->irq_poll_scheduled) { 36128c2ecf20Sopenharmony_ci irq_context->irq_poll_scheduled = true; 36138c2ecf20Sopenharmony_ci irq_context->irq_line_enable = true; 36148c2ecf20Sopenharmony_ci irq_poll_sched(&irq_context->irqpoll); 36158c2ecf20Sopenharmony_ci } 36168c2ecf20Sopenharmony_ci return num_completed; 36178c2ecf20Sopenharmony_ci } 36188c2ecf20Sopenharmony_ci } 36198c2ecf20Sopenharmony_ci } 36208c2ecf20Sopenharmony_ci 36218c2ecf20Sopenharmony_ci if (num_completed) { 36228c2ecf20Sopenharmony_ci wmb(); 36238c2ecf20Sopenharmony_ci if (instance->msix_combined) 36248c2ecf20Sopenharmony_ci writel(((MSIxIndex & 0x7) << 24) | 36258c2ecf20Sopenharmony_ci fusion->last_reply_idx[MSIxIndex], 36268c2ecf20Sopenharmony_ci instance->reply_post_host_index_addr[MSIxIndex/8]); 36278c2ecf20Sopenharmony_ci else 36288c2ecf20Sopenharmony_ci writel((MSIxIndex << 24) | 36298c2ecf20Sopenharmony_ci fusion->last_reply_idx[MSIxIndex], 36308c2ecf20Sopenharmony_ci instance->reply_post_host_index_addr[0]); 36318c2ecf20Sopenharmony_ci megasas_check_and_restore_queue_depth(instance); 36328c2ecf20Sopenharmony_ci } 36338c2ecf20Sopenharmony_ci return num_completed; 36348c2ecf20Sopenharmony_ci} 36358c2ecf20Sopenharmony_ci 36368c2ecf20Sopenharmony_ci/** 36378c2ecf20Sopenharmony_ci * megasas_enable_irq_poll() - enable irqpoll 36388c2ecf20Sopenharmony_ci * @instance: Adapter soft state 36398c2ecf20Sopenharmony_ci */ 36408c2ecf20Sopenharmony_cistatic void megasas_enable_irq_poll(struct megasas_instance *instance) 36418c2ecf20Sopenharmony_ci{ 36428c2ecf20Sopenharmony_ci u32 count, i; 36438c2ecf20Sopenharmony_ci struct megasas_irq_context *irq_ctx; 36448c2ecf20Sopenharmony_ci 36458c2ecf20Sopenharmony_ci count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; 36468c2ecf20Sopenharmony_ci 36478c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 36488c2ecf20Sopenharmony_ci irq_ctx = &instance->irq_context[i]; 36498c2ecf20Sopenharmony_ci irq_poll_enable(&irq_ctx->irqpoll); 36508c2ecf20Sopenharmony_ci } 36518c2ecf20Sopenharmony_ci} 36528c2ecf20Sopenharmony_ci 36538c2ecf20Sopenharmony_ci/** 36548c2ecf20Sopenharmony_ci * megasas_sync_irqs - Synchronizes all IRQs owned by adapter 36558c2ecf20Sopenharmony_ci * @instance_addr: Adapter soft state address 36568c2ecf20Sopenharmony_ci */ 36578c2ecf20Sopenharmony_cistatic void megasas_sync_irqs(unsigned long instance_addr) 36588c2ecf20Sopenharmony_ci{ 36598c2ecf20Sopenharmony_ci u32 count, i; 36608c2ecf20Sopenharmony_ci struct megasas_instance *instance = 36618c2ecf20Sopenharmony_ci (struct megasas_instance *)instance_addr; 36628c2ecf20Sopenharmony_ci struct megasas_irq_context *irq_ctx; 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; 36658c2ecf20Sopenharmony_ci 36668c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 36678c2ecf20Sopenharmony_ci synchronize_irq(pci_irq_vector(instance->pdev, i)); 36688c2ecf20Sopenharmony_ci irq_ctx = &instance->irq_context[i]; 36698c2ecf20Sopenharmony_ci irq_poll_disable(&irq_ctx->irqpoll); 36708c2ecf20Sopenharmony_ci if (irq_ctx->irq_poll_scheduled) { 36718c2ecf20Sopenharmony_ci irq_ctx->irq_poll_scheduled = false; 36728c2ecf20Sopenharmony_ci enable_irq(irq_ctx->os_irq); 36738c2ecf20Sopenharmony_ci complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx); 36748c2ecf20Sopenharmony_ci } 36758c2ecf20Sopenharmony_ci } 36768c2ecf20Sopenharmony_ci} 36778c2ecf20Sopenharmony_ci 36788c2ecf20Sopenharmony_ci/** 36798c2ecf20Sopenharmony_ci * megasas_irqpoll() - process a queue for completed reply descriptors 36808c2ecf20Sopenharmony_ci * @irqpoll: IRQ poll structure associated with queue to poll. 36818c2ecf20Sopenharmony_ci * @budget: Threshold of reply descriptors to process per poll. 36828c2ecf20Sopenharmony_ci * 36838c2ecf20Sopenharmony_ci * Return: The number of entries processed. 36848c2ecf20Sopenharmony_ci */ 36858c2ecf20Sopenharmony_ci 36868c2ecf20Sopenharmony_ciint megasas_irqpoll(struct irq_poll *irqpoll, int budget) 36878c2ecf20Sopenharmony_ci{ 36888c2ecf20Sopenharmony_ci struct megasas_irq_context *irq_ctx; 36898c2ecf20Sopenharmony_ci struct megasas_instance *instance; 36908c2ecf20Sopenharmony_ci int num_entries; 36918c2ecf20Sopenharmony_ci 36928c2ecf20Sopenharmony_ci irq_ctx = container_of(irqpoll, struct megasas_irq_context, irqpoll); 36938c2ecf20Sopenharmony_ci instance = irq_ctx->instance; 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci if (irq_ctx->irq_line_enable) { 36968c2ecf20Sopenharmony_ci disable_irq_nosync(irq_ctx->os_irq); 36978c2ecf20Sopenharmony_ci irq_ctx->irq_line_enable = false; 36988c2ecf20Sopenharmony_ci } 36998c2ecf20Sopenharmony_ci 37008c2ecf20Sopenharmony_ci num_entries = complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx); 37018c2ecf20Sopenharmony_ci if (num_entries < budget) { 37028c2ecf20Sopenharmony_ci irq_poll_complete(irqpoll); 37038c2ecf20Sopenharmony_ci irq_ctx->irq_poll_scheduled = false; 37048c2ecf20Sopenharmony_ci enable_irq(irq_ctx->os_irq); 37058c2ecf20Sopenharmony_ci complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx); 37068c2ecf20Sopenharmony_ci } 37078c2ecf20Sopenharmony_ci 37088c2ecf20Sopenharmony_ci return num_entries; 37098c2ecf20Sopenharmony_ci} 37108c2ecf20Sopenharmony_ci 37118c2ecf20Sopenharmony_ci/** 37128c2ecf20Sopenharmony_ci * megasas_complete_cmd_dpc_fusion - Completes command 37138c2ecf20Sopenharmony_ci * @instance_addr: Adapter soft state address 37148c2ecf20Sopenharmony_ci * 37158c2ecf20Sopenharmony_ci * Tasklet to complete cmds 37168c2ecf20Sopenharmony_ci */ 37178c2ecf20Sopenharmony_cistatic void 37188c2ecf20Sopenharmony_cimegasas_complete_cmd_dpc_fusion(unsigned long instance_addr) 37198c2ecf20Sopenharmony_ci{ 37208c2ecf20Sopenharmony_ci struct megasas_instance *instance = 37218c2ecf20Sopenharmony_ci (struct megasas_instance *)instance_addr; 37228c2ecf20Sopenharmony_ci struct megasas_irq_context *irq_ctx = NULL; 37238c2ecf20Sopenharmony_ci u32 count, MSIxIndex; 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; 37268c2ecf20Sopenharmony_ci 37278c2ecf20Sopenharmony_ci /* If we have already declared adapter dead, donot complete cmds */ 37288c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) 37298c2ecf20Sopenharmony_ci return; 37308c2ecf20Sopenharmony_ci 37318c2ecf20Sopenharmony_ci for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++) { 37328c2ecf20Sopenharmony_ci irq_ctx = &instance->irq_context[MSIxIndex]; 37338c2ecf20Sopenharmony_ci complete_cmd_fusion(instance, MSIxIndex, irq_ctx); 37348c2ecf20Sopenharmony_ci } 37358c2ecf20Sopenharmony_ci} 37368c2ecf20Sopenharmony_ci 37378c2ecf20Sopenharmony_ci/** 37388c2ecf20Sopenharmony_ci * megasas_isr_fusion - isr entry point 37398c2ecf20Sopenharmony_ci * @irq: IRQ number 37408c2ecf20Sopenharmony_ci * @devp: IRQ context 37418c2ecf20Sopenharmony_ci */ 37428c2ecf20Sopenharmony_cistatic irqreturn_t megasas_isr_fusion(int irq, void *devp) 37438c2ecf20Sopenharmony_ci{ 37448c2ecf20Sopenharmony_ci struct megasas_irq_context *irq_context = devp; 37458c2ecf20Sopenharmony_ci struct megasas_instance *instance = irq_context->instance; 37468c2ecf20Sopenharmony_ci u32 mfiStatus; 37478c2ecf20Sopenharmony_ci 37488c2ecf20Sopenharmony_ci if (instance->mask_interrupts) 37498c2ecf20Sopenharmony_ci return IRQ_NONE; 37508c2ecf20Sopenharmony_ci 37518c2ecf20Sopenharmony_ci if (irq_context->irq_poll_scheduled) 37528c2ecf20Sopenharmony_ci return IRQ_HANDLED; 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_ci if (!instance->msix_vectors) { 37558c2ecf20Sopenharmony_ci mfiStatus = instance->instancet->clear_intr(instance); 37568c2ecf20Sopenharmony_ci if (!mfiStatus) 37578c2ecf20Sopenharmony_ci return IRQ_NONE; 37588c2ecf20Sopenharmony_ci } 37598c2ecf20Sopenharmony_ci 37608c2ecf20Sopenharmony_ci /* If we are resetting, bail */ 37618c2ecf20Sopenharmony_ci if (test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags)) { 37628c2ecf20Sopenharmony_ci instance->instancet->clear_intr(instance); 37638c2ecf20Sopenharmony_ci return IRQ_HANDLED; 37648c2ecf20Sopenharmony_ci } 37658c2ecf20Sopenharmony_ci 37668c2ecf20Sopenharmony_ci return complete_cmd_fusion(instance, irq_context->MSIxIndex, irq_context) 37678c2ecf20Sopenharmony_ci ? IRQ_HANDLED : IRQ_NONE; 37688c2ecf20Sopenharmony_ci} 37698c2ecf20Sopenharmony_ci 37708c2ecf20Sopenharmony_ci/** 37718c2ecf20Sopenharmony_ci * build_mpt_mfi_pass_thru - builds a cmd fo MFI Pass thru 37728c2ecf20Sopenharmony_ci * @instance: Adapter soft state 37738c2ecf20Sopenharmony_ci * @mfi_cmd: megasas_cmd pointer 37748c2ecf20Sopenharmony_ci * 37758c2ecf20Sopenharmony_ci */ 37768c2ecf20Sopenharmony_cistatic void 37778c2ecf20Sopenharmony_cibuild_mpt_mfi_pass_thru(struct megasas_instance *instance, 37788c2ecf20Sopenharmony_ci struct megasas_cmd *mfi_cmd) 37798c2ecf20Sopenharmony_ci{ 37808c2ecf20Sopenharmony_ci struct MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain; 37818c2ecf20Sopenharmony_ci struct MPI2_RAID_SCSI_IO_REQUEST *io_req; 37828c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd; 37838c2ecf20Sopenharmony_ci struct fusion_context *fusion; 37848c2ecf20Sopenharmony_ci struct megasas_header *frame_hdr = &mfi_cmd->frame->hdr; 37858c2ecf20Sopenharmony_ci 37868c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 37878c2ecf20Sopenharmony_ci 37888c2ecf20Sopenharmony_ci cmd = megasas_get_cmd_fusion(instance, 37898c2ecf20Sopenharmony_ci instance->max_scsi_cmds + mfi_cmd->index); 37908c2ecf20Sopenharmony_ci 37918c2ecf20Sopenharmony_ci /* Save the smid. To be used for returning the cmd */ 37928c2ecf20Sopenharmony_ci mfi_cmd->context.smid = cmd->index; 37938c2ecf20Sopenharmony_ci 37948c2ecf20Sopenharmony_ci /* 37958c2ecf20Sopenharmony_ci * For cmds where the flag is set, store the flag and check 37968c2ecf20Sopenharmony_ci * on completion. For cmds with this flag, don't call 37978c2ecf20Sopenharmony_ci * megasas_complete_cmd 37988c2ecf20Sopenharmony_ci */ 37998c2ecf20Sopenharmony_ci 38008c2ecf20Sopenharmony_ci if (frame_hdr->flags & cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE)) 38018c2ecf20Sopenharmony_ci mfi_cmd->flags |= DRV_DCMD_POLLED_MODE; 38028c2ecf20Sopenharmony_ci 38038c2ecf20Sopenharmony_ci io_req = cmd->io_request; 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ci if (instance->adapter_type >= INVADER_SERIES) { 38068c2ecf20Sopenharmony_ci struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = 38078c2ecf20Sopenharmony_ci (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL; 38088c2ecf20Sopenharmony_ci sgl_ptr_end += fusion->max_sge_in_main_msg - 1; 38098c2ecf20Sopenharmony_ci sgl_ptr_end->Flags = 0; 38108c2ecf20Sopenharmony_ci } 38118c2ecf20Sopenharmony_ci 38128c2ecf20Sopenharmony_ci mpi25_ieee_chain = 38138c2ecf20Sopenharmony_ci (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain; 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ci io_req->Function = MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST; 38168c2ecf20Sopenharmony_ci io_req->SGLOffset0 = offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, 38178c2ecf20Sopenharmony_ci SGL) / 4; 38188c2ecf20Sopenharmony_ci io_req->ChainOffset = fusion->chain_offset_mfi_pthru; 38198c2ecf20Sopenharmony_ci 38208c2ecf20Sopenharmony_ci mpi25_ieee_chain->Address = cpu_to_le64(mfi_cmd->frame_phys_addr); 38218c2ecf20Sopenharmony_ci 38228c2ecf20Sopenharmony_ci mpi25_ieee_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT | 38238c2ecf20Sopenharmony_ci MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR; 38248c2ecf20Sopenharmony_ci 38258c2ecf20Sopenharmony_ci mpi25_ieee_chain->Length = cpu_to_le32(instance->mfi_frame_size); 38268c2ecf20Sopenharmony_ci} 38278c2ecf20Sopenharmony_ci 38288c2ecf20Sopenharmony_ci/** 38298c2ecf20Sopenharmony_ci * build_mpt_cmd - Calls helper function to build a cmd MFI Pass thru cmd 38308c2ecf20Sopenharmony_ci * @instance: Adapter soft state 38318c2ecf20Sopenharmony_ci * @cmd: mfi cmd to build 38328c2ecf20Sopenharmony_ci * 38338c2ecf20Sopenharmony_ci */ 38348c2ecf20Sopenharmony_cistatic union MEGASAS_REQUEST_DESCRIPTOR_UNION * 38358c2ecf20Sopenharmony_cibuild_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) 38368c2ecf20Sopenharmony_ci{ 38378c2ecf20Sopenharmony_ci union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc = NULL; 38388c2ecf20Sopenharmony_ci u16 index; 38398c2ecf20Sopenharmony_ci 38408c2ecf20Sopenharmony_ci build_mpt_mfi_pass_thru(instance, cmd); 38418c2ecf20Sopenharmony_ci index = cmd->context.smid; 38428c2ecf20Sopenharmony_ci 38438c2ecf20Sopenharmony_ci req_desc = megasas_get_request_descriptor(instance, index - 1); 38448c2ecf20Sopenharmony_ci 38458c2ecf20Sopenharmony_ci req_desc->Words = 0; 38468c2ecf20Sopenharmony_ci req_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << 38478c2ecf20Sopenharmony_ci MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci req_desc->SCSIIO.SMID = cpu_to_le16(index); 38508c2ecf20Sopenharmony_ci 38518c2ecf20Sopenharmony_ci return req_desc; 38528c2ecf20Sopenharmony_ci} 38538c2ecf20Sopenharmony_ci 38548c2ecf20Sopenharmony_ci/** 38558c2ecf20Sopenharmony_ci * megasas_issue_dcmd_fusion - Issues a MFI Pass thru cmd 38568c2ecf20Sopenharmony_ci * @instance: Adapter soft state 38578c2ecf20Sopenharmony_ci * @cmd: mfi cmd pointer 38588c2ecf20Sopenharmony_ci * 38598c2ecf20Sopenharmony_ci */ 38608c2ecf20Sopenharmony_cistatic void 38618c2ecf20Sopenharmony_cimegasas_issue_dcmd_fusion(struct megasas_instance *instance, 38628c2ecf20Sopenharmony_ci struct megasas_cmd *cmd) 38638c2ecf20Sopenharmony_ci{ 38648c2ecf20Sopenharmony_ci union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; 38658c2ecf20Sopenharmony_ci 38668c2ecf20Sopenharmony_ci req_desc = build_mpt_cmd(instance, cmd); 38678c2ecf20Sopenharmony_ci 38688c2ecf20Sopenharmony_ci megasas_fire_cmd_fusion(instance, req_desc); 38698c2ecf20Sopenharmony_ci return; 38708c2ecf20Sopenharmony_ci} 38718c2ecf20Sopenharmony_ci 38728c2ecf20Sopenharmony_ci/** 38738c2ecf20Sopenharmony_ci * megasas_release_fusion - Reverses the FW initialization 38748c2ecf20Sopenharmony_ci * @instance: Adapter soft state 38758c2ecf20Sopenharmony_ci */ 38768c2ecf20Sopenharmony_civoid 38778c2ecf20Sopenharmony_cimegasas_release_fusion(struct megasas_instance *instance) 38788c2ecf20Sopenharmony_ci{ 38798c2ecf20Sopenharmony_ci megasas_free_ioc_init_cmd(instance); 38808c2ecf20Sopenharmony_ci megasas_free_cmds(instance); 38818c2ecf20Sopenharmony_ci megasas_free_cmds_fusion(instance); 38828c2ecf20Sopenharmony_ci 38838c2ecf20Sopenharmony_ci iounmap(instance->reg_set); 38848c2ecf20Sopenharmony_ci 38858c2ecf20Sopenharmony_ci pci_release_selected_regions(instance->pdev, 1<<instance->bar); 38868c2ecf20Sopenharmony_ci} 38878c2ecf20Sopenharmony_ci 38888c2ecf20Sopenharmony_ci/** 38898c2ecf20Sopenharmony_ci * megasas_read_fw_status_reg_fusion - returns the current FW status value 38908c2ecf20Sopenharmony_ci * @instance: Adapter soft state 38918c2ecf20Sopenharmony_ci */ 38928c2ecf20Sopenharmony_cistatic u32 38938c2ecf20Sopenharmony_cimegasas_read_fw_status_reg_fusion(struct megasas_instance *instance) 38948c2ecf20Sopenharmony_ci{ 38958c2ecf20Sopenharmony_ci return megasas_readl(instance, &instance->reg_set->outbound_scratch_pad_0); 38968c2ecf20Sopenharmony_ci} 38978c2ecf20Sopenharmony_ci 38988c2ecf20Sopenharmony_ci/** 38998c2ecf20Sopenharmony_ci * megasas_alloc_host_crash_buffer - Host buffers for Crash dump collection from Firmware 39008c2ecf20Sopenharmony_ci * @instance: Controller's soft instance 39018c2ecf20Sopenharmony_ci * @return: Number of allocated host crash buffers 39028c2ecf20Sopenharmony_ci */ 39038c2ecf20Sopenharmony_cistatic void 39048c2ecf20Sopenharmony_cimegasas_alloc_host_crash_buffer(struct megasas_instance *instance) 39058c2ecf20Sopenharmony_ci{ 39068c2ecf20Sopenharmony_ci unsigned int i; 39078c2ecf20Sopenharmony_ci 39088c2ecf20Sopenharmony_ci for (i = 0; i < MAX_CRASH_DUMP_SIZE; i++) { 39098c2ecf20Sopenharmony_ci instance->crash_buf[i] = vzalloc(CRASH_DMA_BUF_SIZE); 39108c2ecf20Sopenharmony_ci if (!instance->crash_buf[i]) { 39118c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Firmware crash dump " 39128c2ecf20Sopenharmony_ci "memory allocation failed at index %d\n", i); 39138c2ecf20Sopenharmony_ci break; 39148c2ecf20Sopenharmony_ci } 39158c2ecf20Sopenharmony_ci } 39168c2ecf20Sopenharmony_ci instance->drv_buf_alloc = i; 39178c2ecf20Sopenharmony_ci} 39188c2ecf20Sopenharmony_ci 39198c2ecf20Sopenharmony_ci/** 39208c2ecf20Sopenharmony_ci * megasas_free_host_crash_buffer - Host buffers for Crash dump collection from Firmware 39218c2ecf20Sopenharmony_ci * @instance: Controller's soft instance 39228c2ecf20Sopenharmony_ci */ 39238c2ecf20Sopenharmony_civoid 39248c2ecf20Sopenharmony_cimegasas_free_host_crash_buffer(struct megasas_instance *instance) 39258c2ecf20Sopenharmony_ci{ 39268c2ecf20Sopenharmony_ci unsigned int i; 39278c2ecf20Sopenharmony_ci for (i = 0; i < instance->drv_buf_alloc; i++) { 39288c2ecf20Sopenharmony_ci if (instance->crash_buf[i]) 39298c2ecf20Sopenharmony_ci vfree(instance->crash_buf[i]); 39308c2ecf20Sopenharmony_ci } 39318c2ecf20Sopenharmony_ci instance->drv_buf_index = 0; 39328c2ecf20Sopenharmony_ci instance->drv_buf_alloc = 0; 39338c2ecf20Sopenharmony_ci instance->fw_crash_state = UNAVAILABLE; 39348c2ecf20Sopenharmony_ci instance->fw_crash_buffer_size = 0; 39358c2ecf20Sopenharmony_ci} 39368c2ecf20Sopenharmony_ci 39378c2ecf20Sopenharmony_ci/** 39388c2ecf20Sopenharmony_ci * megasas_adp_reset_fusion - For controller reset 39398c2ecf20Sopenharmony_ci * @instance: Controller's soft instance 39408c2ecf20Sopenharmony_ci * @regs: MFI register set 39418c2ecf20Sopenharmony_ci */ 39428c2ecf20Sopenharmony_cistatic int 39438c2ecf20Sopenharmony_cimegasas_adp_reset_fusion(struct megasas_instance *instance, 39448c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs) 39458c2ecf20Sopenharmony_ci{ 39468c2ecf20Sopenharmony_ci u32 host_diag, abs_state, retry; 39478c2ecf20Sopenharmony_ci 39488c2ecf20Sopenharmony_ci /* Now try to reset the chip */ 39498c2ecf20Sopenharmony_ci writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &instance->reg_set->fusion_seq_offset); 39508c2ecf20Sopenharmony_ci writel(MPI2_WRSEQ_1ST_KEY_VALUE, &instance->reg_set->fusion_seq_offset); 39518c2ecf20Sopenharmony_ci writel(MPI2_WRSEQ_2ND_KEY_VALUE, &instance->reg_set->fusion_seq_offset); 39528c2ecf20Sopenharmony_ci writel(MPI2_WRSEQ_3RD_KEY_VALUE, &instance->reg_set->fusion_seq_offset); 39538c2ecf20Sopenharmony_ci writel(MPI2_WRSEQ_4TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset); 39548c2ecf20Sopenharmony_ci writel(MPI2_WRSEQ_5TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset); 39558c2ecf20Sopenharmony_ci writel(MPI2_WRSEQ_6TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset); 39568c2ecf20Sopenharmony_ci 39578c2ecf20Sopenharmony_ci /* Check that the diag write enable (DRWE) bit is on */ 39588c2ecf20Sopenharmony_ci host_diag = megasas_readl(instance, &instance->reg_set->fusion_host_diag); 39598c2ecf20Sopenharmony_ci retry = 0; 39608c2ecf20Sopenharmony_ci while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) { 39618c2ecf20Sopenharmony_ci msleep(100); 39628c2ecf20Sopenharmony_ci host_diag = megasas_readl(instance, 39638c2ecf20Sopenharmony_ci &instance->reg_set->fusion_host_diag); 39648c2ecf20Sopenharmony_ci if (retry++ == 100) { 39658c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, 39668c2ecf20Sopenharmony_ci "Host diag unlock failed from %s %d\n", 39678c2ecf20Sopenharmony_ci __func__, __LINE__); 39688c2ecf20Sopenharmony_ci break; 39698c2ecf20Sopenharmony_ci } 39708c2ecf20Sopenharmony_ci } 39718c2ecf20Sopenharmony_ci if (!(host_diag & HOST_DIAG_WRITE_ENABLE)) 39728c2ecf20Sopenharmony_ci return -1; 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_ci /* Send chip reset command */ 39758c2ecf20Sopenharmony_ci writel(host_diag | HOST_DIAG_RESET_ADAPTER, 39768c2ecf20Sopenharmony_ci &instance->reg_set->fusion_host_diag); 39778c2ecf20Sopenharmony_ci msleep(3000); 39788c2ecf20Sopenharmony_ci 39798c2ecf20Sopenharmony_ci /* Make sure reset adapter bit is cleared */ 39808c2ecf20Sopenharmony_ci host_diag = megasas_readl(instance, &instance->reg_set->fusion_host_diag); 39818c2ecf20Sopenharmony_ci retry = 0; 39828c2ecf20Sopenharmony_ci while (host_diag & HOST_DIAG_RESET_ADAPTER) { 39838c2ecf20Sopenharmony_ci msleep(100); 39848c2ecf20Sopenharmony_ci host_diag = megasas_readl(instance, 39858c2ecf20Sopenharmony_ci &instance->reg_set->fusion_host_diag); 39868c2ecf20Sopenharmony_ci if (retry++ == 1000) { 39878c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, 39888c2ecf20Sopenharmony_ci "Diag reset adapter never cleared %s %d\n", 39898c2ecf20Sopenharmony_ci __func__, __LINE__); 39908c2ecf20Sopenharmony_ci break; 39918c2ecf20Sopenharmony_ci } 39928c2ecf20Sopenharmony_ci } 39938c2ecf20Sopenharmony_ci if (host_diag & HOST_DIAG_RESET_ADAPTER) 39948c2ecf20Sopenharmony_ci return -1; 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci abs_state = instance->instancet->read_fw_status_reg(instance) 39978c2ecf20Sopenharmony_ci & MFI_STATE_MASK; 39988c2ecf20Sopenharmony_ci retry = 0; 39998c2ecf20Sopenharmony_ci 40008c2ecf20Sopenharmony_ci while ((abs_state <= MFI_STATE_FW_INIT) && (retry++ < 1000)) { 40018c2ecf20Sopenharmony_ci msleep(100); 40028c2ecf20Sopenharmony_ci abs_state = instance->instancet-> 40038c2ecf20Sopenharmony_ci read_fw_status_reg(instance) & MFI_STATE_MASK; 40048c2ecf20Sopenharmony_ci } 40058c2ecf20Sopenharmony_ci if (abs_state <= MFI_STATE_FW_INIT) { 40068c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, 40078c2ecf20Sopenharmony_ci "fw state < MFI_STATE_FW_INIT, state = 0x%x %s %d\n", 40088c2ecf20Sopenharmony_ci abs_state, __func__, __LINE__); 40098c2ecf20Sopenharmony_ci return -1; 40108c2ecf20Sopenharmony_ci } 40118c2ecf20Sopenharmony_ci 40128c2ecf20Sopenharmony_ci return 0; 40138c2ecf20Sopenharmony_ci} 40148c2ecf20Sopenharmony_ci 40158c2ecf20Sopenharmony_ci/** 40168c2ecf20Sopenharmony_ci * megasas_check_reset_fusion - For controller reset check 40178c2ecf20Sopenharmony_ci * @instance: Controller's soft instance 40188c2ecf20Sopenharmony_ci * @regs: MFI register set 40198c2ecf20Sopenharmony_ci */ 40208c2ecf20Sopenharmony_cistatic int 40218c2ecf20Sopenharmony_cimegasas_check_reset_fusion(struct megasas_instance *instance, 40228c2ecf20Sopenharmony_ci struct megasas_register_set __iomem *regs) 40238c2ecf20Sopenharmony_ci{ 40248c2ecf20Sopenharmony_ci return 0; 40258c2ecf20Sopenharmony_ci} 40268c2ecf20Sopenharmony_ci 40278c2ecf20Sopenharmony_ci/** 40288c2ecf20Sopenharmony_ci * megasas_trigger_snap_dump - Trigger snap dump in FW 40298c2ecf20Sopenharmony_ci * @instance: Soft instance of adapter 40308c2ecf20Sopenharmony_ci */ 40318c2ecf20Sopenharmony_cistatic inline void megasas_trigger_snap_dump(struct megasas_instance *instance) 40328c2ecf20Sopenharmony_ci{ 40338c2ecf20Sopenharmony_ci int j; 40348c2ecf20Sopenharmony_ci u32 fw_state, abs_state; 40358c2ecf20Sopenharmony_ci 40368c2ecf20Sopenharmony_ci if (!instance->disableOnlineCtrlReset) { 40378c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Trigger snap dump\n"); 40388c2ecf20Sopenharmony_ci writel(MFI_ADP_TRIGGER_SNAP_DUMP, 40398c2ecf20Sopenharmony_ci &instance->reg_set->doorbell); 40408c2ecf20Sopenharmony_ci readl(&instance->reg_set->doorbell); 40418c2ecf20Sopenharmony_ci } 40428c2ecf20Sopenharmony_ci 40438c2ecf20Sopenharmony_ci for (j = 0; j < instance->snapdump_wait_time; j++) { 40448c2ecf20Sopenharmony_ci abs_state = instance->instancet->read_fw_status_reg(instance); 40458c2ecf20Sopenharmony_ci fw_state = abs_state & MFI_STATE_MASK; 40468c2ecf20Sopenharmony_ci if (fw_state == MFI_STATE_FAULT) { 40478c2ecf20Sopenharmony_ci dev_printk(KERN_ERR, &instance->pdev->dev, 40488c2ecf20Sopenharmony_ci "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n", 40498c2ecf20Sopenharmony_ci abs_state & MFI_STATE_FAULT_CODE, 40508c2ecf20Sopenharmony_ci abs_state & MFI_STATE_FAULT_SUBCODE, __func__); 40518c2ecf20Sopenharmony_ci return; 40528c2ecf20Sopenharmony_ci } 40538c2ecf20Sopenharmony_ci msleep(1000); 40548c2ecf20Sopenharmony_ci } 40558c2ecf20Sopenharmony_ci} 40568c2ecf20Sopenharmony_ci 40578c2ecf20Sopenharmony_ci/* This function waits for outstanding commands on fusion to complete */ 40588c2ecf20Sopenharmony_cistatic int 40598c2ecf20Sopenharmony_cimegasas_wait_for_outstanding_fusion(struct megasas_instance *instance, 40608c2ecf20Sopenharmony_ci int reason, int *convert) 40618c2ecf20Sopenharmony_ci{ 40628c2ecf20Sopenharmony_ci int i, outstanding, retval = 0, hb_seconds_missed = 0; 40638c2ecf20Sopenharmony_ci u32 fw_state, abs_state; 40648c2ecf20Sopenharmony_ci u32 waittime_for_io_completion; 40658c2ecf20Sopenharmony_ci 40668c2ecf20Sopenharmony_ci waittime_for_io_completion = 40678c2ecf20Sopenharmony_ci min_t(u32, resetwaittime, 40688c2ecf20Sopenharmony_ci (resetwaittime - instance->snapdump_wait_time)); 40698c2ecf20Sopenharmony_ci 40708c2ecf20Sopenharmony_ci if (reason == MFI_IO_TIMEOUT_OCR) { 40718c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 40728c2ecf20Sopenharmony_ci "MFI command is timed out\n"); 40738c2ecf20Sopenharmony_ci megasas_complete_cmd_dpc_fusion((unsigned long)instance); 40748c2ecf20Sopenharmony_ci if (instance->snapdump_wait_time) 40758c2ecf20Sopenharmony_ci megasas_trigger_snap_dump(instance); 40768c2ecf20Sopenharmony_ci retval = 1; 40778c2ecf20Sopenharmony_ci goto out; 40788c2ecf20Sopenharmony_ci } 40798c2ecf20Sopenharmony_ci 40808c2ecf20Sopenharmony_ci for (i = 0; i < waittime_for_io_completion; i++) { 40818c2ecf20Sopenharmony_ci /* Check if firmware is in fault state */ 40828c2ecf20Sopenharmony_ci abs_state = instance->instancet->read_fw_status_reg(instance); 40838c2ecf20Sopenharmony_ci fw_state = abs_state & MFI_STATE_MASK; 40848c2ecf20Sopenharmony_ci if (fw_state == MFI_STATE_FAULT) { 40858c2ecf20Sopenharmony_ci dev_printk(KERN_ERR, &instance->pdev->dev, 40868c2ecf20Sopenharmony_ci "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n", 40878c2ecf20Sopenharmony_ci abs_state & MFI_STATE_FAULT_CODE, 40888c2ecf20Sopenharmony_ci abs_state & MFI_STATE_FAULT_SUBCODE, __func__); 40898c2ecf20Sopenharmony_ci megasas_complete_cmd_dpc_fusion((unsigned long)instance); 40908c2ecf20Sopenharmony_ci if (instance->requestorId && reason) { 40918c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV Found FW in FAULT" 40928c2ecf20Sopenharmony_ci " state while polling during" 40938c2ecf20Sopenharmony_ci " I/O timeout handling for %d\n", 40948c2ecf20Sopenharmony_ci instance->host->host_no); 40958c2ecf20Sopenharmony_ci *convert = 1; 40968c2ecf20Sopenharmony_ci } 40978c2ecf20Sopenharmony_ci 40988c2ecf20Sopenharmony_ci retval = 1; 40998c2ecf20Sopenharmony_ci goto out; 41008c2ecf20Sopenharmony_ci } 41018c2ecf20Sopenharmony_ci 41028c2ecf20Sopenharmony_ci 41038c2ecf20Sopenharmony_ci /* If SR-IOV VF mode & heartbeat timeout, don't wait */ 41048c2ecf20Sopenharmony_ci if (instance->requestorId && !reason) { 41058c2ecf20Sopenharmony_ci retval = 1; 41068c2ecf20Sopenharmony_ci goto out; 41078c2ecf20Sopenharmony_ci } 41088c2ecf20Sopenharmony_ci 41098c2ecf20Sopenharmony_ci /* If SR-IOV VF mode & I/O timeout, check for HB timeout */ 41108c2ecf20Sopenharmony_ci if (instance->requestorId && (reason == SCSIIO_TIMEOUT_OCR)) { 41118c2ecf20Sopenharmony_ci if (instance->hb_host_mem->HB.fwCounter != 41128c2ecf20Sopenharmony_ci instance->hb_host_mem->HB.driverCounter) { 41138c2ecf20Sopenharmony_ci instance->hb_host_mem->HB.driverCounter = 41148c2ecf20Sopenharmony_ci instance->hb_host_mem->HB.fwCounter; 41158c2ecf20Sopenharmony_ci hb_seconds_missed = 0; 41168c2ecf20Sopenharmony_ci } else { 41178c2ecf20Sopenharmony_ci hb_seconds_missed++; 41188c2ecf20Sopenharmony_ci if (hb_seconds_missed == 41198c2ecf20Sopenharmony_ci (MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF/HZ)) { 41208c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "SR-IOV:" 41218c2ecf20Sopenharmony_ci " Heartbeat never completed " 41228c2ecf20Sopenharmony_ci " while polling during I/O " 41238c2ecf20Sopenharmony_ci " timeout handling for " 41248c2ecf20Sopenharmony_ci "scsi%d.\n", 41258c2ecf20Sopenharmony_ci instance->host->host_no); 41268c2ecf20Sopenharmony_ci *convert = 1; 41278c2ecf20Sopenharmony_ci retval = 1; 41288c2ecf20Sopenharmony_ci goto out; 41298c2ecf20Sopenharmony_ci } 41308c2ecf20Sopenharmony_ci } 41318c2ecf20Sopenharmony_ci } 41328c2ecf20Sopenharmony_ci 41338c2ecf20Sopenharmony_ci megasas_complete_cmd_dpc_fusion((unsigned long)instance); 41348c2ecf20Sopenharmony_ci outstanding = atomic_read(&instance->fw_outstanding); 41358c2ecf20Sopenharmony_ci if (!outstanding) 41368c2ecf20Sopenharmony_ci goto out; 41378c2ecf20Sopenharmony_ci 41388c2ecf20Sopenharmony_ci if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { 41398c2ecf20Sopenharmony_ci dev_notice(&instance->pdev->dev, "[%2d]waiting for %d " 41408c2ecf20Sopenharmony_ci "commands to complete for scsi%d\n", i, 41418c2ecf20Sopenharmony_ci outstanding, instance->host->host_no); 41428c2ecf20Sopenharmony_ci } 41438c2ecf20Sopenharmony_ci msleep(1000); 41448c2ecf20Sopenharmony_ci } 41458c2ecf20Sopenharmony_ci 41468c2ecf20Sopenharmony_ci if (instance->snapdump_wait_time) { 41478c2ecf20Sopenharmony_ci megasas_trigger_snap_dump(instance); 41488c2ecf20Sopenharmony_ci retval = 1; 41498c2ecf20Sopenharmony_ci goto out; 41508c2ecf20Sopenharmony_ci } 41518c2ecf20Sopenharmony_ci 41528c2ecf20Sopenharmony_ci if (atomic_read(&instance->fw_outstanding)) { 41538c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "pending commands remain after waiting, " 41548c2ecf20Sopenharmony_ci "will reset adapter scsi%d.\n", 41558c2ecf20Sopenharmony_ci instance->host->host_no); 41568c2ecf20Sopenharmony_ci *convert = 1; 41578c2ecf20Sopenharmony_ci retval = 1; 41588c2ecf20Sopenharmony_ci } 41598c2ecf20Sopenharmony_ci 41608c2ecf20Sopenharmony_ciout: 41618c2ecf20Sopenharmony_ci return retval; 41628c2ecf20Sopenharmony_ci} 41638c2ecf20Sopenharmony_ci 41648c2ecf20Sopenharmony_civoid megasas_reset_reply_desc(struct megasas_instance *instance) 41658c2ecf20Sopenharmony_ci{ 41668c2ecf20Sopenharmony_ci int i, j, count; 41678c2ecf20Sopenharmony_ci struct fusion_context *fusion; 41688c2ecf20Sopenharmony_ci union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; 41698c2ecf20Sopenharmony_ci 41708c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 41718c2ecf20Sopenharmony_ci count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; 41728c2ecf20Sopenharmony_ci for (i = 0 ; i < count ; i++) { 41738c2ecf20Sopenharmony_ci fusion->last_reply_idx[i] = 0; 41748c2ecf20Sopenharmony_ci reply_desc = fusion->reply_frames_desc[i]; 41758c2ecf20Sopenharmony_ci for (j = 0 ; j < fusion->reply_q_depth; j++, reply_desc++) 41768c2ecf20Sopenharmony_ci reply_desc->Words = cpu_to_le64(ULLONG_MAX); 41778c2ecf20Sopenharmony_ci } 41788c2ecf20Sopenharmony_ci} 41798c2ecf20Sopenharmony_ci 41808c2ecf20Sopenharmony_ci/* 41818c2ecf20Sopenharmony_ci * megasas_refire_mgmt_cmd : Re-fire management commands 41828c2ecf20Sopenharmony_ci * @instance: Controller's soft instance 41838c2ecf20Sopenharmony_ci*/ 41848c2ecf20Sopenharmony_cistatic void megasas_refire_mgmt_cmd(struct megasas_instance *instance, 41858c2ecf20Sopenharmony_ci bool return_ioctl) 41868c2ecf20Sopenharmony_ci{ 41878c2ecf20Sopenharmony_ci int j; 41888c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd_fusion; 41898c2ecf20Sopenharmony_ci struct fusion_context *fusion; 41908c2ecf20Sopenharmony_ci struct megasas_cmd *cmd_mfi; 41918c2ecf20Sopenharmony_ci union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; 41928c2ecf20Sopenharmony_ci struct MPI2_RAID_SCSI_IO_REQUEST *scsi_io_req; 41938c2ecf20Sopenharmony_ci u16 smid; 41948c2ecf20Sopenharmony_ci bool refire_cmd = false; 41958c2ecf20Sopenharmony_ci u8 result; 41968c2ecf20Sopenharmony_ci u32 opcode = 0; 41978c2ecf20Sopenharmony_ci 41988c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 41998c2ecf20Sopenharmony_ci 42008c2ecf20Sopenharmony_ci /* Re-fire management commands. 42018c2ecf20Sopenharmony_ci * Do not traverse complet MPT frame pool. Start from max_scsi_cmds. 42028c2ecf20Sopenharmony_ci */ 42038c2ecf20Sopenharmony_ci for (j = instance->max_scsi_cmds ; j < instance->max_fw_cmds; j++) { 42048c2ecf20Sopenharmony_ci cmd_fusion = fusion->cmd_list[j]; 42058c2ecf20Sopenharmony_ci cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx]; 42068c2ecf20Sopenharmony_ci smid = le16_to_cpu(cmd_mfi->context.smid); 42078c2ecf20Sopenharmony_ci result = REFIRE_CMD; 42088c2ecf20Sopenharmony_ci 42098c2ecf20Sopenharmony_ci if (!smid) 42108c2ecf20Sopenharmony_ci continue; 42118c2ecf20Sopenharmony_ci 42128c2ecf20Sopenharmony_ci req_desc = megasas_get_request_descriptor(instance, smid - 1); 42138c2ecf20Sopenharmony_ci 42148c2ecf20Sopenharmony_ci switch (cmd_mfi->frame->hdr.cmd) { 42158c2ecf20Sopenharmony_ci case MFI_CMD_DCMD: 42168c2ecf20Sopenharmony_ci opcode = le32_to_cpu(cmd_mfi->frame->dcmd.opcode); 42178c2ecf20Sopenharmony_ci /* Do not refire shutdown command */ 42188c2ecf20Sopenharmony_ci if (opcode == MR_DCMD_CTRL_SHUTDOWN) { 42198c2ecf20Sopenharmony_ci cmd_mfi->frame->dcmd.cmd_status = MFI_STAT_OK; 42208c2ecf20Sopenharmony_ci result = COMPLETE_CMD; 42218c2ecf20Sopenharmony_ci break; 42228c2ecf20Sopenharmony_ci } 42238c2ecf20Sopenharmony_ci 42248c2ecf20Sopenharmony_ci refire_cmd = ((opcode != MR_DCMD_LD_MAP_GET_INFO)) && 42258c2ecf20Sopenharmony_ci (opcode != MR_DCMD_SYSTEM_PD_MAP_GET_INFO) && 42268c2ecf20Sopenharmony_ci !(cmd_mfi->flags & DRV_DCMD_SKIP_REFIRE); 42278c2ecf20Sopenharmony_ci 42288c2ecf20Sopenharmony_ci if (!refire_cmd) 42298c2ecf20Sopenharmony_ci result = RETURN_CMD; 42308c2ecf20Sopenharmony_ci 42318c2ecf20Sopenharmony_ci break; 42328c2ecf20Sopenharmony_ci case MFI_CMD_NVME: 42338c2ecf20Sopenharmony_ci if (!instance->support_nvme_passthru) { 42348c2ecf20Sopenharmony_ci cmd_mfi->frame->hdr.cmd_status = MFI_STAT_INVALID_CMD; 42358c2ecf20Sopenharmony_ci result = COMPLETE_CMD; 42368c2ecf20Sopenharmony_ci } 42378c2ecf20Sopenharmony_ci 42388c2ecf20Sopenharmony_ci break; 42398c2ecf20Sopenharmony_ci case MFI_CMD_TOOLBOX: 42408c2ecf20Sopenharmony_ci if (!instance->support_pci_lane_margining) { 42418c2ecf20Sopenharmony_ci cmd_mfi->frame->hdr.cmd_status = MFI_STAT_INVALID_CMD; 42428c2ecf20Sopenharmony_ci result = COMPLETE_CMD; 42438c2ecf20Sopenharmony_ci } 42448c2ecf20Sopenharmony_ci 42458c2ecf20Sopenharmony_ci break; 42468c2ecf20Sopenharmony_ci default: 42478c2ecf20Sopenharmony_ci break; 42488c2ecf20Sopenharmony_ci } 42498c2ecf20Sopenharmony_ci 42508c2ecf20Sopenharmony_ci if (return_ioctl && cmd_mfi->sync_cmd && 42518c2ecf20Sopenharmony_ci cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT) { 42528c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 42538c2ecf20Sopenharmony_ci "return -EBUSY from %s %d cmd 0x%x opcode 0x%x\n", 42548c2ecf20Sopenharmony_ci __func__, __LINE__, cmd_mfi->frame->hdr.cmd, 42558c2ecf20Sopenharmony_ci le32_to_cpu(cmd_mfi->frame->dcmd.opcode)); 42568c2ecf20Sopenharmony_ci cmd_mfi->cmd_status_drv = DCMD_BUSY; 42578c2ecf20Sopenharmony_ci result = COMPLETE_CMD; 42588c2ecf20Sopenharmony_ci } 42598c2ecf20Sopenharmony_ci 42608c2ecf20Sopenharmony_ci scsi_io_req = (struct MPI2_RAID_SCSI_IO_REQUEST *) 42618c2ecf20Sopenharmony_ci cmd_fusion->io_request; 42628c2ecf20Sopenharmony_ci if (scsi_io_req->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) 42638c2ecf20Sopenharmony_ci result = RETURN_CMD; 42648c2ecf20Sopenharmony_ci 42658c2ecf20Sopenharmony_ci switch (result) { 42668c2ecf20Sopenharmony_ci case REFIRE_CMD: 42678c2ecf20Sopenharmony_ci megasas_fire_cmd_fusion(instance, req_desc); 42688c2ecf20Sopenharmony_ci break; 42698c2ecf20Sopenharmony_ci case RETURN_CMD: 42708c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd_mfi); 42718c2ecf20Sopenharmony_ci break; 42728c2ecf20Sopenharmony_ci case COMPLETE_CMD: 42738c2ecf20Sopenharmony_ci megasas_complete_cmd(instance, cmd_mfi, DID_OK); 42748c2ecf20Sopenharmony_ci break; 42758c2ecf20Sopenharmony_ci } 42768c2ecf20Sopenharmony_ci } 42778c2ecf20Sopenharmony_ci} 42788c2ecf20Sopenharmony_ci 42798c2ecf20Sopenharmony_ci/* 42808c2ecf20Sopenharmony_ci * megasas_return_polled_cmds: Return polled mode commands back to the pool 42818c2ecf20Sopenharmony_ci * before initiating an OCR. 42828c2ecf20Sopenharmony_ci * @instance: Controller's soft instance 42838c2ecf20Sopenharmony_ci */ 42848c2ecf20Sopenharmony_cistatic void 42858c2ecf20Sopenharmony_cimegasas_return_polled_cmds(struct megasas_instance *instance) 42868c2ecf20Sopenharmony_ci{ 42878c2ecf20Sopenharmony_ci int i; 42888c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd_fusion; 42898c2ecf20Sopenharmony_ci struct fusion_context *fusion; 42908c2ecf20Sopenharmony_ci struct megasas_cmd *cmd_mfi; 42918c2ecf20Sopenharmony_ci 42928c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 42938c2ecf20Sopenharmony_ci 42948c2ecf20Sopenharmony_ci for (i = instance->max_scsi_cmds; i < instance->max_fw_cmds; i++) { 42958c2ecf20Sopenharmony_ci cmd_fusion = fusion->cmd_list[i]; 42968c2ecf20Sopenharmony_ci cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx]; 42978c2ecf20Sopenharmony_ci 42988c2ecf20Sopenharmony_ci if (cmd_mfi->flags & DRV_DCMD_POLLED_MODE) { 42998c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & OCR_DEBUG) 43008c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 43018c2ecf20Sopenharmony_ci "%s %d return cmd 0x%x opcode 0x%x\n", 43028c2ecf20Sopenharmony_ci __func__, __LINE__, cmd_mfi->frame->hdr.cmd, 43038c2ecf20Sopenharmony_ci le32_to_cpu(cmd_mfi->frame->dcmd.opcode)); 43048c2ecf20Sopenharmony_ci cmd_mfi->flags &= ~DRV_DCMD_POLLED_MODE; 43058c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd_mfi); 43068c2ecf20Sopenharmony_ci } 43078c2ecf20Sopenharmony_ci } 43088c2ecf20Sopenharmony_ci} 43098c2ecf20Sopenharmony_ci 43108c2ecf20Sopenharmony_ci/* 43118c2ecf20Sopenharmony_ci * megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device 43128c2ecf20Sopenharmony_ci * @instance: per adapter struct 43138c2ecf20Sopenharmony_ci * @channel: the channel assigned by the OS 43148c2ecf20Sopenharmony_ci * @id: the id assigned by the OS 43158c2ecf20Sopenharmony_ci * 43168c2ecf20Sopenharmony_ci * Returns SUCCESS if no IOs pending to SCSI device, else return FAILED 43178c2ecf20Sopenharmony_ci */ 43188c2ecf20Sopenharmony_ci 43198c2ecf20Sopenharmony_cistatic int megasas_track_scsiio(struct megasas_instance *instance, 43208c2ecf20Sopenharmony_ci int id, int channel) 43218c2ecf20Sopenharmony_ci{ 43228c2ecf20Sopenharmony_ci int i, found = 0; 43238c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd_fusion; 43248c2ecf20Sopenharmony_ci struct fusion_context *fusion; 43258c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 43268c2ecf20Sopenharmony_ci 43278c2ecf20Sopenharmony_ci for (i = 0 ; i < instance->max_scsi_cmds; i++) { 43288c2ecf20Sopenharmony_ci cmd_fusion = fusion->cmd_list[i]; 43298c2ecf20Sopenharmony_ci if (cmd_fusion->scmd && 43308c2ecf20Sopenharmony_ci (cmd_fusion->scmd->device->id == id && 43318c2ecf20Sopenharmony_ci cmd_fusion->scmd->device->channel == channel)) { 43328c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 43338c2ecf20Sopenharmony_ci "SCSI commands pending to target" 43348c2ecf20Sopenharmony_ci "channel %d id %d \tSMID: 0x%x\n", 43358c2ecf20Sopenharmony_ci channel, id, cmd_fusion->index); 43368c2ecf20Sopenharmony_ci scsi_print_command(cmd_fusion->scmd); 43378c2ecf20Sopenharmony_ci found = 1; 43388c2ecf20Sopenharmony_ci break; 43398c2ecf20Sopenharmony_ci } 43408c2ecf20Sopenharmony_ci } 43418c2ecf20Sopenharmony_ci 43428c2ecf20Sopenharmony_ci return found ? FAILED : SUCCESS; 43438c2ecf20Sopenharmony_ci} 43448c2ecf20Sopenharmony_ci 43458c2ecf20Sopenharmony_ci/** 43468c2ecf20Sopenharmony_ci * megasas_tm_response_code - translation of device response code 43478c2ecf20Sopenharmony_ci * @instance: Controller's soft instance 43488c2ecf20Sopenharmony_ci * @mpi_reply: MPI reply returned by firmware 43498c2ecf20Sopenharmony_ci * 43508c2ecf20Sopenharmony_ci * Return nothing. 43518c2ecf20Sopenharmony_ci */ 43528c2ecf20Sopenharmony_cistatic void 43538c2ecf20Sopenharmony_cimegasas_tm_response_code(struct megasas_instance *instance, 43548c2ecf20Sopenharmony_ci struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply) 43558c2ecf20Sopenharmony_ci{ 43568c2ecf20Sopenharmony_ci char *desc; 43578c2ecf20Sopenharmony_ci 43588c2ecf20Sopenharmony_ci switch (mpi_reply->ResponseCode) { 43598c2ecf20Sopenharmony_ci case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: 43608c2ecf20Sopenharmony_ci desc = "task management request completed"; 43618c2ecf20Sopenharmony_ci break; 43628c2ecf20Sopenharmony_ci case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: 43638c2ecf20Sopenharmony_ci desc = "invalid frame"; 43648c2ecf20Sopenharmony_ci break; 43658c2ecf20Sopenharmony_ci case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: 43668c2ecf20Sopenharmony_ci desc = "task management request not supported"; 43678c2ecf20Sopenharmony_ci break; 43688c2ecf20Sopenharmony_ci case MPI2_SCSITASKMGMT_RSP_TM_FAILED: 43698c2ecf20Sopenharmony_ci desc = "task management request failed"; 43708c2ecf20Sopenharmony_ci break; 43718c2ecf20Sopenharmony_ci case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: 43728c2ecf20Sopenharmony_ci desc = "task management request succeeded"; 43738c2ecf20Sopenharmony_ci break; 43748c2ecf20Sopenharmony_ci case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: 43758c2ecf20Sopenharmony_ci desc = "invalid lun"; 43768c2ecf20Sopenharmony_ci break; 43778c2ecf20Sopenharmony_ci case 0xA: 43788c2ecf20Sopenharmony_ci desc = "overlapped tag attempted"; 43798c2ecf20Sopenharmony_ci break; 43808c2ecf20Sopenharmony_ci case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: 43818c2ecf20Sopenharmony_ci desc = "task queued, however not sent to target"; 43828c2ecf20Sopenharmony_ci break; 43838c2ecf20Sopenharmony_ci default: 43848c2ecf20Sopenharmony_ci desc = "unknown"; 43858c2ecf20Sopenharmony_ci break; 43868c2ecf20Sopenharmony_ci } 43878c2ecf20Sopenharmony_ci dev_dbg(&instance->pdev->dev, "response_code(%01x): %s\n", 43888c2ecf20Sopenharmony_ci mpi_reply->ResponseCode, desc); 43898c2ecf20Sopenharmony_ci dev_dbg(&instance->pdev->dev, 43908c2ecf20Sopenharmony_ci "TerminationCount/DevHandle/Function/TaskType/IOCStat/IOCLoginfo" 43918c2ecf20Sopenharmony_ci " 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n", 43928c2ecf20Sopenharmony_ci mpi_reply->TerminationCount, mpi_reply->DevHandle, 43938c2ecf20Sopenharmony_ci mpi_reply->Function, mpi_reply->TaskType, 43948c2ecf20Sopenharmony_ci mpi_reply->IOCStatus, mpi_reply->IOCLogInfo); 43958c2ecf20Sopenharmony_ci} 43968c2ecf20Sopenharmony_ci 43978c2ecf20Sopenharmony_ci/** 43988c2ecf20Sopenharmony_ci * megasas_issue_tm - main routine for sending tm requests 43998c2ecf20Sopenharmony_ci * @instance: per adapter struct 44008c2ecf20Sopenharmony_ci * @device_handle: device handle 44018c2ecf20Sopenharmony_ci * @channel: the channel assigned by the OS 44028c2ecf20Sopenharmony_ci * @id: the id assigned by the OS 44038c2ecf20Sopenharmony_ci * @smid_task: smid assigned to the task 44048c2ecf20Sopenharmony_ci * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in megaraid_sas_fusion.c) 44058c2ecf20Sopenharmony_ci * @mr_device_priv_data: private data 44068c2ecf20Sopenharmony_ci * Context: user 44078c2ecf20Sopenharmony_ci * 44088c2ecf20Sopenharmony_ci * MegaRaid use MPT interface for Task Magement request. 44098c2ecf20Sopenharmony_ci * A generic API for sending task management requests to firmware. 44108c2ecf20Sopenharmony_ci * 44118c2ecf20Sopenharmony_ci * Return SUCCESS or FAILED. 44128c2ecf20Sopenharmony_ci */ 44138c2ecf20Sopenharmony_cistatic int 44148c2ecf20Sopenharmony_cimegasas_issue_tm(struct megasas_instance *instance, u16 device_handle, 44158c2ecf20Sopenharmony_ci uint channel, uint id, u16 smid_task, u8 type, 44168c2ecf20Sopenharmony_ci struct MR_PRIV_DEVICE *mr_device_priv_data) 44178c2ecf20Sopenharmony_ci{ 44188c2ecf20Sopenharmony_ci struct MR_TASK_MANAGE_REQUEST *mr_request; 44198c2ecf20Sopenharmony_ci struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_request; 44208c2ecf20Sopenharmony_ci unsigned long timeleft; 44218c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd_fusion; 44228c2ecf20Sopenharmony_ci struct megasas_cmd *cmd_mfi; 44238c2ecf20Sopenharmony_ci union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; 44248c2ecf20Sopenharmony_ci struct fusion_context *fusion = NULL; 44258c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *scsi_lookup; 44268c2ecf20Sopenharmony_ci int rc; 44278c2ecf20Sopenharmony_ci int timeout = MEGASAS_DEFAULT_TM_TIMEOUT; 44288c2ecf20Sopenharmony_ci struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply; 44298c2ecf20Sopenharmony_ci 44308c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 44318c2ecf20Sopenharmony_ci 44328c2ecf20Sopenharmony_ci cmd_mfi = megasas_get_cmd(instance); 44338c2ecf20Sopenharmony_ci 44348c2ecf20Sopenharmony_ci if (!cmd_mfi) { 44358c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed from %s %d\n", 44368c2ecf20Sopenharmony_ci __func__, __LINE__); 44378c2ecf20Sopenharmony_ci return -ENOMEM; 44388c2ecf20Sopenharmony_ci } 44398c2ecf20Sopenharmony_ci 44408c2ecf20Sopenharmony_ci cmd_fusion = megasas_get_cmd_fusion(instance, 44418c2ecf20Sopenharmony_ci instance->max_scsi_cmds + cmd_mfi->index); 44428c2ecf20Sopenharmony_ci 44438c2ecf20Sopenharmony_ci /* Save the smid. To be used for returning the cmd */ 44448c2ecf20Sopenharmony_ci cmd_mfi->context.smid = cmd_fusion->index; 44458c2ecf20Sopenharmony_ci 44468c2ecf20Sopenharmony_ci req_desc = megasas_get_request_descriptor(instance, 44478c2ecf20Sopenharmony_ci (cmd_fusion->index - 1)); 44488c2ecf20Sopenharmony_ci 44498c2ecf20Sopenharmony_ci cmd_fusion->request_desc = req_desc; 44508c2ecf20Sopenharmony_ci req_desc->Words = 0; 44518c2ecf20Sopenharmony_ci 44528c2ecf20Sopenharmony_ci mr_request = (struct MR_TASK_MANAGE_REQUEST *) cmd_fusion->io_request; 44538c2ecf20Sopenharmony_ci memset(mr_request, 0, sizeof(struct MR_TASK_MANAGE_REQUEST)); 44548c2ecf20Sopenharmony_ci mpi_request = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *) &mr_request->TmRequest; 44558c2ecf20Sopenharmony_ci mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 44568c2ecf20Sopenharmony_ci mpi_request->DevHandle = cpu_to_le16(device_handle); 44578c2ecf20Sopenharmony_ci mpi_request->TaskType = type; 44588c2ecf20Sopenharmony_ci mpi_request->TaskMID = cpu_to_le16(smid_task); 44598c2ecf20Sopenharmony_ci mpi_request->LUN[1] = 0; 44608c2ecf20Sopenharmony_ci 44618c2ecf20Sopenharmony_ci 44628c2ecf20Sopenharmony_ci req_desc = cmd_fusion->request_desc; 44638c2ecf20Sopenharmony_ci req_desc->HighPriority.SMID = cpu_to_le16(cmd_fusion->index); 44648c2ecf20Sopenharmony_ci req_desc->HighPriority.RequestFlags = 44658c2ecf20Sopenharmony_ci (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << 44668c2ecf20Sopenharmony_ci MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 44678c2ecf20Sopenharmony_ci req_desc->HighPriority.MSIxIndex = 0; 44688c2ecf20Sopenharmony_ci req_desc->HighPriority.LMID = 0; 44698c2ecf20Sopenharmony_ci req_desc->HighPriority.Reserved1 = 0; 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_ci if (channel < MEGASAS_MAX_PD_CHANNELS) 44728c2ecf20Sopenharmony_ci mr_request->tmReqFlags.isTMForPD = 1; 44738c2ecf20Sopenharmony_ci else 44748c2ecf20Sopenharmony_ci mr_request->tmReqFlags.isTMForLD = 1; 44758c2ecf20Sopenharmony_ci 44768c2ecf20Sopenharmony_ci init_completion(&cmd_fusion->done); 44778c2ecf20Sopenharmony_ci megasas_fire_cmd_fusion(instance, req_desc); 44788c2ecf20Sopenharmony_ci 44798c2ecf20Sopenharmony_ci switch (type) { 44808c2ecf20Sopenharmony_ci case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: 44818c2ecf20Sopenharmony_ci timeout = mr_device_priv_data->task_abort_tmo; 44828c2ecf20Sopenharmony_ci break; 44838c2ecf20Sopenharmony_ci case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: 44848c2ecf20Sopenharmony_ci timeout = mr_device_priv_data->target_reset_tmo; 44858c2ecf20Sopenharmony_ci break; 44868c2ecf20Sopenharmony_ci } 44878c2ecf20Sopenharmony_ci 44888c2ecf20Sopenharmony_ci timeleft = wait_for_completion_timeout(&cmd_fusion->done, timeout * HZ); 44898c2ecf20Sopenharmony_ci 44908c2ecf20Sopenharmony_ci if (!timeleft) { 44918c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, 44928c2ecf20Sopenharmony_ci "task mgmt type 0x%x timed out\n", type); 44938c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 44948c2ecf20Sopenharmony_ci rc = megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR); 44958c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 44968c2ecf20Sopenharmony_ci return rc; 44978c2ecf20Sopenharmony_ci } 44988c2ecf20Sopenharmony_ci 44998c2ecf20Sopenharmony_ci mpi_reply = (struct MPI2_SCSI_TASK_MANAGE_REPLY *) &mr_request->TMReply; 45008c2ecf20Sopenharmony_ci megasas_tm_response_code(instance, mpi_reply); 45018c2ecf20Sopenharmony_ci 45028c2ecf20Sopenharmony_ci megasas_return_cmd(instance, cmd_mfi); 45038c2ecf20Sopenharmony_ci rc = SUCCESS; 45048c2ecf20Sopenharmony_ci switch (type) { 45058c2ecf20Sopenharmony_ci case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: 45068c2ecf20Sopenharmony_ci scsi_lookup = fusion->cmd_list[smid_task - 1]; 45078c2ecf20Sopenharmony_ci 45088c2ecf20Sopenharmony_ci if (scsi_lookup->scmd == NULL) 45098c2ecf20Sopenharmony_ci break; 45108c2ecf20Sopenharmony_ci else { 45118c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 45128c2ecf20Sopenharmony_ci megasas_sync_irqs((unsigned long)instance); 45138c2ecf20Sopenharmony_ci instance->instancet->enable_intr(instance); 45148c2ecf20Sopenharmony_ci megasas_enable_irq_poll(instance); 45158c2ecf20Sopenharmony_ci if (scsi_lookup->scmd == NULL) 45168c2ecf20Sopenharmony_ci break; 45178c2ecf20Sopenharmony_ci } 45188c2ecf20Sopenharmony_ci rc = FAILED; 45198c2ecf20Sopenharmony_ci break; 45208c2ecf20Sopenharmony_ci 45218c2ecf20Sopenharmony_ci case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: 45228c2ecf20Sopenharmony_ci if ((channel == 0xFFFFFFFF) && (id == 0xFFFFFFFF)) 45238c2ecf20Sopenharmony_ci break; 45248c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 45258c2ecf20Sopenharmony_ci megasas_sync_irqs((unsigned long)instance); 45268c2ecf20Sopenharmony_ci rc = megasas_track_scsiio(instance, id, channel); 45278c2ecf20Sopenharmony_ci instance->instancet->enable_intr(instance); 45288c2ecf20Sopenharmony_ci megasas_enable_irq_poll(instance); 45298c2ecf20Sopenharmony_ci 45308c2ecf20Sopenharmony_ci break; 45318c2ecf20Sopenharmony_ci case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: 45328c2ecf20Sopenharmony_ci case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK: 45338c2ecf20Sopenharmony_ci break; 45348c2ecf20Sopenharmony_ci default: 45358c2ecf20Sopenharmony_ci rc = FAILED; 45368c2ecf20Sopenharmony_ci break; 45378c2ecf20Sopenharmony_ci } 45388c2ecf20Sopenharmony_ci 45398c2ecf20Sopenharmony_ci return rc; 45408c2ecf20Sopenharmony_ci 45418c2ecf20Sopenharmony_ci} 45428c2ecf20Sopenharmony_ci 45438c2ecf20Sopenharmony_ci/* 45448c2ecf20Sopenharmony_ci * megasas_fusion_smid_lookup : Look for fusion command correpspodning to SCSI 45458c2ecf20Sopenharmony_ci * @instance: per adapter struct 45468c2ecf20Sopenharmony_ci * 45478c2ecf20Sopenharmony_ci * Return Non Zero index, if SMID found in outstanding commands 45488c2ecf20Sopenharmony_ci */ 45498c2ecf20Sopenharmony_cistatic u16 megasas_fusion_smid_lookup(struct scsi_cmnd *scmd) 45508c2ecf20Sopenharmony_ci{ 45518c2ecf20Sopenharmony_ci int i, ret = 0; 45528c2ecf20Sopenharmony_ci struct megasas_instance *instance; 45538c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd_fusion; 45548c2ecf20Sopenharmony_ci struct fusion_context *fusion; 45558c2ecf20Sopenharmony_ci 45568c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)scmd->device->host->hostdata; 45578c2ecf20Sopenharmony_ci 45588c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 45598c2ecf20Sopenharmony_ci 45608c2ecf20Sopenharmony_ci for (i = 0; i < instance->max_scsi_cmds; i++) { 45618c2ecf20Sopenharmony_ci cmd_fusion = fusion->cmd_list[i]; 45628c2ecf20Sopenharmony_ci if (cmd_fusion->scmd && (cmd_fusion->scmd == scmd)) { 45638c2ecf20Sopenharmony_ci scmd_printk(KERN_NOTICE, scmd, "Abort request is for" 45648c2ecf20Sopenharmony_ci " SMID: %d\n", cmd_fusion->index); 45658c2ecf20Sopenharmony_ci ret = cmd_fusion->index; 45668c2ecf20Sopenharmony_ci break; 45678c2ecf20Sopenharmony_ci } 45688c2ecf20Sopenharmony_ci } 45698c2ecf20Sopenharmony_ci 45708c2ecf20Sopenharmony_ci return ret; 45718c2ecf20Sopenharmony_ci} 45728c2ecf20Sopenharmony_ci 45738c2ecf20Sopenharmony_ci/* 45748c2ecf20Sopenharmony_ci* megasas_get_tm_devhandle - Get devhandle for TM request 45758c2ecf20Sopenharmony_ci* @sdev- OS provided scsi device 45768c2ecf20Sopenharmony_ci* 45778c2ecf20Sopenharmony_ci* Returns- devhandle/targetID of SCSI device 45788c2ecf20Sopenharmony_ci*/ 45798c2ecf20Sopenharmony_cistatic u16 megasas_get_tm_devhandle(struct scsi_device *sdev) 45808c2ecf20Sopenharmony_ci{ 45818c2ecf20Sopenharmony_ci u16 pd_index = 0; 45828c2ecf20Sopenharmony_ci u32 device_id; 45838c2ecf20Sopenharmony_ci struct megasas_instance *instance; 45848c2ecf20Sopenharmony_ci struct fusion_context *fusion; 45858c2ecf20Sopenharmony_ci struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; 45868c2ecf20Sopenharmony_ci u16 devhandle = (u16)ULONG_MAX; 45878c2ecf20Sopenharmony_ci 45888c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)sdev->host->hostdata; 45898c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 45908c2ecf20Sopenharmony_ci 45918c2ecf20Sopenharmony_ci if (!MEGASAS_IS_LOGICAL(sdev)) { 45928c2ecf20Sopenharmony_ci if (instance->use_seqnum_jbod_fp) { 45938c2ecf20Sopenharmony_ci pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) 45948c2ecf20Sopenharmony_ci + sdev->id; 45958c2ecf20Sopenharmony_ci pd_sync = (void *)fusion->pd_seq_sync 45968c2ecf20Sopenharmony_ci [(instance->pd_seq_map_id - 1) & 1]; 45978c2ecf20Sopenharmony_ci devhandle = pd_sync->seq[pd_index].devHandle; 45988c2ecf20Sopenharmony_ci } else 45998c2ecf20Sopenharmony_ci sdev_printk(KERN_ERR, sdev, "Firmware expose tmCapable" 46008c2ecf20Sopenharmony_ci " without JBOD MAP support from %s %d\n", __func__, __LINE__); 46018c2ecf20Sopenharmony_ci } else { 46028c2ecf20Sopenharmony_ci device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) 46038c2ecf20Sopenharmony_ci + sdev->id; 46048c2ecf20Sopenharmony_ci devhandle = device_id; 46058c2ecf20Sopenharmony_ci } 46068c2ecf20Sopenharmony_ci 46078c2ecf20Sopenharmony_ci return devhandle; 46088c2ecf20Sopenharmony_ci} 46098c2ecf20Sopenharmony_ci 46108c2ecf20Sopenharmony_ci/* 46118c2ecf20Sopenharmony_ci * megasas_task_abort_fusion : SCSI task abort function for fusion adapters 46128c2ecf20Sopenharmony_ci * @scmd : pointer to scsi command object 46138c2ecf20Sopenharmony_ci * 46148c2ecf20Sopenharmony_ci * Return SUCCESS, if command aborted else FAILED 46158c2ecf20Sopenharmony_ci */ 46168c2ecf20Sopenharmony_ci 46178c2ecf20Sopenharmony_ciint megasas_task_abort_fusion(struct scsi_cmnd *scmd) 46188c2ecf20Sopenharmony_ci{ 46198c2ecf20Sopenharmony_ci struct megasas_instance *instance; 46208c2ecf20Sopenharmony_ci u16 smid, devhandle; 46218c2ecf20Sopenharmony_ci int ret; 46228c2ecf20Sopenharmony_ci struct MR_PRIV_DEVICE *mr_device_priv_data; 46238c2ecf20Sopenharmony_ci mr_device_priv_data = scmd->device->hostdata; 46248c2ecf20Sopenharmony_ci 46258c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)scmd->device->host->hostdata; 46268c2ecf20Sopenharmony_ci 46278c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) { 46288c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL," 46298c2ecf20Sopenharmony_ci "SCSI host:%d\n", instance->host->host_no); 46308c2ecf20Sopenharmony_ci ret = FAILED; 46318c2ecf20Sopenharmony_ci return ret; 46328c2ecf20Sopenharmony_ci } 46338c2ecf20Sopenharmony_ci 46348c2ecf20Sopenharmony_ci if (!mr_device_priv_data) { 46358c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, "device been deleted! " 46368c2ecf20Sopenharmony_ci "scmd(%p)\n", scmd); 46378c2ecf20Sopenharmony_ci scmd->result = DID_NO_CONNECT << 16; 46388c2ecf20Sopenharmony_ci ret = SUCCESS; 46398c2ecf20Sopenharmony_ci goto out; 46408c2ecf20Sopenharmony_ci } 46418c2ecf20Sopenharmony_ci 46428c2ecf20Sopenharmony_ci if (!mr_device_priv_data->is_tm_capable) { 46438c2ecf20Sopenharmony_ci ret = FAILED; 46448c2ecf20Sopenharmony_ci goto out; 46458c2ecf20Sopenharmony_ci } 46468c2ecf20Sopenharmony_ci 46478c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 46488c2ecf20Sopenharmony_ci 46498c2ecf20Sopenharmony_ci smid = megasas_fusion_smid_lookup(scmd); 46508c2ecf20Sopenharmony_ci 46518c2ecf20Sopenharmony_ci if (!smid) { 46528c2ecf20Sopenharmony_ci ret = SUCCESS; 46538c2ecf20Sopenharmony_ci scmd_printk(KERN_NOTICE, scmd, "Command for which abort is" 46548c2ecf20Sopenharmony_ci " issued is not found in outstanding commands\n"); 46558c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 46568c2ecf20Sopenharmony_ci goto out; 46578c2ecf20Sopenharmony_ci } 46588c2ecf20Sopenharmony_ci 46598c2ecf20Sopenharmony_ci devhandle = megasas_get_tm_devhandle(scmd->device); 46608c2ecf20Sopenharmony_ci 46618c2ecf20Sopenharmony_ci if (devhandle == (u16)ULONG_MAX) { 46628c2ecf20Sopenharmony_ci ret = FAILED; 46638c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 46648c2ecf20Sopenharmony_ci "task abort issued for invalid devhandle\n"); 46658c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 46668c2ecf20Sopenharmony_ci goto out; 46678c2ecf20Sopenharmony_ci } 46688c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 46698c2ecf20Sopenharmony_ci "attempting task abort! scmd(0x%p) tm_dev_handle 0x%x\n", 46708c2ecf20Sopenharmony_ci scmd, devhandle); 46718c2ecf20Sopenharmony_ci 46728c2ecf20Sopenharmony_ci mr_device_priv_data->tm_busy = true; 46738c2ecf20Sopenharmony_ci ret = megasas_issue_tm(instance, devhandle, 46748c2ecf20Sopenharmony_ci scmd->device->channel, scmd->device->id, smid, 46758c2ecf20Sopenharmony_ci MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, 46768c2ecf20Sopenharmony_ci mr_device_priv_data); 46778c2ecf20Sopenharmony_ci mr_device_priv_data->tm_busy = false; 46788c2ecf20Sopenharmony_ci 46798c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 46808c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, scmd, "task abort %s!! scmd(0x%p)\n", 46818c2ecf20Sopenharmony_ci ((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); 46828c2ecf20Sopenharmony_ciout: 46838c2ecf20Sopenharmony_ci scsi_print_command(scmd); 46848c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & TM_DEBUG) 46858c2ecf20Sopenharmony_ci megasas_dump_fusion_io(scmd); 46868c2ecf20Sopenharmony_ci 46878c2ecf20Sopenharmony_ci return ret; 46888c2ecf20Sopenharmony_ci} 46898c2ecf20Sopenharmony_ci 46908c2ecf20Sopenharmony_ci/* 46918c2ecf20Sopenharmony_ci * megasas_reset_target_fusion : target reset function for fusion adapters 46928c2ecf20Sopenharmony_ci * scmd: SCSI command pointer 46938c2ecf20Sopenharmony_ci * 46948c2ecf20Sopenharmony_ci * Returns SUCCESS if all commands associated with target aborted else FAILED 46958c2ecf20Sopenharmony_ci */ 46968c2ecf20Sopenharmony_ci 46978c2ecf20Sopenharmony_ciint megasas_reset_target_fusion(struct scsi_cmnd *scmd) 46988c2ecf20Sopenharmony_ci{ 46998c2ecf20Sopenharmony_ci 47008c2ecf20Sopenharmony_ci struct megasas_instance *instance; 47018c2ecf20Sopenharmony_ci int ret = FAILED; 47028c2ecf20Sopenharmony_ci u16 devhandle; 47038c2ecf20Sopenharmony_ci struct MR_PRIV_DEVICE *mr_device_priv_data; 47048c2ecf20Sopenharmony_ci mr_device_priv_data = scmd->device->hostdata; 47058c2ecf20Sopenharmony_ci 47068c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)scmd->device->host->hostdata; 47078c2ecf20Sopenharmony_ci 47088c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) { 47098c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL," 47108c2ecf20Sopenharmony_ci "SCSI host:%d\n", instance->host->host_no); 47118c2ecf20Sopenharmony_ci ret = FAILED; 47128c2ecf20Sopenharmony_ci return ret; 47138c2ecf20Sopenharmony_ci } 47148c2ecf20Sopenharmony_ci 47158c2ecf20Sopenharmony_ci if (!mr_device_priv_data) { 47168c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 47178c2ecf20Sopenharmony_ci "device been deleted! scmd: (0x%p)\n", scmd); 47188c2ecf20Sopenharmony_ci scmd->result = DID_NO_CONNECT << 16; 47198c2ecf20Sopenharmony_ci ret = SUCCESS; 47208c2ecf20Sopenharmony_ci goto out; 47218c2ecf20Sopenharmony_ci } 47228c2ecf20Sopenharmony_ci 47238c2ecf20Sopenharmony_ci if (!mr_device_priv_data->is_tm_capable) { 47248c2ecf20Sopenharmony_ci ret = FAILED; 47258c2ecf20Sopenharmony_ci goto out; 47268c2ecf20Sopenharmony_ci } 47278c2ecf20Sopenharmony_ci 47288c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 47298c2ecf20Sopenharmony_ci devhandle = megasas_get_tm_devhandle(scmd->device); 47308c2ecf20Sopenharmony_ci 47318c2ecf20Sopenharmony_ci if (devhandle == (u16)ULONG_MAX) { 47328c2ecf20Sopenharmony_ci ret = FAILED; 47338c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 47348c2ecf20Sopenharmony_ci "target reset issued for invalid devhandle\n"); 47358c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 47368c2ecf20Sopenharmony_ci goto out; 47378c2ecf20Sopenharmony_ci } 47388c2ecf20Sopenharmony_ci 47398c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 47408c2ecf20Sopenharmony_ci "attempting target reset! scmd(0x%p) tm_dev_handle: 0x%x\n", 47418c2ecf20Sopenharmony_ci scmd, devhandle); 47428c2ecf20Sopenharmony_ci mr_device_priv_data->tm_busy = true; 47438c2ecf20Sopenharmony_ci ret = megasas_issue_tm(instance, devhandle, 47448c2ecf20Sopenharmony_ci scmd->device->channel, scmd->device->id, 0, 47458c2ecf20Sopenharmony_ci MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 47468c2ecf20Sopenharmony_ci mr_device_priv_data); 47478c2ecf20Sopenharmony_ci mr_device_priv_data->tm_busy = false; 47488c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 47498c2ecf20Sopenharmony_ci scmd_printk(KERN_NOTICE, scmd, "target reset %s!!\n", 47508c2ecf20Sopenharmony_ci (ret == SUCCESS) ? "SUCCESS" : "FAILED"); 47518c2ecf20Sopenharmony_ci 47528c2ecf20Sopenharmony_ciout: 47538c2ecf20Sopenharmony_ci return ret; 47548c2ecf20Sopenharmony_ci} 47558c2ecf20Sopenharmony_ci 47568c2ecf20Sopenharmony_ci/*SRIOV get other instance in cluster if any*/ 47578c2ecf20Sopenharmony_cistatic struct 47588c2ecf20Sopenharmony_cimegasas_instance *megasas_get_peer_instance(struct megasas_instance *instance) 47598c2ecf20Sopenharmony_ci{ 47608c2ecf20Sopenharmony_ci int i; 47618c2ecf20Sopenharmony_ci 47628c2ecf20Sopenharmony_ci for (i = 0; i < MAX_MGMT_ADAPTERS; i++) { 47638c2ecf20Sopenharmony_ci if (megasas_mgmt_info.instance[i] && 47648c2ecf20Sopenharmony_ci (megasas_mgmt_info.instance[i] != instance) && 47658c2ecf20Sopenharmony_ci megasas_mgmt_info.instance[i]->requestorId && 47668c2ecf20Sopenharmony_ci megasas_mgmt_info.instance[i]->peerIsPresent && 47678c2ecf20Sopenharmony_ci (memcmp((megasas_mgmt_info.instance[i]->clusterId), 47688c2ecf20Sopenharmony_ci instance->clusterId, MEGASAS_CLUSTER_ID_SIZE) == 0)) 47698c2ecf20Sopenharmony_ci return megasas_mgmt_info.instance[i]; 47708c2ecf20Sopenharmony_ci } 47718c2ecf20Sopenharmony_ci return NULL; 47728c2ecf20Sopenharmony_ci} 47738c2ecf20Sopenharmony_ci 47748c2ecf20Sopenharmony_ci/* Check for a second path that is currently UP */ 47758c2ecf20Sopenharmony_ciint megasas_check_mpio_paths(struct megasas_instance *instance, 47768c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd) 47778c2ecf20Sopenharmony_ci{ 47788c2ecf20Sopenharmony_ci struct megasas_instance *peer_instance = NULL; 47798c2ecf20Sopenharmony_ci int retval = (DID_REQUEUE << 16); 47808c2ecf20Sopenharmony_ci 47818c2ecf20Sopenharmony_ci if (instance->peerIsPresent) { 47828c2ecf20Sopenharmony_ci peer_instance = megasas_get_peer_instance(instance); 47838c2ecf20Sopenharmony_ci if ((peer_instance) && 47848c2ecf20Sopenharmony_ci (atomic_read(&peer_instance->adprecovery) == 47858c2ecf20Sopenharmony_ci MEGASAS_HBA_OPERATIONAL)) 47868c2ecf20Sopenharmony_ci retval = (DID_NO_CONNECT << 16); 47878c2ecf20Sopenharmony_ci } 47888c2ecf20Sopenharmony_ci return retval; 47898c2ecf20Sopenharmony_ci} 47908c2ecf20Sopenharmony_ci 47918c2ecf20Sopenharmony_ci/* Core fusion reset function */ 47928c2ecf20Sopenharmony_ciint megasas_reset_fusion(struct Scsi_Host *shost, int reason) 47938c2ecf20Sopenharmony_ci{ 47948c2ecf20Sopenharmony_ci int retval = SUCCESS, i, j, convert = 0; 47958c2ecf20Sopenharmony_ci struct megasas_instance *instance; 47968c2ecf20Sopenharmony_ci struct megasas_cmd_fusion *cmd_fusion, *r1_cmd; 47978c2ecf20Sopenharmony_ci struct fusion_context *fusion; 47988c2ecf20Sopenharmony_ci u32 abs_state, status_reg, reset_adapter, fpio_count = 0; 47998c2ecf20Sopenharmony_ci u32 io_timeout_in_crash_mode = 0; 48008c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd_local = NULL; 48018c2ecf20Sopenharmony_ci struct scsi_device *sdev; 48028c2ecf20Sopenharmony_ci int ret_target_prop = DCMD_FAILED; 48038c2ecf20Sopenharmony_ci bool is_target_prop = false; 48048c2ecf20Sopenharmony_ci bool do_adp_reset = true; 48058c2ecf20Sopenharmony_ci int max_reset_tries = MEGASAS_FUSION_MAX_RESET_TRIES; 48068c2ecf20Sopenharmony_ci 48078c2ecf20Sopenharmony_ci instance = (struct megasas_instance *)shost->hostdata; 48088c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 48098c2ecf20Sopenharmony_ci 48108c2ecf20Sopenharmony_ci mutex_lock(&instance->reset_mutex); 48118c2ecf20Sopenharmony_ci 48128c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) { 48138c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "Hardware critical error, " 48148c2ecf20Sopenharmony_ci "returning FAILED for scsi%d.\n", 48158c2ecf20Sopenharmony_ci instance->host->host_no); 48168c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 48178c2ecf20Sopenharmony_ci return FAILED; 48188c2ecf20Sopenharmony_ci } 48198c2ecf20Sopenharmony_ci status_reg = instance->instancet->read_fw_status_reg(instance); 48208c2ecf20Sopenharmony_ci abs_state = status_reg & MFI_STATE_MASK; 48218c2ecf20Sopenharmony_ci 48228c2ecf20Sopenharmony_ci /* IO timeout detected, forcibly put FW in FAULT state */ 48238c2ecf20Sopenharmony_ci if (abs_state != MFI_STATE_FAULT && instance->crash_dump_buf && 48248c2ecf20Sopenharmony_ci instance->crash_dump_app_support && reason) { 48258c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "IO/DCMD timeout is detected, " 48268c2ecf20Sopenharmony_ci "forcibly FAULT Firmware\n"); 48278c2ecf20Sopenharmony_ci atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT); 48288c2ecf20Sopenharmony_ci status_reg = megasas_readl(instance, &instance->reg_set->doorbell); 48298c2ecf20Sopenharmony_ci writel(status_reg | MFI_STATE_FORCE_OCR, 48308c2ecf20Sopenharmony_ci &instance->reg_set->doorbell); 48318c2ecf20Sopenharmony_ci readl(&instance->reg_set->doorbell); 48328c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 48338c2ecf20Sopenharmony_ci do { 48348c2ecf20Sopenharmony_ci ssleep(3); 48358c2ecf20Sopenharmony_ci io_timeout_in_crash_mode++; 48368c2ecf20Sopenharmony_ci dev_dbg(&instance->pdev->dev, "waiting for [%d] " 48378c2ecf20Sopenharmony_ci "seconds for crash dump collection and OCR " 48388c2ecf20Sopenharmony_ci "to be done\n", (io_timeout_in_crash_mode * 3)); 48398c2ecf20Sopenharmony_ci } while ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) && 48408c2ecf20Sopenharmony_ci (io_timeout_in_crash_mode < 80)); 48418c2ecf20Sopenharmony_ci 48428c2ecf20Sopenharmony_ci if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) { 48438c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "OCR done for IO " 48448c2ecf20Sopenharmony_ci "timeout case\n"); 48458c2ecf20Sopenharmony_ci retval = SUCCESS; 48468c2ecf20Sopenharmony_ci } else { 48478c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Controller is not " 48488c2ecf20Sopenharmony_ci "operational after 240 seconds wait for IO " 48498c2ecf20Sopenharmony_ci "timeout case in FW crash dump mode\n do " 48508c2ecf20Sopenharmony_ci "OCR/kill adapter\n"); 48518c2ecf20Sopenharmony_ci retval = megasas_reset_fusion(shost, 0); 48528c2ecf20Sopenharmony_ci } 48538c2ecf20Sopenharmony_ci return retval; 48548c2ecf20Sopenharmony_ci } 48558c2ecf20Sopenharmony_ci 48568c2ecf20Sopenharmony_ci if (instance->requestorId && !instance->skip_heartbeat_timer_del) 48578c2ecf20Sopenharmony_ci del_timer_sync(&instance->sriov_heartbeat_timer); 48588c2ecf20Sopenharmony_ci set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); 48598c2ecf20Sopenharmony_ci set_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE, &instance->reset_flags); 48608c2ecf20Sopenharmony_ci atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_POLLING); 48618c2ecf20Sopenharmony_ci instance->instancet->disable_intr(instance); 48628c2ecf20Sopenharmony_ci megasas_sync_irqs((unsigned long)instance); 48638c2ecf20Sopenharmony_ci 48648c2ecf20Sopenharmony_ci /* First try waiting for commands to complete */ 48658c2ecf20Sopenharmony_ci if (megasas_wait_for_outstanding_fusion(instance, reason, 48668c2ecf20Sopenharmony_ci &convert)) { 48678c2ecf20Sopenharmony_ci atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT); 48688c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "resetting fusion " 48698c2ecf20Sopenharmony_ci "adapter scsi%d.\n", instance->host->host_no); 48708c2ecf20Sopenharmony_ci if (convert) 48718c2ecf20Sopenharmony_ci reason = 0; 48728c2ecf20Sopenharmony_ci 48738c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & OCR_DEBUG) 48748c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "\nPending SCSI commands:\n"); 48758c2ecf20Sopenharmony_ci 48768c2ecf20Sopenharmony_ci /* Now return commands back to the OS */ 48778c2ecf20Sopenharmony_ci for (i = 0 ; i < instance->max_scsi_cmds; i++) { 48788c2ecf20Sopenharmony_ci cmd_fusion = fusion->cmd_list[i]; 48798c2ecf20Sopenharmony_ci /*check for extra commands issued by driver*/ 48808c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) { 48818c2ecf20Sopenharmony_ci r1_cmd = fusion->cmd_list[i + instance->max_fw_cmds]; 48828c2ecf20Sopenharmony_ci megasas_return_cmd_fusion(instance, r1_cmd); 48838c2ecf20Sopenharmony_ci } 48848c2ecf20Sopenharmony_ci scmd_local = cmd_fusion->scmd; 48858c2ecf20Sopenharmony_ci if (cmd_fusion->scmd) { 48868c2ecf20Sopenharmony_ci if (megasas_dbg_lvl & OCR_DEBUG) { 48878c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, 48888c2ecf20Sopenharmony_ci cmd_fusion->scmd->device, "SMID: 0x%x\n", 48898c2ecf20Sopenharmony_ci cmd_fusion->index); 48908c2ecf20Sopenharmony_ci megasas_dump_fusion_io(cmd_fusion->scmd); 48918c2ecf20Sopenharmony_ci } 48928c2ecf20Sopenharmony_ci 48938c2ecf20Sopenharmony_ci if (cmd_fusion->io_request->Function == 48948c2ecf20Sopenharmony_ci MPI2_FUNCTION_SCSI_IO_REQUEST) 48958c2ecf20Sopenharmony_ci fpio_count++; 48968c2ecf20Sopenharmony_ci 48978c2ecf20Sopenharmony_ci scmd_local->result = 48988c2ecf20Sopenharmony_ci megasas_check_mpio_paths(instance, 48998c2ecf20Sopenharmony_ci scmd_local); 49008c2ecf20Sopenharmony_ci if (instance->ldio_threshold && 49018c2ecf20Sopenharmony_ci megasas_cmd_type(scmd_local) == READ_WRITE_LDIO) 49028c2ecf20Sopenharmony_ci atomic_dec(&instance->ldio_outstanding); 49038c2ecf20Sopenharmony_ci megasas_return_cmd_fusion(instance, cmd_fusion); 49048c2ecf20Sopenharmony_ci scsi_dma_unmap(scmd_local); 49058c2ecf20Sopenharmony_ci scmd_local->scsi_done(scmd_local); 49068c2ecf20Sopenharmony_ci } 49078c2ecf20Sopenharmony_ci } 49088c2ecf20Sopenharmony_ci 49098c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Outstanding fastpath IOs: %d\n", 49108c2ecf20Sopenharmony_ci fpio_count); 49118c2ecf20Sopenharmony_ci 49128c2ecf20Sopenharmony_ci atomic_set(&instance->fw_outstanding, 0); 49138c2ecf20Sopenharmony_ci 49148c2ecf20Sopenharmony_ci status_reg = instance->instancet->read_fw_status_reg(instance); 49158c2ecf20Sopenharmony_ci abs_state = status_reg & MFI_STATE_MASK; 49168c2ecf20Sopenharmony_ci reset_adapter = status_reg & MFI_RESET_ADAPTER; 49178c2ecf20Sopenharmony_ci if (instance->disableOnlineCtrlReset || 49188c2ecf20Sopenharmony_ci (abs_state == MFI_STATE_FAULT && !reset_adapter)) { 49198c2ecf20Sopenharmony_ci /* Reset not supported, kill adapter */ 49208c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "Reset not supported" 49218c2ecf20Sopenharmony_ci ", killing adapter scsi%d.\n", 49228c2ecf20Sopenharmony_ci instance->host->host_no); 49238c2ecf20Sopenharmony_ci goto kill_hba; 49248c2ecf20Sopenharmony_ci } 49258c2ecf20Sopenharmony_ci 49268c2ecf20Sopenharmony_ci /* Let SR-IOV VF & PF sync up if there was a HB failure */ 49278c2ecf20Sopenharmony_ci if (instance->requestorId && !reason) { 49288c2ecf20Sopenharmony_ci msleep(MEGASAS_OCR_SETTLE_TIME_VF); 49298c2ecf20Sopenharmony_ci do_adp_reset = false; 49308c2ecf20Sopenharmony_ci max_reset_tries = MEGASAS_SRIOV_MAX_RESET_TRIES_VF; 49318c2ecf20Sopenharmony_ci } 49328c2ecf20Sopenharmony_ci 49338c2ecf20Sopenharmony_ci /* Now try to reset the chip */ 49348c2ecf20Sopenharmony_ci for (i = 0; i < max_reset_tries; i++) { 49358c2ecf20Sopenharmony_ci /* 49368c2ecf20Sopenharmony_ci * Do adp reset and wait for 49378c2ecf20Sopenharmony_ci * controller to transition to ready 49388c2ecf20Sopenharmony_ci */ 49398c2ecf20Sopenharmony_ci if (megasas_adp_reset_wait_for_ready(instance, 49408c2ecf20Sopenharmony_ci do_adp_reset, 1) == FAILED) 49418c2ecf20Sopenharmony_ci continue; 49428c2ecf20Sopenharmony_ci 49438c2ecf20Sopenharmony_ci /* Wait for FW to become ready */ 49448c2ecf20Sopenharmony_ci if (megasas_transition_to_ready(instance, 1)) { 49458c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, 49468c2ecf20Sopenharmony_ci "Failed to transition controller to ready for " 49478c2ecf20Sopenharmony_ci "scsi%d.\n", instance->host->host_no); 49488c2ecf20Sopenharmony_ci continue; 49498c2ecf20Sopenharmony_ci } 49508c2ecf20Sopenharmony_ci megasas_reset_reply_desc(instance); 49518c2ecf20Sopenharmony_ci megasas_fusion_update_can_queue(instance, OCR_CONTEXT); 49528c2ecf20Sopenharmony_ci 49538c2ecf20Sopenharmony_ci if (megasas_ioc_init_fusion(instance)) { 49548c2ecf20Sopenharmony_ci continue; 49558c2ecf20Sopenharmony_ci } 49568c2ecf20Sopenharmony_ci 49578c2ecf20Sopenharmony_ci if (megasas_get_ctrl_info(instance)) { 49588c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 49598c2ecf20Sopenharmony_ci "Failed from %s %d\n", 49608c2ecf20Sopenharmony_ci __func__, __LINE__); 49618c2ecf20Sopenharmony_ci goto kill_hba; 49628c2ecf20Sopenharmony_ci } 49638c2ecf20Sopenharmony_ci 49648c2ecf20Sopenharmony_ci megasas_refire_mgmt_cmd(instance, 49658c2ecf20Sopenharmony_ci (i == (MEGASAS_FUSION_MAX_RESET_TRIES - 1) 49668c2ecf20Sopenharmony_ci ? 1 : 0)); 49678c2ecf20Sopenharmony_ci 49688c2ecf20Sopenharmony_ci /* Reset load balance info */ 49698c2ecf20Sopenharmony_ci if (fusion->load_balance_info) 49708c2ecf20Sopenharmony_ci memset(fusion->load_balance_info, 0, 49718c2ecf20Sopenharmony_ci (sizeof(struct LD_LOAD_BALANCE_INFO) * 49728c2ecf20Sopenharmony_ci MAX_LOGICAL_DRIVES_EXT)); 49738c2ecf20Sopenharmony_ci 49748c2ecf20Sopenharmony_ci if (!megasas_get_map_info(instance)) { 49758c2ecf20Sopenharmony_ci megasas_sync_map_info(instance); 49768c2ecf20Sopenharmony_ci } else { 49778c2ecf20Sopenharmony_ci /* 49788c2ecf20Sopenharmony_ci * Return pending polled mode cmds before 49798c2ecf20Sopenharmony_ci * retrying OCR 49808c2ecf20Sopenharmony_ci */ 49818c2ecf20Sopenharmony_ci megasas_return_polled_cmds(instance); 49828c2ecf20Sopenharmony_ci continue; 49838c2ecf20Sopenharmony_ci } 49848c2ecf20Sopenharmony_ci 49858c2ecf20Sopenharmony_ci megasas_setup_jbod_map(instance); 49868c2ecf20Sopenharmony_ci 49878c2ecf20Sopenharmony_ci /* reset stream detection array */ 49888c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) { 49898c2ecf20Sopenharmony_ci for (j = 0; j < MAX_LOGICAL_DRIVES_EXT; ++j) { 49908c2ecf20Sopenharmony_ci memset(fusion->stream_detect_by_ld[j], 49918c2ecf20Sopenharmony_ci 0, sizeof(struct LD_STREAM_DETECT)); 49928c2ecf20Sopenharmony_ci fusion->stream_detect_by_ld[j]->mru_bit_map 49938c2ecf20Sopenharmony_ci = MR_STREAM_BITMAP; 49948c2ecf20Sopenharmony_ci } 49958c2ecf20Sopenharmony_ci } 49968c2ecf20Sopenharmony_ci 49978c2ecf20Sopenharmony_ci clear_bit(MEGASAS_FUSION_IN_RESET, 49988c2ecf20Sopenharmony_ci &instance->reset_flags); 49998c2ecf20Sopenharmony_ci instance->instancet->enable_intr(instance); 50008c2ecf20Sopenharmony_ci megasas_enable_irq_poll(instance); 50018c2ecf20Sopenharmony_ci shost_for_each_device(sdev, shost) { 50028c2ecf20Sopenharmony_ci if ((instance->tgt_prop) && 50038c2ecf20Sopenharmony_ci (instance->nvme_page_size)) 50048c2ecf20Sopenharmony_ci ret_target_prop = megasas_get_target_prop(instance, sdev); 50058c2ecf20Sopenharmony_ci 50068c2ecf20Sopenharmony_ci is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false; 50078c2ecf20Sopenharmony_ci megasas_set_dynamic_target_properties(sdev, is_target_prop); 50088c2ecf20Sopenharmony_ci } 50098c2ecf20Sopenharmony_ci 50108c2ecf20Sopenharmony_ci status_reg = instance->instancet->read_fw_status_reg 50118c2ecf20Sopenharmony_ci (instance); 50128c2ecf20Sopenharmony_ci abs_state = status_reg & MFI_STATE_MASK; 50138c2ecf20Sopenharmony_ci if (abs_state != MFI_STATE_OPERATIONAL) { 50148c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 50158c2ecf20Sopenharmony_ci "Adapter is not OPERATIONAL, state 0x%x for scsi:%d\n", 50168c2ecf20Sopenharmony_ci abs_state, instance->host->host_no); 50178c2ecf20Sopenharmony_ci goto out; 50188c2ecf20Sopenharmony_ci } 50198c2ecf20Sopenharmony_ci atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL); 50208c2ecf20Sopenharmony_ci 50218c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 50228c2ecf20Sopenharmony_ci "Adapter is OPERATIONAL for scsi:%d\n", 50238c2ecf20Sopenharmony_ci instance->host->host_no); 50248c2ecf20Sopenharmony_ci 50258c2ecf20Sopenharmony_ci /* Restart SR-IOV heartbeat */ 50268c2ecf20Sopenharmony_ci if (instance->requestorId) { 50278c2ecf20Sopenharmony_ci if (!megasas_sriov_start_heartbeat(instance, 0)) 50288c2ecf20Sopenharmony_ci megasas_start_timer(instance); 50298c2ecf20Sopenharmony_ci else 50308c2ecf20Sopenharmony_ci instance->skip_heartbeat_timer_del = 1; 50318c2ecf20Sopenharmony_ci } 50328c2ecf20Sopenharmony_ci 50338c2ecf20Sopenharmony_ci if (instance->crash_dump_drv_support && 50348c2ecf20Sopenharmony_ci instance->crash_dump_app_support) 50358c2ecf20Sopenharmony_ci megasas_set_crash_dump_params(instance, 50368c2ecf20Sopenharmony_ci MR_CRASH_BUF_TURN_ON); 50378c2ecf20Sopenharmony_ci else 50388c2ecf20Sopenharmony_ci megasas_set_crash_dump_params(instance, 50398c2ecf20Sopenharmony_ci MR_CRASH_BUF_TURN_OFF); 50408c2ecf20Sopenharmony_ci 50418c2ecf20Sopenharmony_ci if (instance->snapdump_wait_time) { 50428c2ecf20Sopenharmony_ci megasas_get_snapdump_properties(instance); 50438c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 50448c2ecf20Sopenharmony_ci "Snap dump wait time\t: %d\n", 50458c2ecf20Sopenharmony_ci instance->snapdump_wait_time); 50468c2ecf20Sopenharmony_ci } 50478c2ecf20Sopenharmony_ci 50488c2ecf20Sopenharmony_ci retval = SUCCESS; 50498c2ecf20Sopenharmony_ci 50508c2ecf20Sopenharmony_ci /* Adapter reset completed successfully */ 50518c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, 50528c2ecf20Sopenharmony_ci "Reset successful for scsi%d.\n", 50538c2ecf20Sopenharmony_ci instance->host->host_no); 50548c2ecf20Sopenharmony_ci 50558c2ecf20Sopenharmony_ci goto out; 50568c2ecf20Sopenharmony_ci } 50578c2ecf20Sopenharmony_ci /* Reset failed, kill the adapter */ 50588c2ecf20Sopenharmony_ci dev_warn(&instance->pdev->dev, "Reset failed, killing " 50598c2ecf20Sopenharmony_ci "adapter scsi%d.\n", instance->host->host_no); 50608c2ecf20Sopenharmony_ci goto kill_hba; 50618c2ecf20Sopenharmony_ci } else { 50628c2ecf20Sopenharmony_ci /* For VF: Restart HB timer if we didn't OCR */ 50638c2ecf20Sopenharmony_ci if (instance->requestorId) { 50648c2ecf20Sopenharmony_ci megasas_start_timer(instance); 50658c2ecf20Sopenharmony_ci } 50668c2ecf20Sopenharmony_ci clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); 50678c2ecf20Sopenharmony_ci instance->instancet->enable_intr(instance); 50688c2ecf20Sopenharmony_ci megasas_enable_irq_poll(instance); 50698c2ecf20Sopenharmony_ci atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL); 50708c2ecf20Sopenharmony_ci goto out; 50718c2ecf20Sopenharmony_ci } 50728c2ecf20Sopenharmony_cikill_hba: 50738c2ecf20Sopenharmony_ci megaraid_sas_kill_hba(instance); 50748c2ecf20Sopenharmony_ci megasas_enable_irq_poll(instance); 50758c2ecf20Sopenharmony_ci instance->skip_heartbeat_timer_del = 1; 50768c2ecf20Sopenharmony_ci retval = FAILED; 50778c2ecf20Sopenharmony_ciout: 50788c2ecf20Sopenharmony_ci clear_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE, &instance->reset_flags); 50798c2ecf20Sopenharmony_ci mutex_unlock(&instance->reset_mutex); 50808c2ecf20Sopenharmony_ci return retval; 50818c2ecf20Sopenharmony_ci} 50828c2ecf20Sopenharmony_ci 50838c2ecf20Sopenharmony_ci/* Fusion Crash dump collection */ 50848c2ecf20Sopenharmony_cistatic void megasas_fusion_crash_dump(struct megasas_instance *instance) 50858c2ecf20Sopenharmony_ci{ 50868c2ecf20Sopenharmony_ci u32 status_reg; 50878c2ecf20Sopenharmony_ci u8 partial_copy = 0; 50888c2ecf20Sopenharmony_ci int wait = 0; 50898c2ecf20Sopenharmony_ci 50908c2ecf20Sopenharmony_ci 50918c2ecf20Sopenharmony_ci status_reg = instance->instancet->read_fw_status_reg(instance); 50928c2ecf20Sopenharmony_ci 50938c2ecf20Sopenharmony_ci /* 50948c2ecf20Sopenharmony_ci * Allocate host crash buffers to copy data from 1 MB DMA crash buffer 50958c2ecf20Sopenharmony_ci * to host crash buffers 50968c2ecf20Sopenharmony_ci */ 50978c2ecf20Sopenharmony_ci if (instance->drv_buf_index == 0) { 50988c2ecf20Sopenharmony_ci /* Buffer is already allocated for old Crash dump. 50998c2ecf20Sopenharmony_ci * Do OCR and do not wait for crash dump collection 51008c2ecf20Sopenharmony_ci */ 51018c2ecf20Sopenharmony_ci if (instance->drv_buf_alloc) { 51028c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "earlier crash dump is " 51038c2ecf20Sopenharmony_ci "not yet copied by application, ignoring this " 51048c2ecf20Sopenharmony_ci "crash dump and initiating OCR\n"); 51058c2ecf20Sopenharmony_ci status_reg |= MFI_STATE_CRASH_DUMP_DONE; 51068c2ecf20Sopenharmony_ci writel(status_reg, 51078c2ecf20Sopenharmony_ci &instance->reg_set->outbound_scratch_pad_0); 51088c2ecf20Sopenharmony_ci readl(&instance->reg_set->outbound_scratch_pad_0); 51098c2ecf20Sopenharmony_ci return; 51108c2ecf20Sopenharmony_ci } 51118c2ecf20Sopenharmony_ci megasas_alloc_host_crash_buffer(instance); 51128c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Number of host crash buffers " 51138c2ecf20Sopenharmony_ci "allocated: %d\n", instance->drv_buf_alloc); 51148c2ecf20Sopenharmony_ci } 51158c2ecf20Sopenharmony_ci 51168c2ecf20Sopenharmony_ci while (!(status_reg & MFI_STATE_CRASH_DUMP_DONE) && 51178c2ecf20Sopenharmony_ci (wait < MEGASAS_WATCHDOG_WAIT_COUNT)) { 51188c2ecf20Sopenharmony_ci if (!(status_reg & MFI_STATE_DMADONE)) { 51198c2ecf20Sopenharmony_ci /* 51208c2ecf20Sopenharmony_ci * Next crash dump buffer is not yet DMA'd by FW 51218c2ecf20Sopenharmony_ci * Check after 10ms. Wait for 1 second for FW to 51228c2ecf20Sopenharmony_ci * post the next buffer. If not bail out. 51238c2ecf20Sopenharmony_ci */ 51248c2ecf20Sopenharmony_ci wait++; 51258c2ecf20Sopenharmony_ci msleep(MEGASAS_WAIT_FOR_NEXT_DMA_MSECS); 51268c2ecf20Sopenharmony_ci status_reg = instance->instancet->read_fw_status_reg( 51278c2ecf20Sopenharmony_ci instance); 51288c2ecf20Sopenharmony_ci continue; 51298c2ecf20Sopenharmony_ci } 51308c2ecf20Sopenharmony_ci 51318c2ecf20Sopenharmony_ci wait = 0; 51328c2ecf20Sopenharmony_ci if (instance->drv_buf_index >= instance->drv_buf_alloc) { 51338c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 51348c2ecf20Sopenharmony_ci "Driver is done copying the buffer: %d\n", 51358c2ecf20Sopenharmony_ci instance->drv_buf_alloc); 51368c2ecf20Sopenharmony_ci status_reg |= MFI_STATE_CRASH_DUMP_DONE; 51378c2ecf20Sopenharmony_ci partial_copy = 1; 51388c2ecf20Sopenharmony_ci break; 51398c2ecf20Sopenharmony_ci } else { 51408c2ecf20Sopenharmony_ci memcpy(instance->crash_buf[instance->drv_buf_index], 51418c2ecf20Sopenharmony_ci instance->crash_dump_buf, CRASH_DMA_BUF_SIZE); 51428c2ecf20Sopenharmony_ci instance->drv_buf_index++; 51438c2ecf20Sopenharmony_ci status_reg &= ~MFI_STATE_DMADONE; 51448c2ecf20Sopenharmony_ci } 51458c2ecf20Sopenharmony_ci 51468c2ecf20Sopenharmony_ci writel(status_reg, &instance->reg_set->outbound_scratch_pad_0); 51478c2ecf20Sopenharmony_ci readl(&instance->reg_set->outbound_scratch_pad_0); 51488c2ecf20Sopenharmony_ci 51498c2ecf20Sopenharmony_ci msleep(MEGASAS_WAIT_FOR_NEXT_DMA_MSECS); 51508c2ecf20Sopenharmony_ci status_reg = instance->instancet->read_fw_status_reg(instance); 51518c2ecf20Sopenharmony_ci } 51528c2ecf20Sopenharmony_ci 51538c2ecf20Sopenharmony_ci if (status_reg & MFI_STATE_CRASH_DUMP_DONE) { 51548c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "Crash Dump is available,number " 51558c2ecf20Sopenharmony_ci "of copied buffers: %d\n", instance->drv_buf_index); 51568c2ecf20Sopenharmony_ci instance->fw_crash_buffer_size = instance->drv_buf_index; 51578c2ecf20Sopenharmony_ci instance->fw_crash_state = AVAILABLE; 51588c2ecf20Sopenharmony_ci instance->drv_buf_index = 0; 51598c2ecf20Sopenharmony_ci writel(status_reg, &instance->reg_set->outbound_scratch_pad_0); 51608c2ecf20Sopenharmony_ci readl(&instance->reg_set->outbound_scratch_pad_0); 51618c2ecf20Sopenharmony_ci if (!partial_copy) 51628c2ecf20Sopenharmony_ci megasas_reset_fusion(instance->host, 0); 51638c2ecf20Sopenharmony_ci } 51648c2ecf20Sopenharmony_ci} 51658c2ecf20Sopenharmony_ci 51668c2ecf20Sopenharmony_ci 51678c2ecf20Sopenharmony_ci/* Fusion OCR work queue */ 51688c2ecf20Sopenharmony_civoid megasas_fusion_ocr_wq(struct work_struct *work) 51698c2ecf20Sopenharmony_ci{ 51708c2ecf20Sopenharmony_ci struct megasas_instance *instance = 51718c2ecf20Sopenharmony_ci container_of(work, struct megasas_instance, work_init); 51728c2ecf20Sopenharmony_ci 51738c2ecf20Sopenharmony_ci megasas_reset_fusion(instance->host, 0); 51748c2ecf20Sopenharmony_ci} 51758c2ecf20Sopenharmony_ci 51768c2ecf20Sopenharmony_ci/* Allocate fusion context */ 51778c2ecf20Sopenharmony_ciint 51788c2ecf20Sopenharmony_cimegasas_alloc_fusion_context(struct megasas_instance *instance) 51798c2ecf20Sopenharmony_ci{ 51808c2ecf20Sopenharmony_ci struct fusion_context *fusion; 51818c2ecf20Sopenharmony_ci 51828c2ecf20Sopenharmony_ci instance->ctrl_context = kzalloc(sizeof(struct fusion_context), 51838c2ecf20Sopenharmony_ci GFP_KERNEL); 51848c2ecf20Sopenharmony_ci if (!instance->ctrl_context) { 51858c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed from %s %d\n", 51868c2ecf20Sopenharmony_ci __func__, __LINE__); 51878c2ecf20Sopenharmony_ci return -ENOMEM; 51888c2ecf20Sopenharmony_ci } 51898c2ecf20Sopenharmony_ci 51908c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 51918c2ecf20Sopenharmony_ci 51928c2ecf20Sopenharmony_ci fusion->log_to_span_pages = get_order(MAX_LOGICAL_DRIVES_EXT * 51938c2ecf20Sopenharmony_ci sizeof(LD_SPAN_INFO)); 51948c2ecf20Sopenharmony_ci fusion->log_to_span = 51958c2ecf20Sopenharmony_ci (PLD_SPAN_INFO)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 51968c2ecf20Sopenharmony_ci fusion->log_to_span_pages); 51978c2ecf20Sopenharmony_ci if (!fusion->log_to_span) { 51988c2ecf20Sopenharmony_ci fusion->log_to_span = 51998c2ecf20Sopenharmony_ci vzalloc(array_size(MAX_LOGICAL_DRIVES_EXT, 52008c2ecf20Sopenharmony_ci sizeof(LD_SPAN_INFO))); 52018c2ecf20Sopenharmony_ci if (!fusion->log_to_span) { 52028c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed from %s %d\n", 52038c2ecf20Sopenharmony_ci __func__, __LINE__); 52048c2ecf20Sopenharmony_ci return -ENOMEM; 52058c2ecf20Sopenharmony_ci } 52068c2ecf20Sopenharmony_ci } 52078c2ecf20Sopenharmony_ci 52088c2ecf20Sopenharmony_ci fusion->load_balance_info_pages = get_order(MAX_LOGICAL_DRIVES_EXT * 52098c2ecf20Sopenharmony_ci sizeof(struct LD_LOAD_BALANCE_INFO)); 52108c2ecf20Sopenharmony_ci fusion->load_balance_info = 52118c2ecf20Sopenharmony_ci (struct LD_LOAD_BALANCE_INFO *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 52128c2ecf20Sopenharmony_ci fusion->load_balance_info_pages); 52138c2ecf20Sopenharmony_ci if (!fusion->load_balance_info) { 52148c2ecf20Sopenharmony_ci fusion->load_balance_info = 52158c2ecf20Sopenharmony_ci vzalloc(array_size(MAX_LOGICAL_DRIVES_EXT, 52168c2ecf20Sopenharmony_ci sizeof(struct LD_LOAD_BALANCE_INFO))); 52178c2ecf20Sopenharmony_ci if (!fusion->load_balance_info) 52188c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "Failed to allocate load_balance_info, " 52198c2ecf20Sopenharmony_ci "continuing without Load Balance support\n"); 52208c2ecf20Sopenharmony_ci } 52218c2ecf20Sopenharmony_ci 52228c2ecf20Sopenharmony_ci return 0; 52238c2ecf20Sopenharmony_ci} 52248c2ecf20Sopenharmony_ci 52258c2ecf20Sopenharmony_civoid 52268c2ecf20Sopenharmony_cimegasas_free_fusion_context(struct megasas_instance *instance) 52278c2ecf20Sopenharmony_ci{ 52288c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 52298c2ecf20Sopenharmony_ci 52308c2ecf20Sopenharmony_ci if (fusion) { 52318c2ecf20Sopenharmony_ci if (fusion->load_balance_info) { 52328c2ecf20Sopenharmony_ci if (is_vmalloc_addr(fusion->load_balance_info)) 52338c2ecf20Sopenharmony_ci vfree(fusion->load_balance_info); 52348c2ecf20Sopenharmony_ci else 52358c2ecf20Sopenharmony_ci free_pages((ulong)fusion->load_balance_info, 52368c2ecf20Sopenharmony_ci fusion->load_balance_info_pages); 52378c2ecf20Sopenharmony_ci } 52388c2ecf20Sopenharmony_ci 52398c2ecf20Sopenharmony_ci if (fusion->log_to_span) { 52408c2ecf20Sopenharmony_ci if (is_vmalloc_addr(fusion->log_to_span)) 52418c2ecf20Sopenharmony_ci vfree(fusion->log_to_span); 52428c2ecf20Sopenharmony_ci else 52438c2ecf20Sopenharmony_ci free_pages((ulong)fusion->log_to_span, 52448c2ecf20Sopenharmony_ci fusion->log_to_span_pages); 52458c2ecf20Sopenharmony_ci } 52468c2ecf20Sopenharmony_ci 52478c2ecf20Sopenharmony_ci kfree(fusion); 52488c2ecf20Sopenharmony_ci } 52498c2ecf20Sopenharmony_ci} 52508c2ecf20Sopenharmony_ci 52518c2ecf20Sopenharmony_cistruct megasas_instance_template megasas_instance_template_fusion = { 52528c2ecf20Sopenharmony_ci .enable_intr = megasas_enable_intr_fusion, 52538c2ecf20Sopenharmony_ci .disable_intr = megasas_disable_intr_fusion, 52548c2ecf20Sopenharmony_ci .clear_intr = megasas_clear_intr_fusion, 52558c2ecf20Sopenharmony_ci .read_fw_status_reg = megasas_read_fw_status_reg_fusion, 52568c2ecf20Sopenharmony_ci .adp_reset = megasas_adp_reset_fusion, 52578c2ecf20Sopenharmony_ci .check_reset = megasas_check_reset_fusion, 52588c2ecf20Sopenharmony_ci .service_isr = megasas_isr_fusion, 52598c2ecf20Sopenharmony_ci .tasklet = megasas_complete_cmd_dpc_fusion, 52608c2ecf20Sopenharmony_ci .init_adapter = megasas_init_adapter_fusion, 52618c2ecf20Sopenharmony_ci .build_and_issue_cmd = megasas_build_and_issue_cmd_fusion, 52628c2ecf20Sopenharmony_ci .issue_dcmd = megasas_issue_dcmd_fusion, 52638c2ecf20Sopenharmony_ci}; 5264