162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This is the Fusion MPT base driver providing common API layer interface 362306a36Sopenharmony_ci * for access to MPT (Message Passing Technology) firmware. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c 662306a36Sopenharmony_ci * Copyright (C) 2012-2014 LSI Corporation 762306a36Sopenharmony_ci * Copyright (C) 2013-2014 Avago Technologies 862306a36Sopenharmony_ci * (mailto: MPT-FusionLinux.pdl@avagotech.com) 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or 1162306a36Sopenharmony_ci * modify it under the terms of the GNU General Public License 1262306a36Sopenharmony_ci * as published by the Free Software Foundation; either version 2 1362306a36Sopenharmony_ci * of the License, or (at your option) any later version. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful, 1662306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 1762306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1862306a36Sopenharmony_ci * GNU General Public License for more details. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * NO WARRANTY 2162306a36Sopenharmony_ci * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR 2262306a36Sopenharmony_ci * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT 2362306a36Sopenharmony_ci * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 2462306a36Sopenharmony_ci * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is 2562306a36Sopenharmony_ci * solely responsible for determining the appropriateness of using and 2662306a36Sopenharmony_ci * distributing the Program and assumes all risks associated with its 2762306a36Sopenharmony_ci * exercise of rights under this Agreement, including but not limited to 2862306a36Sopenharmony_ci * the risks and costs of program errors, damage to or loss of data, 2962306a36Sopenharmony_ci * programs or equipment, and unavailability or interruption of operations. 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci * DISCLAIMER OF LIABILITY 3262306a36Sopenharmony_ci * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY 3362306a36Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3462306a36Sopenharmony_ci * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND 3562306a36Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 3662306a36Sopenharmony_ci * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 3762306a36Sopenharmony_ci * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 3862306a36Sopenharmony_ci * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 4162306a36Sopenharmony_ci * along with this program; if not, write to the Free Software 4262306a36Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 4362306a36Sopenharmony_ci * USA. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include <linux/kernel.h> 4762306a36Sopenharmony_ci#include <linux/module.h> 4862306a36Sopenharmony_ci#include <linux/errno.h> 4962306a36Sopenharmony_ci#include <linux/init.h> 5062306a36Sopenharmony_ci#include <linux/slab.h> 5162306a36Sopenharmony_ci#include <linux/types.h> 5262306a36Sopenharmony_ci#include <linux/pci.h> 5362306a36Sopenharmony_ci#include <linux/kdev_t.h> 5462306a36Sopenharmony_ci#include <linux/blkdev.h> 5562306a36Sopenharmony_ci#include <linux/delay.h> 5662306a36Sopenharmony_ci#include <linux/interrupt.h> 5762306a36Sopenharmony_ci#include <linux/dma-mapping.h> 5862306a36Sopenharmony_ci#include <linux/io.h> 5962306a36Sopenharmony_ci#include <linux/time.h> 6062306a36Sopenharmony_ci#include <linux/ktime.h> 6162306a36Sopenharmony_ci#include <linux/kthread.h> 6262306a36Sopenharmony_ci#include <asm/page.h> /* To get host page size per arch */ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#include "mpt3sas_base.h" 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS]; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci /* maximum controller queue depth */ 7362306a36Sopenharmony_ci#define MAX_HBA_QUEUE_DEPTH 30000 7462306a36Sopenharmony_ci#define MAX_CHAIN_DEPTH 100000 7562306a36Sopenharmony_cistatic int max_queue_depth = -1; 7662306a36Sopenharmony_cimodule_param(max_queue_depth, int, 0444); 7762306a36Sopenharmony_ciMODULE_PARM_DESC(max_queue_depth, " max controller queue depth "); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic int max_sgl_entries = -1; 8062306a36Sopenharmony_cimodule_param(max_sgl_entries, int, 0444); 8162306a36Sopenharmony_ciMODULE_PARM_DESC(max_sgl_entries, " max sg entries "); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic int msix_disable = -1; 8462306a36Sopenharmony_cimodule_param(msix_disable, int, 0444); 8562306a36Sopenharmony_ciMODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic int smp_affinity_enable = 1; 8862306a36Sopenharmony_cimodule_param(smp_affinity_enable, int, 0444); 8962306a36Sopenharmony_ciMODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)"); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int max_msix_vectors = -1; 9262306a36Sopenharmony_cimodule_param(max_msix_vectors, int, 0444); 9362306a36Sopenharmony_ciMODULE_PARM_DESC(max_msix_vectors, 9462306a36Sopenharmony_ci " max msix vectors"); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic int irqpoll_weight = -1; 9762306a36Sopenharmony_cimodule_param(irqpoll_weight, int, 0444); 9862306a36Sopenharmony_ciMODULE_PARM_DESC(irqpoll_weight, 9962306a36Sopenharmony_ci "irq poll weight (default= one fourth of HBA queue depth)"); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int mpt3sas_fwfault_debug; 10262306a36Sopenharmony_ciMODULE_PARM_DESC(mpt3sas_fwfault_debug, 10362306a36Sopenharmony_ci " enable detection of firmware fault and halt firmware - (default=0)"); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic int perf_mode = -1; 10662306a36Sopenharmony_cimodule_param(perf_mode, int, 0444); 10762306a36Sopenharmony_ciMODULE_PARM_DESC(perf_mode, 10862306a36Sopenharmony_ci "Performance mode (only for Aero/Sea Generation), options:\n\t\t" 10962306a36Sopenharmony_ci "0 - balanced: high iops mode is enabled &\n\t\t" 11062306a36Sopenharmony_ci "interrupt coalescing is enabled only on high iops queues,\n\t\t" 11162306a36Sopenharmony_ci "1 - iops: high iops mode is disabled &\n\t\t" 11262306a36Sopenharmony_ci "interrupt coalescing is enabled on all queues,\n\t\t" 11362306a36Sopenharmony_ci "2 - latency: high iops mode is disabled &\n\t\t" 11462306a36Sopenharmony_ci "interrupt coalescing is enabled on all queues with timeout value 0xA,\n" 11562306a36Sopenharmony_ci "\t\tdefault - default perf_mode is 'balanced'" 11662306a36Sopenharmony_ci ); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic int poll_queues; 11962306a36Sopenharmony_cimodule_param(poll_queues, int, 0444); 12062306a36Sopenharmony_ciMODULE_PARM_DESC(poll_queues, "Number of queues to be use for io_uring poll mode.\n\t\t" 12162306a36Sopenharmony_ci "This parameter is effective only if host_tagset_enable=1. &\n\t\t" 12262306a36Sopenharmony_ci "when poll_queues are enabled then &\n\t\t" 12362306a36Sopenharmony_ci "perf_mode is set to latency mode. &\n\t\t" 12462306a36Sopenharmony_ci ); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cienum mpt3sas_perf_mode { 12762306a36Sopenharmony_ci MPT_PERF_MODE_DEFAULT = -1, 12862306a36Sopenharmony_ci MPT_PERF_MODE_BALANCED = 0, 12962306a36Sopenharmony_ci MPT_PERF_MODE_IOPS = 1, 13062306a36Sopenharmony_ci MPT_PERF_MODE_LATENCY = 2, 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int 13462306a36Sopenharmony_ci_base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, 13562306a36Sopenharmony_ci u32 ioc_state, int timeout); 13662306a36Sopenharmony_cistatic int 13762306a36Sopenharmony_ci_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc); 13862306a36Sopenharmony_cistatic void 13962306a36Sopenharmony_ci_base_clear_outstanding_commands(struct MPT3SAS_ADAPTER *ioc); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic u32 14262306a36Sopenharmony_ci_base_readl_ext_retry(const void __iomem *addr); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/** 14562306a36Sopenharmony_ci * mpt3sas_base_check_cmd_timeout - Function 14662306a36Sopenharmony_ci * to check timeout and command termination due 14762306a36Sopenharmony_ci * to Host reset. 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * @ioc: per adapter object. 15062306a36Sopenharmony_ci * @status: Status of issued command. 15162306a36Sopenharmony_ci * @mpi_request:mf request pointer. 15262306a36Sopenharmony_ci * @sz: size of buffer. 15362306a36Sopenharmony_ci * 15462306a36Sopenharmony_ci * Return: 1/0 Reset to be done or Not 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ciu8 15762306a36Sopenharmony_cimpt3sas_base_check_cmd_timeout(struct MPT3SAS_ADAPTER *ioc, 15862306a36Sopenharmony_ci u8 status, void *mpi_request, int sz) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci u8 issue_reset = 0; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (!(status & MPT3_CMD_RESET)) 16362306a36Sopenharmony_ci issue_reset = 1; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci ioc_err(ioc, "Command %s\n", 16662306a36Sopenharmony_ci issue_reset == 0 ? "terminated due to Host Reset" : "Timeout"); 16762306a36Sopenharmony_ci _debug_dump_mf(mpi_request, sz); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return issue_reset; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/** 17362306a36Sopenharmony_ci * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug. 17462306a36Sopenharmony_ci * @val: ? 17562306a36Sopenharmony_ci * @kp: ? 17662306a36Sopenharmony_ci * 17762306a36Sopenharmony_ci * Return: ? 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_cistatic int 18062306a36Sopenharmony_ci_scsih_set_fwfault_debug(const char *val, const struct kernel_param *kp) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci int ret = param_set_int(val, kp); 18362306a36Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (ret) 18662306a36Sopenharmony_ci return ret; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* global ioc spinlock to protect controller list on list operations */ 18962306a36Sopenharmony_ci pr_info("setting fwfault_debug(%d)\n", mpt3sas_fwfault_debug); 19062306a36Sopenharmony_ci spin_lock(&gioc_lock); 19162306a36Sopenharmony_ci list_for_each_entry(ioc, &mpt3sas_ioc_list, list) 19262306a36Sopenharmony_ci ioc->fwfault_debug = mpt3sas_fwfault_debug; 19362306a36Sopenharmony_ci spin_unlock(&gioc_lock); 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_cimodule_param_call(mpt3sas_fwfault_debug, _scsih_set_fwfault_debug, 19762306a36Sopenharmony_ci param_get_int, &mpt3sas_fwfault_debug, 0644); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/** 20062306a36Sopenharmony_ci * _base_readl_aero - retry readl for max three times. 20162306a36Sopenharmony_ci * @addr: MPT Fusion system interface register address 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * Retry the readl() for max three times if it gets zero value 20462306a36Sopenharmony_ci * while reading the system interface register. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_cistatic inline u32 20762306a36Sopenharmony_ci_base_readl_aero(const void __iomem *addr) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci u32 i = 0, ret_val; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci do { 21262306a36Sopenharmony_ci ret_val = readl(addr); 21362306a36Sopenharmony_ci i++; 21462306a36Sopenharmony_ci } while (ret_val == 0 && i < 3); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return ret_val; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic u32 22062306a36Sopenharmony_ci_base_readl_ext_retry(const void __iomem *addr) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci u32 i, ret_val; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci for (i = 0 ; i < 30 ; i++) { 22562306a36Sopenharmony_ci ret_val = readl(addr); 22662306a36Sopenharmony_ci if (ret_val != 0) 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return ret_val; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic inline u32 23462306a36Sopenharmony_ci_base_readl(const void __iomem *addr) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci return readl(addr); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/** 24062306a36Sopenharmony_ci * _base_clone_reply_to_sys_mem - copies reply to reply free iomem 24162306a36Sopenharmony_ci * in BAR0 space. 24262306a36Sopenharmony_ci * 24362306a36Sopenharmony_ci * @ioc: per adapter object 24462306a36Sopenharmony_ci * @reply: reply message frame(lower 32bit addr) 24562306a36Sopenharmony_ci * @index: System request message index. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_cistatic void 24862306a36Sopenharmony_ci_base_clone_reply_to_sys_mem(struct MPT3SAS_ADAPTER *ioc, u32 reply, 24962306a36Sopenharmony_ci u32 index) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci /* 25262306a36Sopenharmony_ci * 256 is offset within sys register. 25362306a36Sopenharmony_ci * 256 offset MPI frame starts. Max MPI frame supported is 32. 25462306a36Sopenharmony_ci * 32 * 128 = 4K. From here, Clone of reply free for mcpu starts 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci u16 cmd_credit = ioc->facts.RequestCredit + 1; 25762306a36Sopenharmony_ci void __iomem *reply_free_iomem = (void __iomem *)ioc->chip + 25862306a36Sopenharmony_ci MPI_FRAME_START_OFFSET + 25962306a36Sopenharmony_ci (cmd_credit * ioc->request_sz) + (index * sizeof(u32)); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci writel(reply, reply_free_iomem); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/** 26562306a36Sopenharmony_ci * _base_clone_mpi_to_sys_mem - Writes/copies MPI frames 26662306a36Sopenharmony_ci * to system/BAR0 region. 26762306a36Sopenharmony_ci * 26862306a36Sopenharmony_ci * @dst_iomem: Pointer to the destination location in BAR0 space. 26962306a36Sopenharmony_ci * @src: Pointer to the Source data. 27062306a36Sopenharmony_ci * @size: Size of data to be copied. 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_cistatic void 27362306a36Sopenharmony_ci_base_clone_mpi_to_sys_mem(void *dst_iomem, void *src, u32 size) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci int i; 27662306a36Sopenharmony_ci u32 *src_virt_mem = (u32 *)src; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci for (i = 0; i < size/4; i++) 27962306a36Sopenharmony_ci writel((u32)src_virt_mem[i], 28062306a36Sopenharmony_ci (void __iomem *)dst_iomem + (i * 4)); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/** 28462306a36Sopenharmony_ci * _base_clone_to_sys_mem - Writes/copies data to system/BAR0 region 28562306a36Sopenharmony_ci * 28662306a36Sopenharmony_ci * @dst_iomem: Pointer to the destination location in BAR0 space. 28762306a36Sopenharmony_ci * @src: Pointer to the Source data. 28862306a36Sopenharmony_ci * @size: Size of data to be copied. 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_cistatic void 29162306a36Sopenharmony_ci_base_clone_to_sys_mem(void __iomem *dst_iomem, void *src, u32 size) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci int i; 29462306a36Sopenharmony_ci u32 *src_virt_mem = (u32 *)(src); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci for (i = 0; i < size/4; i++) 29762306a36Sopenharmony_ci writel((u32)src_virt_mem[i], 29862306a36Sopenharmony_ci (void __iomem *)dst_iomem + (i * 4)); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/** 30262306a36Sopenharmony_ci * _base_get_chain - Calculates and Returns virtual chain address 30362306a36Sopenharmony_ci * for the provided smid in BAR0 space. 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci * @ioc: per adapter object 30662306a36Sopenharmony_ci * @smid: system request message index 30762306a36Sopenharmony_ci * @sge_chain_count: Scatter gather chain count. 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * Return: the chain address. 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_cistatic inline void __iomem* 31262306a36Sopenharmony_ci_base_get_chain(struct MPT3SAS_ADAPTER *ioc, u16 smid, 31362306a36Sopenharmony_ci u8 sge_chain_count) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci void __iomem *base_chain, *chain_virt; 31662306a36Sopenharmony_ci u16 cmd_credit = ioc->facts.RequestCredit + 1; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci base_chain = (void __iomem *)ioc->chip + MPI_FRAME_START_OFFSET + 31962306a36Sopenharmony_ci (cmd_credit * ioc->request_sz) + 32062306a36Sopenharmony_ci REPLY_FREE_POOL_SIZE; 32162306a36Sopenharmony_ci chain_virt = base_chain + (smid * ioc->facts.MaxChainDepth * 32262306a36Sopenharmony_ci ioc->request_sz) + (sge_chain_count * ioc->request_sz); 32362306a36Sopenharmony_ci return chain_virt; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci/** 32762306a36Sopenharmony_ci * _base_get_chain_phys - Calculates and Returns physical address 32862306a36Sopenharmony_ci * in BAR0 for scatter gather chains, for 32962306a36Sopenharmony_ci * the provided smid. 33062306a36Sopenharmony_ci * 33162306a36Sopenharmony_ci * @ioc: per adapter object 33262306a36Sopenharmony_ci * @smid: system request message index 33362306a36Sopenharmony_ci * @sge_chain_count: Scatter gather chain count. 33462306a36Sopenharmony_ci * 33562306a36Sopenharmony_ci * Return: Physical chain address. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_cistatic inline phys_addr_t 33862306a36Sopenharmony_ci_base_get_chain_phys(struct MPT3SAS_ADAPTER *ioc, u16 smid, 33962306a36Sopenharmony_ci u8 sge_chain_count) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci phys_addr_t base_chain_phys, chain_phys; 34262306a36Sopenharmony_ci u16 cmd_credit = ioc->facts.RequestCredit + 1; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci base_chain_phys = ioc->chip_phys + MPI_FRAME_START_OFFSET + 34562306a36Sopenharmony_ci (cmd_credit * ioc->request_sz) + 34662306a36Sopenharmony_ci REPLY_FREE_POOL_SIZE; 34762306a36Sopenharmony_ci chain_phys = base_chain_phys + (smid * ioc->facts.MaxChainDepth * 34862306a36Sopenharmony_ci ioc->request_sz) + (sge_chain_count * ioc->request_sz); 34962306a36Sopenharmony_ci return chain_phys; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci/** 35362306a36Sopenharmony_ci * _base_get_buffer_bar0 - Calculates and Returns BAR0 mapped Host 35462306a36Sopenharmony_ci * buffer address for the provided smid. 35562306a36Sopenharmony_ci * (Each smid can have 64K starts from 17024) 35662306a36Sopenharmony_ci * 35762306a36Sopenharmony_ci * @ioc: per adapter object 35862306a36Sopenharmony_ci * @smid: system request message index 35962306a36Sopenharmony_ci * 36062306a36Sopenharmony_ci * Return: Pointer to buffer location in BAR0. 36162306a36Sopenharmony_ci */ 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic void __iomem * 36462306a36Sopenharmony_ci_base_get_buffer_bar0(struct MPT3SAS_ADAPTER *ioc, u16 smid) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci u16 cmd_credit = ioc->facts.RequestCredit + 1; 36762306a36Sopenharmony_ci // Added extra 1 to reach end of chain. 36862306a36Sopenharmony_ci void __iomem *chain_end = _base_get_chain(ioc, 36962306a36Sopenharmony_ci cmd_credit + 1, 37062306a36Sopenharmony_ci ioc->facts.MaxChainDepth); 37162306a36Sopenharmony_ci return chain_end + (smid * 64 * 1024); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci/** 37562306a36Sopenharmony_ci * _base_get_buffer_phys_bar0 - Calculates and Returns BAR0 mapped 37662306a36Sopenharmony_ci * Host buffer Physical address for the provided smid. 37762306a36Sopenharmony_ci * (Each smid can have 64K starts from 17024) 37862306a36Sopenharmony_ci * 37962306a36Sopenharmony_ci * @ioc: per adapter object 38062306a36Sopenharmony_ci * @smid: system request message index 38162306a36Sopenharmony_ci * 38262306a36Sopenharmony_ci * Return: Pointer to buffer location in BAR0. 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_cistatic phys_addr_t 38562306a36Sopenharmony_ci_base_get_buffer_phys_bar0(struct MPT3SAS_ADAPTER *ioc, u16 smid) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci u16 cmd_credit = ioc->facts.RequestCredit + 1; 38862306a36Sopenharmony_ci phys_addr_t chain_end_phys = _base_get_chain_phys(ioc, 38962306a36Sopenharmony_ci cmd_credit + 1, 39062306a36Sopenharmony_ci ioc->facts.MaxChainDepth); 39162306a36Sopenharmony_ci return chain_end_phys + (smid * 64 * 1024); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci/** 39562306a36Sopenharmony_ci * _base_get_chain_buffer_dma_to_chain_buffer - Iterates chain 39662306a36Sopenharmony_ci * lookup list and Provides chain_buffer 39762306a36Sopenharmony_ci * address for the matching dma address. 39862306a36Sopenharmony_ci * (Each smid can have 64K starts from 17024) 39962306a36Sopenharmony_ci * 40062306a36Sopenharmony_ci * @ioc: per adapter object 40162306a36Sopenharmony_ci * @chain_buffer_dma: Chain buffer dma address. 40262306a36Sopenharmony_ci * 40362306a36Sopenharmony_ci * Return: Pointer to chain buffer. Or Null on Failure. 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_cistatic void * 40662306a36Sopenharmony_ci_base_get_chain_buffer_dma_to_chain_buffer(struct MPT3SAS_ADAPTER *ioc, 40762306a36Sopenharmony_ci dma_addr_t chain_buffer_dma) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci u16 index, j; 41062306a36Sopenharmony_ci struct chain_tracker *ct; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci for (index = 0; index < ioc->scsiio_depth; index++) { 41362306a36Sopenharmony_ci for (j = 0; j < ioc->chains_needed_per_io; j++) { 41462306a36Sopenharmony_ci ct = &ioc->chain_lookup[index].chains_per_smid[j]; 41562306a36Sopenharmony_ci if (ct && ct->chain_buffer_dma == chain_buffer_dma) 41662306a36Sopenharmony_ci return ct->chain_buffer; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci ioc_info(ioc, "Provided chain_buffer_dma address is not in the lookup list\n"); 42062306a36Sopenharmony_ci return NULL; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci/** 42462306a36Sopenharmony_ci * _clone_sg_entries - MPI EP's scsiio and config requests 42562306a36Sopenharmony_ci * are handled here. Base function for 42662306a36Sopenharmony_ci * double buffering, before submitting 42762306a36Sopenharmony_ci * the requests. 42862306a36Sopenharmony_ci * 42962306a36Sopenharmony_ci * @ioc: per adapter object. 43062306a36Sopenharmony_ci * @mpi_request: mf request pointer. 43162306a36Sopenharmony_ci * @smid: system request message index. 43262306a36Sopenharmony_ci */ 43362306a36Sopenharmony_cistatic void _clone_sg_entries(struct MPT3SAS_ADAPTER *ioc, 43462306a36Sopenharmony_ci void *mpi_request, u16 smid) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci Mpi2SGESimple32_t *sgel, *sgel_next; 43762306a36Sopenharmony_ci u32 sgl_flags, sge_chain_count = 0; 43862306a36Sopenharmony_ci bool is_write = false; 43962306a36Sopenharmony_ci u16 i = 0; 44062306a36Sopenharmony_ci void __iomem *buffer_iomem; 44162306a36Sopenharmony_ci phys_addr_t buffer_iomem_phys; 44262306a36Sopenharmony_ci void __iomem *buff_ptr; 44362306a36Sopenharmony_ci phys_addr_t buff_ptr_phys; 44462306a36Sopenharmony_ci void __iomem *dst_chain_addr[MCPU_MAX_CHAINS_PER_IO]; 44562306a36Sopenharmony_ci void *src_chain_addr[MCPU_MAX_CHAINS_PER_IO]; 44662306a36Sopenharmony_ci phys_addr_t dst_addr_phys; 44762306a36Sopenharmony_ci MPI2RequestHeader_t *request_hdr; 44862306a36Sopenharmony_ci struct scsi_cmnd *scmd; 44962306a36Sopenharmony_ci struct scatterlist *sg_scmd = NULL; 45062306a36Sopenharmony_ci int is_scsiio_req = 0; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci request_hdr = (MPI2RequestHeader_t *) mpi_request; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) { 45562306a36Sopenharmony_ci Mpi25SCSIIORequest_t *scsiio_request = 45662306a36Sopenharmony_ci (Mpi25SCSIIORequest_t *)mpi_request; 45762306a36Sopenharmony_ci sgel = (Mpi2SGESimple32_t *) &scsiio_request->SGL; 45862306a36Sopenharmony_ci is_scsiio_req = 1; 45962306a36Sopenharmony_ci } else if (request_hdr->Function == MPI2_FUNCTION_CONFIG) { 46062306a36Sopenharmony_ci Mpi2ConfigRequest_t *config_req = 46162306a36Sopenharmony_ci (Mpi2ConfigRequest_t *)mpi_request; 46262306a36Sopenharmony_ci sgel = (Mpi2SGESimple32_t *) &config_req->PageBufferSGE; 46362306a36Sopenharmony_ci } else 46462306a36Sopenharmony_ci return; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* From smid we can get scsi_cmd, once we have sg_scmd, 46762306a36Sopenharmony_ci * we just need to get sg_virt and sg_next to get virtual 46862306a36Sopenharmony_ci * address associated with sgel->Address. 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (is_scsiio_req) { 47262306a36Sopenharmony_ci /* Get scsi_cmd using smid */ 47362306a36Sopenharmony_ci scmd = mpt3sas_scsih_scsi_lookup_get(ioc, smid); 47462306a36Sopenharmony_ci if (scmd == NULL) { 47562306a36Sopenharmony_ci ioc_err(ioc, "scmd is NULL\n"); 47662306a36Sopenharmony_ci return; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* Get sg_scmd from scmd provided */ 48062306a36Sopenharmony_ci sg_scmd = scsi_sglist(scmd); 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* 48462306a36Sopenharmony_ci * 0 - 255 System register 48562306a36Sopenharmony_ci * 256 - 4352 MPI Frame. (This is based on maxCredit 32) 48662306a36Sopenharmony_ci * 4352 - 4864 Reply_free pool (512 byte is reserved 48762306a36Sopenharmony_ci * considering maxCredit 32. Reply need extra 48862306a36Sopenharmony_ci * room, for mCPU case kept four times of 48962306a36Sopenharmony_ci * maxCredit). 49062306a36Sopenharmony_ci * 4864 - 17152 SGE chain element. (32cmd * 3 chain of 49162306a36Sopenharmony_ci * 128 byte size = 12288) 49262306a36Sopenharmony_ci * 17152 - x Host buffer mapped with smid. 49362306a36Sopenharmony_ci * (Each smid can have 64K Max IO.) 49462306a36Sopenharmony_ci * BAR0+Last 1K MSIX Addr and Data 49562306a36Sopenharmony_ci * Total size in use 2113664 bytes of 4MB BAR0 49662306a36Sopenharmony_ci */ 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci buffer_iomem = _base_get_buffer_bar0(ioc, smid); 49962306a36Sopenharmony_ci buffer_iomem_phys = _base_get_buffer_phys_bar0(ioc, smid); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci buff_ptr = buffer_iomem; 50262306a36Sopenharmony_ci buff_ptr_phys = buffer_iomem_phys; 50362306a36Sopenharmony_ci WARN_ON(buff_ptr_phys > U32_MAX); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (le32_to_cpu(sgel->FlagsLength) & 50662306a36Sopenharmony_ci (MPI2_SGE_FLAGS_HOST_TO_IOC << MPI2_SGE_FLAGS_SHIFT)) 50762306a36Sopenharmony_ci is_write = true; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci for (i = 0; i < MPT_MIN_PHYS_SEGMENTS + ioc->facts.MaxChainDepth; i++) { 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci sgl_flags = 51262306a36Sopenharmony_ci (le32_to_cpu(sgel->FlagsLength) >> MPI2_SGE_FLAGS_SHIFT); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci switch (sgl_flags & MPI2_SGE_FLAGS_ELEMENT_MASK) { 51562306a36Sopenharmony_ci case MPI2_SGE_FLAGS_CHAIN_ELEMENT: 51662306a36Sopenharmony_ci /* 51762306a36Sopenharmony_ci * Helper function which on passing 51862306a36Sopenharmony_ci * chain_buffer_dma returns chain_buffer. Get 51962306a36Sopenharmony_ci * the virtual address for sgel->Address 52062306a36Sopenharmony_ci */ 52162306a36Sopenharmony_ci sgel_next = 52262306a36Sopenharmony_ci _base_get_chain_buffer_dma_to_chain_buffer(ioc, 52362306a36Sopenharmony_ci le32_to_cpu(sgel->Address)); 52462306a36Sopenharmony_ci if (sgel_next == NULL) 52562306a36Sopenharmony_ci return; 52662306a36Sopenharmony_ci /* 52762306a36Sopenharmony_ci * This is coping 128 byte chain 52862306a36Sopenharmony_ci * frame (not a host buffer) 52962306a36Sopenharmony_ci */ 53062306a36Sopenharmony_ci dst_chain_addr[sge_chain_count] = 53162306a36Sopenharmony_ci _base_get_chain(ioc, 53262306a36Sopenharmony_ci smid, sge_chain_count); 53362306a36Sopenharmony_ci src_chain_addr[sge_chain_count] = 53462306a36Sopenharmony_ci (void *) sgel_next; 53562306a36Sopenharmony_ci dst_addr_phys = _base_get_chain_phys(ioc, 53662306a36Sopenharmony_ci smid, sge_chain_count); 53762306a36Sopenharmony_ci WARN_ON(dst_addr_phys > U32_MAX); 53862306a36Sopenharmony_ci sgel->Address = 53962306a36Sopenharmony_ci cpu_to_le32(lower_32_bits(dst_addr_phys)); 54062306a36Sopenharmony_ci sgel = sgel_next; 54162306a36Sopenharmony_ci sge_chain_count++; 54262306a36Sopenharmony_ci break; 54362306a36Sopenharmony_ci case MPI2_SGE_FLAGS_SIMPLE_ELEMENT: 54462306a36Sopenharmony_ci if (is_write) { 54562306a36Sopenharmony_ci if (is_scsiio_req) { 54662306a36Sopenharmony_ci _base_clone_to_sys_mem(buff_ptr, 54762306a36Sopenharmony_ci sg_virt(sg_scmd), 54862306a36Sopenharmony_ci (le32_to_cpu(sgel->FlagsLength) & 54962306a36Sopenharmony_ci 0x00ffffff)); 55062306a36Sopenharmony_ci /* 55162306a36Sopenharmony_ci * FIXME: this relies on a a zero 55262306a36Sopenharmony_ci * PCI mem_offset. 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_ci sgel->Address = 55562306a36Sopenharmony_ci cpu_to_le32((u32)buff_ptr_phys); 55662306a36Sopenharmony_ci } else { 55762306a36Sopenharmony_ci _base_clone_to_sys_mem(buff_ptr, 55862306a36Sopenharmony_ci ioc->config_vaddr, 55962306a36Sopenharmony_ci (le32_to_cpu(sgel->FlagsLength) & 56062306a36Sopenharmony_ci 0x00ffffff)); 56162306a36Sopenharmony_ci sgel->Address = 56262306a36Sopenharmony_ci cpu_to_le32((u32)buff_ptr_phys); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci buff_ptr += (le32_to_cpu(sgel->FlagsLength) & 56662306a36Sopenharmony_ci 0x00ffffff); 56762306a36Sopenharmony_ci buff_ptr_phys += (le32_to_cpu(sgel->FlagsLength) & 56862306a36Sopenharmony_ci 0x00ffffff); 56962306a36Sopenharmony_ci if ((le32_to_cpu(sgel->FlagsLength) & 57062306a36Sopenharmony_ci (MPI2_SGE_FLAGS_END_OF_BUFFER 57162306a36Sopenharmony_ci << MPI2_SGE_FLAGS_SHIFT))) 57262306a36Sopenharmony_ci goto eob_clone_chain; 57362306a36Sopenharmony_ci else { 57462306a36Sopenharmony_ci /* 57562306a36Sopenharmony_ci * Every single element in MPT will have 57662306a36Sopenharmony_ci * associated sg_next. Better to sanity that 57762306a36Sopenharmony_ci * sg_next is not NULL, but it will be a bug 57862306a36Sopenharmony_ci * if it is null. 57962306a36Sopenharmony_ci */ 58062306a36Sopenharmony_ci if (is_scsiio_req) { 58162306a36Sopenharmony_ci sg_scmd = sg_next(sg_scmd); 58262306a36Sopenharmony_ci if (sg_scmd) 58362306a36Sopenharmony_ci sgel++; 58462306a36Sopenharmony_ci else 58562306a36Sopenharmony_ci goto eob_clone_chain; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci break; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cieob_clone_chain: 59362306a36Sopenharmony_ci for (i = 0; i < sge_chain_count; i++) { 59462306a36Sopenharmony_ci if (is_scsiio_req) 59562306a36Sopenharmony_ci _base_clone_to_sys_mem(dst_chain_addr[i], 59662306a36Sopenharmony_ci src_chain_addr[i], ioc->request_sz); 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci/** 60162306a36Sopenharmony_ci * mpt3sas_remove_dead_ioc_func - kthread context to remove dead ioc 60262306a36Sopenharmony_ci * @arg: input argument, used to derive ioc 60362306a36Sopenharmony_ci * 60462306a36Sopenharmony_ci * Return: 60562306a36Sopenharmony_ci * 0 if controller is removed from pci subsystem. 60662306a36Sopenharmony_ci * -1 for other case. 60762306a36Sopenharmony_ci */ 60862306a36Sopenharmony_cistatic int mpt3sas_remove_dead_ioc_func(void *arg) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = (struct MPT3SAS_ADAPTER *)arg; 61162306a36Sopenharmony_ci struct pci_dev *pdev; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (!ioc) 61462306a36Sopenharmony_ci return -1; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci pdev = ioc->pdev; 61762306a36Sopenharmony_ci if (!pdev) 61862306a36Sopenharmony_ci return -1; 61962306a36Sopenharmony_ci pci_stop_and_remove_bus_device_locked(pdev); 62062306a36Sopenharmony_ci return 0; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci/** 62462306a36Sopenharmony_ci * _base_sync_drv_fw_timestamp - Sync Drive-Fw TimeStamp. 62562306a36Sopenharmony_ci * @ioc: Per Adapter Object 62662306a36Sopenharmony_ci * 62762306a36Sopenharmony_ci * Return: nothing. 62862306a36Sopenharmony_ci */ 62962306a36Sopenharmony_cistatic void _base_sync_drv_fw_timestamp(struct MPT3SAS_ADAPTER *ioc) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci Mpi26IoUnitControlRequest_t *mpi_request; 63262306a36Sopenharmony_ci Mpi26IoUnitControlReply_t *mpi_reply; 63362306a36Sopenharmony_ci u16 smid; 63462306a36Sopenharmony_ci ktime_t current_time; 63562306a36Sopenharmony_ci u64 TimeStamp = 0; 63662306a36Sopenharmony_ci u8 issue_reset = 0; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci mutex_lock(&ioc->scsih_cmds.mutex); 63962306a36Sopenharmony_ci if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) { 64062306a36Sopenharmony_ci ioc_err(ioc, "scsih_cmd in use %s\n", __func__); 64162306a36Sopenharmony_ci goto out; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci ioc->scsih_cmds.status = MPT3_CMD_PENDING; 64462306a36Sopenharmony_ci smid = mpt3sas_base_get_smid(ioc, ioc->scsih_cb_idx); 64562306a36Sopenharmony_ci if (!smid) { 64662306a36Sopenharmony_ci ioc_err(ioc, "Failed obtaining a smid %s\n", __func__); 64762306a36Sopenharmony_ci ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; 64862306a36Sopenharmony_ci goto out; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); 65162306a36Sopenharmony_ci ioc->scsih_cmds.smid = smid; 65262306a36Sopenharmony_ci memset(mpi_request, 0, sizeof(Mpi26IoUnitControlRequest_t)); 65362306a36Sopenharmony_ci mpi_request->Function = MPI2_FUNCTION_IO_UNIT_CONTROL; 65462306a36Sopenharmony_ci mpi_request->Operation = MPI26_CTRL_OP_SET_IOC_PARAMETER; 65562306a36Sopenharmony_ci mpi_request->IOCParameter = MPI26_SET_IOC_PARAMETER_SYNC_TIMESTAMP; 65662306a36Sopenharmony_ci current_time = ktime_get_real(); 65762306a36Sopenharmony_ci TimeStamp = ktime_to_ms(current_time); 65862306a36Sopenharmony_ci mpi_request->Reserved7 = cpu_to_le32(TimeStamp >> 32); 65962306a36Sopenharmony_ci mpi_request->IOCParameterValue = cpu_to_le32(TimeStamp & 0xFFFFFFFF); 66062306a36Sopenharmony_ci init_completion(&ioc->scsih_cmds.done); 66162306a36Sopenharmony_ci ioc->put_smid_default(ioc, smid); 66262306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, 66362306a36Sopenharmony_ci "Io Unit Control Sync TimeStamp (sending), @time %lld ms\n", 66462306a36Sopenharmony_ci TimeStamp)); 66562306a36Sopenharmony_ci wait_for_completion_timeout(&ioc->scsih_cmds.done, 66662306a36Sopenharmony_ci MPT3SAS_TIMESYNC_TIMEOUT_SECONDS*HZ); 66762306a36Sopenharmony_ci if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { 66862306a36Sopenharmony_ci mpt3sas_check_cmd_timeout(ioc, 66962306a36Sopenharmony_ci ioc->scsih_cmds.status, mpi_request, 67062306a36Sopenharmony_ci sizeof(Mpi2SasIoUnitControlRequest_t)/4, issue_reset); 67162306a36Sopenharmony_ci goto issue_host_reset; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) { 67462306a36Sopenharmony_ci mpi_reply = ioc->scsih_cmds.reply; 67562306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, 67662306a36Sopenharmony_ci "Io Unit Control sync timestamp (complete): ioc_status(0x%04x), loginfo(0x%08x)\n", 67762306a36Sopenharmony_ci le16_to_cpu(mpi_reply->IOCStatus), 67862306a36Sopenharmony_ci le32_to_cpu(mpi_reply->IOCLogInfo))); 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ciissue_host_reset: 68162306a36Sopenharmony_ci if (issue_reset) 68262306a36Sopenharmony_ci mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); 68362306a36Sopenharmony_ci ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; 68462306a36Sopenharmony_ciout: 68562306a36Sopenharmony_ci mutex_unlock(&ioc->scsih_cmds.mutex); 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci/** 68962306a36Sopenharmony_ci * _base_fault_reset_work - workq handling ioc fault conditions 69062306a36Sopenharmony_ci * @work: input argument, used to derive ioc 69162306a36Sopenharmony_ci * 69262306a36Sopenharmony_ci * Context: sleep. 69362306a36Sopenharmony_ci */ 69462306a36Sopenharmony_cistatic void 69562306a36Sopenharmony_ci_base_fault_reset_work(struct work_struct *work) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = 69862306a36Sopenharmony_ci container_of(work, struct MPT3SAS_ADAPTER, fault_reset_work.work); 69962306a36Sopenharmony_ci unsigned long flags; 70062306a36Sopenharmony_ci u32 doorbell; 70162306a36Sopenharmony_ci int rc; 70262306a36Sopenharmony_ci struct task_struct *p; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); 70662306a36Sopenharmony_ci if ((ioc->shost_recovery && (ioc->ioc_coredump_loop == 0)) || 70762306a36Sopenharmony_ci ioc->pci_error_recovery) 70862306a36Sopenharmony_ci goto rearm_timer; 70962306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci doorbell = mpt3sas_base_get_iocstate(ioc, 0); 71262306a36Sopenharmony_ci if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_MASK) { 71362306a36Sopenharmony_ci ioc_err(ioc, "SAS host is non-operational !!!!\n"); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* It may be possible that EEH recovery can resolve some of 71662306a36Sopenharmony_ci * pci bus failure issues rather removing the dead ioc function 71762306a36Sopenharmony_ci * by considering controller is in a non-operational state. So 71862306a36Sopenharmony_ci * here priority is given to the EEH recovery. If it doesn't 71962306a36Sopenharmony_ci * not resolve this issue, mpt3sas driver will consider this 72062306a36Sopenharmony_ci * controller to non-operational state and remove the dead ioc 72162306a36Sopenharmony_ci * function. 72262306a36Sopenharmony_ci */ 72362306a36Sopenharmony_ci if (ioc->non_operational_loop++ < 5) { 72462306a36Sopenharmony_ci spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, 72562306a36Sopenharmony_ci flags); 72662306a36Sopenharmony_ci goto rearm_timer; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci /* 73062306a36Sopenharmony_ci * Call _scsih_flush_pending_cmds callback so that we flush all 73162306a36Sopenharmony_ci * pending commands back to OS. This call is required to avoid 73262306a36Sopenharmony_ci * deadlock at block layer. Dead IOC will fail to do diag reset, 73362306a36Sopenharmony_ci * and this call is safe since dead ioc will never return any 73462306a36Sopenharmony_ci * command back from HW. 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_ci mpt3sas_base_pause_mq_polling(ioc); 73762306a36Sopenharmony_ci ioc->schedule_dead_ioc_flush_running_cmds(ioc); 73862306a36Sopenharmony_ci /* 73962306a36Sopenharmony_ci * Set remove_host flag early since kernel thread will 74062306a36Sopenharmony_ci * take some time to execute. 74162306a36Sopenharmony_ci */ 74262306a36Sopenharmony_ci ioc->remove_host = 1; 74362306a36Sopenharmony_ci /*Remove the Dead Host */ 74462306a36Sopenharmony_ci p = kthread_run(mpt3sas_remove_dead_ioc_func, ioc, 74562306a36Sopenharmony_ci "%s_dead_ioc_%d", ioc->driver_name, ioc->id); 74662306a36Sopenharmony_ci if (IS_ERR(p)) 74762306a36Sopenharmony_ci ioc_err(ioc, "%s: Running mpt3sas_dead_ioc thread failed !!!!\n", 74862306a36Sopenharmony_ci __func__); 74962306a36Sopenharmony_ci else 75062306a36Sopenharmony_ci ioc_err(ioc, "%s: Running mpt3sas_dead_ioc thread success !!!!\n", 75162306a36Sopenharmony_ci __func__); 75262306a36Sopenharmony_ci return; /* don't rearm timer */ 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_COREDUMP) { 75662306a36Sopenharmony_ci u8 timeout = (ioc->manu_pg11.CoreDumpTOSec) ? 75762306a36Sopenharmony_ci ioc->manu_pg11.CoreDumpTOSec : 75862306a36Sopenharmony_ci MPT3SAS_DEFAULT_COREDUMP_TIMEOUT_SECONDS; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci timeout /= (FAULT_POLLING_INTERVAL/1000); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (ioc->ioc_coredump_loop == 0) { 76362306a36Sopenharmony_ci mpt3sas_print_coredump_info(ioc, 76462306a36Sopenharmony_ci doorbell & MPI2_DOORBELL_DATA_MASK); 76562306a36Sopenharmony_ci /* do not accept any IOs and disable the interrupts */ 76662306a36Sopenharmony_ci spin_lock_irqsave( 76762306a36Sopenharmony_ci &ioc->ioc_reset_in_progress_lock, flags); 76862306a36Sopenharmony_ci ioc->shost_recovery = 1; 76962306a36Sopenharmony_ci spin_unlock_irqrestore( 77062306a36Sopenharmony_ci &ioc->ioc_reset_in_progress_lock, flags); 77162306a36Sopenharmony_ci mpt3sas_base_mask_interrupts(ioc); 77262306a36Sopenharmony_ci mpt3sas_base_pause_mq_polling(ioc); 77362306a36Sopenharmony_ci _base_clear_outstanding_commands(ioc); 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci ioc_info(ioc, "%s: CoreDump loop %d.", 77762306a36Sopenharmony_ci __func__, ioc->ioc_coredump_loop); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* Wait until CoreDump completes or times out */ 78062306a36Sopenharmony_ci if (ioc->ioc_coredump_loop++ < timeout) { 78162306a36Sopenharmony_ci spin_lock_irqsave( 78262306a36Sopenharmony_ci &ioc->ioc_reset_in_progress_lock, flags); 78362306a36Sopenharmony_ci goto rearm_timer; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (ioc->ioc_coredump_loop) { 78862306a36Sopenharmony_ci if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_COREDUMP) 78962306a36Sopenharmony_ci ioc_err(ioc, "%s: CoreDump completed. LoopCount: %d", 79062306a36Sopenharmony_ci __func__, ioc->ioc_coredump_loop); 79162306a36Sopenharmony_ci else 79262306a36Sopenharmony_ci ioc_err(ioc, "%s: CoreDump Timed out. LoopCount: %d", 79362306a36Sopenharmony_ci __func__, ioc->ioc_coredump_loop); 79462306a36Sopenharmony_ci ioc->ioc_coredump_loop = MPT3SAS_COREDUMP_LOOP_DONE; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci ioc->non_operational_loop = 0; 79762306a36Sopenharmony_ci if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) { 79862306a36Sopenharmony_ci rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); 79962306a36Sopenharmony_ci ioc_warn(ioc, "%s: hard reset: %s\n", 80062306a36Sopenharmony_ci __func__, rc == 0 ? "success" : "failed"); 80162306a36Sopenharmony_ci doorbell = mpt3sas_base_get_iocstate(ioc, 0); 80262306a36Sopenharmony_ci if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { 80362306a36Sopenharmony_ci mpt3sas_print_fault_code(ioc, doorbell & 80462306a36Sopenharmony_ci MPI2_DOORBELL_DATA_MASK); 80562306a36Sopenharmony_ci } else if ((doorbell & MPI2_IOC_STATE_MASK) == 80662306a36Sopenharmony_ci MPI2_IOC_STATE_COREDUMP) 80762306a36Sopenharmony_ci mpt3sas_print_coredump_info(ioc, doorbell & 80862306a36Sopenharmony_ci MPI2_DOORBELL_DATA_MASK); 80962306a36Sopenharmony_ci if (rc && (doorbell & MPI2_IOC_STATE_MASK) != 81062306a36Sopenharmony_ci MPI2_IOC_STATE_OPERATIONAL) 81162306a36Sopenharmony_ci return; /* don't rearm timer */ 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci ioc->ioc_coredump_loop = 0; 81462306a36Sopenharmony_ci if (ioc->time_sync_interval && 81562306a36Sopenharmony_ci ++ioc->timestamp_update_count >= ioc->time_sync_interval) { 81662306a36Sopenharmony_ci ioc->timestamp_update_count = 0; 81762306a36Sopenharmony_ci _base_sync_drv_fw_timestamp(ioc); 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); 82062306a36Sopenharmony_ci rearm_timer: 82162306a36Sopenharmony_ci if (ioc->fault_reset_work_q) 82262306a36Sopenharmony_ci queue_delayed_work(ioc->fault_reset_work_q, 82362306a36Sopenharmony_ci &ioc->fault_reset_work, 82462306a36Sopenharmony_ci msecs_to_jiffies(FAULT_POLLING_INTERVAL)); 82562306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci/** 82962306a36Sopenharmony_ci * mpt3sas_base_start_watchdog - start the fault_reset_work_q 83062306a36Sopenharmony_ci * @ioc: per adapter object 83162306a36Sopenharmony_ci * 83262306a36Sopenharmony_ci * Context: sleep. 83362306a36Sopenharmony_ci */ 83462306a36Sopenharmony_civoid 83562306a36Sopenharmony_cimpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci unsigned long flags; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (ioc->fault_reset_work_q) 84062306a36Sopenharmony_ci return; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci ioc->timestamp_update_count = 0; 84362306a36Sopenharmony_ci /* initialize fault polling */ 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); 84662306a36Sopenharmony_ci snprintf(ioc->fault_reset_work_q_name, 84762306a36Sopenharmony_ci sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status", 84862306a36Sopenharmony_ci ioc->driver_name, ioc->id); 84962306a36Sopenharmony_ci ioc->fault_reset_work_q = 85062306a36Sopenharmony_ci create_singlethread_workqueue(ioc->fault_reset_work_q_name); 85162306a36Sopenharmony_ci if (!ioc->fault_reset_work_q) { 85262306a36Sopenharmony_ci ioc_err(ioc, "%s: failed (line=%d)\n", __func__, __LINE__); 85362306a36Sopenharmony_ci return; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); 85662306a36Sopenharmony_ci if (ioc->fault_reset_work_q) 85762306a36Sopenharmony_ci queue_delayed_work(ioc->fault_reset_work_q, 85862306a36Sopenharmony_ci &ioc->fault_reset_work, 85962306a36Sopenharmony_ci msecs_to_jiffies(FAULT_POLLING_INTERVAL)); 86062306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci/** 86462306a36Sopenharmony_ci * mpt3sas_base_stop_watchdog - stop the fault_reset_work_q 86562306a36Sopenharmony_ci * @ioc: per adapter object 86662306a36Sopenharmony_ci * 86762306a36Sopenharmony_ci * Context: sleep. 86862306a36Sopenharmony_ci */ 86962306a36Sopenharmony_civoid 87062306a36Sopenharmony_cimpt3sas_base_stop_watchdog(struct MPT3SAS_ADAPTER *ioc) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci unsigned long flags; 87362306a36Sopenharmony_ci struct workqueue_struct *wq; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); 87662306a36Sopenharmony_ci wq = ioc->fault_reset_work_q; 87762306a36Sopenharmony_ci ioc->fault_reset_work_q = NULL; 87862306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); 87962306a36Sopenharmony_ci if (wq) { 88062306a36Sopenharmony_ci if (!cancel_delayed_work_sync(&ioc->fault_reset_work)) 88162306a36Sopenharmony_ci flush_workqueue(wq); 88262306a36Sopenharmony_ci destroy_workqueue(wq); 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci/** 88762306a36Sopenharmony_ci * mpt3sas_base_fault_info - verbose translation of firmware FAULT code 88862306a36Sopenharmony_ci * @ioc: per adapter object 88962306a36Sopenharmony_ci * @fault_code: fault code 89062306a36Sopenharmony_ci */ 89162306a36Sopenharmony_civoid 89262306a36Sopenharmony_cimpt3sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc, u16 fault_code) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci ioc_err(ioc, "fault_state(0x%04x)!\n", fault_code); 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci/** 89862306a36Sopenharmony_ci * mpt3sas_base_coredump_info - verbose translation of firmware CoreDump state 89962306a36Sopenharmony_ci * @ioc: per adapter object 90062306a36Sopenharmony_ci * @fault_code: fault code 90162306a36Sopenharmony_ci * 90262306a36Sopenharmony_ci * Return: nothing. 90362306a36Sopenharmony_ci */ 90462306a36Sopenharmony_civoid 90562306a36Sopenharmony_cimpt3sas_base_coredump_info(struct MPT3SAS_ADAPTER *ioc, u16 fault_code) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci ioc_err(ioc, "coredump_state(0x%04x)!\n", fault_code); 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci/** 91162306a36Sopenharmony_ci * mpt3sas_base_wait_for_coredump_completion - Wait until coredump 91262306a36Sopenharmony_ci * completes or times out 91362306a36Sopenharmony_ci * @ioc: per adapter object 91462306a36Sopenharmony_ci * @caller: caller function name 91562306a36Sopenharmony_ci * 91662306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 91762306a36Sopenharmony_ci */ 91862306a36Sopenharmony_ciint 91962306a36Sopenharmony_cimpt3sas_base_wait_for_coredump_completion(struct MPT3SAS_ADAPTER *ioc, 92062306a36Sopenharmony_ci const char *caller) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci u8 timeout = (ioc->manu_pg11.CoreDumpTOSec) ? 92362306a36Sopenharmony_ci ioc->manu_pg11.CoreDumpTOSec : 92462306a36Sopenharmony_ci MPT3SAS_DEFAULT_COREDUMP_TIMEOUT_SECONDS; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci int ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_FAULT, 92762306a36Sopenharmony_ci timeout); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (ioc_state) 93062306a36Sopenharmony_ci ioc_err(ioc, 93162306a36Sopenharmony_ci "%s: CoreDump timed out. (ioc_state=0x%x)\n", 93262306a36Sopenharmony_ci caller, ioc_state); 93362306a36Sopenharmony_ci else 93462306a36Sopenharmony_ci ioc_info(ioc, 93562306a36Sopenharmony_ci "%s: CoreDump completed. (ioc_state=0x%x)\n", 93662306a36Sopenharmony_ci caller, ioc_state); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci return ioc_state; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci/** 94262306a36Sopenharmony_ci * mpt3sas_halt_firmware - halt's mpt controller firmware 94362306a36Sopenharmony_ci * @ioc: per adapter object 94462306a36Sopenharmony_ci * 94562306a36Sopenharmony_ci * For debugging timeout related issues. Writing 0xCOFFEE00 94662306a36Sopenharmony_ci * to the doorbell register will halt controller firmware. With 94762306a36Sopenharmony_ci * the purpose to stop both driver and firmware, the enduser can 94862306a36Sopenharmony_ci * obtain a ring buffer from controller UART. 94962306a36Sopenharmony_ci */ 95062306a36Sopenharmony_civoid 95162306a36Sopenharmony_cimpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc) 95262306a36Sopenharmony_ci{ 95362306a36Sopenharmony_ci u32 doorbell; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci if (!ioc->fwfault_debug) 95662306a36Sopenharmony_ci return; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci dump_stack(); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci doorbell = ioc->base_readl_ext_retry(&ioc->chip->Doorbell); 96162306a36Sopenharmony_ci if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { 96262306a36Sopenharmony_ci mpt3sas_print_fault_code(ioc, doorbell & 96362306a36Sopenharmony_ci MPI2_DOORBELL_DATA_MASK); 96462306a36Sopenharmony_ci } else if ((doorbell & MPI2_IOC_STATE_MASK) == 96562306a36Sopenharmony_ci MPI2_IOC_STATE_COREDUMP) { 96662306a36Sopenharmony_ci mpt3sas_print_coredump_info(ioc, doorbell & 96762306a36Sopenharmony_ci MPI2_DOORBELL_DATA_MASK); 96862306a36Sopenharmony_ci } else { 96962306a36Sopenharmony_ci writel(0xC0FFEE00, &ioc->chip->Doorbell); 97062306a36Sopenharmony_ci ioc_err(ioc, "Firmware is halted due to command timeout\n"); 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci if (ioc->fwfault_debug == 2) 97462306a36Sopenharmony_ci for (;;) 97562306a36Sopenharmony_ci ; 97662306a36Sopenharmony_ci else 97762306a36Sopenharmony_ci panic("panic in %s\n", __func__); 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci/** 98162306a36Sopenharmony_ci * _base_sas_ioc_info - verbose translation of the ioc status 98262306a36Sopenharmony_ci * @ioc: per adapter object 98362306a36Sopenharmony_ci * @mpi_reply: reply mf payload returned from firmware 98462306a36Sopenharmony_ci * @request_hdr: request mf 98562306a36Sopenharmony_ci */ 98662306a36Sopenharmony_cistatic void 98762306a36Sopenharmony_ci_base_sas_ioc_info(struct MPT3SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, 98862306a36Sopenharmony_ci MPI2RequestHeader_t *request_hdr) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & 99162306a36Sopenharmony_ci MPI2_IOCSTATUS_MASK; 99262306a36Sopenharmony_ci char *desc = NULL; 99362306a36Sopenharmony_ci u16 frame_sz; 99462306a36Sopenharmony_ci char *func_str = NULL; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci /* SCSI_IO, RAID_PASS are handled from _scsih_scsi_ioc_info */ 99762306a36Sopenharmony_ci if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || 99862306a36Sopenharmony_ci request_hdr->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || 99962306a36Sopenharmony_ci request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION) 100062306a36Sopenharmony_ci return; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) 100362306a36Sopenharmony_ci return; 100462306a36Sopenharmony_ci /* 100562306a36Sopenharmony_ci * Older Firmware version doesn't support driver trigger pages. 100662306a36Sopenharmony_ci * So, skip displaying 'config invalid type' type 100762306a36Sopenharmony_ci * of error message. 100862306a36Sopenharmony_ci */ 100962306a36Sopenharmony_ci if (request_hdr->Function == MPI2_FUNCTION_CONFIG) { 101062306a36Sopenharmony_ci Mpi2ConfigRequest_t *rqst = (Mpi2ConfigRequest_t *)request_hdr; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if ((rqst->ExtPageType == 101362306a36Sopenharmony_ci MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER) && 101462306a36Sopenharmony_ci !(ioc->logging_level & MPT_DEBUG_CONFIG)) { 101562306a36Sopenharmony_ci return; 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci switch (ioc_status) { 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci/**************************************************************************** 102262306a36Sopenharmony_ci* Common IOCStatus values for all replies 102362306a36Sopenharmony_ci****************************************************************************/ 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci case MPI2_IOCSTATUS_INVALID_FUNCTION: 102662306a36Sopenharmony_ci desc = "invalid function"; 102762306a36Sopenharmony_ci break; 102862306a36Sopenharmony_ci case MPI2_IOCSTATUS_BUSY: 102962306a36Sopenharmony_ci desc = "busy"; 103062306a36Sopenharmony_ci break; 103162306a36Sopenharmony_ci case MPI2_IOCSTATUS_INVALID_SGL: 103262306a36Sopenharmony_ci desc = "invalid sgl"; 103362306a36Sopenharmony_ci break; 103462306a36Sopenharmony_ci case MPI2_IOCSTATUS_INTERNAL_ERROR: 103562306a36Sopenharmony_ci desc = "internal error"; 103662306a36Sopenharmony_ci break; 103762306a36Sopenharmony_ci case MPI2_IOCSTATUS_INVALID_VPID: 103862306a36Sopenharmony_ci desc = "invalid vpid"; 103962306a36Sopenharmony_ci break; 104062306a36Sopenharmony_ci case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: 104162306a36Sopenharmony_ci desc = "insufficient resources"; 104262306a36Sopenharmony_ci break; 104362306a36Sopenharmony_ci case MPI2_IOCSTATUS_INSUFFICIENT_POWER: 104462306a36Sopenharmony_ci desc = "insufficient power"; 104562306a36Sopenharmony_ci break; 104662306a36Sopenharmony_ci case MPI2_IOCSTATUS_INVALID_FIELD: 104762306a36Sopenharmony_ci desc = "invalid field"; 104862306a36Sopenharmony_ci break; 104962306a36Sopenharmony_ci case MPI2_IOCSTATUS_INVALID_STATE: 105062306a36Sopenharmony_ci desc = "invalid state"; 105162306a36Sopenharmony_ci break; 105262306a36Sopenharmony_ci case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED: 105362306a36Sopenharmony_ci desc = "op state not supported"; 105462306a36Sopenharmony_ci break; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci/**************************************************************************** 105762306a36Sopenharmony_ci* Config IOCStatus values 105862306a36Sopenharmony_ci****************************************************************************/ 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci case MPI2_IOCSTATUS_CONFIG_INVALID_ACTION: 106162306a36Sopenharmony_ci desc = "config invalid action"; 106262306a36Sopenharmony_ci break; 106362306a36Sopenharmony_ci case MPI2_IOCSTATUS_CONFIG_INVALID_TYPE: 106462306a36Sopenharmony_ci desc = "config invalid type"; 106562306a36Sopenharmony_ci break; 106662306a36Sopenharmony_ci case MPI2_IOCSTATUS_CONFIG_INVALID_PAGE: 106762306a36Sopenharmony_ci desc = "config invalid page"; 106862306a36Sopenharmony_ci break; 106962306a36Sopenharmony_ci case MPI2_IOCSTATUS_CONFIG_INVALID_DATA: 107062306a36Sopenharmony_ci desc = "config invalid data"; 107162306a36Sopenharmony_ci break; 107262306a36Sopenharmony_ci case MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS: 107362306a36Sopenharmony_ci desc = "config no defaults"; 107462306a36Sopenharmony_ci break; 107562306a36Sopenharmony_ci case MPI2_IOCSTATUS_CONFIG_CANT_COMMIT: 107662306a36Sopenharmony_ci desc = "config can't commit"; 107762306a36Sopenharmony_ci break; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci/**************************************************************************** 108062306a36Sopenharmony_ci* SCSI IO Reply 108162306a36Sopenharmony_ci****************************************************************************/ 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: 108462306a36Sopenharmony_ci case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: 108562306a36Sopenharmony_ci case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: 108662306a36Sopenharmony_ci case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: 108762306a36Sopenharmony_ci case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: 108862306a36Sopenharmony_ci case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: 108962306a36Sopenharmony_ci case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: 109062306a36Sopenharmony_ci case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: 109162306a36Sopenharmony_ci case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: 109262306a36Sopenharmony_ci case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: 109362306a36Sopenharmony_ci case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: 109462306a36Sopenharmony_ci case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: 109562306a36Sopenharmony_ci break; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci/**************************************************************************** 109862306a36Sopenharmony_ci* For use by SCSI Initiator and SCSI Target end-to-end data protection 109962306a36Sopenharmony_ci****************************************************************************/ 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: 110262306a36Sopenharmony_ci desc = "eedp guard error"; 110362306a36Sopenharmony_ci break; 110462306a36Sopenharmony_ci case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: 110562306a36Sopenharmony_ci desc = "eedp ref tag error"; 110662306a36Sopenharmony_ci break; 110762306a36Sopenharmony_ci case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: 110862306a36Sopenharmony_ci desc = "eedp app tag error"; 110962306a36Sopenharmony_ci break; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci/**************************************************************************** 111262306a36Sopenharmony_ci* SCSI Target values 111362306a36Sopenharmony_ci****************************************************************************/ 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci case MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX: 111662306a36Sopenharmony_ci desc = "target invalid io index"; 111762306a36Sopenharmony_ci break; 111862306a36Sopenharmony_ci case MPI2_IOCSTATUS_TARGET_ABORTED: 111962306a36Sopenharmony_ci desc = "target aborted"; 112062306a36Sopenharmony_ci break; 112162306a36Sopenharmony_ci case MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: 112262306a36Sopenharmony_ci desc = "target no conn retryable"; 112362306a36Sopenharmony_ci break; 112462306a36Sopenharmony_ci case MPI2_IOCSTATUS_TARGET_NO_CONNECTION: 112562306a36Sopenharmony_ci desc = "target no connection"; 112662306a36Sopenharmony_ci break; 112762306a36Sopenharmony_ci case MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: 112862306a36Sopenharmony_ci desc = "target xfer count mismatch"; 112962306a36Sopenharmony_ci break; 113062306a36Sopenharmony_ci case MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: 113162306a36Sopenharmony_ci desc = "target data offset error"; 113262306a36Sopenharmony_ci break; 113362306a36Sopenharmony_ci case MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: 113462306a36Sopenharmony_ci desc = "target too much write data"; 113562306a36Sopenharmony_ci break; 113662306a36Sopenharmony_ci case MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT: 113762306a36Sopenharmony_ci desc = "target iu too short"; 113862306a36Sopenharmony_ci break; 113962306a36Sopenharmony_ci case MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: 114062306a36Sopenharmony_ci desc = "target ack nak timeout"; 114162306a36Sopenharmony_ci break; 114262306a36Sopenharmony_ci case MPI2_IOCSTATUS_TARGET_NAK_RECEIVED: 114362306a36Sopenharmony_ci desc = "target nak received"; 114462306a36Sopenharmony_ci break; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci/**************************************************************************** 114762306a36Sopenharmony_ci* Serial Attached SCSI values 114862306a36Sopenharmony_ci****************************************************************************/ 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci case MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED: 115162306a36Sopenharmony_ci desc = "smp request failed"; 115262306a36Sopenharmony_ci break; 115362306a36Sopenharmony_ci case MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN: 115462306a36Sopenharmony_ci desc = "smp data overrun"; 115562306a36Sopenharmony_ci break; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci/**************************************************************************** 115862306a36Sopenharmony_ci* Diagnostic Buffer Post / Diagnostic Release values 115962306a36Sopenharmony_ci****************************************************************************/ 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci case MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED: 116262306a36Sopenharmony_ci desc = "diagnostic released"; 116362306a36Sopenharmony_ci break; 116462306a36Sopenharmony_ci default: 116562306a36Sopenharmony_ci break; 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (!desc) 116962306a36Sopenharmony_ci return; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci switch (request_hdr->Function) { 117262306a36Sopenharmony_ci case MPI2_FUNCTION_CONFIG: 117362306a36Sopenharmony_ci frame_sz = sizeof(Mpi2ConfigRequest_t) + ioc->sge_size; 117462306a36Sopenharmony_ci func_str = "config_page"; 117562306a36Sopenharmony_ci break; 117662306a36Sopenharmony_ci case MPI2_FUNCTION_SCSI_TASK_MGMT: 117762306a36Sopenharmony_ci frame_sz = sizeof(Mpi2SCSITaskManagementRequest_t); 117862306a36Sopenharmony_ci func_str = "task_mgmt"; 117962306a36Sopenharmony_ci break; 118062306a36Sopenharmony_ci case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: 118162306a36Sopenharmony_ci frame_sz = sizeof(Mpi2SasIoUnitControlRequest_t); 118262306a36Sopenharmony_ci func_str = "sas_iounit_ctl"; 118362306a36Sopenharmony_ci break; 118462306a36Sopenharmony_ci case MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR: 118562306a36Sopenharmony_ci frame_sz = sizeof(Mpi2SepRequest_t); 118662306a36Sopenharmony_ci func_str = "enclosure"; 118762306a36Sopenharmony_ci break; 118862306a36Sopenharmony_ci case MPI2_FUNCTION_IOC_INIT: 118962306a36Sopenharmony_ci frame_sz = sizeof(Mpi2IOCInitRequest_t); 119062306a36Sopenharmony_ci func_str = "ioc_init"; 119162306a36Sopenharmony_ci break; 119262306a36Sopenharmony_ci case MPI2_FUNCTION_PORT_ENABLE: 119362306a36Sopenharmony_ci frame_sz = sizeof(Mpi2PortEnableRequest_t); 119462306a36Sopenharmony_ci func_str = "port_enable"; 119562306a36Sopenharmony_ci break; 119662306a36Sopenharmony_ci case MPI2_FUNCTION_SMP_PASSTHROUGH: 119762306a36Sopenharmony_ci frame_sz = sizeof(Mpi2SmpPassthroughRequest_t) + ioc->sge_size; 119862306a36Sopenharmony_ci func_str = "smp_passthru"; 119962306a36Sopenharmony_ci break; 120062306a36Sopenharmony_ci case MPI2_FUNCTION_NVME_ENCAPSULATED: 120162306a36Sopenharmony_ci frame_sz = sizeof(Mpi26NVMeEncapsulatedRequest_t) + 120262306a36Sopenharmony_ci ioc->sge_size; 120362306a36Sopenharmony_ci func_str = "nvme_encapsulated"; 120462306a36Sopenharmony_ci break; 120562306a36Sopenharmony_ci default: 120662306a36Sopenharmony_ci frame_sz = 32; 120762306a36Sopenharmony_ci func_str = "unknown"; 120862306a36Sopenharmony_ci break; 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci ioc_warn(ioc, "ioc_status: %s(0x%04x), request(0x%p),(%s)\n", 121262306a36Sopenharmony_ci desc, ioc_status, request_hdr, func_str); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci _debug_dump_mf(request_hdr, frame_sz/4); 121562306a36Sopenharmony_ci} 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci/** 121862306a36Sopenharmony_ci * _base_display_event_data - verbose translation of firmware asyn events 121962306a36Sopenharmony_ci * @ioc: per adapter object 122062306a36Sopenharmony_ci * @mpi_reply: reply mf payload returned from firmware 122162306a36Sopenharmony_ci */ 122262306a36Sopenharmony_cistatic void 122362306a36Sopenharmony_ci_base_display_event_data(struct MPT3SAS_ADAPTER *ioc, 122462306a36Sopenharmony_ci Mpi2EventNotificationReply_t *mpi_reply) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci char *desc = NULL; 122762306a36Sopenharmony_ci u16 event; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci if (!(ioc->logging_level & MPT_DEBUG_EVENTS)) 123062306a36Sopenharmony_ci return; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci event = le16_to_cpu(mpi_reply->Event); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci switch (event) { 123562306a36Sopenharmony_ci case MPI2_EVENT_LOG_DATA: 123662306a36Sopenharmony_ci desc = "Log Data"; 123762306a36Sopenharmony_ci break; 123862306a36Sopenharmony_ci case MPI2_EVENT_STATE_CHANGE: 123962306a36Sopenharmony_ci desc = "Status Change"; 124062306a36Sopenharmony_ci break; 124162306a36Sopenharmony_ci case MPI2_EVENT_HARD_RESET_RECEIVED: 124262306a36Sopenharmony_ci desc = "Hard Reset Received"; 124362306a36Sopenharmony_ci break; 124462306a36Sopenharmony_ci case MPI2_EVENT_EVENT_CHANGE: 124562306a36Sopenharmony_ci desc = "Event Change"; 124662306a36Sopenharmony_ci break; 124762306a36Sopenharmony_ci case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: 124862306a36Sopenharmony_ci desc = "Device Status Change"; 124962306a36Sopenharmony_ci break; 125062306a36Sopenharmony_ci case MPI2_EVENT_IR_OPERATION_STATUS: 125162306a36Sopenharmony_ci if (!ioc->hide_ir_msg) 125262306a36Sopenharmony_ci desc = "IR Operation Status"; 125362306a36Sopenharmony_ci break; 125462306a36Sopenharmony_ci case MPI2_EVENT_SAS_DISCOVERY: 125562306a36Sopenharmony_ci { 125662306a36Sopenharmony_ci Mpi2EventDataSasDiscovery_t *event_data = 125762306a36Sopenharmony_ci (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData; 125862306a36Sopenharmony_ci ioc_info(ioc, "Discovery: (%s)", 125962306a36Sopenharmony_ci event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED ? 126062306a36Sopenharmony_ci "start" : "stop"); 126162306a36Sopenharmony_ci if (event_data->DiscoveryStatus) 126262306a36Sopenharmony_ci pr_cont(" discovery_status(0x%08x)", 126362306a36Sopenharmony_ci le32_to_cpu(event_data->DiscoveryStatus)); 126462306a36Sopenharmony_ci pr_cont("\n"); 126562306a36Sopenharmony_ci return; 126662306a36Sopenharmony_ci } 126762306a36Sopenharmony_ci case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: 126862306a36Sopenharmony_ci desc = "SAS Broadcast Primitive"; 126962306a36Sopenharmony_ci break; 127062306a36Sopenharmony_ci case MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: 127162306a36Sopenharmony_ci desc = "SAS Init Device Status Change"; 127262306a36Sopenharmony_ci break; 127362306a36Sopenharmony_ci case MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW: 127462306a36Sopenharmony_ci desc = "SAS Init Table Overflow"; 127562306a36Sopenharmony_ci break; 127662306a36Sopenharmony_ci case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: 127762306a36Sopenharmony_ci desc = "SAS Topology Change List"; 127862306a36Sopenharmony_ci break; 127962306a36Sopenharmony_ci case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: 128062306a36Sopenharmony_ci desc = "SAS Enclosure Device Status Change"; 128162306a36Sopenharmony_ci break; 128262306a36Sopenharmony_ci case MPI2_EVENT_IR_VOLUME: 128362306a36Sopenharmony_ci if (!ioc->hide_ir_msg) 128462306a36Sopenharmony_ci desc = "IR Volume"; 128562306a36Sopenharmony_ci break; 128662306a36Sopenharmony_ci case MPI2_EVENT_IR_PHYSICAL_DISK: 128762306a36Sopenharmony_ci if (!ioc->hide_ir_msg) 128862306a36Sopenharmony_ci desc = "IR Physical Disk"; 128962306a36Sopenharmony_ci break; 129062306a36Sopenharmony_ci case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: 129162306a36Sopenharmony_ci if (!ioc->hide_ir_msg) 129262306a36Sopenharmony_ci desc = "IR Configuration Change List"; 129362306a36Sopenharmony_ci break; 129462306a36Sopenharmony_ci case MPI2_EVENT_LOG_ENTRY_ADDED: 129562306a36Sopenharmony_ci if (!ioc->hide_ir_msg) 129662306a36Sopenharmony_ci desc = "Log Entry Added"; 129762306a36Sopenharmony_ci break; 129862306a36Sopenharmony_ci case MPI2_EVENT_TEMP_THRESHOLD: 129962306a36Sopenharmony_ci desc = "Temperature Threshold"; 130062306a36Sopenharmony_ci break; 130162306a36Sopenharmony_ci case MPI2_EVENT_ACTIVE_CABLE_EXCEPTION: 130262306a36Sopenharmony_ci desc = "Cable Event"; 130362306a36Sopenharmony_ci break; 130462306a36Sopenharmony_ci case MPI2_EVENT_SAS_DEVICE_DISCOVERY_ERROR: 130562306a36Sopenharmony_ci desc = "SAS Device Discovery Error"; 130662306a36Sopenharmony_ci break; 130762306a36Sopenharmony_ci case MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE: 130862306a36Sopenharmony_ci desc = "PCIE Device Status Change"; 130962306a36Sopenharmony_ci break; 131062306a36Sopenharmony_ci case MPI2_EVENT_PCIE_ENUMERATION: 131162306a36Sopenharmony_ci { 131262306a36Sopenharmony_ci Mpi26EventDataPCIeEnumeration_t *event_data = 131362306a36Sopenharmony_ci (Mpi26EventDataPCIeEnumeration_t *)mpi_reply->EventData; 131462306a36Sopenharmony_ci ioc_info(ioc, "PCIE Enumeration: (%s)", 131562306a36Sopenharmony_ci event_data->ReasonCode == MPI26_EVENT_PCIE_ENUM_RC_STARTED ? 131662306a36Sopenharmony_ci "start" : "stop"); 131762306a36Sopenharmony_ci if (event_data->EnumerationStatus) 131862306a36Sopenharmony_ci pr_cont("enumeration_status(0x%08x)", 131962306a36Sopenharmony_ci le32_to_cpu(event_data->EnumerationStatus)); 132062306a36Sopenharmony_ci pr_cont("\n"); 132162306a36Sopenharmony_ci return; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: 132462306a36Sopenharmony_ci desc = "PCIE Topology Change List"; 132562306a36Sopenharmony_ci break; 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci if (!desc) 132962306a36Sopenharmony_ci return; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci ioc_info(ioc, "%s\n", desc); 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci/** 133562306a36Sopenharmony_ci * _base_sas_log_info - verbose translation of firmware log info 133662306a36Sopenharmony_ci * @ioc: per adapter object 133762306a36Sopenharmony_ci * @log_info: log info 133862306a36Sopenharmony_ci */ 133962306a36Sopenharmony_cistatic void 134062306a36Sopenharmony_ci_base_sas_log_info(struct MPT3SAS_ADAPTER *ioc, u32 log_info) 134162306a36Sopenharmony_ci{ 134262306a36Sopenharmony_ci union loginfo_type { 134362306a36Sopenharmony_ci u32 loginfo; 134462306a36Sopenharmony_ci struct { 134562306a36Sopenharmony_ci u32 subcode:16; 134662306a36Sopenharmony_ci u32 code:8; 134762306a36Sopenharmony_ci u32 originator:4; 134862306a36Sopenharmony_ci u32 bus_type:4; 134962306a36Sopenharmony_ci } dw; 135062306a36Sopenharmony_ci }; 135162306a36Sopenharmony_ci union loginfo_type sas_loginfo; 135262306a36Sopenharmony_ci char *originator_str = NULL; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci sas_loginfo.loginfo = log_info; 135562306a36Sopenharmony_ci if (sas_loginfo.dw.bus_type != 3 /*SAS*/) 135662306a36Sopenharmony_ci return; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci /* each nexus loss loginfo */ 135962306a36Sopenharmony_ci if (log_info == 0x31170000) 136062306a36Sopenharmony_ci return; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci /* eat the loginfos associated with task aborts */ 136362306a36Sopenharmony_ci if (ioc->ignore_loginfos && (log_info == 0x30050000 || log_info == 136462306a36Sopenharmony_ci 0x31140000 || log_info == 0x31130000)) 136562306a36Sopenharmony_ci return; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci switch (sas_loginfo.dw.originator) { 136862306a36Sopenharmony_ci case 0: 136962306a36Sopenharmony_ci originator_str = "IOP"; 137062306a36Sopenharmony_ci break; 137162306a36Sopenharmony_ci case 1: 137262306a36Sopenharmony_ci originator_str = "PL"; 137362306a36Sopenharmony_ci break; 137462306a36Sopenharmony_ci case 2: 137562306a36Sopenharmony_ci if (!ioc->hide_ir_msg) 137662306a36Sopenharmony_ci originator_str = "IR"; 137762306a36Sopenharmony_ci else 137862306a36Sopenharmony_ci originator_str = "WarpDrive"; 137962306a36Sopenharmony_ci break; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci ioc_warn(ioc, "log_info(0x%08x): originator(%s), code(0x%02x), sub_code(0x%04x)\n", 138362306a36Sopenharmony_ci log_info, 138462306a36Sopenharmony_ci originator_str, sas_loginfo.dw.code, sas_loginfo.dw.subcode); 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci/** 138862306a36Sopenharmony_ci * _base_display_reply_info - handle reply descriptors depending on IOC Status 138962306a36Sopenharmony_ci * @ioc: per adapter object 139062306a36Sopenharmony_ci * @smid: system request message index 139162306a36Sopenharmony_ci * @msix_index: MSIX table index supplied by the OS 139262306a36Sopenharmony_ci * @reply: reply message frame (lower 32bit addr) 139362306a36Sopenharmony_ci */ 139462306a36Sopenharmony_cistatic void 139562306a36Sopenharmony_ci_base_display_reply_info(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, 139662306a36Sopenharmony_ci u32 reply) 139762306a36Sopenharmony_ci{ 139862306a36Sopenharmony_ci MPI2DefaultReply_t *mpi_reply; 139962306a36Sopenharmony_ci u16 ioc_status; 140062306a36Sopenharmony_ci u32 loginfo = 0; 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); 140362306a36Sopenharmony_ci if (unlikely(!mpi_reply)) { 140462306a36Sopenharmony_ci ioc_err(ioc, "mpi_reply not valid at %s:%d/%s()!\n", 140562306a36Sopenharmony_ci __FILE__, __LINE__, __func__); 140662306a36Sopenharmony_ci return; 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply->IOCStatus); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci if ((ioc_status & MPI2_IOCSTATUS_MASK) && 141162306a36Sopenharmony_ci (ioc->logging_level & MPT_DEBUG_REPLY)) { 141262306a36Sopenharmony_ci _base_sas_ioc_info(ioc, mpi_reply, 141362306a36Sopenharmony_ci mpt3sas_base_get_msg_frame(ioc, smid)); 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { 141762306a36Sopenharmony_ci loginfo = le32_to_cpu(mpi_reply->IOCLogInfo); 141862306a36Sopenharmony_ci _base_sas_log_info(ioc, loginfo); 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci if (ioc_status || loginfo) { 142262306a36Sopenharmony_ci ioc_status &= MPI2_IOCSTATUS_MASK; 142362306a36Sopenharmony_ci mpt3sas_trigger_mpi(ioc, ioc_status, loginfo); 142462306a36Sopenharmony_ci } 142562306a36Sopenharmony_ci} 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci/** 142862306a36Sopenharmony_ci * mpt3sas_base_done - base internal command completion routine 142962306a36Sopenharmony_ci * @ioc: per adapter object 143062306a36Sopenharmony_ci * @smid: system request message index 143162306a36Sopenharmony_ci * @msix_index: MSIX table index supplied by the OS 143262306a36Sopenharmony_ci * @reply: reply message frame(lower 32bit addr) 143362306a36Sopenharmony_ci * 143462306a36Sopenharmony_ci * Return: 143562306a36Sopenharmony_ci * 1 meaning mf should be freed from _base_interrupt 143662306a36Sopenharmony_ci * 0 means the mf is freed from this function. 143762306a36Sopenharmony_ci */ 143862306a36Sopenharmony_ciu8 143962306a36Sopenharmony_cimpt3sas_base_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, 144062306a36Sopenharmony_ci u32 reply) 144162306a36Sopenharmony_ci{ 144262306a36Sopenharmony_ci MPI2DefaultReply_t *mpi_reply; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); 144562306a36Sopenharmony_ci if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) 144662306a36Sopenharmony_ci return mpt3sas_check_for_pending_internal_cmds(ioc, smid); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci if (ioc->base_cmds.status == MPT3_CMD_NOT_USED) 144962306a36Sopenharmony_ci return 1; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci ioc->base_cmds.status |= MPT3_CMD_COMPLETE; 145262306a36Sopenharmony_ci if (mpi_reply) { 145362306a36Sopenharmony_ci ioc->base_cmds.status |= MPT3_CMD_REPLY_VALID; 145462306a36Sopenharmony_ci memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); 145562306a36Sopenharmony_ci } 145662306a36Sopenharmony_ci ioc->base_cmds.status &= ~MPT3_CMD_PENDING; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci complete(&ioc->base_cmds.done); 145962306a36Sopenharmony_ci return 1; 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci/** 146362306a36Sopenharmony_ci * _base_async_event - main callback handler for firmware asyn events 146462306a36Sopenharmony_ci * @ioc: per adapter object 146562306a36Sopenharmony_ci * @msix_index: MSIX table index supplied by the OS 146662306a36Sopenharmony_ci * @reply: reply message frame(lower 32bit addr) 146762306a36Sopenharmony_ci * 146862306a36Sopenharmony_ci * Return: 146962306a36Sopenharmony_ci * 1 meaning mf should be freed from _base_interrupt 147062306a36Sopenharmony_ci * 0 means the mf is freed from this function. 147162306a36Sopenharmony_ci */ 147262306a36Sopenharmony_cistatic u8 147362306a36Sopenharmony_ci_base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci Mpi2EventNotificationReply_t *mpi_reply; 147662306a36Sopenharmony_ci Mpi2EventAckRequest_t *ack_request; 147762306a36Sopenharmony_ci u16 smid; 147862306a36Sopenharmony_ci struct _event_ack_list *delayed_event_ack; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); 148162306a36Sopenharmony_ci if (!mpi_reply) 148262306a36Sopenharmony_ci return 1; 148362306a36Sopenharmony_ci if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION) 148462306a36Sopenharmony_ci return 1; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci _base_display_event_data(ioc, mpi_reply); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED)) 148962306a36Sopenharmony_ci goto out; 149062306a36Sopenharmony_ci smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx); 149162306a36Sopenharmony_ci if (!smid) { 149262306a36Sopenharmony_ci delayed_event_ack = kzalloc(sizeof(*delayed_event_ack), 149362306a36Sopenharmony_ci GFP_ATOMIC); 149462306a36Sopenharmony_ci if (!delayed_event_ack) 149562306a36Sopenharmony_ci goto out; 149662306a36Sopenharmony_ci INIT_LIST_HEAD(&delayed_event_ack->list); 149762306a36Sopenharmony_ci delayed_event_ack->Event = mpi_reply->Event; 149862306a36Sopenharmony_ci delayed_event_ack->EventContext = mpi_reply->EventContext; 149962306a36Sopenharmony_ci list_add_tail(&delayed_event_ack->list, 150062306a36Sopenharmony_ci &ioc->delayed_event_ack_list); 150162306a36Sopenharmony_ci dewtprintk(ioc, 150262306a36Sopenharmony_ci ioc_info(ioc, "DELAYED: EVENT ACK: event (0x%04x)\n", 150362306a36Sopenharmony_ci le16_to_cpu(mpi_reply->Event))); 150462306a36Sopenharmony_ci goto out; 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci ack_request = mpt3sas_base_get_msg_frame(ioc, smid); 150862306a36Sopenharmony_ci memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t)); 150962306a36Sopenharmony_ci ack_request->Function = MPI2_FUNCTION_EVENT_ACK; 151062306a36Sopenharmony_ci ack_request->Event = mpi_reply->Event; 151162306a36Sopenharmony_ci ack_request->EventContext = mpi_reply->EventContext; 151262306a36Sopenharmony_ci ack_request->VF_ID = 0; /* TODO */ 151362306a36Sopenharmony_ci ack_request->VP_ID = 0; 151462306a36Sopenharmony_ci ioc->put_smid_default(ioc, smid); 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci out: 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci /* scsih callback handler */ 151962306a36Sopenharmony_ci mpt3sas_scsih_event_callback(ioc, msix_index, reply); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci /* ctl callback handler */ 152262306a36Sopenharmony_ci mpt3sas_ctl_event_callback(ioc, msix_index, reply); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci return 1; 152562306a36Sopenharmony_ci} 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_cistatic struct scsiio_tracker * 152862306a36Sopenharmony_ci_get_st_from_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid) 152962306a36Sopenharmony_ci{ 153062306a36Sopenharmony_ci struct scsi_cmnd *cmd; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci if (WARN_ON(!smid) || 153362306a36Sopenharmony_ci WARN_ON(smid >= ioc->hi_priority_smid)) 153462306a36Sopenharmony_ci return NULL; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci cmd = mpt3sas_scsih_scsi_lookup_get(ioc, smid); 153762306a36Sopenharmony_ci if (cmd) 153862306a36Sopenharmony_ci return scsi_cmd_priv(cmd); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci return NULL; 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci/** 154462306a36Sopenharmony_ci * _base_get_cb_idx - obtain the callback index 154562306a36Sopenharmony_ci * @ioc: per adapter object 154662306a36Sopenharmony_ci * @smid: system request message index 154762306a36Sopenharmony_ci * 154862306a36Sopenharmony_ci * Return: callback index. 154962306a36Sopenharmony_ci */ 155062306a36Sopenharmony_cistatic u8 155162306a36Sopenharmony_ci_base_get_cb_idx(struct MPT3SAS_ADAPTER *ioc, u16 smid) 155262306a36Sopenharmony_ci{ 155362306a36Sopenharmony_ci int i; 155462306a36Sopenharmony_ci u16 ctl_smid = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT + 1; 155562306a36Sopenharmony_ci u8 cb_idx = 0xFF; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci if (smid < ioc->hi_priority_smid) { 155862306a36Sopenharmony_ci struct scsiio_tracker *st; 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci if (smid < ctl_smid) { 156162306a36Sopenharmony_ci st = _get_st_from_smid(ioc, smid); 156262306a36Sopenharmony_ci if (st) 156362306a36Sopenharmony_ci cb_idx = st->cb_idx; 156462306a36Sopenharmony_ci } else if (smid == ctl_smid) 156562306a36Sopenharmony_ci cb_idx = ioc->ctl_cb_idx; 156662306a36Sopenharmony_ci } else if (smid < ioc->internal_smid) { 156762306a36Sopenharmony_ci i = smid - ioc->hi_priority_smid; 156862306a36Sopenharmony_ci cb_idx = ioc->hpr_lookup[i].cb_idx; 156962306a36Sopenharmony_ci } else if (smid <= ioc->hba_queue_depth) { 157062306a36Sopenharmony_ci i = smid - ioc->internal_smid; 157162306a36Sopenharmony_ci cb_idx = ioc->internal_lookup[i].cb_idx; 157262306a36Sopenharmony_ci } 157362306a36Sopenharmony_ci return cb_idx; 157462306a36Sopenharmony_ci} 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci/** 157762306a36Sopenharmony_ci * mpt3sas_base_pause_mq_polling - pause polling on the mq poll queues 157862306a36Sopenharmony_ci * when driver is flushing out the IOs. 157962306a36Sopenharmony_ci * @ioc: per adapter object 158062306a36Sopenharmony_ci * 158162306a36Sopenharmony_ci * Pause polling on the mq poll (io uring) queues when driver is flushing 158262306a36Sopenharmony_ci * out the IOs. Otherwise we may see the race condition of completing the same 158362306a36Sopenharmony_ci * IO from two paths. 158462306a36Sopenharmony_ci * 158562306a36Sopenharmony_ci * Returns nothing. 158662306a36Sopenharmony_ci */ 158762306a36Sopenharmony_civoid 158862306a36Sopenharmony_cimpt3sas_base_pause_mq_polling(struct MPT3SAS_ADAPTER *ioc) 158962306a36Sopenharmony_ci{ 159062306a36Sopenharmony_ci int iopoll_q_count = 159162306a36Sopenharmony_ci ioc->reply_queue_count - ioc->iopoll_q_start_index; 159262306a36Sopenharmony_ci int qid; 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci for (qid = 0; qid < iopoll_q_count; qid++) 159562306a36Sopenharmony_ci atomic_set(&ioc->io_uring_poll_queues[qid].pause, 1); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci /* 159862306a36Sopenharmony_ci * wait for current poll to complete. 159962306a36Sopenharmony_ci */ 160062306a36Sopenharmony_ci for (qid = 0; qid < iopoll_q_count; qid++) { 160162306a36Sopenharmony_ci while (atomic_read(&ioc->io_uring_poll_queues[qid].busy)) { 160262306a36Sopenharmony_ci cpu_relax(); 160362306a36Sopenharmony_ci udelay(500); 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci} 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci/** 160962306a36Sopenharmony_ci * mpt3sas_base_resume_mq_polling - Resume polling on mq poll queues. 161062306a36Sopenharmony_ci * @ioc: per adapter object 161162306a36Sopenharmony_ci * 161262306a36Sopenharmony_ci * Returns nothing. 161362306a36Sopenharmony_ci */ 161462306a36Sopenharmony_civoid 161562306a36Sopenharmony_cimpt3sas_base_resume_mq_polling(struct MPT3SAS_ADAPTER *ioc) 161662306a36Sopenharmony_ci{ 161762306a36Sopenharmony_ci int iopoll_q_count = 161862306a36Sopenharmony_ci ioc->reply_queue_count - ioc->iopoll_q_start_index; 161962306a36Sopenharmony_ci int qid; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci for (qid = 0; qid < iopoll_q_count; qid++) 162262306a36Sopenharmony_ci atomic_set(&ioc->io_uring_poll_queues[qid].pause, 0); 162362306a36Sopenharmony_ci} 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci/** 162662306a36Sopenharmony_ci * mpt3sas_base_mask_interrupts - disable interrupts 162762306a36Sopenharmony_ci * @ioc: per adapter object 162862306a36Sopenharmony_ci * 162962306a36Sopenharmony_ci * Disabling ResetIRQ, Reply and Doorbell Interrupts 163062306a36Sopenharmony_ci */ 163162306a36Sopenharmony_civoid 163262306a36Sopenharmony_cimpt3sas_base_mask_interrupts(struct MPT3SAS_ADAPTER *ioc) 163362306a36Sopenharmony_ci{ 163462306a36Sopenharmony_ci u32 him_register; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci ioc->mask_interrupts = 1; 163762306a36Sopenharmony_ci him_register = ioc->base_readl(&ioc->chip->HostInterruptMask); 163862306a36Sopenharmony_ci him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + MPI2_HIM_RESET_IRQ_MASK; 163962306a36Sopenharmony_ci writel(him_register, &ioc->chip->HostInterruptMask); 164062306a36Sopenharmony_ci ioc->base_readl(&ioc->chip->HostInterruptMask); 164162306a36Sopenharmony_ci} 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci/** 164462306a36Sopenharmony_ci * mpt3sas_base_unmask_interrupts - enable interrupts 164562306a36Sopenharmony_ci * @ioc: per adapter object 164662306a36Sopenharmony_ci * 164762306a36Sopenharmony_ci * Enabling only Reply Interrupts 164862306a36Sopenharmony_ci */ 164962306a36Sopenharmony_civoid 165062306a36Sopenharmony_cimpt3sas_base_unmask_interrupts(struct MPT3SAS_ADAPTER *ioc) 165162306a36Sopenharmony_ci{ 165262306a36Sopenharmony_ci u32 him_register; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci him_register = ioc->base_readl(&ioc->chip->HostInterruptMask); 165562306a36Sopenharmony_ci him_register &= ~MPI2_HIM_RIM; 165662306a36Sopenharmony_ci writel(him_register, &ioc->chip->HostInterruptMask); 165762306a36Sopenharmony_ci ioc->mask_interrupts = 0; 165862306a36Sopenharmony_ci} 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ciunion reply_descriptor { 166162306a36Sopenharmony_ci u64 word; 166262306a36Sopenharmony_ci struct { 166362306a36Sopenharmony_ci u32 low; 166462306a36Sopenharmony_ci u32 high; 166562306a36Sopenharmony_ci } u; 166662306a36Sopenharmony_ci}; 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_cistatic u32 base_mod64(u64 dividend, u32 divisor) 166962306a36Sopenharmony_ci{ 167062306a36Sopenharmony_ci u32 remainder; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci if (!divisor) 167362306a36Sopenharmony_ci pr_err("mpt3sas: DIVISOR is zero, in div fn\n"); 167462306a36Sopenharmony_ci remainder = do_div(dividend, divisor); 167562306a36Sopenharmony_ci return remainder; 167662306a36Sopenharmony_ci} 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci/** 167962306a36Sopenharmony_ci * _base_process_reply_queue - Process reply descriptors from reply 168062306a36Sopenharmony_ci * descriptor post queue. 168162306a36Sopenharmony_ci * @reply_q: per IRQ's reply queue object. 168262306a36Sopenharmony_ci * 168362306a36Sopenharmony_ci * Return: number of reply descriptors processed from reply 168462306a36Sopenharmony_ci * descriptor queue. 168562306a36Sopenharmony_ci */ 168662306a36Sopenharmony_cistatic int 168762306a36Sopenharmony_ci_base_process_reply_queue(struct adapter_reply_queue *reply_q) 168862306a36Sopenharmony_ci{ 168962306a36Sopenharmony_ci union reply_descriptor rd; 169062306a36Sopenharmony_ci u64 completed_cmds; 169162306a36Sopenharmony_ci u8 request_descript_type; 169262306a36Sopenharmony_ci u16 smid; 169362306a36Sopenharmony_ci u8 cb_idx; 169462306a36Sopenharmony_ci u32 reply; 169562306a36Sopenharmony_ci u8 msix_index = reply_q->msix_index; 169662306a36Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = reply_q->ioc; 169762306a36Sopenharmony_ci Mpi2ReplyDescriptorsUnion_t *rpf; 169862306a36Sopenharmony_ci u8 rc; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci completed_cmds = 0; 170162306a36Sopenharmony_ci if (!atomic_add_unless(&reply_q->busy, 1, 1)) 170262306a36Sopenharmony_ci return completed_cmds; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index]; 170562306a36Sopenharmony_ci request_descript_type = rpf->Default.ReplyFlags 170662306a36Sopenharmony_ci & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; 170762306a36Sopenharmony_ci if (request_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) { 170862306a36Sopenharmony_ci atomic_dec(&reply_q->busy); 170962306a36Sopenharmony_ci return completed_cmds; 171062306a36Sopenharmony_ci } 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci cb_idx = 0xFF; 171362306a36Sopenharmony_ci do { 171462306a36Sopenharmony_ci rd.word = le64_to_cpu(rpf->Words); 171562306a36Sopenharmony_ci if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX) 171662306a36Sopenharmony_ci goto out; 171762306a36Sopenharmony_ci reply = 0; 171862306a36Sopenharmony_ci smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1); 171962306a36Sopenharmony_ci if (request_descript_type == 172062306a36Sopenharmony_ci MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS || 172162306a36Sopenharmony_ci request_descript_type == 172262306a36Sopenharmony_ci MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS || 172362306a36Sopenharmony_ci request_descript_type == 172462306a36Sopenharmony_ci MPI26_RPY_DESCRIPT_FLAGS_PCIE_ENCAPSULATED_SUCCESS) { 172562306a36Sopenharmony_ci cb_idx = _base_get_cb_idx(ioc, smid); 172662306a36Sopenharmony_ci if ((likely(cb_idx < MPT_MAX_CALLBACKS)) && 172762306a36Sopenharmony_ci (likely(mpt_callbacks[cb_idx] != NULL))) { 172862306a36Sopenharmony_ci rc = mpt_callbacks[cb_idx](ioc, smid, 172962306a36Sopenharmony_ci msix_index, 0); 173062306a36Sopenharmony_ci if (rc) 173162306a36Sopenharmony_ci mpt3sas_base_free_smid(ioc, smid); 173262306a36Sopenharmony_ci } 173362306a36Sopenharmony_ci } else if (request_descript_type == 173462306a36Sopenharmony_ci MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { 173562306a36Sopenharmony_ci reply = le32_to_cpu( 173662306a36Sopenharmony_ci rpf->AddressReply.ReplyFrameAddress); 173762306a36Sopenharmony_ci if (reply > ioc->reply_dma_max_address || 173862306a36Sopenharmony_ci reply < ioc->reply_dma_min_address) 173962306a36Sopenharmony_ci reply = 0; 174062306a36Sopenharmony_ci if (smid) { 174162306a36Sopenharmony_ci cb_idx = _base_get_cb_idx(ioc, smid); 174262306a36Sopenharmony_ci if ((likely(cb_idx < MPT_MAX_CALLBACKS)) && 174362306a36Sopenharmony_ci (likely(mpt_callbacks[cb_idx] != NULL))) { 174462306a36Sopenharmony_ci rc = mpt_callbacks[cb_idx](ioc, smid, 174562306a36Sopenharmony_ci msix_index, reply); 174662306a36Sopenharmony_ci if (reply) 174762306a36Sopenharmony_ci _base_display_reply_info(ioc, 174862306a36Sopenharmony_ci smid, msix_index, reply); 174962306a36Sopenharmony_ci if (rc) 175062306a36Sopenharmony_ci mpt3sas_base_free_smid(ioc, 175162306a36Sopenharmony_ci smid); 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci } else { 175462306a36Sopenharmony_ci _base_async_event(ioc, msix_index, reply); 175562306a36Sopenharmony_ci } 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci /* reply free queue handling */ 175862306a36Sopenharmony_ci if (reply) { 175962306a36Sopenharmony_ci ioc->reply_free_host_index = 176062306a36Sopenharmony_ci (ioc->reply_free_host_index == 176162306a36Sopenharmony_ci (ioc->reply_free_queue_depth - 1)) ? 176262306a36Sopenharmony_ci 0 : ioc->reply_free_host_index + 1; 176362306a36Sopenharmony_ci ioc->reply_free[ioc->reply_free_host_index] = 176462306a36Sopenharmony_ci cpu_to_le32(reply); 176562306a36Sopenharmony_ci if (ioc->is_mcpu_endpoint) 176662306a36Sopenharmony_ci _base_clone_reply_to_sys_mem(ioc, 176762306a36Sopenharmony_ci reply, 176862306a36Sopenharmony_ci ioc->reply_free_host_index); 176962306a36Sopenharmony_ci writel(ioc->reply_free_host_index, 177062306a36Sopenharmony_ci &ioc->chip->ReplyFreeHostIndex); 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci } 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci rpf->Words = cpu_to_le64(ULLONG_MAX); 177562306a36Sopenharmony_ci reply_q->reply_post_host_index = 177662306a36Sopenharmony_ci (reply_q->reply_post_host_index == 177762306a36Sopenharmony_ci (ioc->reply_post_queue_depth - 1)) ? 0 : 177862306a36Sopenharmony_ci reply_q->reply_post_host_index + 1; 177962306a36Sopenharmony_ci request_descript_type = 178062306a36Sopenharmony_ci reply_q->reply_post_free[reply_q->reply_post_host_index]. 178162306a36Sopenharmony_ci Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; 178262306a36Sopenharmony_ci completed_cmds++; 178362306a36Sopenharmony_ci /* Update the reply post host index after continuously 178462306a36Sopenharmony_ci * processing the threshold number of Reply Descriptors. 178562306a36Sopenharmony_ci * So that FW can find enough entries to post the Reply 178662306a36Sopenharmony_ci * Descriptors in the reply descriptor post queue. 178762306a36Sopenharmony_ci */ 178862306a36Sopenharmony_ci if (completed_cmds >= ioc->thresh_hold) { 178962306a36Sopenharmony_ci if (ioc->combined_reply_queue) { 179062306a36Sopenharmony_ci writel(reply_q->reply_post_host_index | 179162306a36Sopenharmony_ci ((msix_index & 7) << 179262306a36Sopenharmony_ci MPI2_RPHI_MSIX_INDEX_SHIFT), 179362306a36Sopenharmony_ci ioc->replyPostRegisterIndex[msix_index/8]); 179462306a36Sopenharmony_ci } else { 179562306a36Sopenharmony_ci writel(reply_q->reply_post_host_index | 179662306a36Sopenharmony_ci (msix_index << 179762306a36Sopenharmony_ci MPI2_RPHI_MSIX_INDEX_SHIFT), 179862306a36Sopenharmony_ci &ioc->chip->ReplyPostHostIndex); 179962306a36Sopenharmony_ci } 180062306a36Sopenharmony_ci if (!reply_q->is_iouring_poll_q && 180162306a36Sopenharmony_ci !reply_q->irq_poll_scheduled) { 180262306a36Sopenharmony_ci reply_q->irq_poll_scheduled = true; 180362306a36Sopenharmony_ci irq_poll_sched(&reply_q->irqpoll); 180462306a36Sopenharmony_ci } 180562306a36Sopenharmony_ci atomic_dec(&reply_q->busy); 180662306a36Sopenharmony_ci return completed_cmds; 180762306a36Sopenharmony_ci } 180862306a36Sopenharmony_ci if (request_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) 180962306a36Sopenharmony_ci goto out; 181062306a36Sopenharmony_ci if (!reply_q->reply_post_host_index) 181162306a36Sopenharmony_ci rpf = reply_q->reply_post_free; 181262306a36Sopenharmony_ci else 181362306a36Sopenharmony_ci rpf++; 181462306a36Sopenharmony_ci } while (1); 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci out: 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci if (!completed_cmds) { 181962306a36Sopenharmony_ci atomic_dec(&reply_q->busy); 182062306a36Sopenharmony_ci return completed_cmds; 182162306a36Sopenharmony_ci } 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci if (ioc->is_warpdrive) { 182462306a36Sopenharmony_ci writel(reply_q->reply_post_host_index, 182562306a36Sopenharmony_ci ioc->reply_post_host_index[msix_index]); 182662306a36Sopenharmony_ci atomic_dec(&reply_q->busy); 182762306a36Sopenharmony_ci return completed_cmds; 182862306a36Sopenharmony_ci } 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci /* Update Reply Post Host Index. 183162306a36Sopenharmony_ci * For those HBA's which support combined reply queue feature 183262306a36Sopenharmony_ci * 1. Get the correct Supplemental Reply Post Host Index Register. 183362306a36Sopenharmony_ci * i.e. (msix_index / 8)th entry from Supplemental Reply Post Host 183462306a36Sopenharmony_ci * Index Register address bank i.e replyPostRegisterIndex[], 183562306a36Sopenharmony_ci * 2. Then update this register with new reply host index value 183662306a36Sopenharmony_ci * in ReplyPostIndex field and the MSIxIndex field with 183762306a36Sopenharmony_ci * msix_index value reduced to a value between 0 and 7, 183862306a36Sopenharmony_ci * using a modulo 8 operation. Since each Supplemental Reply Post 183962306a36Sopenharmony_ci * Host Index Register supports 8 MSI-X vectors. 184062306a36Sopenharmony_ci * 184162306a36Sopenharmony_ci * For other HBA's just update the Reply Post Host Index register with 184262306a36Sopenharmony_ci * new reply host index value in ReplyPostIndex Field and msix_index 184362306a36Sopenharmony_ci * value in MSIxIndex field. 184462306a36Sopenharmony_ci */ 184562306a36Sopenharmony_ci if (ioc->combined_reply_queue) 184662306a36Sopenharmony_ci writel(reply_q->reply_post_host_index | ((msix_index & 7) << 184762306a36Sopenharmony_ci MPI2_RPHI_MSIX_INDEX_SHIFT), 184862306a36Sopenharmony_ci ioc->replyPostRegisterIndex[msix_index/8]); 184962306a36Sopenharmony_ci else 185062306a36Sopenharmony_ci writel(reply_q->reply_post_host_index | (msix_index << 185162306a36Sopenharmony_ci MPI2_RPHI_MSIX_INDEX_SHIFT), 185262306a36Sopenharmony_ci &ioc->chip->ReplyPostHostIndex); 185362306a36Sopenharmony_ci atomic_dec(&reply_q->busy); 185462306a36Sopenharmony_ci return completed_cmds; 185562306a36Sopenharmony_ci} 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci/** 185862306a36Sopenharmony_ci * mpt3sas_blk_mq_poll - poll the blk mq poll queue 185962306a36Sopenharmony_ci * @shost: Scsi_Host object 186062306a36Sopenharmony_ci * @queue_num: hw ctx queue number 186162306a36Sopenharmony_ci * 186262306a36Sopenharmony_ci * Return number of entries that has been processed from poll queue. 186362306a36Sopenharmony_ci */ 186462306a36Sopenharmony_ciint mpt3sas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num) 186562306a36Sopenharmony_ci{ 186662306a36Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = 186762306a36Sopenharmony_ci (struct MPT3SAS_ADAPTER *)shost->hostdata; 186862306a36Sopenharmony_ci struct adapter_reply_queue *reply_q; 186962306a36Sopenharmony_ci int num_entries = 0; 187062306a36Sopenharmony_ci int qid = queue_num - ioc->iopoll_q_start_index; 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci if (atomic_read(&ioc->io_uring_poll_queues[qid].pause) || 187362306a36Sopenharmony_ci !atomic_add_unless(&ioc->io_uring_poll_queues[qid].busy, 1, 1)) 187462306a36Sopenharmony_ci return 0; 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci reply_q = ioc->io_uring_poll_queues[qid].reply_q; 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci num_entries = _base_process_reply_queue(reply_q); 187962306a36Sopenharmony_ci atomic_dec(&ioc->io_uring_poll_queues[qid].busy); 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci return num_entries; 188262306a36Sopenharmony_ci} 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci/** 188562306a36Sopenharmony_ci * _base_interrupt - MPT adapter (IOC) specific interrupt handler. 188662306a36Sopenharmony_ci * @irq: irq number (not used) 188762306a36Sopenharmony_ci * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure 188862306a36Sopenharmony_ci * 188962306a36Sopenharmony_ci * Return: IRQ_HANDLED if processed, else IRQ_NONE. 189062306a36Sopenharmony_ci */ 189162306a36Sopenharmony_cistatic irqreturn_t 189262306a36Sopenharmony_ci_base_interrupt(int irq, void *bus_id) 189362306a36Sopenharmony_ci{ 189462306a36Sopenharmony_ci struct adapter_reply_queue *reply_q = bus_id; 189562306a36Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = reply_q->ioc; 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci if (ioc->mask_interrupts) 189862306a36Sopenharmony_ci return IRQ_NONE; 189962306a36Sopenharmony_ci if (reply_q->irq_poll_scheduled) 190062306a36Sopenharmony_ci return IRQ_HANDLED; 190162306a36Sopenharmony_ci return ((_base_process_reply_queue(reply_q) > 0) ? 190262306a36Sopenharmony_ci IRQ_HANDLED : IRQ_NONE); 190362306a36Sopenharmony_ci} 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci/** 190662306a36Sopenharmony_ci * _base_irqpoll - IRQ poll callback handler 190762306a36Sopenharmony_ci * @irqpoll: irq_poll object 190862306a36Sopenharmony_ci * @budget: irq poll weight 190962306a36Sopenharmony_ci * 191062306a36Sopenharmony_ci * Return: number of reply descriptors processed 191162306a36Sopenharmony_ci */ 191262306a36Sopenharmony_cistatic int 191362306a36Sopenharmony_ci_base_irqpoll(struct irq_poll *irqpoll, int budget) 191462306a36Sopenharmony_ci{ 191562306a36Sopenharmony_ci struct adapter_reply_queue *reply_q; 191662306a36Sopenharmony_ci int num_entries = 0; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci reply_q = container_of(irqpoll, struct adapter_reply_queue, 191962306a36Sopenharmony_ci irqpoll); 192062306a36Sopenharmony_ci if (reply_q->irq_line_enable) { 192162306a36Sopenharmony_ci disable_irq_nosync(reply_q->os_irq); 192262306a36Sopenharmony_ci reply_q->irq_line_enable = false; 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci num_entries = _base_process_reply_queue(reply_q); 192562306a36Sopenharmony_ci if (num_entries < budget) { 192662306a36Sopenharmony_ci irq_poll_complete(irqpoll); 192762306a36Sopenharmony_ci reply_q->irq_poll_scheduled = false; 192862306a36Sopenharmony_ci reply_q->irq_line_enable = true; 192962306a36Sopenharmony_ci enable_irq(reply_q->os_irq); 193062306a36Sopenharmony_ci /* 193162306a36Sopenharmony_ci * Go for one more round of processing the 193262306a36Sopenharmony_ci * reply descriptor post queue in case the HBA 193362306a36Sopenharmony_ci * Firmware has posted some reply descriptors 193462306a36Sopenharmony_ci * while reenabling the IRQ. 193562306a36Sopenharmony_ci */ 193662306a36Sopenharmony_ci _base_process_reply_queue(reply_q); 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci return num_entries; 194062306a36Sopenharmony_ci} 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci/** 194362306a36Sopenharmony_ci * _base_init_irqpolls - initliaze IRQ polls 194462306a36Sopenharmony_ci * @ioc: per adapter object 194562306a36Sopenharmony_ci * 194662306a36Sopenharmony_ci * Return: nothing 194762306a36Sopenharmony_ci */ 194862306a36Sopenharmony_cistatic void 194962306a36Sopenharmony_ci_base_init_irqpolls(struct MPT3SAS_ADAPTER *ioc) 195062306a36Sopenharmony_ci{ 195162306a36Sopenharmony_ci struct adapter_reply_queue *reply_q, *next; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci if (list_empty(&ioc->reply_queue_list)) 195462306a36Sopenharmony_ci return; 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { 195762306a36Sopenharmony_ci if (reply_q->is_iouring_poll_q) 195862306a36Sopenharmony_ci continue; 195962306a36Sopenharmony_ci irq_poll_init(&reply_q->irqpoll, 196062306a36Sopenharmony_ci ioc->hba_queue_depth/4, _base_irqpoll); 196162306a36Sopenharmony_ci reply_q->irq_poll_scheduled = false; 196262306a36Sopenharmony_ci reply_q->irq_line_enable = true; 196362306a36Sopenharmony_ci reply_q->os_irq = pci_irq_vector(ioc->pdev, 196462306a36Sopenharmony_ci reply_q->msix_index); 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci} 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci/** 196962306a36Sopenharmony_ci * _base_is_controller_msix_enabled - is controller support muli-reply queues 197062306a36Sopenharmony_ci * @ioc: per adapter object 197162306a36Sopenharmony_ci * 197262306a36Sopenharmony_ci * Return: Whether or not MSI/X is enabled. 197362306a36Sopenharmony_ci */ 197462306a36Sopenharmony_cistatic inline int 197562306a36Sopenharmony_ci_base_is_controller_msix_enabled(struct MPT3SAS_ADAPTER *ioc) 197662306a36Sopenharmony_ci{ 197762306a36Sopenharmony_ci return (ioc->facts.IOCCapabilities & 197862306a36Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable; 197962306a36Sopenharmony_ci} 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci/** 198262306a36Sopenharmony_ci * mpt3sas_base_sync_reply_irqs - flush pending MSIX interrupts 198362306a36Sopenharmony_ci * @ioc: per adapter object 198462306a36Sopenharmony_ci * @poll: poll over reply descriptor pools incase interrupt for 198562306a36Sopenharmony_ci * timed-out SCSI command got delayed 198662306a36Sopenharmony_ci * Context: non-ISR context 198762306a36Sopenharmony_ci * 198862306a36Sopenharmony_ci * Called when a Task Management request has completed. 198962306a36Sopenharmony_ci */ 199062306a36Sopenharmony_civoid 199162306a36Sopenharmony_cimpt3sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc, u8 poll) 199262306a36Sopenharmony_ci{ 199362306a36Sopenharmony_ci struct adapter_reply_queue *reply_q; 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci /* If MSIX capability is turned off 199662306a36Sopenharmony_ci * then multi-queues are not enabled 199762306a36Sopenharmony_ci */ 199862306a36Sopenharmony_ci if (!_base_is_controller_msix_enabled(ioc)) 199962306a36Sopenharmony_ci return; 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { 200262306a36Sopenharmony_ci if (ioc->shost_recovery || ioc->remove_host || 200362306a36Sopenharmony_ci ioc->pci_error_recovery) 200462306a36Sopenharmony_ci return; 200562306a36Sopenharmony_ci /* TMs are on msix_index == 0 */ 200662306a36Sopenharmony_ci if (reply_q->msix_index == 0) 200762306a36Sopenharmony_ci continue; 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci if (reply_q->is_iouring_poll_q) { 201062306a36Sopenharmony_ci _base_process_reply_queue(reply_q); 201162306a36Sopenharmony_ci continue; 201262306a36Sopenharmony_ci } 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci synchronize_irq(pci_irq_vector(ioc->pdev, reply_q->msix_index)); 201562306a36Sopenharmony_ci if (reply_q->irq_poll_scheduled) { 201662306a36Sopenharmony_ci /* Calling irq_poll_disable will wait for any pending 201762306a36Sopenharmony_ci * callbacks to have completed. 201862306a36Sopenharmony_ci */ 201962306a36Sopenharmony_ci irq_poll_disable(&reply_q->irqpoll); 202062306a36Sopenharmony_ci irq_poll_enable(&reply_q->irqpoll); 202162306a36Sopenharmony_ci /* check how the scheduled poll has ended, 202262306a36Sopenharmony_ci * clean up only if necessary 202362306a36Sopenharmony_ci */ 202462306a36Sopenharmony_ci if (reply_q->irq_poll_scheduled) { 202562306a36Sopenharmony_ci reply_q->irq_poll_scheduled = false; 202662306a36Sopenharmony_ci reply_q->irq_line_enable = true; 202762306a36Sopenharmony_ci enable_irq(reply_q->os_irq); 202862306a36Sopenharmony_ci } 202962306a36Sopenharmony_ci } 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci if (poll) 203262306a36Sopenharmony_ci _base_process_reply_queue(reply_q); 203362306a36Sopenharmony_ci } 203462306a36Sopenharmony_ci} 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci/** 203762306a36Sopenharmony_ci * mpt3sas_base_release_callback_handler - clear interrupt callback handler 203862306a36Sopenharmony_ci * @cb_idx: callback index 203962306a36Sopenharmony_ci */ 204062306a36Sopenharmony_civoid 204162306a36Sopenharmony_cimpt3sas_base_release_callback_handler(u8 cb_idx) 204262306a36Sopenharmony_ci{ 204362306a36Sopenharmony_ci mpt_callbacks[cb_idx] = NULL; 204462306a36Sopenharmony_ci} 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci/** 204762306a36Sopenharmony_ci * mpt3sas_base_register_callback_handler - obtain index for the interrupt callback handler 204862306a36Sopenharmony_ci * @cb_func: callback function 204962306a36Sopenharmony_ci * 205062306a36Sopenharmony_ci * Return: Index of @cb_func. 205162306a36Sopenharmony_ci */ 205262306a36Sopenharmony_ciu8 205362306a36Sopenharmony_cimpt3sas_base_register_callback_handler(MPT_CALLBACK cb_func) 205462306a36Sopenharmony_ci{ 205562306a36Sopenharmony_ci u8 cb_idx; 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci for (cb_idx = MPT_MAX_CALLBACKS-1; cb_idx; cb_idx--) 205862306a36Sopenharmony_ci if (mpt_callbacks[cb_idx] == NULL) 205962306a36Sopenharmony_ci break; 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci mpt_callbacks[cb_idx] = cb_func; 206262306a36Sopenharmony_ci return cb_idx; 206362306a36Sopenharmony_ci} 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci/** 206662306a36Sopenharmony_ci * mpt3sas_base_initialize_callback_handler - initialize the interrupt callback handler 206762306a36Sopenharmony_ci */ 206862306a36Sopenharmony_civoid 206962306a36Sopenharmony_cimpt3sas_base_initialize_callback_handler(void) 207062306a36Sopenharmony_ci{ 207162306a36Sopenharmony_ci u8 cb_idx; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci for (cb_idx = 0; cb_idx < MPT_MAX_CALLBACKS; cb_idx++) 207462306a36Sopenharmony_ci mpt3sas_base_release_callback_handler(cb_idx); 207562306a36Sopenharmony_ci} 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci/** 207962306a36Sopenharmony_ci * _base_build_zero_len_sge - build zero length sg entry 208062306a36Sopenharmony_ci * @ioc: per adapter object 208162306a36Sopenharmony_ci * @paddr: virtual address for SGE 208262306a36Sopenharmony_ci * 208362306a36Sopenharmony_ci * Create a zero length scatter gather entry to insure the IOCs hardware has 208462306a36Sopenharmony_ci * something to use if the target device goes brain dead and tries 208562306a36Sopenharmony_ci * to send data even when none is asked for. 208662306a36Sopenharmony_ci */ 208762306a36Sopenharmony_cistatic void 208862306a36Sopenharmony_ci_base_build_zero_len_sge(struct MPT3SAS_ADAPTER *ioc, void *paddr) 208962306a36Sopenharmony_ci{ 209062306a36Sopenharmony_ci u32 flags_length = (u32)((MPI2_SGE_FLAGS_LAST_ELEMENT | 209162306a36Sopenharmony_ci MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST | 209262306a36Sopenharmony_ci MPI2_SGE_FLAGS_SIMPLE_ELEMENT) << 209362306a36Sopenharmony_ci MPI2_SGE_FLAGS_SHIFT); 209462306a36Sopenharmony_ci ioc->base_add_sg_single(paddr, flags_length, -1); 209562306a36Sopenharmony_ci} 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci/** 209862306a36Sopenharmony_ci * _base_add_sg_single_32 - Place a simple 32 bit SGE at address pAddr. 209962306a36Sopenharmony_ci * @paddr: virtual address for SGE 210062306a36Sopenharmony_ci * @flags_length: SGE flags and data transfer length 210162306a36Sopenharmony_ci * @dma_addr: Physical address 210262306a36Sopenharmony_ci */ 210362306a36Sopenharmony_cistatic void 210462306a36Sopenharmony_ci_base_add_sg_single_32(void *paddr, u32 flags_length, dma_addr_t dma_addr) 210562306a36Sopenharmony_ci{ 210662306a36Sopenharmony_ci Mpi2SGESimple32_t *sgel = paddr; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci flags_length |= (MPI2_SGE_FLAGS_32_BIT_ADDRESSING | 210962306a36Sopenharmony_ci MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT; 211062306a36Sopenharmony_ci sgel->FlagsLength = cpu_to_le32(flags_length); 211162306a36Sopenharmony_ci sgel->Address = cpu_to_le32(dma_addr); 211262306a36Sopenharmony_ci} 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci/** 211662306a36Sopenharmony_ci * _base_add_sg_single_64 - Place a simple 64 bit SGE at address pAddr. 211762306a36Sopenharmony_ci * @paddr: virtual address for SGE 211862306a36Sopenharmony_ci * @flags_length: SGE flags and data transfer length 211962306a36Sopenharmony_ci * @dma_addr: Physical address 212062306a36Sopenharmony_ci */ 212162306a36Sopenharmony_cistatic void 212262306a36Sopenharmony_ci_base_add_sg_single_64(void *paddr, u32 flags_length, dma_addr_t dma_addr) 212362306a36Sopenharmony_ci{ 212462306a36Sopenharmony_ci Mpi2SGESimple64_t *sgel = paddr; 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci flags_length |= (MPI2_SGE_FLAGS_64_BIT_ADDRESSING | 212762306a36Sopenharmony_ci MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT; 212862306a36Sopenharmony_ci sgel->FlagsLength = cpu_to_le32(flags_length); 212962306a36Sopenharmony_ci sgel->Address = cpu_to_le64(dma_addr); 213062306a36Sopenharmony_ci} 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci/** 213362306a36Sopenharmony_ci * _base_get_chain_buffer_tracker - obtain chain tracker 213462306a36Sopenharmony_ci * @ioc: per adapter object 213562306a36Sopenharmony_ci * @scmd: SCSI commands of the IO request 213662306a36Sopenharmony_ci * 213762306a36Sopenharmony_ci * Return: chain tracker from chain_lookup table using key as 213862306a36Sopenharmony_ci * smid and smid's chain_offset. 213962306a36Sopenharmony_ci */ 214062306a36Sopenharmony_cistatic struct chain_tracker * 214162306a36Sopenharmony_ci_base_get_chain_buffer_tracker(struct MPT3SAS_ADAPTER *ioc, 214262306a36Sopenharmony_ci struct scsi_cmnd *scmd) 214362306a36Sopenharmony_ci{ 214462306a36Sopenharmony_ci struct chain_tracker *chain_req; 214562306a36Sopenharmony_ci struct scsiio_tracker *st = scsi_cmd_priv(scmd); 214662306a36Sopenharmony_ci u16 smid = st->smid; 214762306a36Sopenharmony_ci u8 chain_offset = 214862306a36Sopenharmony_ci atomic_read(&ioc->chain_lookup[smid - 1].chain_offset); 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci if (chain_offset == ioc->chains_needed_per_io) 215162306a36Sopenharmony_ci return NULL; 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_ci chain_req = &ioc->chain_lookup[smid - 1].chains_per_smid[chain_offset]; 215462306a36Sopenharmony_ci atomic_inc(&ioc->chain_lookup[smid - 1].chain_offset); 215562306a36Sopenharmony_ci return chain_req; 215662306a36Sopenharmony_ci} 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci/** 216062306a36Sopenharmony_ci * _base_build_sg - build generic sg 216162306a36Sopenharmony_ci * @ioc: per adapter object 216262306a36Sopenharmony_ci * @psge: virtual address for SGE 216362306a36Sopenharmony_ci * @data_out_dma: physical address for WRITES 216462306a36Sopenharmony_ci * @data_out_sz: data xfer size for WRITES 216562306a36Sopenharmony_ci * @data_in_dma: physical address for READS 216662306a36Sopenharmony_ci * @data_in_sz: data xfer size for READS 216762306a36Sopenharmony_ci */ 216862306a36Sopenharmony_cistatic void 216962306a36Sopenharmony_ci_base_build_sg(struct MPT3SAS_ADAPTER *ioc, void *psge, 217062306a36Sopenharmony_ci dma_addr_t data_out_dma, size_t data_out_sz, dma_addr_t data_in_dma, 217162306a36Sopenharmony_ci size_t data_in_sz) 217262306a36Sopenharmony_ci{ 217362306a36Sopenharmony_ci u32 sgl_flags; 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci if (!data_out_sz && !data_in_sz) { 217662306a36Sopenharmony_ci _base_build_zero_len_sge(ioc, psge); 217762306a36Sopenharmony_ci return; 217862306a36Sopenharmony_ci } 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci if (data_out_sz && data_in_sz) { 218162306a36Sopenharmony_ci /* WRITE sgel first */ 218262306a36Sopenharmony_ci sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 218362306a36Sopenharmony_ci MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); 218462306a36Sopenharmony_ci sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; 218562306a36Sopenharmony_ci ioc->base_add_sg_single(psge, sgl_flags | 218662306a36Sopenharmony_ci data_out_sz, data_out_dma); 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci /* incr sgel */ 218962306a36Sopenharmony_ci psge += ioc->sge_size; 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci /* READ sgel last */ 219262306a36Sopenharmony_ci sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 219362306a36Sopenharmony_ci MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | 219462306a36Sopenharmony_ci MPI2_SGE_FLAGS_END_OF_LIST); 219562306a36Sopenharmony_ci sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; 219662306a36Sopenharmony_ci ioc->base_add_sg_single(psge, sgl_flags | 219762306a36Sopenharmony_ci data_in_sz, data_in_dma); 219862306a36Sopenharmony_ci } else if (data_out_sz) /* WRITE */ { 219962306a36Sopenharmony_ci sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 220062306a36Sopenharmony_ci MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | 220162306a36Sopenharmony_ci MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC); 220262306a36Sopenharmony_ci sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; 220362306a36Sopenharmony_ci ioc->base_add_sg_single(psge, sgl_flags | 220462306a36Sopenharmony_ci data_out_sz, data_out_dma); 220562306a36Sopenharmony_ci } else if (data_in_sz) /* READ */ { 220662306a36Sopenharmony_ci sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 220762306a36Sopenharmony_ci MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | 220862306a36Sopenharmony_ci MPI2_SGE_FLAGS_END_OF_LIST); 220962306a36Sopenharmony_ci sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; 221062306a36Sopenharmony_ci ioc->base_add_sg_single(psge, sgl_flags | 221162306a36Sopenharmony_ci data_in_sz, data_in_dma); 221262306a36Sopenharmony_ci } 221362306a36Sopenharmony_ci} 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci/* IEEE format sgls */ 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci/** 221862306a36Sopenharmony_ci * _base_build_nvme_prp - This function is called for NVMe end devices to build 221962306a36Sopenharmony_ci * a native SGL (NVMe PRP). 222062306a36Sopenharmony_ci * @ioc: per adapter object 222162306a36Sopenharmony_ci * @smid: system request message index for getting asscociated SGL 222262306a36Sopenharmony_ci * @nvme_encap_request: the NVMe request msg frame pointer 222362306a36Sopenharmony_ci * @data_out_dma: physical address for WRITES 222462306a36Sopenharmony_ci * @data_out_sz: data xfer size for WRITES 222562306a36Sopenharmony_ci * @data_in_dma: physical address for READS 222662306a36Sopenharmony_ci * @data_in_sz: data xfer size for READS 222762306a36Sopenharmony_ci * 222862306a36Sopenharmony_ci * The native SGL is built starting in the first PRP 222962306a36Sopenharmony_ci * entry of the NVMe message (PRP1). If the data buffer is small enough to be 223062306a36Sopenharmony_ci * described entirely using PRP1, then PRP2 is not used. If needed, PRP2 is 223162306a36Sopenharmony_ci * used to describe a larger data buffer. If the data buffer is too large to 223262306a36Sopenharmony_ci * describe using the two PRP entriess inside the NVMe message, then PRP1 223362306a36Sopenharmony_ci * describes the first data memory segment, and PRP2 contains a pointer to a PRP 223462306a36Sopenharmony_ci * list located elsewhere in memory to describe the remaining data memory 223562306a36Sopenharmony_ci * segments. The PRP list will be contiguous. 223662306a36Sopenharmony_ci * 223762306a36Sopenharmony_ci * The native SGL for NVMe devices is a Physical Region Page (PRP). A PRP 223862306a36Sopenharmony_ci * consists of a list of PRP entries to describe a number of noncontigous 223962306a36Sopenharmony_ci * physical memory segments as a single memory buffer, just as a SGL does. Note 224062306a36Sopenharmony_ci * however, that this function is only used by the IOCTL call, so the memory 224162306a36Sopenharmony_ci * given will be guaranteed to be contiguous. There is no need to translate 224262306a36Sopenharmony_ci * non-contiguous SGL into a PRP in this case. All PRPs will describe 224362306a36Sopenharmony_ci * contiguous space that is one page size each. 224462306a36Sopenharmony_ci * 224562306a36Sopenharmony_ci * Each NVMe message contains two PRP entries. The first (PRP1) either contains 224662306a36Sopenharmony_ci * a PRP list pointer or a PRP element, depending upon the command. PRP2 224762306a36Sopenharmony_ci * contains the second PRP element if the memory being described fits within 2 224862306a36Sopenharmony_ci * PRP entries, or a PRP list pointer if the PRP spans more than two entries. 224962306a36Sopenharmony_ci * 225062306a36Sopenharmony_ci * A PRP list pointer contains the address of a PRP list, structured as a linear 225162306a36Sopenharmony_ci * array of PRP entries. Each PRP entry in this list describes a segment of 225262306a36Sopenharmony_ci * physical memory. 225362306a36Sopenharmony_ci * 225462306a36Sopenharmony_ci * Each 64-bit PRP entry comprises an address and an offset field. The address 225562306a36Sopenharmony_ci * always points at the beginning of a 4KB physical memory page, and the offset 225662306a36Sopenharmony_ci * describes where within that 4KB page the memory segment begins. Only the 225762306a36Sopenharmony_ci * first element in a PRP list may contain a non-zero offset, implying that all 225862306a36Sopenharmony_ci * memory segments following the first begin at the start of a 4KB page. 225962306a36Sopenharmony_ci * 226062306a36Sopenharmony_ci * Each PRP element normally describes 4KB of physical memory, with exceptions 226162306a36Sopenharmony_ci * for the first and last elements in the list. If the memory being described 226262306a36Sopenharmony_ci * by the list begins at a non-zero offset within the first 4KB page, then the 226362306a36Sopenharmony_ci * first PRP element will contain a non-zero offset indicating where the region 226462306a36Sopenharmony_ci * begins within the 4KB page. The last memory segment may end before the end 226562306a36Sopenharmony_ci * of the 4KB segment, depending upon the overall size of the memory being 226662306a36Sopenharmony_ci * described by the PRP list. 226762306a36Sopenharmony_ci * 226862306a36Sopenharmony_ci * Since PRP entries lack any indication of size, the overall data buffer length 226962306a36Sopenharmony_ci * is used to determine where the end of the data memory buffer is located, and 227062306a36Sopenharmony_ci * how many PRP entries are required to describe it. 227162306a36Sopenharmony_ci */ 227262306a36Sopenharmony_cistatic void 227362306a36Sopenharmony_ci_base_build_nvme_prp(struct MPT3SAS_ADAPTER *ioc, u16 smid, 227462306a36Sopenharmony_ci Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request, 227562306a36Sopenharmony_ci dma_addr_t data_out_dma, size_t data_out_sz, dma_addr_t data_in_dma, 227662306a36Sopenharmony_ci size_t data_in_sz) 227762306a36Sopenharmony_ci{ 227862306a36Sopenharmony_ci int prp_size = NVME_PRP_SIZE; 227962306a36Sopenharmony_ci __le64 *prp_entry, *prp1_entry, *prp2_entry; 228062306a36Sopenharmony_ci __le64 *prp_page; 228162306a36Sopenharmony_ci dma_addr_t prp_entry_dma, prp_page_dma, dma_addr; 228262306a36Sopenharmony_ci u32 offset, entry_len; 228362306a36Sopenharmony_ci u32 page_mask_result, page_mask; 228462306a36Sopenharmony_ci size_t length; 228562306a36Sopenharmony_ci struct mpt3sas_nvme_cmd *nvme_cmd = 228662306a36Sopenharmony_ci (void *)nvme_encap_request->NVMe_Command; 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ci /* 228962306a36Sopenharmony_ci * Not all commands require a data transfer. If no data, just return 229062306a36Sopenharmony_ci * without constructing any PRP. 229162306a36Sopenharmony_ci */ 229262306a36Sopenharmony_ci if (!data_in_sz && !data_out_sz) 229362306a36Sopenharmony_ci return; 229462306a36Sopenharmony_ci prp1_entry = &nvme_cmd->prp1; 229562306a36Sopenharmony_ci prp2_entry = &nvme_cmd->prp2; 229662306a36Sopenharmony_ci prp_entry = prp1_entry; 229762306a36Sopenharmony_ci /* 229862306a36Sopenharmony_ci * For the PRP entries, use the specially allocated buffer of 229962306a36Sopenharmony_ci * contiguous memory. 230062306a36Sopenharmony_ci */ 230162306a36Sopenharmony_ci prp_page = (__le64 *)mpt3sas_base_get_pcie_sgl(ioc, smid); 230262306a36Sopenharmony_ci prp_page_dma = mpt3sas_base_get_pcie_sgl_dma(ioc, smid); 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci /* 230562306a36Sopenharmony_ci * Check if we are within 1 entry of a page boundary we don't 230662306a36Sopenharmony_ci * want our first entry to be a PRP List entry. 230762306a36Sopenharmony_ci */ 230862306a36Sopenharmony_ci page_mask = ioc->page_size - 1; 230962306a36Sopenharmony_ci page_mask_result = (uintptr_t)((u8 *)prp_page + prp_size) & page_mask; 231062306a36Sopenharmony_ci if (!page_mask_result) { 231162306a36Sopenharmony_ci /* Bump up to next page boundary. */ 231262306a36Sopenharmony_ci prp_page = (__le64 *)((u8 *)prp_page + prp_size); 231362306a36Sopenharmony_ci prp_page_dma = prp_page_dma + prp_size; 231462306a36Sopenharmony_ci } 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci /* 231762306a36Sopenharmony_ci * Set PRP physical pointer, which initially points to the current PRP 231862306a36Sopenharmony_ci * DMA memory page. 231962306a36Sopenharmony_ci */ 232062306a36Sopenharmony_ci prp_entry_dma = prp_page_dma; 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci /* Get physical address and length of the data buffer. */ 232362306a36Sopenharmony_ci if (data_in_sz) { 232462306a36Sopenharmony_ci dma_addr = data_in_dma; 232562306a36Sopenharmony_ci length = data_in_sz; 232662306a36Sopenharmony_ci } else { 232762306a36Sopenharmony_ci dma_addr = data_out_dma; 232862306a36Sopenharmony_ci length = data_out_sz; 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci /* Loop while the length is not zero. */ 233262306a36Sopenharmony_ci while (length) { 233362306a36Sopenharmony_ci /* 233462306a36Sopenharmony_ci * Check if we need to put a list pointer here if we are at 233562306a36Sopenharmony_ci * page boundary - prp_size (8 bytes). 233662306a36Sopenharmony_ci */ 233762306a36Sopenharmony_ci page_mask_result = (prp_entry_dma + prp_size) & page_mask; 233862306a36Sopenharmony_ci if (!page_mask_result) { 233962306a36Sopenharmony_ci /* 234062306a36Sopenharmony_ci * This is the last entry in a PRP List, so we need to 234162306a36Sopenharmony_ci * put a PRP list pointer here. What this does is: 234262306a36Sopenharmony_ci * - bump the current memory pointer to the next 234362306a36Sopenharmony_ci * address, which will be the next full page. 234462306a36Sopenharmony_ci * - set the PRP Entry to point to that page. This 234562306a36Sopenharmony_ci * is now the PRP List pointer. 234662306a36Sopenharmony_ci * - bump the PRP Entry pointer the start of the 234762306a36Sopenharmony_ci * next page. Since all of this PRP memory is 234862306a36Sopenharmony_ci * contiguous, no need to get a new page - it's 234962306a36Sopenharmony_ci * just the next address. 235062306a36Sopenharmony_ci */ 235162306a36Sopenharmony_ci prp_entry_dma++; 235262306a36Sopenharmony_ci *prp_entry = cpu_to_le64(prp_entry_dma); 235362306a36Sopenharmony_ci prp_entry++; 235462306a36Sopenharmony_ci } 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci /* Need to handle if entry will be part of a page. */ 235762306a36Sopenharmony_ci offset = dma_addr & page_mask; 235862306a36Sopenharmony_ci entry_len = ioc->page_size - offset; 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci if (prp_entry == prp1_entry) { 236162306a36Sopenharmony_ci /* 236262306a36Sopenharmony_ci * Must fill in the first PRP pointer (PRP1) before 236362306a36Sopenharmony_ci * moving on. 236462306a36Sopenharmony_ci */ 236562306a36Sopenharmony_ci *prp1_entry = cpu_to_le64(dma_addr); 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci /* 236862306a36Sopenharmony_ci * Now point to the second PRP entry within the 236962306a36Sopenharmony_ci * command (PRP2). 237062306a36Sopenharmony_ci */ 237162306a36Sopenharmony_ci prp_entry = prp2_entry; 237262306a36Sopenharmony_ci } else if (prp_entry == prp2_entry) { 237362306a36Sopenharmony_ci /* 237462306a36Sopenharmony_ci * Should the PRP2 entry be a PRP List pointer or just 237562306a36Sopenharmony_ci * a regular PRP pointer? If there is more than one 237662306a36Sopenharmony_ci * more page of data, must use a PRP List pointer. 237762306a36Sopenharmony_ci */ 237862306a36Sopenharmony_ci if (length > ioc->page_size) { 237962306a36Sopenharmony_ci /* 238062306a36Sopenharmony_ci * PRP2 will contain a PRP List pointer because 238162306a36Sopenharmony_ci * more PRP's are needed with this command. The 238262306a36Sopenharmony_ci * list will start at the beginning of the 238362306a36Sopenharmony_ci * contiguous buffer. 238462306a36Sopenharmony_ci */ 238562306a36Sopenharmony_ci *prp2_entry = cpu_to_le64(prp_entry_dma); 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci /* 238862306a36Sopenharmony_ci * The next PRP Entry will be the start of the 238962306a36Sopenharmony_ci * first PRP List. 239062306a36Sopenharmony_ci */ 239162306a36Sopenharmony_ci prp_entry = prp_page; 239262306a36Sopenharmony_ci } else { 239362306a36Sopenharmony_ci /* 239462306a36Sopenharmony_ci * After this, the PRP Entries are complete. 239562306a36Sopenharmony_ci * This command uses 2 PRP's and no PRP list. 239662306a36Sopenharmony_ci */ 239762306a36Sopenharmony_ci *prp2_entry = cpu_to_le64(dma_addr); 239862306a36Sopenharmony_ci } 239962306a36Sopenharmony_ci } else { 240062306a36Sopenharmony_ci /* 240162306a36Sopenharmony_ci * Put entry in list and bump the addresses. 240262306a36Sopenharmony_ci * 240362306a36Sopenharmony_ci * After PRP1 and PRP2 are filled in, this will fill in 240462306a36Sopenharmony_ci * all remaining PRP entries in a PRP List, one per 240562306a36Sopenharmony_ci * each time through the loop. 240662306a36Sopenharmony_ci */ 240762306a36Sopenharmony_ci *prp_entry = cpu_to_le64(dma_addr); 240862306a36Sopenharmony_ci prp_entry++; 240962306a36Sopenharmony_ci prp_entry_dma++; 241062306a36Sopenharmony_ci } 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci /* 241362306a36Sopenharmony_ci * Bump the phys address of the command's data buffer by the 241462306a36Sopenharmony_ci * entry_len. 241562306a36Sopenharmony_ci */ 241662306a36Sopenharmony_ci dma_addr += entry_len; 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci /* Decrement length accounting for last partial page. */ 241962306a36Sopenharmony_ci if (entry_len > length) 242062306a36Sopenharmony_ci length = 0; 242162306a36Sopenharmony_ci else 242262306a36Sopenharmony_ci length -= entry_len; 242362306a36Sopenharmony_ci } 242462306a36Sopenharmony_ci} 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci/** 242762306a36Sopenharmony_ci * base_make_prp_nvme - Prepare PRPs (Physical Region Page) - 242862306a36Sopenharmony_ci * SGLs specific to NVMe drives only 242962306a36Sopenharmony_ci * 243062306a36Sopenharmony_ci * @ioc: per adapter object 243162306a36Sopenharmony_ci * @scmd: SCSI command from the mid-layer 243262306a36Sopenharmony_ci * @mpi_request: mpi request 243362306a36Sopenharmony_ci * @smid: msg Index 243462306a36Sopenharmony_ci * @sge_count: scatter gather element count. 243562306a36Sopenharmony_ci * 243662306a36Sopenharmony_ci * Return: true: PRPs are built 243762306a36Sopenharmony_ci * false: IEEE SGLs needs to be built 243862306a36Sopenharmony_ci */ 243962306a36Sopenharmony_cistatic void 244062306a36Sopenharmony_cibase_make_prp_nvme(struct MPT3SAS_ADAPTER *ioc, 244162306a36Sopenharmony_ci struct scsi_cmnd *scmd, 244262306a36Sopenharmony_ci Mpi25SCSIIORequest_t *mpi_request, 244362306a36Sopenharmony_ci u16 smid, int sge_count) 244462306a36Sopenharmony_ci{ 244562306a36Sopenharmony_ci int sge_len, num_prp_in_chain = 0; 244662306a36Sopenharmony_ci Mpi25IeeeSgeChain64_t *main_chain_element, *ptr_first_sgl; 244762306a36Sopenharmony_ci __le64 *curr_buff; 244862306a36Sopenharmony_ci dma_addr_t msg_dma, sge_addr, offset; 244962306a36Sopenharmony_ci u32 page_mask, page_mask_result; 245062306a36Sopenharmony_ci struct scatterlist *sg_scmd; 245162306a36Sopenharmony_ci u32 first_prp_len; 245262306a36Sopenharmony_ci int data_len = scsi_bufflen(scmd); 245362306a36Sopenharmony_ci u32 nvme_pg_size; 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci nvme_pg_size = max_t(u32, ioc->page_size, NVME_PRP_PAGE_SIZE); 245662306a36Sopenharmony_ci /* 245762306a36Sopenharmony_ci * Nvme has a very convoluted prp format. One prp is required 245862306a36Sopenharmony_ci * for each page or partial page. Driver need to split up OS sg_list 245962306a36Sopenharmony_ci * entries if it is longer than one page or cross a page 246062306a36Sopenharmony_ci * boundary. Driver also have to insert a PRP list pointer entry as 246162306a36Sopenharmony_ci * the last entry in each physical page of the PRP list. 246262306a36Sopenharmony_ci * 246362306a36Sopenharmony_ci * NOTE: The first PRP "entry" is actually placed in the first 246462306a36Sopenharmony_ci * SGL entry in the main message as IEEE 64 format. The 2nd 246562306a36Sopenharmony_ci * entry in the main message is the chain element, and the rest 246662306a36Sopenharmony_ci * of the PRP entries are built in the contiguous pcie buffer. 246762306a36Sopenharmony_ci */ 246862306a36Sopenharmony_ci page_mask = nvme_pg_size - 1; 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci /* 247162306a36Sopenharmony_ci * Native SGL is needed. 247262306a36Sopenharmony_ci * Put a chain element in main message frame that points to the first 247362306a36Sopenharmony_ci * chain buffer. 247462306a36Sopenharmony_ci * 247562306a36Sopenharmony_ci * NOTE: The ChainOffset field must be 0 when using a chain pointer to 247662306a36Sopenharmony_ci * a native SGL. 247762306a36Sopenharmony_ci */ 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci /* Set main message chain element pointer */ 248062306a36Sopenharmony_ci main_chain_element = (pMpi25IeeeSgeChain64_t)&mpi_request->SGL; 248162306a36Sopenharmony_ci /* 248262306a36Sopenharmony_ci * For NVMe the chain element needs to be the 2nd SG entry in the main 248362306a36Sopenharmony_ci * message. 248462306a36Sopenharmony_ci */ 248562306a36Sopenharmony_ci main_chain_element = (Mpi25IeeeSgeChain64_t *) 248662306a36Sopenharmony_ci ((u8 *)main_chain_element + sizeof(MPI25_IEEE_SGE_CHAIN64)); 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_ci /* 248962306a36Sopenharmony_ci * For the PRP entries, use the specially allocated buffer of 249062306a36Sopenharmony_ci * contiguous memory. Normal chain buffers can't be used 249162306a36Sopenharmony_ci * because each chain buffer would need to be the size of an OS 249262306a36Sopenharmony_ci * page (4k). 249362306a36Sopenharmony_ci */ 249462306a36Sopenharmony_ci curr_buff = mpt3sas_base_get_pcie_sgl(ioc, smid); 249562306a36Sopenharmony_ci msg_dma = mpt3sas_base_get_pcie_sgl_dma(ioc, smid); 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci main_chain_element->Address = cpu_to_le64(msg_dma); 249862306a36Sopenharmony_ci main_chain_element->NextChainOffset = 0; 249962306a36Sopenharmony_ci main_chain_element->Flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | 250062306a36Sopenharmony_ci MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR | 250162306a36Sopenharmony_ci MPI26_IEEE_SGE_FLAGS_NSF_NVME_PRP; 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci /* Build first prp, sge need not to be page aligned*/ 250462306a36Sopenharmony_ci ptr_first_sgl = (pMpi25IeeeSgeChain64_t)&mpi_request->SGL; 250562306a36Sopenharmony_ci sg_scmd = scsi_sglist(scmd); 250662306a36Sopenharmony_ci sge_addr = sg_dma_address(sg_scmd); 250762306a36Sopenharmony_ci sge_len = sg_dma_len(sg_scmd); 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci offset = sge_addr & page_mask; 251062306a36Sopenharmony_ci first_prp_len = nvme_pg_size - offset; 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci ptr_first_sgl->Address = cpu_to_le64(sge_addr); 251362306a36Sopenharmony_ci ptr_first_sgl->Length = cpu_to_le32(first_prp_len); 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci data_len -= first_prp_len; 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci if (sge_len > first_prp_len) { 251862306a36Sopenharmony_ci sge_addr += first_prp_len; 251962306a36Sopenharmony_ci sge_len -= first_prp_len; 252062306a36Sopenharmony_ci } else if (data_len && (sge_len == first_prp_len)) { 252162306a36Sopenharmony_ci sg_scmd = sg_next(sg_scmd); 252262306a36Sopenharmony_ci sge_addr = sg_dma_address(sg_scmd); 252362306a36Sopenharmony_ci sge_len = sg_dma_len(sg_scmd); 252462306a36Sopenharmony_ci } 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci for (;;) { 252762306a36Sopenharmony_ci offset = sge_addr & page_mask; 252862306a36Sopenharmony_ci 252962306a36Sopenharmony_ci /* Put PRP pointer due to page boundary*/ 253062306a36Sopenharmony_ci page_mask_result = (uintptr_t)(curr_buff + 1) & page_mask; 253162306a36Sopenharmony_ci if (unlikely(!page_mask_result)) { 253262306a36Sopenharmony_ci scmd_printk(KERN_NOTICE, 253362306a36Sopenharmony_ci scmd, "page boundary curr_buff: 0x%p\n", 253462306a36Sopenharmony_ci curr_buff); 253562306a36Sopenharmony_ci msg_dma += 8; 253662306a36Sopenharmony_ci *curr_buff = cpu_to_le64(msg_dma); 253762306a36Sopenharmony_ci curr_buff++; 253862306a36Sopenharmony_ci num_prp_in_chain++; 253962306a36Sopenharmony_ci } 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci *curr_buff = cpu_to_le64(sge_addr); 254262306a36Sopenharmony_ci curr_buff++; 254362306a36Sopenharmony_ci msg_dma += 8; 254462306a36Sopenharmony_ci num_prp_in_chain++; 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci sge_addr += nvme_pg_size; 254762306a36Sopenharmony_ci sge_len -= nvme_pg_size; 254862306a36Sopenharmony_ci data_len -= nvme_pg_size; 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci if (data_len <= 0) 255162306a36Sopenharmony_ci break; 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci if (sge_len > 0) 255462306a36Sopenharmony_ci continue; 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci sg_scmd = sg_next(sg_scmd); 255762306a36Sopenharmony_ci sge_addr = sg_dma_address(sg_scmd); 255862306a36Sopenharmony_ci sge_len = sg_dma_len(sg_scmd); 255962306a36Sopenharmony_ci } 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci main_chain_element->Length = 256262306a36Sopenharmony_ci cpu_to_le32(num_prp_in_chain * sizeof(u64)); 256362306a36Sopenharmony_ci return; 256462306a36Sopenharmony_ci} 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_cistatic bool 256762306a36Sopenharmony_cibase_is_prp_possible(struct MPT3SAS_ADAPTER *ioc, 256862306a36Sopenharmony_ci struct _pcie_device *pcie_device, struct scsi_cmnd *scmd, int sge_count) 256962306a36Sopenharmony_ci{ 257062306a36Sopenharmony_ci u32 data_length = 0; 257162306a36Sopenharmony_ci bool build_prp = true; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci data_length = scsi_bufflen(scmd); 257462306a36Sopenharmony_ci if (pcie_device && 257562306a36Sopenharmony_ci (mpt3sas_scsih_is_pcie_scsi_device(pcie_device->device_info))) { 257662306a36Sopenharmony_ci build_prp = false; 257762306a36Sopenharmony_ci return build_prp; 257862306a36Sopenharmony_ci } 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_ci /* If Datalenth is <= 16K and number of SGE’s entries are <= 2 258162306a36Sopenharmony_ci * we built IEEE SGL 258262306a36Sopenharmony_ci */ 258362306a36Sopenharmony_ci if ((data_length <= NVME_PRP_PAGE_SIZE*4) && (sge_count <= 2)) 258462306a36Sopenharmony_ci build_prp = false; 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci return build_prp; 258762306a36Sopenharmony_ci} 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci/** 259062306a36Sopenharmony_ci * _base_check_pcie_native_sgl - This function is called for PCIe end devices to 259162306a36Sopenharmony_ci * determine if the driver needs to build a native SGL. If so, that native 259262306a36Sopenharmony_ci * SGL is built in the special contiguous buffers allocated especially for 259362306a36Sopenharmony_ci * PCIe SGL creation. If the driver will not build a native SGL, return 259462306a36Sopenharmony_ci * TRUE and a normal IEEE SGL will be built. Currently this routine 259562306a36Sopenharmony_ci * supports NVMe. 259662306a36Sopenharmony_ci * @ioc: per adapter object 259762306a36Sopenharmony_ci * @mpi_request: mf request pointer 259862306a36Sopenharmony_ci * @smid: system request message index 259962306a36Sopenharmony_ci * @scmd: scsi command 260062306a36Sopenharmony_ci * @pcie_device: points to the PCIe device's info 260162306a36Sopenharmony_ci * 260262306a36Sopenharmony_ci * Return: 0 if native SGL was built, 1 if no SGL was built 260362306a36Sopenharmony_ci */ 260462306a36Sopenharmony_cistatic int 260562306a36Sopenharmony_ci_base_check_pcie_native_sgl(struct MPT3SAS_ADAPTER *ioc, 260662306a36Sopenharmony_ci Mpi25SCSIIORequest_t *mpi_request, u16 smid, struct scsi_cmnd *scmd, 260762306a36Sopenharmony_ci struct _pcie_device *pcie_device) 260862306a36Sopenharmony_ci{ 260962306a36Sopenharmony_ci int sges_left; 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci /* Get the SG list pointer and info. */ 261262306a36Sopenharmony_ci sges_left = scsi_dma_map(scmd); 261362306a36Sopenharmony_ci if (sges_left < 0) 261462306a36Sopenharmony_ci return 1; 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci /* Check if we need to build a native SG list. */ 261762306a36Sopenharmony_ci if (!base_is_prp_possible(ioc, pcie_device, 261862306a36Sopenharmony_ci scmd, sges_left)) { 261962306a36Sopenharmony_ci /* We built a native SG list, just return. */ 262062306a36Sopenharmony_ci goto out; 262162306a36Sopenharmony_ci } 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_ci /* 262462306a36Sopenharmony_ci * Build native NVMe PRP. 262562306a36Sopenharmony_ci */ 262662306a36Sopenharmony_ci base_make_prp_nvme(ioc, scmd, mpi_request, 262762306a36Sopenharmony_ci smid, sges_left); 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci return 0; 263062306a36Sopenharmony_ciout: 263162306a36Sopenharmony_ci scsi_dma_unmap(scmd); 263262306a36Sopenharmony_ci return 1; 263362306a36Sopenharmony_ci} 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_ci/** 263662306a36Sopenharmony_ci * _base_add_sg_single_ieee - add sg element for IEEE format 263762306a36Sopenharmony_ci * @paddr: virtual address for SGE 263862306a36Sopenharmony_ci * @flags: SGE flags 263962306a36Sopenharmony_ci * @chain_offset: number of 128 byte elements from start of segment 264062306a36Sopenharmony_ci * @length: data transfer length 264162306a36Sopenharmony_ci * @dma_addr: Physical address 264262306a36Sopenharmony_ci */ 264362306a36Sopenharmony_cistatic void 264462306a36Sopenharmony_ci_base_add_sg_single_ieee(void *paddr, u8 flags, u8 chain_offset, u32 length, 264562306a36Sopenharmony_ci dma_addr_t dma_addr) 264662306a36Sopenharmony_ci{ 264762306a36Sopenharmony_ci Mpi25IeeeSgeChain64_t *sgel = paddr; 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci sgel->Flags = flags; 265062306a36Sopenharmony_ci sgel->NextChainOffset = chain_offset; 265162306a36Sopenharmony_ci sgel->Length = cpu_to_le32(length); 265262306a36Sopenharmony_ci sgel->Address = cpu_to_le64(dma_addr); 265362306a36Sopenharmony_ci} 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci/** 265662306a36Sopenharmony_ci * _base_build_zero_len_sge_ieee - build zero length sg entry for IEEE format 265762306a36Sopenharmony_ci * @ioc: per adapter object 265862306a36Sopenharmony_ci * @paddr: virtual address for SGE 265962306a36Sopenharmony_ci * 266062306a36Sopenharmony_ci * Create a zero length scatter gather entry to insure the IOCs hardware has 266162306a36Sopenharmony_ci * something to use if the target device goes brain dead and tries 266262306a36Sopenharmony_ci * to send data even when none is asked for. 266362306a36Sopenharmony_ci */ 266462306a36Sopenharmony_cistatic void 266562306a36Sopenharmony_ci_base_build_zero_len_sge_ieee(struct MPT3SAS_ADAPTER *ioc, void *paddr) 266662306a36Sopenharmony_ci{ 266762306a36Sopenharmony_ci u8 sgl_flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | 266862306a36Sopenharmony_ci MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR | 266962306a36Sopenharmony_ci MPI25_IEEE_SGE_FLAGS_END_OF_LIST); 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci _base_add_sg_single_ieee(paddr, sgl_flags, 0, 0, -1); 267262306a36Sopenharmony_ci} 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci/** 267562306a36Sopenharmony_ci * _base_build_sg_scmd - main sg creation routine 267662306a36Sopenharmony_ci * pcie_device is unused here! 267762306a36Sopenharmony_ci * @ioc: per adapter object 267862306a36Sopenharmony_ci * @scmd: scsi command 267962306a36Sopenharmony_ci * @smid: system request message index 268062306a36Sopenharmony_ci * @unused: unused pcie_device pointer 268162306a36Sopenharmony_ci * Context: none. 268262306a36Sopenharmony_ci * 268362306a36Sopenharmony_ci * The main routine that builds scatter gather table from a given 268462306a36Sopenharmony_ci * scsi request sent via the .queuecommand main handler. 268562306a36Sopenharmony_ci * 268662306a36Sopenharmony_ci * Return: 0 success, anything else error 268762306a36Sopenharmony_ci */ 268862306a36Sopenharmony_cistatic int 268962306a36Sopenharmony_ci_base_build_sg_scmd(struct MPT3SAS_ADAPTER *ioc, 269062306a36Sopenharmony_ci struct scsi_cmnd *scmd, u16 smid, struct _pcie_device *unused) 269162306a36Sopenharmony_ci{ 269262306a36Sopenharmony_ci Mpi2SCSIIORequest_t *mpi_request; 269362306a36Sopenharmony_ci dma_addr_t chain_dma; 269462306a36Sopenharmony_ci struct scatterlist *sg_scmd; 269562306a36Sopenharmony_ci void *sg_local, *chain; 269662306a36Sopenharmony_ci u32 chain_offset; 269762306a36Sopenharmony_ci u32 chain_length; 269862306a36Sopenharmony_ci u32 chain_flags; 269962306a36Sopenharmony_ci int sges_left; 270062306a36Sopenharmony_ci u32 sges_in_segment; 270162306a36Sopenharmony_ci u32 sgl_flags; 270262306a36Sopenharmony_ci u32 sgl_flags_last_element; 270362306a36Sopenharmony_ci u32 sgl_flags_end_buffer; 270462306a36Sopenharmony_ci struct chain_tracker *chain_req; 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_ci mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ci /* init scatter gather flags */ 270962306a36Sopenharmony_ci sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT; 271062306a36Sopenharmony_ci if (scmd->sc_data_direction == DMA_TO_DEVICE) 271162306a36Sopenharmony_ci sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC; 271262306a36Sopenharmony_ci sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT) 271362306a36Sopenharmony_ci << MPI2_SGE_FLAGS_SHIFT; 271462306a36Sopenharmony_ci sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT | 271562306a36Sopenharmony_ci MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST) 271662306a36Sopenharmony_ci << MPI2_SGE_FLAGS_SHIFT; 271762306a36Sopenharmony_ci sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci sg_scmd = scsi_sglist(scmd); 272062306a36Sopenharmony_ci sges_left = scsi_dma_map(scmd); 272162306a36Sopenharmony_ci if (sges_left < 0) 272262306a36Sopenharmony_ci return -ENOMEM; 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci sg_local = &mpi_request->SGL; 272562306a36Sopenharmony_ci sges_in_segment = ioc->max_sges_in_main_message; 272662306a36Sopenharmony_ci if (sges_left <= sges_in_segment) 272762306a36Sopenharmony_ci goto fill_in_last_segment; 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) + 273062306a36Sopenharmony_ci (sges_in_segment * ioc->sge_size))/4; 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_ci /* fill in main message segment when there is a chain following */ 273362306a36Sopenharmony_ci while (sges_in_segment) { 273462306a36Sopenharmony_ci if (sges_in_segment == 1) 273562306a36Sopenharmony_ci ioc->base_add_sg_single(sg_local, 273662306a36Sopenharmony_ci sgl_flags_last_element | sg_dma_len(sg_scmd), 273762306a36Sopenharmony_ci sg_dma_address(sg_scmd)); 273862306a36Sopenharmony_ci else 273962306a36Sopenharmony_ci ioc->base_add_sg_single(sg_local, sgl_flags | 274062306a36Sopenharmony_ci sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); 274162306a36Sopenharmony_ci sg_scmd = sg_next(sg_scmd); 274262306a36Sopenharmony_ci sg_local += ioc->sge_size; 274362306a36Sopenharmony_ci sges_left--; 274462306a36Sopenharmony_ci sges_in_segment--; 274562306a36Sopenharmony_ci } 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci /* initializing the chain flags and pointers */ 274862306a36Sopenharmony_ci chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT; 274962306a36Sopenharmony_ci chain_req = _base_get_chain_buffer_tracker(ioc, scmd); 275062306a36Sopenharmony_ci if (!chain_req) 275162306a36Sopenharmony_ci return -1; 275262306a36Sopenharmony_ci chain = chain_req->chain_buffer; 275362306a36Sopenharmony_ci chain_dma = chain_req->chain_buffer_dma; 275462306a36Sopenharmony_ci do { 275562306a36Sopenharmony_ci sges_in_segment = (sges_left <= 275662306a36Sopenharmony_ci ioc->max_sges_in_chain_message) ? sges_left : 275762306a36Sopenharmony_ci ioc->max_sges_in_chain_message; 275862306a36Sopenharmony_ci chain_offset = (sges_left == sges_in_segment) ? 275962306a36Sopenharmony_ci 0 : (sges_in_segment * ioc->sge_size)/4; 276062306a36Sopenharmony_ci chain_length = sges_in_segment * ioc->sge_size; 276162306a36Sopenharmony_ci if (chain_offset) { 276262306a36Sopenharmony_ci chain_offset = chain_offset << 276362306a36Sopenharmony_ci MPI2_SGE_CHAIN_OFFSET_SHIFT; 276462306a36Sopenharmony_ci chain_length += ioc->sge_size; 276562306a36Sopenharmony_ci } 276662306a36Sopenharmony_ci ioc->base_add_sg_single(sg_local, chain_flags | chain_offset | 276762306a36Sopenharmony_ci chain_length, chain_dma); 276862306a36Sopenharmony_ci sg_local = chain; 276962306a36Sopenharmony_ci if (!chain_offset) 277062306a36Sopenharmony_ci goto fill_in_last_segment; 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci /* fill in chain segments */ 277362306a36Sopenharmony_ci while (sges_in_segment) { 277462306a36Sopenharmony_ci if (sges_in_segment == 1) 277562306a36Sopenharmony_ci ioc->base_add_sg_single(sg_local, 277662306a36Sopenharmony_ci sgl_flags_last_element | 277762306a36Sopenharmony_ci sg_dma_len(sg_scmd), 277862306a36Sopenharmony_ci sg_dma_address(sg_scmd)); 277962306a36Sopenharmony_ci else 278062306a36Sopenharmony_ci ioc->base_add_sg_single(sg_local, sgl_flags | 278162306a36Sopenharmony_ci sg_dma_len(sg_scmd), 278262306a36Sopenharmony_ci sg_dma_address(sg_scmd)); 278362306a36Sopenharmony_ci sg_scmd = sg_next(sg_scmd); 278462306a36Sopenharmony_ci sg_local += ioc->sge_size; 278562306a36Sopenharmony_ci sges_left--; 278662306a36Sopenharmony_ci sges_in_segment--; 278762306a36Sopenharmony_ci } 278862306a36Sopenharmony_ci 278962306a36Sopenharmony_ci chain_req = _base_get_chain_buffer_tracker(ioc, scmd); 279062306a36Sopenharmony_ci if (!chain_req) 279162306a36Sopenharmony_ci return -1; 279262306a36Sopenharmony_ci chain = chain_req->chain_buffer; 279362306a36Sopenharmony_ci chain_dma = chain_req->chain_buffer_dma; 279462306a36Sopenharmony_ci } while (1); 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_ci fill_in_last_segment: 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci /* fill the last segment */ 280062306a36Sopenharmony_ci while (sges_left) { 280162306a36Sopenharmony_ci if (sges_left == 1) 280262306a36Sopenharmony_ci ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer | 280362306a36Sopenharmony_ci sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); 280462306a36Sopenharmony_ci else 280562306a36Sopenharmony_ci ioc->base_add_sg_single(sg_local, sgl_flags | 280662306a36Sopenharmony_ci sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); 280762306a36Sopenharmony_ci sg_scmd = sg_next(sg_scmd); 280862306a36Sopenharmony_ci sg_local += ioc->sge_size; 280962306a36Sopenharmony_ci sges_left--; 281062306a36Sopenharmony_ci } 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci return 0; 281362306a36Sopenharmony_ci} 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci/** 281662306a36Sopenharmony_ci * _base_build_sg_scmd_ieee - main sg creation routine for IEEE format 281762306a36Sopenharmony_ci * @ioc: per adapter object 281862306a36Sopenharmony_ci * @scmd: scsi command 281962306a36Sopenharmony_ci * @smid: system request message index 282062306a36Sopenharmony_ci * @pcie_device: Pointer to pcie_device. If set, the pcie native sgl will be 282162306a36Sopenharmony_ci * constructed on need. 282262306a36Sopenharmony_ci * Context: none. 282362306a36Sopenharmony_ci * 282462306a36Sopenharmony_ci * The main routine that builds scatter gather table from a given 282562306a36Sopenharmony_ci * scsi request sent via the .queuecommand main handler. 282662306a36Sopenharmony_ci * 282762306a36Sopenharmony_ci * Return: 0 success, anything else error 282862306a36Sopenharmony_ci */ 282962306a36Sopenharmony_cistatic int 283062306a36Sopenharmony_ci_base_build_sg_scmd_ieee(struct MPT3SAS_ADAPTER *ioc, 283162306a36Sopenharmony_ci struct scsi_cmnd *scmd, u16 smid, struct _pcie_device *pcie_device) 283262306a36Sopenharmony_ci{ 283362306a36Sopenharmony_ci Mpi25SCSIIORequest_t *mpi_request; 283462306a36Sopenharmony_ci dma_addr_t chain_dma; 283562306a36Sopenharmony_ci struct scatterlist *sg_scmd; 283662306a36Sopenharmony_ci void *sg_local, *chain; 283762306a36Sopenharmony_ci u32 chain_offset; 283862306a36Sopenharmony_ci u32 chain_length; 283962306a36Sopenharmony_ci int sges_left; 284062306a36Sopenharmony_ci u32 sges_in_segment; 284162306a36Sopenharmony_ci u8 simple_sgl_flags; 284262306a36Sopenharmony_ci u8 simple_sgl_flags_last; 284362306a36Sopenharmony_ci u8 chain_sgl_flags; 284462306a36Sopenharmony_ci struct chain_tracker *chain_req; 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_ci /* init scatter gather flags */ 284962306a36Sopenharmony_ci simple_sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | 285062306a36Sopenharmony_ci MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; 285162306a36Sopenharmony_ci simple_sgl_flags_last = simple_sgl_flags | 285262306a36Sopenharmony_ci MPI25_IEEE_SGE_FLAGS_END_OF_LIST; 285362306a36Sopenharmony_ci chain_sgl_flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | 285462306a36Sopenharmony_ci MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci /* Check if we need to build a native SG list. */ 285762306a36Sopenharmony_ci if ((pcie_device) && (_base_check_pcie_native_sgl(ioc, mpi_request, 285862306a36Sopenharmony_ci smid, scmd, pcie_device) == 0)) { 285962306a36Sopenharmony_ci /* We built a native SG list, just return. */ 286062306a36Sopenharmony_ci return 0; 286162306a36Sopenharmony_ci } 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci sg_scmd = scsi_sglist(scmd); 286462306a36Sopenharmony_ci sges_left = scsi_dma_map(scmd); 286562306a36Sopenharmony_ci if (sges_left < 0) 286662306a36Sopenharmony_ci return -ENOMEM; 286762306a36Sopenharmony_ci 286862306a36Sopenharmony_ci sg_local = &mpi_request->SGL; 286962306a36Sopenharmony_ci sges_in_segment = (ioc->request_sz - 287062306a36Sopenharmony_ci offsetof(Mpi25SCSIIORequest_t, SGL))/ioc->sge_size_ieee; 287162306a36Sopenharmony_ci if (sges_left <= sges_in_segment) 287262306a36Sopenharmony_ci goto fill_in_last_segment; 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci mpi_request->ChainOffset = (sges_in_segment - 1 /* chain element */) + 287562306a36Sopenharmony_ci (offsetof(Mpi25SCSIIORequest_t, SGL)/ioc->sge_size_ieee); 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_ci /* fill in main message segment when there is a chain following */ 287862306a36Sopenharmony_ci while (sges_in_segment > 1) { 287962306a36Sopenharmony_ci _base_add_sg_single_ieee(sg_local, simple_sgl_flags, 0, 288062306a36Sopenharmony_ci sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); 288162306a36Sopenharmony_ci sg_scmd = sg_next(sg_scmd); 288262306a36Sopenharmony_ci sg_local += ioc->sge_size_ieee; 288362306a36Sopenharmony_ci sges_left--; 288462306a36Sopenharmony_ci sges_in_segment--; 288562306a36Sopenharmony_ci } 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci /* initializing the pointers */ 288862306a36Sopenharmony_ci chain_req = _base_get_chain_buffer_tracker(ioc, scmd); 288962306a36Sopenharmony_ci if (!chain_req) 289062306a36Sopenharmony_ci return -1; 289162306a36Sopenharmony_ci chain = chain_req->chain_buffer; 289262306a36Sopenharmony_ci chain_dma = chain_req->chain_buffer_dma; 289362306a36Sopenharmony_ci do { 289462306a36Sopenharmony_ci sges_in_segment = (sges_left <= 289562306a36Sopenharmony_ci ioc->max_sges_in_chain_message) ? sges_left : 289662306a36Sopenharmony_ci ioc->max_sges_in_chain_message; 289762306a36Sopenharmony_ci chain_offset = (sges_left == sges_in_segment) ? 289862306a36Sopenharmony_ci 0 : sges_in_segment; 289962306a36Sopenharmony_ci chain_length = sges_in_segment * ioc->sge_size_ieee; 290062306a36Sopenharmony_ci if (chain_offset) 290162306a36Sopenharmony_ci chain_length += ioc->sge_size_ieee; 290262306a36Sopenharmony_ci _base_add_sg_single_ieee(sg_local, chain_sgl_flags, 290362306a36Sopenharmony_ci chain_offset, chain_length, chain_dma); 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci sg_local = chain; 290662306a36Sopenharmony_ci if (!chain_offset) 290762306a36Sopenharmony_ci goto fill_in_last_segment; 290862306a36Sopenharmony_ci 290962306a36Sopenharmony_ci /* fill in chain segments */ 291062306a36Sopenharmony_ci while (sges_in_segment) { 291162306a36Sopenharmony_ci _base_add_sg_single_ieee(sg_local, simple_sgl_flags, 0, 291262306a36Sopenharmony_ci sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); 291362306a36Sopenharmony_ci sg_scmd = sg_next(sg_scmd); 291462306a36Sopenharmony_ci sg_local += ioc->sge_size_ieee; 291562306a36Sopenharmony_ci sges_left--; 291662306a36Sopenharmony_ci sges_in_segment--; 291762306a36Sopenharmony_ci } 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci chain_req = _base_get_chain_buffer_tracker(ioc, scmd); 292062306a36Sopenharmony_ci if (!chain_req) 292162306a36Sopenharmony_ci return -1; 292262306a36Sopenharmony_ci chain = chain_req->chain_buffer; 292362306a36Sopenharmony_ci chain_dma = chain_req->chain_buffer_dma; 292462306a36Sopenharmony_ci } while (1); 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ci fill_in_last_segment: 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_ci /* fill the last segment */ 293062306a36Sopenharmony_ci while (sges_left > 0) { 293162306a36Sopenharmony_ci if (sges_left == 1) 293262306a36Sopenharmony_ci _base_add_sg_single_ieee(sg_local, 293362306a36Sopenharmony_ci simple_sgl_flags_last, 0, sg_dma_len(sg_scmd), 293462306a36Sopenharmony_ci sg_dma_address(sg_scmd)); 293562306a36Sopenharmony_ci else 293662306a36Sopenharmony_ci _base_add_sg_single_ieee(sg_local, simple_sgl_flags, 0, 293762306a36Sopenharmony_ci sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); 293862306a36Sopenharmony_ci sg_scmd = sg_next(sg_scmd); 293962306a36Sopenharmony_ci sg_local += ioc->sge_size_ieee; 294062306a36Sopenharmony_ci sges_left--; 294162306a36Sopenharmony_ci } 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci return 0; 294462306a36Sopenharmony_ci} 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci/** 294762306a36Sopenharmony_ci * _base_build_sg_ieee - build generic sg for IEEE format 294862306a36Sopenharmony_ci * @ioc: per adapter object 294962306a36Sopenharmony_ci * @psge: virtual address for SGE 295062306a36Sopenharmony_ci * @data_out_dma: physical address for WRITES 295162306a36Sopenharmony_ci * @data_out_sz: data xfer size for WRITES 295262306a36Sopenharmony_ci * @data_in_dma: physical address for READS 295362306a36Sopenharmony_ci * @data_in_sz: data xfer size for READS 295462306a36Sopenharmony_ci */ 295562306a36Sopenharmony_cistatic void 295662306a36Sopenharmony_ci_base_build_sg_ieee(struct MPT3SAS_ADAPTER *ioc, void *psge, 295762306a36Sopenharmony_ci dma_addr_t data_out_dma, size_t data_out_sz, dma_addr_t data_in_dma, 295862306a36Sopenharmony_ci size_t data_in_sz) 295962306a36Sopenharmony_ci{ 296062306a36Sopenharmony_ci u8 sgl_flags; 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci if (!data_out_sz && !data_in_sz) { 296362306a36Sopenharmony_ci _base_build_zero_len_sge_ieee(ioc, psge); 296462306a36Sopenharmony_ci return; 296562306a36Sopenharmony_ci } 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci if (data_out_sz && data_in_sz) { 296862306a36Sopenharmony_ci /* WRITE sgel first */ 296962306a36Sopenharmony_ci sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | 297062306a36Sopenharmony_ci MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; 297162306a36Sopenharmony_ci _base_add_sg_single_ieee(psge, sgl_flags, 0, data_out_sz, 297262306a36Sopenharmony_ci data_out_dma); 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci /* incr sgel */ 297562306a36Sopenharmony_ci psge += ioc->sge_size_ieee; 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ci /* READ sgel last */ 297862306a36Sopenharmony_ci sgl_flags |= MPI25_IEEE_SGE_FLAGS_END_OF_LIST; 297962306a36Sopenharmony_ci _base_add_sg_single_ieee(psge, sgl_flags, 0, data_in_sz, 298062306a36Sopenharmony_ci data_in_dma); 298162306a36Sopenharmony_ci } else if (data_out_sz) /* WRITE */ { 298262306a36Sopenharmony_ci sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | 298362306a36Sopenharmony_ci MPI25_IEEE_SGE_FLAGS_END_OF_LIST | 298462306a36Sopenharmony_ci MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; 298562306a36Sopenharmony_ci _base_add_sg_single_ieee(psge, sgl_flags, 0, data_out_sz, 298662306a36Sopenharmony_ci data_out_dma); 298762306a36Sopenharmony_ci } else if (data_in_sz) /* READ */ { 298862306a36Sopenharmony_ci sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | 298962306a36Sopenharmony_ci MPI25_IEEE_SGE_FLAGS_END_OF_LIST | 299062306a36Sopenharmony_ci MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; 299162306a36Sopenharmony_ci _base_add_sg_single_ieee(psge, sgl_flags, 0, data_in_sz, 299262306a36Sopenharmony_ci data_in_dma); 299362306a36Sopenharmony_ci } 299462306a36Sopenharmony_ci} 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci#define convert_to_kb(x) ((x) << (PAGE_SHIFT - 10)) 299762306a36Sopenharmony_ci 299862306a36Sopenharmony_ci/** 299962306a36Sopenharmony_ci * _base_config_dma_addressing - set dma addressing 300062306a36Sopenharmony_ci * @ioc: per adapter object 300162306a36Sopenharmony_ci * @pdev: PCI device struct 300262306a36Sopenharmony_ci * 300362306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 300462306a36Sopenharmony_ci */ 300562306a36Sopenharmony_cistatic int 300662306a36Sopenharmony_ci_base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev) 300762306a36Sopenharmony_ci{ 300862306a36Sopenharmony_ci struct sysinfo s; 300962306a36Sopenharmony_ci u64 coherent_dma_mask, dma_mask; 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_ci if (ioc->is_mcpu_endpoint || sizeof(dma_addr_t) == 4) { 301262306a36Sopenharmony_ci ioc->dma_mask = 32; 301362306a36Sopenharmony_ci coherent_dma_mask = dma_mask = DMA_BIT_MASK(32); 301462306a36Sopenharmony_ci /* Set 63 bit DMA mask for all SAS3 and SAS35 controllers */ 301562306a36Sopenharmony_ci } else if (ioc->hba_mpi_version_belonged > MPI2_VERSION) { 301662306a36Sopenharmony_ci ioc->dma_mask = 63; 301762306a36Sopenharmony_ci coherent_dma_mask = dma_mask = DMA_BIT_MASK(63); 301862306a36Sopenharmony_ci } else { 301962306a36Sopenharmony_ci ioc->dma_mask = 64; 302062306a36Sopenharmony_ci coherent_dma_mask = dma_mask = DMA_BIT_MASK(64); 302162306a36Sopenharmony_ci } 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci if (ioc->use_32bit_dma) 302462306a36Sopenharmony_ci coherent_dma_mask = DMA_BIT_MASK(32); 302562306a36Sopenharmony_ci 302662306a36Sopenharmony_ci if (dma_set_mask(&pdev->dev, dma_mask) || 302762306a36Sopenharmony_ci dma_set_coherent_mask(&pdev->dev, coherent_dma_mask)) 302862306a36Sopenharmony_ci return -ENODEV; 302962306a36Sopenharmony_ci 303062306a36Sopenharmony_ci if (ioc->dma_mask > 32) { 303162306a36Sopenharmony_ci ioc->base_add_sg_single = &_base_add_sg_single_64; 303262306a36Sopenharmony_ci ioc->sge_size = sizeof(Mpi2SGESimple64_t); 303362306a36Sopenharmony_ci } else { 303462306a36Sopenharmony_ci ioc->base_add_sg_single = &_base_add_sg_single_32; 303562306a36Sopenharmony_ci ioc->sge_size = sizeof(Mpi2SGESimple32_t); 303662306a36Sopenharmony_ci } 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_ci si_meminfo(&s); 303962306a36Sopenharmony_ci ioc_info(ioc, "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n", 304062306a36Sopenharmony_ci ioc->dma_mask, convert_to_kb(s.totalram)); 304162306a36Sopenharmony_ci 304262306a36Sopenharmony_ci return 0; 304362306a36Sopenharmony_ci} 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci/** 304662306a36Sopenharmony_ci * _base_check_enable_msix - checks MSIX capabable. 304762306a36Sopenharmony_ci * @ioc: per adapter object 304862306a36Sopenharmony_ci * 304962306a36Sopenharmony_ci * Check to see if card is capable of MSIX, and set number 305062306a36Sopenharmony_ci * of available msix vectors 305162306a36Sopenharmony_ci */ 305262306a36Sopenharmony_cistatic int 305362306a36Sopenharmony_ci_base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc) 305462306a36Sopenharmony_ci{ 305562306a36Sopenharmony_ci int base; 305662306a36Sopenharmony_ci u16 message_control; 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci /* Check whether controller SAS2008 B0 controller, 305962306a36Sopenharmony_ci * if it is SAS2008 B0 controller use IO-APIC instead of MSIX 306062306a36Sopenharmony_ci */ 306162306a36Sopenharmony_ci if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 && 306262306a36Sopenharmony_ci ioc->pdev->revision == SAS2_PCI_DEVICE_B0_REVISION) { 306362306a36Sopenharmony_ci return -EINVAL; 306462306a36Sopenharmony_ci } 306562306a36Sopenharmony_ci 306662306a36Sopenharmony_ci base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); 306762306a36Sopenharmony_ci if (!base) { 306862306a36Sopenharmony_ci dfailprintk(ioc, ioc_info(ioc, "msix not supported\n")); 306962306a36Sopenharmony_ci return -EINVAL; 307062306a36Sopenharmony_ci } 307162306a36Sopenharmony_ci 307262306a36Sopenharmony_ci /* get msix vector count */ 307362306a36Sopenharmony_ci /* NUMA_IO not supported for older controllers */ 307462306a36Sopenharmony_ci if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 || 307562306a36Sopenharmony_ci ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 || 307662306a36Sopenharmony_ci ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 || 307762306a36Sopenharmony_ci ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 || 307862306a36Sopenharmony_ci ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 || 307962306a36Sopenharmony_ci ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 || 308062306a36Sopenharmony_ci ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2) 308162306a36Sopenharmony_ci ioc->msix_vector_count = 1; 308262306a36Sopenharmony_ci else { 308362306a36Sopenharmony_ci pci_read_config_word(ioc->pdev, base + 2, &message_control); 308462306a36Sopenharmony_ci ioc->msix_vector_count = (message_control & 0x3FF) + 1; 308562306a36Sopenharmony_ci } 308662306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "msix is supported, vector_count(%d)\n", 308762306a36Sopenharmony_ci ioc->msix_vector_count)); 308862306a36Sopenharmony_ci return 0; 308962306a36Sopenharmony_ci} 309062306a36Sopenharmony_ci 309162306a36Sopenharmony_ci/** 309262306a36Sopenharmony_ci * mpt3sas_base_free_irq - free irq 309362306a36Sopenharmony_ci * @ioc: per adapter object 309462306a36Sopenharmony_ci * 309562306a36Sopenharmony_ci * Freeing respective reply_queue from the list. 309662306a36Sopenharmony_ci */ 309762306a36Sopenharmony_civoid 309862306a36Sopenharmony_cimpt3sas_base_free_irq(struct MPT3SAS_ADAPTER *ioc) 309962306a36Sopenharmony_ci{ 310062306a36Sopenharmony_ci unsigned int irq; 310162306a36Sopenharmony_ci struct adapter_reply_queue *reply_q, *next; 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci if (list_empty(&ioc->reply_queue_list)) 310462306a36Sopenharmony_ci return; 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { 310762306a36Sopenharmony_ci list_del(&reply_q->list); 310862306a36Sopenharmony_ci if (reply_q->is_iouring_poll_q) { 310962306a36Sopenharmony_ci kfree(reply_q); 311062306a36Sopenharmony_ci continue; 311162306a36Sopenharmony_ci } 311262306a36Sopenharmony_ci 311362306a36Sopenharmony_ci if (ioc->smp_affinity_enable) { 311462306a36Sopenharmony_ci irq = pci_irq_vector(ioc->pdev, reply_q->msix_index); 311562306a36Sopenharmony_ci irq_update_affinity_hint(irq, NULL); 311662306a36Sopenharmony_ci } 311762306a36Sopenharmony_ci free_irq(pci_irq_vector(ioc->pdev, reply_q->msix_index), 311862306a36Sopenharmony_ci reply_q); 311962306a36Sopenharmony_ci kfree(reply_q); 312062306a36Sopenharmony_ci } 312162306a36Sopenharmony_ci} 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ci/** 312462306a36Sopenharmony_ci * _base_request_irq - request irq 312562306a36Sopenharmony_ci * @ioc: per adapter object 312662306a36Sopenharmony_ci * @index: msix index into vector table 312762306a36Sopenharmony_ci * 312862306a36Sopenharmony_ci * Inserting respective reply_queue into the list. 312962306a36Sopenharmony_ci */ 313062306a36Sopenharmony_cistatic int 313162306a36Sopenharmony_ci_base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index) 313262306a36Sopenharmony_ci{ 313362306a36Sopenharmony_ci struct pci_dev *pdev = ioc->pdev; 313462306a36Sopenharmony_ci struct adapter_reply_queue *reply_q; 313562306a36Sopenharmony_ci int r, qid; 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL); 313862306a36Sopenharmony_ci if (!reply_q) { 313962306a36Sopenharmony_ci ioc_err(ioc, "unable to allocate memory %zu!\n", 314062306a36Sopenharmony_ci sizeof(struct adapter_reply_queue)); 314162306a36Sopenharmony_ci return -ENOMEM; 314262306a36Sopenharmony_ci } 314362306a36Sopenharmony_ci reply_q->ioc = ioc; 314462306a36Sopenharmony_ci reply_q->msix_index = index; 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_ci atomic_set(&reply_q->busy, 0); 314762306a36Sopenharmony_ci 314862306a36Sopenharmony_ci if (index >= ioc->iopoll_q_start_index) { 314962306a36Sopenharmony_ci qid = index - ioc->iopoll_q_start_index; 315062306a36Sopenharmony_ci snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-mq-poll%d", 315162306a36Sopenharmony_ci ioc->driver_name, ioc->id, qid); 315262306a36Sopenharmony_ci reply_q->is_iouring_poll_q = 1; 315362306a36Sopenharmony_ci ioc->io_uring_poll_queues[qid].reply_q = reply_q; 315462306a36Sopenharmony_ci goto out; 315562306a36Sopenharmony_ci } 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_ci if (ioc->msix_enable) 315962306a36Sopenharmony_ci snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", 316062306a36Sopenharmony_ci ioc->driver_name, ioc->id, index); 316162306a36Sopenharmony_ci else 316262306a36Sopenharmony_ci snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", 316362306a36Sopenharmony_ci ioc->driver_name, ioc->id); 316462306a36Sopenharmony_ci r = request_irq(pci_irq_vector(pdev, index), _base_interrupt, 316562306a36Sopenharmony_ci IRQF_SHARED, reply_q->name, reply_q); 316662306a36Sopenharmony_ci if (r) { 316762306a36Sopenharmony_ci pr_err("%s: unable to allocate interrupt %d!\n", 316862306a36Sopenharmony_ci reply_q->name, pci_irq_vector(pdev, index)); 316962306a36Sopenharmony_ci kfree(reply_q); 317062306a36Sopenharmony_ci return -EBUSY; 317162306a36Sopenharmony_ci } 317262306a36Sopenharmony_ciout: 317362306a36Sopenharmony_ci INIT_LIST_HEAD(&reply_q->list); 317462306a36Sopenharmony_ci list_add_tail(&reply_q->list, &ioc->reply_queue_list); 317562306a36Sopenharmony_ci return 0; 317662306a36Sopenharmony_ci} 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci/** 317962306a36Sopenharmony_ci * _base_assign_reply_queues - assigning msix index for each cpu 318062306a36Sopenharmony_ci * @ioc: per adapter object 318162306a36Sopenharmony_ci * 318262306a36Sopenharmony_ci * The enduser would need to set the affinity via /proc/irq/#/smp_affinity 318362306a36Sopenharmony_ci */ 318462306a36Sopenharmony_cistatic void 318562306a36Sopenharmony_ci_base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) 318662306a36Sopenharmony_ci{ 318762306a36Sopenharmony_ci unsigned int cpu, nr_cpus, nr_msix, index = 0, irq; 318862306a36Sopenharmony_ci struct adapter_reply_queue *reply_q; 318962306a36Sopenharmony_ci int iopoll_q_count = ioc->reply_queue_count - 319062306a36Sopenharmony_ci ioc->iopoll_q_start_index; 319162306a36Sopenharmony_ci const struct cpumask *mask; 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_ci if (!_base_is_controller_msix_enabled(ioc)) 319462306a36Sopenharmony_ci return; 319562306a36Sopenharmony_ci 319662306a36Sopenharmony_ci if (ioc->msix_load_balance) 319762306a36Sopenharmony_ci return; 319862306a36Sopenharmony_ci 319962306a36Sopenharmony_ci memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz); 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_ci nr_cpus = num_online_cpus(); 320262306a36Sopenharmony_ci nr_msix = ioc->reply_queue_count = min(ioc->reply_queue_count, 320362306a36Sopenharmony_ci ioc->facts.MaxMSIxVectors); 320462306a36Sopenharmony_ci if (!nr_msix) 320562306a36Sopenharmony_ci return; 320662306a36Sopenharmony_ci 320762306a36Sopenharmony_ci if (ioc->smp_affinity_enable) { 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_ci /* 321062306a36Sopenharmony_ci * set irq affinity to local numa node for those irqs 321162306a36Sopenharmony_ci * corresponding to high iops queues. 321262306a36Sopenharmony_ci */ 321362306a36Sopenharmony_ci if (ioc->high_iops_queues) { 321462306a36Sopenharmony_ci mask = cpumask_of_node(dev_to_node(&ioc->pdev->dev)); 321562306a36Sopenharmony_ci for (index = 0; index < ioc->high_iops_queues; 321662306a36Sopenharmony_ci index++) { 321762306a36Sopenharmony_ci irq = pci_irq_vector(ioc->pdev, index); 321862306a36Sopenharmony_ci irq_set_affinity_and_hint(irq, mask); 321962306a36Sopenharmony_ci } 322062306a36Sopenharmony_ci } 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { 322362306a36Sopenharmony_ci const cpumask_t *mask; 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_ci if (reply_q->msix_index < ioc->high_iops_queues || 322662306a36Sopenharmony_ci reply_q->msix_index >= ioc->iopoll_q_start_index) 322762306a36Sopenharmony_ci continue; 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_ci mask = pci_irq_get_affinity(ioc->pdev, 323062306a36Sopenharmony_ci reply_q->msix_index); 323162306a36Sopenharmony_ci if (!mask) { 323262306a36Sopenharmony_ci ioc_warn(ioc, "no affinity for msi %x\n", 323362306a36Sopenharmony_ci reply_q->msix_index); 323462306a36Sopenharmony_ci goto fall_back; 323562306a36Sopenharmony_ci } 323662306a36Sopenharmony_ci 323762306a36Sopenharmony_ci for_each_cpu_and(cpu, mask, cpu_online_mask) { 323862306a36Sopenharmony_ci if (cpu >= ioc->cpu_msix_table_sz) 323962306a36Sopenharmony_ci break; 324062306a36Sopenharmony_ci ioc->cpu_msix_table[cpu] = reply_q->msix_index; 324162306a36Sopenharmony_ci } 324262306a36Sopenharmony_ci } 324362306a36Sopenharmony_ci return; 324462306a36Sopenharmony_ci } 324562306a36Sopenharmony_ci 324662306a36Sopenharmony_cifall_back: 324762306a36Sopenharmony_ci cpu = cpumask_first(cpu_online_mask); 324862306a36Sopenharmony_ci nr_msix -= (ioc->high_iops_queues - iopoll_q_count); 324962306a36Sopenharmony_ci index = 0; 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { 325262306a36Sopenharmony_ci unsigned int i, group = nr_cpus / nr_msix; 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci if (reply_q->msix_index < ioc->high_iops_queues || 325562306a36Sopenharmony_ci reply_q->msix_index >= ioc->iopoll_q_start_index) 325662306a36Sopenharmony_ci continue; 325762306a36Sopenharmony_ci 325862306a36Sopenharmony_ci if (cpu >= nr_cpus) 325962306a36Sopenharmony_ci break; 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci if (index < nr_cpus % nr_msix) 326262306a36Sopenharmony_ci group++; 326362306a36Sopenharmony_ci 326462306a36Sopenharmony_ci for (i = 0 ; i < group ; i++) { 326562306a36Sopenharmony_ci ioc->cpu_msix_table[cpu] = reply_q->msix_index; 326662306a36Sopenharmony_ci cpu = cpumask_next(cpu, cpu_online_mask); 326762306a36Sopenharmony_ci } 326862306a36Sopenharmony_ci index++; 326962306a36Sopenharmony_ci } 327062306a36Sopenharmony_ci} 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_ci/** 327362306a36Sopenharmony_ci * _base_check_and_enable_high_iops_queues - enable high iops mode 327462306a36Sopenharmony_ci * @ioc: per adapter object 327562306a36Sopenharmony_ci * @hba_msix_vector_count: msix vectors supported by HBA 327662306a36Sopenharmony_ci * 327762306a36Sopenharmony_ci * Enable high iops queues only if 327862306a36Sopenharmony_ci * - HBA is a SEA/AERO controller and 327962306a36Sopenharmony_ci * - MSI-Xs vector supported by the HBA is 128 and 328062306a36Sopenharmony_ci * - total CPU count in the system >=16 and 328162306a36Sopenharmony_ci * - loaded driver with default max_msix_vectors module parameter and 328262306a36Sopenharmony_ci * - system booted in non kdump mode 328362306a36Sopenharmony_ci * 328462306a36Sopenharmony_ci * Return: nothing. 328562306a36Sopenharmony_ci */ 328662306a36Sopenharmony_cistatic void 328762306a36Sopenharmony_ci_base_check_and_enable_high_iops_queues(struct MPT3SAS_ADAPTER *ioc, 328862306a36Sopenharmony_ci int hba_msix_vector_count) 328962306a36Sopenharmony_ci{ 329062306a36Sopenharmony_ci u16 lnksta, speed; 329162306a36Sopenharmony_ci 329262306a36Sopenharmony_ci /* 329362306a36Sopenharmony_ci * Disable high iops queues if io uring poll queues are enabled. 329462306a36Sopenharmony_ci */ 329562306a36Sopenharmony_ci if (perf_mode == MPT_PERF_MODE_IOPS || 329662306a36Sopenharmony_ci perf_mode == MPT_PERF_MODE_LATENCY || 329762306a36Sopenharmony_ci ioc->io_uring_poll_queues) { 329862306a36Sopenharmony_ci ioc->high_iops_queues = 0; 329962306a36Sopenharmony_ci return; 330062306a36Sopenharmony_ci } 330162306a36Sopenharmony_ci 330262306a36Sopenharmony_ci if (perf_mode == MPT_PERF_MODE_DEFAULT) { 330362306a36Sopenharmony_ci 330462306a36Sopenharmony_ci pcie_capability_read_word(ioc->pdev, PCI_EXP_LNKSTA, &lnksta); 330562306a36Sopenharmony_ci speed = lnksta & PCI_EXP_LNKSTA_CLS; 330662306a36Sopenharmony_ci 330762306a36Sopenharmony_ci if (speed < 0x4) { 330862306a36Sopenharmony_ci ioc->high_iops_queues = 0; 330962306a36Sopenharmony_ci return; 331062306a36Sopenharmony_ci } 331162306a36Sopenharmony_ci } 331262306a36Sopenharmony_ci 331362306a36Sopenharmony_ci if (!reset_devices && ioc->is_aero_ioc && 331462306a36Sopenharmony_ci hba_msix_vector_count == MPT3SAS_GEN35_MAX_MSIX_QUEUES && 331562306a36Sopenharmony_ci num_online_cpus() >= MPT3SAS_HIGH_IOPS_REPLY_QUEUES && 331662306a36Sopenharmony_ci max_msix_vectors == -1) 331762306a36Sopenharmony_ci ioc->high_iops_queues = MPT3SAS_HIGH_IOPS_REPLY_QUEUES; 331862306a36Sopenharmony_ci else 331962306a36Sopenharmony_ci ioc->high_iops_queues = 0; 332062306a36Sopenharmony_ci} 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ci/** 332362306a36Sopenharmony_ci * mpt3sas_base_disable_msix - disables msix 332462306a36Sopenharmony_ci * @ioc: per adapter object 332562306a36Sopenharmony_ci * 332662306a36Sopenharmony_ci */ 332762306a36Sopenharmony_civoid 332862306a36Sopenharmony_cimpt3sas_base_disable_msix(struct MPT3SAS_ADAPTER *ioc) 332962306a36Sopenharmony_ci{ 333062306a36Sopenharmony_ci if (!ioc->msix_enable) 333162306a36Sopenharmony_ci return; 333262306a36Sopenharmony_ci pci_free_irq_vectors(ioc->pdev); 333362306a36Sopenharmony_ci ioc->msix_enable = 0; 333462306a36Sopenharmony_ci kfree(ioc->io_uring_poll_queues); 333562306a36Sopenharmony_ci} 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci/** 333862306a36Sopenharmony_ci * _base_alloc_irq_vectors - allocate msix vectors 333962306a36Sopenharmony_ci * @ioc: per adapter object 334062306a36Sopenharmony_ci * 334162306a36Sopenharmony_ci */ 334262306a36Sopenharmony_cistatic int 334362306a36Sopenharmony_ci_base_alloc_irq_vectors(struct MPT3SAS_ADAPTER *ioc) 334462306a36Sopenharmony_ci{ 334562306a36Sopenharmony_ci int i, irq_flags = PCI_IRQ_MSIX; 334662306a36Sopenharmony_ci struct irq_affinity desc = { .pre_vectors = ioc->high_iops_queues }; 334762306a36Sopenharmony_ci struct irq_affinity *descp = &desc; 334862306a36Sopenharmony_ci /* 334962306a36Sopenharmony_ci * Don't allocate msix vectors for poll_queues. 335062306a36Sopenharmony_ci * msix_vectors is always within a range of FW supported reply queue. 335162306a36Sopenharmony_ci */ 335262306a36Sopenharmony_ci int nr_msix_vectors = ioc->iopoll_q_start_index; 335362306a36Sopenharmony_ci 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_ci if (ioc->smp_affinity_enable) 335662306a36Sopenharmony_ci irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES; 335762306a36Sopenharmony_ci else 335862306a36Sopenharmony_ci descp = NULL; 335962306a36Sopenharmony_ci 336062306a36Sopenharmony_ci ioc_info(ioc, " %d %d %d\n", ioc->high_iops_queues, 336162306a36Sopenharmony_ci ioc->reply_queue_count, nr_msix_vectors); 336262306a36Sopenharmony_ci 336362306a36Sopenharmony_ci i = pci_alloc_irq_vectors_affinity(ioc->pdev, 336462306a36Sopenharmony_ci ioc->high_iops_queues, 336562306a36Sopenharmony_ci nr_msix_vectors, irq_flags, descp); 336662306a36Sopenharmony_ci 336762306a36Sopenharmony_ci return i; 336862306a36Sopenharmony_ci} 336962306a36Sopenharmony_ci 337062306a36Sopenharmony_ci/** 337162306a36Sopenharmony_ci * _base_enable_msix - enables msix, failback to io_apic 337262306a36Sopenharmony_ci * @ioc: per adapter object 337362306a36Sopenharmony_ci * 337462306a36Sopenharmony_ci */ 337562306a36Sopenharmony_cistatic int 337662306a36Sopenharmony_ci_base_enable_msix(struct MPT3SAS_ADAPTER *ioc) 337762306a36Sopenharmony_ci{ 337862306a36Sopenharmony_ci int r; 337962306a36Sopenharmony_ci int i, local_max_msix_vectors; 338062306a36Sopenharmony_ci u8 try_msix = 0; 338162306a36Sopenharmony_ci int iopoll_q_count = 0; 338262306a36Sopenharmony_ci 338362306a36Sopenharmony_ci ioc->msix_load_balance = false; 338462306a36Sopenharmony_ci 338562306a36Sopenharmony_ci if (msix_disable == -1 || msix_disable == 0) 338662306a36Sopenharmony_ci try_msix = 1; 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ci if (!try_msix) 338962306a36Sopenharmony_ci goto try_ioapic; 339062306a36Sopenharmony_ci 339162306a36Sopenharmony_ci if (_base_check_enable_msix(ioc) != 0) 339262306a36Sopenharmony_ci goto try_ioapic; 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci ioc_info(ioc, "MSI-X vectors supported: %d\n", ioc->msix_vector_count); 339562306a36Sopenharmony_ci pr_info("\t no of cores: %d, max_msix_vectors: %d\n", 339662306a36Sopenharmony_ci ioc->cpu_count, max_msix_vectors); 339762306a36Sopenharmony_ci 339862306a36Sopenharmony_ci ioc->reply_queue_count = 339962306a36Sopenharmony_ci min_t(int, ioc->cpu_count, ioc->msix_vector_count); 340062306a36Sopenharmony_ci 340162306a36Sopenharmony_ci if (!ioc->rdpq_array_enable && max_msix_vectors == -1) 340262306a36Sopenharmony_ci local_max_msix_vectors = (reset_devices) ? 1 : 8; 340362306a36Sopenharmony_ci else 340462306a36Sopenharmony_ci local_max_msix_vectors = max_msix_vectors; 340562306a36Sopenharmony_ci 340662306a36Sopenharmony_ci if (local_max_msix_vectors == 0) 340762306a36Sopenharmony_ci goto try_ioapic; 340862306a36Sopenharmony_ci 340962306a36Sopenharmony_ci /* 341062306a36Sopenharmony_ci * Enable msix_load_balance only if combined reply queue mode is 341162306a36Sopenharmony_ci * disabled on SAS3 & above generation HBA devices. 341262306a36Sopenharmony_ci */ 341362306a36Sopenharmony_ci if (!ioc->combined_reply_queue && 341462306a36Sopenharmony_ci ioc->hba_mpi_version_belonged != MPI2_VERSION) { 341562306a36Sopenharmony_ci ioc_info(ioc, 341662306a36Sopenharmony_ci "combined ReplyQueue is off, Enabling msix load balance\n"); 341762306a36Sopenharmony_ci ioc->msix_load_balance = true; 341862306a36Sopenharmony_ci } 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci /* 342162306a36Sopenharmony_ci * smp affinity setting is not need when msix load balance 342262306a36Sopenharmony_ci * is enabled. 342362306a36Sopenharmony_ci */ 342462306a36Sopenharmony_ci if (ioc->msix_load_balance) 342562306a36Sopenharmony_ci ioc->smp_affinity_enable = 0; 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci if (!ioc->smp_affinity_enable || ioc->reply_queue_count <= 1) 342862306a36Sopenharmony_ci ioc->shost->host_tagset = 0; 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_ci /* 343162306a36Sopenharmony_ci * Enable io uring poll queues only if host_tagset is enabled. 343262306a36Sopenharmony_ci */ 343362306a36Sopenharmony_ci if (ioc->shost->host_tagset) 343462306a36Sopenharmony_ci iopoll_q_count = poll_queues; 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci if (iopoll_q_count) { 343762306a36Sopenharmony_ci ioc->io_uring_poll_queues = kcalloc(iopoll_q_count, 343862306a36Sopenharmony_ci sizeof(struct io_uring_poll_queue), GFP_KERNEL); 343962306a36Sopenharmony_ci if (!ioc->io_uring_poll_queues) 344062306a36Sopenharmony_ci iopoll_q_count = 0; 344162306a36Sopenharmony_ci } 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_ci if (ioc->is_aero_ioc) 344462306a36Sopenharmony_ci _base_check_and_enable_high_iops_queues(ioc, 344562306a36Sopenharmony_ci ioc->msix_vector_count); 344662306a36Sopenharmony_ci 344762306a36Sopenharmony_ci /* 344862306a36Sopenharmony_ci * Add high iops queues count to reply queue count if high iops queues 344962306a36Sopenharmony_ci * are enabled. 345062306a36Sopenharmony_ci */ 345162306a36Sopenharmony_ci ioc->reply_queue_count = min_t(int, 345262306a36Sopenharmony_ci ioc->reply_queue_count + ioc->high_iops_queues, 345362306a36Sopenharmony_ci ioc->msix_vector_count); 345462306a36Sopenharmony_ci 345562306a36Sopenharmony_ci /* 345662306a36Sopenharmony_ci * Adjust the reply queue count incase reply queue count 345762306a36Sopenharmony_ci * exceeds the user provided MSIx vectors count. 345862306a36Sopenharmony_ci */ 345962306a36Sopenharmony_ci if (local_max_msix_vectors > 0) 346062306a36Sopenharmony_ci ioc->reply_queue_count = min_t(int, local_max_msix_vectors, 346162306a36Sopenharmony_ci ioc->reply_queue_count); 346262306a36Sopenharmony_ci /* 346362306a36Sopenharmony_ci * Add io uring poll queues count to reply queues count 346462306a36Sopenharmony_ci * if io uring is enabled in driver. 346562306a36Sopenharmony_ci */ 346662306a36Sopenharmony_ci if (iopoll_q_count) { 346762306a36Sopenharmony_ci if (ioc->reply_queue_count < (iopoll_q_count + MPT3_MIN_IRQS)) 346862306a36Sopenharmony_ci iopoll_q_count = 0; 346962306a36Sopenharmony_ci ioc->reply_queue_count = min_t(int, 347062306a36Sopenharmony_ci ioc->reply_queue_count + iopoll_q_count, 347162306a36Sopenharmony_ci ioc->msix_vector_count); 347262306a36Sopenharmony_ci } 347362306a36Sopenharmony_ci 347462306a36Sopenharmony_ci /* 347562306a36Sopenharmony_ci * Starting index of io uring poll queues in reply queue list. 347662306a36Sopenharmony_ci */ 347762306a36Sopenharmony_ci ioc->iopoll_q_start_index = 347862306a36Sopenharmony_ci ioc->reply_queue_count - iopoll_q_count; 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci r = _base_alloc_irq_vectors(ioc); 348162306a36Sopenharmony_ci if (r < 0) { 348262306a36Sopenharmony_ci ioc_info(ioc, "pci_alloc_irq_vectors failed (r=%d) !!!\n", r); 348362306a36Sopenharmony_ci goto try_ioapic; 348462306a36Sopenharmony_ci } 348562306a36Sopenharmony_ci 348662306a36Sopenharmony_ci /* 348762306a36Sopenharmony_ci * Adjust the reply queue count if the allocated 348862306a36Sopenharmony_ci * MSIx vectors is less then the requested number 348962306a36Sopenharmony_ci * of MSIx vectors. 349062306a36Sopenharmony_ci */ 349162306a36Sopenharmony_ci if (r < ioc->iopoll_q_start_index) { 349262306a36Sopenharmony_ci ioc->reply_queue_count = r + iopoll_q_count; 349362306a36Sopenharmony_ci ioc->iopoll_q_start_index = 349462306a36Sopenharmony_ci ioc->reply_queue_count - iopoll_q_count; 349562306a36Sopenharmony_ci } 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_ci ioc->msix_enable = 1; 349862306a36Sopenharmony_ci for (i = 0; i < ioc->reply_queue_count; i++) { 349962306a36Sopenharmony_ci r = _base_request_irq(ioc, i); 350062306a36Sopenharmony_ci if (r) { 350162306a36Sopenharmony_ci mpt3sas_base_free_irq(ioc); 350262306a36Sopenharmony_ci mpt3sas_base_disable_msix(ioc); 350362306a36Sopenharmony_ci goto try_ioapic; 350462306a36Sopenharmony_ci } 350562306a36Sopenharmony_ci } 350662306a36Sopenharmony_ci 350762306a36Sopenharmony_ci ioc_info(ioc, "High IOPs queues : %s\n", 350862306a36Sopenharmony_ci ioc->high_iops_queues ? "enabled" : "disabled"); 350962306a36Sopenharmony_ci 351062306a36Sopenharmony_ci return 0; 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_ci/* failback to io_apic interrupt routing */ 351362306a36Sopenharmony_ci try_ioapic: 351462306a36Sopenharmony_ci ioc->high_iops_queues = 0; 351562306a36Sopenharmony_ci ioc_info(ioc, "High IOPs queues : disabled\n"); 351662306a36Sopenharmony_ci ioc->reply_queue_count = 1; 351762306a36Sopenharmony_ci ioc->iopoll_q_start_index = ioc->reply_queue_count - 0; 351862306a36Sopenharmony_ci r = pci_alloc_irq_vectors(ioc->pdev, 1, 1, PCI_IRQ_LEGACY); 351962306a36Sopenharmony_ci if (r < 0) { 352062306a36Sopenharmony_ci dfailprintk(ioc, 352162306a36Sopenharmony_ci ioc_info(ioc, "pci_alloc_irq_vector(legacy) failed (r=%d) !!!\n", 352262306a36Sopenharmony_ci r)); 352362306a36Sopenharmony_ci } else 352462306a36Sopenharmony_ci r = _base_request_irq(ioc, 0); 352562306a36Sopenharmony_ci 352662306a36Sopenharmony_ci return r; 352762306a36Sopenharmony_ci} 352862306a36Sopenharmony_ci 352962306a36Sopenharmony_ci/** 353062306a36Sopenharmony_ci * mpt3sas_base_unmap_resources - free controller resources 353162306a36Sopenharmony_ci * @ioc: per adapter object 353262306a36Sopenharmony_ci */ 353362306a36Sopenharmony_cistatic void 353462306a36Sopenharmony_cimpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc) 353562306a36Sopenharmony_ci{ 353662306a36Sopenharmony_ci struct pci_dev *pdev = ioc->pdev; 353762306a36Sopenharmony_ci 353862306a36Sopenharmony_ci dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci mpt3sas_base_free_irq(ioc); 354162306a36Sopenharmony_ci mpt3sas_base_disable_msix(ioc); 354262306a36Sopenharmony_ci 354362306a36Sopenharmony_ci kfree(ioc->replyPostRegisterIndex); 354462306a36Sopenharmony_ci ioc->replyPostRegisterIndex = NULL; 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci 354762306a36Sopenharmony_ci if (ioc->chip_phys) { 354862306a36Sopenharmony_ci iounmap(ioc->chip); 354962306a36Sopenharmony_ci ioc->chip_phys = 0; 355062306a36Sopenharmony_ci } 355162306a36Sopenharmony_ci 355262306a36Sopenharmony_ci if (pci_is_enabled(pdev)) { 355362306a36Sopenharmony_ci pci_release_selected_regions(ioc->pdev, ioc->bars); 355462306a36Sopenharmony_ci pci_disable_device(pdev); 355562306a36Sopenharmony_ci } 355662306a36Sopenharmony_ci} 355762306a36Sopenharmony_ci 355862306a36Sopenharmony_cistatic int 355962306a36Sopenharmony_ci_base_diag_reset(struct MPT3SAS_ADAPTER *ioc); 356062306a36Sopenharmony_ci 356162306a36Sopenharmony_ci/** 356262306a36Sopenharmony_ci * mpt3sas_base_check_for_fault_and_issue_reset - check if IOC is in fault state 356362306a36Sopenharmony_ci * and if it is in fault state then issue diag reset. 356462306a36Sopenharmony_ci * @ioc: per adapter object 356562306a36Sopenharmony_ci * 356662306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 356762306a36Sopenharmony_ci */ 356862306a36Sopenharmony_ciint 356962306a36Sopenharmony_cimpt3sas_base_check_for_fault_and_issue_reset(struct MPT3SAS_ADAPTER *ioc) 357062306a36Sopenharmony_ci{ 357162306a36Sopenharmony_ci u32 ioc_state; 357262306a36Sopenharmony_ci int rc = -EFAULT; 357362306a36Sopenharmony_ci 357462306a36Sopenharmony_ci dinitprintk(ioc, pr_info("%s\n", __func__)); 357562306a36Sopenharmony_ci if (ioc->pci_error_recovery) 357662306a36Sopenharmony_ci return 0; 357762306a36Sopenharmony_ci ioc_state = mpt3sas_base_get_iocstate(ioc, 0); 357862306a36Sopenharmony_ci dhsprintk(ioc, pr_info("%s: ioc_state(0x%08x)\n", __func__, ioc_state)); 357962306a36Sopenharmony_ci 358062306a36Sopenharmony_ci if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { 358162306a36Sopenharmony_ci mpt3sas_print_fault_code(ioc, ioc_state & 358262306a36Sopenharmony_ci MPI2_DOORBELL_DATA_MASK); 358362306a36Sopenharmony_ci mpt3sas_base_mask_interrupts(ioc); 358462306a36Sopenharmony_ci rc = _base_diag_reset(ioc); 358562306a36Sopenharmony_ci } else if ((ioc_state & MPI2_IOC_STATE_MASK) == 358662306a36Sopenharmony_ci MPI2_IOC_STATE_COREDUMP) { 358762306a36Sopenharmony_ci mpt3sas_print_coredump_info(ioc, ioc_state & 358862306a36Sopenharmony_ci MPI2_DOORBELL_DATA_MASK); 358962306a36Sopenharmony_ci mpt3sas_base_wait_for_coredump_completion(ioc, __func__); 359062306a36Sopenharmony_ci mpt3sas_base_mask_interrupts(ioc); 359162306a36Sopenharmony_ci rc = _base_diag_reset(ioc); 359262306a36Sopenharmony_ci } 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_ci return rc; 359562306a36Sopenharmony_ci} 359662306a36Sopenharmony_ci 359762306a36Sopenharmony_ci/** 359862306a36Sopenharmony_ci * mpt3sas_base_map_resources - map in controller resources (io/irq/memap) 359962306a36Sopenharmony_ci * @ioc: per adapter object 360062306a36Sopenharmony_ci * 360162306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 360262306a36Sopenharmony_ci */ 360362306a36Sopenharmony_ciint 360462306a36Sopenharmony_cimpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) 360562306a36Sopenharmony_ci{ 360662306a36Sopenharmony_ci struct pci_dev *pdev = ioc->pdev; 360762306a36Sopenharmony_ci u32 memap_sz; 360862306a36Sopenharmony_ci u32 pio_sz; 360962306a36Sopenharmony_ci int i, r = 0, rc; 361062306a36Sopenharmony_ci u64 pio_chip = 0; 361162306a36Sopenharmony_ci phys_addr_t chip_phys = 0; 361262306a36Sopenharmony_ci struct adapter_reply_queue *reply_q; 361362306a36Sopenharmony_ci int iopoll_q_count = 0; 361462306a36Sopenharmony_ci 361562306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 361662306a36Sopenharmony_ci 361762306a36Sopenharmony_ci ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); 361862306a36Sopenharmony_ci if (pci_enable_device_mem(pdev)) { 361962306a36Sopenharmony_ci ioc_warn(ioc, "pci_enable_device_mem: failed\n"); 362062306a36Sopenharmony_ci ioc->bars = 0; 362162306a36Sopenharmony_ci return -ENODEV; 362262306a36Sopenharmony_ci } 362362306a36Sopenharmony_ci 362462306a36Sopenharmony_ci 362562306a36Sopenharmony_ci if (pci_request_selected_regions(pdev, ioc->bars, 362662306a36Sopenharmony_ci ioc->driver_name)) { 362762306a36Sopenharmony_ci ioc_warn(ioc, "pci_request_selected_regions: failed\n"); 362862306a36Sopenharmony_ci ioc->bars = 0; 362962306a36Sopenharmony_ci r = -ENODEV; 363062306a36Sopenharmony_ci goto out_fail; 363162306a36Sopenharmony_ci } 363262306a36Sopenharmony_ci 363362306a36Sopenharmony_ci pci_set_master(pdev); 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_ci 363662306a36Sopenharmony_ci if (_base_config_dma_addressing(ioc, pdev) != 0) { 363762306a36Sopenharmony_ci ioc_warn(ioc, "no suitable DMA mask for %s\n", pci_name(pdev)); 363862306a36Sopenharmony_ci r = -ENODEV; 363962306a36Sopenharmony_ci goto out_fail; 364062306a36Sopenharmony_ci } 364162306a36Sopenharmony_ci 364262306a36Sopenharmony_ci for (i = 0, memap_sz = 0, pio_sz = 0; (i < DEVICE_COUNT_RESOURCE) && 364362306a36Sopenharmony_ci (!memap_sz || !pio_sz); i++) { 364462306a36Sopenharmony_ci if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { 364562306a36Sopenharmony_ci if (pio_sz) 364662306a36Sopenharmony_ci continue; 364762306a36Sopenharmony_ci pio_chip = (u64)pci_resource_start(pdev, i); 364862306a36Sopenharmony_ci pio_sz = pci_resource_len(pdev, i); 364962306a36Sopenharmony_ci } else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { 365062306a36Sopenharmony_ci if (memap_sz) 365162306a36Sopenharmony_ci continue; 365262306a36Sopenharmony_ci ioc->chip_phys = pci_resource_start(pdev, i); 365362306a36Sopenharmony_ci chip_phys = ioc->chip_phys; 365462306a36Sopenharmony_ci memap_sz = pci_resource_len(pdev, i); 365562306a36Sopenharmony_ci ioc->chip = ioremap(ioc->chip_phys, memap_sz); 365662306a36Sopenharmony_ci } 365762306a36Sopenharmony_ci } 365862306a36Sopenharmony_ci 365962306a36Sopenharmony_ci if (ioc->chip == NULL) { 366062306a36Sopenharmony_ci ioc_err(ioc, 366162306a36Sopenharmony_ci "unable to map adapter memory! or resource not found\n"); 366262306a36Sopenharmony_ci r = -EINVAL; 366362306a36Sopenharmony_ci goto out_fail; 366462306a36Sopenharmony_ci } 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ci mpt3sas_base_mask_interrupts(ioc); 366762306a36Sopenharmony_ci 366862306a36Sopenharmony_ci r = _base_get_ioc_facts(ioc); 366962306a36Sopenharmony_ci if (r) { 367062306a36Sopenharmony_ci rc = mpt3sas_base_check_for_fault_and_issue_reset(ioc); 367162306a36Sopenharmony_ci if (rc || (_base_get_ioc_facts(ioc))) 367262306a36Sopenharmony_ci goto out_fail; 367362306a36Sopenharmony_ci } 367462306a36Sopenharmony_ci 367562306a36Sopenharmony_ci if (!ioc->rdpq_array_enable_assigned) { 367662306a36Sopenharmony_ci ioc->rdpq_array_enable = ioc->rdpq_array_capable; 367762306a36Sopenharmony_ci ioc->rdpq_array_enable_assigned = 1; 367862306a36Sopenharmony_ci } 367962306a36Sopenharmony_ci 368062306a36Sopenharmony_ci r = _base_enable_msix(ioc); 368162306a36Sopenharmony_ci if (r) 368262306a36Sopenharmony_ci goto out_fail; 368362306a36Sopenharmony_ci 368462306a36Sopenharmony_ci iopoll_q_count = ioc->reply_queue_count - ioc->iopoll_q_start_index; 368562306a36Sopenharmony_ci for (i = 0; i < iopoll_q_count; i++) { 368662306a36Sopenharmony_ci atomic_set(&ioc->io_uring_poll_queues[i].busy, 0); 368762306a36Sopenharmony_ci atomic_set(&ioc->io_uring_poll_queues[i].pause, 0); 368862306a36Sopenharmony_ci } 368962306a36Sopenharmony_ci 369062306a36Sopenharmony_ci if (!ioc->is_driver_loading) 369162306a36Sopenharmony_ci _base_init_irqpolls(ioc); 369262306a36Sopenharmony_ci /* Use the Combined reply queue feature only for SAS3 C0 & higher 369362306a36Sopenharmony_ci * revision HBAs and also only when reply queue count is greater than 8 369462306a36Sopenharmony_ci */ 369562306a36Sopenharmony_ci if (ioc->combined_reply_queue) { 369662306a36Sopenharmony_ci /* Determine the Supplemental Reply Post Host Index Registers 369762306a36Sopenharmony_ci * Addresse. Supplemental Reply Post Host Index Registers 369862306a36Sopenharmony_ci * starts at offset MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET and 369962306a36Sopenharmony_ci * each register is at offset bytes of 370062306a36Sopenharmony_ci * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET from previous one. 370162306a36Sopenharmony_ci */ 370262306a36Sopenharmony_ci ioc->replyPostRegisterIndex = kcalloc( 370362306a36Sopenharmony_ci ioc->combined_reply_index_count, 370462306a36Sopenharmony_ci sizeof(resource_size_t *), GFP_KERNEL); 370562306a36Sopenharmony_ci if (!ioc->replyPostRegisterIndex) { 370662306a36Sopenharmony_ci ioc_err(ioc, 370762306a36Sopenharmony_ci "allocation for replyPostRegisterIndex failed!\n"); 370862306a36Sopenharmony_ci r = -ENOMEM; 370962306a36Sopenharmony_ci goto out_fail; 371062306a36Sopenharmony_ci } 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_ci for (i = 0; i < ioc->combined_reply_index_count; i++) { 371362306a36Sopenharmony_ci ioc->replyPostRegisterIndex[i] = 371462306a36Sopenharmony_ci (resource_size_t __iomem *) 371562306a36Sopenharmony_ci ((u8 __force *)&ioc->chip->Doorbell + 371662306a36Sopenharmony_ci MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET + 371762306a36Sopenharmony_ci (i * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET)); 371862306a36Sopenharmony_ci } 371962306a36Sopenharmony_ci } 372062306a36Sopenharmony_ci 372162306a36Sopenharmony_ci if (ioc->is_warpdrive) { 372262306a36Sopenharmony_ci ioc->reply_post_host_index[0] = (resource_size_t __iomem *) 372362306a36Sopenharmony_ci &ioc->chip->ReplyPostHostIndex; 372462306a36Sopenharmony_ci 372562306a36Sopenharmony_ci for (i = 1; i < ioc->cpu_msix_table_sz; i++) 372662306a36Sopenharmony_ci ioc->reply_post_host_index[i] = 372762306a36Sopenharmony_ci (resource_size_t __iomem *) 372862306a36Sopenharmony_ci ((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1) 372962306a36Sopenharmony_ci * 4))); 373062306a36Sopenharmony_ci } 373162306a36Sopenharmony_ci 373262306a36Sopenharmony_ci list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { 373362306a36Sopenharmony_ci if (reply_q->msix_index >= ioc->iopoll_q_start_index) { 373462306a36Sopenharmony_ci pr_info("%s: enabled: index: %d\n", 373562306a36Sopenharmony_ci reply_q->name, reply_q->msix_index); 373662306a36Sopenharmony_ci continue; 373762306a36Sopenharmony_ci } 373862306a36Sopenharmony_ci 373962306a36Sopenharmony_ci pr_info("%s: %s enabled: IRQ %d\n", 374062306a36Sopenharmony_ci reply_q->name, 374162306a36Sopenharmony_ci ioc->msix_enable ? "PCI-MSI-X" : "IO-APIC", 374262306a36Sopenharmony_ci pci_irq_vector(ioc->pdev, reply_q->msix_index)); 374362306a36Sopenharmony_ci } 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci ioc_info(ioc, "iomem(%pap), mapped(0x%p), size(%d)\n", 374662306a36Sopenharmony_ci &chip_phys, ioc->chip, memap_sz); 374762306a36Sopenharmony_ci ioc_info(ioc, "ioport(0x%016llx), size(%d)\n", 374862306a36Sopenharmony_ci (unsigned long long)pio_chip, pio_sz); 374962306a36Sopenharmony_ci 375062306a36Sopenharmony_ci /* Save PCI configuration state for recovery from PCI AER/EEH errors */ 375162306a36Sopenharmony_ci pci_save_state(pdev); 375262306a36Sopenharmony_ci return 0; 375362306a36Sopenharmony_ci 375462306a36Sopenharmony_ci out_fail: 375562306a36Sopenharmony_ci mpt3sas_base_unmap_resources(ioc); 375662306a36Sopenharmony_ci return r; 375762306a36Sopenharmony_ci} 375862306a36Sopenharmony_ci 375962306a36Sopenharmony_ci/** 376062306a36Sopenharmony_ci * mpt3sas_base_get_msg_frame - obtain request mf pointer 376162306a36Sopenharmony_ci * @ioc: per adapter object 376262306a36Sopenharmony_ci * @smid: system request message index(smid zero is invalid) 376362306a36Sopenharmony_ci * 376462306a36Sopenharmony_ci * Return: virt pointer to message frame. 376562306a36Sopenharmony_ci */ 376662306a36Sopenharmony_civoid * 376762306a36Sopenharmony_cimpt3sas_base_get_msg_frame(struct MPT3SAS_ADAPTER *ioc, u16 smid) 376862306a36Sopenharmony_ci{ 376962306a36Sopenharmony_ci return (void *)(ioc->request + (smid * ioc->request_sz)); 377062306a36Sopenharmony_ci} 377162306a36Sopenharmony_ci 377262306a36Sopenharmony_ci/** 377362306a36Sopenharmony_ci * mpt3sas_base_get_sense_buffer - obtain a sense buffer virt addr 377462306a36Sopenharmony_ci * @ioc: per adapter object 377562306a36Sopenharmony_ci * @smid: system request message index 377662306a36Sopenharmony_ci * 377762306a36Sopenharmony_ci * Return: virt pointer to sense buffer. 377862306a36Sopenharmony_ci */ 377962306a36Sopenharmony_civoid * 378062306a36Sopenharmony_cimpt3sas_base_get_sense_buffer(struct MPT3SAS_ADAPTER *ioc, u16 smid) 378162306a36Sopenharmony_ci{ 378262306a36Sopenharmony_ci return (void *)(ioc->sense + ((smid - 1) * SCSI_SENSE_BUFFERSIZE)); 378362306a36Sopenharmony_ci} 378462306a36Sopenharmony_ci 378562306a36Sopenharmony_ci/** 378662306a36Sopenharmony_ci * mpt3sas_base_get_sense_buffer_dma - obtain a sense buffer dma addr 378762306a36Sopenharmony_ci * @ioc: per adapter object 378862306a36Sopenharmony_ci * @smid: system request message index 378962306a36Sopenharmony_ci * 379062306a36Sopenharmony_ci * Return: phys pointer to the low 32bit address of the sense buffer. 379162306a36Sopenharmony_ci */ 379262306a36Sopenharmony_ci__le32 379362306a36Sopenharmony_cimpt3sas_base_get_sense_buffer_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid) 379462306a36Sopenharmony_ci{ 379562306a36Sopenharmony_ci return cpu_to_le32(ioc->sense_dma + ((smid - 1) * 379662306a36Sopenharmony_ci SCSI_SENSE_BUFFERSIZE)); 379762306a36Sopenharmony_ci} 379862306a36Sopenharmony_ci 379962306a36Sopenharmony_ci/** 380062306a36Sopenharmony_ci * mpt3sas_base_get_pcie_sgl - obtain a PCIe SGL virt addr 380162306a36Sopenharmony_ci * @ioc: per adapter object 380262306a36Sopenharmony_ci * @smid: system request message index 380362306a36Sopenharmony_ci * 380462306a36Sopenharmony_ci * Return: virt pointer to a PCIe SGL. 380562306a36Sopenharmony_ci */ 380662306a36Sopenharmony_civoid * 380762306a36Sopenharmony_cimpt3sas_base_get_pcie_sgl(struct MPT3SAS_ADAPTER *ioc, u16 smid) 380862306a36Sopenharmony_ci{ 380962306a36Sopenharmony_ci return (void *)(ioc->pcie_sg_lookup[smid - 1].pcie_sgl); 381062306a36Sopenharmony_ci} 381162306a36Sopenharmony_ci 381262306a36Sopenharmony_ci/** 381362306a36Sopenharmony_ci * mpt3sas_base_get_pcie_sgl_dma - obtain a PCIe SGL dma addr 381462306a36Sopenharmony_ci * @ioc: per adapter object 381562306a36Sopenharmony_ci * @smid: system request message index 381662306a36Sopenharmony_ci * 381762306a36Sopenharmony_ci * Return: phys pointer to the address of the PCIe buffer. 381862306a36Sopenharmony_ci */ 381962306a36Sopenharmony_cidma_addr_t 382062306a36Sopenharmony_cimpt3sas_base_get_pcie_sgl_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid) 382162306a36Sopenharmony_ci{ 382262306a36Sopenharmony_ci return ioc->pcie_sg_lookup[smid - 1].pcie_sgl_dma; 382362306a36Sopenharmony_ci} 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_ci/** 382662306a36Sopenharmony_ci * mpt3sas_base_get_reply_virt_addr - obtain reply frames virt address 382762306a36Sopenharmony_ci * @ioc: per adapter object 382862306a36Sopenharmony_ci * @phys_addr: lower 32 physical addr of the reply 382962306a36Sopenharmony_ci * 383062306a36Sopenharmony_ci * Converts 32bit lower physical addr into a virt address. 383162306a36Sopenharmony_ci */ 383262306a36Sopenharmony_civoid * 383362306a36Sopenharmony_cimpt3sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, u32 phys_addr) 383462306a36Sopenharmony_ci{ 383562306a36Sopenharmony_ci if (!phys_addr) 383662306a36Sopenharmony_ci return NULL; 383762306a36Sopenharmony_ci return ioc->reply + (phys_addr - (u32)ioc->reply_dma); 383862306a36Sopenharmony_ci} 383962306a36Sopenharmony_ci 384062306a36Sopenharmony_ci/** 384162306a36Sopenharmony_ci * _base_get_msix_index - get the msix index 384262306a36Sopenharmony_ci * @ioc: per adapter object 384362306a36Sopenharmony_ci * @scmd: scsi_cmnd object 384462306a36Sopenharmony_ci * 384562306a36Sopenharmony_ci * Return: msix index of general reply queues, 384662306a36Sopenharmony_ci * i.e. reply queue on which IO request's reply 384762306a36Sopenharmony_ci * should be posted by the HBA firmware. 384862306a36Sopenharmony_ci */ 384962306a36Sopenharmony_cistatic inline u8 385062306a36Sopenharmony_ci_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc, 385162306a36Sopenharmony_ci struct scsi_cmnd *scmd) 385262306a36Sopenharmony_ci{ 385362306a36Sopenharmony_ci /* Enables reply_queue load balancing */ 385462306a36Sopenharmony_ci if (ioc->msix_load_balance) 385562306a36Sopenharmony_ci return ioc->reply_queue_count ? 385662306a36Sopenharmony_ci base_mod64(atomic64_add_return(1, 385762306a36Sopenharmony_ci &ioc->total_io_cnt), ioc->reply_queue_count) : 0; 385862306a36Sopenharmony_ci 385962306a36Sopenharmony_ci if (scmd && ioc->shost->nr_hw_queues > 1) { 386062306a36Sopenharmony_ci u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); 386162306a36Sopenharmony_ci 386262306a36Sopenharmony_ci return blk_mq_unique_tag_to_hwq(tag) + 386362306a36Sopenharmony_ci ioc->high_iops_queues; 386462306a36Sopenharmony_ci } 386562306a36Sopenharmony_ci 386662306a36Sopenharmony_ci return ioc->cpu_msix_table[raw_smp_processor_id()]; 386762306a36Sopenharmony_ci} 386862306a36Sopenharmony_ci 386962306a36Sopenharmony_ci/** 387062306a36Sopenharmony_ci * _base_get_high_iops_msix_index - get the msix index of 387162306a36Sopenharmony_ci * high iops queues 387262306a36Sopenharmony_ci * @ioc: per adapter object 387362306a36Sopenharmony_ci * @scmd: scsi_cmnd object 387462306a36Sopenharmony_ci * 387562306a36Sopenharmony_ci * Return: msix index of high iops reply queues. 387662306a36Sopenharmony_ci * i.e. high iops reply queue on which IO request's 387762306a36Sopenharmony_ci * reply should be posted by the HBA firmware. 387862306a36Sopenharmony_ci */ 387962306a36Sopenharmony_cistatic inline u8 388062306a36Sopenharmony_ci_base_get_high_iops_msix_index(struct MPT3SAS_ADAPTER *ioc, 388162306a36Sopenharmony_ci struct scsi_cmnd *scmd) 388262306a36Sopenharmony_ci{ 388362306a36Sopenharmony_ci /** 388462306a36Sopenharmony_ci * Round robin the IO interrupts among the high iops 388562306a36Sopenharmony_ci * reply queues in terms of batch count 16 when outstanding 388662306a36Sopenharmony_ci * IOs on the target device is >=8. 388762306a36Sopenharmony_ci */ 388862306a36Sopenharmony_ci 388962306a36Sopenharmony_ci if (scsi_device_busy(scmd->device) > MPT3SAS_DEVICE_HIGH_IOPS_DEPTH) 389062306a36Sopenharmony_ci return base_mod64(( 389162306a36Sopenharmony_ci atomic64_add_return(1, &ioc->high_iops_outstanding) / 389262306a36Sopenharmony_ci MPT3SAS_HIGH_IOPS_BATCH_COUNT), 389362306a36Sopenharmony_ci MPT3SAS_HIGH_IOPS_REPLY_QUEUES); 389462306a36Sopenharmony_ci 389562306a36Sopenharmony_ci return _base_get_msix_index(ioc, scmd); 389662306a36Sopenharmony_ci} 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_ci/** 389962306a36Sopenharmony_ci * mpt3sas_base_get_smid - obtain a free smid from internal queue 390062306a36Sopenharmony_ci * @ioc: per adapter object 390162306a36Sopenharmony_ci * @cb_idx: callback index 390262306a36Sopenharmony_ci * 390362306a36Sopenharmony_ci * Return: smid (zero is invalid) 390462306a36Sopenharmony_ci */ 390562306a36Sopenharmony_ciu16 390662306a36Sopenharmony_cimpt3sas_base_get_smid(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx) 390762306a36Sopenharmony_ci{ 390862306a36Sopenharmony_ci unsigned long flags; 390962306a36Sopenharmony_ci struct request_tracker *request; 391062306a36Sopenharmony_ci u16 smid; 391162306a36Sopenharmony_ci 391262306a36Sopenharmony_ci spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); 391362306a36Sopenharmony_ci if (list_empty(&ioc->internal_free_list)) { 391462306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); 391562306a36Sopenharmony_ci ioc_err(ioc, "%s: smid not available\n", __func__); 391662306a36Sopenharmony_ci return 0; 391762306a36Sopenharmony_ci } 391862306a36Sopenharmony_ci 391962306a36Sopenharmony_ci request = list_entry(ioc->internal_free_list.next, 392062306a36Sopenharmony_ci struct request_tracker, tracker_list); 392162306a36Sopenharmony_ci request->cb_idx = cb_idx; 392262306a36Sopenharmony_ci smid = request->smid; 392362306a36Sopenharmony_ci list_del(&request->tracker_list); 392462306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); 392562306a36Sopenharmony_ci return smid; 392662306a36Sopenharmony_ci} 392762306a36Sopenharmony_ci 392862306a36Sopenharmony_ci/** 392962306a36Sopenharmony_ci * mpt3sas_base_get_smid_scsiio - obtain a free smid from scsiio queue 393062306a36Sopenharmony_ci * @ioc: per adapter object 393162306a36Sopenharmony_ci * @cb_idx: callback index 393262306a36Sopenharmony_ci * @scmd: pointer to scsi command object 393362306a36Sopenharmony_ci * 393462306a36Sopenharmony_ci * Return: smid (zero is invalid) 393562306a36Sopenharmony_ci */ 393662306a36Sopenharmony_ciu16 393762306a36Sopenharmony_cimpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx, 393862306a36Sopenharmony_ci struct scsi_cmnd *scmd) 393962306a36Sopenharmony_ci{ 394062306a36Sopenharmony_ci struct scsiio_tracker *request = scsi_cmd_priv(scmd); 394162306a36Sopenharmony_ci u16 smid; 394262306a36Sopenharmony_ci u32 tag, unique_tag; 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_ci unique_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); 394562306a36Sopenharmony_ci tag = blk_mq_unique_tag_to_tag(unique_tag); 394662306a36Sopenharmony_ci 394762306a36Sopenharmony_ci /* 394862306a36Sopenharmony_ci * Store hw queue number corresponding to the tag. 394962306a36Sopenharmony_ci * This hw queue number is used later to determine 395062306a36Sopenharmony_ci * the unique_tag using the logic below. This unique_tag 395162306a36Sopenharmony_ci * is used to retrieve the scmd pointer corresponding 395262306a36Sopenharmony_ci * to tag using scsi_host_find_tag() API. 395362306a36Sopenharmony_ci * 395462306a36Sopenharmony_ci * tag = smid - 1; 395562306a36Sopenharmony_ci * unique_tag = ioc->io_queue_num[tag] << BLK_MQ_UNIQUE_TAG_BITS | tag; 395662306a36Sopenharmony_ci */ 395762306a36Sopenharmony_ci ioc->io_queue_num[tag] = blk_mq_unique_tag_to_hwq(unique_tag); 395862306a36Sopenharmony_ci 395962306a36Sopenharmony_ci smid = tag + 1; 396062306a36Sopenharmony_ci request->cb_idx = cb_idx; 396162306a36Sopenharmony_ci request->smid = smid; 396262306a36Sopenharmony_ci request->scmd = scmd; 396362306a36Sopenharmony_ci INIT_LIST_HEAD(&request->chain_list); 396462306a36Sopenharmony_ci return smid; 396562306a36Sopenharmony_ci} 396662306a36Sopenharmony_ci 396762306a36Sopenharmony_ci/** 396862306a36Sopenharmony_ci * mpt3sas_base_get_smid_hpr - obtain a free smid from hi-priority queue 396962306a36Sopenharmony_ci * @ioc: per adapter object 397062306a36Sopenharmony_ci * @cb_idx: callback index 397162306a36Sopenharmony_ci * 397262306a36Sopenharmony_ci * Return: smid (zero is invalid) 397362306a36Sopenharmony_ci */ 397462306a36Sopenharmony_ciu16 397562306a36Sopenharmony_cimpt3sas_base_get_smid_hpr(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx) 397662306a36Sopenharmony_ci{ 397762306a36Sopenharmony_ci unsigned long flags; 397862306a36Sopenharmony_ci struct request_tracker *request; 397962306a36Sopenharmony_ci u16 smid; 398062306a36Sopenharmony_ci 398162306a36Sopenharmony_ci spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); 398262306a36Sopenharmony_ci if (list_empty(&ioc->hpr_free_list)) { 398362306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); 398462306a36Sopenharmony_ci return 0; 398562306a36Sopenharmony_ci } 398662306a36Sopenharmony_ci 398762306a36Sopenharmony_ci request = list_entry(ioc->hpr_free_list.next, 398862306a36Sopenharmony_ci struct request_tracker, tracker_list); 398962306a36Sopenharmony_ci request->cb_idx = cb_idx; 399062306a36Sopenharmony_ci smid = request->smid; 399162306a36Sopenharmony_ci list_del(&request->tracker_list); 399262306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); 399362306a36Sopenharmony_ci return smid; 399462306a36Sopenharmony_ci} 399562306a36Sopenharmony_ci 399662306a36Sopenharmony_cistatic void 399762306a36Sopenharmony_ci_base_recovery_check(struct MPT3SAS_ADAPTER *ioc) 399862306a36Sopenharmony_ci{ 399962306a36Sopenharmony_ci /* 400062306a36Sopenharmony_ci * See _wait_for_commands_to_complete() call with regards to this code. 400162306a36Sopenharmony_ci */ 400262306a36Sopenharmony_ci if (ioc->shost_recovery && ioc->pending_io_count) { 400362306a36Sopenharmony_ci ioc->pending_io_count = scsi_host_busy(ioc->shost); 400462306a36Sopenharmony_ci if (ioc->pending_io_count == 0) 400562306a36Sopenharmony_ci wake_up(&ioc->reset_wq); 400662306a36Sopenharmony_ci } 400762306a36Sopenharmony_ci} 400862306a36Sopenharmony_ci 400962306a36Sopenharmony_civoid mpt3sas_base_clear_st(struct MPT3SAS_ADAPTER *ioc, 401062306a36Sopenharmony_ci struct scsiio_tracker *st) 401162306a36Sopenharmony_ci{ 401262306a36Sopenharmony_ci if (WARN_ON(st->smid == 0)) 401362306a36Sopenharmony_ci return; 401462306a36Sopenharmony_ci st->cb_idx = 0xFF; 401562306a36Sopenharmony_ci st->direct_io = 0; 401662306a36Sopenharmony_ci st->scmd = NULL; 401762306a36Sopenharmony_ci atomic_set(&ioc->chain_lookup[st->smid - 1].chain_offset, 0); 401862306a36Sopenharmony_ci st->smid = 0; 401962306a36Sopenharmony_ci} 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_ci/** 402262306a36Sopenharmony_ci * mpt3sas_base_free_smid - put smid back on free_list 402362306a36Sopenharmony_ci * @ioc: per adapter object 402462306a36Sopenharmony_ci * @smid: system request message index 402562306a36Sopenharmony_ci */ 402662306a36Sopenharmony_civoid 402762306a36Sopenharmony_cimpt3sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid) 402862306a36Sopenharmony_ci{ 402962306a36Sopenharmony_ci unsigned long flags; 403062306a36Sopenharmony_ci int i; 403162306a36Sopenharmony_ci 403262306a36Sopenharmony_ci if (smid < ioc->hi_priority_smid) { 403362306a36Sopenharmony_ci struct scsiio_tracker *st; 403462306a36Sopenharmony_ci void *request; 403562306a36Sopenharmony_ci 403662306a36Sopenharmony_ci st = _get_st_from_smid(ioc, smid); 403762306a36Sopenharmony_ci if (!st) { 403862306a36Sopenharmony_ci _base_recovery_check(ioc); 403962306a36Sopenharmony_ci return; 404062306a36Sopenharmony_ci } 404162306a36Sopenharmony_ci 404262306a36Sopenharmony_ci /* Clear MPI request frame */ 404362306a36Sopenharmony_ci request = mpt3sas_base_get_msg_frame(ioc, smid); 404462306a36Sopenharmony_ci memset(request, 0, ioc->request_sz); 404562306a36Sopenharmony_ci 404662306a36Sopenharmony_ci mpt3sas_base_clear_st(ioc, st); 404762306a36Sopenharmony_ci _base_recovery_check(ioc); 404862306a36Sopenharmony_ci ioc->io_queue_num[smid - 1] = 0; 404962306a36Sopenharmony_ci return; 405062306a36Sopenharmony_ci } 405162306a36Sopenharmony_ci 405262306a36Sopenharmony_ci spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); 405362306a36Sopenharmony_ci if (smid < ioc->internal_smid) { 405462306a36Sopenharmony_ci /* hi-priority */ 405562306a36Sopenharmony_ci i = smid - ioc->hi_priority_smid; 405662306a36Sopenharmony_ci ioc->hpr_lookup[i].cb_idx = 0xFF; 405762306a36Sopenharmony_ci list_add(&ioc->hpr_lookup[i].tracker_list, &ioc->hpr_free_list); 405862306a36Sopenharmony_ci } else if (smid <= ioc->hba_queue_depth) { 405962306a36Sopenharmony_ci /* internal queue */ 406062306a36Sopenharmony_ci i = smid - ioc->internal_smid; 406162306a36Sopenharmony_ci ioc->internal_lookup[i].cb_idx = 0xFF; 406262306a36Sopenharmony_ci list_add(&ioc->internal_lookup[i].tracker_list, 406362306a36Sopenharmony_ci &ioc->internal_free_list); 406462306a36Sopenharmony_ci } 406562306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); 406662306a36Sopenharmony_ci} 406762306a36Sopenharmony_ci 406862306a36Sopenharmony_ci/** 406962306a36Sopenharmony_ci * _base_mpi_ep_writeq - 32 bit write to MMIO 407062306a36Sopenharmony_ci * @b: data payload 407162306a36Sopenharmony_ci * @addr: address in MMIO space 407262306a36Sopenharmony_ci * @writeq_lock: spin lock 407362306a36Sopenharmony_ci * 407462306a36Sopenharmony_ci * This special handling for MPI EP to take care of 32 bit 407562306a36Sopenharmony_ci * environment where its not quarenteed to send the entire word 407662306a36Sopenharmony_ci * in one transfer. 407762306a36Sopenharmony_ci */ 407862306a36Sopenharmony_cistatic inline void 407962306a36Sopenharmony_ci_base_mpi_ep_writeq(__u64 b, volatile void __iomem *addr, 408062306a36Sopenharmony_ci spinlock_t *writeq_lock) 408162306a36Sopenharmony_ci{ 408262306a36Sopenharmony_ci unsigned long flags; 408362306a36Sopenharmony_ci 408462306a36Sopenharmony_ci spin_lock_irqsave(writeq_lock, flags); 408562306a36Sopenharmony_ci __raw_writel((u32)(b), addr); 408662306a36Sopenharmony_ci __raw_writel((u32)(b >> 32), (addr + 4)); 408762306a36Sopenharmony_ci spin_unlock_irqrestore(writeq_lock, flags); 408862306a36Sopenharmony_ci} 408962306a36Sopenharmony_ci 409062306a36Sopenharmony_ci/** 409162306a36Sopenharmony_ci * _base_writeq - 64 bit write to MMIO 409262306a36Sopenharmony_ci * @b: data payload 409362306a36Sopenharmony_ci * @addr: address in MMIO space 409462306a36Sopenharmony_ci * @writeq_lock: spin lock 409562306a36Sopenharmony_ci * 409662306a36Sopenharmony_ci * Glue for handling an atomic 64 bit word to MMIO. This special handling takes 409762306a36Sopenharmony_ci * care of 32 bit environment where its not quarenteed to send the entire word 409862306a36Sopenharmony_ci * in one transfer. 409962306a36Sopenharmony_ci */ 410062306a36Sopenharmony_ci#if defined(writeq) && defined(CONFIG_64BIT) 410162306a36Sopenharmony_cistatic inline void 410262306a36Sopenharmony_ci_base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock) 410362306a36Sopenharmony_ci{ 410462306a36Sopenharmony_ci wmb(); 410562306a36Sopenharmony_ci __raw_writeq(b, addr); 410662306a36Sopenharmony_ci barrier(); 410762306a36Sopenharmony_ci} 410862306a36Sopenharmony_ci#else 410962306a36Sopenharmony_cistatic inline void 411062306a36Sopenharmony_ci_base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock) 411162306a36Sopenharmony_ci{ 411262306a36Sopenharmony_ci _base_mpi_ep_writeq(b, addr, writeq_lock); 411362306a36Sopenharmony_ci} 411462306a36Sopenharmony_ci#endif 411562306a36Sopenharmony_ci 411662306a36Sopenharmony_ci/** 411762306a36Sopenharmony_ci * _base_set_and_get_msix_index - get the msix index and assign to msix_io 411862306a36Sopenharmony_ci * variable of scsi tracker 411962306a36Sopenharmony_ci * @ioc: per adapter object 412062306a36Sopenharmony_ci * @smid: system request message index 412162306a36Sopenharmony_ci * 412262306a36Sopenharmony_ci * Return: msix index. 412362306a36Sopenharmony_ci */ 412462306a36Sopenharmony_cistatic u8 412562306a36Sopenharmony_ci_base_set_and_get_msix_index(struct MPT3SAS_ADAPTER *ioc, u16 smid) 412662306a36Sopenharmony_ci{ 412762306a36Sopenharmony_ci struct scsiio_tracker *st = NULL; 412862306a36Sopenharmony_ci 412962306a36Sopenharmony_ci if (smid < ioc->hi_priority_smid) 413062306a36Sopenharmony_ci st = _get_st_from_smid(ioc, smid); 413162306a36Sopenharmony_ci 413262306a36Sopenharmony_ci if (st == NULL) 413362306a36Sopenharmony_ci return _base_get_msix_index(ioc, NULL); 413462306a36Sopenharmony_ci 413562306a36Sopenharmony_ci st->msix_io = ioc->get_msix_index_for_smlio(ioc, st->scmd); 413662306a36Sopenharmony_ci return st->msix_io; 413762306a36Sopenharmony_ci} 413862306a36Sopenharmony_ci 413962306a36Sopenharmony_ci/** 414062306a36Sopenharmony_ci * _base_put_smid_mpi_ep_scsi_io - send SCSI_IO request to firmware 414162306a36Sopenharmony_ci * @ioc: per adapter object 414262306a36Sopenharmony_ci * @smid: system request message index 414362306a36Sopenharmony_ci * @handle: device handle 414462306a36Sopenharmony_ci */ 414562306a36Sopenharmony_cistatic void 414662306a36Sopenharmony_ci_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, 414762306a36Sopenharmony_ci u16 smid, u16 handle) 414862306a36Sopenharmony_ci{ 414962306a36Sopenharmony_ci Mpi2RequestDescriptorUnion_t descriptor; 415062306a36Sopenharmony_ci u64 *request = (u64 *)&descriptor; 415162306a36Sopenharmony_ci void *mpi_req_iomem; 415262306a36Sopenharmony_ci __le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid); 415362306a36Sopenharmony_ci 415462306a36Sopenharmony_ci _clone_sg_entries(ioc, (void *) mfp, smid); 415562306a36Sopenharmony_ci mpi_req_iomem = (void __force *)ioc->chip + 415662306a36Sopenharmony_ci MPI_FRAME_START_OFFSET + (smid * ioc->request_sz); 415762306a36Sopenharmony_ci _base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp, 415862306a36Sopenharmony_ci ioc->request_sz); 415962306a36Sopenharmony_ci descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; 416062306a36Sopenharmony_ci descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); 416162306a36Sopenharmony_ci descriptor.SCSIIO.SMID = cpu_to_le16(smid); 416262306a36Sopenharmony_ci descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); 416362306a36Sopenharmony_ci descriptor.SCSIIO.LMID = 0; 416462306a36Sopenharmony_ci _base_mpi_ep_writeq(*request, &ioc->chip->RequestDescriptorPostLow, 416562306a36Sopenharmony_ci &ioc->scsi_lookup_lock); 416662306a36Sopenharmony_ci} 416762306a36Sopenharmony_ci 416862306a36Sopenharmony_ci/** 416962306a36Sopenharmony_ci * _base_put_smid_scsi_io - send SCSI_IO request to firmware 417062306a36Sopenharmony_ci * @ioc: per adapter object 417162306a36Sopenharmony_ci * @smid: system request message index 417262306a36Sopenharmony_ci * @handle: device handle 417362306a36Sopenharmony_ci */ 417462306a36Sopenharmony_cistatic void 417562306a36Sopenharmony_ci_base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) 417662306a36Sopenharmony_ci{ 417762306a36Sopenharmony_ci Mpi2RequestDescriptorUnion_t descriptor; 417862306a36Sopenharmony_ci u64 *request = (u64 *)&descriptor; 417962306a36Sopenharmony_ci 418062306a36Sopenharmony_ci 418162306a36Sopenharmony_ci descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; 418262306a36Sopenharmony_ci descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); 418362306a36Sopenharmony_ci descriptor.SCSIIO.SMID = cpu_to_le16(smid); 418462306a36Sopenharmony_ci descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); 418562306a36Sopenharmony_ci descriptor.SCSIIO.LMID = 0; 418662306a36Sopenharmony_ci _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, 418762306a36Sopenharmony_ci &ioc->scsi_lookup_lock); 418862306a36Sopenharmony_ci} 418962306a36Sopenharmony_ci 419062306a36Sopenharmony_ci/** 419162306a36Sopenharmony_ci * _base_put_smid_fast_path - send fast path request to firmware 419262306a36Sopenharmony_ci * @ioc: per adapter object 419362306a36Sopenharmony_ci * @smid: system request message index 419462306a36Sopenharmony_ci * @handle: device handle 419562306a36Sopenharmony_ci */ 419662306a36Sopenharmony_cistatic void 419762306a36Sopenharmony_ci_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, 419862306a36Sopenharmony_ci u16 handle) 419962306a36Sopenharmony_ci{ 420062306a36Sopenharmony_ci Mpi2RequestDescriptorUnion_t descriptor; 420162306a36Sopenharmony_ci u64 *request = (u64 *)&descriptor; 420262306a36Sopenharmony_ci 420362306a36Sopenharmony_ci descriptor.SCSIIO.RequestFlags = 420462306a36Sopenharmony_ci MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; 420562306a36Sopenharmony_ci descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); 420662306a36Sopenharmony_ci descriptor.SCSIIO.SMID = cpu_to_le16(smid); 420762306a36Sopenharmony_ci descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); 420862306a36Sopenharmony_ci descriptor.SCSIIO.LMID = 0; 420962306a36Sopenharmony_ci _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, 421062306a36Sopenharmony_ci &ioc->scsi_lookup_lock); 421162306a36Sopenharmony_ci} 421262306a36Sopenharmony_ci 421362306a36Sopenharmony_ci/** 421462306a36Sopenharmony_ci * _base_put_smid_hi_priority - send Task Management request to firmware 421562306a36Sopenharmony_ci * @ioc: per adapter object 421662306a36Sopenharmony_ci * @smid: system request message index 421762306a36Sopenharmony_ci * @msix_task: msix_task will be same as msix of IO in case of task abort else 0 421862306a36Sopenharmony_ci */ 421962306a36Sopenharmony_cistatic void 422062306a36Sopenharmony_ci_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid, 422162306a36Sopenharmony_ci u16 msix_task) 422262306a36Sopenharmony_ci{ 422362306a36Sopenharmony_ci Mpi2RequestDescriptorUnion_t descriptor; 422462306a36Sopenharmony_ci void *mpi_req_iomem; 422562306a36Sopenharmony_ci u64 *request; 422662306a36Sopenharmony_ci 422762306a36Sopenharmony_ci if (ioc->is_mcpu_endpoint) { 422862306a36Sopenharmony_ci __le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid); 422962306a36Sopenharmony_ci 423062306a36Sopenharmony_ci /* TBD 256 is offset within sys register. */ 423162306a36Sopenharmony_ci mpi_req_iomem = (void __force *)ioc->chip 423262306a36Sopenharmony_ci + MPI_FRAME_START_OFFSET 423362306a36Sopenharmony_ci + (smid * ioc->request_sz); 423462306a36Sopenharmony_ci _base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp, 423562306a36Sopenharmony_ci ioc->request_sz); 423662306a36Sopenharmony_ci } 423762306a36Sopenharmony_ci 423862306a36Sopenharmony_ci request = (u64 *)&descriptor; 423962306a36Sopenharmony_ci 424062306a36Sopenharmony_ci descriptor.HighPriority.RequestFlags = 424162306a36Sopenharmony_ci MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 424262306a36Sopenharmony_ci descriptor.HighPriority.MSIxIndex = msix_task; 424362306a36Sopenharmony_ci descriptor.HighPriority.SMID = cpu_to_le16(smid); 424462306a36Sopenharmony_ci descriptor.HighPriority.LMID = 0; 424562306a36Sopenharmony_ci descriptor.HighPriority.Reserved1 = 0; 424662306a36Sopenharmony_ci if (ioc->is_mcpu_endpoint) 424762306a36Sopenharmony_ci _base_mpi_ep_writeq(*request, 424862306a36Sopenharmony_ci &ioc->chip->RequestDescriptorPostLow, 424962306a36Sopenharmony_ci &ioc->scsi_lookup_lock); 425062306a36Sopenharmony_ci else 425162306a36Sopenharmony_ci _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, 425262306a36Sopenharmony_ci &ioc->scsi_lookup_lock); 425362306a36Sopenharmony_ci} 425462306a36Sopenharmony_ci 425562306a36Sopenharmony_ci/** 425662306a36Sopenharmony_ci * mpt3sas_base_put_smid_nvme_encap - send NVMe encapsulated request to 425762306a36Sopenharmony_ci * firmware 425862306a36Sopenharmony_ci * @ioc: per adapter object 425962306a36Sopenharmony_ci * @smid: system request message index 426062306a36Sopenharmony_ci */ 426162306a36Sopenharmony_civoid 426262306a36Sopenharmony_cimpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid) 426362306a36Sopenharmony_ci{ 426462306a36Sopenharmony_ci Mpi2RequestDescriptorUnion_t descriptor; 426562306a36Sopenharmony_ci u64 *request = (u64 *)&descriptor; 426662306a36Sopenharmony_ci 426762306a36Sopenharmony_ci descriptor.Default.RequestFlags = 426862306a36Sopenharmony_ci MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED; 426962306a36Sopenharmony_ci descriptor.Default.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); 427062306a36Sopenharmony_ci descriptor.Default.SMID = cpu_to_le16(smid); 427162306a36Sopenharmony_ci descriptor.Default.LMID = 0; 427262306a36Sopenharmony_ci descriptor.Default.DescriptorTypeDependent = 0; 427362306a36Sopenharmony_ci _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, 427462306a36Sopenharmony_ci &ioc->scsi_lookup_lock); 427562306a36Sopenharmony_ci} 427662306a36Sopenharmony_ci 427762306a36Sopenharmony_ci/** 427862306a36Sopenharmony_ci * _base_put_smid_default - Default, primarily used for config pages 427962306a36Sopenharmony_ci * @ioc: per adapter object 428062306a36Sopenharmony_ci * @smid: system request message index 428162306a36Sopenharmony_ci */ 428262306a36Sopenharmony_cistatic void 428362306a36Sopenharmony_ci_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) 428462306a36Sopenharmony_ci{ 428562306a36Sopenharmony_ci Mpi2RequestDescriptorUnion_t descriptor; 428662306a36Sopenharmony_ci void *mpi_req_iomem; 428762306a36Sopenharmony_ci u64 *request; 428862306a36Sopenharmony_ci 428962306a36Sopenharmony_ci if (ioc->is_mcpu_endpoint) { 429062306a36Sopenharmony_ci __le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid); 429162306a36Sopenharmony_ci 429262306a36Sopenharmony_ci _clone_sg_entries(ioc, (void *) mfp, smid); 429362306a36Sopenharmony_ci /* TBD 256 is offset within sys register */ 429462306a36Sopenharmony_ci mpi_req_iomem = (void __force *)ioc->chip + 429562306a36Sopenharmony_ci MPI_FRAME_START_OFFSET + (smid * ioc->request_sz); 429662306a36Sopenharmony_ci _base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp, 429762306a36Sopenharmony_ci ioc->request_sz); 429862306a36Sopenharmony_ci } 429962306a36Sopenharmony_ci request = (u64 *)&descriptor; 430062306a36Sopenharmony_ci descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 430162306a36Sopenharmony_ci descriptor.Default.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); 430262306a36Sopenharmony_ci descriptor.Default.SMID = cpu_to_le16(smid); 430362306a36Sopenharmony_ci descriptor.Default.LMID = 0; 430462306a36Sopenharmony_ci descriptor.Default.DescriptorTypeDependent = 0; 430562306a36Sopenharmony_ci if (ioc->is_mcpu_endpoint) 430662306a36Sopenharmony_ci _base_mpi_ep_writeq(*request, 430762306a36Sopenharmony_ci &ioc->chip->RequestDescriptorPostLow, 430862306a36Sopenharmony_ci &ioc->scsi_lookup_lock); 430962306a36Sopenharmony_ci else 431062306a36Sopenharmony_ci _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, 431162306a36Sopenharmony_ci &ioc->scsi_lookup_lock); 431262306a36Sopenharmony_ci} 431362306a36Sopenharmony_ci 431462306a36Sopenharmony_ci/** 431562306a36Sopenharmony_ci * _base_put_smid_scsi_io_atomic - send SCSI_IO request to firmware using 431662306a36Sopenharmony_ci * Atomic Request Descriptor 431762306a36Sopenharmony_ci * @ioc: per adapter object 431862306a36Sopenharmony_ci * @smid: system request message index 431962306a36Sopenharmony_ci * @handle: device handle, unused in this function, for function type match 432062306a36Sopenharmony_ci * 432162306a36Sopenharmony_ci * Return: nothing. 432262306a36Sopenharmony_ci */ 432362306a36Sopenharmony_cistatic void 432462306a36Sopenharmony_ci_base_put_smid_scsi_io_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, 432562306a36Sopenharmony_ci u16 handle) 432662306a36Sopenharmony_ci{ 432762306a36Sopenharmony_ci Mpi26AtomicRequestDescriptor_t descriptor; 432862306a36Sopenharmony_ci u32 *request = (u32 *)&descriptor; 432962306a36Sopenharmony_ci 433062306a36Sopenharmony_ci descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; 433162306a36Sopenharmony_ci descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); 433262306a36Sopenharmony_ci descriptor.SMID = cpu_to_le16(smid); 433362306a36Sopenharmony_ci 433462306a36Sopenharmony_ci writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); 433562306a36Sopenharmony_ci} 433662306a36Sopenharmony_ci 433762306a36Sopenharmony_ci/** 433862306a36Sopenharmony_ci * _base_put_smid_fast_path_atomic - send fast path request to firmware 433962306a36Sopenharmony_ci * using Atomic Request Descriptor 434062306a36Sopenharmony_ci * @ioc: per adapter object 434162306a36Sopenharmony_ci * @smid: system request message index 434262306a36Sopenharmony_ci * @handle: device handle, unused in this function, for function type match 434362306a36Sopenharmony_ci * Return: nothing 434462306a36Sopenharmony_ci */ 434562306a36Sopenharmony_cistatic void 434662306a36Sopenharmony_ci_base_put_smid_fast_path_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, 434762306a36Sopenharmony_ci u16 handle) 434862306a36Sopenharmony_ci{ 434962306a36Sopenharmony_ci Mpi26AtomicRequestDescriptor_t descriptor; 435062306a36Sopenharmony_ci u32 *request = (u32 *)&descriptor; 435162306a36Sopenharmony_ci 435262306a36Sopenharmony_ci descriptor.RequestFlags = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; 435362306a36Sopenharmony_ci descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); 435462306a36Sopenharmony_ci descriptor.SMID = cpu_to_le16(smid); 435562306a36Sopenharmony_ci 435662306a36Sopenharmony_ci writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); 435762306a36Sopenharmony_ci} 435862306a36Sopenharmony_ci 435962306a36Sopenharmony_ci/** 436062306a36Sopenharmony_ci * _base_put_smid_hi_priority_atomic - send Task Management request to 436162306a36Sopenharmony_ci * firmware using Atomic Request Descriptor 436262306a36Sopenharmony_ci * @ioc: per adapter object 436362306a36Sopenharmony_ci * @smid: system request message index 436462306a36Sopenharmony_ci * @msix_task: msix_task will be same as msix of IO in case of task abort else 0 436562306a36Sopenharmony_ci * 436662306a36Sopenharmony_ci * Return: nothing. 436762306a36Sopenharmony_ci */ 436862306a36Sopenharmony_cistatic void 436962306a36Sopenharmony_ci_base_put_smid_hi_priority_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, 437062306a36Sopenharmony_ci u16 msix_task) 437162306a36Sopenharmony_ci{ 437262306a36Sopenharmony_ci Mpi26AtomicRequestDescriptor_t descriptor; 437362306a36Sopenharmony_ci u32 *request = (u32 *)&descriptor; 437462306a36Sopenharmony_ci 437562306a36Sopenharmony_ci descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 437662306a36Sopenharmony_ci descriptor.MSIxIndex = msix_task; 437762306a36Sopenharmony_ci descriptor.SMID = cpu_to_le16(smid); 437862306a36Sopenharmony_ci 437962306a36Sopenharmony_ci writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); 438062306a36Sopenharmony_ci} 438162306a36Sopenharmony_ci 438262306a36Sopenharmony_ci/** 438362306a36Sopenharmony_ci * _base_put_smid_default_atomic - Default, primarily used for config pages 438462306a36Sopenharmony_ci * use Atomic Request Descriptor 438562306a36Sopenharmony_ci * @ioc: per adapter object 438662306a36Sopenharmony_ci * @smid: system request message index 438762306a36Sopenharmony_ci * 438862306a36Sopenharmony_ci * Return: nothing. 438962306a36Sopenharmony_ci */ 439062306a36Sopenharmony_cistatic void 439162306a36Sopenharmony_ci_base_put_smid_default_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid) 439262306a36Sopenharmony_ci{ 439362306a36Sopenharmony_ci Mpi26AtomicRequestDescriptor_t descriptor; 439462306a36Sopenharmony_ci u32 *request = (u32 *)&descriptor; 439562306a36Sopenharmony_ci 439662306a36Sopenharmony_ci descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 439762306a36Sopenharmony_ci descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); 439862306a36Sopenharmony_ci descriptor.SMID = cpu_to_le16(smid); 439962306a36Sopenharmony_ci 440062306a36Sopenharmony_ci writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); 440162306a36Sopenharmony_ci} 440262306a36Sopenharmony_ci 440362306a36Sopenharmony_ci/** 440462306a36Sopenharmony_ci * _base_display_OEMs_branding - Display branding string 440562306a36Sopenharmony_ci * @ioc: per adapter object 440662306a36Sopenharmony_ci */ 440762306a36Sopenharmony_cistatic void 440862306a36Sopenharmony_ci_base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc) 440962306a36Sopenharmony_ci{ 441062306a36Sopenharmony_ci if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL) 441162306a36Sopenharmony_ci return; 441262306a36Sopenharmony_ci 441362306a36Sopenharmony_ci switch (ioc->pdev->subsystem_vendor) { 441462306a36Sopenharmony_ci case PCI_VENDOR_ID_INTEL: 441562306a36Sopenharmony_ci switch (ioc->pdev->device) { 441662306a36Sopenharmony_ci case MPI2_MFGPAGE_DEVID_SAS2008: 441762306a36Sopenharmony_ci switch (ioc->pdev->subsystem_device) { 441862306a36Sopenharmony_ci case MPT2SAS_INTEL_RMS2LL080_SSDID: 441962306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 442062306a36Sopenharmony_ci MPT2SAS_INTEL_RMS2LL080_BRANDING); 442162306a36Sopenharmony_ci break; 442262306a36Sopenharmony_ci case MPT2SAS_INTEL_RMS2LL040_SSDID: 442362306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 442462306a36Sopenharmony_ci MPT2SAS_INTEL_RMS2LL040_BRANDING); 442562306a36Sopenharmony_ci break; 442662306a36Sopenharmony_ci case MPT2SAS_INTEL_SSD910_SSDID: 442762306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 442862306a36Sopenharmony_ci MPT2SAS_INTEL_SSD910_BRANDING); 442962306a36Sopenharmony_ci break; 443062306a36Sopenharmony_ci default: 443162306a36Sopenharmony_ci ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n", 443262306a36Sopenharmony_ci ioc->pdev->subsystem_device); 443362306a36Sopenharmony_ci break; 443462306a36Sopenharmony_ci } 443562306a36Sopenharmony_ci break; 443662306a36Sopenharmony_ci case MPI2_MFGPAGE_DEVID_SAS2308_2: 443762306a36Sopenharmony_ci switch (ioc->pdev->subsystem_device) { 443862306a36Sopenharmony_ci case MPT2SAS_INTEL_RS25GB008_SSDID: 443962306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 444062306a36Sopenharmony_ci MPT2SAS_INTEL_RS25GB008_BRANDING); 444162306a36Sopenharmony_ci break; 444262306a36Sopenharmony_ci case MPT2SAS_INTEL_RMS25JB080_SSDID: 444362306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 444462306a36Sopenharmony_ci MPT2SAS_INTEL_RMS25JB080_BRANDING); 444562306a36Sopenharmony_ci break; 444662306a36Sopenharmony_ci case MPT2SAS_INTEL_RMS25JB040_SSDID: 444762306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 444862306a36Sopenharmony_ci MPT2SAS_INTEL_RMS25JB040_BRANDING); 444962306a36Sopenharmony_ci break; 445062306a36Sopenharmony_ci case MPT2SAS_INTEL_RMS25KB080_SSDID: 445162306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 445262306a36Sopenharmony_ci MPT2SAS_INTEL_RMS25KB080_BRANDING); 445362306a36Sopenharmony_ci break; 445462306a36Sopenharmony_ci case MPT2SAS_INTEL_RMS25KB040_SSDID: 445562306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 445662306a36Sopenharmony_ci MPT2SAS_INTEL_RMS25KB040_BRANDING); 445762306a36Sopenharmony_ci break; 445862306a36Sopenharmony_ci case MPT2SAS_INTEL_RMS25LB040_SSDID: 445962306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 446062306a36Sopenharmony_ci MPT2SAS_INTEL_RMS25LB040_BRANDING); 446162306a36Sopenharmony_ci break; 446262306a36Sopenharmony_ci case MPT2SAS_INTEL_RMS25LB080_SSDID: 446362306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 446462306a36Sopenharmony_ci MPT2SAS_INTEL_RMS25LB080_BRANDING); 446562306a36Sopenharmony_ci break; 446662306a36Sopenharmony_ci default: 446762306a36Sopenharmony_ci ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n", 446862306a36Sopenharmony_ci ioc->pdev->subsystem_device); 446962306a36Sopenharmony_ci break; 447062306a36Sopenharmony_ci } 447162306a36Sopenharmony_ci break; 447262306a36Sopenharmony_ci case MPI25_MFGPAGE_DEVID_SAS3008: 447362306a36Sopenharmony_ci switch (ioc->pdev->subsystem_device) { 447462306a36Sopenharmony_ci case MPT3SAS_INTEL_RMS3JC080_SSDID: 447562306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 447662306a36Sopenharmony_ci MPT3SAS_INTEL_RMS3JC080_BRANDING); 447762306a36Sopenharmony_ci break; 447862306a36Sopenharmony_ci 447962306a36Sopenharmony_ci case MPT3SAS_INTEL_RS3GC008_SSDID: 448062306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 448162306a36Sopenharmony_ci MPT3SAS_INTEL_RS3GC008_BRANDING); 448262306a36Sopenharmony_ci break; 448362306a36Sopenharmony_ci case MPT3SAS_INTEL_RS3FC044_SSDID: 448462306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 448562306a36Sopenharmony_ci MPT3SAS_INTEL_RS3FC044_BRANDING); 448662306a36Sopenharmony_ci break; 448762306a36Sopenharmony_ci case MPT3SAS_INTEL_RS3UC080_SSDID: 448862306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 448962306a36Sopenharmony_ci MPT3SAS_INTEL_RS3UC080_BRANDING); 449062306a36Sopenharmony_ci break; 449162306a36Sopenharmony_ci default: 449262306a36Sopenharmony_ci ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n", 449362306a36Sopenharmony_ci ioc->pdev->subsystem_device); 449462306a36Sopenharmony_ci break; 449562306a36Sopenharmony_ci } 449662306a36Sopenharmony_ci break; 449762306a36Sopenharmony_ci default: 449862306a36Sopenharmony_ci ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n", 449962306a36Sopenharmony_ci ioc->pdev->subsystem_device); 450062306a36Sopenharmony_ci break; 450162306a36Sopenharmony_ci } 450262306a36Sopenharmony_ci break; 450362306a36Sopenharmony_ci case PCI_VENDOR_ID_DELL: 450462306a36Sopenharmony_ci switch (ioc->pdev->device) { 450562306a36Sopenharmony_ci case MPI2_MFGPAGE_DEVID_SAS2008: 450662306a36Sopenharmony_ci switch (ioc->pdev->subsystem_device) { 450762306a36Sopenharmony_ci case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID: 450862306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 450962306a36Sopenharmony_ci MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING); 451062306a36Sopenharmony_ci break; 451162306a36Sopenharmony_ci case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID: 451262306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 451362306a36Sopenharmony_ci MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING); 451462306a36Sopenharmony_ci break; 451562306a36Sopenharmony_ci case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID: 451662306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 451762306a36Sopenharmony_ci MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING); 451862306a36Sopenharmony_ci break; 451962306a36Sopenharmony_ci case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID: 452062306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 452162306a36Sopenharmony_ci MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING); 452262306a36Sopenharmony_ci break; 452362306a36Sopenharmony_ci case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID: 452462306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 452562306a36Sopenharmony_ci MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING); 452662306a36Sopenharmony_ci break; 452762306a36Sopenharmony_ci case MPT2SAS_DELL_PERC_H200_SSDID: 452862306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 452962306a36Sopenharmony_ci MPT2SAS_DELL_PERC_H200_BRANDING); 453062306a36Sopenharmony_ci break; 453162306a36Sopenharmony_ci case MPT2SAS_DELL_6GBPS_SAS_SSDID: 453262306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 453362306a36Sopenharmony_ci MPT2SAS_DELL_6GBPS_SAS_BRANDING); 453462306a36Sopenharmony_ci break; 453562306a36Sopenharmony_ci default: 453662306a36Sopenharmony_ci ioc_info(ioc, "Dell 6Gbps HBA: Subsystem ID: 0x%X\n", 453762306a36Sopenharmony_ci ioc->pdev->subsystem_device); 453862306a36Sopenharmony_ci break; 453962306a36Sopenharmony_ci } 454062306a36Sopenharmony_ci break; 454162306a36Sopenharmony_ci case MPI25_MFGPAGE_DEVID_SAS3008: 454262306a36Sopenharmony_ci switch (ioc->pdev->subsystem_device) { 454362306a36Sopenharmony_ci case MPT3SAS_DELL_12G_HBA_SSDID: 454462306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 454562306a36Sopenharmony_ci MPT3SAS_DELL_12G_HBA_BRANDING); 454662306a36Sopenharmony_ci break; 454762306a36Sopenharmony_ci default: 454862306a36Sopenharmony_ci ioc_info(ioc, "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", 454962306a36Sopenharmony_ci ioc->pdev->subsystem_device); 455062306a36Sopenharmony_ci break; 455162306a36Sopenharmony_ci } 455262306a36Sopenharmony_ci break; 455362306a36Sopenharmony_ci default: 455462306a36Sopenharmony_ci ioc_info(ioc, "Dell HBA: Subsystem ID: 0x%X\n", 455562306a36Sopenharmony_ci ioc->pdev->subsystem_device); 455662306a36Sopenharmony_ci break; 455762306a36Sopenharmony_ci } 455862306a36Sopenharmony_ci break; 455962306a36Sopenharmony_ci case PCI_VENDOR_ID_CISCO: 456062306a36Sopenharmony_ci switch (ioc->pdev->device) { 456162306a36Sopenharmony_ci case MPI25_MFGPAGE_DEVID_SAS3008: 456262306a36Sopenharmony_ci switch (ioc->pdev->subsystem_device) { 456362306a36Sopenharmony_ci case MPT3SAS_CISCO_12G_8E_HBA_SSDID: 456462306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 456562306a36Sopenharmony_ci MPT3SAS_CISCO_12G_8E_HBA_BRANDING); 456662306a36Sopenharmony_ci break; 456762306a36Sopenharmony_ci case MPT3SAS_CISCO_12G_8I_HBA_SSDID: 456862306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 456962306a36Sopenharmony_ci MPT3SAS_CISCO_12G_8I_HBA_BRANDING); 457062306a36Sopenharmony_ci break; 457162306a36Sopenharmony_ci case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: 457262306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 457362306a36Sopenharmony_ci MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); 457462306a36Sopenharmony_ci break; 457562306a36Sopenharmony_ci default: 457662306a36Sopenharmony_ci ioc_info(ioc, "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", 457762306a36Sopenharmony_ci ioc->pdev->subsystem_device); 457862306a36Sopenharmony_ci break; 457962306a36Sopenharmony_ci } 458062306a36Sopenharmony_ci break; 458162306a36Sopenharmony_ci case MPI25_MFGPAGE_DEVID_SAS3108_1: 458262306a36Sopenharmony_ci switch (ioc->pdev->subsystem_device) { 458362306a36Sopenharmony_ci case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: 458462306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 458562306a36Sopenharmony_ci MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); 458662306a36Sopenharmony_ci break; 458762306a36Sopenharmony_ci case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID: 458862306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 458962306a36Sopenharmony_ci MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING); 459062306a36Sopenharmony_ci break; 459162306a36Sopenharmony_ci default: 459262306a36Sopenharmony_ci ioc_info(ioc, "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", 459362306a36Sopenharmony_ci ioc->pdev->subsystem_device); 459462306a36Sopenharmony_ci break; 459562306a36Sopenharmony_ci } 459662306a36Sopenharmony_ci break; 459762306a36Sopenharmony_ci default: 459862306a36Sopenharmony_ci ioc_info(ioc, "Cisco SAS HBA: Subsystem ID: 0x%X\n", 459962306a36Sopenharmony_ci ioc->pdev->subsystem_device); 460062306a36Sopenharmony_ci break; 460162306a36Sopenharmony_ci } 460262306a36Sopenharmony_ci break; 460362306a36Sopenharmony_ci case MPT2SAS_HP_3PAR_SSVID: 460462306a36Sopenharmony_ci switch (ioc->pdev->device) { 460562306a36Sopenharmony_ci case MPI2_MFGPAGE_DEVID_SAS2004: 460662306a36Sopenharmony_ci switch (ioc->pdev->subsystem_device) { 460762306a36Sopenharmony_ci case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID: 460862306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 460962306a36Sopenharmony_ci MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING); 461062306a36Sopenharmony_ci break; 461162306a36Sopenharmony_ci default: 461262306a36Sopenharmony_ci ioc_info(ioc, "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", 461362306a36Sopenharmony_ci ioc->pdev->subsystem_device); 461462306a36Sopenharmony_ci break; 461562306a36Sopenharmony_ci } 461662306a36Sopenharmony_ci break; 461762306a36Sopenharmony_ci case MPI2_MFGPAGE_DEVID_SAS2308_2: 461862306a36Sopenharmony_ci switch (ioc->pdev->subsystem_device) { 461962306a36Sopenharmony_ci case MPT2SAS_HP_2_4_INTERNAL_SSDID: 462062306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 462162306a36Sopenharmony_ci MPT2SAS_HP_2_4_INTERNAL_BRANDING); 462262306a36Sopenharmony_ci break; 462362306a36Sopenharmony_ci case MPT2SAS_HP_2_4_EXTERNAL_SSDID: 462462306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 462562306a36Sopenharmony_ci MPT2SAS_HP_2_4_EXTERNAL_BRANDING); 462662306a36Sopenharmony_ci break; 462762306a36Sopenharmony_ci case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID: 462862306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 462962306a36Sopenharmony_ci MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING); 463062306a36Sopenharmony_ci break; 463162306a36Sopenharmony_ci case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID: 463262306a36Sopenharmony_ci ioc_info(ioc, "%s\n", 463362306a36Sopenharmony_ci MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING); 463462306a36Sopenharmony_ci break; 463562306a36Sopenharmony_ci default: 463662306a36Sopenharmony_ci ioc_info(ioc, "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", 463762306a36Sopenharmony_ci ioc->pdev->subsystem_device); 463862306a36Sopenharmony_ci break; 463962306a36Sopenharmony_ci } 464062306a36Sopenharmony_ci break; 464162306a36Sopenharmony_ci default: 464262306a36Sopenharmony_ci ioc_info(ioc, "HP SAS HBA: Subsystem ID: 0x%X\n", 464362306a36Sopenharmony_ci ioc->pdev->subsystem_device); 464462306a36Sopenharmony_ci break; 464562306a36Sopenharmony_ci } 464662306a36Sopenharmony_ci break; 464762306a36Sopenharmony_ci default: 464862306a36Sopenharmony_ci break; 464962306a36Sopenharmony_ci } 465062306a36Sopenharmony_ci} 465162306a36Sopenharmony_ci 465262306a36Sopenharmony_ci/** 465362306a36Sopenharmony_ci * _base_display_fwpkg_version - sends FWUpload request to pull FWPkg 465462306a36Sopenharmony_ci * version from FW Image Header. 465562306a36Sopenharmony_ci * @ioc: per adapter object 465662306a36Sopenharmony_ci * 465762306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 465862306a36Sopenharmony_ci */ 465962306a36Sopenharmony_ci static int 466062306a36Sopenharmony_ci_base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc) 466162306a36Sopenharmony_ci{ 466262306a36Sopenharmony_ci Mpi2FWImageHeader_t *fw_img_hdr; 466362306a36Sopenharmony_ci Mpi26ComponentImageHeader_t *cmp_img_hdr; 466462306a36Sopenharmony_ci Mpi25FWUploadRequest_t *mpi_request; 466562306a36Sopenharmony_ci Mpi2FWUploadReply_t mpi_reply; 466662306a36Sopenharmony_ci int r = 0, issue_diag_reset = 0; 466762306a36Sopenharmony_ci u32 package_version = 0; 466862306a36Sopenharmony_ci void *fwpkg_data = NULL; 466962306a36Sopenharmony_ci dma_addr_t fwpkg_data_dma; 467062306a36Sopenharmony_ci u16 smid, ioc_status; 467162306a36Sopenharmony_ci size_t data_length; 467262306a36Sopenharmony_ci 467362306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 467462306a36Sopenharmony_ci 467562306a36Sopenharmony_ci if (ioc->base_cmds.status & MPT3_CMD_PENDING) { 467662306a36Sopenharmony_ci ioc_err(ioc, "%s: internal command already in use\n", __func__); 467762306a36Sopenharmony_ci return -EAGAIN; 467862306a36Sopenharmony_ci } 467962306a36Sopenharmony_ci 468062306a36Sopenharmony_ci data_length = sizeof(Mpi2FWImageHeader_t); 468162306a36Sopenharmony_ci fwpkg_data = dma_alloc_coherent(&ioc->pdev->dev, data_length, 468262306a36Sopenharmony_ci &fwpkg_data_dma, GFP_KERNEL); 468362306a36Sopenharmony_ci if (!fwpkg_data) { 468462306a36Sopenharmony_ci ioc_err(ioc, 468562306a36Sopenharmony_ci "Memory allocation for fwpkg data failed at %s:%d/%s()!\n", 468662306a36Sopenharmony_ci __FILE__, __LINE__, __func__); 468762306a36Sopenharmony_ci return -ENOMEM; 468862306a36Sopenharmony_ci } 468962306a36Sopenharmony_ci 469062306a36Sopenharmony_ci smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx); 469162306a36Sopenharmony_ci if (!smid) { 469262306a36Sopenharmony_ci ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); 469362306a36Sopenharmony_ci r = -EAGAIN; 469462306a36Sopenharmony_ci goto out; 469562306a36Sopenharmony_ci } 469662306a36Sopenharmony_ci 469762306a36Sopenharmony_ci ioc->base_cmds.status = MPT3_CMD_PENDING; 469862306a36Sopenharmony_ci mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); 469962306a36Sopenharmony_ci ioc->base_cmds.smid = smid; 470062306a36Sopenharmony_ci memset(mpi_request, 0, sizeof(Mpi25FWUploadRequest_t)); 470162306a36Sopenharmony_ci mpi_request->Function = MPI2_FUNCTION_FW_UPLOAD; 470262306a36Sopenharmony_ci mpi_request->ImageType = MPI2_FW_UPLOAD_ITYPE_FW_FLASH; 470362306a36Sopenharmony_ci mpi_request->ImageSize = cpu_to_le32(data_length); 470462306a36Sopenharmony_ci ioc->build_sg(ioc, &mpi_request->SGL, 0, 0, fwpkg_data_dma, 470562306a36Sopenharmony_ci data_length); 470662306a36Sopenharmony_ci init_completion(&ioc->base_cmds.done); 470762306a36Sopenharmony_ci ioc->put_smid_default(ioc, smid); 470862306a36Sopenharmony_ci /* Wait for 15 seconds */ 470962306a36Sopenharmony_ci wait_for_completion_timeout(&ioc->base_cmds.done, 471062306a36Sopenharmony_ci FW_IMG_HDR_READ_TIMEOUT*HZ); 471162306a36Sopenharmony_ci ioc_info(ioc, "%s: complete\n", __func__); 471262306a36Sopenharmony_ci if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { 471362306a36Sopenharmony_ci ioc_err(ioc, "%s: timeout\n", __func__); 471462306a36Sopenharmony_ci _debug_dump_mf(mpi_request, 471562306a36Sopenharmony_ci sizeof(Mpi25FWUploadRequest_t)/4); 471662306a36Sopenharmony_ci issue_diag_reset = 1; 471762306a36Sopenharmony_ci } else { 471862306a36Sopenharmony_ci memset(&mpi_reply, 0, sizeof(Mpi2FWUploadReply_t)); 471962306a36Sopenharmony_ci if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID) { 472062306a36Sopenharmony_ci memcpy(&mpi_reply, ioc->base_cmds.reply, 472162306a36Sopenharmony_ci sizeof(Mpi2FWUploadReply_t)); 472262306a36Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & 472362306a36Sopenharmony_ci MPI2_IOCSTATUS_MASK; 472462306a36Sopenharmony_ci if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { 472562306a36Sopenharmony_ci fw_img_hdr = (Mpi2FWImageHeader_t *)fwpkg_data; 472662306a36Sopenharmony_ci if (le32_to_cpu(fw_img_hdr->Signature) == 472762306a36Sopenharmony_ci MPI26_IMAGE_HEADER_SIGNATURE0_MPI26) { 472862306a36Sopenharmony_ci cmp_img_hdr = 472962306a36Sopenharmony_ci (Mpi26ComponentImageHeader_t *) 473062306a36Sopenharmony_ci (fwpkg_data); 473162306a36Sopenharmony_ci package_version = 473262306a36Sopenharmony_ci le32_to_cpu( 473362306a36Sopenharmony_ci cmp_img_hdr->ApplicationSpecific); 473462306a36Sopenharmony_ci } else 473562306a36Sopenharmony_ci package_version = 473662306a36Sopenharmony_ci le32_to_cpu( 473762306a36Sopenharmony_ci fw_img_hdr->PackageVersion.Word); 473862306a36Sopenharmony_ci if (package_version) 473962306a36Sopenharmony_ci ioc_info(ioc, 474062306a36Sopenharmony_ci "FW Package Ver(%02d.%02d.%02d.%02d)\n", 474162306a36Sopenharmony_ci ((package_version) & 0xFF000000) >> 24, 474262306a36Sopenharmony_ci ((package_version) & 0x00FF0000) >> 16, 474362306a36Sopenharmony_ci ((package_version) & 0x0000FF00) >> 8, 474462306a36Sopenharmony_ci (package_version) & 0x000000FF); 474562306a36Sopenharmony_ci } else { 474662306a36Sopenharmony_ci _debug_dump_mf(&mpi_reply, 474762306a36Sopenharmony_ci sizeof(Mpi2FWUploadReply_t)/4); 474862306a36Sopenharmony_ci } 474962306a36Sopenharmony_ci } 475062306a36Sopenharmony_ci } 475162306a36Sopenharmony_ci ioc->base_cmds.status = MPT3_CMD_NOT_USED; 475262306a36Sopenharmony_ciout: 475362306a36Sopenharmony_ci if (fwpkg_data) 475462306a36Sopenharmony_ci dma_free_coherent(&ioc->pdev->dev, data_length, fwpkg_data, 475562306a36Sopenharmony_ci fwpkg_data_dma); 475662306a36Sopenharmony_ci if (issue_diag_reset) { 475762306a36Sopenharmony_ci if (ioc->drv_internal_flags & MPT_DRV_INTERNAL_FIRST_PE_ISSUED) 475862306a36Sopenharmony_ci return -EFAULT; 475962306a36Sopenharmony_ci if (mpt3sas_base_check_for_fault_and_issue_reset(ioc)) 476062306a36Sopenharmony_ci return -EFAULT; 476162306a36Sopenharmony_ci r = -EAGAIN; 476262306a36Sopenharmony_ci } 476362306a36Sopenharmony_ci return r; 476462306a36Sopenharmony_ci} 476562306a36Sopenharmony_ci 476662306a36Sopenharmony_ci/** 476762306a36Sopenharmony_ci * _base_display_ioc_capabilities - Display IOC's capabilities. 476862306a36Sopenharmony_ci * @ioc: per adapter object 476962306a36Sopenharmony_ci */ 477062306a36Sopenharmony_cistatic void 477162306a36Sopenharmony_ci_base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) 477262306a36Sopenharmony_ci{ 477362306a36Sopenharmony_ci int i = 0; 477462306a36Sopenharmony_ci char desc[17] = {0}; 477562306a36Sopenharmony_ci u32 iounit_pg1_flags; 477662306a36Sopenharmony_ci 477762306a36Sopenharmony_ci strncpy(desc, ioc->manu_pg0.ChipName, 16); 477862306a36Sopenharmony_ci ioc_info(ioc, "%s: FWVersion(%02d.%02d.%02d.%02d), ChipRevision(0x%02x)\n", 477962306a36Sopenharmony_ci desc, 478062306a36Sopenharmony_ci (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, 478162306a36Sopenharmony_ci (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, 478262306a36Sopenharmony_ci (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, 478362306a36Sopenharmony_ci ioc->facts.FWVersion.Word & 0x000000FF, 478462306a36Sopenharmony_ci ioc->pdev->revision); 478562306a36Sopenharmony_ci 478662306a36Sopenharmony_ci _base_display_OEMs_branding(ioc); 478762306a36Sopenharmony_ci 478862306a36Sopenharmony_ci if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_NVME_DEVICES) { 478962306a36Sopenharmony_ci pr_info("%sNVMe", i ? "," : ""); 479062306a36Sopenharmony_ci i++; 479162306a36Sopenharmony_ci } 479262306a36Sopenharmony_ci 479362306a36Sopenharmony_ci ioc_info(ioc, "Protocol=("); 479462306a36Sopenharmony_ci 479562306a36Sopenharmony_ci if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) { 479662306a36Sopenharmony_ci pr_cont("Initiator"); 479762306a36Sopenharmony_ci i++; 479862306a36Sopenharmony_ci } 479962306a36Sopenharmony_ci 480062306a36Sopenharmony_ci if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) { 480162306a36Sopenharmony_ci pr_cont("%sTarget", i ? "," : ""); 480262306a36Sopenharmony_ci i++; 480362306a36Sopenharmony_ci } 480462306a36Sopenharmony_ci 480562306a36Sopenharmony_ci i = 0; 480662306a36Sopenharmony_ci pr_cont("), Capabilities=("); 480762306a36Sopenharmony_ci 480862306a36Sopenharmony_ci if (!ioc->hide_ir_msg) { 480962306a36Sopenharmony_ci if (ioc->facts.IOCCapabilities & 481062306a36Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { 481162306a36Sopenharmony_ci pr_cont("Raid"); 481262306a36Sopenharmony_ci i++; 481362306a36Sopenharmony_ci } 481462306a36Sopenharmony_ci } 481562306a36Sopenharmony_ci 481662306a36Sopenharmony_ci if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) { 481762306a36Sopenharmony_ci pr_cont("%sTLR", i ? "," : ""); 481862306a36Sopenharmony_ci i++; 481962306a36Sopenharmony_ci } 482062306a36Sopenharmony_ci 482162306a36Sopenharmony_ci if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) { 482262306a36Sopenharmony_ci pr_cont("%sMulticast", i ? "," : ""); 482362306a36Sopenharmony_ci i++; 482462306a36Sopenharmony_ci } 482562306a36Sopenharmony_ci 482662306a36Sopenharmony_ci if (ioc->facts.IOCCapabilities & 482762306a36Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) { 482862306a36Sopenharmony_ci pr_cont("%sBIDI Target", i ? "," : ""); 482962306a36Sopenharmony_ci i++; 483062306a36Sopenharmony_ci } 483162306a36Sopenharmony_ci 483262306a36Sopenharmony_ci if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) { 483362306a36Sopenharmony_ci pr_cont("%sEEDP", i ? "," : ""); 483462306a36Sopenharmony_ci i++; 483562306a36Sopenharmony_ci } 483662306a36Sopenharmony_ci 483762306a36Sopenharmony_ci if (ioc->facts.IOCCapabilities & 483862306a36Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) { 483962306a36Sopenharmony_ci pr_cont("%sSnapshot Buffer", i ? "," : ""); 484062306a36Sopenharmony_ci i++; 484162306a36Sopenharmony_ci } 484262306a36Sopenharmony_ci 484362306a36Sopenharmony_ci if (ioc->facts.IOCCapabilities & 484462306a36Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) { 484562306a36Sopenharmony_ci pr_cont("%sDiag Trace Buffer", i ? "," : ""); 484662306a36Sopenharmony_ci i++; 484762306a36Sopenharmony_ci } 484862306a36Sopenharmony_ci 484962306a36Sopenharmony_ci if (ioc->facts.IOCCapabilities & 485062306a36Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) { 485162306a36Sopenharmony_ci pr_cont("%sDiag Extended Buffer", i ? "," : ""); 485262306a36Sopenharmony_ci i++; 485362306a36Sopenharmony_ci } 485462306a36Sopenharmony_ci 485562306a36Sopenharmony_ci if (ioc->facts.IOCCapabilities & 485662306a36Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) { 485762306a36Sopenharmony_ci pr_cont("%sTask Set Full", i ? "," : ""); 485862306a36Sopenharmony_ci i++; 485962306a36Sopenharmony_ci } 486062306a36Sopenharmony_ci 486162306a36Sopenharmony_ci iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); 486262306a36Sopenharmony_ci if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) { 486362306a36Sopenharmony_ci pr_cont("%sNCQ", i ? "," : ""); 486462306a36Sopenharmony_ci i++; 486562306a36Sopenharmony_ci } 486662306a36Sopenharmony_ci 486762306a36Sopenharmony_ci pr_cont(")\n"); 486862306a36Sopenharmony_ci} 486962306a36Sopenharmony_ci 487062306a36Sopenharmony_ci/** 487162306a36Sopenharmony_ci * mpt3sas_base_update_missing_delay - change the missing delay timers 487262306a36Sopenharmony_ci * @ioc: per adapter object 487362306a36Sopenharmony_ci * @device_missing_delay: amount of time till device is reported missing 487462306a36Sopenharmony_ci * @io_missing_delay: interval IO is returned when there is a missing device 487562306a36Sopenharmony_ci * 487662306a36Sopenharmony_ci * Passed on the command line, this function will modify the device missing 487762306a36Sopenharmony_ci * delay, as well as the io missing delay. This should be called at driver 487862306a36Sopenharmony_ci * load time. 487962306a36Sopenharmony_ci */ 488062306a36Sopenharmony_civoid 488162306a36Sopenharmony_cimpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc, 488262306a36Sopenharmony_ci u16 device_missing_delay, u8 io_missing_delay) 488362306a36Sopenharmony_ci{ 488462306a36Sopenharmony_ci u16 dmd, dmd_new, dmd_orignal; 488562306a36Sopenharmony_ci u8 io_missing_delay_original; 488662306a36Sopenharmony_ci u16 sz; 488762306a36Sopenharmony_ci Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; 488862306a36Sopenharmony_ci Mpi2ConfigReply_t mpi_reply; 488962306a36Sopenharmony_ci u8 num_phys = 0; 489062306a36Sopenharmony_ci u16 ioc_status; 489162306a36Sopenharmony_ci 489262306a36Sopenharmony_ci mpt3sas_config_get_number_hba_phys(ioc, &num_phys); 489362306a36Sopenharmony_ci if (!num_phys) 489462306a36Sopenharmony_ci return; 489562306a36Sopenharmony_ci 489662306a36Sopenharmony_ci sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (num_phys * 489762306a36Sopenharmony_ci sizeof(Mpi2SasIOUnit1PhyData_t)); 489862306a36Sopenharmony_ci sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); 489962306a36Sopenharmony_ci if (!sas_iounit_pg1) { 490062306a36Sopenharmony_ci ioc_err(ioc, "failure at %s:%d/%s()!\n", 490162306a36Sopenharmony_ci __FILE__, __LINE__, __func__); 490262306a36Sopenharmony_ci goto out; 490362306a36Sopenharmony_ci } 490462306a36Sopenharmony_ci if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, 490562306a36Sopenharmony_ci sas_iounit_pg1, sz))) { 490662306a36Sopenharmony_ci ioc_err(ioc, "failure at %s:%d/%s()!\n", 490762306a36Sopenharmony_ci __FILE__, __LINE__, __func__); 490862306a36Sopenharmony_ci goto out; 490962306a36Sopenharmony_ci } 491062306a36Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & 491162306a36Sopenharmony_ci MPI2_IOCSTATUS_MASK; 491262306a36Sopenharmony_ci if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { 491362306a36Sopenharmony_ci ioc_err(ioc, "failure at %s:%d/%s()!\n", 491462306a36Sopenharmony_ci __FILE__, __LINE__, __func__); 491562306a36Sopenharmony_ci goto out; 491662306a36Sopenharmony_ci } 491762306a36Sopenharmony_ci 491862306a36Sopenharmony_ci /* device missing delay */ 491962306a36Sopenharmony_ci dmd = sas_iounit_pg1->ReportDeviceMissingDelay; 492062306a36Sopenharmony_ci if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) 492162306a36Sopenharmony_ci dmd = (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; 492262306a36Sopenharmony_ci else 492362306a36Sopenharmony_ci dmd = dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; 492462306a36Sopenharmony_ci dmd_orignal = dmd; 492562306a36Sopenharmony_ci if (device_missing_delay > 0x7F) { 492662306a36Sopenharmony_ci dmd = (device_missing_delay > 0x7F0) ? 0x7F0 : 492762306a36Sopenharmony_ci device_missing_delay; 492862306a36Sopenharmony_ci dmd = dmd / 16; 492962306a36Sopenharmony_ci dmd |= MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16; 493062306a36Sopenharmony_ci } else 493162306a36Sopenharmony_ci dmd = device_missing_delay; 493262306a36Sopenharmony_ci sas_iounit_pg1->ReportDeviceMissingDelay = dmd; 493362306a36Sopenharmony_ci 493462306a36Sopenharmony_ci /* io missing delay */ 493562306a36Sopenharmony_ci io_missing_delay_original = sas_iounit_pg1->IODeviceMissingDelay; 493662306a36Sopenharmony_ci sas_iounit_pg1->IODeviceMissingDelay = io_missing_delay; 493762306a36Sopenharmony_ci 493862306a36Sopenharmony_ci if (!mpt3sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, 493962306a36Sopenharmony_ci sz)) { 494062306a36Sopenharmony_ci if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) 494162306a36Sopenharmony_ci dmd_new = (dmd & 494262306a36Sopenharmony_ci MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; 494362306a36Sopenharmony_ci else 494462306a36Sopenharmony_ci dmd_new = 494562306a36Sopenharmony_ci dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; 494662306a36Sopenharmony_ci ioc_info(ioc, "device_missing_delay: old(%d), new(%d)\n", 494762306a36Sopenharmony_ci dmd_orignal, dmd_new); 494862306a36Sopenharmony_ci ioc_info(ioc, "ioc_missing_delay: old(%d), new(%d)\n", 494962306a36Sopenharmony_ci io_missing_delay_original, 495062306a36Sopenharmony_ci io_missing_delay); 495162306a36Sopenharmony_ci ioc->device_missing_delay = dmd_new; 495262306a36Sopenharmony_ci ioc->io_missing_delay = io_missing_delay; 495362306a36Sopenharmony_ci } 495462306a36Sopenharmony_ci 495562306a36Sopenharmony_ciout: 495662306a36Sopenharmony_ci kfree(sas_iounit_pg1); 495762306a36Sopenharmony_ci} 495862306a36Sopenharmony_ci 495962306a36Sopenharmony_ci/** 496062306a36Sopenharmony_ci * _base_update_ioc_page1_inlinewith_perf_mode - Update IOC Page1 fields 496162306a36Sopenharmony_ci * according to performance mode. 496262306a36Sopenharmony_ci * @ioc : per adapter object 496362306a36Sopenharmony_ci * 496462306a36Sopenharmony_ci * Return: zero on success; otherwise return EAGAIN error code asking the 496562306a36Sopenharmony_ci * caller to retry. 496662306a36Sopenharmony_ci */ 496762306a36Sopenharmony_cistatic int 496862306a36Sopenharmony_ci_base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc) 496962306a36Sopenharmony_ci{ 497062306a36Sopenharmony_ci Mpi2IOCPage1_t ioc_pg1; 497162306a36Sopenharmony_ci Mpi2ConfigReply_t mpi_reply; 497262306a36Sopenharmony_ci int rc; 497362306a36Sopenharmony_ci 497462306a36Sopenharmony_ci rc = mpt3sas_config_get_ioc_pg1(ioc, &mpi_reply, &ioc->ioc_pg1_copy); 497562306a36Sopenharmony_ci if (rc) 497662306a36Sopenharmony_ci return rc; 497762306a36Sopenharmony_ci memcpy(&ioc_pg1, &ioc->ioc_pg1_copy, sizeof(Mpi2IOCPage1_t)); 497862306a36Sopenharmony_ci 497962306a36Sopenharmony_ci switch (perf_mode) { 498062306a36Sopenharmony_ci case MPT_PERF_MODE_DEFAULT: 498162306a36Sopenharmony_ci case MPT_PERF_MODE_BALANCED: 498262306a36Sopenharmony_ci if (ioc->high_iops_queues) { 498362306a36Sopenharmony_ci ioc_info(ioc, 498462306a36Sopenharmony_ci "Enable interrupt coalescing only for first\t" 498562306a36Sopenharmony_ci "%d reply queues\n", 498662306a36Sopenharmony_ci MPT3SAS_HIGH_IOPS_REPLY_QUEUES); 498762306a36Sopenharmony_ci /* 498862306a36Sopenharmony_ci * If 31st bit is zero then interrupt coalescing is 498962306a36Sopenharmony_ci * enabled for all reply descriptor post queues. 499062306a36Sopenharmony_ci * If 31st bit is set to one then user can 499162306a36Sopenharmony_ci * enable/disable interrupt coalescing on per reply 499262306a36Sopenharmony_ci * descriptor post queue group(8) basis. So to enable 499362306a36Sopenharmony_ci * interrupt coalescing only on first reply descriptor 499462306a36Sopenharmony_ci * post queue group 31st bit and zero th bit is enabled. 499562306a36Sopenharmony_ci */ 499662306a36Sopenharmony_ci ioc_pg1.ProductSpecific = cpu_to_le32(0x80000000 | 499762306a36Sopenharmony_ci ((1 << MPT3SAS_HIGH_IOPS_REPLY_QUEUES/8) - 1)); 499862306a36Sopenharmony_ci rc = mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1); 499962306a36Sopenharmony_ci if (rc) 500062306a36Sopenharmony_ci return rc; 500162306a36Sopenharmony_ci ioc_info(ioc, "performance mode: balanced\n"); 500262306a36Sopenharmony_ci return 0; 500362306a36Sopenharmony_ci } 500462306a36Sopenharmony_ci fallthrough; 500562306a36Sopenharmony_ci case MPT_PERF_MODE_LATENCY: 500662306a36Sopenharmony_ci /* 500762306a36Sopenharmony_ci * Enable interrupt coalescing on all reply queues 500862306a36Sopenharmony_ci * with timeout value 0xA 500962306a36Sopenharmony_ci */ 501062306a36Sopenharmony_ci ioc_pg1.CoalescingTimeout = cpu_to_le32(0xa); 501162306a36Sopenharmony_ci ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING); 501262306a36Sopenharmony_ci ioc_pg1.ProductSpecific = 0; 501362306a36Sopenharmony_ci rc = mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1); 501462306a36Sopenharmony_ci if (rc) 501562306a36Sopenharmony_ci return rc; 501662306a36Sopenharmony_ci ioc_info(ioc, "performance mode: latency\n"); 501762306a36Sopenharmony_ci break; 501862306a36Sopenharmony_ci case MPT_PERF_MODE_IOPS: 501962306a36Sopenharmony_ci /* 502062306a36Sopenharmony_ci * Enable interrupt coalescing on all reply queues. 502162306a36Sopenharmony_ci */ 502262306a36Sopenharmony_ci ioc_info(ioc, 502362306a36Sopenharmony_ci "performance mode: iops with coalescing timeout: 0x%x\n", 502462306a36Sopenharmony_ci le32_to_cpu(ioc_pg1.CoalescingTimeout)); 502562306a36Sopenharmony_ci ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING); 502662306a36Sopenharmony_ci ioc_pg1.ProductSpecific = 0; 502762306a36Sopenharmony_ci rc = mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1); 502862306a36Sopenharmony_ci if (rc) 502962306a36Sopenharmony_ci return rc; 503062306a36Sopenharmony_ci break; 503162306a36Sopenharmony_ci } 503262306a36Sopenharmony_ci return 0; 503362306a36Sopenharmony_ci} 503462306a36Sopenharmony_ci 503562306a36Sopenharmony_ci/** 503662306a36Sopenharmony_ci * _base_get_event_diag_triggers - get event diag trigger values from 503762306a36Sopenharmony_ci * persistent pages 503862306a36Sopenharmony_ci * @ioc : per adapter object 503962306a36Sopenharmony_ci * 504062306a36Sopenharmony_ci * Return: nothing. 504162306a36Sopenharmony_ci */ 504262306a36Sopenharmony_cistatic int 504362306a36Sopenharmony_ci_base_get_event_diag_triggers(struct MPT3SAS_ADAPTER *ioc) 504462306a36Sopenharmony_ci{ 504562306a36Sopenharmony_ci Mpi26DriverTriggerPage2_t trigger_pg2; 504662306a36Sopenharmony_ci struct SL_WH_EVENT_TRIGGER_T *event_tg; 504762306a36Sopenharmony_ci MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY *mpi_event_tg; 504862306a36Sopenharmony_ci Mpi2ConfigReply_t mpi_reply; 504962306a36Sopenharmony_ci int r = 0, i = 0; 505062306a36Sopenharmony_ci u16 count = 0; 505162306a36Sopenharmony_ci u16 ioc_status; 505262306a36Sopenharmony_ci 505362306a36Sopenharmony_ci r = mpt3sas_config_get_driver_trigger_pg2(ioc, &mpi_reply, 505462306a36Sopenharmony_ci &trigger_pg2); 505562306a36Sopenharmony_ci if (r) 505662306a36Sopenharmony_ci return r; 505762306a36Sopenharmony_ci 505862306a36Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & 505962306a36Sopenharmony_ci MPI2_IOCSTATUS_MASK; 506062306a36Sopenharmony_ci if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { 506162306a36Sopenharmony_ci dinitprintk(ioc, 506262306a36Sopenharmony_ci ioc_err(ioc, 506362306a36Sopenharmony_ci "%s: Failed to get trigger pg2, ioc_status(0x%04x)\n", 506462306a36Sopenharmony_ci __func__, ioc_status)); 506562306a36Sopenharmony_ci return 0; 506662306a36Sopenharmony_ci } 506762306a36Sopenharmony_ci 506862306a36Sopenharmony_ci if (le16_to_cpu(trigger_pg2.NumMPIEventTrigger)) { 506962306a36Sopenharmony_ci count = le16_to_cpu(trigger_pg2.NumMPIEventTrigger); 507062306a36Sopenharmony_ci count = min_t(u16, NUM_VALID_ENTRIES, count); 507162306a36Sopenharmony_ci ioc->diag_trigger_event.ValidEntries = count; 507262306a36Sopenharmony_ci 507362306a36Sopenharmony_ci event_tg = &ioc->diag_trigger_event.EventTriggerEntry[0]; 507462306a36Sopenharmony_ci mpi_event_tg = &trigger_pg2.MPIEventTriggers[0]; 507562306a36Sopenharmony_ci for (i = 0; i < count; i++) { 507662306a36Sopenharmony_ci event_tg->EventValue = le16_to_cpu( 507762306a36Sopenharmony_ci mpi_event_tg->MPIEventCode); 507862306a36Sopenharmony_ci event_tg->LogEntryQualifier = le16_to_cpu( 507962306a36Sopenharmony_ci mpi_event_tg->MPIEventCodeSpecific); 508062306a36Sopenharmony_ci event_tg++; 508162306a36Sopenharmony_ci mpi_event_tg++; 508262306a36Sopenharmony_ci } 508362306a36Sopenharmony_ci } 508462306a36Sopenharmony_ci return 0; 508562306a36Sopenharmony_ci} 508662306a36Sopenharmony_ci 508762306a36Sopenharmony_ci/** 508862306a36Sopenharmony_ci * _base_get_scsi_diag_triggers - get scsi diag trigger values from 508962306a36Sopenharmony_ci * persistent pages 509062306a36Sopenharmony_ci * @ioc : per adapter object 509162306a36Sopenharmony_ci * 509262306a36Sopenharmony_ci * Return: 0 on success; otherwise return failure status. 509362306a36Sopenharmony_ci */ 509462306a36Sopenharmony_cistatic int 509562306a36Sopenharmony_ci_base_get_scsi_diag_triggers(struct MPT3SAS_ADAPTER *ioc) 509662306a36Sopenharmony_ci{ 509762306a36Sopenharmony_ci Mpi26DriverTriggerPage3_t trigger_pg3; 509862306a36Sopenharmony_ci struct SL_WH_SCSI_TRIGGER_T *scsi_tg; 509962306a36Sopenharmony_ci MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY *mpi_scsi_tg; 510062306a36Sopenharmony_ci Mpi2ConfigReply_t mpi_reply; 510162306a36Sopenharmony_ci int r = 0, i = 0; 510262306a36Sopenharmony_ci u16 count = 0; 510362306a36Sopenharmony_ci u16 ioc_status; 510462306a36Sopenharmony_ci 510562306a36Sopenharmony_ci r = mpt3sas_config_get_driver_trigger_pg3(ioc, &mpi_reply, 510662306a36Sopenharmony_ci &trigger_pg3); 510762306a36Sopenharmony_ci if (r) 510862306a36Sopenharmony_ci return r; 510962306a36Sopenharmony_ci 511062306a36Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & 511162306a36Sopenharmony_ci MPI2_IOCSTATUS_MASK; 511262306a36Sopenharmony_ci if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { 511362306a36Sopenharmony_ci dinitprintk(ioc, 511462306a36Sopenharmony_ci ioc_err(ioc, 511562306a36Sopenharmony_ci "%s: Failed to get trigger pg3, ioc_status(0x%04x)\n", 511662306a36Sopenharmony_ci __func__, ioc_status)); 511762306a36Sopenharmony_ci return 0; 511862306a36Sopenharmony_ci } 511962306a36Sopenharmony_ci 512062306a36Sopenharmony_ci if (le16_to_cpu(trigger_pg3.NumSCSISenseTrigger)) { 512162306a36Sopenharmony_ci count = le16_to_cpu(trigger_pg3.NumSCSISenseTrigger); 512262306a36Sopenharmony_ci count = min_t(u16, NUM_VALID_ENTRIES, count); 512362306a36Sopenharmony_ci ioc->diag_trigger_scsi.ValidEntries = count; 512462306a36Sopenharmony_ci 512562306a36Sopenharmony_ci scsi_tg = &ioc->diag_trigger_scsi.SCSITriggerEntry[0]; 512662306a36Sopenharmony_ci mpi_scsi_tg = &trigger_pg3.SCSISenseTriggers[0]; 512762306a36Sopenharmony_ci for (i = 0; i < count; i++) { 512862306a36Sopenharmony_ci scsi_tg->ASCQ = mpi_scsi_tg->ASCQ; 512962306a36Sopenharmony_ci scsi_tg->ASC = mpi_scsi_tg->ASC; 513062306a36Sopenharmony_ci scsi_tg->SenseKey = mpi_scsi_tg->SenseKey; 513162306a36Sopenharmony_ci 513262306a36Sopenharmony_ci scsi_tg++; 513362306a36Sopenharmony_ci mpi_scsi_tg++; 513462306a36Sopenharmony_ci } 513562306a36Sopenharmony_ci } 513662306a36Sopenharmony_ci return 0; 513762306a36Sopenharmony_ci} 513862306a36Sopenharmony_ci 513962306a36Sopenharmony_ci/** 514062306a36Sopenharmony_ci * _base_get_mpi_diag_triggers - get mpi diag trigger values from 514162306a36Sopenharmony_ci * persistent pages 514262306a36Sopenharmony_ci * @ioc : per adapter object 514362306a36Sopenharmony_ci * 514462306a36Sopenharmony_ci * Return: 0 on success; otherwise return failure status. 514562306a36Sopenharmony_ci */ 514662306a36Sopenharmony_cistatic int 514762306a36Sopenharmony_ci_base_get_mpi_diag_triggers(struct MPT3SAS_ADAPTER *ioc) 514862306a36Sopenharmony_ci{ 514962306a36Sopenharmony_ci Mpi26DriverTriggerPage4_t trigger_pg4; 515062306a36Sopenharmony_ci struct SL_WH_MPI_TRIGGER_T *status_tg; 515162306a36Sopenharmony_ci MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY *mpi_status_tg; 515262306a36Sopenharmony_ci Mpi2ConfigReply_t mpi_reply; 515362306a36Sopenharmony_ci int r = 0, i = 0; 515462306a36Sopenharmony_ci u16 count = 0; 515562306a36Sopenharmony_ci u16 ioc_status; 515662306a36Sopenharmony_ci 515762306a36Sopenharmony_ci r = mpt3sas_config_get_driver_trigger_pg4(ioc, &mpi_reply, 515862306a36Sopenharmony_ci &trigger_pg4); 515962306a36Sopenharmony_ci if (r) 516062306a36Sopenharmony_ci return r; 516162306a36Sopenharmony_ci 516262306a36Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & 516362306a36Sopenharmony_ci MPI2_IOCSTATUS_MASK; 516462306a36Sopenharmony_ci if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { 516562306a36Sopenharmony_ci dinitprintk(ioc, 516662306a36Sopenharmony_ci ioc_err(ioc, 516762306a36Sopenharmony_ci "%s: Failed to get trigger pg4, ioc_status(0x%04x)\n", 516862306a36Sopenharmony_ci __func__, ioc_status)); 516962306a36Sopenharmony_ci return 0; 517062306a36Sopenharmony_ci } 517162306a36Sopenharmony_ci 517262306a36Sopenharmony_ci if (le16_to_cpu(trigger_pg4.NumIOCStatusLogInfoTrigger)) { 517362306a36Sopenharmony_ci count = le16_to_cpu(trigger_pg4.NumIOCStatusLogInfoTrigger); 517462306a36Sopenharmony_ci count = min_t(u16, NUM_VALID_ENTRIES, count); 517562306a36Sopenharmony_ci ioc->diag_trigger_mpi.ValidEntries = count; 517662306a36Sopenharmony_ci 517762306a36Sopenharmony_ci status_tg = &ioc->diag_trigger_mpi.MPITriggerEntry[0]; 517862306a36Sopenharmony_ci mpi_status_tg = &trigger_pg4.IOCStatusLoginfoTriggers[0]; 517962306a36Sopenharmony_ci 518062306a36Sopenharmony_ci for (i = 0; i < count; i++) { 518162306a36Sopenharmony_ci status_tg->IOCStatus = le16_to_cpu( 518262306a36Sopenharmony_ci mpi_status_tg->IOCStatus); 518362306a36Sopenharmony_ci status_tg->IocLogInfo = le32_to_cpu( 518462306a36Sopenharmony_ci mpi_status_tg->LogInfo); 518562306a36Sopenharmony_ci 518662306a36Sopenharmony_ci status_tg++; 518762306a36Sopenharmony_ci mpi_status_tg++; 518862306a36Sopenharmony_ci } 518962306a36Sopenharmony_ci } 519062306a36Sopenharmony_ci return 0; 519162306a36Sopenharmony_ci} 519262306a36Sopenharmony_ci 519362306a36Sopenharmony_ci/** 519462306a36Sopenharmony_ci * _base_get_master_diag_triggers - get master diag trigger values from 519562306a36Sopenharmony_ci * persistent pages 519662306a36Sopenharmony_ci * @ioc : per adapter object 519762306a36Sopenharmony_ci * 519862306a36Sopenharmony_ci * Return: nothing. 519962306a36Sopenharmony_ci */ 520062306a36Sopenharmony_cistatic int 520162306a36Sopenharmony_ci_base_get_master_diag_triggers(struct MPT3SAS_ADAPTER *ioc) 520262306a36Sopenharmony_ci{ 520362306a36Sopenharmony_ci Mpi26DriverTriggerPage1_t trigger_pg1; 520462306a36Sopenharmony_ci Mpi2ConfigReply_t mpi_reply; 520562306a36Sopenharmony_ci int r; 520662306a36Sopenharmony_ci u16 ioc_status; 520762306a36Sopenharmony_ci 520862306a36Sopenharmony_ci r = mpt3sas_config_get_driver_trigger_pg1(ioc, &mpi_reply, 520962306a36Sopenharmony_ci &trigger_pg1); 521062306a36Sopenharmony_ci if (r) 521162306a36Sopenharmony_ci return r; 521262306a36Sopenharmony_ci 521362306a36Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & 521462306a36Sopenharmony_ci MPI2_IOCSTATUS_MASK; 521562306a36Sopenharmony_ci if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { 521662306a36Sopenharmony_ci dinitprintk(ioc, 521762306a36Sopenharmony_ci ioc_err(ioc, 521862306a36Sopenharmony_ci "%s: Failed to get trigger pg1, ioc_status(0x%04x)\n", 521962306a36Sopenharmony_ci __func__, ioc_status)); 522062306a36Sopenharmony_ci return 0; 522162306a36Sopenharmony_ci } 522262306a36Sopenharmony_ci 522362306a36Sopenharmony_ci if (le16_to_cpu(trigger_pg1.NumMasterTrigger)) 522462306a36Sopenharmony_ci ioc->diag_trigger_master.MasterData |= 522562306a36Sopenharmony_ci le32_to_cpu( 522662306a36Sopenharmony_ci trigger_pg1.MasterTriggers[0].MasterTriggerFlags); 522762306a36Sopenharmony_ci return 0; 522862306a36Sopenharmony_ci} 522962306a36Sopenharmony_ci 523062306a36Sopenharmony_ci/** 523162306a36Sopenharmony_ci * _base_check_for_trigger_pages_support - checks whether HBA FW supports 523262306a36Sopenharmony_ci * driver trigger pages or not 523362306a36Sopenharmony_ci * @ioc : per adapter object 523462306a36Sopenharmony_ci * @trigger_flags : address where trigger page0's TriggerFlags value is copied 523562306a36Sopenharmony_ci * 523662306a36Sopenharmony_ci * Return: trigger flags mask if HBA FW supports driver trigger pages; 523762306a36Sopenharmony_ci * otherwise returns %-EFAULT if driver trigger pages are not supported by FW or 523862306a36Sopenharmony_ci * return EAGAIN if diag reset occurred due to FW fault and asking the 523962306a36Sopenharmony_ci * caller to retry the command. 524062306a36Sopenharmony_ci * 524162306a36Sopenharmony_ci */ 524262306a36Sopenharmony_cistatic int 524362306a36Sopenharmony_ci_base_check_for_trigger_pages_support(struct MPT3SAS_ADAPTER *ioc, u32 *trigger_flags) 524462306a36Sopenharmony_ci{ 524562306a36Sopenharmony_ci Mpi26DriverTriggerPage0_t trigger_pg0; 524662306a36Sopenharmony_ci int r = 0; 524762306a36Sopenharmony_ci Mpi2ConfigReply_t mpi_reply; 524862306a36Sopenharmony_ci u16 ioc_status; 524962306a36Sopenharmony_ci 525062306a36Sopenharmony_ci r = mpt3sas_config_get_driver_trigger_pg0(ioc, &mpi_reply, 525162306a36Sopenharmony_ci &trigger_pg0); 525262306a36Sopenharmony_ci if (r) 525362306a36Sopenharmony_ci return r; 525462306a36Sopenharmony_ci 525562306a36Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & 525662306a36Sopenharmony_ci MPI2_IOCSTATUS_MASK; 525762306a36Sopenharmony_ci if (ioc_status != MPI2_IOCSTATUS_SUCCESS) 525862306a36Sopenharmony_ci return -EFAULT; 525962306a36Sopenharmony_ci 526062306a36Sopenharmony_ci *trigger_flags = le16_to_cpu(trigger_pg0.TriggerFlags); 526162306a36Sopenharmony_ci return 0; 526262306a36Sopenharmony_ci} 526362306a36Sopenharmony_ci 526462306a36Sopenharmony_ci/** 526562306a36Sopenharmony_ci * _base_get_diag_triggers - Retrieve diag trigger values from 526662306a36Sopenharmony_ci * persistent pages. 526762306a36Sopenharmony_ci * @ioc : per adapter object 526862306a36Sopenharmony_ci * 526962306a36Sopenharmony_ci * Return: zero on success; otherwise return EAGAIN error codes 527062306a36Sopenharmony_ci * asking the caller to retry. 527162306a36Sopenharmony_ci */ 527262306a36Sopenharmony_cistatic int 527362306a36Sopenharmony_ci_base_get_diag_triggers(struct MPT3SAS_ADAPTER *ioc) 527462306a36Sopenharmony_ci{ 527562306a36Sopenharmony_ci int trigger_flags; 527662306a36Sopenharmony_ci int r; 527762306a36Sopenharmony_ci 527862306a36Sopenharmony_ci /* 527962306a36Sopenharmony_ci * Default setting of master trigger. 528062306a36Sopenharmony_ci */ 528162306a36Sopenharmony_ci ioc->diag_trigger_master.MasterData = 528262306a36Sopenharmony_ci (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET); 528362306a36Sopenharmony_ci 528462306a36Sopenharmony_ci r = _base_check_for_trigger_pages_support(ioc, &trigger_flags); 528562306a36Sopenharmony_ci if (r) { 528662306a36Sopenharmony_ci if (r == -EAGAIN) 528762306a36Sopenharmony_ci return r; 528862306a36Sopenharmony_ci /* 528962306a36Sopenharmony_ci * Don't go for error handling when FW doesn't support 529062306a36Sopenharmony_ci * driver trigger pages. 529162306a36Sopenharmony_ci */ 529262306a36Sopenharmony_ci return 0; 529362306a36Sopenharmony_ci } 529462306a36Sopenharmony_ci 529562306a36Sopenharmony_ci ioc->supports_trigger_pages = 1; 529662306a36Sopenharmony_ci 529762306a36Sopenharmony_ci /* 529862306a36Sopenharmony_ci * Retrieve master diag trigger values from driver trigger pg1 529962306a36Sopenharmony_ci * if master trigger bit enabled in TriggerFlags. 530062306a36Sopenharmony_ci */ 530162306a36Sopenharmony_ci if ((u16)trigger_flags & 530262306a36Sopenharmony_ci MPI26_DRIVER_TRIGGER0_FLAG_MASTER_TRIGGER_VALID) { 530362306a36Sopenharmony_ci r = _base_get_master_diag_triggers(ioc); 530462306a36Sopenharmony_ci if (r) 530562306a36Sopenharmony_ci return r; 530662306a36Sopenharmony_ci } 530762306a36Sopenharmony_ci 530862306a36Sopenharmony_ci /* 530962306a36Sopenharmony_ci * Retrieve event diag trigger values from driver trigger pg2 531062306a36Sopenharmony_ci * if event trigger bit enabled in TriggerFlags. 531162306a36Sopenharmony_ci */ 531262306a36Sopenharmony_ci if ((u16)trigger_flags & 531362306a36Sopenharmony_ci MPI26_DRIVER_TRIGGER0_FLAG_MPI_EVENT_TRIGGER_VALID) { 531462306a36Sopenharmony_ci r = _base_get_event_diag_triggers(ioc); 531562306a36Sopenharmony_ci if (r) 531662306a36Sopenharmony_ci return r; 531762306a36Sopenharmony_ci } 531862306a36Sopenharmony_ci 531962306a36Sopenharmony_ci /* 532062306a36Sopenharmony_ci * Retrieve scsi diag trigger values from driver trigger pg3 532162306a36Sopenharmony_ci * if scsi trigger bit enabled in TriggerFlags. 532262306a36Sopenharmony_ci */ 532362306a36Sopenharmony_ci if ((u16)trigger_flags & 532462306a36Sopenharmony_ci MPI26_DRIVER_TRIGGER0_FLAG_SCSI_SENSE_TRIGGER_VALID) { 532562306a36Sopenharmony_ci r = _base_get_scsi_diag_triggers(ioc); 532662306a36Sopenharmony_ci if (r) 532762306a36Sopenharmony_ci return r; 532862306a36Sopenharmony_ci } 532962306a36Sopenharmony_ci /* 533062306a36Sopenharmony_ci * Retrieve mpi error diag trigger values from driver trigger pg4 533162306a36Sopenharmony_ci * if loginfo trigger bit enabled in TriggerFlags. 533262306a36Sopenharmony_ci */ 533362306a36Sopenharmony_ci if ((u16)trigger_flags & 533462306a36Sopenharmony_ci MPI26_DRIVER_TRIGGER0_FLAG_LOGINFO_TRIGGER_VALID) { 533562306a36Sopenharmony_ci r = _base_get_mpi_diag_triggers(ioc); 533662306a36Sopenharmony_ci if (r) 533762306a36Sopenharmony_ci return r; 533862306a36Sopenharmony_ci } 533962306a36Sopenharmony_ci return 0; 534062306a36Sopenharmony_ci} 534162306a36Sopenharmony_ci 534262306a36Sopenharmony_ci/** 534362306a36Sopenharmony_ci * _base_update_diag_trigger_pages - Update the driver trigger pages after 534462306a36Sopenharmony_ci * online FW update, in case updated FW supports driver 534562306a36Sopenharmony_ci * trigger pages. 534662306a36Sopenharmony_ci * @ioc : per adapter object 534762306a36Sopenharmony_ci * 534862306a36Sopenharmony_ci * Return: nothing. 534962306a36Sopenharmony_ci */ 535062306a36Sopenharmony_cistatic void 535162306a36Sopenharmony_ci_base_update_diag_trigger_pages(struct MPT3SAS_ADAPTER *ioc) 535262306a36Sopenharmony_ci{ 535362306a36Sopenharmony_ci 535462306a36Sopenharmony_ci if (ioc->diag_trigger_master.MasterData) 535562306a36Sopenharmony_ci mpt3sas_config_update_driver_trigger_pg1(ioc, 535662306a36Sopenharmony_ci &ioc->diag_trigger_master, 1); 535762306a36Sopenharmony_ci 535862306a36Sopenharmony_ci if (ioc->diag_trigger_event.ValidEntries) 535962306a36Sopenharmony_ci mpt3sas_config_update_driver_trigger_pg2(ioc, 536062306a36Sopenharmony_ci &ioc->diag_trigger_event, 1); 536162306a36Sopenharmony_ci 536262306a36Sopenharmony_ci if (ioc->diag_trigger_scsi.ValidEntries) 536362306a36Sopenharmony_ci mpt3sas_config_update_driver_trigger_pg3(ioc, 536462306a36Sopenharmony_ci &ioc->diag_trigger_scsi, 1); 536562306a36Sopenharmony_ci 536662306a36Sopenharmony_ci if (ioc->diag_trigger_mpi.ValidEntries) 536762306a36Sopenharmony_ci mpt3sas_config_update_driver_trigger_pg4(ioc, 536862306a36Sopenharmony_ci &ioc->diag_trigger_mpi, 1); 536962306a36Sopenharmony_ci} 537062306a36Sopenharmony_ci 537162306a36Sopenharmony_ci/** 537262306a36Sopenharmony_ci * _base_assign_fw_reported_qd - Get FW reported QD for SAS/SATA devices. 537362306a36Sopenharmony_ci * - On failure set default QD values. 537462306a36Sopenharmony_ci * @ioc : per adapter object 537562306a36Sopenharmony_ci * 537662306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 537762306a36Sopenharmony_ci * 537862306a36Sopenharmony_ci */ 537962306a36Sopenharmony_cistatic int _base_assign_fw_reported_qd(struct MPT3SAS_ADAPTER *ioc) 538062306a36Sopenharmony_ci{ 538162306a36Sopenharmony_ci Mpi2ConfigReply_t mpi_reply; 538262306a36Sopenharmony_ci Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; 538362306a36Sopenharmony_ci Mpi26PCIeIOUnitPage1_t pcie_iounit_pg1; 538462306a36Sopenharmony_ci u16 depth; 538562306a36Sopenharmony_ci int sz; 538662306a36Sopenharmony_ci int rc = 0; 538762306a36Sopenharmony_ci 538862306a36Sopenharmony_ci ioc->max_wideport_qd = MPT3SAS_SAS_QUEUE_DEPTH; 538962306a36Sopenharmony_ci ioc->max_narrowport_qd = MPT3SAS_SAS_QUEUE_DEPTH; 539062306a36Sopenharmony_ci ioc->max_sata_qd = MPT3SAS_SATA_QUEUE_DEPTH; 539162306a36Sopenharmony_ci ioc->max_nvme_qd = MPT3SAS_NVME_QUEUE_DEPTH; 539262306a36Sopenharmony_ci if (!ioc->is_gen35_ioc) 539362306a36Sopenharmony_ci goto out; 539462306a36Sopenharmony_ci /* sas iounit page 1 */ 539562306a36Sopenharmony_ci sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData); 539662306a36Sopenharmony_ci sas_iounit_pg1 = kzalloc(sizeof(Mpi2SasIOUnitPage1_t), GFP_KERNEL); 539762306a36Sopenharmony_ci if (!sas_iounit_pg1) { 539862306a36Sopenharmony_ci pr_err("%s: failure at %s:%d/%s()!\n", 539962306a36Sopenharmony_ci ioc->name, __FILE__, __LINE__, __func__); 540062306a36Sopenharmony_ci return rc; 540162306a36Sopenharmony_ci } 540262306a36Sopenharmony_ci rc = mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, 540362306a36Sopenharmony_ci sas_iounit_pg1, sz); 540462306a36Sopenharmony_ci if (rc) { 540562306a36Sopenharmony_ci pr_err("%s: failure at %s:%d/%s()!\n", 540662306a36Sopenharmony_ci ioc->name, __FILE__, __LINE__, __func__); 540762306a36Sopenharmony_ci goto out; 540862306a36Sopenharmony_ci } 540962306a36Sopenharmony_ci 541062306a36Sopenharmony_ci depth = le16_to_cpu(sas_iounit_pg1->SASWideMaxQueueDepth); 541162306a36Sopenharmony_ci ioc->max_wideport_qd = (depth ? depth : MPT3SAS_SAS_QUEUE_DEPTH); 541262306a36Sopenharmony_ci 541362306a36Sopenharmony_ci depth = le16_to_cpu(sas_iounit_pg1->SASNarrowMaxQueueDepth); 541462306a36Sopenharmony_ci ioc->max_narrowport_qd = (depth ? depth : MPT3SAS_SAS_QUEUE_DEPTH); 541562306a36Sopenharmony_ci 541662306a36Sopenharmony_ci depth = sas_iounit_pg1->SATAMaxQDepth; 541762306a36Sopenharmony_ci ioc->max_sata_qd = (depth ? depth : MPT3SAS_SATA_QUEUE_DEPTH); 541862306a36Sopenharmony_ci 541962306a36Sopenharmony_ci /* pcie iounit page 1 */ 542062306a36Sopenharmony_ci rc = mpt3sas_config_get_pcie_iounit_pg1(ioc, &mpi_reply, 542162306a36Sopenharmony_ci &pcie_iounit_pg1, sizeof(Mpi26PCIeIOUnitPage1_t)); 542262306a36Sopenharmony_ci if (rc) { 542362306a36Sopenharmony_ci pr_err("%s: failure at %s:%d/%s()!\n", 542462306a36Sopenharmony_ci ioc->name, __FILE__, __LINE__, __func__); 542562306a36Sopenharmony_ci goto out; 542662306a36Sopenharmony_ci } 542762306a36Sopenharmony_ci ioc->max_nvme_qd = (le16_to_cpu(pcie_iounit_pg1.NVMeMaxQueueDepth)) ? 542862306a36Sopenharmony_ci (le16_to_cpu(pcie_iounit_pg1.NVMeMaxQueueDepth)) : 542962306a36Sopenharmony_ci MPT3SAS_NVME_QUEUE_DEPTH; 543062306a36Sopenharmony_ciout: 543162306a36Sopenharmony_ci dinitprintk(ioc, pr_err( 543262306a36Sopenharmony_ci "MaxWidePortQD: 0x%x MaxNarrowPortQD: 0x%x MaxSataQD: 0x%x MaxNvmeQD: 0x%x\n", 543362306a36Sopenharmony_ci ioc->max_wideport_qd, ioc->max_narrowport_qd, 543462306a36Sopenharmony_ci ioc->max_sata_qd, ioc->max_nvme_qd)); 543562306a36Sopenharmony_ci kfree(sas_iounit_pg1); 543662306a36Sopenharmony_ci return rc; 543762306a36Sopenharmony_ci} 543862306a36Sopenharmony_ci 543962306a36Sopenharmony_ci/** 544062306a36Sopenharmony_ci * mpt3sas_atto_validate_nvram - validate the ATTO nvram read from mfg pg1 544162306a36Sopenharmony_ci * 544262306a36Sopenharmony_ci * @ioc : per adapter object 544362306a36Sopenharmony_ci * @n : ptr to the ATTO nvram structure 544462306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 544562306a36Sopenharmony_ci */ 544662306a36Sopenharmony_cistatic int 544762306a36Sopenharmony_cimpt3sas_atto_validate_nvram(struct MPT3SAS_ADAPTER *ioc, 544862306a36Sopenharmony_ci struct ATTO_SAS_NVRAM *n) 544962306a36Sopenharmony_ci{ 545062306a36Sopenharmony_ci int r = -EINVAL; 545162306a36Sopenharmony_ci union ATTO_SAS_ADDRESS *s1; 545262306a36Sopenharmony_ci u32 len; 545362306a36Sopenharmony_ci u8 *pb; 545462306a36Sopenharmony_ci u8 ckSum; 545562306a36Sopenharmony_ci 545662306a36Sopenharmony_ci /* validate nvram checksum */ 545762306a36Sopenharmony_ci pb = (u8 *) n; 545862306a36Sopenharmony_ci ckSum = ATTO_SASNVR_CKSUM_SEED; 545962306a36Sopenharmony_ci len = sizeof(struct ATTO_SAS_NVRAM); 546062306a36Sopenharmony_ci 546162306a36Sopenharmony_ci while (len--) 546262306a36Sopenharmony_ci ckSum = ckSum + pb[len]; 546362306a36Sopenharmony_ci 546462306a36Sopenharmony_ci if (ckSum) { 546562306a36Sopenharmony_ci ioc_err(ioc, "Invalid ATTO NVRAM checksum\n"); 546662306a36Sopenharmony_ci return r; 546762306a36Sopenharmony_ci } 546862306a36Sopenharmony_ci 546962306a36Sopenharmony_ci s1 = (union ATTO_SAS_ADDRESS *) n->SasAddr; 547062306a36Sopenharmony_ci 547162306a36Sopenharmony_ci if (n->Signature[0] != 'E' 547262306a36Sopenharmony_ci || n->Signature[1] != 'S' 547362306a36Sopenharmony_ci || n->Signature[2] != 'A' 547462306a36Sopenharmony_ci || n->Signature[3] != 'S') 547562306a36Sopenharmony_ci ioc_err(ioc, "Invalid ATTO NVRAM signature\n"); 547662306a36Sopenharmony_ci else if (n->Version > ATTO_SASNVR_VERSION) 547762306a36Sopenharmony_ci ioc_info(ioc, "Invalid ATTO NVRAM version"); 547862306a36Sopenharmony_ci else if ((n->SasAddr[7] & (ATTO_SAS_ADDR_ALIGN - 1)) 547962306a36Sopenharmony_ci || s1->b[0] != 0x50 548062306a36Sopenharmony_ci || s1->b[1] != 0x01 548162306a36Sopenharmony_ci || s1->b[2] != 0x08 548262306a36Sopenharmony_ci || (s1->b[3] & 0xF0) != 0x60 548362306a36Sopenharmony_ci || ((s1->b[3] & 0x0F) | le32_to_cpu(s1->d[1])) == 0) { 548462306a36Sopenharmony_ci ioc_err(ioc, "Invalid ATTO SAS address\n"); 548562306a36Sopenharmony_ci } else 548662306a36Sopenharmony_ci r = 0; 548762306a36Sopenharmony_ci return r; 548862306a36Sopenharmony_ci} 548962306a36Sopenharmony_ci 549062306a36Sopenharmony_ci/** 549162306a36Sopenharmony_ci * mpt3sas_atto_get_sas_addr - get the ATTO SAS address from mfg page 1 549262306a36Sopenharmony_ci * 549362306a36Sopenharmony_ci * @ioc : per adapter object 549462306a36Sopenharmony_ci * @*sas_addr : return sas address 549562306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 549662306a36Sopenharmony_ci */ 549762306a36Sopenharmony_cistatic int 549862306a36Sopenharmony_cimpt3sas_atto_get_sas_addr(struct MPT3SAS_ADAPTER *ioc, union ATTO_SAS_ADDRESS *sas_addr) 549962306a36Sopenharmony_ci{ 550062306a36Sopenharmony_ci Mpi2ManufacturingPage1_t mfg_pg1; 550162306a36Sopenharmony_ci Mpi2ConfigReply_t mpi_reply; 550262306a36Sopenharmony_ci struct ATTO_SAS_NVRAM *nvram; 550362306a36Sopenharmony_ci int r; 550462306a36Sopenharmony_ci __be64 addr; 550562306a36Sopenharmony_ci 550662306a36Sopenharmony_ci r = mpt3sas_config_get_manufacturing_pg1(ioc, &mpi_reply, &mfg_pg1); 550762306a36Sopenharmony_ci if (r) { 550862306a36Sopenharmony_ci ioc_err(ioc, "Failed to read manufacturing page 1\n"); 550962306a36Sopenharmony_ci return r; 551062306a36Sopenharmony_ci } 551162306a36Sopenharmony_ci 551262306a36Sopenharmony_ci /* validate nvram */ 551362306a36Sopenharmony_ci nvram = (struct ATTO_SAS_NVRAM *) mfg_pg1.VPD; 551462306a36Sopenharmony_ci r = mpt3sas_atto_validate_nvram(ioc, nvram); 551562306a36Sopenharmony_ci if (r) 551662306a36Sopenharmony_ci return r; 551762306a36Sopenharmony_ci 551862306a36Sopenharmony_ci addr = *((__be64 *) nvram->SasAddr); 551962306a36Sopenharmony_ci sas_addr->q = cpu_to_le64(be64_to_cpu(addr)); 552062306a36Sopenharmony_ci return r; 552162306a36Sopenharmony_ci} 552262306a36Sopenharmony_ci 552362306a36Sopenharmony_ci/** 552462306a36Sopenharmony_ci * mpt3sas_atto_init - perform initializaion for ATTO branded 552562306a36Sopenharmony_ci * adapter. 552662306a36Sopenharmony_ci * @ioc : per adapter object 552762306a36Sopenharmony_ci *5 552862306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 552962306a36Sopenharmony_ci */ 553062306a36Sopenharmony_cistatic int 553162306a36Sopenharmony_cimpt3sas_atto_init(struct MPT3SAS_ADAPTER *ioc) 553262306a36Sopenharmony_ci{ 553362306a36Sopenharmony_ci int sz = 0; 553462306a36Sopenharmony_ci Mpi2BiosPage4_t *bios_pg4 = NULL; 553562306a36Sopenharmony_ci Mpi2ConfigReply_t mpi_reply; 553662306a36Sopenharmony_ci int r; 553762306a36Sopenharmony_ci int ix; 553862306a36Sopenharmony_ci union ATTO_SAS_ADDRESS sas_addr; 553962306a36Sopenharmony_ci union ATTO_SAS_ADDRESS temp; 554062306a36Sopenharmony_ci union ATTO_SAS_ADDRESS bias; 554162306a36Sopenharmony_ci 554262306a36Sopenharmony_ci r = mpt3sas_atto_get_sas_addr(ioc, &sas_addr); 554362306a36Sopenharmony_ci if (r) 554462306a36Sopenharmony_ci return r; 554562306a36Sopenharmony_ci 554662306a36Sopenharmony_ci /* get header first to get size */ 554762306a36Sopenharmony_ci r = mpt3sas_config_get_bios_pg4(ioc, &mpi_reply, NULL, 0); 554862306a36Sopenharmony_ci if (r) { 554962306a36Sopenharmony_ci ioc_err(ioc, "Failed to read ATTO bios page 4 header.\n"); 555062306a36Sopenharmony_ci return r; 555162306a36Sopenharmony_ci } 555262306a36Sopenharmony_ci 555362306a36Sopenharmony_ci sz = mpi_reply.Header.PageLength * sizeof(u32); 555462306a36Sopenharmony_ci bios_pg4 = kzalloc(sz, GFP_KERNEL); 555562306a36Sopenharmony_ci if (!bios_pg4) { 555662306a36Sopenharmony_ci ioc_err(ioc, "Failed to allocate memory for ATTO bios page.\n"); 555762306a36Sopenharmony_ci return -ENOMEM; 555862306a36Sopenharmony_ci } 555962306a36Sopenharmony_ci 556062306a36Sopenharmony_ci /* read bios page 4 */ 556162306a36Sopenharmony_ci r = mpt3sas_config_get_bios_pg4(ioc, &mpi_reply, bios_pg4, sz); 556262306a36Sopenharmony_ci if (r) { 556362306a36Sopenharmony_ci ioc_err(ioc, "Failed to read ATTO bios page 4\n"); 556462306a36Sopenharmony_ci goto out; 556562306a36Sopenharmony_ci } 556662306a36Sopenharmony_ci 556762306a36Sopenharmony_ci /* Update bios page 4 with the ATTO WWID */ 556862306a36Sopenharmony_ci bias.q = sas_addr.q; 556962306a36Sopenharmony_ci bias.b[7] += ATTO_SAS_ADDR_DEVNAME_BIAS; 557062306a36Sopenharmony_ci 557162306a36Sopenharmony_ci for (ix = 0; ix < bios_pg4->NumPhys; ix++) { 557262306a36Sopenharmony_ci temp.q = sas_addr.q; 557362306a36Sopenharmony_ci temp.b[7] += ix; 557462306a36Sopenharmony_ci bios_pg4->Phy[ix].ReassignmentWWID = temp.q; 557562306a36Sopenharmony_ci bios_pg4->Phy[ix].ReassignmentDeviceName = bias.q; 557662306a36Sopenharmony_ci } 557762306a36Sopenharmony_ci r = mpt3sas_config_set_bios_pg4(ioc, &mpi_reply, bios_pg4, sz); 557862306a36Sopenharmony_ci 557962306a36Sopenharmony_ciout: 558062306a36Sopenharmony_ci kfree(bios_pg4); 558162306a36Sopenharmony_ci return r; 558262306a36Sopenharmony_ci} 558362306a36Sopenharmony_ci 558462306a36Sopenharmony_ci/** 558562306a36Sopenharmony_ci * _base_static_config_pages - static start of day config pages 558662306a36Sopenharmony_ci * @ioc: per adapter object 558762306a36Sopenharmony_ci */ 558862306a36Sopenharmony_cistatic int 558962306a36Sopenharmony_ci_base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) 559062306a36Sopenharmony_ci{ 559162306a36Sopenharmony_ci Mpi2ConfigReply_t mpi_reply; 559262306a36Sopenharmony_ci u32 iounit_pg1_flags; 559362306a36Sopenharmony_ci int tg_flags = 0; 559462306a36Sopenharmony_ci int rc; 559562306a36Sopenharmony_ci ioc->nvme_abort_timeout = 30; 559662306a36Sopenharmony_ci 559762306a36Sopenharmony_ci rc = mpt3sas_config_get_manufacturing_pg0(ioc, &mpi_reply, 559862306a36Sopenharmony_ci &ioc->manu_pg0); 559962306a36Sopenharmony_ci if (rc) 560062306a36Sopenharmony_ci return rc; 560162306a36Sopenharmony_ci if (ioc->ir_firmware) { 560262306a36Sopenharmony_ci rc = mpt3sas_config_get_manufacturing_pg10(ioc, &mpi_reply, 560362306a36Sopenharmony_ci &ioc->manu_pg10); 560462306a36Sopenharmony_ci if (rc) 560562306a36Sopenharmony_ci return rc; 560662306a36Sopenharmony_ci } 560762306a36Sopenharmony_ci 560862306a36Sopenharmony_ci if (ioc->pdev->vendor == MPI2_MFGPAGE_VENDORID_ATTO) { 560962306a36Sopenharmony_ci rc = mpt3sas_atto_init(ioc); 561062306a36Sopenharmony_ci if (rc) 561162306a36Sopenharmony_ci return rc; 561262306a36Sopenharmony_ci } 561362306a36Sopenharmony_ci 561462306a36Sopenharmony_ci /* 561562306a36Sopenharmony_ci * Ensure correct T10 PI operation if vendor left EEDPTagMode 561662306a36Sopenharmony_ci * flag unset in NVDATA. 561762306a36Sopenharmony_ci */ 561862306a36Sopenharmony_ci rc = mpt3sas_config_get_manufacturing_pg11(ioc, &mpi_reply, 561962306a36Sopenharmony_ci &ioc->manu_pg11); 562062306a36Sopenharmony_ci if (rc) 562162306a36Sopenharmony_ci return rc; 562262306a36Sopenharmony_ci if (!ioc->is_gen35_ioc && ioc->manu_pg11.EEDPTagMode == 0) { 562362306a36Sopenharmony_ci pr_err("%s: overriding NVDATA EEDPTagMode setting\n", 562462306a36Sopenharmony_ci ioc->name); 562562306a36Sopenharmony_ci ioc->manu_pg11.EEDPTagMode &= ~0x3; 562662306a36Sopenharmony_ci ioc->manu_pg11.EEDPTagMode |= 0x1; 562762306a36Sopenharmony_ci mpt3sas_config_set_manufacturing_pg11(ioc, &mpi_reply, 562862306a36Sopenharmony_ci &ioc->manu_pg11); 562962306a36Sopenharmony_ci } 563062306a36Sopenharmony_ci if (ioc->manu_pg11.AddlFlags2 & NVME_TASK_MNGT_CUSTOM_MASK) 563162306a36Sopenharmony_ci ioc->tm_custom_handling = 1; 563262306a36Sopenharmony_ci else { 563362306a36Sopenharmony_ci ioc->tm_custom_handling = 0; 563462306a36Sopenharmony_ci if (ioc->manu_pg11.NVMeAbortTO < NVME_TASK_ABORT_MIN_TIMEOUT) 563562306a36Sopenharmony_ci ioc->nvme_abort_timeout = NVME_TASK_ABORT_MIN_TIMEOUT; 563662306a36Sopenharmony_ci else if (ioc->manu_pg11.NVMeAbortTO > 563762306a36Sopenharmony_ci NVME_TASK_ABORT_MAX_TIMEOUT) 563862306a36Sopenharmony_ci ioc->nvme_abort_timeout = NVME_TASK_ABORT_MAX_TIMEOUT; 563962306a36Sopenharmony_ci else 564062306a36Sopenharmony_ci ioc->nvme_abort_timeout = ioc->manu_pg11.NVMeAbortTO; 564162306a36Sopenharmony_ci } 564262306a36Sopenharmony_ci ioc->time_sync_interval = 564362306a36Sopenharmony_ci ioc->manu_pg11.TimeSyncInterval & MPT3SAS_TIMESYNC_MASK; 564462306a36Sopenharmony_ci if (ioc->time_sync_interval) { 564562306a36Sopenharmony_ci if (ioc->manu_pg11.TimeSyncInterval & MPT3SAS_TIMESYNC_UNIT_MASK) 564662306a36Sopenharmony_ci ioc->time_sync_interval = 564762306a36Sopenharmony_ci ioc->time_sync_interval * SECONDS_PER_HOUR; 564862306a36Sopenharmony_ci else 564962306a36Sopenharmony_ci ioc->time_sync_interval = 565062306a36Sopenharmony_ci ioc->time_sync_interval * SECONDS_PER_MIN; 565162306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, 565262306a36Sopenharmony_ci "Driver-FW TimeSync interval is %d seconds. ManuPg11 TimeSync Unit is in %s\n", 565362306a36Sopenharmony_ci ioc->time_sync_interval, (ioc->manu_pg11.TimeSyncInterval & 565462306a36Sopenharmony_ci MPT3SAS_TIMESYNC_UNIT_MASK) ? "Hour" : "Minute")); 565562306a36Sopenharmony_ci } else { 565662306a36Sopenharmony_ci if (ioc->is_gen35_ioc) 565762306a36Sopenharmony_ci ioc_warn(ioc, 565862306a36Sopenharmony_ci "TimeSync Interval in Manuf page-11 is not enabled. Periodic Time-Sync will be disabled\n"); 565962306a36Sopenharmony_ci } 566062306a36Sopenharmony_ci rc = _base_assign_fw_reported_qd(ioc); 566162306a36Sopenharmony_ci if (rc) 566262306a36Sopenharmony_ci return rc; 566362306a36Sopenharmony_ci 566462306a36Sopenharmony_ci /* 566562306a36Sopenharmony_ci * ATTO doesn't use bios page 2 and 3 for bios settings. 566662306a36Sopenharmony_ci */ 566762306a36Sopenharmony_ci if (ioc->pdev->vendor == MPI2_MFGPAGE_VENDORID_ATTO) 566862306a36Sopenharmony_ci ioc->bios_pg3.BiosVersion = 0; 566962306a36Sopenharmony_ci else { 567062306a36Sopenharmony_ci rc = mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2); 567162306a36Sopenharmony_ci if (rc) 567262306a36Sopenharmony_ci return rc; 567362306a36Sopenharmony_ci rc = mpt3sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3); 567462306a36Sopenharmony_ci if (rc) 567562306a36Sopenharmony_ci return rc; 567662306a36Sopenharmony_ci } 567762306a36Sopenharmony_ci 567862306a36Sopenharmony_ci rc = mpt3sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8); 567962306a36Sopenharmony_ci if (rc) 568062306a36Sopenharmony_ci return rc; 568162306a36Sopenharmony_ci rc = mpt3sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0); 568262306a36Sopenharmony_ci if (rc) 568362306a36Sopenharmony_ci return rc; 568462306a36Sopenharmony_ci rc = mpt3sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); 568562306a36Sopenharmony_ci if (rc) 568662306a36Sopenharmony_ci return rc; 568762306a36Sopenharmony_ci rc = mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8); 568862306a36Sopenharmony_ci if (rc) 568962306a36Sopenharmony_ci return rc; 569062306a36Sopenharmony_ci _base_display_ioc_capabilities(ioc); 569162306a36Sopenharmony_ci 569262306a36Sopenharmony_ci /* 569362306a36Sopenharmony_ci * Enable task_set_full handling in iounit_pg1 when the 569462306a36Sopenharmony_ci * facts capabilities indicate that its supported. 569562306a36Sopenharmony_ci */ 569662306a36Sopenharmony_ci iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); 569762306a36Sopenharmony_ci if ((ioc->facts.IOCCapabilities & 569862306a36Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING)) 569962306a36Sopenharmony_ci iounit_pg1_flags &= 570062306a36Sopenharmony_ci ~MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; 570162306a36Sopenharmony_ci else 570262306a36Sopenharmony_ci iounit_pg1_flags |= 570362306a36Sopenharmony_ci MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; 570462306a36Sopenharmony_ci ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags); 570562306a36Sopenharmony_ci rc = mpt3sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); 570662306a36Sopenharmony_ci if (rc) 570762306a36Sopenharmony_ci return rc; 570862306a36Sopenharmony_ci 570962306a36Sopenharmony_ci if (ioc->iounit_pg8.NumSensors) 571062306a36Sopenharmony_ci ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors; 571162306a36Sopenharmony_ci if (ioc->is_aero_ioc) { 571262306a36Sopenharmony_ci rc = _base_update_ioc_page1_inlinewith_perf_mode(ioc); 571362306a36Sopenharmony_ci if (rc) 571462306a36Sopenharmony_ci return rc; 571562306a36Sopenharmony_ci } 571662306a36Sopenharmony_ci if (ioc->is_gen35_ioc) { 571762306a36Sopenharmony_ci if (ioc->is_driver_loading) { 571862306a36Sopenharmony_ci rc = _base_get_diag_triggers(ioc); 571962306a36Sopenharmony_ci if (rc) 572062306a36Sopenharmony_ci return rc; 572162306a36Sopenharmony_ci } else { 572262306a36Sopenharmony_ci /* 572362306a36Sopenharmony_ci * In case of online HBA FW update operation, 572462306a36Sopenharmony_ci * check whether updated FW supports the driver trigger 572562306a36Sopenharmony_ci * pages or not. 572662306a36Sopenharmony_ci * - If previous FW has not supported driver trigger 572762306a36Sopenharmony_ci * pages and newer FW supports them then update these 572862306a36Sopenharmony_ci * pages with current diag trigger values. 572962306a36Sopenharmony_ci * - If previous FW has supported driver trigger pages 573062306a36Sopenharmony_ci * and new FW doesn't support them then disable 573162306a36Sopenharmony_ci * support_trigger_pages flag. 573262306a36Sopenharmony_ci */ 573362306a36Sopenharmony_ci _base_check_for_trigger_pages_support(ioc, &tg_flags); 573462306a36Sopenharmony_ci if (!ioc->supports_trigger_pages && tg_flags != -EFAULT) 573562306a36Sopenharmony_ci _base_update_diag_trigger_pages(ioc); 573662306a36Sopenharmony_ci else if (ioc->supports_trigger_pages && 573762306a36Sopenharmony_ci tg_flags == -EFAULT) 573862306a36Sopenharmony_ci ioc->supports_trigger_pages = 0; 573962306a36Sopenharmony_ci } 574062306a36Sopenharmony_ci } 574162306a36Sopenharmony_ci return 0; 574262306a36Sopenharmony_ci} 574362306a36Sopenharmony_ci 574462306a36Sopenharmony_ci/** 574562306a36Sopenharmony_ci * mpt3sas_free_enclosure_list - release memory 574662306a36Sopenharmony_ci * @ioc: per adapter object 574762306a36Sopenharmony_ci * 574862306a36Sopenharmony_ci * Free memory allocated during enclosure add. 574962306a36Sopenharmony_ci */ 575062306a36Sopenharmony_civoid 575162306a36Sopenharmony_cimpt3sas_free_enclosure_list(struct MPT3SAS_ADAPTER *ioc) 575262306a36Sopenharmony_ci{ 575362306a36Sopenharmony_ci struct _enclosure_node *enclosure_dev, *enclosure_dev_next; 575462306a36Sopenharmony_ci 575562306a36Sopenharmony_ci /* Free enclosure list */ 575662306a36Sopenharmony_ci list_for_each_entry_safe(enclosure_dev, 575762306a36Sopenharmony_ci enclosure_dev_next, &ioc->enclosure_list, list) { 575862306a36Sopenharmony_ci list_del(&enclosure_dev->list); 575962306a36Sopenharmony_ci kfree(enclosure_dev); 576062306a36Sopenharmony_ci } 576162306a36Sopenharmony_ci} 576262306a36Sopenharmony_ci 576362306a36Sopenharmony_ci/** 576462306a36Sopenharmony_ci * _base_release_memory_pools - release memory 576562306a36Sopenharmony_ci * @ioc: per adapter object 576662306a36Sopenharmony_ci * 576762306a36Sopenharmony_ci * Free memory allocated from _base_allocate_memory_pools. 576862306a36Sopenharmony_ci */ 576962306a36Sopenharmony_cistatic void 577062306a36Sopenharmony_ci_base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc) 577162306a36Sopenharmony_ci{ 577262306a36Sopenharmony_ci int i = 0; 577362306a36Sopenharmony_ci int j = 0; 577462306a36Sopenharmony_ci int dma_alloc_count = 0; 577562306a36Sopenharmony_ci struct chain_tracker *ct; 577662306a36Sopenharmony_ci int count = ioc->rdpq_array_enable ? ioc->reply_queue_count : 1; 577762306a36Sopenharmony_ci 577862306a36Sopenharmony_ci dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 577962306a36Sopenharmony_ci 578062306a36Sopenharmony_ci if (ioc->request) { 578162306a36Sopenharmony_ci dma_free_coherent(&ioc->pdev->dev, ioc->request_dma_sz, 578262306a36Sopenharmony_ci ioc->request, ioc->request_dma); 578362306a36Sopenharmony_ci dexitprintk(ioc, 578462306a36Sopenharmony_ci ioc_info(ioc, "request_pool(0x%p): free\n", 578562306a36Sopenharmony_ci ioc->request)); 578662306a36Sopenharmony_ci ioc->request = NULL; 578762306a36Sopenharmony_ci } 578862306a36Sopenharmony_ci 578962306a36Sopenharmony_ci if (ioc->sense) { 579062306a36Sopenharmony_ci dma_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma); 579162306a36Sopenharmony_ci dma_pool_destroy(ioc->sense_dma_pool); 579262306a36Sopenharmony_ci dexitprintk(ioc, 579362306a36Sopenharmony_ci ioc_info(ioc, "sense_pool(0x%p): free\n", 579462306a36Sopenharmony_ci ioc->sense)); 579562306a36Sopenharmony_ci ioc->sense = NULL; 579662306a36Sopenharmony_ci } 579762306a36Sopenharmony_ci 579862306a36Sopenharmony_ci if (ioc->reply) { 579962306a36Sopenharmony_ci dma_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma); 580062306a36Sopenharmony_ci dma_pool_destroy(ioc->reply_dma_pool); 580162306a36Sopenharmony_ci dexitprintk(ioc, 580262306a36Sopenharmony_ci ioc_info(ioc, "reply_pool(0x%p): free\n", 580362306a36Sopenharmony_ci ioc->reply)); 580462306a36Sopenharmony_ci ioc->reply = NULL; 580562306a36Sopenharmony_ci } 580662306a36Sopenharmony_ci 580762306a36Sopenharmony_ci if (ioc->reply_free) { 580862306a36Sopenharmony_ci dma_pool_free(ioc->reply_free_dma_pool, ioc->reply_free, 580962306a36Sopenharmony_ci ioc->reply_free_dma); 581062306a36Sopenharmony_ci dma_pool_destroy(ioc->reply_free_dma_pool); 581162306a36Sopenharmony_ci dexitprintk(ioc, 581262306a36Sopenharmony_ci ioc_info(ioc, "reply_free_pool(0x%p): free\n", 581362306a36Sopenharmony_ci ioc->reply_free)); 581462306a36Sopenharmony_ci ioc->reply_free = NULL; 581562306a36Sopenharmony_ci } 581662306a36Sopenharmony_ci 581762306a36Sopenharmony_ci if (ioc->reply_post) { 581862306a36Sopenharmony_ci dma_alloc_count = DIV_ROUND_UP(count, 581962306a36Sopenharmony_ci RDPQ_MAX_INDEX_IN_ONE_CHUNK); 582062306a36Sopenharmony_ci for (i = 0; i < count; i++) { 582162306a36Sopenharmony_ci if (i % RDPQ_MAX_INDEX_IN_ONE_CHUNK == 0 582262306a36Sopenharmony_ci && dma_alloc_count) { 582362306a36Sopenharmony_ci if (ioc->reply_post[i].reply_post_free) { 582462306a36Sopenharmony_ci dma_pool_free( 582562306a36Sopenharmony_ci ioc->reply_post_free_dma_pool, 582662306a36Sopenharmony_ci ioc->reply_post[i].reply_post_free, 582762306a36Sopenharmony_ci ioc->reply_post[i].reply_post_free_dma); 582862306a36Sopenharmony_ci dexitprintk(ioc, ioc_info(ioc, 582962306a36Sopenharmony_ci "reply_post_free_pool(0x%p): free\n", 583062306a36Sopenharmony_ci ioc->reply_post[i].reply_post_free)); 583162306a36Sopenharmony_ci ioc->reply_post[i].reply_post_free = 583262306a36Sopenharmony_ci NULL; 583362306a36Sopenharmony_ci } 583462306a36Sopenharmony_ci --dma_alloc_count; 583562306a36Sopenharmony_ci } 583662306a36Sopenharmony_ci } 583762306a36Sopenharmony_ci dma_pool_destroy(ioc->reply_post_free_dma_pool); 583862306a36Sopenharmony_ci if (ioc->reply_post_free_array && 583962306a36Sopenharmony_ci ioc->rdpq_array_enable) { 584062306a36Sopenharmony_ci dma_pool_free(ioc->reply_post_free_array_dma_pool, 584162306a36Sopenharmony_ci ioc->reply_post_free_array, 584262306a36Sopenharmony_ci ioc->reply_post_free_array_dma); 584362306a36Sopenharmony_ci ioc->reply_post_free_array = NULL; 584462306a36Sopenharmony_ci } 584562306a36Sopenharmony_ci dma_pool_destroy(ioc->reply_post_free_array_dma_pool); 584662306a36Sopenharmony_ci kfree(ioc->reply_post); 584762306a36Sopenharmony_ci } 584862306a36Sopenharmony_ci 584962306a36Sopenharmony_ci if (ioc->pcie_sgl_dma_pool) { 585062306a36Sopenharmony_ci for (i = 0; i < ioc->scsiio_depth; i++) { 585162306a36Sopenharmony_ci dma_pool_free(ioc->pcie_sgl_dma_pool, 585262306a36Sopenharmony_ci ioc->pcie_sg_lookup[i].pcie_sgl, 585362306a36Sopenharmony_ci ioc->pcie_sg_lookup[i].pcie_sgl_dma); 585462306a36Sopenharmony_ci ioc->pcie_sg_lookup[i].pcie_sgl = NULL; 585562306a36Sopenharmony_ci } 585662306a36Sopenharmony_ci dma_pool_destroy(ioc->pcie_sgl_dma_pool); 585762306a36Sopenharmony_ci } 585862306a36Sopenharmony_ci kfree(ioc->pcie_sg_lookup); 585962306a36Sopenharmony_ci ioc->pcie_sg_lookup = NULL; 586062306a36Sopenharmony_ci 586162306a36Sopenharmony_ci if (ioc->config_page) { 586262306a36Sopenharmony_ci dexitprintk(ioc, 586362306a36Sopenharmony_ci ioc_info(ioc, "config_page(0x%p): free\n", 586462306a36Sopenharmony_ci ioc->config_page)); 586562306a36Sopenharmony_ci dma_free_coherent(&ioc->pdev->dev, ioc->config_page_sz, 586662306a36Sopenharmony_ci ioc->config_page, ioc->config_page_dma); 586762306a36Sopenharmony_ci } 586862306a36Sopenharmony_ci 586962306a36Sopenharmony_ci kfree(ioc->hpr_lookup); 587062306a36Sopenharmony_ci ioc->hpr_lookup = NULL; 587162306a36Sopenharmony_ci kfree(ioc->internal_lookup); 587262306a36Sopenharmony_ci ioc->internal_lookup = NULL; 587362306a36Sopenharmony_ci if (ioc->chain_lookup) { 587462306a36Sopenharmony_ci for (i = 0; i < ioc->scsiio_depth; i++) { 587562306a36Sopenharmony_ci for (j = ioc->chains_per_prp_buffer; 587662306a36Sopenharmony_ci j < ioc->chains_needed_per_io; j++) { 587762306a36Sopenharmony_ci ct = &ioc->chain_lookup[i].chains_per_smid[j]; 587862306a36Sopenharmony_ci if (ct && ct->chain_buffer) 587962306a36Sopenharmony_ci dma_pool_free(ioc->chain_dma_pool, 588062306a36Sopenharmony_ci ct->chain_buffer, 588162306a36Sopenharmony_ci ct->chain_buffer_dma); 588262306a36Sopenharmony_ci } 588362306a36Sopenharmony_ci kfree(ioc->chain_lookup[i].chains_per_smid); 588462306a36Sopenharmony_ci } 588562306a36Sopenharmony_ci dma_pool_destroy(ioc->chain_dma_pool); 588662306a36Sopenharmony_ci kfree(ioc->chain_lookup); 588762306a36Sopenharmony_ci ioc->chain_lookup = NULL; 588862306a36Sopenharmony_ci } 588962306a36Sopenharmony_ci 589062306a36Sopenharmony_ci kfree(ioc->io_queue_num); 589162306a36Sopenharmony_ci ioc->io_queue_num = NULL; 589262306a36Sopenharmony_ci} 589362306a36Sopenharmony_ci 589462306a36Sopenharmony_ci/** 589562306a36Sopenharmony_ci * mpt3sas_check_same_4gb_region - checks whether all reply queues in a set are 589662306a36Sopenharmony_ci * having same upper 32bits in their base memory address. 589762306a36Sopenharmony_ci * @start_address: Base address of a reply queue set 589862306a36Sopenharmony_ci * @pool_sz: Size of single Reply Descriptor Post Queues pool size 589962306a36Sopenharmony_ci * 590062306a36Sopenharmony_ci * Return: 1 if reply queues in a set have a same upper 32bits in their base 590162306a36Sopenharmony_ci * memory address, else 0. 590262306a36Sopenharmony_ci */ 590362306a36Sopenharmony_cistatic int 590462306a36Sopenharmony_cimpt3sas_check_same_4gb_region(dma_addr_t start_address, u32 pool_sz) 590562306a36Sopenharmony_ci{ 590662306a36Sopenharmony_ci dma_addr_t end_address; 590762306a36Sopenharmony_ci 590862306a36Sopenharmony_ci end_address = start_address + pool_sz - 1; 590962306a36Sopenharmony_ci 591062306a36Sopenharmony_ci if (upper_32_bits(start_address) == upper_32_bits(end_address)) 591162306a36Sopenharmony_ci return 1; 591262306a36Sopenharmony_ci else 591362306a36Sopenharmony_ci return 0; 591462306a36Sopenharmony_ci} 591562306a36Sopenharmony_ci 591662306a36Sopenharmony_ci/** 591762306a36Sopenharmony_ci * _base_reduce_hba_queue_depth- Retry with reduced queue depth 591862306a36Sopenharmony_ci * @ioc: Adapter object 591962306a36Sopenharmony_ci * 592062306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 592162306a36Sopenharmony_ci **/ 592262306a36Sopenharmony_cistatic inline int 592362306a36Sopenharmony_ci_base_reduce_hba_queue_depth(struct MPT3SAS_ADAPTER *ioc) 592462306a36Sopenharmony_ci{ 592562306a36Sopenharmony_ci int reduce_sz = 64; 592662306a36Sopenharmony_ci 592762306a36Sopenharmony_ci if ((ioc->hba_queue_depth - reduce_sz) > 592862306a36Sopenharmony_ci (ioc->internal_depth + INTERNAL_SCSIIO_CMDS_COUNT)) { 592962306a36Sopenharmony_ci ioc->hba_queue_depth -= reduce_sz; 593062306a36Sopenharmony_ci return 0; 593162306a36Sopenharmony_ci } else 593262306a36Sopenharmony_ci return -ENOMEM; 593362306a36Sopenharmony_ci} 593462306a36Sopenharmony_ci 593562306a36Sopenharmony_ci/** 593662306a36Sopenharmony_ci * _base_allocate_pcie_sgl_pool - Allocating DMA'able memory 593762306a36Sopenharmony_ci * for pcie sgl pools. 593862306a36Sopenharmony_ci * @ioc: Adapter object 593962306a36Sopenharmony_ci * @sz: DMA Pool size 594062306a36Sopenharmony_ci * 594162306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 594262306a36Sopenharmony_ci */ 594362306a36Sopenharmony_ci 594462306a36Sopenharmony_cistatic int 594562306a36Sopenharmony_ci_base_allocate_pcie_sgl_pool(struct MPT3SAS_ADAPTER *ioc, u32 sz) 594662306a36Sopenharmony_ci{ 594762306a36Sopenharmony_ci int i = 0, j = 0; 594862306a36Sopenharmony_ci struct chain_tracker *ct; 594962306a36Sopenharmony_ci 595062306a36Sopenharmony_ci ioc->pcie_sgl_dma_pool = 595162306a36Sopenharmony_ci dma_pool_create("PCIe SGL pool", &ioc->pdev->dev, sz, 595262306a36Sopenharmony_ci ioc->page_size, 0); 595362306a36Sopenharmony_ci if (!ioc->pcie_sgl_dma_pool) { 595462306a36Sopenharmony_ci ioc_err(ioc, "PCIe SGL pool: dma_pool_create failed\n"); 595562306a36Sopenharmony_ci return -ENOMEM; 595662306a36Sopenharmony_ci } 595762306a36Sopenharmony_ci 595862306a36Sopenharmony_ci ioc->chains_per_prp_buffer = sz/ioc->chain_segment_sz; 595962306a36Sopenharmony_ci ioc->chains_per_prp_buffer = 596062306a36Sopenharmony_ci min(ioc->chains_per_prp_buffer, ioc->chains_needed_per_io); 596162306a36Sopenharmony_ci for (i = 0; i < ioc->scsiio_depth; i++) { 596262306a36Sopenharmony_ci ioc->pcie_sg_lookup[i].pcie_sgl = 596362306a36Sopenharmony_ci dma_pool_alloc(ioc->pcie_sgl_dma_pool, GFP_KERNEL, 596462306a36Sopenharmony_ci &ioc->pcie_sg_lookup[i].pcie_sgl_dma); 596562306a36Sopenharmony_ci if (!ioc->pcie_sg_lookup[i].pcie_sgl) { 596662306a36Sopenharmony_ci ioc_err(ioc, "PCIe SGL pool: dma_pool_alloc failed\n"); 596762306a36Sopenharmony_ci return -EAGAIN; 596862306a36Sopenharmony_ci } 596962306a36Sopenharmony_ci 597062306a36Sopenharmony_ci if (!mpt3sas_check_same_4gb_region( 597162306a36Sopenharmony_ci ioc->pcie_sg_lookup[i].pcie_sgl_dma, sz)) { 597262306a36Sopenharmony_ci ioc_err(ioc, "PCIE SGLs are not in same 4G !! pcie sgl (0x%p) dma = (0x%llx)\n", 597362306a36Sopenharmony_ci ioc->pcie_sg_lookup[i].pcie_sgl, 597462306a36Sopenharmony_ci (unsigned long long) 597562306a36Sopenharmony_ci ioc->pcie_sg_lookup[i].pcie_sgl_dma); 597662306a36Sopenharmony_ci ioc->use_32bit_dma = true; 597762306a36Sopenharmony_ci return -EAGAIN; 597862306a36Sopenharmony_ci } 597962306a36Sopenharmony_ci 598062306a36Sopenharmony_ci for (j = 0; j < ioc->chains_per_prp_buffer; j++) { 598162306a36Sopenharmony_ci ct = &ioc->chain_lookup[i].chains_per_smid[j]; 598262306a36Sopenharmony_ci ct->chain_buffer = 598362306a36Sopenharmony_ci ioc->pcie_sg_lookup[i].pcie_sgl + 598462306a36Sopenharmony_ci (j * ioc->chain_segment_sz); 598562306a36Sopenharmony_ci ct->chain_buffer_dma = 598662306a36Sopenharmony_ci ioc->pcie_sg_lookup[i].pcie_sgl_dma + 598762306a36Sopenharmony_ci (j * ioc->chain_segment_sz); 598862306a36Sopenharmony_ci } 598962306a36Sopenharmony_ci } 599062306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, 599162306a36Sopenharmony_ci "PCIe sgl pool depth(%d), element_size(%d), pool_size(%d kB)\n", 599262306a36Sopenharmony_ci ioc->scsiio_depth, sz, (sz * ioc->scsiio_depth)/1024)); 599362306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, 599462306a36Sopenharmony_ci "Number of chains can fit in a PRP page(%d)\n", 599562306a36Sopenharmony_ci ioc->chains_per_prp_buffer)); 599662306a36Sopenharmony_ci return 0; 599762306a36Sopenharmony_ci} 599862306a36Sopenharmony_ci 599962306a36Sopenharmony_ci/** 600062306a36Sopenharmony_ci * _base_allocate_chain_dma_pool - Allocating DMA'able memory 600162306a36Sopenharmony_ci * for chain dma pool. 600262306a36Sopenharmony_ci * @ioc: Adapter object 600362306a36Sopenharmony_ci * @sz: DMA Pool size 600462306a36Sopenharmony_ci * 600562306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 600662306a36Sopenharmony_ci */ 600762306a36Sopenharmony_cistatic int 600862306a36Sopenharmony_ci_base_allocate_chain_dma_pool(struct MPT3SAS_ADAPTER *ioc, u32 sz) 600962306a36Sopenharmony_ci{ 601062306a36Sopenharmony_ci int i = 0, j = 0; 601162306a36Sopenharmony_ci struct chain_tracker *ctr; 601262306a36Sopenharmony_ci 601362306a36Sopenharmony_ci ioc->chain_dma_pool = dma_pool_create("chain pool", &ioc->pdev->dev, 601462306a36Sopenharmony_ci ioc->chain_segment_sz, 16, 0); 601562306a36Sopenharmony_ci if (!ioc->chain_dma_pool) 601662306a36Sopenharmony_ci return -ENOMEM; 601762306a36Sopenharmony_ci 601862306a36Sopenharmony_ci for (i = 0; i < ioc->scsiio_depth; i++) { 601962306a36Sopenharmony_ci for (j = ioc->chains_per_prp_buffer; 602062306a36Sopenharmony_ci j < ioc->chains_needed_per_io; j++) { 602162306a36Sopenharmony_ci ctr = &ioc->chain_lookup[i].chains_per_smid[j]; 602262306a36Sopenharmony_ci ctr->chain_buffer = dma_pool_alloc(ioc->chain_dma_pool, 602362306a36Sopenharmony_ci GFP_KERNEL, &ctr->chain_buffer_dma); 602462306a36Sopenharmony_ci if (!ctr->chain_buffer) 602562306a36Sopenharmony_ci return -EAGAIN; 602662306a36Sopenharmony_ci if (!mpt3sas_check_same_4gb_region( 602762306a36Sopenharmony_ci ctr->chain_buffer_dma, ioc->chain_segment_sz)) { 602862306a36Sopenharmony_ci ioc_err(ioc, 602962306a36Sopenharmony_ci "Chain buffers are not in same 4G !!! Chain buff (0x%p) dma = (0x%llx)\n", 603062306a36Sopenharmony_ci ctr->chain_buffer, 603162306a36Sopenharmony_ci (unsigned long long)ctr->chain_buffer_dma); 603262306a36Sopenharmony_ci ioc->use_32bit_dma = true; 603362306a36Sopenharmony_ci return -EAGAIN; 603462306a36Sopenharmony_ci } 603562306a36Sopenharmony_ci } 603662306a36Sopenharmony_ci } 603762306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, 603862306a36Sopenharmony_ci "chain_lookup depth (%d), frame_size(%d), pool_size(%d kB)\n", 603962306a36Sopenharmony_ci ioc->scsiio_depth, ioc->chain_segment_sz, ((ioc->scsiio_depth * 604062306a36Sopenharmony_ci (ioc->chains_needed_per_io - ioc->chains_per_prp_buffer) * 604162306a36Sopenharmony_ci ioc->chain_segment_sz))/1024)); 604262306a36Sopenharmony_ci return 0; 604362306a36Sopenharmony_ci} 604462306a36Sopenharmony_ci 604562306a36Sopenharmony_ci/** 604662306a36Sopenharmony_ci * _base_allocate_sense_dma_pool - Allocating DMA'able memory 604762306a36Sopenharmony_ci * for sense dma pool. 604862306a36Sopenharmony_ci * @ioc: Adapter object 604962306a36Sopenharmony_ci * @sz: DMA Pool size 605062306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 605162306a36Sopenharmony_ci */ 605262306a36Sopenharmony_cistatic int 605362306a36Sopenharmony_ci_base_allocate_sense_dma_pool(struct MPT3SAS_ADAPTER *ioc, u32 sz) 605462306a36Sopenharmony_ci{ 605562306a36Sopenharmony_ci ioc->sense_dma_pool = 605662306a36Sopenharmony_ci dma_pool_create("sense pool", &ioc->pdev->dev, sz, 4, 0); 605762306a36Sopenharmony_ci if (!ioc->sense_dma_pool) 605862306a36Sopenharmony_ci return -ENOMEM; 605962306a36Sopenharmony_ci ioc->sense = dma_pool_alloc(ioc->sense_dma_pool, 606062306a36Sopenharmony_ci GFP_KERNEL, &ioc->sense_dma); 606162306a36Sopenharmony_ci if (!ioc->sense) 606262306a36Sopenharmony_ci return -EAGAIN; 606362306a36Sopenharmony_ci if (!mpt3sas_check_same_4gb_region(ioc->sense_dma, sz)) { 606462306a36Sopenharmony_ci dinitprintk(ioc, pr_err( 606562306a36Sopenharmony_ci "Bad Sense Pool! sense (0x%p) sense_dma = (0x%llx)\n", 606662306a36Sopenharmony_ci ioc->sense, (unsigned long long) ioc->sense_dma)); 606762306a36Sopenharmony_ci ioc->use_32bit_dma = true; 606862306a36Sopenharmony_ci return -EAGAIN; 606962306a36Sopenharmony_ci } 607062306a36Sopenharmony_ci ioc_info(ioc, 607162306a36Sopenharmony_ci "sense pool(0x%p) - dma(0x%llx): depth(%d), element_size(%d), pool_size (%d kB)\n", 607262306a36Sopenharmony_ci ioc->sense, (unsigned long long)ioc->sense_dma, 607362306a36Sopenharmony_ci ioc->scsiio_depth, SCSI_SENSE_BUFFERSIZE, sz/1024); 607462306a36Sopenharmony_ci return 0; 607562306a36Sopenharmony_ci} 607662306a36Sopenharmony_ci 607762306a36Sopenharmony_ci/** 607862306a36Sopenharmony_ci * _base_allocate_reply_pool - Allocating DMA'able memory 607962306a36Sopenharmony_ci * for reply pool. 608062306a36Sopenharmony_ci * @ioc: Adapter object 608162306a36Sopenharmony_ci * @sz: DMA Pool size 608262306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 608362306a36Sopenharmony_ci */ 608462306a36Sopenharmony_cistatic int 608562306a36Sopenharmony_ci_base_allocate_reply_pool(struct MPT3SAS_ADAPTER *ioc, u32 sz) 608662306a36Sopenharmony_ci{ 608762306a36Sopenharmony_ci /* reply pool, 4 byte align */ 608862306a36Sopenharmony_ci ioc->reply_dma_pool = dma_pool_create("reply pool", 608962306a36Sopenharmony_ci &ioc->pdev->dev, sz, 4, 0); 609062306a36Sopenharmony_ci if (!ioc->reply_dma_pool) 609162306a36Sopenharmony_ci return -ENOMEM; 609262306a36Sopenharmony_ci ioc->reply = dma_pool_alloc(ioc->reply_dma_pool, GFP_KERNEL, 609362306a36Sopenharmony_ci &ioc->reply_dma); 609462306a36Sopenharmony_ci if (!ioc->reply) 609562306a36Sopenharmony_ci return -EAGAIN; 609662306a36Sopenharmony_ci if (!mpt3sas_check_same_4gb_region(ioc->reply_dma, sz)) { 609762306a36Sopenharmony_ci dinitprintk(ioc, pr_err( 609862306a36Sopenharmony_ci "Bad Reply Pool! Reply (0x%p) Reply dma = (0x%llx)\n", 609962306a36Sopenharmony_ci ioc->reply, (unsigned long long) ioc->reply_dma)); 610062306a36Sopenharmony_ci ioc->use_32bit_dma = true; 610162306a36Sopenharmony_ci return -EAGAIN; 610262306a36Sopenharmony_ci } 610362306a36Sopenharmony_ci ioc->reply_dma_min_address = (u32)(ioc->reply_dma); 610462306a36Sopenharmony_ci ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz; 610562306a36Sopenharmony_ci ioc_info(ioc, 610662306a36Sopenharmony_ci "reply pool(0x%p) - dma(0x%llx): depth(%d), frame_size(%d), pool_size(%d kB)\n", 610762306a36Sopenharmony_ci ioc->reply, (unsigned long long)ioc->reply_dma, 610862306a36Sopenharmony_ci ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024); 610962306a36Sopenharmony_ci return 0; 611062306a36Sopenharmony_ci} 611162306a36Sopenharmony_ci 611262306a36Sopenharmony_ci/** 611362306a36Sopenharmony_ci * _base_allocate_reply_free_dma_pool - Allocating DMA'able memory 611462306a36Sopenharmony_ci * for reply free dma pool. 611562306a36Sopenharmony_ci * @ioc: Adapter object 611662306a36Sopenharmony_ci * @sz: DMA Pool size 611762306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 611862306a36Sopenharmony_ci */ 611962306a36Sopenharmony_cistatic int 612062306a36Sopenharmony_ci_base_allocate_reply_free_dma_pool(struct MPT3SAS_ADAPTER *ioc, u32 sz) 612162306a36Sopenharmony_ci{ 612262306a36Sopenharmony_ci /* reply free queue, 16 byte align */ 612362306a36Sopenharmony_ci ioc->reply_free_dma_pool = dma_pool_create( 612462306a36Sopenharmony_ci "reply_free pool", &ioc->pdev->dev, sz, 16, 0); 612562306a36Sopenharmony_ci if (!ioc->reply_free_dma_pool) 612662306a36Sopenharmony_ci return -ENOMEM; 612762306a36Sopenharmony_ci ioc->reply_free = dma_pool_alloc(ioc->reply_free_dma_pool, 612862306a36Sopenharmony_ci GFP_KERNEL, &ioc->reply_free_dma); 612962306a36Sopenharmony_ci if (!ioc->reply_free) 613062306a36Sopenharmony_ci return -EAGAIN; 613162306a36Sopenharmony_ci if (!mpt3sas_check_same_4gb_region(ioc->reply_free_dma, sz)) { 613262306a36Sopenharmony_ci dinitprintk(ioc, 613362306a36Sopenharmony_ci pr_err("Bad Reply Free Pool! Reply Free (0x%p) Reply Free dma = (0x%llx)\n", 613462306a36Sopenharmony_ci ioc->reply_free, (unsigned long long) ioc->reply_free_dma)); 613562306a36Sopenharmony_ci ioc->use_32bit_dma = true; 613662306a36Sopenharmony_ci return -EAGAIN; 613762306a36Sopenharmony_ci } 613862306a36Sopenharmony_ci memset(ioc->reply_free, 0, sz); 613962306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, 614062306a36Sopenharmony_ci "reply_free pool(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n", 614162306a36Sopenharmony_ci ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024)); 614262306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, 614362306a36Sopenharmony_ci "reply_free_dma (0x%llx)\n", 614462306a36Sopenharmony_ci (unsigned long long)ioc->reply_free_dma)); 614562306a36Sopenharmony_ci return 0; 614662306a36Sopenharmony_ci} 614762306a36Sopenharmony_ci 614862306a36Sopenharmony_ci/** 614962306a36Sopenharmony_ci * _base_allocate_reply_post_free_array - Allocating DMA'able memory 615062306a36Sopenharmony_ci * for reply post free array. 615162306a36Sopenharmony_ci * @ioc: Adapter object 615262306a36Sopenharmony_ci * @reply_post_free_array_sz: DMA Pool size 615362306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 615462306a36Sopenharmony_ci */ 615562306a36Sopenharmony_ci 615662306a36Sopenharmony_cistatic int 615762306a36Sopenharmony_ci_base_allocate_reply_post_free_array(struct MPT3SAS_ADAPTER *ioc, 615862306a36Sopenharmony_ci u32 reply_post_free_array_sz) 615962306a36Sopenharmony_ci{ 616062306a36Sopenharmony_ci ioc->reply_post_free_array_dma_pool = 616162306a36Sopenharmony_ci dma_pool_create("reply_post_free_array pool", 616262306a36Sopenharmony_ci &ioc->pdev->dev, reply_post_free_array_sz, 16, 0); 616362306a36Sopenharmony_ci if (!ioc->reply_post_free_array_dma_pool) 616462306a36Sopenharmony_ci return -ENOMEM; 616562306a36Sopenharmony_ci ioc->reply_post_free_array = 616662306a36Sopenharmony_ci dma_pool_alloc(ioc->reply_post_free_array_dma_pool, 616762306a36Sopenharmony_ci GFP_KERNEL, &ioc->reply_post_free_array_dma); 616862306a36Sopenharmony_ci if (!ioc->reply_post_free_array) 616962306a36Sopenharmony_ci return -EAGAIN; 617062306a36Sopenharmony_ci if (!mpt3sas_check_same_4gb_region(ioc->reply_post_free_array_dma, 617162306a36Sopenharmony_ci reply_post_free_array_sz)) { 617262306a36Sopenharmony_ci dinitprintk(ioc, pr_err( 617362306a36Sopenharmony_ci "Bad Reply Free Pool! Reply Free (0x%p) Reply Free dma = (0x%llx)\n", 617462306a36Sopenharmony_ci ioc->reply_free, 617562306a36Sopenharmony_ci (unsigned long long) ioc->reply_free_dma)); 617662306a36Sopenharmony_ci ioc->use_32bit_dma = true; 617762306a36Sopenharmony_ci return -EAGAIN; 617862306a36Sopenharmony_ci } 617962306a36Sopenharmony_ci return 0; 618062306a36Sopenharmony_ci} 618162306a36Sopenharmony_ci/** 618262306a36Sopenharmony_ci * base_alloc_rdpq_dma_pool - Allocating DMA'able memory 618362306a36Sopenharmony_ci * for reply queues. 618462306a36Sopenharmony_ci * @ioc: per adapter object 618562306a36Sopenharmony_ci * @sz: DMA Pool size 618662306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 618762306a36Sopenharmony_ci */ 618862306a36Sopenharmony_cistatic int 618962306a36Sopenharmony_cibase_alloc_rdpq_dma_pool(struct MPT3SAS_ADAPTER *ioc, int sz) 619062306a36Sopenharmony_ci{ 619162306a36Sopenharmony_ci int i = 0; 619262306a36Sopenharmony_ci u32 dma_alloc_count = 0; 619362306a36Sopenharmony_ci int reply_post_free_sz = ioc->reply_post_queue_depth * 619462306a36Sopenharmony_ci sizeof(Mpi2DefaultReplyDescriptor_t); 619562306a36Sopenharmony_ci int count = ioc->rdpq_array_enable ? ioc->reply_queue_count : 1; 619662306a36Sopenharmony_ci 619762306a36Sopenharmony_ci ioc->reply_post = kcalloc(count, sizeof(struct reply_post_struct), 619862306a36Sopenharmony_ci GFP_KERNEL); 619962306a36Sopenharmony_ci if (!ioc->reply_post) 620062306a36Sopenharmony_ci return -ENOMEM; 620162306a36Sopenharmony_ci /* 620262306a36Sopenharmony_ci * For INVADER_SERIES each set of 8 reply queues(0-7, 8-15, ..) and 620362306a36Sopenharmony_ci * VENTURA_SERIES each set of 16 reply queues(0-15, 16-31, ..) should 620462306a36Sopenharmony_ci * be within 4GB boundary i.e reply queues in a set must have same 620562306a36Sopenharmony_ci * upper 32-bits in their memory address. so here driver is allocating 620662306a36Sopenharmony_ci * the DMA'able memory for reply queues according. 620762306a36Sopenharmony_ci * Driver uses limitation of 620862306a36Sopenharmony_ci * VENTURA_SERIES to manage INVADER_SERIES as well. 620962306a36Sopenharmony_ci */ 621062306a36Sopenharmony_ci dma_alloc_count = DIV_ROUND_UP(count, 621162306a36Sopenharmony_ci RDPQ_MAX_INDEX_IN_ONE_CHUNK); 621262306a36Sopenharmony_ci ioc->reply_post_free_dma_pool = 621362306a36Sopenharmony_ci dma_pool_create("reply_post_free pool", 621462306a36Sopenharmony_ci &ioc->pdev->dev, sz, 16, 0); 621562306a36Sopenharmony_ci if (!ioc->reply_post_free_dma_pool) 621662306a36Sopenharmony_ci return -ENOMEM; 621762306a36Sopenharmony_ci for (i = 0; i < count; i++) { 621862306a36Sopenharmony_ci if ((i % RDPQ_MAX_INDEX_IN_ONE_CHUNK == 0) && dma_alloc_count) { 621962306a36Sopenharmony_ci ioc->reply_post[i].reply_post_free = 622062306a36Sopenharmony_ci dma_pool_zalloc(ioc->reply_post_free_dma_pool, 622162306a36Sopenharmony_ci GFP_KERNEL, 622262306a36Sopenharmony_ci &ioc->reply_post[i].reply_post_free_dma); 622362306a36Sopenharmony_ci if (!ioc->reply_post[i].reply_post_free) 622462306a36Sopenharmony_ci return -ENOMEM; 622562306a36Sopenharmony_ci /* 622662306a36Sopenharmony_ci * Each set of RDPQ pool must satisfy 4gb boundary 622762306a36Sopenharmony_ci * restriction. 622862306a36Sopenharmony_ci * 1) Check if allocated resources for RDPQ pool are in 622962306a36Sopenharmony_ci * the same 4GB range. 623062306a36Sopenharmony_ci * 2) If #1 is true, continue with 64 bit DMA. 623162306a36Sopenharmony_ci * 3) If #1 is false, return 1. which means free all the 623262306a36Sopenharmony_ci * resources and set DMA mask to 32 and allocate. 623362306a36Sopenharmony_ci */ 623462306a36Sopenharmony_ci if (!mpt3sas_check_same_4gb_region( 623562306a36Sopenharmony_ci ioc->reply_post[i].reply_post_free_dma, sz)) { 623662306a36Sopenharmony_ci dinitprintk(ioc, 623762306a36Sopenharmony_ci ioc_err(ioc, "bad Replypost free pool(0x%p)" 623862306a36Sopenharmony_ci "reply_post_free_dma = (0x%llx)\n", 623962306a36Sopenharmony_ci ioc->reply_post[i].reply_post_free, 624062306a36Sopenharmony_ci (unsigned long long) 624162306a36Sopenharmony_ci ioc->reply_post[i].reply_post_free_dma)); 624262306a36Sopenharmony_ci return -EAGAIN; 624362306a36Sopenharmony_ci } 624462306a36Sopenharmony_ci dma_alloc_count--; 624562306a36Sopenharmony_ci 624662306a36Sopenharmony_ci } else { 624762306a36Sopenharmony_ci ioc->reply_post[i].reply_post_free = 624862306a36Sopenharmony_ci (Mpi2ReplyDescriptorsUnion_t *) 624962306a36Sopenharmony_ci ((long)ioc->reply_post[i-1].reply_post_free 625062306a36Sopenharmony_ci + reply_post_free_sz); 625162306a36Sopenharmony_ci ioc->reply_post[i].reply_post_free_dma = 625262306a36Sopenharmony_ci (dma_addr_t) 625362306a36Sopenharmony_ci (ioc->reply_post[i-1].reply_post_free_dma + 625462306a36Sopenharmony_ci reply_post_free_sz); 625562306a36Sopenharmony_ci } 625662306a36Sopenharmony_ci } 625762306a36Sopenharmony_ci return 0; 625862306a36Sopenharmony_ci} 625962306a36Sopenharmony_ci 626062306a36Sopenharmony_ci/** 626162306a36Sopenharmony_ci * _base_allocate_memory_pools - allocate start of day memory pools 626262306a36Sopenharmony_ci * @ioc: per adapter object 626362306a36Sopenharmony_ci * 626462306a36Sopenharmony_ci * Return: 0 success, anything else error. 626562306a36Sopenharmony_ci */ 626662306a36Sopenharmony_cistatic int 626762306a36Sopenharmony_ci_base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) 626862306a36Sopenharmony_ci{ 626962306a36Sopenharmony_ci struct mpt3sas_facts *facts; 627062306a36Sopenharmony_ci u16 max_sge_elements; 627162306a36Sopenharmony_ci u16 chains_needed_per_io; 627262306a36Sopenharmony_ci u32 sz, total_sz, reply_post_free_sz, reply_post_free_array_sz; 627362306a36Sopenharmony_ci u32 retry_sz; 627462306a36Sopenharmony_ci u32 rdpq_sz = 0, sense_sz = 0; 627562306a36Sopenharmony_ci u16 max_request_credit, nvme_blocks_needed; 627662306a36Sopenharmony_ci unsigned short sg_tablesize; 627762306a36Sopenharmony_ci u16 sge_size; 627862306a36Sopenharmony_ci int i; 627962306a36Sopenharmony_ci int ret = 0, rc = 0; 628062306a36Sopenharmony_ci 628162306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 628262306a36Sopenharmony_ci 628362306a36Sopenharmony_ci 628462306a36Sopenharmony_ci retry_sz = 0; 628562306a36Sopenharmony_ci facts = &ioc->facts; 628662306a36Sopenharmony_ci 628762306a36Sopenharmony_ci /* command line tunables for max sgl entries */ 628862306a36Sopenharmony_ci if (max_sgl_entries != -1) 628962306a36Sopenharmony_ci sg_tablesize = max_sgl_entries; 629062306a36Sopenharmony_ci else { 629162306a36Sopenharmony_ci if (ioc->hba_mpi_version_belonged == MPI2_VERSION) 629262306a36Sopenharmony_ci sg_tablesize = MPT2SAS_SG_DEPTH; 629362306a36Sopenharmony_ci else 629462306a36Sopenharmony_ci sg_tablesize = MPT3SAS_SG_DEPTH; 629562306a36Sopenharmony_ci } 629662306a36Sopenharmony_ci 629762306a36Sopenharmony_ci /* max sgl entries <= MPT_KDUMP_MIN_PHYS_SEGMENTS in KDUMP mode */ 629862306a36Sopenharmony_ci if (reset_devices) 629962306a36Sopenharmony_ci sg_tablesize = min_t(unsigned short, sg_tablesize, 630062306a36Sopenharmony_ci MPT_KDUMP_MIN_PHYS_SEGMENTS); 630162306a36Sopenharmony_ci 630262306a36Sopenharmony_ci if (ioc->is_mcpu_endpoint) 630362306a36Sopenharmony_ci ioc->shost->sg_tablesize = MPT_MIN_PHYS_SEGMENTS; 630462306a36Sopenharmony_ci else { 630562306a36Sopenharmony_ci if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS) 630662306a36Sopenharmony_ci sg_tablesize = MPT_MIN_PHYS_SEGMENTS; 630762306a36Sopenharmony_ci else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) { 630862306a36Sopenharmony_ci sg_tablesize = min_t(unsigned short, sg_tablesize, 630962306a36Sopenharmony_ci SG_MAX_SEGMENTS); 631062306a36Sopenharmony_ci ioc_warn(ioc, "sg_tablesize(%u) is bigger than kernel defined SG_CHUNK_SIZE(%u)\n", 631162306a36Sopenharmony_ci sg_tablesize, MPT_MAX_PHYS_SEGMENTS); 631262306a36Sopenharmony_ci } 631362306a36Sopenharmony_ci ioc->shost->sg_tablesize = sg_tablesize; 631462306a36Sopenharmony_ci } 631562306a36Sopenharmony_ci 631662306a36Sopenharmony_ci ioc->internal_depth = min_t(int, (facts->HighPriorityCredit + (5)), 631762306a36Sopenharmony_ci (facts->RequestCredit / 4)); 631862306a36Sopenharmony_ci if (ioc->internal_depth < INTERNAL_CMDS_COUNT) { 631962306a36Sopenharmony_ci if (facts->RequestCredit <= (INTERNAL_CMDS_COUNT + 632062306a36Sopenharmony_ci INTERNAL_SCSIIO_CMDS_COUNT)) { 632162306a36Sopenharmony_ci ioc_err(ioc, "IOC doesn't have enough Request Credits, it has just %d number of credits\n", 632262306a36Sopenharmony_ci facts->RequestCredit); 632362306a36Sopenharmony_ci return -ENOMEM; 632462306a36Sopenharmony_ci } 632562306a36Sopenharmony_ci ioc->internal_depth = 10; 632662306a36Sopenharmony_ci } 632762306a36Sopenharmony_ci 632862306a36Sopenharmony_ci ioc->hi_priority_depth = ioc->internal_depth - (5); 632962306a36Sopenharmony_ci /* command line tunables for max controller queue depth */ 633062306a36Sopenharmony_ci if (max_queue_depth != -1 && max_queue_depth != 0) { 633162306a36Sopenharmony_ci max_request_credit = min_t(u16, max_queue_depth + 633262306a36Sopenharmony_ci ioc->internal_depth, facts->RequestCredit); 633362306a36Sopenharmony_ci if (max_request_credit > MAX_HBA_QUEUE_DEPTH) 633462306a36Sopenharmony_ci max_request_credit = MAX_HBA_QUEUE_DEPTH; 633562306a36Sopenharmony_ci } else if (reset_devices) 633662306a36Sopenharmony_ci max_request_credit = min_t(u16, facts->RequestCredit, 633762306a36Sopenharmony_ci (MPT3SAS_KDUMP_SCSI_IO_DEPTH + ioc->internal_depth)); 633862306a36Sopenharmony_ci else 633962306a36Sopenharmony_ci max_request_credit = min_t(u16, facts->RequestCredit, 634062306a36Sopenharmony_ci MAX_HBA_QUEUE_DEPTH); 634162306a36Sopenharmony_ci 634262306a36Sopenharmony_ci /* Firmware maintains additional facts->HighPriorityCredit number of 634362306a36Sopenharmony_ci * credits for HiPriprity Request messages, so hba queue depth will be 634462306a36Sopenharmony_ci * sum of max_request_credit and high priority queue depth. 634562306a36Sopenharmony_ci */ 634662306a36Sopenharmony_ci ioc->hba_queue_depth = max_request_credit + ioc->hi_priority_depth; 634762306a36Sopenharmony_ci 634862306a36Sopenharmony_ci /* request frame size */ 634962306a36Sopenharmony_ci ioc->request_sz = facts->IOCRequestFrameSize * 4; 635062306a36Sopenharmony_ci 635162306a36Sopenharmony_ci /* reply frame size */ 635262306a36Sopenharmony_ci ioc->reply_sz = facts->ReplyFrameSize * 4; 635362306a36Sopenharmony_ci 635462306a36Sopenharmony_ci /* chain segment size */ 635562306a36Sopenharmony_ci if (ioc->hba_mpi_version_belonged != MPI2_VERSION) { 635662306a36Sopenharmony_ci if (facts->IOCMaxChainSegmentSize) 635762306a36Sopenharmony_ci ioc->chain_segment_sz = 635862306a36Sopenharmony_ci facts->IOCMaxChainSegmentSize * 635962306a36Sopenharmony_ci MAX_CHAIN_ELEMT_SZ; 636062306a36Sopenharmony_ci else 636162306a36Sopenharmony_ci /* set to 128 bytes size if IOCMaxChainSegmentSize is zero */ 636262306a36Sopenharmony_ci ioc->chain_segment_sz = DEFAULT_NUM_FWCHAIN_ELEMTS * 636362306a36Sopenharmony_ci MAX_CHAIN_ELEMT_SZ; 636462306a36Sopenharmony_ci } else 636562306a36Sopenharmony_ci ioc->chain_segment_sz = ioc->request_sz; 636662306a36Sopenharmony_ci 636762306a36Sopenharmony_ci /* calculate the max scatter element size */ 636862306a36Sopenharmony_ci sge_size = max_t(u16, ioc->sge_size, ioc->sge_size_ieee); 636962306a36Sopenharmony_ci 637062306a36Sopenharmony_ci retry_allocation: 637162306a36Sopenharmony_ci total_sz = 0; 637262306a36Sopenharmony_ci /* calculate number of sg elements left over in the 1st frame */ 637362306a36Sopenharmony_ci max_sge_elements = ioc->request_sz - ((sizeof(Mpi2SCSIIORequest_t) - 637462306a36Sopenharmony_ci sizeof(Mpi2SGEIOUnion_t)) + sge_size); 637562306a36Sopenharmony_ci ioc->max_sges_in_main_message = max_sge_elements/sge_size; 637662306a36Sopenharmony_ci 637762306a36Sopenharmony_ci /* now do the same for a chain buffer */ 637862306a36Sopenharmony_ci max_sge_elements = ioc->chain_segment_sz - sge_size; 637962306a36Sopenharmony_ci ioc->max_sges_in_chain_message = max_sge_elements/sge_size; 638062306a36Sopenharmony_ci 638162306a36Sopenharmony_ci /* 638262306a36Sopenharmony_ci * MPT3SAS_SG_DEPTH = CONFIG_FUSION_MAX_SGE 638362306a36Sopenharmony_ci */ 638462306a36Sopenharmony_ci chains_needed_per_io = ((ioc->shost->sg_tablesize - 638562306a36Sopenharmony_ci ioc->max_sges_in_main_message)/ioc->max_sges_in_chain_message) 638662306a36Sopenharmony_ci + 1; 638762306a36Sopenharmony_ci if (chains_needed_per_io > facts->MaxChainDepth) { 638862306a36Sopenharmony_ci chains_needed_per_io = facts->MaxChainDepth; 638962306a36Sopenharmony_ci ioc->shost->sg_tablesize = min_t(u16, 639062306a36Sopenharmony_ci ioc->max_sges_in_main_message + (ioc->max_sges_in_chain_message 639162306a36Sopenharmony_ci * chains_needed_per_io), ioc->shost->sg_tablesize); 639262306a36Sopenharmony_ci } 639362306a36Sopenharmony_ci ioc->chains_needed_per_io = chains_needed_per_io; 639462306a36Sopenharmony_ci 639562306a36Sopenharmony_ci /* reply free queue sizing - taking into account for 64 FW events */ 639662306a36Sopenharmony_ci ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; 639762306a36Sopenharmony_ci 639862306a36Sopenharmony_ci /* mCPU manage single counters for simplicity */ 639962306a36Sopenharmony_ci if (ioc->is_mcpu_endpoint) 640062306a36Sopenharmony_ci ioc->reply_post_queue_depth = ioc->reply_free_queue_depth; 640162306a36Sopenharmony_ci else { 640262306a36Sopenharmony_ci /* calculate reply descriptor post queue depth */ 640362306a36Sopenharmony_ci ioc->reply_post_queue_depth = ioc->hba_queue_depth + 640462306a36Sopenharmony_ci ioc->reply_free_queue_depth + 1; 640562306a36Sopenharmony_ci /* align the reply post queue on the next 16 count boundary */ 640662306a36Sopenharmony_ci if (ioc->reply_post_queue_depth % 16) 640762306a36Sopenharmony_ci ioc->reply_post_queue_depth += 16 - 640862306a36Sopenharmony_ci (ioc->reply_post_queue_depth % 16); 640962306a36Sopenharmony_ci } 641062306a36Sopenharmony_ci 641162306a36Sopenharmony_ci if (ioc->reply_post_queue_depth > 641262306a36Sopenharmony_ci facts->MaxReplyDescriptorPostQueueDepth) { 641362306a36Sopenharmony_ci ioc->reply_post_queue_depth = 641462306a36Sopenharmony_ci facts->MaxReplyDescriptorPostQueueDepth - 641562306a36Sopenharmony_ci (facts->MaxReplyDescriptorPostQueueDepth % 16); 641662306a36Sopenharmony_ci ioc->hba_queue_depth = 641762306a36Sopenharmony_ci ((ioc->reply_post_queue_depth - 64) / 2) - 1; 641862306a36Sopenharmony_ci ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; 641962306a36Sopenharmony_ci } 642062306a36Sopenharmony_ci 642162306a36Sopenharmony_ci ioc_info(ioc, 642262306a36Sopenharmony_ci "scatter gather: sge_in_main_msg(%d), sge_per_chain(%d), " 642362306a36Sopenharmony_ci "sge_per_io(%d), chains_per_io(%d)\n", 642462306a36Sopenharmony_ci ioc->max_sges_in_main_message, 642562306a36Sopenharmony_ci ioc->max_sges_in_chain_message, 642662306a36Sopenharmony_ci ioc->shost->sg_tablesize, 642762306a36Sopenharmony_ci ioc->chains_needed_per_io); 642862306a36Sopenharmony_ci 642962306a36Sopenharmony_ci /* reply post queue, 16 byte align */ 643062306a36Sopenharmony_ci reply_post_free_sz = ioc->reply_post_queue_depth * 643162306a36Sopenharmony_ci sizeof(Mpi2DefaultReplyDescriptor_t); 643262306a36Sopenharmony_ci rdpq_sz = reply_post_free_sz * RDPQ_MAX_INDEX_IN_ONE_CHUNK; 643362306a36Sopenharmony_ci if ((_base_is_controller_msix_enabled(ioc) && !ioc->rdpq_array_enable) 643462306a36Sopenharmony_ci || (ioc->reply_queue_count < RDPQ_MAX_INDEX_IN_ONE_CHUNK)) 643562306a36Sopenharmony_ci rdpq_sz = reply_post_free_sz * ioc->reply_queue_count; 643662306a36Sopenharmony_ci ret = base_alloc_rdpq_dma_pool(ioc, rdpq_sz); 643762306a36Sopenharmony_ci if (ret == -EAGAIN) { 643862306a36Sopenharmony_ci /* 643962306a36Sopenharmony_ci * Free allocated bad RDPQ memory pools. 644062306a36Sopenharmony_ci * Change dma coherent mask to 32 bit and reallocate RDPQ 644162306a36Sopenharmony_ci */ 644262306a36Sopenharmony_ci _base_release_memory_pools(ioc); 644362306a36Sopenharmony_ci ioc->use_32bit_dma = true; 644462306a36Sopenharmony_ci if (_base_config_dma_addressing(ioc, ioc->pdev) != 0) { 644562306a36Sopenharmony_ci ioc_err(ioc, 644662306a36Sopenharmony_ci "32 DMA mask failed %s\n", pci_name(ioc->pdev)); 644762306a36Sopenharmony_ci return -ENODEV; 644862306a36Sopenharmony_ci } 644962306a36Sopenharmony_ci if (base_alloc_rdpq_dma_pool(ioc, rdpq_sz)) 645062306a36Sopenharmony_ci return -ENOMEM; 645162306a36Sopenharmony_ci } else if (ret == -ENOMEM) 645262306a36Sopenharmony_ci return -ENOMEM; 645362306a36Sopenharmony_ci total_sz = rdpq_sz * (!ioc->rdpq_array_enable ? 1 : 645462306a36Sopenharmony_ci DIV_ROUND_UP(ioc->reply_queue_count, RDPQ_MAX_INDEX_IN_ONE_CHUNK)); 645562306a36Sopenharmony_ci ioc->scsiio_depth = ioc->hba_queue_depth - 645662306a36Sopenharmony_ci ioc->hi_priority_depth - ioc->internal_depth; 645762306a36Sopenharmony_ci 645862306a36Sopenharmony_ci /* set the scsi host can_queue depth 645962306a36Sopenharmony_ci * with some internal commands that could be outstanding 646062306a36Sopenharmony_ci */ 646162306a36Sopenharmony_ci ioc->shost->can_queue = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT; 646262306a36Sopenharmony_ci dinitprintk(ioc, 646362306a36Sopenharmony_ci ioc_info(ioc, "scsi host: can_queue depth (%d)\n", 646462306a36Sopenharmony_ci ioc->shost->can_queue)); 646562306a36Sopenharmony_ci 646662306a36Sopenharmony_ci /* contiguous pool for request and chains, 16 byte align, one extra " 646762306a36Sopenharmony_ci * "frame for smid=0 646862306a36Sopenharmony_ci */ 646962306a36Sopenharmony_ci ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth; 647062306a36Sopenharmony_ci sz = ((ioc->scsiio_depth + 1) * ioc->request_sz); 647162306a36Sopenharmony_ci 647262306a36Sopenharmony_ci /* hi-priority queue */ 647362306a36Sopenharmony_ci sz += (ioc->hi_priority_depth * ioc->request_sz); 647462306a36Sopenharmony_ci 647562306a36Sopenharmony_ci /* internal queue */ 647662306a36Sopenharmony_ci sz += (ioc->internal_depth * ioc->request_sz); 647762306a36Sopenharmony_ci 647862306a36Sopenharmony_ci ioc->request_dma_sz = sz; 647962306a36Sopenharmony_ci ioc->request = dma_alloc_coherent(&ioc->pdev->dev, sz, 648062306a36Sopenharmony_ci &ioc->request_dma, GFP_KERNEL); 648162306a36Sopenharmony_ci if (!ioc->request) { 648262306a36Sopenharmony_ci ioc_err(ioc, "request pool: dma_alloc_coherent failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), total(%d kB)\n", 648362306a36Sopenharmony_ci ioc->hba_queue_depth, ioc->chains_needed_per_io, 648462306a36Sopenharmony_ci ioc->request_sz, sz / 1024); 648562306a36Sopenharmony_ci if (ioc->scsiio_depth < MPT3SAS_SAS_QUEUE_DEPTH) 648662306a36Sopenharmony_ci goto out; 648762306a36Sopenharmony_ci retry_sz = 64; 648862306a36Sopenharmony_ci ioc->hba_queue_depth -= retry_sz; 648962306a36Sopenharmony_ci _base_release_memory_pools(ioc); 649062306a36Sopenharmony_ci goto retry_allocation; 649162306a36Sopenharmony_ci } 649262306a36Sopenharmony_ci 649362306a36Sopenharmony_ci if (retry_sz) 649462306a36Sopenharmony_ci ioc_err(ioc, "request pool: dma_alloc_coherent succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), total(%d kb)\n", 649562306a36Sopenharmony_ci ioc->hba_queue_depth, ioc->chains_needed_per_io, 649662306a36Sopenharmony_ci ioc->request_sz, sz / 1024); 649762306a36Sopenharmony_ci 649862306a36Sopenharmony_ci /* hi-priority queue */ 649962306a36Sopenharmony_ci ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) * 650062306a36Sopenharmony_ci ioc->request_sz); 650162306a36Sopenharmony_ci ioc->hi_priority_dma = ioc->request_dma + ((ioc->scsiio_depth + 1) * 650262306a36Sopenharmony_ci ioc->request_sz); 650362306a36Sopenharmony_ci 650462306a36Sopenharmony_ci /* internal queue */ 650562306a36Sopenharmony_ci ioc->internal = ioc->hi_priority + (ioc->hi_priority_depth * 650662306a36Sopenharmony_ci ioc->request_sz); 650762306a36Sopenharmony_ci ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth * 650862306a36Sopenharmony_ci ioc->request_sz); 650962306a36Sopenharmony_ci 651062306a36Sopenharmony_ci ioc_info(ioc, 651162306a36Sopenharmony_ci "request pool(0x%p) - dma(0x%llx): " 651262306a36Sopenharmony_ci "depth(%d), frame_size(%d), pool_size(%d kB)\n", 651362306a36Sopenharmony_ci ioc->request, (unsigned long long) ioc->request_dma, 651462306a36Sopenharmony_ci ioc->hba_queue_depth, ioc->request_sz, 651562306a36Sopenharmony_ci (ioc->hba_queue_depth * ioc->request_sz) / 1024); 651662306a36Sopenharmony_ci 651762306a36Sopenharmony_ci total_sz += sz; 651862306a36Sopenharmony_ci 651962306a36Sopenharmony_ci dinitprintk(ioc, 652062306a36Sopenharmony_ci ioc_info(ioc, "scsiio(0x%p): depth(%d)\n", 652162306a36Sopenharmony_ci ioc->request, ioc->scsiio_depth)); 652262306a36Sopenharmony_ci 652362306a36Sopenharmony_ci ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH); 652462306a36Sopenharmony_ci sz = ioc->scsiio_depth * sizeof(struct chain_lookup); 652562306a36Sopenharmony_ci ioc->chain_lookup = kzalloc(sz, GFP_KERNEL); 652662306a36Sopenharmony_ci if (!ioc->chain_lookup) { 652762306a36Sopenharmony_ci ioc_err(ioc, "chain_lookup: __get_free_pages failed\n"); 652862306a36Sopenharmony_ci goto out; 652962306a36Sopenharmony_ci } 653062306a36Sopenharmony_ci 653162306a36Sopenharmony_ci sz = ioc->chains_needed_per_io * sizeof(struct chain_tracker); 653262306a36Sopenharmony_ci for (i = 0; i < ioc->scsiio_depth; i++) { 653362306a36Sopenharmony_ci ioc->chain_lookup[i].chains_per_smid = kzalloc(sz, GFP_KERNEL); 653462306a36Sopenharmony_ci if (!ioc->chain_lookup[i].chains_per_smid) { 653562306a36Sopenharmony_ci ioc_err(ioc, "chain_lookup: kzalloc failed\n"); 653662306a36Sopenharmony_ci goto out; 653762306a36Sopenharmony_ci } 653862306a36Sopenharmony_ci } 653962306a36Sopenharmony_ci 654062306a36Sopenharmony_ci /* initialize hi-priority queue smid's */ 654162306a36Sopenharmony_ci ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth, 654262306a36Sopenharmony_ci sizeof(struct request_tracker), GFP_KERNEL); 654362306a36Sopenharmony_ci if (!ioc->hpr_lookup) { 654462306a36Sopenharmony_ci ioc_err(ioc, "hpr_lookup: kcalloc failed\n"); 654562306a36Sopenharmony_ci goto out; 654662306a36Sopenharmony_ci } 654762306a36Sopenharmony_ci ioc->hi_priority_smid = ioc->scsiio_depth + 1; 654862306a36Sopenharmony_ci dinitprintk(ioc, 654962306a36Sopenharmony_ci ioc_info(ioc, "hi_priority(0x%p): depth(%d), start smid(%d)\n", 655062306a36Sopenharmony_ci ioc->hi_priority, 655162306a36Sopenharmony_ci ioc->hi_priority_depth, ioc->hi_priority_smid)); 655262306a36Sopenharmony_ci 655362306a36Sopenharmony_ci /* initialize internal queue smid's */ 655462306a36Sopenharmony_ci ioc->internal_lookup = kcalloc(ioc->internal_depth, 655562306a36Sopenharmony_ci sizeof(struct request_tracker), GFP_KERNEL); 655662306a36Sopenharmony_ci if (!ioc->internal_lookup) { 655762306a36Sopenharmony_ci ioc_err(ioc, "internal_lookup: kcalloc failed\n"); 655862306a36Sopenharmony_ci goto out; 655962306a36Sopenharmony_ci } 656062306a36Sopenharmony_ci ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth; 656162306a36Sopenharmony_ci dinitprintk(ioc, 656262306a36Sopenharmony_ci ioc_info(ioc, "internal(0x%p): depth(%d), start smid(%d)\n", 656362306a36Sopenharmony_ci ioc->internal, 656462306a36Sopenharmony_ci ioc->internal_depth, ioc->internal_smid)); 656562306a36Sopenharmony_ci 656662306a36Sopenharmony_ci ioc->io_queue_num = kcalloc(ioc->scsiio_depth, 656762306a36Sopenharmony_ci sizeof(u16), GFP_KERNEL); 656862306a36Sopenharmony_ci if (!ioc->io_queue_num) 656962306a36Sopenharmony_ci goto out; 657062306a36Sopenharmony_ci /* 657162306a36Sopenharmony_ci * The number of NVMe page sized blocks needed is: 657262306a36Sopenharmony_ci * (((sg_tablesize * 8) - 1) / (page_size - 8)) + 1 657362306a36Sopenharmony_ci * ((sg_tablesize * 8) - 1) is the max PRP's minus the first PRP entry 657462306a36Sopenharmony_ci * that is placed in the main message frame. 8 is the size of each PRP 657562306a36Sopenharmony_ci * entry or PRP list pointer entry. 8 is subtracted from page_size 657662306a36Sopenharmony_ci * because of the PRP list pointer entry at the end of a page, so this 657762306a36Sopenharmony_ci * is not counted as a PRP entry. The 1 added page is a round up. 657862306a36Sopenharmony_ci * 657962306a36Sopenharmony_ci * To avoid allocation failures due to the amount of memory that could 658062306a36Sopenharmony_ci * be required for NVMe PRP's, only each set of NVMe blocks will be 658162306a36Sopenharmony_ci * contiguous, so a new set is allocated for each possible I/O. 658262306a36Sopenharmony_ci */ 658362306a36Sopenharmony_ci 658462306a36Sopenharmony_ci ioc->chains_per_prp_buffer = 0; 658562306a36Sopenharmony_ci if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_NVME_DEVICES) { 658662306a36Sopenharmony_ci nvme_blocks_needed = 658762306a36Sopenharmony_ci (ioc->shost->sg_tablesize * NVME_PRP_SIZE) - 1; 658862306a36Sopenharmony_ci nvme_blocks_needed /= (ioc->page_size - NVME_PRP_SIZE); 658962306a36Sopenharmony_ci nvme_blocks_needed++; 659062306a36Sopenharmony_ci 659162306a36Sopenharmony_ci sz = sizeof(struct pcie_sg_list) * ioc->scsiio_depth; 659262306a36Sopenharmony_ci ioc->pcie_sg_lookup = kzalloc(sz, GFP_KERNEL); 659362306a36Sopenharmony_ci if (!ioc->pcie_sg_lookup) { 659462306a36Sopenharmony_ci ioc_info(ioc, "PCIe SGL lookup: kzalloc failed\n"); 659562306a36Sopenharmony_ci goto out; 659662306a36Sopenharmony_ci } 659762306a36Sopenharmony_ci sz = nvme_blocks_needed * ioc->page_size; 659862306a36Sopenharmony_ci rc = _base_allocate_pcie_sgl_pool(ioc, sz); 659962306a36Sopenharmony_ci if (rc == -ENOMEM) 660062306a36Sopenharmony_ci return -ENOMEM; 660162306a36Sopenharmony_ci else if (rc == -EAGAIN) 660262306a36Sopenharmony_ci goto try_32bit_dma; 660362306a36Sopenharmony_ci total_sz += sz * ioc->scsiio_depth; 660462306a36Sopenharmony_ci } 660562306a36Sopenharmony_ci 660662306a36Sopenharmony_ci rc = _base_allocate_chain_dma_pool(ioc, ioc->chain_segment_sz); 660762306a36Sopenharmony_ci if (rc == -ENOMEM) 660862306a36Sopenharmony_ci return -ENOMEM; 660962306a36Sopenharmony_ci else if (rc == -EAGAIN) 661062306a36Sopenharmony_ci goto try_32bit_dma; 661162306a36Sopenharmony_ci total_sz += ioc->chain_segment_sz * ((ioc->chains_needed_per_io - 661262306a36Sopenharmony_ci ioc->chains_per_prp_buffer) * ioc->scsiio_depth); 661362306a36Sopenharmony_ci dinitprintk(ioc, 661462306a36Sopenharmony_ci ioc_info(ioc, "chain pool depth(%d), frame_size(%d), pool_size(%d kB)\n", 661562306a36Sopenharmony_ci ioc->chain_depth, ioc->chain_segment_sz, 661662306a36Sopenharmony_ci (ioc->chain_depth * ioc->chain_segment_sz) / 1024)); 661762306a36Sopenharmony_ci /* sense buffers, 4 byte align */ 661862306a36Sopenharmony_ci sense_sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE; 661962306a36Sopenharmony_ci rc = _base_allocate_sense_dma_pool(ioc, sense_sz); 662062306a36Sopenharmony_ci if (rc == -ENOMEM) 662162306a36Sopenharmony_ci return -ENOMEM; 662262306a36Sopenharmony_ci else if (rc == -EAGAIN) 662362306a36Sopenharmony_ci goto try_32bit_dma; 662462306a36Sopenharmony_ci total_sz += sense_sz; 662562306a36Sopenharmony_ci /* reply pool, 4 byte align */ 662662306a36Sopenharmony_ci sz = ioc->reply_free_queue_depth * ioc->reply_sz; 662762306a36Sopenharmony_ci rc = _base_allocate_reply_pool(ioc, sz); 662862306a36Sopenharmony_ci if (rc == -ENOMEM) 662962306a36Sopenharmony_ci return -ENOMEM; 663062306a36Sopenharmony_ci else if (rc == -EAGAIN) 663162306a36Sopenharmony_ci goto try_32bit_dma; 663262306a36Sopenharmony_ci total_sz += sz; 663362306a36Sopenharmony_ci 663462306a36Sopenharmony_ci /* reply free queue, 16 byte align */ 663562306a36Sopenharmony_ci sz = ioc->reply_free_queue_depth * 4; 663662306a36Sopenharmony_ci rc = _base_allocate_reply_free_dma_pool(ioc, sz); 663762306a36Sopenharmony_ci if (rc == -ENOMEM) 663862306a36Sopenharmony_ci return -ENOMEM; 663962306a36Sopenharmony_ci else if (rc == -EAGAIN) 664062306a36Sopenharmony_ci goto try_32bit_dma; 664162306a36Sopenharmony_ci dinitprintk(ioc, 664262306a36Sopenharmony_ci ioc_info(ioc, "reply_free_dma (0x%llx)\n", 664362306a36Sopenharmony_ci (unsigned long long)ioc->reply_free_dma)); 664462306a36Sopenharmony_ci total_sz += sz; 664562306a36Sopenharmony_ci if (ioc->rdpq_array_enable) { 664662306a36Sopenharmony_ci reply_post_free_array_sz = ioc->reply_queue_count * 664762306a36Sopenharmony_ci sizeof(Mpi2IOCInitRDPQArrayEntry); 664862306a36Sopenharmony_ci rc = _base_allocate_reply_post_free_array(ioc, 664962306a36Sopenharmony_ci reply_post_free_array_sz); 665062306a36Sopenharmony_ci if (rc == -ENOMEM) 665162306a36Sopenharmony_ci return -ENOMEM; 665262306a36Sopenharmony_ci else if (rc == -EAGAIN) 665362306a36Sopenharmony_ci goto try_32bit_dma; 665462306a36Sopenharmony_ci } 665562306a36Sopenharmony_ci ioc->config_page_sz = 512; 665662306a36Sopenharmony_ci ioc->config_page = dma_alloc_coherent(&ioc->pdev->dev, 665762306a36Sopenharmony_ci ioc->config_page_sz, &ioc->config_page_dma, GFP_KERNEL); 665862306a36Sopenharmony_ci if (!ioc->config_page) { 665962306a36Sopenharmony_ci ioc_err(ioc, "config page: dma_pool_alloc failed\n"); 666062306a36Sopenharmony_ci goto out; 666162306a36Sopenharmony_ci } 666262306a36Sopenharmony_ci 666362306a36Sopenharmony_ci ioc_info(ioc, "config page(0x%p) - dma(0x%llx): size(%d)\n", 666462306a36Sopenharmony_ci ioc->config_page, (unsigned long long)ioc->config_page_dma, 666562306a36Sopenharmony_ci ioc->config_page_sz); 666662306a36Sopenharmony_ci total_sz += ioc->config_page_sz; 666762306a36Sopenharmony_ci 666862306a36Sopenharmony_ci ioc_info(ioc, "Allocated physical memory: size(%d kB)\n", 666962306a36Sopenharmony_ci total_sz / 1024); 667062306a36Sopenharmony_ci ioc_info(ioc, "Current Controller Queue Depth(%d),Max Controller Queue Depth(%d)\n", 667162306a36Sopenharmony_ci ioc->shost->can_queue, facts->RequestCredit); 667262306a36Sopenharmony_ci ioc_info(ioc, "Scatter Gather Elements per IO(%d)\n", 667362306a36Sopenharmony_ci ioc->shost->sg_tablesize); 667462306a36Sopenharmony_ci return 0; 667562306a36Sopenharmony_ci 667662306a36Sopenharmony_citry_32bit_dma: 667762306a36Sopenharmony_ci _base_release_memory_pools(ioc); 667862306a36Sopenharmony_ci if (ioc->use_32bit_dma && (ioc->dma_mask > 32)) { 667962306a36Sopenharmony_ci /* Change dma coherent mask to 32 bit and reallocate */ 668062306a36Sopenharmony_ci if (_base_config_dma_addressing(ioc, ioc->pdev) != 0) { 668162306a36Sopenharmony_ci pr_err("Setting 32 bit coherent DMA mask Failed %s\n", 668262306a36Sopenharmony_ci pci_name(ioc->pdev)); 668362306a36Sopenharmony_ci return -ENODEV; 668462306a36Sopenharmony_ci } 668562306a36Sopenharmony_ci } else if (_base_reduce_hba_queue_depth(ioc) != 0) 668662306a36Sopenharmony_ci return -ENOMEM; 668762306a36Sopenharmony_ci goto retry_allocation; 668862306a36Sopenharmony_ci 668962306a36Sopenharmony_ci out: 669062306a36Sopenharmony_ci return -ENOMEM; 669162306a36Sopenharmony_ci} 669262306a36Sopenharmony_ci 669362306a36Sopenharmony_ci/** 669462306a36Sopenharmony_ci * mpt3sas_base_get_iocstate - Get the current state of a MPT adapter. 669562306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 669662306a36Sopenharmony_ci * @cooked: Request raw or cooked IOC state 669762306a36Sopenharmony_ci * 669862306a36Sopenharmony_ci * Return: all IOC Doorbell register bits if cooked==0, else just the 669962306a36Sopenharmony_ci * Doorbell bits in MPI_IOC_STATE_MASK. 670062306a36Sopenharmony_ci */ 670162306a36Sopenharmony_ciu32 670262306a36Sopenharmony_cimpt3sas_base_get_iocstate(struct MPT3SAS_ADAPTER *ioc, int cooked) 670362306a36Sopenharmony_ci{ 670462306a36Sopenharmony_ci u32 s, sc; 670562306a36Sopenharmony_ci 670662306a36Sopenharmony_ci s = ioc->base_readl_ext_retry(&ioc->chip->Doorbell); 670762306a36Sopenharmony_ci sc = s & MPI2_IOC_STATE_MASK; 670862306a36Sopenharmony_ci return cooked ? sc : s; 670962306a36Sopenharmony_ci} 671062306a36Sopenharmony_ci 671162306a36Sopenharmony_ci/** 671262306a36Sopenharmony_ci * _base_wait_on_iocstate - waiting on a particular ioc state 671362306a36Sopenharmony_ci * @ioc: ? 671462306a36Sopenharmony_ci * @ioc_state: controller state { READY, OPERATIONAL, or RESET } 671562306a36Sopenharmony_ci * @timeout: timeout in second 671662306a36Sopenharmony_ci * 671762306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 671862306a36Sopenharmony_ci */ 671962306a36Sopenharmony_cistatic int 672062306a36Sopenharmony_ci_base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout) 672162306a36Sopenharmony_ci{ 672262306a36Sopenharmony_ci u32 count, cntdn; 672362306a36Sopenharmony_ci u32 current_state; 672462306a36Sopenharmony_ci 672562306a36Sopenharmony_ci count = 0; 672662306a36Sopenharmony_ci cntdn = 1000 * timeout; 672762306a36Sopenharmony_ci do { 672862306a36Sopenharmony_ci current_state = mpt3sas_base_get_iocstate(ioc, 1); 672962306a36Sopenharmony_ci if (current_state == ioc_state) 673062306a36Sopenharmony_ci return 0; 673162306a36Sopenharmony_ci if (count && current_state == MPI2_IOC_STATE_FAULT) 673262306a36Sopenharmony_ci break; 673362306a36Sopenharmony_ci if (count && current_state == MPI2_IOC_STATE_COREDUMP) 673462306a36Sopenharmony_ci break; 673562306a36Sopenharmony_ci 673662306a36Sopenharmony_ci usleep_range(1000, 1500); 673762306a36Sopenharmony_ci count++; 673862306a36Sopenharmony_ci } while (--cntdn); 673962306a36Sopenharmony_ci 674062306a36Sopenharmony_ci return current_state; 674162306a36Sopenharmony_ci} 674262306a36Sopenharmony_ci 674362306a36Sopenharmony_ci/** 674462306a36Sopenharmony_ci * _base_dump_reg_set - This function will print hexdump of register set. 674562306a36Sopenharmony_ci * @ioc: per adapter object 674662306a36Sopenharmony_ci * 674762306a36Sopenharmony_ci * Return: nothing. 674862306a36Sopenharmony_ci */ 674962306a36Sopenharmony_cistatic inline void 675062306a36Sopenharmony_ci_base_dump_reg_set(struct MPT3SAS_ADAPTER *ioc) 675162306a36Sopenharmony_ci{ 675262306a36Sopenharmony_ci unsigned int i, sz = 256; 675362306a36Sopenharmony_ci u32 __iomem *reg = (u32 __iomem *)ioc->chip; 675462306a36Sopenharmony_ci 675562306a36Sopenharmony_ci ioc_info(ioc, "System Register set:\n"); 675662306a36Sopenharmony_ci for (i = 0; i < (sz / sizeof(u32)); i++) 675762306a36Sopenharmony_ci pr_info("%08x: %08x\n", (i * 4), readl(®[i])); 675862306a36Sopenharmony_ci} 675962306a36Sopenharmony_ci 676062306a36Sopenharmony_ci/** 676162306a36Sopenharmony_ci * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by 676262306a36Sopenharmony_ci * a write to the doorbell) 676362306a36Sopenharmony_ci * @ioc: per adapter object 676462306a36Sopenharmony_ci * @timeout: timeout in seconds 676562306a36Sopenharmony_ci * 676662306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 676762306a36Sopenharmony_ci * 676862306a36Sopenharmony_ci * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell. 676962306a36Sopenharmony_ci */ 677062306a36Sopenharmony_ci 677162306a36Sopenharmony_cistatic int 677262306a36Sopenharmony_ci_base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout) 677362306a36Sopenharmony_ci{ 677462306a36Sopenharmony_ci u32 cntdn, count; 677562306a36Sopenharmony_ci u32 int_status; 677662306a36Sopenharmony_ci 677762306a36Sopenharmony_ci count = 0; 677862306a36Sopenharmony_ci cntdn = 1000 * timeout; 677962306a36Sopenharmony_ci do { 678062306a36Sopenharmony_ci int_status = ioc->base_readl(&ioc->chip->HostInterruptStatus); 678162306a36Sopenharmony_ci if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { 678262306a36Sopenharmony_ci dhsprintk(ioc, 678362306a36Sopenharmony_ci ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n", 678462306a36Sopenharmony_ci __func__, count, timeout)); 678562306a36Sopenharmony_ci return 0; 678662306a36Sopenharmony_ci } 678762306a36Sopenharmony_ci 678862306a36Sopenharmony_ci usleep_range(1000, 1500); 678962306a36Sopenharmony_ci count++; 679062306a36Sopenharmony_ci } while (--cntdn); 679162306a36Sopenharmony_ci 679262306a36Sopenharmony_ci ioc_err(ioc, "%s: failed due to timeout count(%d), int_status(%x)!\n", 679362306a36Sopenharmony_ci __func__, count, int_status); 679462306a36Sopenharmony_ci return -EFAULT; 679562306a36Sopenharmony_ci} 679662306a36Sopenharmony_ci 679762306a36Sopenharmony_cistatic int 679862306a36Sopenharmony_ci_base_spin_on_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout) 679962306a36Sopenharmony_ci{ 680062306a36Sopenharmony_ci u32 cntdn, count; 680162306a36Sopenharmony_ci u32 int_status; 680262306a36Sopenharmony_ci 680362306a36Sopenharmony_ci count = 0; 680462306a36Sopenharmony_ci cntdn = 2000 * timeout; 680562306a36Sopenharmony_ci do { 680662306a36Sopenharmony_ci int_status = ioc->base_readl(&ioc->chip->HostInterruptStatus); 680762306a36Sopenharmony_ci if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { 680862306a36Sopenharmony_ci dhsprintk(ioc, 680962306a36Sopenharmony_ci ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n", 681062306a36Sopenharmony_ci __func__, count, timeout)); 681162306a36Sopenharmony_ci return 0; 681262306a36Sopenharmony_ci } 681362306a36Sopenharmony_ci 681462306a36Sopenharmony_ci udelay(500); 681562306a36Sopenharmony_ci count++; 681662306a36Sopenharmony_ci } while (--cntdn); 681762306a36Sopenharmony_ci 681862306a36Sopenharmony_ci ioc_err(ioc, "%s: failed due to timeout count(%d), int_status(%x)!\n", 681962306a36Sopenharmony_ci __func__, count, int_status); 682062306a36Sopenharmony_ci return -EFAULT; 682162306a36Sopenharmony_ci 682262306a36Sopenharmony_ci} 682362306a36Sopenharmony_ci 682462306a36Sopenharmony_ci/** 682562306a36Sopenharmony_ci * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell. 682662306a36Sopenharmony_ci * @ioc: per adapter object 682762306a36Sopenharmony_ci * @timeout: timeout in second 682862306a36Sopenharmony_ci * 682962306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 683062306a36Sopenharmony_ci * 683162306a36Sopenharmony_ci * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to 683262306a36Sopenharmony_ci * doorbell. 683362306a36Sopenharmony_ci */ 683462306a36Sopenharmony_cistatic int 683562306a36Sopenharmony_ci_base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout) 683662306a36Sopenharmony_ci{ 683762306a36Sopenharmony_ci u32 cntdn, count; 683862306a36Sopenharmony_ci u32 int_status; 683962306a36Sopenharmony_ci u32 doorbell; 684062306a36Sopenharmony_ci 684162306a36Sopenharmony_ci count = 0; 684262306a36Sopenharmony_ci cntdn = 1000 * timeout; 684362306a36Sopenharmony_ci do { 684462306a36Sopenharmony_ci int_status = ioc->base_readl(&ioc->chip->HostInterruptStatus); 684562306a36Sopenharmony_ci if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) { 684662306a36Sopenharmony_ci dhsprintk(ioc, 684762306a36Sopenharmony_ci ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n", 684862306a36Sopenharmony_ci __func__, count, timeout)); 684962306a36Sopenharmony_ci return 0; 685062306a36Sopenharmony_ci } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { 685162306a36Sopenharmony_ci doorbell = ioc->base_readl_ext_retry(&ioc->chip->Doorbell); 685262306a36Sopenharmony_ci if ((doorbell & MPI2_IOC_STATE_MASK) == 685362306a36Sopenharmony_ci MPI2_IOC_STATE_FAULT) { 685462306a36Sopenharmony_ci mpt3sas_print_fault_code(ioc, doorbell); 685562306a36Sopenharmony_ci return -EFAULT; 685662306a36Sopenharmony_ci } 685762306a36Sopenharmony_ci if ((doorbell & MPI2_IOC_STATE_MASK) == 685862306a36Sopenharmony_ci MPI2_IOC_STATE_COREDUMP) { 685962306a36Sopenharmony_ci mpt3sas_print_coredump_info(ioc, doorbell); 686062306a36Sopenharmony_ci return -EFAULT; 686162306a36Sopenharmony_ci } 686262306a36Sopenharmony_ci } else if (int_status == 0xFFFFFFFF) 686362306a36Sopenharmony_ci goto out; 686462306a36Sopenharmony_ci 686562306a36Sopenharmony_ci usleep_range(1000, 1500); 686662306a36Sopenharmony_ci count++; 686762306a36Sopenharmony_ci } while (--cntdn); 686862306a36Sopenharmony_ci 686962306a36Sopenharmony_ci out: 687062306a36Sopenharmony_ci ioc_err(ioc, "%s: failed due to timeout count(%d), int_status(%x)!\n", 687162306a36Sopenharmony_ci __func__, count, int_status); 687262306a36Sopenharmony_ci return -EFAULT; 687362306a36Sopenharmony_ci} 687462306a36Sopenharmony_ci 687562306a36Sopenharmony_ci/** 687662306a36Sopenharmony_ci * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use 687762306a36Sopenharmony_ci * @ioc: per adapter object 687862306a36Sopenharmony_ci * @timeout: timeout in second 687962306a36Sopenharmony_ci * 688062306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 688162306a36Sopenharmony_ci */ 688262306a36Sopenharmony_cistatic int 688362306a36Sopenharmony_ci_base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout) 688462306a36Sopenharmony_ci{ 688562306a36Sopenharmony_ci u32 cntdn, count; 688662306a36Sopenharmony_ci u32 doorbell_reg; 688762306a36Sopenharmony_ci 688862306a36Sopenharmony_ci count = 0; 688962306a36Sopenharmony_ci cntdn = 1000 * timeout; 689062306a36Sopenharmony_ci do { 689162306a36Sopenharmony_ci doorbell_reg = ioc->base_readl_ext_retry(&ioc->chip->Doorbell); 689262306a36Sopenharmony_ci if (!(doorbell_reg & MPI2_DOORBELL_USED)) { 689362306a36Sopenharmony_ci dhsprintk(ioc, 689462306a36Sopenharmony_ci ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n", 689562306a36Sopenharmony_ci __func__, count, timeout)); 689662306a36Sopenharmony_ci return 0; 689762306a36Sopenharmony_ci } 689862306a36Sopenharmony_ci 689962306a36Sopenharmony_ci usleep_range(1000, 1500); 690062306a36Sopenharmony_ci count++; 690162306a36Sopenharmony_ci } while (--cntdn); 690262306a36Sopenharmony_ci 690362306a36Sopenharmony_ci ioc_err(ioc, "%s: failed due to timeout count(%d), doorbell_reg(%x)!\n", 690462306a36Sopenharmony_ci __func__, count, doorbell_reg); 690562306a36Sopenharmony_ci return -EFAULT; 690662306a36Sopenharmony_ci} 690762306a36Sopenharmony_ci 690862306a36Sopenharmony_ci/** 690962306a36Sopenharmony_ci * _base_send_ioc_reset - send doorbell reset 691062306a36Sopenharmony_ci * @ioc: per adapter object 691162306a36Sopenharmony_ci * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET 691262306a36Sopenharmony_ci * @timeout: timeout in second 691362306a36Sopenharmony_ci * 691462306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 691562306a36Sopenharmony_ci */ 691662306a36Sopenharmony_cistatic int 691762306a36Sopenharmony_ci_base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout) 691862306a36Sopenharmony_ci{ 691962306a36Sopenharmony_ci u32 ioc_state; 692062306a36Sopenharmony_ci int r = 0; 692162306a36Sopenharmony_ci unsigned long flags; 692262306a36Sopenharmony_ci 692362306a36Sopenharmony_ci if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) { 692462306a36Sopenharmony_ci ioc_err(ioc, "%s: unknown reset_type\n", __func__); 692562306a36Sopenharmony_ci return -EFAULT; 692662306a36Sopenharmony_ci } 692762306a36Sopenharmony_ci 692862306a36Sopenharmony_ci if (!(ioc->facts.IOCCapabilities & 692962306a36Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY)) 693062306a36Sopenharmony_ci return -EFAULT; 693162306a36Sopenharmony_ci 693262306a36Sopenharmony_ci ioc_info(ioc, "sending message unit reset !!\n"); 693362306a36Sopenharmony_ci 693462306a36Sopenharmony_ci writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT, 693562306a36Sopenharmony_ci &ioc->chip->Doorbell); 693662306a36Sopenharmony_ci if ((_base_wait_for_doorbell_ack(ioc, 15))) { 693762306a36Sopenharmony_ci r = -EFAULT; 693862306a36Sopenharmony_ci goto out; 693962306a36Sopenharmony_ci } 694062306a36Sopenharmony_ci 694162306a36Sopenharmony_ci ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout); 694262306a36Sopenharmony_ci if (ioc_state) { 694362306a36Sopenharmony_ci ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n", 694462306a36Sopenharmony_ci __func__, ioc_state); 694562306a36Sopenharmony_ci r = -EFAULT; 694662306a36Sopenharmony_ci goto out; 694762306a36Sopenharmony_ci } 694862306a36Sopenharmony_ci out: 694962306a36Sopenharmony_ci if (r != 0) { 695062306a36Sopenharmony_ci ioc_state = mpt3sas_base_get_iocstate(ioc, 0); 695162306a36Sopenharmony_ci spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); 695262306a36Sopenharmony_ci /* 695362306a36Sopenharmony_ci * Wait for IOC state CoreDump to clear only during 695462306a36Sopenharmony_ci * HBA initialization & release time. 695562306a36Sopenharmony_ci */ 695662306a36Sopenharmony_ci if ((ioc_state & MPI2_IOC_STATE_MASK) == 695762306a36Sopenharmony_ci MPI2_IOC_STATE_COREDUMP && (ioc->is_driver_loading == 1 || 695862306a36Sopenharmony_ci ioc->fault_reset_work_q == NULL)) { 695962306a36Sopenharmony_ci spin_unlock_irqrestore( 696062306a36Sopenharmony_ci &ioc->ioc_reset_in_progress_lock, flags); 696162306a36Sopenharmony_ci mpt3sas_print_coredump_info(ioc, ioc_state); 696262306a36Sopenharmony_ci mpt3sas_base_wait_for_coredump_completion(ioc, 696362306a36Sopenharmony_ci __func__); 696462306a36Sopenharmony_ci spin_lock_irqsave( 696562306a36Sopenharmony_ci &ioc->ioc_reset_in_progress_lock, flags); 696662306a36Sopenharmony_ci } 696762306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); 696862306a36Sopenharmony_ci } 696962306a36Sopenharmony_ci ioc_info(ioc, "message unit reset: %s\n", 697062306a36Sopenharmony_ci r == 0 ? "SUCCESS" : "FAILED"); 697162306a36Sopenharmony_ci return r; 697262306a36Sopenharmony_ci} 697362306a36Sopenharmony_ci 697462306a36Sopenharmony_ci/** 697562306a36Sopenharmony_ci * mpt3sas_wait_for_ioc - IOC's operational state is checked here. 697662306a36Sopenharmony_ci * @ioc: per adapter object 697762306a36Sopenharmony_ci * @timeout: timeout in seconds 697862306a36Sopenharmony_ci * 697962306a36Sopenharmony_ci * Return: Waits up to timeout seconds for the IOC to 698062306a36Sopenharmony_ci * become operational. Returns 0 if IOC is present 698162306a36Sopenharmony_ci * and operational; otherwise returns %-EFAULT. 698262306a36Sopenharmony_ci */ 698362306a36Sopenharmony_ci 698462306a36Sopenharmony_ciint 698562306a36Sopenharmony_cimpt3sas_wait_for_ioc(struct MPT3SAS_ADAPTER *ioc, int timeout) 698662306a36Sopenharmony_ci{ 698762306a36Sopenharmony_ci int wait_state_count = 0; 698862306a36Sopenharmony_ci u32 ioc_state; 698962306a36Sopenharmony_ci 699062306a36Sopenharmony_ci do { 699162306a36Sopenharmony_ci ioc_state = mpt3sas_base_get_iocstate(ioc, 1); 699262306a36Sopenharmony_ci if (ioc_state == MPI2_IOC_STATE_OPERATIONAL) 699362306a36Sopenharmony_ci break; 699462306a36Sopenharmony_ci 699562306a36Sopenharmony_ci /* 699662306a36Sopenharmony_ci * Watchdog thread will be started after IOC Initialization, so 699762306a36Sopenharmony_ci * no need to wait here for IOC state to become operational 699862306a36Sopenharmony_ci * when IOC Initialization is on. Instead the driver will 699962306a36Sopenharmony_ci * return ETIME status, so that calling function can issue 700062306a36Sopenharmony_ci * diag reset operation and retry the command. 700162306a36Sopenharmony_ci */ 700262306a36Sopenharmony_ci if (ioc->is_driver_loading) 700362306a36Sopenharmony_ci return -ETIME; 700462306a36Sopenharmony_ci 700562306a36Sopenharmony_ci ssleep(1); 700662306a36Sopenharmony_ci ioc_info(ioc, "%s: waiting for operational state(count=%d)\n", 700762306a36Sopenharmony_ci __func__, ++wait_state_count); 700862306a36Sopenharmony_ci } while (--timeout); 700962306a36Sopenharmony_ci if (!timeout) { 701062306a36Sopenharmony_ci ioc_err(ioc, "%s: failed due to ioc not operational\n", __func__); 701162306a36Sopenharmony_ci return -EFAULT; 701262306a36Sopenharmony_ci } 701362306a36Sopenharmony_ci if (wait_state_count) 701462306a36Sopenharmony_ci ioc_info(ioc, "ioc is operational\n"); 701562306a36Sopenharmony_ci return 0; 701662306a36Sopenharmony_ci} 701762306a36Sopenharmony_ci 701862306a36Sopenharmony_ci/** 701962306a36Sopenharmony_ci * _base_handshake_req_reply_wait - send request thru doorbell interface 702062306a36Sopenharmony_ci * @ioc: per adapter object 702162306a36Sopenharmony_ci * @request_bytes: request length 702262306a36Sopenharmony_ci * @request: pointer having request payload 702362306a36Sopenharmony_ci * @reply_bytes: reply length 702462306a36Sopenharmony_ci * @reply: pointer to reply payload 702562306a36Sopenharmony_ci * @timeout: timeout in second 702662306a36Sopenharmony_ci * 702762306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 702862306a36Sopenharmony_ci */ 702962306a36Sopenharmony_cistatic int 703062306a36Sopenharmony_ci_base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, 703162306a36Sopenharmony_ci u32 *request, int reply_bytes, u16 *reply, int timeout) 703262306a36Sopenharmony_ci{ 703362306a36Sopenharmony_ci MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply; 703462306a36Sopenharmony_ci int i; 703562306a36Sopenharmony_ci u8 failed; 703662306a36Sopenharmony_ci __le32 *mfp; 703762306a36Sopenharmony_ci 703862306a36Sopenharmony_ci /* make sure doorbell is not in use */ 703962306a36Sopenharmony_ci if ((ioc->base_readl_ext_retry(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) { 704062306a36Sopenharmony_ci ioc_err(ioc, "doorbell is in use (line=%d)\n", __LINE__); 704162306a36Sopenharmony_ci return -EFAULT; 704262306a36Sopenharmony_ci } 704362306a36Sopenharmony_ci 704462306a36Sopenharmony_ci /* clear pending doorbell interrupts from previous state changes */ 704562306a36Sopenharmony_ci if (ioc->base_readl(&ioc->chip->HostInterruptStatus) & 704662306a36Sopenharmony_ci MPI2_HIS_IOC2SYS_DB_STATUS) 704762306a36Sopenharmony_ci writel(0, &ioc->chip->HostInterruptStatus); 704862306a36Sopenharmony_ci 704962306a36Sopenharmony_ci /* send message to ioc */ 705062306a36Sopenharmony_ci writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) | 705162306a36Sopenharmony_ci ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)), 705262306a36Sopenharmony_ci &ioc->chip->Doorbell); 705362306a36Sopenharmony_ci 705462306a36Sopenharmony_ci if ((_base_spin_on_doorbell_int(ioc, 5))) { 705562306a36Sopenharmony_ci ioc_err(ioc, "doorbell handshake int failed (line=%d)\n", 705662306a36Sopenharmony_ci __LINE__); 705762306a36Sopenharmony_ci return -EFAULT; 705862306a36Sopenharmony_ci } 705962306a36Sopenharmony_ci writel(0, &ioc->chip->HostInterruptStatus); 706062306a36Sopenharmony_ci 706162306a36Sopenharmony_ci if ((_base_wait_for_doorbell_ack(ioc, 5))) { 706262306a36Sopenharmony_ci ioc_err(ioc, "doorbell handshake ack failed (line=%d)\n", 706362306a36Sopenharmony_ci __LINE__); 706462306a36Sopenharmony_ci return -EFAULT; 706562306a36Sopenharmony_ci } 706662306a36Sopenharmony_ci 706762306a36Sopenharmony_ci /* send message 32-bits at a time */ 706862306a36Sopenharmony_ci for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) { 706962306a36Sopenharmony_ci writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell); 707062306a36Sopenharmony_ci if ((_base_wait_for_doorbell_ack(ioc, 5))) 707162306a36Sopenharmony_ci failed = 1; 707262306a36Sopenharmony_ci } 707362306a36Sopenharmony_ci 707462306a36Sopenharmony_ci if (failed) { 707562306a36Sopenharmony_ci ioc_err(ioc, "doorbell handshake sending request failed (line=%d)\n", 707662306a36Sopenharmony_ci __LINE__); 707762306a36Sopenharmony_ci return -EFAULT; 707862306a36Sopenharmony_ci } 707962306a36Sopenharmony_ci 708062306a36Sopenharmony_ci /* now wait for the reply */ 708162306a36Sopenharmony_ci if ((_base_wait_for_doorbell_int(ioc, timeout))) { 708262306a36Sopenharmony_ci ioc_err(ioc, "doorbell handshake int failed (line=%d)\n", 708362306a36Sopenharmony_ci __LINE__); 708462306a36Sopenharmony_ci return -EFAULT; 708562306a36Sopenharmony_ci } 708662306a36Sopenharmony_ci 708762306a36Sopenharmony_ci /* read the first two 16-bits, it gives the total length of the reply */ 708862306a36Sopenharmony_ci reply[0] = le16_to_cpu(ioc->base_readl_ext_retry(&ioc->chip->Doorbell) 708962306a36Sopenharmony_ci & MPI2_DOORBELL_DATA_MASK); 709062306a36Sopenharmony_ci writel(0, &ioc->chip->HostInterruptStatus); 709162306a36Sopenharmony_ci if ((_base_wait_for_doorbell_int(ioc, 5))) { 709262306a36Sopenharmony_ci ioc_err(ioc, "doorbell handshake int failed (line=%d)\n", 709362306a36Sopenharmony_ci __LINE__); 709462306a36Sopenharmony_ci return -EFAULT; 709562306a36Sopenharmony_ci } 709662306a36Sopenharmony_ci reply[1] = le16_to_cpu(ioc->base_readl_ext_retry(&ioc->chip->Doorbell) 709762306a36Sopenharmony_ci & MPI2_DOORBELL_DATA_MASK); 709862306a36Sopenharmony_ci writel(0, &ioc->chip->HostInterruptStatus); 709962306a36Sopenharmony_ci 710062306a36Sopenharmony_ci for (i = 2; i < default_reply->MsgLength * 2; i++) { 710162306a36Sopenharmony_ci if ((_base_wait_for_doorbell_int(ioc, 5))) { 710262306a36Sopenharmony_ci ioc_err(ioc, "doorbell handshake int failed (line=%d)\n", 710362306a36Sopenharmony_ci __LINE__); 710462306a36Sopenharmony_ci return -EFAULT; 710562306a36Sopenharmony_ci } 710662306a36Sopenharmony_ci if (i >= reply_bytes/2) /* overflow case */ 710762306a36Sopenharmony_ci ioc->base_readl_ext_retry(&ioc->chip->Doorbell); 710862306a36Sopenharmony_ci else 710962306a36Sopenharmony_ci reply[i] = le16_to_cpu( 711062306a36Sopenharmony_ci ioc->base_readl_ext_retry(&ioc->chip->Doorbell) 711162306a36Sopenharmony_ci & MPI2_DOORBELL_DATA_MASK); 711262306a36Sopenharmony_ci writel(0, &ioc->chip->HostInterruptStatus); 711362306a36Sopenharmony_ci } 711462306a36Sopenharmony_ci 711562306a36Sopenharmony_ci _base_wait_for_doorbell_int(ioc, 5); 711662306a36Sopenharmony_ci if (_base_wait_for_doorbell_not_used(ioc, 5) != 0) { 711762306a36Sopenharmony_ci dhsprintk(ioc, 711862306a36Sopenharmony_ci ioc_info(ioc, "doorbell is in use (line=%d)\n", 711962306a36Sopenharmony_ci __LINE__)); 712062306a36Sopenharmony_ci } 712162306a36Sopenharmony_ci writel(0, &ioc->chip->HostInterruptStatus); 712262306a36Sopenharmony_ci 712362306a36Sopenharmony_ci if (ioc->logging_level & MPT_DEBUG_INIT) { 712462306a36Sopenharmony_ci mfp = (__le32 *)reply; 712562306a36Sopenharmony_ci pr_info("\toffset:data\n"); 712662306a36Sopenharmony_ci for (i = 0; i < reply_bytes/4; i++) 712762306a36Sopenharmony_ci ioc_info(ioc, "\t[0x%02x]:%08x\n", i*4, 712862306a36Sopenharmony_ci le32_to_cpu(mfp[i])); 712962306a36Sopenharmony_ci } 713062306a36Sopenharmony_ci return 0; 713162306a36Sopenharmony_ci} 713262306a36Sopenharmony_ci 713362306a36Sopenharmony_ci/** 713462306a36Sopenharmony_ci * mpt3sas_base_sas_iounit_control - send sas iounit control to FW 713562306a36Sopenharmony_ci * @ioc: per adapter object 713662306a36Sopenharmony_ci * @mpi_reply: the reply payload from FW 713762306a36Sopenharmony_ci * @mpi_request: the request payload sent to FW 713862306a36Sopenharmony_ci * 713962306a36Sopenharmony_ci * The SAS IO Unit Control Request message allows the host to perform low-level 714062306a36Sopenharmony_ci * operations, such as resets on the PHYs of the IO Unit, also allows the host 714162306a36Sopenharmony_ci * to obtain the IOC assigned device handles for a device if it has other 714262306a36Sopenharmony_ci * identifying information about the device, in addition allows the host to 714362306a36Sopenharmony_ci * remove IOC resources associated with the device. 714462306a36Sopenharmony_ci * 714562306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 714662306a36Sopenharmony_ci */ 714762306a36Sopenharmony_ciint 714862306a36Sopenharmony_cimpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, 714962306a36Sopenharmony_ci Mpi2SasIoUnitControlReply_t *mpi_reply, 715062306a36Sopenharmony_ci Mpi2SasIoUnitControlRequest_t *mpi_request) 715162306a36Sopenharmony_ci{ 715262306a36Sopenharmony_ci u16 smid; 715362306a36Sopenharmony_ci u8 issue_reset = 0; 715462306a36Sopenharmony_ci int rc; 715562306a36Sopenharmony_ci void *request; 715662306a36Sopenharmony_ci 715762306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 715862306a36Sopenharmony_ci 715962306a36Sopenharmony_ci mutex_lock(&ioc->base_cmds.mutex); 716062306a36Sopenharmony_ci 716162306a36Sopenharmony_ci if (ioc->base_cmds.status != MPT3_CMD_NOT_USED) { 716262306a36Sopenharmony_ci ioc_err(ioc, "%s: base_cmd in use\n", __func__); 716362306a36Sopenharmony_ci rc = -EAGAIN; 716462306a36Sopenharmony_ci goto out; 716562306a36Sopenharmony_ci } 716662306a36Sopenharmony_ci 716762306a36Sopenharmony_ci rc = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT); 716862306a36Sopenharmony_ci if (rc) 716962306a36Sopenharmony_ci goto out; 717062306a36Sopenharmony_ci 717162306a36Sopenharmony_ci smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx); 717262306a36Sopenharmony_ci if (!smid) { 717362306a36Sopenharmony_ci ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); 717462306a36Sopenharmony_ci rc = -EAGAIN; 717562306a36Sopenharmony_ci goto out; 717662306a36Sopenharmony_ci } 717762306a36Sopenharmony_ci 717862306a36Sopenharmony_ci rc = 0; 717962306a36Sopenharmony_ci ioc->base_cmds.status = MPT3_CMD_PENDING; 718062306a36Sopenharmony_ci request = mpt3sas_base_get_msg_frame(ioc, smid); 718162306a36Sopenharmony_ci ioc->base_cmds.smid = smid; 718262306a36Sopenharmony_ci memcpy(request, mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)); 718362306a36Sopenharmony_ci if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || 718462306a36Sopenharmony_ci mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) 718562306a36Sopenharmony_ci ioc->ioc_link_reset_in_progress = 1; 718662306a36Sopenharmony_ci init_completion(&ioc->base_cmds.done); 718762306a36Sopenharmony_ci ioc->put_smid_default(ioc, smid); 718862306a36Sopenharmony_ci wait_for_completion_timeout(&ioc->base_cmds.done, 718962306a36Sopenharmony_ci msecs_to_jiffies(10000)); 719062306a36Sopenharmony_ci if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || 719162306a36Sopenharmony_ci mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) && 719262306a36Sopenharmony_ci ioc->ioc_link_reset_in_progress) 719362306a36Sopenharmony_ci ioc->ioc_link_reset_in_progress = 0; 719462306a36Sopenharmony_ci if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { 719562306a36Sopenharmony_ci mpt3sas_check_cmd_timeout(ioc, ioc->base_cmds.status, 719662306a36Sopenharmony_ci mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)/4, 719762306a36Sopenharmony_ci issue_reset); 719862306a36Sopenharmony_ci goto issue_host_reset; 719962306a36Sopenharmony_ci } 720062306a36Sopenharmony_ci if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID) 720162306a36Sopenharmony_ci memcpy(mpi_reply, ioc->base_cmds.reply, 720262306a36Sopenharmony_ci sizeof(Mpi2SasIoUnitControlReply_t)); 720362306a36Sopenharmony_ci else 720462306a36Sopenharmony_ci memset(mpi_reply, 0, sizeof(Mpi2SasIoUnitControlReply_t)); 720562306a36Sopenharmony_ci ioc->base_cmds.status = MPT3_CMD_NOT_USED; 720662306a36Sopenharmony_ci goto out; 720762306a36Sopenharmony_ci 720862306a36Sopenharmony_ci issue_host_reset: 720962306a36Sopenharmony_ci if (issue_reset) 721062306a36Sopenharmony_ci mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); 721162306a36Sopenharmony_ci ioc->base_cmds.status = MPT3_CMD_NOT_USED; 721262306a36Sopenharmony_ci rc = -EFAULT; 721362306a36Sopenharmony_ci out: 721462306a36Sopenharmony_ci mutex_unlock(&ioc->base_cmds.mutex); 721562306a36Sopenharmony_ci return rc; 721662306a36Sopenharmony_ci} 721762306a36Sopenharmony_ci 721862306a36Sopenharmony_ci/** 721962306a36Sopenharmony_ci * mpt3sas_base_scsi_enclosure_processor - sending request to sep device 722062306a36Sopenharmony_ci * @ioc: per adapter object 722162306a36Sopenharmony_ci * @mpi_reply: the reply payload from FW 722262306a36Sopenharmony_ci * @mpi_request: the request payload sent to FW 722362306a36Sopenharmony_ci * 722462306a36Sopenharmony_ci * The SCSI Enclosure Processor request message causes the IOC to 722562306a36Sopenharmony_ci * communicate with SES devices to control LED status signals. 722662306a36Sopenharmony_ci * 722762306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 722862306a36Sopenharmony_ci */ 722962306a36Sopenharmony_ciint 723062306a36Sopenharmony_cimpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, 723162306a36Sopenharmony_ci Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request) 723262306a36Sopenharmony_ci{ 723362306a36Sopenharmony_ci u16 smid; 723462306a36Sopenharmony_ci u8 issue_reset = 0; 723562306a36Sopenharmony_ci int rc; 723662306a36Sopenharmony_ci void *request; 723762306a36Sopenharmony_ci 723862306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 723962306a36Sopenharmony_ci 724062306a36Sopenharmony_ci mutex_lock(&ioc->base_cmds.mutex); 724162306a36Sopenharmony_ci 724262306a36Sopenharmony_ci if (ioc->base_cmds.status != MPT3_CMD_NOT_USED) { 724362306a36Sopenharmony_ci ioc_err(ioc, "%s: base_cmd in use\n", __func__); 724462306a36Sopenharmony_ci rc = -EAGAIN; 724562306a36Sopenharmony_ci goto out; 724662306a36Sopenharmony_ci } 724762306a36Sopenharmony_ci 724862306a36Sopenharmony_ci rc = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT); 724962306a36Sopenharmony_ci if (rc) 725062306a36Sopenharmony_ci goto out; 725162306a36Sopenharmony_ci 725262306a36Sopenharmony_ci smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx); 725362306a36Sopenharmony_ci if (!smid) { 725462306a36Sopenharmony_ci ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); 725562306a36Sopenharmony_ci rc = -EAGAIN; 725662306a36Sopenharmony_ci goto out; 725762306a36Sopenharmony_ci } 725862306a36Sopenharmony_ci 725962306a36Sopenharmony_ci rc = 0; 726062306a36Sopenharmony_ci ioc->base_cmds.status = MPT3_CMD_PENDING; 726162306a36Sopenharmony_ci request = mpt3sas_base_get_msg_frame(ioc, smid); 726262306a36Sopenharmony_ci ioc->base_cmds.smid = smid; 726362306a36Sopenharmony_ci memset(request, 0, ioc->request_sz); 726462306a36Sopenharmony_ci memcpy(request, mpi_request, sizeof(Mpi2SepReply_t)); 726562306a36Sopenharmony_ci init_completion(&ioc->base_cmds.done); 726662306a36Sopenharmony_ci ioc->put_smid_default(ioc, smid); 726762306a36Sopenharmony_ci wait_for_completion_timeout(&ioc->base_cmds.done, 726862306a36Sopenharmony_ci msecs_to_jiffies(10000)); 726962306a36Sopenharmony_ci if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { 727062306a36Sopenharmony_ci mpt3sas_check_cmd_timeout(ioc, 727162306a36Sopenharmony_ci ioc->base_cmds.status, mpi_request, 727262306a36Sopenharmony_ci sizeof(Mpi2SepRequest_t)/4, issue_reset); 727362306a36Sopenharmony_ci goto issue_host_reset; 727462306a36Sopenharmony_ci } 727562306a36Sopenharmony_ci if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID) 727662306a36Sopenharmony_ci memcpy(mpi_reply, ioc->base_cmds.reply, 727762306a36Sopenharmony_ci sizeof(Mpi2SepReply_t)); 727862306a36Sopenharmony_ci else 727962306a36Sopenharmony_ci memset(mpi_reply, 0, sizeof(Mpi2SepReply_t)); 728062306a36Sopenharmony_ci ioc->base_cmds.status = MPT3_CMD_NOT_USED; 728162306a36Sopenharmony_ci goto out; 728262306a36Sopenharmony_ci 728362306a36Sopenharmony_ci issue_host_reset: 728462306a36Sopenharmony_ci if (issue_reset) 728562306a36Sopenharmony_ci mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); 728662306a36Sopenharmony_ci ioc->base_cmds.status = MPT3_CMD_NOT_USED; 728762306a36Sopenharmony_ci rc = -EFAULT; 728862306a36Sopenharmony_ci out: 728962306a36Sopenharmony_ci mutex_unlock(&ioc->base_cmds.mutex); 729062306a36Sopenharmony_ci return rc; 729162306a36Sopenharmony_ci} 729262306a36Sopenharmony_ci 729362306a36Sopenharmony_ci/** 729462306a36Sopenharmony_ci * _base_get_port_facts - obtain port facts reply and save in ioc 729562306a36Sopenharmony_ci * @ioc: per adapter object 729662306a36Sopenharmony_ci * @port: ? 729762306a36Sopenharmony_ci * 729862306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 729962306a36Sopenharmony_ci */ 730062306a36Sopenharmony_cistatic int 730162306a36Sopenharmony_ci_base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port) 730262306a36Sopenharmony_ci{ 730362306a36Sopenharmony_ci Mpi2PortFactsRequest_t mpi_request; 730462306a36Sopenharmony_ci Mpi2PortFactsReply_t mpi_reply; 730562306a36Sopenharmony_ci struct mpt3sas_port_facts *pfacts; 730662306a36Sopenharmony_ci int mpi_reply_sz, mpi_request_sz, r; 730762306a36Sopenharmony_ci 730862306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 730962306a36Sopenharmony_ci 731062306a36Sopenharmony_ci mpi_reply_sz = sizeof(Mpi2PortFactsReply_t); 731162306a36Sopenharmony_ci mpi_request_sz = sizeof(Mpi2PortFactsRequest_t); 731262306a36Sopenharmony_ci memset(&mpi_request, 0, mpi_request_sz); 731362306a36Sopenharmony_ci mpi_request.Function = MPI2_FUNCTION_PORT_FACTS; 731462306a36Sopenharmony_ci mpi_request.PortNumber = port; 731562306a36Sopenharmony_ci r = _base_handshake_req_reply_wait(ioc, mpi_request_sz, 731662306a36Sopenharmony_ci (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5); 731762306a36Sopenharmony_ci 731862306a36Sopenharmony_ci if (r != 0) { 731962306a36Sopenharmony_ci ioc_err(ioc, "%s: handshake failed (r=%d)\n", __func__, r); 732062306a36Sopenharmony_ci return r; 732162306a36Sopenharmony_ci } 732262306a36Sopenharmony_ci 732362306a36Sopenharmony_ci pfacts = &ioc->pfacts[port]; 732462306a36Sopenharmony_ci memset(pfacts, 0, sizeof(struct mpt3sas_port_facts)); 732562306a36Sopenharmony_ci pfacts->PortNumber = mpi_reply.PortNumber; 732662306a36Sopenharmony_ci pfacts->VP_ID = mpi_reply.VP_ID; 732762306a36Sopenharmony_ci pfacts->VF_ID = mpi_reply.VF_ID; 732862306a36Sopenharmony_ci pfacts->MaxPostedCmdBuffers = 732962306a36Sopenharmony_ci le16_to_cpu(mpi_reply.MaxPostedCmdBuffers); 733062306a36Sopenharmony_ci 733162306a36Sopenharmony_ci return 0; 733262306a36Sopenharmony_ci} 733362306a36Sopenharmony_ci 733462306a36Sopenharmony_ci/** 733562306a36Sopenharmony_ci * _base_wait_for_iocstate - Wait until the card is in READY or OPERATIONAL 733662306a36Sopenharmony_ci * @ioc: per adapter object 733762306a36Sopenharmony_ci * @timeout: 733862306a36Sopenharmony_ci * 733962306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 734062306a36Sopenharmony_ci */ 734162306a36Sopenharmony_cistatic int 734262306a36Sopenharmony_ci_base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout) 734362306a36Sopenharmony_ci{ 734462306a36Sopenharmony_ci u32 ioc_state; 734562306a36Sopenharmony_ci int rc; 734662306a36Sopenharmony_ci 734762306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 734862306a36Sopenharmony_ci 734962306a36Sopenharmony_ci if (ioc->pci_error_recovery) { 735062306a36Sopenharmony_ci dfailprintk(ioc, 735162306a36Sopenharmony_ci ioc_info(ioc, "%s: host in pci error recovery\n", 735262306a36Sopenharmony_ci __func__)); 735362306a36Sopenharmony_ci return -EFAULT; 735462306a36Sopenharmony_ci } 735562306a36Sopenharmony_ci 735662306a36Sopenharmony_ci ioc_state = mpt3sas_base_get_iocstate(ioc, 0); 735762306a36Sopenharmony_ci dhsprintk(ioc, 735862306a36Sopenharmony_ci ioc_info(ioc, "%s: ioc_state(0x%08x)\n", 735962306a36Sopenharmony_ci __func__, ioc_state)); 736062306a36Sopenharmony_ci 736162306a36Sopenharmony_ci if (((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) || 736262306a36Sopenharmony_ci (ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL) 736362306a36Sopenharmony_ci return 0; 736462306a36Sopenharmony_ci 736562306a36Sopenharmony_ci if (ioc_state & MPI2_DOORBELL_USED) { 736662306a36Sopenharmony_ci dhsprintk(ioc, ioc_info(ioc, "unexpected doorbell active!\n")); 736762306a36Sopenharmony_ci goto issue_diag_reset; 736862306a36Sopenharmony_ci } 736962306a36Sopenharmony_ci 737062306a36Sopenharmony_ci if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { 737162306a36Sopenharmony_ci mpt3sas_print_fault_code(ioc, ioc_state & 737262306a36Sopenharmony_ci MPI2_DOORBELL_DATA_MASK); 737362306a36Sopenharmony_ci goto issue_diag_reset; 737462306a36Sopenharmony_ci } else if ((ioc_state & MPI2_IOC_STATE_MASK) == 737562306a36Sopenharmony_ci MPI2_IOC_STATE_COREDUMP) { 737662306a36Sopenharmony_ci ioc_info(ioc, 737762306a36Sopenharmony_ci "%s: Skipping the diag reset here. (ioc_state=0x%x)\n", 737862306a36Sopenharmony_ci __func__, ioc_state); 737962306a36Sopenharmony_ci return -EFAULT; 738062306a36Sopenharmony_ci } 738162306a36Sopenharmony_ci 738262306a36Sopenharmony_ci ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout); 738362306a36Sopenharmony_ci if (ioc_state) { 738462306a36Sopenharmony_ci dfailprintk(ioc, 738562306a36Sopenharmony_ci ioc_info(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n", 738662306a36Sopenharmony_ci __func__, ioc_state)); 738762306a36Sopenharmony_ci return -EFAULT; 738862306a36Sopenharmony_ci } 738962306a36Sopenharmony_ci 739062306a36Sopenharmony_ci return 0; 739162306a36Sopenharmony_ci 739262306a36Sopenharmony_ciissue_diag_reset: 739362306a36Sopenharmony_ci rc = _base_diag_reset(ioc); 739462306a36Sopenharmony_ci return rc; 739562306a36Sopenharmony_ci} 739662306a36Sopenharmony_ci 739762306a36Sopenharmony_ci/** 739862306a36Sopenharmony_ci * _base_get_ioc_facts - obtain ioc facts reply and save in ioc 739962306a36Sopenharmony_ci * @ioc: per adapter object 740062306a36Sopenharmony_ci * 740162306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 740262306a36Sopenharmony_ci */ 740362306a36Sopenharmony_cistatic int 740462306a36Sopenharmony_ci_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc) 740562306a36Sopenharmony_ci{ 740662306a36Sopenharmony_ci Mpi2IOCFactsRequest_t mpi_request; 740762306a36Sopenharmony_ci Mpi2IOCFactsReply_t mpi_reply; 740862306a36Sopenharmony_ci struct mpt3sas_facts *facts; 740962306a36Sopenharmony_ci int mpi_reply_sz, mpi_request_sz, r; 741062306a36Sopenharmony_ci 741162306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 741262306a36Sopenharmony_ci 741362306a36Sopenharmony_ci r = _base_wait_for_iocstate(ioc, 10); 741462306a36Sopenharmony_ci if (r) { 741562306a36Sopenharmony_ci dfailprintk(ioc, 741662306a36Sopenharmony_ci ioc_info(ioc, "%s: failed getting to correct state\n", 741762306a36Sopenharmony_ci __func__)); 741862306a36Sopenharmony_ci return r; 741962306a36Sopenharmony_ci } 742062306a36Sopenharmony_ci mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t); 742162306a36Sopenharmony_ci mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t); 742262306a36Sopenharmony_ci memset(&mpi_request, 0, mpi_request_sz); 742362306a36Sopenharmony_ci mpi_request.Function = MPI2_FUNCTION_IOC_FACTS; 742462306a36Sopenharmony_ci r = _base_handshake_req_reply_wait(ioc, mpi_request_sz, 742562306a36Sopenharmony_ci (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5); 742662306a36Sopenharmony_ci 742762306a36Sopenharmony_ci if (r != 0) { 742862306a36Sopenharmony_ci ioc_err(ioc, "%s: handshake failed (r=%d)\n", __func__, r); 742962306a36Sopenharmony_ci return r; 743062306a36Sopenharmony_ci } 743162306a36Sopenharmony_ci 743262306a36Sopenharmony_ci facts = &ioc->facts; 743362306a36Sopenharmony_ci memset(facts, 0, sizeof(struct mpt3sas_facts)); 743462306a36Sopenharmony_ci facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion); 743562306a36Sopenharmony_ci facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion); 743662306a36Sopenharmony_ci facts->VP_ID = mpi_reply.VP_ID; 743762306a36Sopenharmony_ci facts->VF_ID = mpi_reply.VF_ID; 743862306a36Sopenharmony_ci facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions); 743962306a36Sopenharmony_ci facts->MaxChainDepth = mpi_reply.MaxChainDepth; 744062306a36Sopenharmony_ci facts->WhoInit = mpi_reply.WhoInit; 744162306a36Sopenharmony_ci facts->NumberOfPorts = mpi_reply.NumberOfPorts; 744262306a36Sopenharmony_ci facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors; 744362306a36Sopenharmony_ci if (ioc->msix_enable && (facts->MaxMSIxVectors <= 744462306a36Sopenharmony_ci MAX_COMBINED_MSIX_VECTORS(ioc->is_gen35_ioc))) 744562306a36Sopenharmony_ci ioc->combined_reply_queue = 0; 744662306a36Sopenharmony_ci facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit); 744762306a36Sopenharmony_ci facts->MaxReplyDescriptorPostQueueDepth = 744862306a36Sopenharmony_ci le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth); 744962306a36Sopenharmony_ci facts->ProductID = le16_to_cpu(mpi_reply.ProductID); 745062306a36Sopenharmony_ci facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities); 745162306a36Sopenharmony_ci if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)) 745262306a36Sopenharmony_ci ioc->ir_firmware = 1; 745362306a36Sopenharmony_ci if ((facts->IOCCapabilities & 745462306a36Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE) && (!reset_devices)) 745562306a36Sopenharmony_ci ioc->rdpq_array_capable = 1; 745662306a36Sopenharmony_ci if ((facts->IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ) 745762306a36Sopenharmony_ci && ioc->is_aero_ioc) 745862306a36Sopenharmony_ci ioc->atomic_desc_capable = 1; 745962306a36Sopenharmony_ci facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word); 746062306a36Sopenharmony_ci facts->IOCRequestFrameSize = 746162306a36Sopenharmony_ci le16_to_cpu(mpi_reply.IOCRequestFrameSize); 746262306a36Sopenharmony_ci if (ioc->hba_mpi_version_belonged != MPI2_VERSION) { 746362306a36Sopenharmony_ci facts->IOCMaxChainSegmentSize = 746462306a36Sopenharmony_ci le16_to_cpu(mpi_reply.IOCMaxChainSegmentSize); 746562306a36Sopenharmony_ci } 746662306a36Sopenharmony_ci facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators); 746762306a36Sopenharmony_ci facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets); 746862306a36Sopenharmony_ci ioc->shost->max_id = -1; 746962306a36Sopenharmony_ci facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders); 747062306a36Sopenharmony_ci facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures); 747162306a36Sopenharmony_ci facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags); 747262306a36Sopenharmony_ci facts->HighPriorityCredit = 747362306a36Sopenharmony_ci le16_to_cpu(mpi_reply.HighPriorityCredit); 747462306a36Sopenharmony_ci facts->ReplyFrameSize = mpi_reply.ReplyFrameSize; 747562306a36Sopenharmony_ci facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle); 747662306a36Sopenharmony_ci facts->CurrentHostPageSize = mpi_reply.CurrentHostPageSize; 747762306a36Sopenharmony_ci 747862306a36Sopenharmony_ci /* 747962306a36Sopenharmony_ci * Get the Page Size from IOC Facts. If it's 0, default to 4k. 748062306a36Sopenharmony_ci */ 748162306a36Sopenharmony_ci ioc->page_size = 1 << facts->CurrentHostPageSize; 748262306a36Sopenharmony_ci if (ioc->page_size == 1) { 748362306a36Sopenharmony_ci ioc_info(ioc, "CurrentHostPageSize is 0: Setting default host page size to 4k\n"); 748462306a36Sopenharmony_ci ioc->page_size = 1 << MPT3SAS_HOST_PAGE_SIZE_4K; 748562306a36Sopenharmony_ci } 748662306a36Sopenharmony_ci dinitprintk(ioc, 748762306a36Sopenharmony_ci ioc_info(ioc, "CurrentHostPageSize(%d)\n", 748862306a36Sopenharmony_ci facts->CurrentHostPageSize)); 748962306a36Sopenharmony_ci 749062306a36Sopenharmony_ci dinitprintk(ioc, 749162306a36Sopenharmony_ci ioc_info(ioc, "hba queue depth(%d), max chains per io(%d)\n", 749262306a36Sopenharmony_ci facts->RequestCredit, facts->MaxChainDepth)); 749362306a36Sopenharmony_ci dinitprintk(ioc, 749462306a36Sopenharmony_ci ioc_info(ioc, "request frame size(%d), reply frame size(%d)\n", 749562306a36Sopenharmony_ci facts->IOCRequestFrameSize * 4, 749662306a36Sopenharmony_ci facts->ReplyFrameSize * 4)); 749762306a36Sopenharmony_ci return 0; 749862306a36Sopenharmony_ci} 749962306a36Sopenharmony_ci 750062306a36Sopenharmony_ci/** 750162306a36Sopenharmony_ci * _base_send_ioc_init - send ioc_init to firmware 750262306a36Sopenharmony_ci * @ioc: per adapter object 750362306a36Sopenharmony_ci * 750462306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 750562306a36Sopenharmony_ci */ 750662306a36Sopenharmony_cistatic int 750762306a36Sopenharmony_ci_base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc) 750862306a36Sopenharmony_ci{ 750962306a36Sopenharmony_ci Mpi2IOCInitRequest_t mpi_request; 751062306a36Sopenharmony_ci Mpi2IOCInitReply_t mpi_reply; 751162306a36Sopenharmony_ci int i, r = 0; 751262306a36Sopenharmony_ci ktime_t current_time; 751362306a36Sopenharmony_ci u16 ioc_status; 751462306a36Sopenharmony_ci u32 reply_post_free_array_sz = 0; 751562306a36Sopenharmony_ci 751662306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 751762306a36Sopenharmony_ci 751862306a36Sopenharmony_ci memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t)); 751962306a36Sopenharmony_ci mpi_request.Function = MPI2_FUNCTION_IOC_INIT; 752062306a36Sopenharmony_ci mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER; 752162306a36Sopenharmony_ci mpi_request.VF_ID = 0; /* TODO */ 752262306a36Sopenharmony_ci mpi_request.VP_ID = 0; 752362306a36Sopenharmony_ci mpi_request.MsgVersion = cpu_to_le16(ioc->hba_mpi_version_belonged); 752462306a36Sopenharmony_ci mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); 752562306a36Sopenharmony_ci mpi_request.HostPageSize = MPT3SAS_HOST_PAGE_SIZE_4K; 752662306a36Sopenharmony_ci 752762306a36Sopenharmony_ci if (_base_is_controller_msix_enabled(ioc)) 752862306a36Sopenharmony_ci mpi_request.HostMSIxVectors = ioc->reply_queue_count; 752962306a36Sopenharmony_ci mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4); 753062306a36Sopenharmony_ci mpi_request.ReplyDescriptorPostQueueDepth = 753162306a36Sopenharmony_ci cpu_to_le16(ioc->reply_post_queue_depth); 753262306a36Sopenharmony_ci mpi_request.ReplyFreeQueueDepth = 753362306a36Sopenharmony_ci cpu_to_le16(ioc->reply_free_queue_depth); 753462306a36Sopenharmony_ci 753562306a36Sopenharmony_ci mpi_request.SenseBufferAddressHigh = 753662306a36Sopenharmony_ci cpu_to_le32((u64)ioc->sense_dma >> 32); 753762306a36Sopenharmony_ci mpi_request.SystemReplyAddressHigh = 753862306a36Sopenharmony_ci cpu_to_le32((u64)ioc->reply_dma >> 32); 753962306a36Sopenharmony_ci mpi_request.SystemRequestFrameBaseAddress = 754062306a36Sopenharmony_ci cpu_to_le64((u64)ioc->request_dma); 754162306a36Sopenharmony_ci mpi_request.ReplyFreeQueueAddress = 754262306a36Sopenharmony_ci cpu_to_le64((u64)ioc->reply_free_dma); 754362306a36Sopenharmony_ci 754462306a36Sopenharmony_ci if (ioc->rdpq_array_enable) { 754562306a36Sopenharmony_ci reply_post_free_array_sz = ioc->reply_queue_count * 754662306a36Sopenharmony_ci sizeof(Mpi2IOCInitRDPQArrayEntry); 754762306a36Sopenharmony_ci memset(ioc->reply_post_free_array, 0, reply_post_free_array_sz); 754862306a36Sopenharmony_ci for (i = 0; i < ioc->reply_queue_count; i++) 754962306a36Sopenharmony_ci ioc->reply_post_free_array[i].RDPQBaseAddress = 755062306a36Sopenharmony_ci cpu_to_le64( 755162306a36Sopenharmony_ci (u64)ioc->reply_post[i].reply_post_free_dma); 755262306a36Sopenharmony_ci mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE; 755362306a36Sopenharmony_ci mpi_request.ReplyDescriptorPostQueueAddress = 755462306a36Sopenharmony_ci cpu_to_le64((u64)ioc->reply_post_free_array_dma); 755562306a36Sopenharmony_ci } else { 755662306a36Sopenharmony_ci mpi_request.ReplyDescriptorPostQueueAddress = 755762306a36Sopenharmony_ci cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma); 755862306a36Sopenharmony_ci } 755962306a36Sopenharmony_ci 756062306a36Sopenharmony_ci /* 756162306a36Sopenharmony_ci * Set the flag to enable CoreDump state feature in IOC firmware. 756262306a36Sopenharmony_ci */ 756362306a36Sopenharmony_ci mpi_request.ConfigurationFlags |= 756462306a36Sopenharmony_ci cpu_to_le16(MPI26_IOCINIT_CFGFLAGS_COREDUMP_ENABLE); 756562306a36Sopenharmony_ci 756662306a36Sopenharmony_ci /* This time stamp specifies number of milliseconds 756762306a36Sopenharmony_ci * since epoch ~ midnight January 1, 1970. 756862306a36Sopenharmony_ci */ 756962306a36Sopenharmony_ci current_time = ktime_get_real(); 757062306a36Sopenharmony_ci mpi_request.TimeStamp = cpu_to_le64(ktime_to_ms(current_time)); 757162306a36Sopenharmony_ci 757262306a36Sopenharmony_ci if (ioc->logging_level & MPT_DEBUG_INIT) { 757362306a36Sopenharmony_ci __le32 *mfp; 757462306a36Sopenharmony_ci int i; 757562306a36Sopenharmony_ci 757662306a36Sopenharmony_ci mfp = (__le32 *)&mpi_request; 757762306a36Sopenharmony_ci ioc_info(ioc, "\toffset:data\n"); 757862306a36Sopenharmony_ci for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++) 757962306a36Sopenharmony_ci ioc_info(ioc, "\t[0x%02x]:%08x\n", i*4, 758062306a36Sopenharmony_ci le32_to_cpu(mfp[i])); 758162306a36Sopenharmony_ci } 758262306a36Sopenharmony_ci 758362306a36Sopenharmony_ci r = _base_handshake_req_reply_wait(ioc, 758462306a36Sopenharmony_ci sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request, 758562306a36Sopenharmony_ci sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 30); 758662306a36Sopenharmony_ci 758762306a36Sopenharmony_ci if (r != 0) { 758862306a36Sopenharmony_ci ioc_err(ioc, "%s: handshake failed (r=%d)\n", __func__, r); 758962306a36Sopenharmony_ci return r; 759062306a36Sopenharmony_ci } 759162306a36Sopenharmony_ci 759262306a36Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; 759362306a36Sopenharmony_ci if (ioc_status != MPI2_IOCSTATUS_SUCCESS || 759462306a36Sopenharmony_ci mpi_reply.IOCLogInfo) { 759562306a36Sopenharmony_ci ioc_err(ioc, "%s: failed\n", __func__); 759662306a36Sopenharmony_ci r = -EIO; 759762306a36Sopenharmony_ci } 759862306a36Sopenharmony_ci 759962306a36Sopenharmony_ci /* Reset TimeSync Counter*/ 760062306a36Sopenharmony_ci ioc->timestamp_update_count = 0; 760162306a36Sopenharmony_ci return r; 760262306a36Sopenharmony_ci} 760362306a36Sopenharmony_ci 760462306a36Sopenharmony_ci/** 760562306a36Sopenharmony_ci * mpt3sas_port_enable_done - command completion routine for port enable 760662306a36Sopenharmony_ci * @ioc: per adapter object 760762306a36Sopenharmony_ci * @smid: system request message index 760862306a36Sopenharmony_ci * @msix_index: MSIX table index supplied by the OS 760962306a36Sopenharmony_ci * @reply: reply message frame(lower 32bit addr) 761062306a36Sopenharmony_ci * 761162306a36Sopenharmony_ci * Return: 1 meaning mf should be freed from _base_interrupt 761262306a36Sopenharmony_ci * 0 means the mf is freed from this function. 761362306a36Sopenharmony_ci */ 761462306a36Sopenharmony_ciu8 761562306a36Sopenharmony_cimpt3sas_port_enable_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, 761662306a36Sopenharmony_ci u32 reply) 761762306a36Sopenharmony_ci{ 761862306a36Sopenharmony_ci MPI2DefaultReply_t *mpi_reply; 761962306a36Sopenharmony_ci u16 ioc_status; 762062306a36Sopenharmony_ci 762162306a36Sopenharmony_ci if (ioc->port_enable_cmds.status == MPT3_CMD_NOT_USED) 762262306a36Sopenharmony_ci return 1; 762362306a36Sopenharmony_ci 762462306a36Sopenharmony_ci mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); 762562306a36Sopenharmony_ci if (!mpi_reply) 762662306a36Sopenharmony_ci return 1; 762762306a36Sopenharmony_ci 762862306a36Sopenharmony_ci if (mpi_reply->Function != MPI2_FUNCTION_PORT_ENABLE) 762962306a36Sopenharmony_ci return 1; 763062306a36Sopenharmony_ci 763162306a36Sopenharmony_ci ioc->port_enable_cmds.status &= ~MPT3_CMD_PENDING; 763262306a36Sopenharmony_ci ioc->port_enable_cmds.status |= MPT3_CMD_COMPLETE; 763362306a36Sopenharmony_ci ioc->port_enable_cmds.status |= MPT3_CMD_REPLY_VALID; 763462306a36Sopenharmony_ci memcpy(ioc->port_enable_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); 763562306a36Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; 763662306a36Sopenharmony_ci if (ioc_status != MPI2_IOCSTATUS_SUCCESS) 763762306a36Sopenharmony_ci ioc->port_enable_failed = 1; 763862306a36Sopenharmony_ci 763962306a36Sopenharmony_ci if (ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE_ASYNC) { 764062306a36Sopenharmony_ci ioc->port_enable_cmds.status &= ~MPT3_CMD_COMPLETE_ASYNC; 764162306a36Sopenharmony_ci if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { 764262306a36Sopenharmony_ci mpt3sas_port_enable_complete(ioc); 764362306a36Sopenharmony_ci return 1; 764462306a36Sopenharmony_ci } else { 764562306a36Sopenharmony_ci ioc->start_scan_failed = ioc_status; 764662306a36Sopenharmony_ci ioc->start_scan = 0; 764762306a36Sopenharmony_ci return 1; 764862306a36Sopenharmony_ci } 764962306a36Sopenharmony_ci } 765062306a36Sopenharmony_ci complete(&ioc->port_enable_cmds.done); 765162306a36Sopenharmony_ci return 1; 765262306a36Sopenharmony_ci} 765362306a36Sopenharmony_ci 765462306a36Sopenharmony_ci/** 765562306a36Sopenharmony_ci * _base_send_port_enable - send port_enable(discovery stuff) to firmware 765662306a36Sopenharmony_ci * @ioc: per adapter object 765762306a36Sopenharmony_ci * 765862306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 765962306a36Sopenharmony_ci */ 766062306a36Sopenharmony_cistatic int 766162306a36Sopenharmony_ci_base_send_port_enable(struct MPT3SAS_ADAPTER *ioc) 766262306a36Sopenharmony_ci{ 766362306a36Sopenharmony_ci Mpi2PortEnableRequest_t *mpi_request; 766462306a36Sopenharmony_ci Mpi2PortEnableReply_t *mpi_reply; 766562306a36Sopenharmony_ci int r = 0; 766662306a36Sopenharmony_ci u16 smid; 766762306a36Sopenharmony_ci u16 ioc_status; 766862306a36Sopenharmony_ci 766962306a36Sopenharmony_ci ioc_info(ioc, "sending port enable !!\n"); 767062306a36Sopenharmony_ci 767162306a36Sopenharmony_ci if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) { 767262306a36Sopenharmony_ci ioc_err(ioc, "%s: internal command already in use\n", __func__); 767362306a36Sopenharmony_ci return -EAGAIN; 767462306a36Sopenharmony_ci } 767562306a36Sopenharmony_ci 767662306a36Sopenharmony_ci smid = mpt3sas_base_get_smid(ioc, ioc->port_enable_cb_idx); 767762306a36Sopenharmony_ci if (!smid) { 767862306a36Sopenharmony_ci ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); 767962306a36Sopenharmony_ci return -EAGAIN; 768062306a36Sopenharmony_ci } 768162306a36Sopenharmony_ci 768262306a36Sopenharmony_ci ioc->port_enable_cmds.status = MPT3_CMD_PENDING; 768362306a36Sopenharmony_ci mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); 768462306a36Sopenharmony_ci ioc->port_enable_cmds.smid = smid; 768562306a36Sopenharmony_ci memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); 768662306a36Sopenharmony_ci mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; 768762306a36Sopenharmony_ci 768862306a36Sopenharmony_ci init_completion(&ioc->port_enable_cmds.done); 768962306a36Sopenharmony_ci ioc->put_smid_default(ioc, smid); 769062306a36Sopenharmony_ci wait_for_completion_timeout(&ioc->port_enable_cmds.done, 300*HZ); 769162306a36Sopenharmony_ci if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) { 769262306a36Sopenharmony_ci ioc_err(ioc, "%s: timeout\n", __func__); 769362306a36Sopenharmony_ci _debug_dump_mf(mpi_request, 769462306a36Sopenharmony_ci sizeof(Mpi2PortEnableRequest_t)/4); 769562306a36Sopenharmony_ci if (ioc->port_enable_cmds.status & MPT3_CMD_RESET) 769662306a36Sopenharmony_ci r = -EFAULT; 769762306a36Sopenharmony_ci else 769862306a36Sopenharmony_ci r = -ETIME; 769962306a36Sopenharmony_ci goto out; 770062306a36Sopenharmony_ci } 770162306a36Sopenharmony_ci 770262306a36Sopenharmony_ci mpi_reply = ioc->port_enable_cmds.reply; 770362306a36Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; 770462306a36Sopenharmony_ci if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { 770562306a36Sopenharmony_ci ioc_err(ioc, "%s: failed with (ioc_status=0x%08x)\n", 770662306a36Sopenharmony_ci __func__, ioc_status); 770762306a36Sopenharmony_ci r = -EFAULT; 770862306a36Sopenharmony_ci goto out; 770962306a36Sopenharmony_ci } 771062306a36Sopenharmony_ci 771162306a36Sopenharmony_ci out: 771262306a36Sopenharmony_ci ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED; 771362306a36Sopenharmony_ci ioc_info(ioc, "port enable: %s\n", r == 0 ? "SUCCESS" : "FAILED"); 771462306a36Sopenharmony_ci return r; 771562306a36Sopenharmony_ci} 771662306a36Sopenharmony_ci 771762306a36Sopenharmony_ci/** 771862306a36Sopenharmony_ci * mpt3sas_port_enable - initiate firmware discovery (don't wait for reply) 771962306a36Sopenharmony_ci * @ioc: per adapter object 772062306a36Sopenharmony_ci * 772162306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 772262306a36Sopenharmony_ci */ 772362306a36Sopenharmony_ciint 772462306a36Sopenharmony_cimpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc) 772562306a36Sopenharmony_ci{ 772662306a36Sopenharmony_ci Mpi2PortEnableRequest_t *mpi_request; 772762306a36Sopenharmony_ci u16 smid; 772862306a36Sopenharmony_ci 772962306a36Sopenharmony_ci ioc_info(ioc, "sending port enable !!\n"); 773062306a36Sopenharmony_ci 773162306a36Sopenharmony_ci if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) { 773262306a36Sopenharmony_ci ioc_err(ioc, "%s: internal command already in use\n", __func__); 773362306a36Sopenharmony_ci return -EAGAIN; 773462306a36Sopenharmony_ci } 773562306a36Sopenharmony_ci 773662306a36Sopenharmony_ci smid = mpt3sas_base_get_smid(ioc, ioc->port_enable_cb_idx); 773762306a36Sopenharmony_ci if (!smid) { 773862306a36Sopenharmony_ci ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); 773962306a36Sopenharmony_ci return -EAGAIN; 774062306a36Sopenharmony_ci } 774162306a36Sopenharmony_ci ioc->drv_internal_flags |= MPT_DRV_INTERNAL_FIRST_PE_ISSUED; 774262306a36Sopenharmony_ci ioc->port_enable_cmds.status = MPT3_CMD_PENDING; 774362306a36Sopenharmony_ci ioc->port_enable_cmds.status |= MPT3_CMD_COMPLETE_ASYNC; 774462306a36Sopenharmony_ci mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); 774562306a36Sopenharmony_ci ioc->port_enable_cmds.smid = smid; 774662306a36Sopenharmony_ci memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); 774762306a36Sopenharmony_ci mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; 774862306a36Sopenharmony_ci 774962306a36Sopenharmony_ci ioc->put_smid_default(ioc, smid); 775062306a36Sopenharmony_ci return 0; 775162306a36Sopenharmony_ci} 775262306a36Sopenharmony_ci 775362306a36Sopenharmony_ci/** 775462306a36Sopenharmony_ci * _base_determine_wait_on_discovery - desposition 775562306a36Sopenharmony_ci * @ioc: per adapter object 775662306a36Sopenharmony_ci * 775762306a36Sopenharmony_ci * Decide whether to wait on discovery to complete. Used to either 775862306a36Sopenharmony_ci * locate boot device, or report volumes ahead of physical devices. 775962306a36Sopenharmony_ci * 776062306a36Sopenharmony_ci * Return: 1 for wait, 0 for don't wait. 776162306a36Sopenharmony_ci */ 776262306a36Sopenharmony_cistatic int 776362306a36Sopenharmony_ci_base_determine_wait_on_discovery(struct MPT3SAS_ADAPTER *ioc) 776462306a36Sopenharmony_ci{ 776562306a36Sopenharmony_ci /* We wait for discovery to complete if IR firmware is loaded. 776662306a36Sopenharmony_ci * The sas topology events arrive before PD events, so we need time to 776762306a36Sopenharmony_ci * turn on the bit in ioc->pd_handles to indicate PD 776862306a36Sopenharmony_ci * Also, it maybe required to report Volumes ahead of physical 776962306a36Sopenharmony_ci * devices when MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING is set. 777062306a36Sopenharmony_ci */ 777162306a36Sopenharmony_ci if (ioc->ir_firmware) 777262306a36Sopenharmony_ci return 1; 777362306a36Sopenharmony_ci 777462306a36Sopenharmony_ci /* if no Bios, then we don't need to wait */ 777562306a36Sopenharmony_ci if (!ioc->bios_pg3.BiosVersion) 777662306a36Sopenharmony_ci return 0; 777762306a36Sopenharmony_ci 777862306a36Sopenharmony_ci /* Bios is present, then we drop down here. 777962306a36Sopenharmony_ci * 778062306a36Sopenharmony_ci * If there any entries in the Bios Page 2, then we wait 778162306a36Sopenharmony_ci * for discovery to complete. 778262306a36Sopenharmony_ci */ 778362306a36Sopenharmony_ci 778462306a36Sopenharmony_ci /* Current Boot Device */ 778562306a36Sopenharmony_ci if ((ioc->bios_pg2.CurrentBootDeviceForm & 778662306a36Sopenharmony_ci MPI2_BIOSPAGE2_FORM_MASK) == 778762306a36Sopenharmony_ci MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && 778862306a36Sopenharmony_ci /* Request Boot Device */ 778962306a36Sopenharmony_ci (ioc->bios_pg2.ReqBootDeviceForm & 779062306a36Sopenharmony_ci MPI2_BIOSPAGE2_FORM_MASK) == 779162306a36Sopenharmony_ci MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && 779262306a36Sopenharmony_ci /* Alternate Request Boot Device */ 779362306a36Sopenharmony_ci (ioc->bios_pg2.ReqAltBootDeviceForm & 779462306a36Sopenharmony_ci MPI2_BIOSPAGE2_FORM_MASK) == 779562306a36Sopenharmony_ci MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED) 779662306a36Sopenharmony_ci return 0; 779762306a36Sopenharmony_ci 779862306a36Sopenharmony_ci return 1; 779962306a36Sopenharmony_ci} 780062306a36Sopenharmony_ci 780162306a36Sopenharmony_ci/** 780262306a36Sopenharmony_ci * _base_unmask_events - turn on notification for this event 780362306a36Sopenharmony_ci * @ioc: per adapter object 780462306a36Sopenharmony_ci * @event: firmware event 780562306a36Sopenharmony_ci * 780662306a36Sopenharmony_ci * The mask is stored in ioc->event_masks. 780762306a36Sopenharmony_ci */ 780862306a36Sopenharmony_cistatic void 780962306a36Sopenharmony_ci_base_unmask_events(struct MPT3SAS_ADAPTER *ioc, u16 event) 781062306a36Sopenharmony_ci{ 781162306a36Sopenharmony_ci u32 desired_event; 781262306a36Sopenharmony_ci 781362306a36Sopenharmony_ci if (event >= 128) 781462306a36Sopenharmony_ci return; 781562306a36Sopenharmony_ci 781662306a36Sopenharmony_ci desired_event = (1 << (event % 32)); 781762306a36Sopenharmony_ci 781862306a36Sopenharmony_ci if (event < 32) 781962306a36Sopenharmony_ci ioc->event_masks[0] &= ~desired_event; 782062306a36Sopenharmony_ci else if (event < 64) 782162306a36Sopenharmony_ci ioc->event_masks[1] &= ~desired_event; 782262306a36Sopenharmony_ci else if (event < 96) 782362306a36Sopenharmony_ci ioc->event_masks[2] &= ~desired_event; 782462306a36Sopenharmony_ci else if (event < 128) 782562306a36Sopenharmony_ci ioc->event_masks[3] &= ~desired_event; 782662306a36Sopenharmony_ci} 782762306a36Sopenharmony_ci 782862306a36Sopenharmony_ci/** 782962306a36Sopenharmony_ci * _base_event_notification - send event notification 783062306a36Sopenharmony_ci * @ioc: per adapter object 783162306a36Sopenharmony_ci * 783262306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 783362306a36Sopenharmony_ci */ 783462306a36Sopenharmony_cistatic int 783562306a36Sopenharmony_ci_base_event_notification(struct MPT3SAS_ADAPTER *ioc) 783662306a36Sopenharmony_ci{ 783762306a36Sopenharmony_ci Mpi2EventNotificationRequest_t *mpi_request; 783862306a36Sopenharmony_ci u16 smid; 783962306a36Sopenharmony_ci int r = 0; 784062306a36Sopenharmony_ci int i, issue_diag_reset = 0; 784162306a36Sopenharmony_ci 784262306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 784362306a36Sopenharmony_ci 784462306a36Sopenharmony_ci if (ioc->base_cmds.status & MPT3_CMD_PENDING) { 784562306a36Sopenharmony_ci ioc_err(ioc, "%s: internal command already in use\n", __func__); 784662306a36Sopenharmony_ci return -EAGAIN; 784762306a36Sopenharmony_ci } 784862306a36Sopenharmony_ci 784962306a36Sopenharmony_ci smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx); 785062306a36Sopenharmony_ci if (!smid) { 785162306a36Sopenharmony_ci ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); 785262306a36Sopenharmony_ci return -EAGAIN; 785362306a36Sopenharmony_ci } 785462306a36Sopenharmony_ci ioc->base_cmds.status = MPT3_CMD_PENDING; 785562306a36Sopenharmony_ci mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); 785662306a36Sopenharmony_ci ioc->base_cmds.smid = smid; 785762306a36Sopenharmony_ci memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t)); 785862306a36Sopenharmony_ci mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; 785962306a36Sopenharmony_ci mpi_request->VF_ID = 0; /* TODO */ 786062306a36Sopenharmony_ci mpi_request->VP_ID = 0; 786162306a36Sopenharmony_ci for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 786262306a36Sopenharmony_ci mpi_request->EventMasks[i] = 786362306a36Sopenharmony_ci cpu_to_le32(ioc->event_masks[i]); 786462306a36Sopenharmony_ci init_completion(&ioc->base_cmds.done); 786562306a36Sopenharmony_ci ioc->put_smid_default(ioc, smid); 786662306a36Sopenharmony_ci wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); 786762306a36Sopenharmony_ci if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { 786862306a36Sopenharmony_ci ioc_err(ioc, "%s: timeout\n", __func__); 786962306a36Sopenharmony_ci _debug_dump_mf(mpi_request, 787062306a36Sopenharmony_ci sizeof(Mpi2EventNotificationRequest_t)/4); 787162306a36Sopenharmony_ci if (ioc->base_cmds.status & MPT3_CMD_RESET) 787262306a36Sopenharmony_ci r = -EFAULT; 787362306a36Sopenharmony_ci else 787462306a36Sopenharmony_ci issue_diag_reset = 1; 787562306a36Sopenharmony_ci 787662306a36Sopenharmony_ci } else 787762306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s: complete\n", __func__)); 787862306a36Sopenharmony_ci ioc->base_cmds.status = MPT3_CMD_NOT_USED; 787962306a36Sopenharmony_ci 788062306a36Sopenharmony_ci if (issue_diag_reset) { 788162306a36Sopenharmony_ci if (ioc->drv_internal_flags & MPT_DRV_INTERNAL_FIRST_PE_ISSUED) 788262306a36Sopenharmony_ci return -EFAULT; 788362306a36Sopenharmony_ci if (mpt3sas_base_check_for_fault_and_issue_reset(ioc)) 788462306a36Sopenharmony_ci return -EFAULT; 788562306a36Sopenharmony_ci r = -EAGAIN; 788662306a36Sopenharmony_ci } 788762306a36Sopenharmony_ci return r; 788862306a36Sopenharmony_ci} 788962306a36Sopenharmony_ci 789062306a36Sopenharmony_ci/** 789162306a36Sopenharmony_ci * mpt3sas_base_validate_event_type - validating event types 789262306a36Sopenharmony_ci * @ioc: per adapter object 789362306a36Sopenharmony_ci * @event_type: firmware event 789462306a36Sopenharmony_ci * 789562306a36Sopenharmony_ci * This will turn on firmware event notification when application 789662306a36Sopenharmony_ci * ask for that event. We don't mask events that are already enabled. 789762306a36Sopenharmony_ci */ 789862306a36Sopenharmony_civoid 789962306a36Sopenharmony_cimpt3sas_base_validate_event_type(struct MPT3SAS_ADAPTER *ioc, u32 *event_type) 790062306a36Sopenharmony_ci{ 790162306a36Sopenharmony_ci int i, j; 790262306a36Sopenharmony_ci u32 event_mask, desired_event; 790362306a36Sopenharmony_ci u8 send_update_to_fw; 790462306a36Sopenharmony_ci 790562306a36Sopenharmony_ci for (i = 0, send_update_to_fw = 0; i < 790662306a36Sopenharmony_ci MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) { 790762306a36Sopenharmony_ci event_mask = ~event_type[i]; 790862306a36Sopenharmony_ci desired_event = 1; 790962306a36Sopenharmony_ci for (j = 0; j < 32; j++) { 791062306a36Sopenharmony_ci if (!(event_mask & desired_event) && 791162306a36Sopenharmony_ci (ioc->event_masks[i] & desired_event)) { 791262306a36Sopenharmony_ci ioc->event_masks[i] &= ~desired_event; 791362306a36Sopenharmony_ci send_update_to_fw = 1; 791462306a36Sopenharmony_ci } 791562306a36Sopenharmony_ci desired_event = (desired_event << 1); 791662306a36Sopenharmony_ci } 791762306a36Sopenharmony_ci } 791862306a36Sopenharmony_ci 791962306a36Sopenharmony_ci if (!send_update_to_fw) 792062306a36Sopenharmony_ci return; 792162306a36Sopenharmony_ci 792262306a36Sopenharmony_ci mutex_lock(&ioc->base_cmds.mutex); 792362306a36Sopenharmony_ci _base_event_notification(ioc); 792462306a36Sopenharmony_ci mutex_unlock(&ioc->base_cmds.mutex); 792562306a36Sopenharmony_ci} 792662306a36Sopenharmony_ci 792762306a36Sopenharmony_ci/** 792862306a36Sopenharmony_ci * _base_diag_reset - the "big hammer" start of day reset 792962306a36Sopenharmony_ci * @ioc: per adapter object 793062306a36Sopenharmony_ci * 793162306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 793262306a36Sopenharmony_ci */ 793362306a36Sopenharmony_cistatic int 793462306a36Sopenharmony_ci_base_diag_reset(struct MPT3SAS_ADAPTER *ioc) 793562306a36Sopenharmony_ci{ 793662306a36Sopenharmony_ci u32 host_diagnostic; 793762306a36Sopenharmony_ci u32 ioc_state; 793862306a36Sopenharmony_ci u32 count; 793962306a36Sopenharmony_ci u32 hcb_size; 794062306a36Sopenharmony_ci 794162306a36Sopenharmony_ci ioc_info(ioc, "sending diag reset !!\n"); 794262306a36Sopenharmony_ci 794362306a36Sopenharmony_ci pci_cfg_access_lock(ioc->pdev); 794462306a36Sopenharmony_ci 794562306a36Sopenharmony_ci drsprintk(ioc, ioc_info(ioc, "clear interrupts\n")); 794662306a36Sopenharmony_ci 794762306a36Sopenharmony_ci count = 0; 794862306a36Sopenharmony_ci do { 794962306a36Sopenharmony_ci /* Write magic sequence to WriteSequence register 795062306a36Sopenharmony_ci * Loop until in diagnostic mode 795162306a36Sopenharmony_ci */ 795262306a36Sopenharmony_ci drsprintk(ioc, ioc_info(ioc, "write magic sequence\n")); 795362306a36Sopenharmony_ci writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); 795462306a36Sopenharmony_ci writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence); 795562306a36Sopenharmony_ci writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence); 795662306a36Sopenharmony_ci writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence); 795762306a36Sopenharmony_ci writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence); 795862306a36Sopenharmony_ci writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence); 795962306a36Sopenharmony_ci writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence); 796062306a36Sopenharmony_ci 796162306a36Sopenharmony_ci /* wait 100 msec */ 796262306a36Sopenharmony_ci msleep(100); 796362306a36Sopenharmony_ci 796462306a36Sopenharmony_ci if (count++ > 20) { 796562306a36Sopenharmony_ci ioc_info(ioc, 796662306a36Sopenharmony_ci "Stop writing magic sequence after 20 retries\n"); 796762306a36Sopenharmony_ci _base_dump_reg_set(ioc); 796862306a36Sopenharmony_ci goto out; 796962306a36Sopenharmony_ci } 797062306a36Sopenharmony_ci 797162306a36Sopenharmony_ci host_diagnostic = ioc->base_readl_ext_retry(&ioc->chip->HostDiagnostic); 797262306a36Sopenharmony_ci drsprintk(ioc, 797362306a36Sopenharmony_ci ioc_info(ioc, "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n", 797462306a36Sopenharmony_ci count, host_diagnostic)); 797562306a36Sopenharmony_ci 797662306a36Sopenharmony_ci } while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0); 797762306a36Sopenharmony_ci 797862306a36Sopenharmony_ci hcb_size = ioc->base_readl(&ioc->chip->HCBSize); 797962306a36Sopenharmony_ci 798062306a36Sopenharmony_ci drsprintk(ioc, ioc_info(ioc, "diag reset: issued\n")); 798162306a36Sopenharmony_ci writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER, 798262306a36Sopenharmony_ci &ioc->chip->HostDiagnostic); 798362306a36Sopenharmony_ci 798462306a36Sopenharmony_ci /*This delay allows the chip PCIe hardware time to finish reset tasks*/ 798562306a36Sopenharmony_ci msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000); 798662306a36Sopenharmony_ci 798762306a36Sopenharmony_ci /* Approximately 300 second max wait */ 798862306a36Sopenharmony_ci for (count = 0; count < (300000000 / 798962306a36Sopenharmony_ci MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) { 799062306a36Sopenharmony_ci 799162306a36Sopenharmony_ci host_diagnostic = ioc->base_readl_ext_retry(&ioc->chip->HostDiagnostic); 799262306a36Sopenharmony_ci 799362306a36Sopenharmony_ci if (host_diagnostic == 0xFFFFFFFF) { 799462306a36Sopenharmony_ci ioc_info(ioc, 799562306a36Sopenharmony_ci "Invalid host diagnostic register value\n"); 799662306a36Sopenharmony_ci _base_dump_reg_set(ioc); 799762306a36Sopenharmony_ci goto out; 799862306a36Sopenharmony_ci } 799962306a36Sopenharmony_ci if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER)) 800062306a36Sopenharmony_ci break; 800162306a36Sopenharmony_ci 800262306a36Sopenharmony_ci msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC / 1000); 800362306a36Sopenharmony_ci } 800462306a36Sopenharmony_ci 800562306a36Sopenharmony_ci if (host_diagnostic & MPI2_DIAG_HCB_MODE) { 800662306a36Sopenharmony_ci 800762306a36Sopenharmony_ci drsprintk(ioc, 800862306a36Sopenharmony_ci ioc_info(ioc, "restart the adapter assuming the HCB Address points to good F/W\n")); 800962306a36Sopenharmony_ci host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK; 801062306a36Sopenharmony_ci host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW; 801162306a36Sopenharmony_ci writel(host_diagnostic, &ioc->chip->HostDiagnostic); 801262306a36Sopenharmony_ci 801362306a36Sopenharmony_ci drsprintk(ioc, ioc_info(ioc, "re-enable the HCDW\n")); 801462306a36Sopenharmony_ci writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE, 801562306a36Sopenharmony_ci &ioc->chip->HCBSize); 801662306a36Sopenharmony_ci } 801762306a36Sopenharmony_ci 801862306a36Sopenharmony_ci drsprintk(ioc, ioc_info(ioc, "restart the adapter\n")); 801962306a36Sopenharmony_ci writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET, 802062306a36Sopenharmony_ci &ioc->chip->HostDiagnostic); 802162306a36Sopenharmony_ci 802262306a36Sopenharmony_ci drsprintk(ioc, 802362306a36Sopenharmony_ci ioc_info(ioc, "disable writes to the diagnostic register\n")); 802462306a36Sopenharmony_ci writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); 802562306a36Sopenharmony_ci 802662306a36Sopenharmony_ci drsprintk(ioc, ioc_info(ioc, "Wait for FW to go to the READY state\n")); 802762306a36Sopenharmony_ci ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20); 802862306a36Sopenharmony_ci if (ioc_state) { 802962306a36Sopenharmony_ci ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n", 803062306a36Sopenharmony_ci __func__, ioc_state); 803162306a36Sopenharmony_ci _base_dump_reg_set(ioc); 803262306a36Sopenharmony_ci goto out; 803362306a36Sopenharmony_ci } 803462306a36Sopenharmony_ci 803562306a36Sopenharmony_ci pci_cfg_access_unlock(ioc->pdev); 803662306a36Sopenharmony_ci ioc_info(ioc, "diag reset: SUCCESS\n"); 803762306a36Sopenharmony_ci return 0; 803862306a36Sopenharmony_ci 803962306a36Sopenharmony_ci out: 804062306a36Sopenharmony_ci pci_cfg_access_unlock(ioc->pdev); 804162306a36Sopenharmony_ci ioc_err(ioc, "diag reset: FAILED\n"); 804262306a36Sopenharmony_ci return -EFAULT; 804362306a36Sopenharmony_ci} 804462306a36Sopenharmony_ci 804562306a36Sopenharmony_ci/** 804662306a36Sopenharmony_ci * mpt3sas_base_make_ioc_ready - put controller in READY state 804762306a36Sopenharmony_ci * @ioc: per adapter object 804862306a36Sopenharmony_ci * @type: FORCE_BIG_HAMMER or SOFT_RESET 804962306a36Sopenharmony_ci * 805062306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 805162306a36Sopenharmony_ci */ 805262306a36Sopenharmony_ciint 805362306a36Sopenharmony_cimpt3sas_base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, enum reset_type type) 805462306a36Sopenharmony_ci{ 805562306a36Sopenharmony_ci u32 ioc_state; 805662306a36Sopenharmony_ci int rc; 805762306a36Sopenharmony_ci int count; 805862306a36Sopenharmony_ci 805962306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 806062306a36Sopenharmony_ci 806162306a36Sopenharmony_ci if (ioc->pci_error_recovery) 806262306a36Sopenharmony_ci return 0; 806362306a36Sopenharmony_ci 806462306a36Sopenharmony_ci ioc_state = mpt3sas_base_get_iocstate(ioc, 0); 806562306a36Sopenharmony_ci dhsprintk(ioc, 806662306a36Sopenharmony_ci ioc_info(ioc, "%s: ioc_state(0x%08x)\n", 806762306a36Sopenharmony_ci __func__, ioc_state)); 806862306a36Sopenharmony_ci 806962306a36Sopenharmony_ci /* if in RESET state, it should move to READY state shortly */ 807062306a36Sopenharmony_ci count = 0; 807162306a36Sopenharmony_ci if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_RESET) { 807262306a36Sopenharmony_ci while ((ioc_state & MPI2_IOC_STATE_MASK) != 807362306a36Sopenharmony_ci MPI2_IOC_STATE_READY) { 807462306a36Sopenharmony_ci if (count++ == 10) { 807562306a36Sopenharmony_ci ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n", 807662306a36Sopenharmony_ci __func__, ioc_state); 807762306a36Sopenharmony_ci return -EFAULT; 807862306a36Sopenharmony_ci } 807962306a36Sopenharmony_ci ssleep(1); 808062306a36Sopenharmony_ci ioc_state = mpt3sas_base_get_iocstate(ioc, 0); 808162306a36Sopenharmony_ci } 808262306a36Sopenharmony_ci } 808362306a36Sopenharmony_ci 808462306a36Sopenharmony_ci if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) 808562306a36Sopenharmony_ci return 0; 808662306a36Sopenharmony_ci 808762306a36Sopenharmony_ci if (ioc_state & MPI2_DOORBELL_USED) { 808862306a36Sopenharmony_ci ioc_info(ioc, "unexpected doorbell active!\n"); 808962306a36Sopenharmony_ci goto issue_diag_reset; 809062306a36Sopenharmony_ci } 809162306a36Sopenharmony_ci 809262306a36Sopenharmony_ci if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { 809362306a36Sopenharmony_ci mpt3sas_print_fault_code(ioc, ioc_state & 809462306a36Sopenharmony_ci MPI2_DOORBELL_DATA_MASK); 809562306a36Sopenharmony_ci goto issue_diag_reset; 809662306a36Sopenharmony_ci } 809762306a36Sopenharmony_ci 809862306a36Sopenharmony_ci if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_COREDUMP) { 809962306a36Sopenharmony_ci /* 810062306a36Sopenharmony_ci * if host reset is invoked while watch dog thread is waiting 810162306a36Sopenharmony_ci * for IOC state to be changed to Fault state then driver has 810262306a36Sopenharmony_ci * to wait here for CoreDump state to clear otherwise reset 810362306a36Sopenharmony_ci * will be issued to the FW and FW move the IOC state to 810462306a36Sopenharmony_ci * reset state without copying the FW logs to coredump region. 810562306a36Sopenharmony_ci */ 810662306a36Sopenharmony_ci if (ioc->ioc_coredump_loop != MPT3SAS_COREDUMP_LOOP_DONE) { 810762306a36Sopenharmony_ci mpt3sas_print_coredump_info(ioc, ioc_state & 810862306a36Sopenharmony_ci MPI2_DOORBELL_DATA_MASK); 810962306a36Sopenharmony_ci mpt3sas_base_wait_for_coredump_completion(ioc, 811062306a36Sopenharmony_ci __func__); 811162306a36Sopenharmony_ci } 811262306a36Sopenharmony_ci goto issue_diag_reset; 811362306a36Sopenharmony_ci } 811462306a36Sopenharmony_ci 811562306a36Sopenharmony_ci if (type == FORCE_BIG_HAMMER) 811662306a36Sopenharmony_ci goto issue_diag_reset; 811762306a36Sopenharmony_ci 811862306a36Sopenharmony_ci if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL) 811962306a36Sopenharmony_ci if (!(_base_send_ioc_reset(ioc, 812062306a36Sopenharmony_ci MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15))) { 812162306a36Sopenharmony_ci return 0; 812262306a36Sopenharmony_ci } 812362306a36Sopenharmony_ci 812462306a36Sopenharmony_ci issue_diag_reset: 812562306a36Sopenharmony_ci rc = _base_diag_reset(ioc); 812662306a36Sopenharmony_ci return rc; 812762306a36Sopenharmony_ci} 812862306a36Sopenharmony_ci 812962306a36Sopenharmony_ci/** 813062306a36Sopenharmony_ci * _base_make_ioc_operational - put controller in OPERATIONAL state 813162306a36Sopenharmony_ci * @ioc: per adapter object 813262306a36Sopenharmony_ci * 813362306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 813462306a36Sopenharmony_ci */ 813562306a36Sopenharmony_cistatic int 813662306a36Sopenharmony_ci_base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc) 813762306a36Sopenharmony_ci{ 813862306a36Sopenharmony_ci int r, i, index, rc; 813962306a36Sopenharmony_ci unsigned long flags; 814062306a36Sopenharmony_ci u32 reply_address; 814162306a36Sopenharmony_ci u16 smid; 814262306a36Sopenharmony_ci struct _tr_list *delayed_tr, *delayed_tr_next; 814362306a36Sopenharmony_ci struct _sc_list *delayed_sc, *delayed_sc_next; 814462306a36Sopenharmony_ci struct _event_ack_list *delayed_event_ack, *delayed_event_ack_next; 814562306a36Sopenharmony_ci u8 hide_flag; 814662306a36Sopenharmony_ci struct adapter_reply_queue *reply_q; 814762306a36Sopenharmony_ci Mpi2ReplyDescriptorsUnion_t *reply_post_free_contig; 814862306a36Sopenharmony_ci 814962306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 815062306a36Sopenharmony_ci 815162306a36Sopenharmony_ci /* clean the delayed target reset list */ 815262306a36Sopenharmony_ci list_for_each_entry_safe(delayed_tr, delayed_tr_next, 815362306a36Sopenharmony_ci &ioc->delayed_tr_list, list) { 815462306a36Sopenharmony_ci list_del(&delayed_tr->list); 815562306a36Sopenharmony_ci kfree(delayed_tr); 815662306a36Sopenharmony_ci } 815762306a36Sopenharmony_ci 815862306a36Sopenharmony_ci 815962306a36Sopenharmony_ci list_for_each_entry_safe(delayed_tr, delayed_tr_next, 816062306a36Sopenharmony_ci &ioc->delayed_tr_volume_list, list) { 816162306a36Sopenharmony_ci list_del(&delayed_tr->list); 816262306a36Sopenharmony_ci kfree(delayed_tr); 816362306a36Sopenharmony_ci } 816462306a36Sopenharmony_ci 816562306a36Sopenharmony_ci list_for_each_entry_safe(delayed_sc, delayed_sc_next, 816662306a36Sopenharmony_ci &ioc->delayed_sc_list, list) { 816762306a36Sopenharmony_ci list_del(&delayed_sc->list); 816862306a36Sopenharmony_ci kfree(delayed_sc); 816962306a36Sopenharmony_ci } 817062306a36Sopenharmony_ci 817162306a36Sopenharmony_ci list_for_each_entry_safe(delayed_event_ack, delayed_event_ack_next, 817262306a36Sopenharmony_ci &ioc->delayed_event_ack_list, list) { 817362306a36Sopenharmony_ci list_del(&delayed_event_ack->list); 817462306a36Sopenharmony_ci kfree(delayed_event_ack); 817562306a36Sopenharmony_ci } 817662306a36Sopenharmony_ci 817762306a36Sopenharmony_ci spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); 817862306a36Sopenharmony_ci 817962306a36Sopenharmony_ci /* hi-priority queue */ 818062306a36Sopenharmony_ci INIT_LIST_HEAD(&ioc->hpr_free_list); 818162306a36Sopenharmony_ci smid = ioc->hi_priority_smid; 818262306a36Sopenharmony_ci for (i = 0; i < ioc->hi_priority_depth; i++, smid++) { 818362306a36Sopenharmony_ci ioc->hpr_lookup[i].cb_idx = 0xFF; 818462306a36Sopenharmony_ci ioc->hpr_lookup[i].smid = smid; 818562306a36Sopenharmony_ci list_add_tail(&ioc->hpr_lookup[i].tracker_list, 818662306a36Sopenharmony_ci &ioc->hpr_free_list); 818762306a36Sopenharmony_ci } 818862306a36Sopenharmony_ci 818962306a36Sopenharmony_ci /* internal queue */ 819062306a36Sopenharmony_ci INIT_LIST_HEAD(&ioc->internal_free_list); 819162306a36Sopenharmony_ci smid = ioc->internal_smid; 819262306a36Sopenharmony_ci for (i = 0; i < ioc->internal_depth; i++, smid++) { 819362306a36Sopenharmony_ci ioc->internal_lookup[i].cb_idx = 0xFF; 819462306a36Sopenharmony_ci ioc->internal_lookup[i].smid = smid; 819562306a36Sopenharmony_ci list_add_tail(&ioc->internal_lookup[i].tracker_list, 819662306a36Sopenharmony_ci &ioc->internal_free_list); 819762306a36Sopenharmony_ci } 819862306a36Sopenharmony_ci 819962306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); 820062306a36Sopenharmony_ci 820162306a36Sopenharmony_ci /* initialize Reply Free Queue */ 820262306a36Sopenharmony_ci for (i = 0, reply_address = (u32)ioc->reply_dma ; 820362306a36Sopenharmony_ci i < ioc->reply_free_queue_depth ; i++, reply_address += 820462306a36Sopenharmony_ci ioc->reply_sz) { 820562306a36Sopenharmony_ci ioc->reply_free[i] = cpu_to_le32(reply_address); 820662306a36Sopenharmony_ci if (ioc->is_mcpu_endpoint) 820762306a36Sopenharmony_ci _base_clone_reply_to_sys_mem(ioc, 820862306a36Sopenharmony_ci reply_address, i); 820962306a36Sopenharmony_ci } 821062306a36Sopenharmony_ci 821162306a36Sopenharmony_ci /* initialize reply queues */ 821262306a36Sopenharmony_ci if (ioc->is_driver_loading) 821362306a36Sopenharmony_ci _base_assign_reply_queues(ioc); 821462306a36Sopenharmony_ci 821562306a36Sopenharmony_ci /* initialize Reply Post Free Queue */ 821662306a36Sopenharmony_ci index = 0; 821762306a36Sopenharmony_ci reply_post_free_contig = ioc->reply_post[0].reply_post_free; 821862306a36Sopenharmony_ci list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { 821962306a36Sopenharmony_ci /* 822062306a36Sopenharmony_ci * If RDPQ is enabled, switch to the next allocation. 822162306a36Sopenharmony_ci * Otherwise advance within the contiguous region. 822262306a36Sopenharmony_ci */ 822362306a36Sopenharmony_ci if (ioc->rdpq_array_enable) { 822462306a36Sopenharmony_ci reply_q->reply_post_free = 822562306a36Sopenharmony_ci ioc->reply_post[index++].reply_post_free; 822662306a36Sopenharmony_ci } else { 822762306a36Sopenharmony_ci reply_q->reply_post_free = reply_post_free_contig; 822862306a36Sopenharmony_ci reply_post_free_contig += ioc->reply_post_queue_depth; 822962306a36Sopenharmony_ci } 823062306a36Sopenharmony_ci 823162306a36Sopenharmony_ci reply_q->reply_post_host_index = 0; 823262306a36Sopenharmony_ci for (i = 0; i < ioc->reply_post_queue_depth; i++) 823362306a36Sopenharmony_ci reply_q->reply_post_free[i].Words = 823462306a36Sopenharmony_ci cpu_to_le64(ULLONG_MAX); 823562306a36Sopenharmony_ci if (!_base_is_controller_msix_enabled(ioc)) 823662306a36Sopenharmony_ci goto skip_init_reply_post_free_queue; 823762306a36Sopenharmony_ci } 823862306a36Sopenharmony_ci skip_init_reply_post_free_queue: 823962306a36Sopenharmony_ci 824062306a36Sopenharmony_ci r = _base_send_ioc_init(ioc); 824162306a36Sopenharmony_ci if (r) { 824262306a36Sopenharmony_ci /* 824362306a36Sopenharmony_ci * No need to check IOC state for fault state & issue 824462306a36Sopenharmony_ci * diag reset during host reset. This check is need 824562306a36Sopenharmony_ci * only during driver load time. 824662306a36Sopenharmony_ci */ 824762306a36Sopenharmony_ci if (!ioc->is_driver_loading) 824862306a36Sopenharmony_ci return r; 824962306a36Sopenharmony_ci 825062306a36Sopenharmony_ci rc = mpt3sas_base_check_for_fault_and_issue_reset(ioc); 825162306a36Sopenharmony_ci if (rc || (_base_send_ioc_init(ioc))) 825262306a36Sopenharmony_ci return r; 825362306a36Sopenharmony_ci } 825462306a36Sopenharmony_ci 825562306a36Sopenharmony_ci /* initialize reply free host index */ 825662306a36Sopenharmony_ci ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1; 825762306a36Sopenharmony_ci writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); 825862306a36Sopenharmony_ci 825962306a36Sopenharmony_ci /* initialize reply post host index */ 826062306a36Sopenharmony_ci list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { 826162306a36Sopenharmony_ci if (ioc->combined_reply_queue) 826262306a36Sopenharmony_ci writel((reply_q->msix_index & 7)<< 826362306a36Sopenharmony_ci MPI2_RPHI_MSIX_INDEX_SHIFT, 826462306a36Sopenharmony_ci ioc->replyPostRegisterIndex[reply_q->msix_index/8]); 826562306a36Sopenharmony_ci else 826662306a36Sopenharmony_ci writel(reply_q->msix_index << 826762306a36Sopenharmony_ci MPI2_RPHI_MSIX_INDEX_SHIFT, 826862306a36Sopenharmony_ci &ioc->chip->ReplyPostHostIndex); 826962306a36Sopenharmony_ci 827062306a36Sopenharmony_ci if (!_base_is_controller_msix_enabled(ioc)) 827162306a36Sopenharmony_ci goto skip_init_reply_post_host_index; 827262306a36Sopenharmony_ci } 827362306a36Sopenharmony_ci 827462306a36Sopenharmony_ci skip_init_reply_post_host_index: 827562306a36Sopenharmony_ci 827662306a36Sopenharmony_ci mpt3sas_base_unmask_interrupts(ioc); 827762306a36Sopenharmony_ci 827862306a36Sopenharmony_ci if (ioc->hba_mpi_version_belonged != MPI2_VERSION) { 827962306a36Sopenharmony_ci r = _base_display_fwpkg_version(ioc); 828062306a36Sopenharmony_ci if (r) 828162306a36Sopenharmony_ci return r; 828262306a36Sopenharmony_ci } 828362306a36Sopenharmony_ci 828462306a36Sopenharmony_ci r = _base_static_config_pages(ioc); 828562306a36Sopenharmony_ci if (r) 828662306a36Sopenharmony_ci return r; 828762306a36Sopenharmony_ci 828862306a36Sopenharmony_ci r = _base_event_notification(ioc); 828962306a36Sopenharmony_ci if (r) 829062306a36Sopenharmony_ci return r; 829162306a36Sopenharmony_ci 829262306a36Sopenharmony_ci if (!ioc->shost_recovery) { 829362306a36Sopenharmony_ci 829462306a36Sopenharmony_ci if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier 829562306a36Sopenharmony_ci == 0x80) { 829662306a36Sopenharmony_ci hide_flag = (u8) ( 829762306a36Sopenharmony_ci le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) & 829862306a36Sopenharmony_ci MFG_PAGE10_HIDE_SSDS_MASK); 829962306a36Sopenharmony_ci if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK) 830062306a36Sopenharmony_ci ioc->mfg_pg10_hide_flag = hide_flag; 830162306a36Sopenharmony_ci } 830262306a36Sopenharmony_ci 830362306a36Sopenharmony_ci ioc->wait_for_discovery_to_complete = 830462306a36Sopenharmony_ci _base_determine_wait_on_discovery(ioc); 830562306a36Sopenharmony_ci 830662306a36Sopenharmony_ci return r; /* scan_start and scan_finished support */ 830762306a36Sopenharmony_ci } 830862306a36Sopenharmony_ci 830962306a36Sopenharmony_ci r = _base_send_port_enable(ioc); 831062306a36Sopenharmony_ci if (r) 831162306a36Sopenharmony_ci return r; 831262306a36Sopenharmony_ci 831362306a36Sopenharmony_ci return r; 831462306a36Sopenharmony_ci} 831562306a36Sopenharmony_ci 831662306a36Sopenharmony_ci/** 831762306a36Sopenharmony_ci * mpt3sas_base_free_resources - free resources controller resources 831862306a36Sopenharmony_ci * @ioc: per adapter object 831962306a36Sopenharmony_ci */ 832062306a36Sopenharmony_civoid 832162306a36Sopenharmony_cimpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc) 832262306a36Sopenharmony_ci{ 832362306a36Sopenharmony_ci dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 832462306a36Sopenharmony_ci 832562306a36Sopenharmony_ci /* synchronizing freeing resource with pci_access_mutex lock */ 832662306a36Sopenharmony_ci mutex_lock(&ioc->pci_access_mutex); 832762306a36Sopenharmony_ci if (ioc->chip_phys && ioc->chip) { 832862306a36Sopenharmony_ci mpt3sas_base_mask_interrupts(ioc); 832962306a36Sopenharmony_ci ioc->shost_recovery = 1; 833062306a36Sopenharmony_ci mpt3sas_base_make_ioc_ready(ioc, SOFT_RESET); 833162306a36Sopenharmony_ci ioc->shost_recovery = 0; 833262306a36Sopenharmony_ci } 833362306a36Sopenharmony_ci 833462306a36Sopenharmony_ci mpt3sas_base_unmap_resources(ioc); 833562306a36Sopenharmony_ci mutex_unlock(&ioc->pci_access_mutex); 833662306a36Sopenharmony_ci return; 833762306a36Sopenharmony_ci} 833862306a36Sopenharmony_ci 833962306a36Sopenharmony_ci/** 834062306a36Sopenharmony_ci * mpt3sas_base_attach - attach controller instance 834162306a36Sopenharmony_ci * @ioc: per adapter object 834262306a36Sopenharmony_ci * 834362306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 834462306a36Sopenharmony_ci */ 834562306a36Sopenharmony_ciint 834662306a36Sopenharmony_cimpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) 834762306a36Sopenharmony_ci{ 834862306a36Sopenharmony_ci int r, i, rc; 834962306a36Sopenharmony_ci int cpu_id, last_cpu_id = 0; 835062306a36Sopenharmony_ci 835162306a36Sopenharmony_ci dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 835262306a36Sopenharmony_ci 835362306a36Sopenharmony_ci /* setup cpu_msix_table */ 835462306a36Sopenharmony_ci ioc->cpu_count = num_online_cpus(); 835562306a36Sopenharmony_ci for_each_online_cpu(cpu_id) 835662306a36Sopenharmony_ci last_cpu_id = cpu_id; 835762306a36Sopenharmony_ci ioc->cpu_msix_table_sz = last_cpu_id + 1; 835862306a36Sopenharmony_ci ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL); 835962306a36Sopenharmony_ci ioc->reply_queue_count = 1; 836062306a36Sopenharmony_ci if (!ioc->cpu_msix_table) { 836162306a36Sopenharmony_ci ioc_info(ioc, "Allocation for cpu_msix_table failed!!!\n"); 836262306a36Sopenharmony_ci r = -ENOMEM; 836362306a36Sopenharmony_ci goto out_free_resources; 836462306a36Sopenharmony_ci } 836562306a36Sopenharmony_ci 836662306a36Sopenharmony_ci if (ioc->is_warpdrive) { 836762306a36Sopenharmony_ci ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz, 836862306a36Sopenharmony_ci sizeof(resource_size_t *), GFP_KERNEL); 836962306a36Sopenharmony_ci if (!ioc->reply_post_host_index) { 837062306a36Sopenharmony_ci ioc_info(ioc, "Allocation for reply_post_host_index failed!!!\n"); 837162306a36Sopenharmony_ci r = -ENOMEM; 837262306a36Sopenharmony_ci goto out_free_resources; 837362306a36Sopenharmony_ci } 837462306a36Sopenharmony_ci } 837562306a36Sopenharmony_ci 837662306a36Sopenharmony_ci ioc->smp_affinity_enable = smp_affinity_enable; 837762306a36Sopenharmony_ci 837862306a36Sopenharmony_ci ioc->rdpq_array_enable_assigned = 0; 837962306a36Sopenharmony_ci ioc->use_32bit_dma = false; 838062306a36Sopenharmony_ci ioc->dma_mask = 64; 838162306a36Sopenharmony_ci if (ioc->is_aero_ioc) { 838262306a36Sopenharmony_ci ioc->base_readl = &_base_readl_aero; 838362306a36Sopenharmony_ci ioc->base_readl_ext_retry = &_base_readl_ext_retry; 838462306a36Sopenharmony_ci } else { 838562306a36Sopenharmony_ci ioc->base_readl = &_base_readl; 838662306a36Sopenharmony_ci ioc->base_readl_ext_retry = &_base_readl; 838762306a36Sopenharmony_ci } 838862306a36Sopenharmony_ci r = mpt3sas_base_map_resources(ioc); 838962306a36Sopenharmony_ci if (r) 839062306a36Sopenharmony_ci goto out_free_resources; 839162306a36Sopenharmony_ci 839262306a36Sopenharmony_ci pci_set_drvdata(ioc->pdev, ioc->shost); 839362306a36Sopenharmony_ci r = _base_get_ioc_facts(ioc); 839462306a36Sopenharmony_ci if (r) { 839562306a36Sopenharmony_ci rc = mpt3sas_base_check_for_fault_and_issue_reset(ioc); 839662306a36Sopenharmony_ci if (rc || (_base_get_ioc_facts(ioc))) 839762306a36Sopenharmony_ci goto out_free_resources; 839862306a36Sopenharmony_ci } 839962306a36Sopenharmony_ci 840062306a36Sopenharmony_ci switch (ioc->hba_mpi_version_belonged) { 840162306a36Sopenharmony_ci case MPI2_VERSION: 840262306a36Sopenharmony_ci ioc->build_sg_scmd = &_base_build_sg_scmd; 840362306a36Sopenharmony_ci ioc->build_sg = &_base_build_sg; 840462306a36Sopenharmony_ci ioc->build_zero_len_sge = &_base_build_zero_len_sge; 840562306a36Sopenharmony_ci ioc->get_msix_index_for_smlio = &_base_get_msix_index; 840662306a36Sopenharmony_ci break; 840762306a36Sopenharmony_ci case MPI25_VERSION: 840862306a36Sopenharmony_ci case MPI26_VERSION: 840962306a36Sopenharmony_ci /* 841062306a36Sopenharmony_ci * In SAS3.0, 841162306a36Sopenharmony_ci * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and 841262306a36Sopenharmony_ci * Target Status - all require the IEEE formatted scatter gather 841362306a36Sopenharmony_ci * elements. 841462306a36Sopenharmony_ci */ 841562306a36Sopenharmony_ci ioc->build_sg_scmd = &_base_build_sg_scmd_ieee; 841662306a36Sopenharmony_ci ioc->build_sg = &_base_build_sg_ieee; 841762306a36Sopenharmony_ci ioc->build_nvme_prp = &_base_build_nvme_prp; 841862306a36Sopenharmony_ci ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee; 841962306a36Sopenharmony_ci ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t); 842062306a36Sopenharmony_ci if (ioc->high_iops_queues) 842162306a36Sopenharmony_ci ioc->get_msix_index_for_smlio = 842262306a36Sopenharmony_ci &_base_get_high_iops_msix_index; 842362306a36Sopenharmony_ci else 842462306a36Sopenharmony_ci ioc->get_msix_index_for_smlio = &_base_get_msix_index; 842562306a36Sopenharmony_ci break; 842662306a36Sopenharmony_ci } 842762306a36Sopenharmony_ci if (ioc->atomic_desc_capable) { 842862306a36Sopenharmony_ci ioc->put_smid_default = &_base_put_smid_default_atomic; 842962306a36Sopenharmony_ci ioc->put_smid_scsi_io = &_base_put_smid_scsi_io_atomic; 843062306a36Sopenharmony_ci ioc->put_smid_fast_path = 843162306a36Sopenharmony_ci &_base_put_smid_fast_path_atomic; 843262306a36Sopenharmony_ci ioc->put_smid_hi_priority = 843362306a36Sopenharmony_ci &_base_put_smid_hi_priority_atomic; 843462306a36Sopenharmony_ci } else { 843562306a36Sopenharmony_ci ioc->put_smid_default = &_base_put_smid_default; 843662306a36Sopenharmony_ci ioc->put_smid_fast_path = &_base_put_smid_fast_path; 843762306a36Sopenharmony_ci ioc->put_smid_hi_priority = &_base_put_smid_hi_priority; 843862306a36Sopenharmony_ci if (ioc->is_mcpu_endpoint) 843962306a36Sopenharmony_ci ioc->put_smid_scsi_io = 844062306a36Sopenharmony_ci &_base_put_smid_mpi_ep_scsi_io; 844162306a36Sopenharmony_ci else 844262306a36Sopenharmony_ci ioc->put_smid_scsi_io = &_base_put_smid_scsi_io; 844362306a36Sopenharmony_ci } 844462306a36Sopenharmony_ci /* 844562306a36Sopenharmony_ci * These function pointers for other requests that don't 844662306a36Sopenharmony_ci * the require IEEE scatter gather elements. 844762306a36Sopenharmony_ci * 844862306a36Sopenharmony_ci * For example Configuration Pages and SAS IOUNIT Control don't. 844962306a36Sopenharmony_ci */ 845062306a36Sopenharmony_ci ioc->build_sg_mpi = &_base_build_sg; 845162306a36Sopenharmony_ci ioc->build_zero_len_sge_mpi = &_base_build_zero_len_sge; 845262306a36Sopenharmony_ci 845362306a36Sopenharmony_ci r = mpt3sas_base_make_ioc_ready(ioc, SOFT_RESET); 845462306a36Sopenharmony_ci if (r) 845562306a36Sopenharmony_ci goto out_free_resources; 845662306a36Sopenharmony_ci 845762306a36Sopenharmony_ci ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, 845862306a36Sopenharmony_ci sizeof(struct mpt3sas_port_facts), GFP_KERNEL); 845962306a36Sopenharmony_ci if (!ioc->pfacts) { 846062306a36Sopenharmony_ci r = -ENOMEM; 846162306a36Sopenharmony_ci goto out_free_resources; 846262306a36Sopenharmony_ci } 846362306a36Sopenharmony_ci 846462306a36Sopenharmony_ci for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { 846562306a36Sopenharmony_ci r = _base_get_port_facts(ioc, i); 846662306a36Sopenharmony_ci if (r) { 846762306a36Sopenharmony_ci rc = mpt3sas_base_check_for_fault_and_issue_reset(ioc); 846862306a36Sopenharmony_ci if (rc || (_base_get_port_facts(ioc, i))) 846962306a36Sopenharmony_ci goto out_free_resources; 847062306a36Sopenharmony_ci } 847162306a36Sopenharmony_ci } 847262306a36Sopenharmony_ci 847362306a36Sopenharmony_ci r = _base_allocate_memory_pools(ioc); 847462306a36Sopenharmony_ci if (r) 847562306a36Sopenharmony_ci goto out_free_resources; 847662306a36Sopenharmony_ci 847762306a36Sopenharmony_ci if (irqpoll_weight > 0) 847862306a36Sopenharmony_ci ioc->thresh_hold = irqpoll_weight; 847962306a36Sopenharmony_ci else 848062306a36Sopenharmony_ci ioc->thresh_hold = ioc->hba_queue_depth/4; 848162306a36Sopenharmony_ci 848262306a36Sopenharmony_ci _base_init_irqpolls(ioc); 848362306a36Sopenharmony_ci init_waitqueue_head(&ioc->reset_wq); 848462306a36Sopenharmony_ci 848562306a36Sopenharmony_ci /* allocate memory pd handle bitmask list */ 848662306a36Sopenharmony_ci ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8); 848762306a36Sopenharmony_ci if (ioc->facts.MaxDevHandle % 8) 848862306a36Sopenharmony_ci ioc->pd_handles_sz++; 848962306a36Sopenharmony_ci ioc->pd_handles = kzalloc(ioc->pd_handles_sz, 849062306a36Sopenharmony_ci GFP_KERNEL); 849162306a36Sopenharmony_ci if (!ioc->pd_handles) { 849262306a36Sopenharmony_ci r = -ENOMEM; 849362306a36Sopenharmony_ci goto out_free_resources; 849462306a36Sopenharmony_ci } 849562306a36Sopenharmony_ci ioc->blocking_handles = kzalloc(ioc->pd_handles_sz, 849662306a36Sopenharmony_ci GFP_KERNEL); 849762306a36Sopenharmony_ci if (!ioc->blocking_handles) { 849862306a36Sopenharmony_ci r = -ENOMEM; 849962306a36Sopenharmony_ci goto out_free_resources; 850062306a36Sopenharmony_ci } 850162306a36Sopenharmony_ci 850262306a36Sopenharmony_ci /* allocate memory for pending OS device add list */ 850362306a36Sopenharmony_ci ioc->pend_os_device_add_sz = (ioc->facts.MaxDevHandle / 8); 850462306a36Sopenharmony_ci if (ioc->facts.MaxDevHandle % 8) 850562306a36Sopenharmony_ci ioc->pend_os_device_add_sz++; 850662306a36Sopenharmony_ci ioc->pend_os_device_add = kzalloc(ioc->pend_os_device_add_sz, 850762306a36Sopenharmony_ci GFP_KERNEL); 850862306a36Sopenharmony_ci if (!ioc->pend_os_device_add) { 850962306a36Sopenharmony_ci r = -ENOMEM; 851062306a36Sopenharmony_ci goto out_free_resources; 851162306a36Sopenharmony_ci } 851262306a36Sopenharmony_ci 851362306a36Sopenharmony_ci ioc->device_remove_in_progress_sz = ioc->pend_os_device_add_sz; 851462306a36Sopenharmony_ci ioc->device_remove_in_progress = 851562306a36Sopenharmony_ci kzalloc(ioc->device_remove_in_progress_sz, GFP_KERNEL); 851662306a36Sopenharmony_ci if (!ioc->device_remove_in_progress) { 851762306a36Sopenharmony_ci r = -ENOMEM; 851862306a36Sopenharmony_ci goto out_free_resources; 851962306a36Sopenharmony_ci } 852062306a36Sopenharmony_ci 852162306a36Sopenharmony_ci ioc->fwfault_debug = mpt3sas_fwfault_debug; 852262306a36Sopenharmony_ci 852362306a36Sopenharmony_ci /* base internal command bits */ 852462306a36Sopenharmony_ci mutex_init(&ioc->base_cmds.mutex); 852562306a36Sopenharmony_ci ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); 852662306a36Sopenharmony_ci ioc->base_cmds.status = MPT3_CMD_NOT_USED; 852762306a36Sopenharmony_ci 852862306a36Sopenharmony_ci /* port_enable command bits */ 852962306a36Sopenharmony_ci ioc->port_enable_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); 853062306a36Sopenharmony_ci ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED; 853162306a36Sopenharmony_ci 853262306a36Sopenharmony_ci /* transport internal command bits */ 853362306a36Sopenharmony_ci ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); 853462306a36Sopenharmony_ci ioc->transport_cmds.status = MPT3_CMD_NOT_USED; 853562306a36Sopenharmony_ci mutex_init(&ioc->transport_cmds.mutex); 853662306a36Sopenharmony_ci 853762306a36Sopenharmony_ci /* scsih internal command bits */ 853862306a36Sopenharmony_ci ioc->scsih_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); 853962306a36Sopenharmony_ci ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; 854062306a36Sopenharmony_ci mutex_init(&ioc->scsih_cmds.mutex); 854162306a36Sopenharmony_ci 854262306a36Sopenharmony_ci /* task management internal command bits */ 854362306a36Sopenharmony_ci ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); 854462306a36Sopenharmony_ci ioc->tm_cmds.status = MPT3_CMD_NOT_USED; 854562306a36Sopenharmony_ci mutex_init(&ioc->tm_cmds.mutex); 854662306a36Sopenharmony_ci 854762306a36Sopenharmony_ci /* config page internal command bits */ 854862306a36Sopenharmony_ci ioc->config_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); 854962306a36Sopenharmony_ci ioc->config_cmds.status = MPT3_CMD_NOT_USED; 855062306a36Sopenharmony_ci mutex_init(&ioc->config_cmds.mutex); 855162306a36Sopenharmony_ci 855262306a36Sopenharmony_ci /* ctl module internal command bits */ 855362306a36Sopenharmony_ci ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); 855462306a36Sopenharmony_ci ioc->ctl_cmds.sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); 855562306a36Sopenharmony_ci ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; 855662306a36Sopenharmony_ci mutex_init(&ioc->ctl_cmds.mutex); 855762306a36Sopenharmony_ci 855862306a36Sopenharmony_ci if (!ioc->base_cmds.reply || !ioc->port_enable_cmds.reply || 855962306a36Sopenharmony_ci !ioc->transport_cmds.reply || !ioc->scsih_cmds.reply || 856062306a36Sopenharmony_ci !ioc->tm_cmds.reply || !ioc->config_cmds.reply || 856162306a36Sopenharmony_ci !ioc->ctl_cmds.reply || !ioc->ctl_cmds.sense) { 856262306a36Sopenharmony_ci r = -ENOMEM; 856362306a36Sopenharmony_ci goto out_free_resources; 856462306a36Sopenharmony_ci } 856562306a36Sopenharmony_ci 856662306a36Sopenharmony_ci for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 856762306a36Sopenharmony_ci ioc->event_masks[i] = -1; 856862306a36Sopenharmony_ci 856962306a36Sopenharmony_ci /* here we enable the events we care about */ 857062306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_SAS_DISCOVERY); 857162306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE); 857262306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); 857362306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); 857462306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); 857562306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); 857662306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_IR_VOLUME); 857762306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK); 857862306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS); 857962306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED); 858062306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_TEMP_THRESHOLD); 858162306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION); 858262306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_SAS_DEVICE_DISCOVERY_ERROR); 858362306a36Sopenharmony_ci if (ioc->hba_mpi_version_belonged == MPI26_VERSION) { 858462306a36Sopenharmony_ci if (ioc->is_gen35_ioc) { 858562306a36Sopenharmony_ci _base_unmask_events(ioc, 858662306a36Sopenharmony_ci MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE); 858762306a36Sopenharmony_ci _base_unmask_events(ioc, MPI2_EVENT_PCIE_ENUMERATION); 858862306a36Sopenharmony_ci _base_unmask_events(ioc, 858962306a36Sopenharmony_ci MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST); 859062306a36Sopenharmony_ci } 859162306a36Sopenharmony_ci } 859262306a36Sopenharmony_ci r = _base_make_ioc_operational(ioc); 859362306a36Sopenharmony_ci if (r == -EAGAIN) { 859462306a36Sopenharmony_ci r = _base_make_ioc_operational(ioc); 859562306a36Sopenharmony_ci if (r) 859662306a36Sopenharmony_ci goto out_free_resources; 859762306a36Sopenharmony_ci } 859862306a36Sopenharmony_ci 859962306a36Sopenharmony_ci /* 860062306a36Sopenharmony_ci * Copy current copy of IOCFacts in prev_fw_facts 860162306a36Sopenharmony_ci * and it will be used during online firmware upgrade. 860262306a36Sopenharmony_ci */ 860362306a36Sopenharmony_ci memcpy(&ioc->prev_fw_facts, &ioc->facts, 860462306a36Sopenharmony_ci sizeof(struct mpt3sas_facts)); 860562306a36Sopenharmony_ci 860662306a36Sopenharmony_ci ioc->non_operational_loop = 0; 860762306a36Sopenharmony_ci ioc->ioc_coredump_loop = 0; 860862306a36Sopenharmony_ci ioc->got_task_abort_from_ioctl = 0; 860962306a36Sopenharmony_ci return 0; 861062306a36Sopenharmony_ci 861162306a36Sopenharmony_ci out_free_resources: 861262306a36Sopenharmony_ci 861362306a36Sopenharmony_ci ioc->remove_host = 1; 861462306a36Sopenharmony_ci 861562306a36Sopenharmony_ci mpt3sas_base_free_resources(ioc); 861662306a36Sopenharmony_ci _base_release_memory_pools(ioc); 861762306a36Sopenharmony_ci pci_set_drvdata(ioc->pdev, NULL); 861862306a36Sopenharmony_ci kfree(ioc->cpu_msix_table); 861962306a36Sopenharmony_ci if (ioc->is_warpdrive) 862062306a36Sopenharmony_ci kfree(ioc->reply_post_host_index); 862162306a36Sopenharmony_ci kfree(ioc->pd_handles); 862262306a36Sopenharmony_ci kfree(ioc->blocking_handles); 862362306a36Sopenharmony_ci kfree(ioc->device_remove_in_progress); 862462306a36Sopenharmony_ci kfree(ioc->pend_os_device_add); 862562306a36Sopenharmony_ci kfree(ioc->tm_cmds.reply); 862662306a36Sopenharmony_ci kfree(ioc->transport_cmds.reply); 862762306a36Sopenharmony_ci kfree(ioc->scsih_cmds.reply); 862862306a36Sopenharmony_ci kfree(ioc->config_cmds.reply); 862962306a36Sopenharmony_ci kfree(ioc->base_cmds.reply); 863062306a36Sopenharmony_ci kfree(ioc->port_enable_cmds.reply); 863162306a36Sopenharmony_ci kfree(ioc->ctl_cmds.reply); 863262306a36Sopenharmony_ci kfree(ioc->ctl_cmds.sense); 863362306a36Sopenharmony_ci kfree(ioc->pfacts); 863462306a36Sopenharmony_ci ioc->ctl_cmds.reply = NULL; 863562306a36Sopenharmony_ci ioc->base_cmds.reply = NULL; 863662306a36Sopenharmony_ci ioc->tm_cmds.reply = NULL; 863762306a36Sopenharmony_ci ioc->scsih_cmds.reply = NULL; 863862306a36Sopenharmony_ci ioc->transport_cmds.reply = NULL; 863962306a36Sopenharmony_ci ioc->config_cmds.reply = NULL; 864062306a36Sopenharmony_ci ioc->pfacts = NULL; 864162306a36Sopenharmony_ci return r; 864262306a36Sopenharmony_ci} 864362306a36Sopenharmony_ci 864462306a36Sopenharmony_ci 864562306a36Sopenharmony_ci/** 864662306a36Sopenharmony_ci * mpt3sas_base_detach - remove controller instance 864762306a36Sopenharmony_ci * @ioc: per adapter object 864862306a36Sopenharmony_ci */ 864962306a36Sopenharmony_civoid 865062306a36Sopenharmony_cimpt3sas_base_detach(struct MPT3SAS_ADAPTER *ioc) 865162306a36Sopenharmony_ci{ 865262306a36Sopenharmony_ci dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); 865362306a36Sopenharmony_ci 865462306a36Sopenharmony_ci mpt3sas_base_stop_watchdog(ioc); 865562306a36Sopenharmony_ci mpt3sas_base_free_resources(ioc); 865662306a36Sopenharmony_ci _base_release_memory_pools(ioc); 865762306a36Sopenharmony_ci mpt3sas_free_enclosure_list(ioc); 865862306a36Sopenharmony_ci pci_set_drvdata(ioc->pdev, NULL); 865962306a36Sopenharmony_ci kfree(ioc->cpu_msix_table); 866062306a36Sopenharmony_ci if (ioc->is_warpdrive) 866162306a36Sopenharmony_ci kfree(ioc->reply_post_host_index); 866262306a36Sopenharmony_ci kfree(ioc->pd_handles); 866362306a36Sopenharmony_ci kfree(ioc->blocking_handles); 866462306a36Sopenharmony_ci kfree(ioc->device_remove_in_progress); 866562306a36Sopenharmony_ci kfree(ioc->pend_os_device_add); 866662306a36Sopenharmony_ci kfree(ioc->pfacts); 866762306a36Sopenharmony_ci kfree(ioc->ctl_cmds.reply); 866862306a36Sopenharmony_ci kfree(ioc->ctl_cmds.sense); 866962306a36Sopenharmony_ci kfree(ioc->base_cmds.reply); 867062306a36Sopenharmony_ci kfree(ioc->port_enable_cmds.reply); 867162306a36Sopenharmony_ci kfree(ioc->tm_cmds.reply); 867262306a36Sopenharmony_ci kfree(ioc->transport_cmds.reply); 867362306a36Sopenharmony_ci kfree(ioc->scsih_cmds.reply); 867462306a36Sopenharmony_ci kfree(ioc->config_cmds.reply); 867562306a36Sopenharmony_ci} 867662306a36Sopenharmony_ci 867762306a36Sopenharmony_ci/** 867862306a36Sopenharmony_ci * _base_pre_reset_handler - pre reset handler 867962306a36Sopenharmony_ci * @ioc: per adapter object 868062306a36Sopenharmony_ci */ 868162306a36Sopenharmony_cistatic void _base_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc) 868262306a36Sopenharmony_ci{ 868362306a36Sopenharmony_ci mpt3sas_scsih_pre_reset_handler(ioc); 868462306a36Sopenharmony_ci mpt3sas_ctl_pre_reset_handler(ioc); 868562306a36Sopenharmony_ci dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_PRE_RESET\n", __func__)); 868662306a36Sopenharmony_ci} 868762306a36Sopenharmony_ci 868862306a36Sopenharmony_ci/** 868962306a36Sopenharmony_ci * _base_clear_outstanding_mpt_commands - clears outstanding mpt commands 869062306a36Sopenharmony_ci * @ioc: per adapter object 869162306a36Sopenharmony_ci */ 869262306a36Sopenharmony_cistatic void 869362306a36Sopenharmony_ci_base_clear_outstanding_mpt_commands(struct MPT3SAS_ADAPTER *ioc) 869462306a36Sopenharmony_ci{ 869562306a36Sopenharmony_ci dtmprintk(ioc, 869662306a36Sopenharmony_ci ioc_info(ioc, "%s: clear outstanding mpt cmds\n", __func__)); 869762306a36Sopenharmony_ci if (ioc->transport_cmds.status & MPT3_CMD_PENDING) { 869862306a36Sopenharmony_ci ioc->transport_cmds.status |= MPT3_CMD_RESET; 869962306a36Sopenharmony_ci mpt3sas_base_free_smid(ioc, ioc->transport_cmds.smid); 870062306a36Sopenharmony_ci complete(&ioc->transport_cmds.done); 870162306a36Sopenharmony_ci } 870262306a36Sopenharmony_ci if (ioc->base_cmds.status & MPT3_CMD_PENDING) { 870362306a36Sopenharmony_ci ioc->base_cmds.status |= MPT3_CMD_RESET; 870462306a36Sopenharmony_ci mpt3sas_base_free_smid(ioc, ioc->base_cmds.smid); 870562306a36Sopenharmony_ci complete(&ioc->base_cmds.done); 870662306a36Sopenharmony_ci } 870762306a36Sopenharmony_ci if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) { 870862306a36Sopenharmony_ci ioc->port_enable_failed = 1; 870962306a36Sopenharmony_ci ioc->port_enable_cmds.status |= MPT3_CMD_RESET; 871062306a36Sopenharmony_ci mpt3sas_base_free_smid(ioc, ioc->port_enable_cmds.smid); 871162306a36Sopenharmony_ci if (ioc->is_driver_loading) { 871262306a36Sopenharmony_ci ioc->start_scan_failed = 871362306a36Sopenharmony_ci MPI2_IOCSTATUS_INTERNAL_ERROR; 871462306a36Sopenharmony_ci ioc->start_scan = 0; 871562306a36Sopenharmony_ci } else { 871662306a36Sopenharmony_ci complete(&ioc->port_enable_cmds.done); 871762306a36Sopenharmony_ci } 871862306a36Sopenharmony_ci } 871962306a36Sopenharmony_ci if (ioc->config_cmds.status & MPT3_CMD_PENDING) { 872062306a36Sopenharmony_ci ioc->config_cmds.status |= MPT3_CMD_RESET; 872162306a36Sopenharmony_ci mpt3sas_base_free_smid(ioc, ioc->config_cmds.smid); 872262306a36Sopenharmony_ci ioc->config_cmds.smid = USHRT_MAX; 872362306a36Sopenharmony_ci complete(&ioc->config_cmds.done); 872462306a36Sopenharmony_ci } 872562306a36Sopenharmony_ci} 872662306a36Sopenharmony_ci 872762306a36Sopenharmony_ci/** 872862306a36Sopenharmony_ci * _base_clear_outstanding_commands - clear all outstanding commands 872962306a36Sopenharmony_ci * @ioc: per adapter object 873062306a36Sopenharmony_ci */ 873162306a36Sopenharmony_cistatic void _base_clear_outstanding_commands(struct MPT3SAS_ADAPTER *ioc) 873262306a36Sopenharmony_ci{ 873362306a36Sopenharmony_ci mpt3sas_scsih_clear_outstanding_scsi_tm_commands(ioc); 873462306a36Sopenharmony_ci mpt3sas_ctl_clear_outstanding_ioctls(ioc); 873562306a36Sopenharmony_ci _base_clear_outstanding_mpt_commands(ioc); 873662306a36Sopenharmony_ci} 873762306a36Sopenharmony_ci 873862306a36Sopenharmony_ci/** 873962306a36Sopenharmony_ci * _base_reset_done_handler - reset done handler 874062306a36Sopenharmony_ci * @ioc: per adapter object 874162306a36Sopenharmony_ci */ 874262306a36Sopenharmony_cistatic void _base_reset_done_handler(struct MPT3SAS_ADAPTER *ioc) 874362306a36Sopenharmony_ci{ 874462306a36Sopenharmony_ci mpt3sas_scsih_reset_done_handler(ioc); 874562306a36Sopenharmony_ci mpt3sas_ctl_reset_done_handler(ioc); 874662306a36Sopenharmony_ci dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_DONE_RESET\n", __func__)); 874762306a36Sopenharmony_ci} 874862306a36Sopenharmony_ci 874962306a36Sopenharmony_ci/** 875062306a36Sopenharmony_ci * mpt3sas_wait_for_commands_to_complete - reset controller 875162306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 875262306a36Sopenharmony_ci * 875362306a36Sopenharmony_ci * This function is waiting 10s for all pending commands to complete 875462306a36Sopenharmony_ci * prior to putting controller in reset. 875562306a36Sopenharmony_ci */ 875662306a36Sopenharmony_civoid 875762306a36Sopenharmony_cimpt3sas_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc) 875862306a36Sopenharmony_ci{ 875962306a36Sopenharmony_ci u32 ioc_state; 876062306a36Sopenharmony_ci 876162306a36Sopenharmony_ci ioc->pending_io_count = 0; 876262306a36Sopenharmony_ci 876362306a36Sopenharmony_ci ioc_state = mpt3sas_base_get_iocstate(ioc, 0); 876462306a36Sopenharmony_ci if ((ioc_state & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) 876562306a36Sopenharmony_ci return; 876662306a36Sopenharmony_ci 876762306a36Sopenharmony_ci /* pending command count */ 876862306a36Sopenharmony_ci ioc->pending_io_count = scsi_host_busy(ioc->shost); 876962306a36Sopenharmony_ci 877062306a36Sopenharmony_ci if (!ioc->pending_io_count) 877162306a36Sopenharmony_ci return; 877262306a36Sopenharmony_ci 877362306a36Sopenharmony_ci /* wait for pending commands to complete */ 877462306a36Sopenharmony_ci wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ); 877562306a36Sopenharmony_ci} 877662306a36Sopenharmony_ci 877762306a36Sopenharmony_ci/** 877862306a36Sopenharmony_ci * _base_check_ioc_facts_changes - Look for increase/decrease of IOCFacts 877962306a36Sopenharmony_ci * attributes during online firmware upgrade and update the corresponding 878062306a36Sopenharmony_ci * IOC variables accordingly. 878162306a36Sopenharmony_ci * 878262306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 878362306a36Sopenharmony_ci */ 878462306a36Sopenharmony_cistatic int 878562306a36Sopenharmony_ci_base_check_ioc_facts_changes(struct MPT3SAS_ADAPTER *ioc) 878662306a36Sopenharmony_ci{ 878762306a36Sopenharmony_ci u16 pd_handles_sz; 878862306a36Sopenharmony_ci void *pd_handles = NULL, *blocking_handles = NULL; 878962306a36Sopenharmony_ci void *pend_os_device_add = NULL, *device_remove_in_progress = NULL; 879062306a36Sopenharmony_ci struct mpt3sas_facts *old_facts = &ioc->prev_fw_facts; 879162306a36Sopenharmony_ci 879262306a36Sopenharmony_ci if (ioc->facts.MaxDevHandle > old_facts->MaxDevHandle) { 879362306a36Sopenharmony_ci pd_handles_sz = (ioc->facts.MaxDevHandle / 8); 879462306a36Sopenharmony_ci if (ioc->facts.MaxDevHandle % 8) 879562306a36Sopenharmony_ci pd_handles_sz++; 879662306a36Sopenharmony_ci 879762306a36Sopenharmony_ci pd_handles = krealloc(ioc->pd_handles, pd_handles_sz, 879862306a36Sopenharmony_ci GFP_KERNEL); 879962306a36Sopenharmony_ci if (!pd_handles) { 880062306a36Sopenharmony_ci ioc_info(ioc, 880162306a36Sopenharmony_ci "Unable to allocate the memory for pd_handles of sz: %d\n", 880262306a36Sopenharmony_ci pd_handles_sz); 880362306a36Sopenharmony_ci return -ENOMEM; 880462306a36Sopenharmony_ci } 880562306a36Sopenharmony_ci memset(pd_handles + ioc->pd_handles_sz, 0, 880662306a36Sopenharmony_ci (pd_handles_sz - ioc->pd_handles_sz)); 880762306a36Sopenharmony_ci ioc->pd_handles = pd_handles; 880862306a36Sopenharmony_ci 880962306a36Sopenharmony_ci blocking_handles = krealloc(ioc->blocking_handles, 881062306a36Sopenharmony_ci pd_handles_sz, GFP_KERNEL); 881162306a36Sopenharmony_ci if (!blocking_handles) { 881262306a36Sopenharmony_ci ioc_info(ioc, 881362306a36Sopenharmony_ci "Unable to allocate the memory for " 881462306a36Sopenharmony_ci "blocking_handles of sz: %d\n", 881562306a36Sopenharmony_ci pd_handles_sz); 881662306a36Sopenharmony_ci return -ENOMEM; 881762306a36Sopenharmony_ci } 881862306a36Sopenharmony_ci memset(blocking_handles + ioc->pd_handles_sz, 0, 881962306a36Sopenharmony_ci (pd_handles_sz - ioc->pd_handles_sz)); 882062306a36Sopenharmony_ci ioc->blocking_handles = blocking_handles; 882162306a36Sopenharmony_ci ioc->pd_handles_sz = pd_handles_sz; 882262306a36Sopenharmony_ci 882362306a36Sopenharmony_ci pend_os_device_add = krealloc(ioc->pend_os_device_add, 882462306a36Sopenharmony_ci pd_handles_sz, GFP_KERNEL); 882562306a36Sopenharmony_ci if (!pend_os_device_add) { 882662306a36Sopenharmony_ci ioc_info(ioc, 882762306a36Sopenharmony_ci "Unable to allocate the memory for pend_os_device_add of sz: %d\n", 882862306a36Sopenharmony_ci pd_handles_sz); 882962306a36Sopenharmony_ci return -ENOMEM; 883062306a36Sopenharmony_ci } 883162306a36Sopenharmony_ci memset(pend_os_device_add + ioc->pend_os_device_add_sz, 0, 883262306a36Sopenharmony_ci (pd_handles_sz - ioc->pend_os_device_add_sz)); 883362306a36Sopenharmony_ci ioc->pend_os_device_add = pend_os_device_add; 883462306a36Sopenharmony_ci ioc->pend_os_device_add_sz = pd_handles_sz; 883562306a36Sopenharmony_ci 883662306a36Sopenharmony_ci device_remove_in_progress = krealloc( 883762306a36Sopenharmony_ci ioc->device_remove_in_progress, pd_handles_sz, GFP_KERNEL); 883862306a36Sopenharmony_ci if (!device_remove_in_progress) { 883962306a36Sopenharmony_ci ioc_info(ioc, 884062306a36Sopenharmony_ci "Unable to allocate the memory for " 884162306a36Sopenharmony_ci "device_remove_in_progress of sz: %d\n " 884262306a36Sopenharmony_ci , pd_handles_sz); 884362306a36Sopenharmony_ci return -ENOMEM; 884462306a36Sopenharmony_ci } 884562306a36Sopenharmony_ci memset(device_remove_in_progress + 884662306a36Sopenharmony_ci ioc->device_remove_in_progress_sz, 0, 884762306a36Sopenharmony_ci (pd_handles_sz - ioc->device_remove_in_progress_sz)); 884862306a36Sopenharmony_ci ioc->device_remove_in_progress = device_remove_in_progress; 884962306a36Sopenharmony_ci ioc->device_remove_in_progress_sz = pd_handles_sz; 885062306a36Sopenharmony_ci } 885162306a36Sopenharmony_ci 885262306a36Sopenharmony_ci memcpy(&ioc->prev_fw_facts, &ioc->facts, sizeof(struct mpt3sas_facts)); 885362306a36Sopenharmony_ci return 0; 885462306a36Sopenharmony_ci} 885562306a36Sopenharmony_ci 885662306a36Sopenharmony_ci/** 885762306a36Sopenharmony_ci * mpt3sas_base_hard_reset_handler - reset controller 885862306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 885962306a36Sopenharmony_ci * @type: FORCE_BIG_HAMMER or SOFT_RESET 886062306a36Sopenharmony_ci * 886162306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 886262306a36Sopenharmony_ci */ 886362306a36Sopenharmony_ciint 886462306a36Sopenharmony_cimpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, 886562306a36Sopenharmony_ci enum reset_type type) 886662306a36Sopenharmony_ci{ 886762306a36Sopenharmony_ci int r; 886862306a36Sopenharmony_ci unsigned long flags; 886962306a36Sopenharmony_ci u32 ioc_state; 887062306a36Sopenharmony_ci u8 is_fault = 0, is_trigger = 0; 887162306a36Sopenharmony_ci 887262306a36Sopenharmony_ci dtmprintk(ioc, ioc_info(ioc, "%s: enter\n", __func__)); 887362306a36Sopenharmony_ci 887462306a36Sopenharmony_ci if (ioc->pci_error_recovery) { 887562306a36Sopenharmony_ci ioc_err(ioc, "%s: pci error recovery reset\n", __func__); 887662306a36Sopenharmony_ci r = 0; 887762306a36Sopenharmony_ci goto out_unlocked; 887862306a36Sopenharmony_ci } 887962306a36Sopenharmony_ci 888062306a36Sopenharmony_ci if (mpt3sas_fwfault_debug) 888162306a36Sopenharmony_ci mpt3sas_halt_firmware(ioc); 888262306a36Sopenharmony_ci 888362306a36Sopenharmony_ci /* wait for an active reset in progress to complete */ 888462306a36Sopenharmony_ci mutex_lock(&ioc->reset_in_progress_mutex); 888562306a36Sopenharmony_ci 888662306a36Sopenharmony_ci spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); 888762306a36Sopenharmony_ci ioc->shost_recovery = 1; 888862306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); 888962306a36Sopenharmony_ci 889062306a36Sopenharmony_ci if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & 889162306a36Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED) && 889262306a36Sopenharmony_ci (!(ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & 889362306a36Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED))) { 889462306a36Sopenharmony_ci is_trigger = 1; 889562306a36Sopenharmony_ci ioc_state = mpt3sas_base_get_iocstate(ioc, 0); 889662306a36Sopenharmony_ci if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT || 889762306a36Sopenharmony_ci (ioc_state & MPI2_IOC_STATE_MASK) == 889862306a36Sopenharmony_ci MPI2_IOC_STATE_COREDUMP) { 889962306a36Sopenharmony_ci is_fault = 1; 890062306a36Sopenharmony_ci ioc->htb_rel.trigger_info_dwords[1] = 890162306a36Sopenharmony_ci (ioc_state & MPI2_DOORBELL_DATA_MASK); 890262306a36Sopenharmony_ci } 890362306a36Sopenharmony_ci } 890462306a36Sopenharmony_ci _base_pre_reset_handler(ioc); 890562306a36Sopenharmony_ci mpt3sas_wait_for_commands_to_complete(ioc); 890662306a36Sopenharmony_ci mpt3sas_base_mask_interrupts(ioc); 890762306a36Sopenharmony_ci mpt3sas_base_pause_mq_polling(ioc); 890862306a36Sopenharmony_ci r = mpt3sas_base_make_ioc_ready(ioc, type); 890962306a36Sopenharmony_ci if (r) 891062306a36Sopenharmony_ci goto out; 891162306a36Sopenharmony_ci _base_clear_outstanding_commands(ioc); 891262306a36Sopenharmony_ci 891362306a36Sopenharmony_ci /* If this hard reset is called while port enable is active, then 891462306a36Sopenharmony_ci * there is no reason to call make_ioc_operational 891562306a36Sopenharmony_ci */ 891662306a36Sopenharmony_ci if (ioc->is_driver_loading && ioc->port_enable_failed) { 891762306a36Sopenharmony_ci ioc->remove_host = 1; 891862306a36Sopenharmony_ci r = -EFAULT; 891962306a36Sopenharmony_ci goto out; 892062306a36Sopenharmony_ci } 892162306a36Sopenharmony_ci r = _base_get_ioc_facts(ioc); 892262306a36Sopenharmony_ci if (r) 892362306a36Sopenharmony_ci goto out; 892462306a36Sopenharmony_ci 892562306a36Sopenharmony_ci r = _base_check_ioc_facts_changes(ioc); 892662306a36Sopenharmony_ci if (r) { 892762306a36Sopenharmony_ci ioc_info(ioc, 892862306a36Sopenharmony_ci "Some of the parameters got changed in this new firmware" 892962306a36Sopenharmony_ci " image and it requires system reboot\n"); 893062306a36Sopenharmony_ci goto out; 893162306a36Sopenharmony_ci } 893262306a36Sopenharmony_ci if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable) 893362306a36Sopenharmony_ci panic("%s: Issue occurred with flashing controller firmware." 893462306a36Sopenharmony_ci "Please reboot the system and ensure that the correct" 893562306a36Sopenharmony_ci " firmware version is running\n", ioc->name); 893662306a36Sopenharmony_ci 893762306a36Sopenharmony_ci r = _base_make_ioc_operational(ioc); 893862306a36Sopenharmony_ci if (!r) 893962306a36Sopenharmony_ci _base_reset_done_handler(ioc); 894062306a36Sopenharmony_ci 894162306a36Sopenharmony_ci out: 894262306a36Sopenharmony_ci ioc_info(ioc, "%s: %s\n", __func__, r == 0 ? "SUCCESS" : "FAILED"); 894362306a36Sopenharmony_ci 894462306a36Sopenharmony_ci spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); 894562306a36Sopenharmony_ci ioc->shost_recovery = 0; 894662306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); 894762306a36Sopenharmony_ci ioc->ioc_reset_count++; 894862306a36Sopenharmony_ci mutex_unlock(&ioc->reset_in_progress_mutex); 894962306a36Sopenharmony_ci mpt3sas_base_resume_mq_polling(ioc); 895062306a36Sopenharmony_ci 895162306a36Sopenharmony_ci out_unlocked: 895262306a36Sopenharmony_ci if ((r == 0) && is_trigger) { 895362306a36Sopenharmony_ci if (is_fault) 895462306a36Sopenharmony_ci mpt3sas_trigger_master(ioc, MASTER_TRIGGER_FW_FAULT); 895562306a36Sopenharmony_ci else 895662306a36Sopenharmony_ci mpt3sas_trigger_master(ioc, 895762306a36Sopenharmony_ci MASTER_TRIGGER_ADAPTER_RESET); 895862306a36Sopenharmony_ci } 895962306a36Sopenharmony_ci dtmprintk(ioc, ioc_info(ioc, "%s: exit\n", __func__)); 896062306a36Sopenharmony_ci return r; 896162306a36Sopenharmony_ci} 8962