1824a1566SKashyap Desai // SPDX-License-Identifier: GPL-2.0-or-later 2824a1566SKashyap Desai /* 3824a1566SKashyap Desai * Driver for Broadcom MPI3 Storage Controllers 4824a1566SKashyap Desai * 5824a1566SKashyap Desai * Copyright (C) 2017-2021 Broadcom Inc. 6824a1566SKashyap Desai * (mailto: mpi3mr-linuxdrv.pdl@broadcom.com) 7824a1566SKashyap Desai * 8824a1566SKashyap Desai */ 9824a1566SKashyap Desai 10824a1566SKashyap Desai #include "mpi3mr.h" 11824a1566SKashyap Desai #include <linux/io-64-nonatomic-lo-hi.h> 12824a1566SKashyap Desai 1359bd9cfeSSreekanth Reddy static int 1459bd9cfeSSreekanth Reddy mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u32 reset_reason); 1559bd9cfeSSreekanth Reddy static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc); 16c5758fc7SSreekanth Reddy static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, 17c5758fc7SSreekanth Reddy struct mpi3_ioc_facts_data *facts_data); 1859bd9cfeSSreekanth Reddy 19*afd3a579SSreekanth Reddy static int poll_queues; 20*afd3a579SSreekanth Reddy module_param(poll_queues, int, 0444); 21*afd3a579SSreekanth Reddy MODULE_PARM_DESC(poll_queues, "Number of queues for io_uring poll mode. (Range 1 - 126)"); 22*afd3a579SSreekanth Reddy 23824a1566SKashyap Desai #if defined(writeq) && defined(CONFIG_64BIT) 24824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) 25824a1566SKashyap Desai { 26824a1566SKashyap Desai writeq(b, addr); 27824a1566SKashyap Desai } 28824a1566SKashyap Desai #else 29824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) 30824a1566SKashyap Desai { 31824a1566SKashyap Desai __u64 data_out = b; 32824a1566SKashyap Desai 33824a1566SKashyap Desai writel((u32)(data_out), addr); 34824a1566SKashyap Desai writel((u32)(data_out >> 32), (addr + 4)); 35824a1566SKashyap Desai } 36824a1566SKashyap Desai #endif 37824a1566SKashyap Desai 38023ab2a9SKashyap Desai static inline bool 39023ab2a9SKashyap Desai mpi3mr_check_req_qfull(struct op_req_qinfo *op_req_q) 40023ab2a9SKashyap Desai { 41023ab2a9SKashyap Desai u16 pi, ci, max_entries; 42023ab2a9SKashyap Desai bool is_qfull = false; 43023ab2a9SKashyap Desai 44023ab2a9SKashyap Desai pi = op_req_q->pi; 45023ab2a9SKashyap Desai ci = READ_ONCE(op_req_q->ci); 46023ab2a9SKashyap Desai max_entries = op_req_q->num_requests; 47023ab2a9SKashyap Desai 48023ab2a9SKashyap Desai if ((ci == (pi + 1)) || ((!ci) && (pi == (max_entries - 1)))) 49023ab2a9SKashyap Desai is_qfull = true; 50023ab2a9SKashyap Desai 51023ab2a9SKashyap Desai return is_qfull; 52023ab2a9SKashyap Desai } 53023ab2a9SKashyap Desai 54824a1566SKashyap Desai static void mpi3mr_sync_irqs(struct mpi3mr_ioc *mrioc) 55824a1566SKashyap Desai { 56824a1566SKashyap Desai u16 i, max_vectors; 57824a1566SKashyap Desai 58824a1566SKashyap Desai max_vectors = mrioc->intr_info_count; 59824a1566SKashyap Desai 60824a1566SKashyap Desai for (i = 0; i < max_vectors; i++) 61824a1566SKashyap Desai synchronize_irq(pci_irq_vector(mrioc->pdev, i)); 62824a1566SKashyap Desai } 63824a1566SKashyap Desai 64824a1566SKashyap Desai void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc) 65824a1566SKashyap Desai { 66824a1566SKashyap Desai mrioc->intr_enabled = 0; 67824a1566SKashyap Desai mpi3mr_sync_irqs(mrioc); 68824a1566SKashyap Desai } 69824a1566SKashyap Desai 70824a1566SKashyap Desai void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc) 71824a1566SKashyap Desai { 72824a1566SKashyap Desai mrioc->intr_enabled = 1; 73824a1566SKashyap Desai } 74824a1566SKashyap Desai 75824a1566SKashyap Desai static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc) 76824a1566SKashyap Desai { 77824a1566SKashyap Desai u16 i; 78824a1566SKashyap Desai 79824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 80824a1566SKashyap Desai 81824a1566SKashyap Desai if (!mrioc->intr_info) 82824a1566SKashyap Desai return; 83824a1566SKashyap Desai 84824a1566SKashyap Desai for (i = 0; i < mrioc->intr_info_count; i++) 85824a1566SKashyap Desai free_irq(pci_irq_vector(mrioc->pdev, i), 86824a1566SKashyap Desai (mrioc->intr_info + i)); 87824a1566SKashyap Desai 88824a1566SKashyap Desai kfree(mrioc->intr_info); 89824a1566SKashyap Desai mrioc->intr_info = NULL; 90824a1566SKashyap Desai mrioc->intr_info_count = 0; 91fe6db615SSreekanth Reddy mrioc->is_intr_info_set = false; 92824a1566SKashyap Desai pci_free_irq_vectors(mrioc->pdev); 93824a1566SKashyap Desai } 94824a1566SKashyap Desai 95824a1566SKashyap Desai void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length, 96824a1566SKashyap Desai dma_addr_t dma_addr) 97824a1566SKashyap Desai { 98824a1566SKashyap Desai struct mpi3_sge_common *sgel = paddr; 99824a1566SKashyap Desai 100824a1566SKashyap Desai sgel->flags = flags; 101824a1566SKashyap Desai sgel->length = cpu_to_le32(length); 102824a1566SKashyap Desai sgel->address = cpu_to_le64(dma_addr); 103824a1566SKashyap Desai } 104824a1566SKashyap Desai 105824a1566SKashyap Desai void mpi3mr_build_zero_len_sge(void *paddr) 106824a1566SKashyap Desai { 107824a1566SKashyap Desai u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 108824a1566SKashyap Desai 109824a1566SKashyap Desai mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1); 110824a1566SKashyap Desai } 111824a1566SKashyap Desai 112824a1566SKashyap Desai void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc, 113824a1566SKashyap Desai dma_addr_t phys_addr) 114824a1566SKashyap Desai { 115824a1566SKashyap Desai if (!phys_addr) 116824a1566SKashyap Desai return NULL; 117824a1566SKashyap Desai 118824a1566SKashyap Desai if ((phys_addr < mrioc->reply_buf_dma) || 119824a1566SKashyap Desai (phys_addr > mrioc->reply_buf_dma_max_address)) 120824a1566SKashyap Desai return NULL; 121824a1566SKashyap Desai 122824a1566SKashyap Desai return mrioc->reply_buf + (phys_addr - mrioc->reply_buf_dma); 123824a1566SKashyap Desai } 124824a1566SKashyap Desai 125824a1566SKashyap Desai void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc, 126824a1566SKashyap Desai dma_addr_t phys_addr) 127824a1566SKashyap Desai { 128824a1566SKashyap Desai if (!phys_addr) 129824a1566SKashyap Desai return NULL; 130824a1566SKashyap Desai 131824a1566SKashyap Desai return mrioc->sense_buf + (phys_addr - mrioc->sense_buf_dma); 132824a1566SKashyap Desai } 133824a1566SKashyap Desai 134824a1566SKashyap Desai static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc, 135824a1566SKashyap Desai u64 reply_dma) 136824a1566SKashyap Desai { 137824a1566SKashyap Desai u32 old_idx = 0; 138a83ec831SSreekanth Reddy unsigned long flags; 139824a1566SKashyap Desai 140a83ec831SSreekanth Reddy spin_lock_irqsave(&mrioc->reply_free_queue_lock, flags); 141824a1566SKashyap Desai old_idx = mrioc->reply_free_queue_host_index; 142824a1566SKashyap Desai mrioc->reply_free_queue_host_index = ( 143824a1566SKashyap Desai (mrioc->reply_free_queue_host_index == 144824a1566SKashyap Desai (mrioc->reply_free_qsz - 1)) ? 0 : 145824a1566SKashyap Desai (mrioc->reply_free_queue_host_index + 1)); 146824a1566SKashyap Desai mrioc->reply_free_q[old_idx] = cpu_to_le64(reply_dma); 147824a1566SKashyap Desai writel(mrioc->reply_free_queue_host_index, 148824a1566SKashyap Desai &mrioc->sysif_regs->reply_free_host_index); 149a83ec831SSreekanth Reddy spin_unlock_irqrestore(&mrioc->reply_free_queue_lock, flags); 150824a1566SKashyap Desai } 151824a1566SKashyap Desai 152824a1566SKashyap Desai void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc, 153824a1566SKashyap Desai u64 sense_buf_dma) 154824a1566SKashyap Desai { 155824a1566SKashyap Desai u32 old_idx = 0; 156a83ec831SSreekanth Reddy unsigned long flags; 157824a1566SKashyap Desai 158a83ec831SSreekanth Reddy spin_lock_irqsave(&mrioc->sbq_lock, flags); 159824a1566SKashyap Desai old_idx = mrioc->sbq_host_index; 160824a1566SKashyap Desai mrioc->sbq_host_index = ((mrioc->sbq_host_index == 161824a1566SKashyap Desai (mrioc->sense_buf_q_sz - 1)) ? 0 : 162824a1566SKashyap Desai (mrioc->sbq_host_index + 1)); 163824a1566SKashyap Desai mrioc->sense_buf_q[old_idx] = cpu_to_le64(sense_buf_dma); 164824a1566SKashyap Desai writel(mrioc->sbq_host_index, 165824a1566SKashyap Desai &mrioc->sysif_regs->sense_buffer_free_host_index); 166a83ec831SSreekanth Reddy spin_unlock_irqrestore(&mrioc->sbq_lock, flags); 167824a1566SKashyap Desai } 168824a1566SKashyap Desai 1699fc4abfeSKashyap Desai static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc, 1709fc4abfeSKashyap Desai struct mpi3_event_notification_reply *event_reply) 1719fc4abfeSKashyap Desai { 1729fc4abfeSKashyap Desai char *desc = NULL; 1739fc4abfeSKashyap Desai u16 event; 1749fc4abfeSKashyap Desai 1759fc4abfeSKashyap Desai event = event_reply->event; 1769fc4abfeSKashyap Desai 1779fc4abfeSKashyap Desai switch (event) { 1789fc4abfeSKashyap Desai case MPI3_EVENT_LOG_DATA: 1799fc4abfeSKashyap Desai desc = "Log Data"; 1809fc4abfeSKashyap Desai break; 1819fc4abfeSKashyap Desai case MPI3_EVENT_CHANGE: 1829fc4abfeSKashyap Desai desc = "Event Change"; 1839fc4abfeSKashyap Desai break; 1849fc4abfeSKashyap Desai case MPI3_EVENT_GPIO_INTERRUPT: 1859fc4abfeSKashyap Desai desc = "GPIO Interrupt"; 1869fc4abfeSKashyap Desai break; 1879fc4abfeSKashyap Desai case MPI3_EVENT_TEMP_THRESHOLD: 1889fc4abfeSKashyap Desai desc = "Temperature Threshold"; 1899fc4abfeSKashyap Desai break; 1909fc4abfeSKashyap Desai case MPI3_EVENT_CABLE_MGMT: 1919fc4abfeSKashyap Desai desc = "Cable Management"; 1929fc4abfeSKashyap Desai break; 1939fc4abfeSKashyap Desai case MPI3_EVENT_ENERGY_PACK_CHANGE: 1949fc4abfeSKashyap Desai desc = "Energy Pack Change"; 1959fc4abfeSKashyap Desai break; 1969fc4abfeSKashyap Desai case MPI3_EVENT_DEVICE_ADDED: 1979fc4abfeSKashyap Desai { 1989fc4abfeSKashyap Desai struct mpi3_device_page0 *event_data = 1999fc4abfeSKashyap Desai (struct mpi3_device_page0 *)event_reply->event_data; 2009fc4abfeSKashyap Desai ioc_info(mrioc, "Device Added: dev=0x%04x Form=0x%x\n", 2019fc4abfeSKashyap Desai event_data->dev_handle, event_data->device_form); 2029fc4abfeSKashyap Desai return; 2039fc4abfeSKashyap Desai } 2049fc4abfeSKashyap Desai case MPI3_EVENT_DEVICE_INFO_CHANGED: 2059fc4abfeSKashyap Desai { 2069fc4abfeSKashyap Desai struct mpi3_device_page0 *event_data = 2079fc4abfeSKashyap Desai (struct mpi3_device_page0 *)event_reply->event_data; 2089fc4abfeSKashyap Desai ioc_info(mrioc, "Device Info Changed: dev=0x%04x Form=0x%x\n", 2099fc4abfeSKashyap Desai event_data->dev_handle, event_data->device_form); 2109fc4abfeSKashyap Desai return; 2119fc4abfeSKashyap Desai } 2129fc4abfeSKashyap Desai case MPI3_EVENT_DEVICE_STATUS_CHANGE: 2139fc4abfeSKashyap Desai { 2149fc4abfeSKashyap Desai struct mpi3_event_data_device_status_change *event_data = 2159fc4abfeSKashyap Desai (struct mpi3_event_data_device_status_change *)event_reply->event_data; 2169fc4abfeSKashyap Desai ioc_info(mrioc, "Device status Change: dev=0x%04x RC=0x%x\n", 2179fc4abfeSKashyap Desai event_data->dev_handle, event_data->reason_code); 2189fc4abfeSKashyap Desai return; 2199fc4abfeSKashyap Desai } 2209fc4abfeSKashyap Desai case MPI3_EVENT_SAS_DISCOVERY: 2219fc4abfeSKashyap Desai { 2229fc4abfeSKashyap Desai struct mpi3_event_data_sas_discovery *event_data = 2239fc4abfeSKashyap Desai (struct mpi3_event_data_sas_discovery *)event_reply->event_data; 2249fc4abfeSKashyap Desai ioc_info(mrioc, "SAS Discovery: (%s) status (0x%08x)\n", 2259fc4abfeSKashyap Desai (event_data->reason_code == MPI3_EVENT_SAS_DISC_RC_STARTED) ? 2269fc4abfeSKashyap Desai "start" : "stop", 2279fc4abfeSKashyap Desai le32_to_cpu(event_data->discovery_status)); 2289fc4abfeSKashyap Desai return; 2299fc4abfeSKashyap Desai } 2309fc4abfeSKashyap Desai case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE: 2319fc4abfeSKashyap Desai desc = "SAS Broadcast Primitive"; 2329fc4abfeSKashyap Desai break; 2339fc4abfeSKashyap Desai case MPI3_EVENT_SAS_NOTIFY_PRIMITIVE: 2349fc4abfeSKashyap Desai desc = "SAS Notify Primitive"; 2359fc4abfeSKashyap Desai break; 2369fc4abfeSKashyap Desai case MPI3_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: 2379fc4abfeSKashyap Desai desc = "SAS Init Device Status Change"; 2389fc4abfeSKashyap Desai break; 2399fc4abfeSKashyap Desai case MPI3_EVENT_SAS_INIT_TABLE_OVERFLOW: 2409fc4abfeSKashyap Desai desc = "SAS Init Table Overflow"; 2419fc4abfeSKashyap Desai break; 2429fc4abfeSKashyap Desai case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST: 2439fc4abfeSKashyap Desai desc = "SAS Topology Change List"; 2449fc4abfeSKashyap Desai break; 2459fc4abfeSKashyap Desai case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE: 2469fc4abfeSKashyap Desai desc = "Enclosure Device Status Change"; 2479fc4abfeSKashyap Desai break; 2489fc4abfeSKashyap Desai case MPI3_EVENT_HARD_RESET_RECEIVED: 2499fc4abfeSKashyap Desai desc = "Hard Reset Received"; 2509fc4abfeSKashyap Desai break; 2519fc4abfeSKashyap Desai case MPI3_EVENT_SAS_PHY_COUNTER: 2529fc4abfeSKashyap Desai desc = "SAS PHY Counter"; 2539fc4abfeSKashyap Desai break; 2549fc4abfeSKashyap Desai case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR: 2559fc4abfeSKashyap Desai desc = "SAS Device Discovery Error"; 2569fc4abfeSKashyap Desai break; 2579fc4abfeSKashyap Desai case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: 2589fc4abfeSKashyap Desai desc = "PCIE Topology Change List"; 2599fc4abfeSKashyap Desai break; 2609fc4abfeSKashyap Desai case MPI3_EVENT_PCIE_ENUMERATION: 2619fc4abfeSKashyap Desai { 2629fc4abfeSKashyap Desai struct mpi3_event_data_pcie_enumeration *event_data = 2639fc4abfeSKashyap Desai (struct mpi3_event_data_pcie_enumeration *)event_reply->event_data; 2649fc4abfeSKashyap Desai ioc_info(mrioc, "PCIE Enumeration: (%s)", 2659fc4abfeSKashyap Desai (event_data->reason_code == 2669fc4abfeSKashyap Desai MPI3_EVENT_PCIE_ENUM_RC_STARTED) ? "start" : "stop"); 2679fc4abfeSKashyap Desai if (event_data->enumeration_status) 2689fc4abfeSKashyap Desai ioc_info(mrioc, "enumeration_status(0x%08x)\n", 2699fc4abfeSKashyap Desai le32_to_cpu(event_data->enumeration_status)); 2709fc4abfeSKashyap Desai return; 2719fc4abfeSKashyap Desai } 2729fc4abfeSKashyap Desai case MPI3_EVENT_PREPARE_FOR_RESET: 2739fc4abfeSKashyap Desai desc = "Prepare For Reset"; 2749fc4abfeSKashyap Desai break; 2759fc4abfeSKashyap Desai } 2769fc4abfeSKashyap Desai 2779fc4abfeSKashyap Desai if (!desc) 2789fc4abfeSKashyap Desai return; 2799fc4abfeSKashyap Desai 2809fc4abfeSKashyap Desai ioc_info(mrioc, "%s\n", desc); 2819fc4abfeSKashyap Desai } 2829fc4abfeSKashyap Desai 283824a1566SKashyap Desai static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc, 284824a1566SKashyap Desai struct mpi3_default_reply *def_reply) 285824a1566SKashyap Desai { 286824a1566SKashyap Desai struct mpi3_event_notification_reply *event_reply = 287824a1566SKashyap Desai (struct mpi3_event_notification_reply *)def_reply; 288824a1566SKashyap Desai 289824a1566SKashyap Desai mrioc->change_count = le16_to_cpu(event_reply->ioc_change_count); 2909fc4abfeSKashyap Desai mpi3mr_print_event_data(mrioc, event_reply); 29113ef29eaSKashyap Desai mpi3mr_os_handle_events(mrioc, event_reply); 292824a1566SKashyap Desai } 293824a1566SKashyap Desai 294824a1566SKashyap Desai static struct mpi3mr_drv_cmd * 295824a1566SKashyap Desai mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag, 296824a1566SKashyap Desai struct mpi3_default_reply *def_reply) 297824a1566SKashyap Desai { 29813ef29eaSKashyap Desai u16 idx; 29913ef29eaSKashyap Desai 300824a1566SKashyap Desai switch (host_tag) { 301824a1566SKashyap Desai case MPI3MR_HOSTTAG_INITCMDS: 302824a1566SKashyap Desai return &mrioc->init_cmds; 303e844adb1SKashyap Desai case MPI3MR_HOSTTAG_BLK_TMS: 304e844adb1SKashyap Desai return &mrioc->host_tm_cmds; 305824a1566SKashyap Desai case MPI3MR_HOSTTAG_INVALID: 306824a1566SKashyap Desai if (def_reply && def_reply->function == 307824a1566SKashyap Desai MPI3_FUNCTION_EVENT_NOTIFICATION) 308824a1566SKashyap Desai mpi3mr_handle_events(mrioc, def_reply); 309824a1566SKashyap Desai return NULL; 310824a1566SKashyap Desai default: 311824a1566SKashyap Desai break; 312824a1566SKashyap Desai } 31313ef29eaSKashyap Desai if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN && 31413ef29eaSKashyap Desai host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX) { 31513ef29eaSKashyap Desai idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN; 31613ef29eaSKashyap Desai return &mrioc->dev_rmhs_cmds[idx]; 31713ef29eaSKashyap Desai } 318824a1566SKashyap Desai 319c1af985dSSreekanth Reddy if (host_tag >= MPI3MR_HOSTTAG_EVTACKCMD_MIN && 320c1af985dSSreekanth Reddy host_tag <= MPI3MR_HOSTTAG_EVTACKCMD_MAX) { 321c1af985dSSreekanth Reddy idx = host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN; 322c1af985dSSreekanth Reddy return &mrioc->evtack_cmds[idx]; 323c1af985dSSreekanth Reddy } 324c1af985dSSreekanth Reddy 325824a1566SKashyap Desai return NULL; 326824a1566SKashyap Desai } 327824a1566SKashyap Desai 328824a1566SKashyap Desai static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, 329824a1566SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma) 330824a1566SKashyap Desai { 331824a1566SKashyap Desai u16 reply_desc_type, host_tag = 0; 332824a1566SKashyap Desai u16 ioc_status = MPI3_IOCSTATUS_SUCCESS; 333824a1566SKashyap Desai u32 ioc_loginfo = 0; 334824a1566SKashyap Desai struct mpi3_status_reply_descriptor *status_desc; 335824a1566SKashyap Desai struct mpi3_address_reply_descriptor *addr_desc; 336824a1566SKashyap Desai struct mpi3_success_reply_descriptor *success_desc; 337824a1566SKashyap Desai struct mpi3_default_reply *def_reply = NULL; 338824a1566SKashyap Desai struct mpi3mr_drv_cmd *cmdptr = NULL; 339824a1566SKashyap Desai struct mpi3_scsi_io_reply *scsi_reply; 340824a1566SKashyap Desai u8 *sense_buf = NULL; 341824a1566SKashyap Desai 342824a1566SKashyap Desai *reply_dma = 0; 343824a1566SKashyap Desai reply_desc_type = le16_to_cpu(reply_desc->reply_flags) & 344824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK; 345824a1566SKashyap Desai switch (reply_desc_type) { 346824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS: 347824a1566SKashyap Desai status_desc = (struct mpi3_status_reply_descriptor *)reply_desc; 348824a1566SKashyap Desai host_tag = le16_to_cpu(status_desc->host_tag); 349824a1566SKashyap Desai ioc_status = le16_to_cpu(status_desc->ioc_status); 350824a1566SKashyap Desai if (ioc_status & 351824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) 352824a1566SKashyap Desai ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info); 353824a1566SKashyap Desai ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; 354824a1566SKashyap Desai break; 355824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY: 356824a1566SKashyap Desai addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc; 357824a1566SKashyap Desai *reply_dma = le64_to_cpu(addr_desc->reply_frame_address); 358824a1566SKashyap Desai def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma); 359824a1566SKashyap Desai if (!def_reply) 360824a1566SKashyap Desai goto out; 361824a1566SKashyap Desai host_tag = le16_to_cpu(def_reply->host_tag); 362824a1566SKashyap Desai ioc_status = le16_to_cpu(def_reply->ioc_status); 363824a1566SKashyap Desai if (ioc_status & 364824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) 365824a1566SKashyap Desai ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info); 366824a1566SKashyap Desai ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; 367824a1566SKashyap Desai if (def_reply->function == MPI3_FUNCTION_SCSI_IO) { 368824a1566SKashyap Desai scsi_reply = (struct mpi3_scsi_io_reply *)def_reply; 369824a1566SKashyap Desai sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc, 370824a1566SKashyap Desai le64_to_cpu(scsi_reply->sense_data_buffer_address)); 371824a1566SKashyap Desai } 372824a1566SKashyap Desai break; 373824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS: 374824a1566SKashyap Desai success_desc = (struct mpi3_success_reply_descriptor *)reply_desc; 375824a1566SKashyap Desai host_tag = le16_to_cpu(success_desc->host_tag); 376824a1566SKashyap Desai break; 377824a1566SKashyap Desai default: 378824a1566SKashyap Desai break; 379824a1566SKashyap Desai } 380824a1566SKashyap Desai 381824a1566SKashyap Desai cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply); 382824a1566SKashyap Desai if (cmdptr) { 383824a1566SKashyap Desai if (cmdptr->state & MPI3MR_CMD_PENDING) { 384824a1566SKashyap Desai cmdptr->state |= MPI3MR_CMD_COMPLETE; 385824a1566SKashyap Desai cmdptr->ioc_loginfo = ioc_loginfo; 386824a1566SKashyap Desai cmdptr->ioc_status = ioc_status; 387824a1566SKashyap Desai cmdptr->state &= ~MPI3MR_CMD_PENDING; 388824a1566SKashyap Desai if (def_reply) { 389824a1566SKashyap Desai cmdptr->state |= MPI3MR_CMD_REPLY_VALID; 390824a1566SKashyap Desai memcpy((u8 *)cmdptr->reply, (u8 *)def_reply, 391c5758fc7SSreekanth Reddy mrioc->reply_sz); 392824a1566SKashyap Desai } 393824a1566SKashyap Desai if (cmdptr->is_waiting) { 394824a1566SKashyap Desai complete(&cmdptr->done); 395824a1566SKashyap Desai cmdptr->is_waiting = 0; 396824a1566SKashyap Desai } else if (cmdptr->callback) 397824a1566SKashyap Desai cmdptr->callback(mrioc, cmdptr); 398824a1566SKashyap Desai } 399824a1566SKashyap Desai } 400824a1566SKashyap Desai out: 401824a1566SKashyap Desai if (sense_buf) 402824a1566SKashyap Desai mpi3mr_repost_sense_buf(mrioc, 403824a1566SKashyap Desai le64_to_cpu(scsi_reply->sense_data_buffer_address)); 404824a1566SKashyap Desai } 405824a1566SKashyap Desai 406824a1566SKashyap Desai static int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) 407824a1566SKashyap Desai { 408824a1566SKashyap Desai u32 exp_phase = mrioc->admin_reply_ephase; 409824a1566SKashyap Desai u32 admin_reply_ci = mrioc->admin_reply_ci; 410824a1566SKashyap Desai u32 num_admin_replies = 0; 411824a1566SKashyap Desai u64 reply_dma = 0; 412824a1566SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc; 413824a1566SKashyap Desai 414824a1566SKashyap Desai reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base + 415824a1566SKashyap Desai admin_reply_ci; 416824a1566SKashyap Desai 417824a1566SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 418824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 419824a1566SKashyap Desai return 0; 420824a1566SKashyap Desai 421824a1566SKashyap Desai do { 422824a1566SKashyap Desai mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci); 423824a1566SKashyap Desai mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma); 424824a1566SKashyap Desai if (reply_dma) 425824a1566SKashyap Desai mpi3mr_repost_reply_buf(mrioc, reply_dma); 426824a1566SKashyap Desai num_admin_replies++; 427824a1566SKashyap Desai if (++admin_reply_ci == mrioc->num_admin_replies) { 428824a1566SKashyap Desai admin_reply_ci = 0; 429824a1566SKashyap Desai exp_phase ^= 1; 430824a1566SKashyap Desai } 431824a1566SKashyap Desai reply_desc = 432824a1566SKashyap Desai (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base + 433824a1566SKashyap Desai admin_reply_ci; 434824a1566SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 435824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 436824a1566SKashyap Desai break; 437824a1566SKashyap Desai } while (1); 438824a1566SKashyap Desai 439824a1566SKashyap Desai writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); 440824a1566SKashyap Desai mrioc->admin_reply_ci = admin_reply_ci; 441824a1566SKashyap Desai mrioc->admin_reply_ephase = exp_phase; 442824a1566SKashyap Desai 443824a1566SKashyap Desai return num_admin_replies; 444824a1566SKashyap Desai } 445824a1566SKashyap Desai 446023ab2a9SKashyap Desai /** 447023ab2a9SKashyap Desai * mpi3mr_get_reply_desc - get reply descriptor frame corresponding to 448023ab2a9SKashyap Desai * queue's consumer index from operational reply descriptor queue. 449023ab2a9SKashyap Desai * @op_reply_q: op_reply_qinfo object 450023ab2a9SKashyap Desai * @reply_ci: operational reply descriptor's queue consumer index 451023ab2a9SKashyap Desai * 452023ab2a9SKashyap Desai * Returns reply descriptor frame address 453023ab2a9SKashyap Desai */ 454023ab2a9SKashyap Desai static inline struct mpi3_default_reply_descriptor * 455023ab2a9SKashyap Desai mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci) 456023ab2a9SKashyap Desai { 457023ab2a9SKashyap Desai void *segment_base_addr; 458023ab2a9SKashyap Desai struct segments *segments = op_reply_q->q_segments; 459023ab2a9SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc = NULL; 460023ab2a9SKashyap Desai 461023ab2a9SKashyap Desai segment_base_addr = 462023ab2a9SKashyap Desai segments[reply_ci / op_reply_q->segment_qd].segment; 463023ab2a9SKashyap Desai reply_desc = (struct mpi3_default_reply_descriptor *)segment_base_addr + 464023ab2a9SKashyap Desai (reply_ci % op_reply_q->segment_qd); 465023ab2a9SKashyap Desai return reply_desc; 466023ab2a9SKashyap Desai } 467023ab2a9SKashyap Desai 468*afd3a579SSreekanth Reddy /** 469*afd3a579SSreekanth Reddy * mpi3mr_process_op_reply_q - Operational reply queue handler 470*afd3a579SSreekanth Reddy * @mrioc: Adapter instance reference 471*afd3a579SSreekanth Reddy * @op_reply_q: Operational reply queue info 472*afd3a579SSreekanth Reddy * 473*afd3a579SSreekanth Reddy * Checks the specific operational reply queue and drains the 474*afd3a579SSreekanth Reddy * reply queue entries until the queue is empty and process the 475*afd3a579SSreekanth Reddy * individual reply descriptors. 476*afd3a579SSreekanth Reddy * 477*afd3a579SSreekanth Reddy * Return: 0 if queue is already processed,or number of reply 478*afd3a579SSreekanth Reddy * descriptors processed. 479*afd3a579SSreekanth Reddy */ 480*afd3a579SSreekanth Reddy int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, 481*afd3a579SSreekanth Reddy struct op_reply_qinfo *op_reply_q) 482023ab2a9SKashyap Desai { 483023ab2a9SKashyap Desai struct op_req_qinfo *op_req_q; 484023ab2a9SKashyap Desai u32 exp_phase; 485023ab2a9SKashyap Desai u32 reply_ci; 486023ab2a9SKashyap Desai u32 num_op_reply = 0; 487023ab2a9SKashyap Desai u64 reply_dma = 0; 488023ab2a9SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc; 489023ab2a9SKashyap Desai u16 req_q_idx = 0, reply_qidx; 490023ab2a9SKashyap Desai 491023ab2a9SKashyap Desai reply_qidx = op_reply_q->qid - 1; 492023ab2a9SKashyap Desai 493463429f8SKashyap Desai if (!atomic_add_unless(&op_reply_q->in_use, 1, 1)) 494463429f8SKashyap Desai return 0; 495463429f8SKashyap Desai 496023ab2a9SKashyap Desai exp_phase = op_reply_q->ephase; 497023ab2a9SKashyap Desai reply_ci = op_reply_q->ci; 498023ab2a9SKashyap Desai 499023ab2a9SKashyap Desai reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci); 500023ab2a9SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 501023ab2a9SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) { 502463429f8SKashyap Desai atomic_dec(&op_reply_q->in_use); 503023ab2a9SKashyap Desai return 0; 504023ab2a9SKashyap Desai } 505023ab2a9SKashyap Desai 506023ab2a9SKashyap Desai do { 507023ab2a9SKashyap Desai req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1; 508023ab2a9SKashyap Desai op_req_q = &mrioc->req_qinfo[req_q_idx]; 509023ab2a9SKashyap Desai 510023ab2a9SKashyap Desai WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci)); 511023ab2a9SKashyap Desai mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma, 512023ab2a9SKashyap Desai reply_qidx); 513463429f8SKashyap Desai atomic_dec(&op_reply_q->pend_ios); 514023ab2a9SKashyap Desai if (reply_dma) 515023ab2a9SKashyap Desai mpi3mr_repost_reply_buf(mrioc, reply_dma); 516023ab2a9SKashyap Desai num_op_reply++; 517023ab2a9SKashyap Desai 518023ab2a9SKashyap Desai if (++reply_ci == op_reply_q->num_replies) { 519023ab2a9SKashyap Desai reply_ci = 0; 520023ab2a9SKashyap Desai exp_phase ^= 1; 521023ab2a9SKashyap Desai } 522023ab2a9SKashyap Desai 523023ab2a9SKashyap Desai reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci); 524023ab2a9SKashyap Desai 525023ab2a9SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 526023ab2a9SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 527023ab2a9SKashyap Desai break; 528463429f8SKashyap Desai /* 529463429f8SKashyap Desai * Exit completion loop to avoid CPU lockup 530463429f8SKashyap Desai * Ensure remaining completion happens from threaded ISR. 531463429f8SKashyap Desai */ 532463429f8SKashyap Desai if (num_op_reply > mrioc->max_host_ios) { 533*afd3a579SSreekanth Reddy op_reply_q->enable_irq_poll = true; 534463429f8SKashyap Desai break; 535463429f8SKashyap Desai } 536023ab2a9SKashyap Desai 537023ab2a9SKashyap Desai } while (1); 538023ab2a9SKashyap Desai 539023ab2a9SKashyap Desai writel(reply_ci, 540023ab2a9SKashyap Desai &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index); 541023ab2a9SKashyap Desai op_reply_q->ci = reply_ci; 542023ab2a9SKashyap Desai op_reply_q->ephase = exp_phase; 543023ab2a9SKashyap Desai 544463429f8SKashyap Desai atomic_dec(&op_reply_q->in_use); 545023ab2a9SKashyap Desai return num_op_reply; 546023ab2a9SKashyap Desai } 547023ab2a9SKashyap Desai 548*afd3a579SSreekanth Reddy /** 549*afd3a579SSreekanth Reddy * mpi3mr_blk_mq_poll - Operational reply queue handler 550*afd3a579SSreekanth Reddy * @shost: SCSI Host reference 551*afd3a579SSreekanth Reddy * @queue_num: Request queue number (w.r.t OS it is hardware context number) 552*afd3a579SSreekanth Reddy * 553*afd3a579SSreekanth Reddy * Checks the specific operational reply queue and drains the 554*afd3a579SSreekanth Reddy * reply queue entries until the queue is empty and process the 555*afd3a579SSreekanth Reddy * individual reply descriptors. 556*afd3a579SSreekanth Reddy * 557*afd3a579SSreekanth Reddy * Return: 0 if queue is already processed,or number of reply 558*afd3a579SSreekanth Reddy * descriptors processed. 559*afd3a579SSreekanth Reddy */ 560*afd3a579SSreekanth Reddy int mpi3mr_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num) 561*afd3a579SSreekanth Reddy { 562*afd3a579SSreekanth Reddy int num_entries = 0; 563*afd3a579SSreekanth Reddy struct mpi3mr_ioc *mrioc; 564*afd3a579SSreekanth Reddy 565*afd3a579SSreekanth Reddy mrioc = (struct mpi3mr_ioc *)shost->hostdata; 566*afd3a579SSreekanth Reddy 567*afd3a579SSreekanth Reddy if ((mrioc->reset_in_progress || mrioc->prepare_for_reset)) 568*afd3a579SSreekanth Reddy return 0; 569*afd3a579SSreekanth Reddy 570*afd3a579SSreekanth Reddy num_entries = mpi3mr_process_op_reply_q(mrioc, 571*afd3a579SSreekanth Reddy &mrioc->op_reply_qinfo[queue_num]); 572*afd3a579SSreekanth Reddy 573*afd3a579SSreekanth Reddy return num_entries; 574*afd3a579SSreekanth Reddy } 575*afd3a579SSreekanth Reddy 576824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata) 577824a1566SKashyap Desai { 578824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = privdata; 579824a1566SKashyap Desai struct mpi3mr_ioc *mrioc; 580824a1566SKashyap Desai u16 midx; 581463429f8SKashyap Desai u32 num_admin_replies = 0, num_op_reply = 0; 582824a1566SKashyap Desai 583824a1566SKashyap Desai if (!intr_info) 584824a1566SKashyap Desai return IRQ_NONE; 585824a1566SKashyap Desai 586824a1566SKashyap Desai mrioc = intr_info->mrioc; 587824a1566SKashyap Desai 588824a1566SKashyap Desai if (!mrioc->intr_enabled) 589824a1566SKashyap Desai return IRQ_NONE; 590824a1566SKashyap Desai 591824a1566SKashyap Desai midx = intr_info->msix_index; 592824a1566SKashyap Desai 593824a1566SKashyap Desai if (!midx) 594824a1566SKashyap Desai num_admin_replies = mpi3mr_process_admin_reply_q(mrioc); 595463429f8SKashyap Desai if (intr_info->op_reply_q) 596*afd3a579SSreekanth Reddy num_op_reply = mpi3mr_process_op_reply_q(mrioc, 597*afd3a579SSreekanth Reddy intr_info->op_reply_q); 598824a1566SKashyap Desai 599463429f8SKashyap Desai if (num_admin_replies || num_op_reply) 600824a1566SKashyap Desai return IRQ_HANDLED; 601824a1566SKashyap Desai else 602824a1566SKashyap Desai return IRQ_NONE; 603824a1566SKashyap Desai } 604824a1566SKashyap Desai 605824a1566SKashyap Desai static irqreturn_t mpi3mr_isr(int irq, void *privdata) 606824a1566SKashyap Desai { 607824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = privdata; 608463429f8SKashyap Desai struct mpi3mr_ioc *mrioc; 609463429f8SKashyap Desai u16 midx; 610824a1566SKashyap Desai int ret; 611824a1566SKashyap Desai 612824a1566SKashyap Desai if (!intr_info) 613824a1566SKashyap Desai return IRQ_NONE; 614824a1566SKashyap Desai 615463429f8SKashyap Desai mrioc = intr_info->mrioc; 616463429f8SKashyap Desai midx = intr_info->msix_index; 617824a1566SKashyap Desai /* Call primary ISR routine */ 618824a1566SKashyap Desai ret = mpi3mr_isr_primary(irq, privdata); 619824a1566SKashyap Desai 620463429f8SKashyap Desai /* 621463429f8SKashyap Desai * If more IOs are expected, schedule IRQ polling thread. 622463429f8SKashyap Desai * Otherwise exit from ISR. 623463429f8SKashyap Desai */ 624463429f8SKashyap Desai if (!intr_info->op_reply_q) 625824a1566SKashyap Desai return ret; 626463429f8SKashyap Desai 627463429f8SKashyap Desai if (!intr_info->op_reply_q->enable_irq_poll || 628463429f8SKashyap Desai !atomic_read(&intr_info->op_reply_q->pend_ios)) 629463429f8SKashyap Desai return ret; 630463429f8SKashyap Desai 631463429f8SKashyap Desai disable_irq_nosync(pci_irq_vector(mrioc->pdev, midx)); 632463429f8SKashyap Desai 633463429f8SKashyap Desai return IRQ_WAKE_THREAD; 634824a1566SKashyap Desai } 635824a1566SKashyap Desai 636824a1566SKashyap Desai /** 637824a1566SKashyap Desai * mpi3mr_isr_poll - Reply queue polling routine 638824a1566SKashyap Desai * @irq: IRQ 639824a1566SKashyap Desai * @privdata: Interrupt info 640824a1566SKashyap Desai * 641824a1566SKashyap Desai * poll for pending I/O completions in a loop until pending I/Os 642824a1566SKashyap Desai * present or controller queue depth I/Os are processed. 643824a1566SKashyap Desai * 644824a1566SKashyap Desai * Return: IRQ_NONE or IRQ_HANDLED 645824a1566SKashyap Desai */ 646824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata) 647824a1566SKashyap Desai { 648463429f8SKashyap Desai struct mpi3mr_intr_info *intr_info = privdata; 649463429f8SKashyap Desai struct mpi3mr_ioc *mrioc; 650463429f8SKashyap Desai u16 midx; 651463429f8SKashyap Desai u32 num_op_reply = 0; 652463429f8SKashyap Desai 653463429f8SKashyap Desai if (!intr_info || !intr_info->op_reply_q) 654463429f8SKashyap Desai return IRQ_NONE; 655463429f8SKashyap Desai 656463429f8SKashyap Desai mrioc = intr_info->mrioc; 657463429f8SKashyap Desai midx = intr_info->msix_index; 658463429f8SKashyap Desai 659463429f8SKashyap Desai /* Poll for pending IOs completions */ 660463429f8SKashyap Desai do { 661463429f8SKashyap Desai if (!mrioc->intr_enabled) 662463429f8SKashyap Desai break; 663463429f8SKashyap Desai 664463429f8SKashyap Desai if (!midx) 665463429f8SKashyap Desai mpi3mr_process_admin_reply_q(mrioc); 666463429f8SKashyap Desai if (intr_info->op_reply_q) 667463429f8SKashyap Desai num_op_reply += 668*afd3a579SSreekanth Reddy mpi3mr_process_op_reply_q(mrioc, 669*afd3a579SSreekanth Reddy intr_info->op_reply_q); 670463429f8SKashyap Desai 671*afd3a579SSreekanth Reddy usleep_range(MPI3MR_IRQ_POLL_SLEEP, 10 * MPI3MR_IRQ_POLL_SLEEP); 672463429f8SKashyap Desai 673463429f8SKashyap Desai } while (atomic_read(&intr_info->op_reply_q->pend_ios) && 674463429f8SKashyap Desai (num_op_reply < mrioc->max_host_ios)); 675463429f8SKashyap Desai 676463429f8SKashyap Desai intr_info->op_reply_q->enable_irq_poll = false; 677463429f8SKashyap Desai enable_irq(pci_irq_vector(mrioc->pdev, midx)); 678463429f8SKashyap Desai 679824a1566SKashyap Desai return IRQ_HANDLED; 680824a1566SKashyap Desai } 681824a1566SKashyap Desai 682824a1566SKashyap Desai /** 683824a1566SKashyap Desai * mpi3mr_request_irq - Request IRQ and register ISR 684824a1566SKashyap Desai * @mrioc: Adapter instance reference 685824a1566SKashyap Desai * @index: IRQ vector index 686824a1566SKashyap Desai * 687824a1566SKashyap Desai * Request threaded ISR with primary ISR and secondary 688824a1566SKashyap Desai * 689824a1566SKashyap Desai * Return: 0 on success and non zero on failures. 690824a1566SKashyap Desai */ 691824a1566SKashyap Desai static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index) 692824a1566SKashyap Desai { 693824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 694824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index; 695824a1566SKashyap Desai int retval = 0; 696824a1566SKashyap Desai 697824a1566SKashyap Desai intr_info->mrioc = mrioc; 698824a1566SKashyap Desai intr_info->msix_index = index; 699824a1566SKashyap Desai intr_info->op_reply_q = NULL; 700824a1566SKashyap Desai 701824a1566SKashyap Desai snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d", 702824a1566SKashyap Desai mrioc->driver_name, mrioc->id, index); 703824a1566SKashyap Desai 704824a1566SKashyap Desai retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr, 705824a1566SKashyap Desai mpi3mr_isr_poll, IRQF_SHARED, intr_info->name, intr_info); 706824a1566SKashyap Desai if (retval) { 707824a1566SKashyap Desai ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n", 708824a1566SKashyap Desai intr_info->name, pci_irq_vector(pdev, index)); 709824a1566SKashyap Desai return retval; 710824a1566SKashyap Desai } 711824a1566SKashyap Desai 712824a1566SKashyap Desai return retval; 713824a1566SKashyap Desai } 714824a1566SKashyap Desai 715*afd3a579SSreekanth Reddy static void mpi3mr_calc_poll_queues(struct mpi3mr_ioc *mrioc, u16 max_vectors) 716*afd3a579SSreekanth Reddy { 717*afd3a579SSreekanth Reddy if (!mrioc->requested_poll_qcount) 718*afd3a579SSreekanth Reddy return; 719*afd3a579SSreekanth Reddy 720*afd3a579SSreekanth Reddy /* Reserved for Admin and Default Queue */ 721*afd3a579SSreekanth Reddy if (max_vectors > 2 && 722*afd3a579SSreekanth Reddy (mrioc->requested_poll_qcount < max_vectors - 2)) { 723*afd3a579SSreekanth Reddy ioc_info(mrioc, 724*afd3a579SSreekanth Reddy "enabled polled queues (%d) msix (%d)\n", 725*afd3a579SSreekanth Reddy mrioc->requested_poll_qcount, max_vectors); 726*afd3a579SSreekanth Reddy } else { 727*afd3a579SSreekanth Reddy ioc_info(mrioc, 728*afd3a579SSreekanth Reddy "disabled polled queues (%d) msix (%d) because of no resources for default queue\n", 729*afd3a579SSreekanth Reddy mrioc->requested_poll_qcount, max_vectors); 730*afd3a579SSreekanth Reddy mrioc->requested_poll_qcount = 0; 731*afd3a579SSreekanth Reddy } 732*afd3a579SSreekanth Reddy } 733*afd3a579SSreekanth Reddy 734824a1566SKashyap Desai /** 735824a1566SKashyap Desai * mpi3mr_setup_isr - Setup ISR for the controller 736824a1566SKashyap Desai * @mrioc: Adapter instance reference 737824a1566SKashyap Desai * @setup_one: Request one IRQ or more 738824a1566SKashyap Desai * 739824a1566SKashyap Desai * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR 740824a1566SKashyap Desai * 741824a1566SKashyap Desai * Return: 0 on success and non zero on failures. 742824a1566SKashyap Desai */ 743824a1566SKashyap Desai static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one) 744824a1566SKashyap Desai { 745824a1566SKashyap Desai unsigned int irq_flags = PCI_IRQ_MSIX; 746*afd3a579SSreekanth Reddy int max_vectors, min_vec; 7472938beddSDan Carpenter int retval; 7482938beddSDan Carpenter int i; 749*afd3a579SSreekanth Reddy struct irq_affinity desc = { .pre_vectors = 1, .post_vectors = 1 }; 750824a1566SKashyap Desai 751fe6db615SSreekanth Reddy if (mrioc->is_intr_info_set) 752fe6db615SSreekanth Reddy return 0; 753fe6db615SSreekanth Reddy 754824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 755824a1566SKashyap Desai 756*afd3a579SSreekanth Reddy if (setup_one || reset_devices) { 757824a1566SKashyap Desai max_vectors = 1; 758*afd3a579SSreekanth Reddy retval = pci_alloc_irq_vectors(mrioc->pdev, 759*afd3a579SSreekanth Reddy 1, max_vectors, irq_flags); 760*afd3a579SSreekanth Reddy if (retval < 0) { 761*afd3a579SSreekanth Reddy ioc_err(mrioc, "cannot allocate irq vectors, ret %d\n", 762*afd3a579SSreekanth Reddy retval); 763*afd3a579SSreekanth Reddy goto out_failed; 764*afd3a579SSreekanth Reddy } 765*afd3a579SSreekanth Reddy } else { 766824a1566SKashyap Desai max_vectors = 767*afd3a579SSreekanth Reddy min_t(int, mrioc->cpu_count + 1 + 768*afd3a579SSreekanth Reddy mrioc->requested_poll_qcount, mrioc->msix_count); 769*afd3a579SSreekanth Reddy 770*afd3a579SSreekanth Reddy mpi3mr_calc_poll_queues(mrioc, max_vectors); 771824a1566SKashyap Desai 772824a1566SKashyap Desai ioc_info(mrioc, 773824a1566SKashyap Desai "MSI-X vectors supported: %d, no of cores: %d,", 774824a1566SKashyap Desai mrioc->msix_count, mrioc->cpu_count); 775824a1566SKashyap Desai ioc_info(mrioc, 776*afd3a579SSreekanth Reddy "MSI-x vectors requested: %d poll_queues %d\n", 777*afd3a579SSreekanth Reddy max_vectors, mrioc->requested_poll_qcount); 778824a1566SKashyap Desai 779*afd3a579SSreekanth Reddy desc.post_vectors = mrioc->requested_poll_qcount; 780*afd3a579SSreekanth Reddy min_vec = desc.pre_vectors + desc.post_vectors; 781824a1566SKashyap Desai irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES; 782824a1566SKashyap Desai 7832938beddSDan Carpenter retval = pci_alloc_irq_vectors_affinity(mrioc->pdev, 784*afd3a579SSreekanth Reddy min_vec, max_vectors, irq_flags, &desc); 785*afd3a579SSreekanth Reddy 7862938beddSDan Carpenter if (retval < 0) { 787*afd3a579SSreekanth Reddy ioc_err(mrioc, "cannot allocate irq vectors, ret %d\n", 788*afd3a579SSreekanth Reddy retval); 789824a1566SKashyap Desai goto out_failed; 790824a1566SKashyap Desai } 791*afd3a579SSreekanth Reddy 792*afd3a579SSreekanth Reddy 793c9566231SKashyap Desai /* 794c9566231SKashyap Desai * If only one MSI-x is allocated, then MSI-x 0 will be shared 795c9566231SKashyap Desai * between Admin queue and operational queue 796c9566231SKashyap Desai */ 797*afd3a579SSreekanth Reddy if (retval == min_vec) 798c9566231SKashyap Desai mrioc->op_reply_q_offset = 0; 799*afd3a579SSreekanth Reddy else if (retval != (max_vectors)) { 800*afd3a579SSreekanth Reddy ioc_info(mrioc, 801*afd3a579SSreekanth Reddy "allocated vectors (%d) are less than configured (%d)\n", 802*afd3a579SSreekanth Reddy retval, max_vectors); 803*afd3a579SSreekanth Reddy } 804824a1566SKashyap Desai 8052938beddSDan Carpenter max_vectors = retval; 806*afd3a579SSreekanth Reddy mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0; 807*afd3a579SSreekanth Reddy 808*afd3a579SSreekanth Reddy mpi3mr_calc_poll_queues(mrioc, max_vectors); 809*afd3a579SSreekanth Reddy 810824a1566SKashyap Desai } 811*afd3a579SSreekanth Reddy 812824a1566SKashyap Desai mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info) * max_vectors, 813824a1566SKashyap Desai GFP_KERNEL); 814824a1566SKashyap Desai if (!mrioc->intr_info) { 8152938beddSDan Carpenter retval = -ENOMEM; 816824a1566SKashyap Desai pci_free_irq_vectors(mrioc->pdev); 817824a1566SKashyap Desai goto out_failed; 818824a1566SKashyap Desai } 819824a1566SKashyap Desai for (i = 0; i < max_vectors; i++) { 820824a1566SKashyap Desai retval = mpi3mr_request_irq(mrioc, i); 821824a1566SKashyap Desai if (retval) { 822824a1566SKashyap Desai mrioc->intr_info_count = i; 823824a1566SKashyap Desai goto out_failed; 824824a1566SKashyap Desai } 825824a1566SKashyap Desai } 826fe6db615SSreekanth Reddy if (reset_devices || !setup_one) 827fe6db615SSreekanth Reddy mrioc->is_intr_info_set = true; 828824a1566SKashyap Desai mrioc->intr_info_count = max_vectors; 829824a1566SKashyap Desai mpi3mr_ioc_enable_intr(mrioc); 8302938beddSDan Carpenter return 0; 8312938beddSDan Carpenter 832824a1566SKashyap Desai out_failed: 833824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 834824a1566SKashyap Desai 835824a1566SKashyap Desai return retval; 836824a1566SKashyap Desai } 837824a1566SKashyap Desai 838824a1566SKashyap Desai static const struct { 839824a1566SKashyap Desai enum mpi3mr_iocstate value; 840824a1566SKashyap Desai char *name; 841824a1566SKashyap Desai } mrioc_states[] = { 842824a1566SKashyap Desai { MRIOC_STATE_READY, "ready" }, 843824a1566SKashyap Desai { MRIOC_STATE_FAULT, "fault" }, 844824a1566SKashyap Desai { MRIOC_STATE_RESET, "reset" }, 845824a1566SKashyap Desai { MRIOC_STATE_BECOMING_READY, "becoming ready" }, 846824a1566SKashyap Desai { MRIOC_STATE_RESET_REQUESTED, "reset requested" }, 847824a1566SKashyap Desai { MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" }, 848824a1566SKashyap Desai }; 849824a1566SKashyap Desai 850824a1566SKashyap Desai static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state) 851824a1566SKashyap Desai { 852824a1566SKashyap Desai int i; 853824a1566SKashyap Desai char *name = NULL; 854824a1566SKashyap Desai 855824a1566SKashyap Desai for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) { 856824a1566SKashyap Desai if (mrioc_states[i].value == mrioc_state) { 857824a1566SKashyap Desai name = mrioc_states[i].name; 858824a1566SKashyap Desai break; 859824a1566SKashyap Desai } 860824a1566SKashyap Desai } 861824a1566SKashyap Desai return name; 862824a1566SKashyap Desai } 863824a1566SKashyap Desai 864f061178eSKashyap Desai /* Reset reason to name mapper structure*/ 865f061178eSKashyap Desai static const struct { 866f061178eSKashyap Desai enum mpi3mr_reset_reason value; 867f061178eSKashyap Desai char *name; 868f061178eSKashyap Desai } mpi3mr_reset_reason_codes[] = { 869f061178eSKashyap Desai { MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" }, 870f061178eSKashyap Desai { MPI3MR_RESET_FROM_FAULT_WATCH, "fault" }, 871f061178eSKashyap Desai { MPI3MR_RESET_FROM_IOCTL, "application invocation" }, 872f061178eSKashyap Desai { MPI3MR_RESET_FROM_EH_HOS, "error handling" }, 873f061178eSKashyap Desai { MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" }, 874f061178eSKashyap Desai { MPI3MR_RESET_FROM_IOCTL_TIMEOUT, "IOCTL timeout" }, 875f061178eSKashyap Desai { MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" }, 876f061178eSKashyap Desai { MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" }, 877f061178eSKashyap Desai { MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" }, 878f061178eSKashyap Desai { MPI3MR_RESET_FROM_PE_TIMEOUT, "port enable timeout" }, 879f061178eSKashyap Desai { MPI3MR_RESET_FROM_TSU_TIMEOUT, "time stamp update timeout" }, 880f061178eSKashyap Desai { MPI3MR_RESET_FROM_DELREQQ_TIMEOUT, "delete request queue timeout" }, 881f061178eSKashyap Desai { MPI3MR_RESET_FROM_DELREPQ_TIMEOUT, "delete reply queue timeout" }, 882f061178eSKashyap Desai { 883f061178eSKashyap Desai MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT, 884f061178eSKashyap Desai "create request queue timeout" 885f061178eSKashyap Desai }, 886f061178eSKashyap Desai { 887f061178eSKashyap Desai MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT, 888f061178eSKashyap Desai "create reply queue timeout" 889f061178eSKashyap Desai }, 890f061178eSKashyap Desai { MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT, "IOC facts timeout" }, 891f061178eSKashyap Desai { MPI3MR_RESET_FROM_IOCINIT_TIMEOUT, "IOC init timeout" }, 892f061178eSKashyap Desai { MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT, "event notify timeout" }, 893f061178eSKashyap Desai { MPI3MR_RESET_FROM_EVTACK_TIMEOUT, "event acknowledgment timeout" }, 894f061178eSKashyap Desai { 895f061178eSKashyap Desai MPI3MR_RESET_FROM_CIACTVRST_TIMER, 896f061178eSKashyap Desai "component image activation timeout" 897f061178eSKashyap Desai }, 898f061178eSKashyap Desai { 899f061178eSKashyap Desai MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT, 900f061178eSKashyap Desai "get package version timeout" 901f061178eSKashyap Desai }, 902f061178eSKashyap Desai { MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" }, 903f061178eSKashyap Desai { MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" }, 904b64845a7SSreekanth Reddy { MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronus reset" }, 905f061178eSKashyap Desai }; 906f061178eSKashyap Desai 907f061178eSKashyap Desai /** 908f061178eSKashyap Desai * mpi3mr_reset_rc_name - get reset reason code name 909f061178eSKashyap Desai * @reason_code: reset reason code value 910f061178eSKashyap Desai * 911f061178eSKashyap Desai * Map reset reason to an NULL terminated ASCII string 912f061178eSKashyap Desai * 913f061178eSKashyap Desai * Return: name corresponding to reset reason value or NULL. 914f061178eSKashyap Desai */ 915f061178eSKashyap Desai static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code) 916f061178eSKashyap Desai { 917f061178eSKashyap Desai int i; 918f061178eSKashyap Desai char *name = NULL; 919f061178eSKashyap Desai 920f061178eSKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_reason_codes); i++) { 921f061178eSKashyap Desai if (mpi3mr_reset_reason_codes[i].value == reason_code) { 922f061178eSKashyap Desai name = mpi3mr_reset_reason_codes[i].name; 923f061178eSKashyap Desai break; 924f061178eSKashyap Desai } 925f061178eSKashyap Desai } 926f061178eSKashyap Desai return name; 927f061178eSKashyap Desai } 928f061178eSKashyap Desai 929f061178eSKashyap Desai /* Reset type to name mapper structure*/ 930f061178eSKashyap Desai static const struct { 931f061178eSKashyap Desai u16 reset_type; 932f061178eSKashyap Desai char *name; 933f061178eSKashyap Desai } mpi3mr_reset_types[] = { 934f061178eSKashyap Desai { MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, "soft" }, 935f061178eSKashyap Desai { MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, "diag fault" }, 936f061178eSKashyap Desai }; 937f061178eSKashyap Desai 938f061178eSKashyap Desai /** 939f061178eSKashyap Desai * mpi3mr_reset_type_name - get reset type name 940f061178eSKashyap Desai * @reset_type: reset type value 941f061178eSKashyap Desai * 942f061178eSKashyap Desai * Map reset type to an NULL terminated ASCII string 943f061178eSKashyap Desai * 944f061178eSKashyap Desai * Return: name corresponding to reset type value or NULL. 945f061178eSKashyap Desai */ 946f061178eSKashyap Desai static const char *mpi3mr_reset_type_name(u16 reset_type) 947f061178eSKashyap Desai { 948f061178eSKashyap Desai int i; 949f061178eSKashyap Desai char *name = NULL; 950f061178eSKashyap Desai 951f061178eSKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_types); i++) { 952f061178eSKashyap Desai if (mpi3mr_reset_types[i].reset_type == reset_type) { 953f061178eSKashyap Desai name = mpi3mr_reset_types[i].name; 954f061178eSKashyap Desai break; 955f061178eSKashyap Desai } 956f061178eSKashyap Desai } 957f061178eSKashyap Desai return name; 958f061178eSKashyap Desai } 959f061178eSKashyap Desai 960824a1566SKashyap Desai /** 961824a1566SKashyap Desai * mpi3mr_print_fault_info - Display fault information 962824a1566SKashyap Desai * @mrioc: Adapter instance reference 963824a1566SKashyap Desai * 964824a1566SKashyap Desai * Display the controller fault information if there is a 965824a1566SKashyap Desai * controller fault. 966824a1566SKashyap Desai * 967824a1566SKashyap Desai * Return: Nothing. 968824a1566SKashyap Desai */ 969b64845a7SSreekanth Reddy void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc) 970824a1566SKashyap Desai { 971824a1566SKashyap Desai u32 ioc_status, code, code1, code2, code3; 972824a1566SKashyap Desai 973824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 974824a1566SKashyap Desai 975824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { 976824a1566SKashyap Desai code = readl(&mrioc->sysif_regs->fault); 977824a1566SKashyap Desai code1 = readl(&mrioc->sysif_regs->fault_info[0]); 978824a1566SKashyap Desai code2 = readl(&mrioc->sysif_regs->fault_info[1]); 979824a1566SKashyap Desai code3 = readl(&mrioc->sysif_regs->fault_info[2]); 980824a1566SKashyap Desai 981824a1566SKashyap Desai ioc_info(mrioc, 982824a1566SKashyap Desai "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n", 983824a1566SKashyap Desai code, code1, code2, code3); 984824a1566SKashyap Desai } 985824a1566SKashyap Desai } 986824a1566SKashyap Desai 987824a1566SKashyap Desai /** 988824a1566SKashyap Desai * mpi3mr_get_iocstate - Get IOC State 989824a1566SKashyap Desai * @mrioc: Adapter instance reference 990824a1566SKashyap Desai * 991824a1566SKashyap Desai * Return a proper IOC state enum based on the IOC status and 992824a1566SKashyap Desai * IOC configuration and unrcoverable state of the controller. 993824a1566SKashyap Desai * 994824a1566SKashyap Desai * Return: Current IOC state. 995824a1566SKashyap Desai */ 996824a1566SKashyap Desai enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc) 997824a1566SKashyap Desai { 998824a1566SKashyap Desai u32 ioc_status, ioc_config; 999824a1566SKashyap Desai u8 ready, enabled; 1000824a1566SKashyap Desai 1001824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1002824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1003824a1566SKashyap Desai 1004824a1566SKashyap Desai if (mrioc->unrecoverable) 1005824a1566SKashyap Desai return MRIOC_STATE_UNRECOVERABLE; 1006824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) 1007824a1566SKashyap Desai return MRIOC_STATE_FAULT; 1008824a1566SKashyap Desai 1009824a1566SKashyap Desai ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY); 1010824a1566SKashyap Desai enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC); 1011824a1566SKashyap Desai 1012824a1566SKashyap Desai if (ready && enabled) 1013824a1566SKashyap Desai return MRIOC_STATE_READY; 1014824a1566SKashyap Desai if ((!ready) && (!enabled)) 1015824a1566SKashyap Desai return MRIOC_STATE_RESET; 1016824a1566SKashyap Desai if ((!ready) && (enabled)) 1017824a1566SKashyap Desai return MRIOC_STATE_BECOMING_READY; 1018824a1566SKashyap Desai 1019824a1566SKashyap Desai return MRIOC_STATE_RESET_REQUESTED; 1020824a1566SKashyap Desai } 1021824a1566SKashyap Desai 1022824a1566SKashyap Desai /** 1023824a1566SKashyap Desai * mpi3mr_clear_reset_history - clear reset history 1024824a1566SKashyap Desai * @mrioc: Adapter instance reference 1025824a1566SKashyap Desai * 1026824a1566SKashyap Desai * Write the reset history bit in IOC status to clear the bit, 1027824a1566SKashyap Desai * if it is already set. 1028824a1566SKashyap Desai * 1029824a1566SKashyap Desai * Return: Nothing. 1030824a1566SKashyap Desai */ 1031824a1566SKashyap Desai static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc) 1032824a1566SKashyap Desai { 1033824a1566SKashyap Desai u32 ioc_status; 1034824a1566SKashyap Desai 1035824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1036824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) 1037824a1566SKashyap Desai writel(ioc_status, &mrioc->sysif_regs->ioc_status); 1038824a1566SKashyap Desai } 1039824a1566SKashyap Desai 1040824a1566SKashyap Desai /** 1041824a1566SKashyap Desai * mpi3mr_issue_and_process_mur - Message unit Reset handler 1042824a1566SKashyap Desai * @mrioc: Adapter instance reference 1043824a1566SKashyap Desai * @reset_reason: Reset reason code 1044824a1566SKashyap Desai * 1045824a1566SKashyap Desai * Issue Message unit Reset to the controller and wait for it to 1046824a1566SKashyap Desai * be complete. 1047824a1566SKashyap Desai * 1048824a1566SKashyap Desai * Return: 0 on success, -1 on failure. 1049824a1566SKashyap Desai */ 1050824a1566SKashyap Desai static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc, 1051824a1566SKashyap Desai u32 reset_reason) 1052824a1566SKashyap Desai { 1053824a1566SKashyap Desai u32 ioc_config, timeout, ioc_status; 1054824a1566SKashyap Desai int retval = -1; 1055824a1566SKashyap Desai 1056824a1566SKashyap Desai ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n"); 1057824a1566SKashyap Desai if (mrioc->unrecoverable) { 1058824a1566SKashyap Desai ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n"); 1059824a1566SKashyap Desai return retval; 1060824a1566SKashyap Desai } 1061824a1566SKashyap Desai mpi3mr_clear_reset_history(mrioc); 1062824a1566SKashyap Desai writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); 1063824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1064824a1566SKashyap Desai ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; 1065824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 1066824a1566SKashyap Desai 1067b64845a7SSreekanth Reddy timeout = MPI3MR_RESET_ACK_TIMEOUT * 10; 1068824a1566SKashyap Desai do { 1069824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1070824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) { 1071824a1566SKashyap Desai mpi3mr_clear_reset_history(mrioc); 1072824a1566SKashyap Desai break; 1073824a1566SKashyap Desai } 1074b64845a7SSreekanth Reddy if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { 1075b64845a7SSreekanth Reddy mpi3mr_print_fault_info(mrioc); 1076b64845a7SSreekanth Reddy break; 1077824a1566SKashyap Desai } 1078824a1566SKashyap Desai msleep(100); 1079824a1566SKashyap Desai } while (--timeout); 1080824a1566SKashyap Desai 1081824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1082b64845a7SSreekanth Reddy if (timeout && !((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || 1083b64845a7SSreekanth Reddy (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) || 1084b64845a7SSreekanth Reddy (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) 1085b64845a7SSreekanth Reddy retval = 0; 1086824a1566SKashyap Desai 1087824a1566SKashyap Desai ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n", 1088824a1566SKashyap Desai (!retval) ? "successful" : "failed", ioc_status, ioc_config); 1089824a1566SKashyap Desai return retval; 1090824a1566SKashyap Desai } 1091824a1566SKashyap Desai 1092824a1566SKashyap Desai /** 1093c5758fc7SSreekanth Reddy * mpi3mr_revalidate_factsdata - validate IOCFacts parameters 1094c5758fc7SSreekanth Reddy * during reset/resume 1095c5758fc7SSreekanth Reddy * @mrioc: Adapter instance reference 1096c5758fc7SSreekanth Reddy * 1097c5758fc7SSreekanth Reddy * Return zero if the new IOCFacts parameters value is compatible with 1098c5758fc7SSreekanth Reddy * older values else return -EPERM 1099c5758fc7SSreekanth Reddy */ 1100c5758fc7SSreekanth Reddy static int 1101c5758fc7SSreekanth Reddy mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc) 1102c5758fc7SSreekanth Reddy { 1103c5758fc7SSreekanth Reddy u16 dev_handle_bitmap_sz; 1104c5758fc7SSreekanth Reddy void *removepend_bitmap; 1105c5758fc7SSreekanth Reddy 1106c5758fc7SSreekanth Reddy if (mrioc->facts.reply_sz > mrioc->reply_sz) { 1107c5758fc7SSreekanth Reddy ioc_err(mrioc, 1108c5758fc7SSreekanth Reddy "cannot increase reply size from %d to %d\n", 1109c5758fc7SSreekanth Reddy mrioc->reply_sz, mrioc->facts.reply_sz); 1110c5758fc7SSreekanth Reddy return -EPERM; 1111c5758fc7SSreekanth Reddy } 1112c5758fc7SSreekanth Reddy 1113c5758fc7SSreekanth Reddy if (mrioc->facts.max_op_reply_q < mrioc->num_op_reply_q) { 1114c5758fc7SSreekanth Reddy ioc_err(mrioc, 1115c5758fc7SSreekanth Reddy "cannot reduce number of operational reply queues from %d to %d\n", 1116c5758fc7SSreekanth Reddy mrioc->num_op_reply_q, 1117c5758fc7SSreekanth Reddy mrioc->facts.max_op_reply_q); 1118c5758fc7SSreekanth Reddy return -EPERM; 1119c5758fc7SSreekanth Reddy } 1120c5758fc7SSreekanth Reddy 1121c5758fc7SSreekanth Reddy if (mrioc->facts.max_op_req_q < mrioc->num_op_req_q) { 1122c5758fc7SSreekanth Reddy ioc_err(mrioc, 1123c5758fc7SSreekanth Reddy "cannot reduce number of operational request queues from %d to %d\n", 1124c5758fc7SSreekanth Reddy mrioc->num_op_req_q, mrioc->facts.max_op_req_q); 1125c5758fc7SSreekanth Reddy return -EPERM; 1126c5758fc7SSreekanth Reddy } 1127c5758fc7SSreekanth Reddy 1128c5758fc7SSreekanth Reddy dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8; 1129c5758fc7SSreekanth Reddy if (mrioc->facts.max_devhandle % 8) 1130c5758fc7SSreekanth Reddy dev_handle_bitmap_sz++; 1131c5758fc7SSreekanth Reddy if (dev_handle_bitmap_sz > mrioc->dev_handle_bitmap_sz) { 1132c5758fc7SSreekanth Reddy removepend_bitmap = krealloc(mrioc->removepend_bitmap, 1133c5758fc7SSreekanth Reddy dev_handle_bitmap_sz, GFP_KERNEL); 1134c5758fc7SSreekanth Reddy if (!removepend_bitmap) { 1135c5758fc7SSreekanth Reddy ioc_err(mrioc, 1136c5758fc7SSreekanth Reddy "failed to increase removepend_bitmap sz from: %d to %d\n", 1137c5758fc7SSreekanth Reddy mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz); 1138c5758fc7SSreekanth Reddy return -EPERM; 1139c5758fc7SSreekanth Reddy } 1140c5758fc7SSreekanth Reddy memset(removepend_bitmap + mrioc->dev_handle_bitmap_sz, 0, 1141c5758fc7SSreekanth Reddy dev_handle_bitmap_sz - mrioc->dev_handle_bitmap_sz); 1142c5758fc7SSreekanth Reddy mrioc->removepend_bitmap = removepend_bitmap; 1143c5758fc7SSreekanth Reddy ioc_info(mrioc, 1144c5758fc7SSreekanth Reddy "increased dev_handle_bitmap_sz from %d to %d\n", 1145c5758fc7SSreekanth Reddy mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz); 1146c5758fc7SSreekanth Reddy mrioc->dev_handle_bitmap_sz = dev_handle_bitmap_sz; 1147c5758fc7SSreekanth Reddy } 1148c5758fc7SSreekanth Reddy 1149c5758fc7SSreekanth Reddy return 0; 1150c5758fc7SSreekanth Reddy } 1151c5758fc7SSreekanth Reddy 1152c5758fc7SSreekanth Reddy /** 1153824a1566SKashyap Desai * mpi3mr_bring_ioc_ready - Bring controller to ready state 1154824a1566SKashyap Desai * @mrioc: Adapter instance reference 1155824a1566SKashyap Desai * 1156824a1566SKashyap Desai * Set Enable IOC bit in IOC configuration register and wait for 1157824a1566SKashyap Desai * the controller to become ready. 1158824a1566SKashyap Desai * 115959bd9cfeSSreekanth Reddy * Return: 0 on success, appropriate error on failure. 1160824a1566SKashyap Desai */ 1161824a1566SKashyap Desai static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) 1162824a1566SKashyap Desai { 116359bd9cfeSSreekanth Reddy u32 ioc_config, ioc_status, timeout; 116459bd9cfeSSreekanth Reddy int retval = 0; 116559bd9cfeSSreekanth Reddy enum mpi3mr_iocstate ioc_state; 116659bd9cfeSSreekanth Reddy u64 base_info; 1167824a1566SKashyap Desai 116859bd9cfeSSreekanth Reddy ioc_status = readl(&mrioc->sysif_regs->ioc_status); 116959bd9cfeSSreekanth Reddy ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 117059bd9cfeSSreekanth Reddy base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information); 117159bd9cfeSSreekanth Reddy ioc_info(mrioc, "ioc_status(0x%08x), ioc_config(0x%08x), ioc_info(0x%016llx) at the bringup\n", 117259bd9cfeSSreekanth Reddy ioc_status, ioc_config, base_info); 117359bd9cfeSSreekanth Reddy 117459bd9cfeSSreekanth Reddy /*The timeout value is in 2sec unit, changing it to seconds*/ 117559bd9cfeSSreekanth Reddy mrioc->ready_timeout = 117659bd9cfeSSreekanth Reddy ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >> 117759bd9cfeSSreekanth Reddy MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2; 117859bd9cfeSSreekanth Reddy 117959bd9cfeSSreekanth Reddy ioc_info(mrioc, "ready timeout: %d seconds\n", mrioc->ready_timeout); 118059bd9cfeSSreekanth Reddy 118159bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 118259bd9cfeSSreekanth Reddy ioc_info(mrioc, "controller is in %s state during detection\n", 118359bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 118459bd9cfeSSreekanth Reddy 118559bd9cfeSSreekanth Reddy if (ioc_state == MRIOC_STATE_BECOMING_READY || 118659bd9cfeSSreekanth Reddy ioc_state == MRIOC_STATE_RESET_REQUESTED) { 118759bd9cfeSSreekanth Reddy timeout = mrioc->ready_timeout * 10; 118859bd9cfeSSreekanth Reddy do { 118959bd9cfeSSreekanth Reddy msleep(100); 119059bd9cfeSSreekanth Reddy } while (--timeout); 119159bd9cfeSSreekanth Reddy 119259bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 119359bd9cfeSSreekanth Reddy ioc_info(mrioc, 119459bd9cfeSSreekanth Reddy "controller is in %s state after waiting to reset\n", 119559bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 119659bd9cfeSSreekanth Reddy } 119759bd9cfeSSreekanth Reddy 119859bd9cfeSSreekanth Reddy if (ioc_state == MRIOC_STATE_READY) { 119959bd9cfeSSreekanth Reddy ioc_info(mrioc, "issuing message unit reset (MUR) to bring to reset state\n"); 120059bd9cfeSSreekanth Reddy retval = mpi3mr_issue_and_process_mur(mrioc, 120159bd9cfeSSreekanth Reddy MPI3MR_RESET_FROM_BRINGUP); 120259bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 120359bd9cfeSSreekanth Reddy if (retval) 120459bd9cfeSSreekanth Reddy ioc_err(mrioc, 120559bd9cfeSSreekanth Reddy "message unit reset failed with error %d current state %s\n", 120659bd9cfeSSreekanth Reddy retval, mpi3mr_iocstate_name(ioc_state)); 120759bd9cfeSSreekanth Reddy } 120859bd9cfeSSreekanth Reddy if (ioc_state != MRIOC_STATE_RESET) { 120959bd9cfeSSreekanth Reddy mpi3mr_print_fault_info(mrioc); 121059bd9cfeSSreekanth Reddy ioc_info(mrioc, "issuing soft reset to bring to reset state\n"); 121159bd9cfeSSreekanth Reddy retval = mpi3mr_issue_reset(mrioc, 121259bd9cfeSSreekanth Reddy MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, 121359bd9cfeSSreekanth Reddy MPI3MR_RESET_FROM_BRINGUP); 121459bd9cfeSSreekanth Reddy if (retval) { 121559bd9cfeSSreekanth Reddy ioc_err(mrioc, 121659bd9cfeSSreekanth Reddy "soft reset failed with error %d\n", retval); 121759bd9cfeSSreekanth Reddy goto out_failed; 121859bd9cfeSSreekanth Reddy } 121959bd9cfeSSreekanth Reddy } 122059bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 122159bd9cfeSSreekanth Reddy if (ioc_state != MRIOC_STATE_RESET) { 122259bd9cfeSSreekanth Reddy ioc_err(mrioc, 122359bd9cfeSSreekanth Reddy "cannot bring controller to reset state, current state: %s\n", 122459bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 122559bd9cfeSSreekanth Reddy goto out_failed; 122659bd9cfeSSreekanth Reddy } 122759bd9cfeSSreekanth Reddy mpi3mr_clear_reset_history(mrioc); 122859bd9cfeSSreekanth Reddy retval = mpi3mr_setup_admin_qpair(mrioc); 122959bd9cfeSSreekanth Reddy if (retval) { 123059bd9cfeSSreekanth Reddy ioc_err(mrioc, "failed to setup admin queues: error %d\n", 123159bd9cfeSSreekanth Reddy retval); 123259bd9cfeSSreekanth Reddy goto out_failed; 123359bd9cfeSSreekanth Reddy } 123459bd9cfeSSreekanth Reddy 123559bd9cfeSSreekanth Reddy ioc_info(mrioc, "bringing controller to ready state\n"); 1236824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1237824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; 1238824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 1239824a1566SKashyap Desai 1240824a1566SKashyap Desai timeout = mrioc->ready_timeout * 10; 1241824a1566SKashyap Desai do { 124259bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 124359bd9cfeSSreekanth Reddy if (ioc_state == MRIOC_STATE_READY) { 124459bd9cfeSSreekanth Reddy ioc_info(mrioc, 124559bd9cfeSSreekanth Reddy "successfully transistioned to %s state\n", 124659bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 1247824a1566SKashyap Desai return 0; 124859bd9cfeSSreekanth Reddy } 1249824a1566SKashyap Desai msleep(100); 1250824a1566SKashyap Desai } while (--timeout); 1251824a1566SKashyap Desai 125259bd9cfeSSreekanth Reddy out_failed: 125359bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 125459bd9cfeSSreekanth Reddy ioc_err(mrioc, 125559bd9cfeSSreekanth Reddy "failed to bring to ready state, current state: %s\n", 125659bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 125759bd9cfeSSreekanth Reddy return retval; 1258824a1566SKashyap Desai } 1259824a1566SKashyap Desai 1260824a1566SKashyap Desai /** 1261f061178eSKashyap Desai * mpi3mr_soft_reset_success - Check softreset is success or not 1262f061178eSKashyap Desai * @ioc_status: IOC status register value 1263f061178eSKashyap Desai * @ioc_config: IOC config register value 1264f061178eSKashyap Desai * 1265f061178eSKashyap Desai * Check whether the soft reset is successful or not based on 1266f061178eSKashyap Desai * IOC status and IOC config register values. 1267f061178eSKashyap Desai * 1268f061178eSKashyap Desai * Return: True when the soft reset is success, false otherwise. 1269f061178eSKashyap Desai */ 1270f061178eSKashyap Desai static inline bool 1271f061178eSKashyap Desai mpi3mr_soft_reset_success(u32 ioc_status, u32 ioc_config) 1272f061178eSKashyap Desai { 1273f061178eSKashyap Desai if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || 1274f061178eSKashyap Desai (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) 1275f061178eSKashyap Desai return true; 1276f061178eSKashyap Desai return false; 1277f061178eSKashyap Desai } 1278f061178eSKashyap Desai 1279f061178eSKashyap Desai /** 1280f061178eSKashyap Desai * mpi3mr_diagfault_success - Check diag fault is success or not 1281f061178eSKashyap Desai * @mrioc: Adapter reference 1282f061178eSKashyap Desai * @ioc_status: IOC status register value 1283f061178eSKashyap Desai * 1284f061178eSKashyap Desai * Check whether the controller hit diag reset fault code. 1285f061178eSKashyap Desai * 1286f061178eSKashyap Desai * Return: True when there is diag fault, false otherwise. 1287f061178eSKashyap Desai */ 1288f061178eSKashyap Desai static inline bool mpi3mr_diagfault_success(struct mpi3mr_ioc *mrioc, 1289f061178eSKashyap Desai u32 ioc_status) 1290f061178eSKashyap Desai { 1291f061178eSKashyap Desai u32 fault; 1292f061178eSKashyap Desai 1293f061178eSKashyap Desai if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) 1294f061178eSKashyap Desai return false; 1295f061178eSKashyap Desai fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK; 1296b64845a7SSreekanth Reddy if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) { 1297b64845a7SSreekanth Reddy mpi3mr_print_fault_info(mrioc); 1298f061178eSKashyap Desai return true; 1299b64845a7SSreekanth Reddy } 1300f061178eSKashyap Desai return false; 1301f061178eSKashyap Desai } 1302f061178eSKashyap Desai 1303f061178eSKashyap Desai /** 1304824a1566SKashyap Desai * mpi3mr_set_diagsave - Set diag save bit for snapdump 1305824a1566SKashyap Desai * @mrioc: Adapter reference 1306824a1566SKashyap Desai * 1307824a1566SKashyap Desai * Set diag save bit in IOC configuration register to enable 1308824a1566SKashyap Desai * snapdump. 1309824a1566SKashyap Desai * 1310824a1566SKashyap Desai * Return: Nothing. 1311824a1566SKashyap Desai */ 1312824a1566SKashyap Desai static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc) 1313824a1566SKashyap Desai { 1314824a1566SKashyap Desai u32 ioc_config; 1315824a1566SKashyap Desai 1316824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1317824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE; 1318824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 1319824a1566SKashyap Desai } 1320824a1566SKashyap Desai 1321824a1566SKashyap Desai /** 1322824a1566SKashyap Desai * mpi3mr_issue_reset - Issue reset to the controller 1323824a1566SKashyap Desai * @mrioc: Adapter reference 1324824a1566SKashyap Desai * @reset_type: Reset type 1325824a1566SKashyap Desai * @reset_reason: Reset reason code 1326824a1566SKashyap Desai * 1327f061178eSKashyap Desai * Unlock the host diagnostic registers and write the specific 1328f061178eSKashyap Desai * reset type to that, wait for reset acknowledgment from the 1329f061178eSKashyap Desai * controller, if the reset is not successful retry for the 1330f061178eSKashyap Desai * predefined number of times. 1331824a1566SKashyap Desai * 1332824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 1333824a1566SKashyap Desai */ 1334824a1566SKashyap Desai static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, 1335824a1566SKashyap Desai u32 reset_reason) 1336824a1566SKashyap Desai { 1337f061178eSKashyap Desai int retval = -1; 1338b64845a7SSreekanth Reddy u8 unlock_retry_count = 0; 1339b64845a7SSreekanth Reddy u32 host_diagnostic, ioc_status, ioc_config; 1340b64845a7SSreekanth Reddy u32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10; 1341f061178eSKashyap Desai 1342f061178eSKashyap Desai if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) && 1343f061178eSKashyap Desai (reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT)) 1344b64845a7SSreekanth Reddy return retval; 1345f061178eSKashyap Desai if (mrioc->unrecoverable) 1346b64845a7SSreekanth Reddy return retval; 1347b64845a7SSreekanth Reddy if (reset_reason == MPI3MR_RESET_FROM_FIRMWARE) { 1348b64845a7SSreekanth Reddy retval = 0; 1349b64845a7SSreekanth Reddy return retval; 1350b64845a7SSreekanth Reddy } 1351b64845a7SSreekanth Reddy 1352b64845a7SSreekanth Reddy ioc_info(mrioc, "%s reset due to %s(0x%x)\n", 1353b64845a7SSreekanth Reddy mpi3mr_reset_type_name(reset_type), 1354b64845a7SSreekanth Reddy mpi3mr_reset_rc_name(reset_reason), reset_reason); 1355b64845a7SSreekanth Reddy 1356f061178eSKashyap Desai mpi3mr_clear_reset_history(mrioc); 1357f061178eSKashyap Desai do { 1358f061178eSKashyap Desai ioc_info(mrioc, 1359f061178eSKashyap Desai "Write magic sequence to unlock host diag register (retry=%d)\n", 1360f061178eSKashyap Desai ++unlock_retry_count); 1361f061178eSKashyap Desai if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) { 1362b64845a7SSreekanth Reddy ioc_err(mrioc, 1363b64845a7SSreekanth Reddy "%s reset failed due to unlock failure, host_diagnostic(0x%08x)\n", 1364b64845a7SSreekanth Reddy mpi3mr_reset_type_name(reset_type), 1365b64845a7SSreekanth Reddy host_diagnostic); 1366f061178eSKashyap Desai mrioc->unrecoverable = 1; 1367b64845a7SSreekanth Reddy return retval; 1368f061178eSKashyap Desai } 1369f061178eSKashyap Desai 1370f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH, 1371f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1372f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST, 1373f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1374f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND, 1375f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1376f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD, 1377f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1378f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH, 1379f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1380f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH, 1381f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1382f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH, 1383f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1384f061178eSKashyap Desai usleep_range(1000, 1100); 1385f061178eSKashyap Desai host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); 1386f061178eSKashyap Desai ioc_info(mrioc, 1387f061178eSKashyap Desai "wrote magic sequence: retry_count(%d), host_diagnostic(0x%08x)\n", 1388f061178eSKashyap Desai unlock_retry_count, host_diagnostic); 1389f061178eSKashyap Desai } while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE)); 1390f061178eSKashyap Desai 1391f061178eSKashyap Desai writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); 1392f061178eSKashyap Desai writel(host_diagnostic | reset_type, 1393f061178eSKashyap Desai &mrioc->sysif_regs->host_diagnostic); 1394b64845a7SSreekanth Reddy switch (reset_type) { 1395b64845a7SSreekanth Reddy case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET: 1396f061178eSKashyap Desai do { 1397f061178eSKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1398f061178eSKashyap Desai ioc_config = 1399f061178eSKashyap Desai readl(&mrioc->sysif_regs->ioc_configuration); 1400b64845a7SSreekanth Reddy if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) 1401b64845a7SSreekanth Reddy && mpi3mr_soft_reset_success(ioc_status, ioc_config) 1402b64845a7SSreekanth Reddy ) { 1403b64845a7SSreekanth Reddy mpi3mr_clear_reset_history(mrioc); 1404f061178eSKashyap Desai retval = 0; 1405f061178eSKashyap Desai break; 1406f061178eSKashyap Desai } 1407f061178eSKashyap Desai msleep(100); 1408f061178eSKashyap Desai } while (--timeout); 1409b64845a7SSreekanth Reddy mpi3mr_print_fault_info(mrioc); 1410b64845a7SSreekanth Reddy break; 1411b64845a7SSreekanth Reddy case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT: 1412f061178eSKashyap Desai do { 1413f061178eSKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1414f061178eSKashyap Desai if (mpi3mr_diagfault_success(mrioc, ioc_status)) { 1415f061178eSKashyap Desai retval = 0; 1416f061178eSKashyap Desai break; 1417f061178eSKashyap Desai } 1418f061178eSKashyap Desai msleep(100); 1419f061178eSKashyap Desai } while (--timeout); 1420b64845a7SSreekanth Reddy break; 1421b64845a7SSreekanth Reddy default: 1422b64845a7SSreekanth Reddy break; 1423b64845a7SSreekanth Reddy } 1424b64845a7SSreekanth Reddy 1425f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND, 1426f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1427f061178eSKashyap Desai 1428f061178eSKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1429b64845a7SSreekanth Reddy ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1430f061178eSKashyap Desai ioc_info(mrioc, 1431b64845a7SSreekanth Reddy "ioc_status/ioc_onfig after %s reset is (0x%x)/(0x%x)\n", 1432f061178eSKashyap Desai (!retval)?"successful":"failed", ioc_status, 1433f061178eSKashyap Desai ioc_config); 1434b64845a7SSreekanth Reddy if (retval) 1435b64845a7SSreekanth Reddy mrioc->unrecoverable = 1; 1436f061178eSKashyap Desai return retval; 1437824a1566SKashyap Desai } 1438824a1566SKashyap Desai 1439824a1566SKashyap Desai /** 1440824a1566SKashyap Desai * mpi3mr_admin_request_post - Post request to admin queue 1441824a1566SKashyap Desai * @mrioc: Adapter reference 1442824a1566SKashyap Desai * @admin_req: MPI3 request 1443824a1566SKashyap Desai * @admin_req_sz: Request size 1444824a1566SKashyap Desai * @ignore_reset: Ignore reset in process 1445824a1566SKashyap Desai * 1446824a1566SKashyap Desai * Post the MPI3 request into admin request queue and 1447824a1566SKashyap Desai * inform the controller, if the queue is full return 1448824a1566SKashyap Desai * appropriate error. 1449824a1566SKashyap Desai * 1450824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 1451824a1566SKashyap Desai */ 1452824a1566SKashyap Desai int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req, 1453824a1566SKashyap Desai u16 admin_req_sz, u8 ignore_reset) 1454824a1566SKashyap Desai { 1455824a1566SKashyap Desai u16 areq_pi = 0, areq_ci = 0, max_entries = 0; 1456824a1566SKashyap Desai int retval = 0; 1457824a1566SKashyap Desai unsigned long flags; 1458824a1566SKashyap Desai u8 *areq_entry; 1459824a1566SKashyap Desai 1460824a1566SKashyap Desai if (mrioc->unrecoverable) { 1461824a1566SKashyap Desai ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__); 1462824a1566SKashyap Desai return -EFAULT; 1463824a1566SKashyap Desai } 1464824a1566SKashyap Desai 1465824a1566SKashyap Desai spin_lock_irqsave(&mrioc->admin_req_lock, flags); 1466824a1566SKashyap Desai areq_pi = mrioc->admin_req_pi; 1467824a1566SKashyap Desai areq_ci = mrioc->admin_req_ci; 1468824a1566SKashyap Desai max_entries = mrioc->num_admin_req; 1469824a1566SKashyap Desai if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) && 1470824a1566SKashyap Desai (areq_pi == (max_entries - 1)))) { 1471824a1566SKashyap Desai ioc_err(mrioc, "AdminReqQ full condition detected\n"); 1472824a1566SKashyap Desai retval = -EAGAIN; 1473824a1566SKashyap Desai goto out; 1474824a1566SKashyap Desai } 1475824a1566SKashyap Desai if (!ignore_reset && mrioc->reset_in_progress) { 1476824a1566SKashyap Desai ioc_err(mrioc, "AdminReqQ submit reset in progress\n"); 1477824a1566SKashyap Desai retval = -EAGAIN; 1478824a1566SKashyap Desai goto out; 1479824a1566SKashyap Desai } 1480824a1566SKashyap Desai areq_entry = (u8 *)mrioc->admin_req_base + 1481824a1566SKashyap Desai (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ); 1482824a1566SKashyap Desai memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ); 1483824a1566SKashyap Desai memcpy(areq_entry, (u8 *)admin_req, admin_req_sz); 1484824a1566SKashyap Desai 1485824a1566SKashyap Desai if (++areq_pi == max_entries) 1486824a1566SKashyap Desai areq_pi = 0; 1487824a1566SKashyap Desai mrioc->admin_req_pi = areq_pi; 1488824a1566SKashyap Desai 1489824a1566SKashyap Desai writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi); 1490824a1566SKashyap Desai 1491824a1566SKashyap Desai out: 1492824a1566SKashyap Desai spin_unlock_irqrestore(&mrioc->admin_req_lock, flags); 1493824a1566SKashyap Desai 1494824a1566SKashyap Desai return retval; 1495824a1566SKashyap Desai } 1496824a1566SKashyap Desai 1497824a1566SKashyap Desai /** 1498c9566231SKashyap Desai * mpi3mr_free_op_req_q_segments - free request memory segments 1499c9566231SKashyap Desai * @mrioc: Adapter instance reference 1500c9566231SKashyap Desai * @q_idx: operational request queue index 1501c9566231SKashyap Desai * 1502c9566231SKashyap Desai * Free memory segments allocated for operational request queue 1503c9566231SKashyap Desai * 1504c9566231SKashyap Desai * Return: Nothing. 1505c9566231SKashyap Desai */ 1506c9566231SKashyap Desai static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) 1507c9566231SKashyap Desai { 1508c9566231SKashyap Desai u16 j; 1509c9566231SKashyap Desai int size; 1510c9566231SKashyap Desai struct segments *segments; 1511c9566231SKashyap Desai 1512c9566231SKashyap Desai segments = mrioc->req_qinfo[q_idx].q_segments; 1513c9566231SKashyap Desai if (!segments) 1514c9566231SKashyap Desai return; 1515c9566231SKashyap Desai 1516c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1517c9566231SKashyap Desai size = MPI3MR_OP_REQ_Q_SEG_SIZE; 1518c9566231SKashyap Desai if (mrioc->req_qinfo[q_idx].q_segment_list) { 1519c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 1520c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, 1521c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segment_list, 1522c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segment_list_dma); 1523c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL; 1524c9566231SKashyap Desai } 1525c9566231SKashyap Desai } else 1526c9566231SKashyap Desai size = mrioc->req_qinfo[q_idx].num_requests * 1527c9566231SKashyap Desai mrioc->facts.op_req_sz; 1528c9566231SKashyap Desai 1529c9566231SKashyap Desai for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) { 1530c9566231SKashyap Desai if (!segments[j].segment) 1531c9566231SKashyap Desai continue; 1532c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 1533c9566231SKashyap Desai size, segments[j].segment, segments[j].segment_dma); 1534c9566231SKashyap Desai segments[j].segment = NULL; 1535c9566231SKashyap Desai } 1536c9566231SKashyap Desai kfree(mrioc->req_qinfo[q_idx].q_segments); 1537c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segments = NULL; 1538c9566231SKashyap Desai mrioc->req_qinfo[q_idx].qid = 0; 1539c9566231SKashyap Desai } 1540c9566231SKashyap Desai 1541c9566231SKashyap Desai /** 1542c9566231SKashyap Desai * mpi3mr_free_op_reply_q_segments - free reply memory segments 1543c9566231SKashyap Desai * @mrioc: Adapter instance reference 1544c9566231SKashyap Desai * @q_idx: operational reply queue index 1545c9566231SKashyap Desai * 1546c9566231SKashyap Desai * Free memory segments allocated for operational reply queue 1547c9566231SKashyap Desai * 1548c9566231SKashyap Desai * Return: Nothing. 1549c9566231SKashyap Desai */ 1550c9566231SKashyap Desai static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) 1551c9566231SKashyap Desai { 1552c9566231SKashyap Desai u16 j; 1553c9566231SKashyap Desai int size; 1554c9566231SKashyap Desai struct segments *segments; 1555c9566231SKashyap Desai 1556c9566231SKashyap Desai segments = mrioc->op_reply_qinfo[q_idx].q_segments; 1557c9566231SKashyap Desai if (!segments) 1558c9566231SKashyap Desai return; 1559c9566231SKashyap Desai 1560c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1561c9566231SKashyap Desai size = MPI3MR_OP_REP_Q_SEG_SIZE; 1562c9566231SKashyap Desai if (mrioc->op_reply_qinfo[q_idx].q_segment_list) { 1563c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 1564c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, 1565c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list, 1566c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list_dma); 1567c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL; 1568c9566231SKashyap Desai } 1569c9566231SKashyap Desai } else 1570c9566231SKashyap Desai size = mrioc->op_reply_qinfo[q_idx].segment_qd * 1571c9566231SKashyap Desai mrioc->op_reply_desc_sz; 1572c9566231SKashyap Desai 1573c9566231SKashyap Desai for (j = 0; j < mrioc->op_reply_qinfo[q_idx].num_segments; j++) { 1574c9566231SKashyap Desai if (!segments[j].segment) 1575c9566231SKashyap Desai continue; 1576c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 1577c9566231SKashyap Desai size, segments[j].segment, segments[j].segment_dma); 1578c9566231SKashyap Desai segments[j].segment = NULL; 1579c9566231SKashyap Desai } 1580c9566231SKashyap Desai 1581c9566231SKashyap Desai kfree(mrioc->op_reply_qinfo[q_idx].q_segments); 1582c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segments = NULL; 1583c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].qid = 0; 1584c9566231SKashyap Desai } 1585c9566231SKashyap Desai 1586c9566231SKashyap Desai /** 1587c9566231SKashyap Desai * mpi3mr_delete_op_reply_q - delete operational reply queue 1588c9566231SKashyap Desai * @mrioc: Adapter instance reference 1589c9566231SKashyap Desai * @qidx: operational reply queue index 1590c9566231SKashyap Desai * 1591c9566231SKashyap Desai * Delete operatinal reply queue by issuing MPI request 1592c9566231SKashyap Desai * through admin queue. 1593c9566231SKashyap Desai * 1594c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1595c9566231SKashyap Desai */ 1596c9566231SKashyap Desai static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) 1597c9566231SKashyap Desai { 1598c9566231SKashyap Desai struct mpi3_delete_reply_queue_request delq_req; 1599*afd3a579SSreekanth Reddy struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 1600c9566231SKashyap Desai int retval = 0; 1601c9566231SKashyap Desai u16 reply_qid = 0, midx; 1602c9566231SKashyap Desai 1603*afd3a579SSreekanth Reddy reply_qid = op_reply_q->qid; 1604c9566231SKashyap Desai 1605c9566231SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset); 1606c9566231SKashyap Desai 1607c9566231SKashyap Desai if (!reply_qid) { 1608c9566231SKashyap Desai retval = -1; 1609c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: called with invalid ReqQID\n"); 1610c9566231SKashyap Desai goto out; 1611c9566231SKashyap Desai } 1612c9566231SKashyap Desai 1613*afd3a579SSreekanth Reddy (op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) ? mrioc->default_qcount-- : 1614*afd3a579SSreekanth Reddy mrioc->active_poll_qcount--; 1615*afd3a579SSreekanth Reddy 1616c9566231SKashyap Desai memset(&delq_req, 0, sizeof(delq_req)); 1617c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1618c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1619c9566231SKashyap Desai retval = -1; 1620c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: Init command is in use\n"); 1621c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1622c9566231SKashyap Desai goto out; 1623c9566231SKashyap Desai } 1624c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1625c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1626c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 1627c9566231SKashyap Desai delq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1628c9566231SKashyap Desai delq_req.function = MPI3_FUNCTION_DELETE_REPLY_QUEUE; 1629c9566231SKashyap Desai delq_req.queue_id = cpu_to_le16(reply_qid); 1630c9566231SKashyap Desai 1631c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 1632c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &delq_req, sizeof(delq_req), 1633c9566231SKashyap Desai 1); 1634c9566231SKashyap Desai if (retval) { 1635c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: Admin Post failed\n"); 1636c9566231SKashyap Desai goto out_unlock; 1637c9566231SKashyap Desai } 1638c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1639c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1640c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1641a6856cc4SSreekanth Reddy ioc_err(mrioc, "delete reply queue timed out\n"); 1642a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 1643c9566231SKashyap Desai MPI3MR_RESET_FROM_DELREPQ_TIMEOUT); 1644c9566231SKashyap Desai retval = -1; 1645c9566231SKashyap Desai goto out_unlock; 1646c9566231SKashyap Desai } 1647c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1648c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1649c9566231SKashyap Desai ioc_err(mrioc, 1650c9566231SKashyap Desai "Issue DelRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1651c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1652c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 1653c9566231SKashyap Desai retval = -1; 1654c9566231SKashyap Desai goto out_unlock; 1655c9566231SKashyap Desai } 1656c9566231SKashyap Desai mrioc->intr_info[midx].op_reply_q = NULL; 1657c9566231SKashyap Desai 1658c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, qidx); 1659c9566231SKashyap Desai out_unlock: 1660c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 1661c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1662c9566231SKashyap Desai out: 1663c9566231SKashyap Desai 1664c9566231SKashyap Desai return retval; 1665c9566231SKashyap Desai } 1666c9566231SKashyap Desai 1667c9566231SKashyap Desai /** 1668c9566231SKashyap Desai * mpi3mr_alloc_op_reply_q_segments -Alloc segmented reply pool 1669c9566231SKashyap Desai * @mrioc: Adapter instance reference 1670c9566231SKashyap Desai * @qidx: request queue index 1671c9566231SKashyap Desai * 1672c9566231SKashyap Desai * Allocate segmented memory pools for operational reply 1673c9566231SKashyap Desai * queue. 1674c9566231SKashyap Desai * 1675c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1676c9566231SKashyap Desai */ 1677c9566231SKashyap Desai static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) 1678c9566231SKashyap Desai { 1679c9566231SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 1680c9566231SKashyap Desai int i, size; 1681c9566231SKashyap Desai u64 *q_segment_list_entry = NULL; 1682c9566231SKashyap Desai struct segments *segments; 1683c9566231SKashyap Desai 1684c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1685c9566231SKashyap Desai op_reply_q->segment_qd = 1686c9566231SKashyap Desai MPI3MR_OP_REP_Q_SEG_SIZE / mrioc->op_reply_desc_sz; 1687c9566231SKashyap Desai 1688c9566231SKashyap Desai size = MPI3MR_OP_REP_Q_SEG_SIZE; 1689c9566231SKashyap Desai 1690c9566231SKashyap Desai op_reply_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev, 1691c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, &op_reply_q->q_segment_list_dma, 1692c9566231SKashyap Desai GFP_KERNEL); 1693c9566231SKashyap Desai if (!op_reply_q->q_segment_list) 1694c9566231SKashyap Desai return -ENOMEM; 1695c9566231SKashyap Desai q_segment_list_entry = (u64 *)op_reply_q->q_segment_list; 1696c9566231SKashyap Desai } else { 1697c9566231SKashyap Desai op_reply_q->segment_qd = op_reply_q->num_replies; 1698c9566231SKashyap Desai size = op_reply_q->num_replies * mrioc->op_reply_desc_sz; 1699c9566231SKashyap Desai } 1700c9566231SKashyap Desai 1701c9566231SKashyap Desai op_reply_q->num_segments = DIV_ROUND_UP(op_reply_q->num_replies, 1702c9566231SKashyap Desai op_reply_q->segment_qd); 1703c9566231SKashyap Desai 1704c9566231SKashyap Desai op_reply_q->q_segments = kcalloc(op_reply_q->num_segments, 1705c9566231SKashyap Desai sizeof(struct segments), GFP_KERNEL); 1706c9566231SKashyap Desai if (!op_reply_q->q_segments) 1707c9566231SKashyap Desai return -ENOMEM; 1708c9566231SKashyap Desai 1709c9566231SKashyap Desai segments = op_reply_q->q_segments; 1710c9566231SKashyap Desai for (i = 0; i < op_reply_q->num_segments; i++) { 1711c9566231SKashyap Desai segments[i].segment = 1712c9566231SKashyap Desai dma_alloc_coherent(&mrioc->pdev->dev, 1713c9566231SKashyap Desai size, &segments[i].segment_dma, GFP_KERNEL); 1714c9566231SKashyap Desai if (!segments[i].segment) 1715c9566231SKashyap Desai return -ENOMEM; 1716c9566231SKashyap Desai if (mrioc->enable_segqueue) 1717c9566231SKashyap Desai q_segment_list_entry[i] = 1718c9566231SKashyap Desai (unsigned long)segments[i].segment_dma; 1719c9566231SKashyap Desai } 1720c9566231SKashyap Desai 1721c9566231SKashyap Desai return 0; 1722c9566231SKashyap Desai } 1723c9566231SKashyap Desai 1724c9566231SKashyap Desai /** 1725c9566231SKashyap Desai * mpi3mr_alloc_op_req_q_segments - Alloc segmented req pool. 1726c9566231SKashyap Desai * @mrioc: Adapter instance reference 1727c9566231SKashyap Desai * @qidx: request queue index 1728c9566231SKashyap Desai * 1729c9566231SKashyap Desai * Allocate segmented memory pools for operational request 1730c9566231SKashyap Desai * queue. 1731c9566231SKashyap Desai * 1732c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1733c9566231SKashyap Desai */ 1734c9566231SKashyap Desai static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) 1735c9566231SKashyap Desai { 1736c9566231SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx; 1737c9566231SKashyap Desai int i, size; 1738c9566231SKashyap Desai u64 *q_segment_list_entry = NULL; 1739c9566231SKashyap Desai struct segments *segments; 1740c9566231SKashyap Desai 1741c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1742c9566231SKashyap Desai op_req_q->segment_qd = 1743c9566231SKashyap Desai MPI3MR_OP_REQ_Q_SEG_SIZE / mrioc->facts.op_req_sz; 1744c9566231SKashyap Desai 1745c9566231SKashyap Desai size = MPI3MR_OP_REQ_Q_SEG_SIZE; 1746c9566231SKashyap Desai 1747c9566231SKashyap Desai op_req_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev, 1748c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, &op_req_q->q_segment_list_dma, 1749c9566231SKashyap Desai GFP_KERNEL); 1750c9566231SKashyap Desai if (!op_req_q->q_segment_list) 1751c9566231SKashyap Desai return -ENOMEM; 1752c9566231SKashyap Desai q_segment_list_entry = (u64 *)op_req_q->q_segment_list; 1753c9566231SKashyap Desai 1754c9566231SKashyap Desai } else { 1755c9566231SKashyap Desai op_req_q->segment_qd = op_req_q->num_requests; 1756c9566231SKashyap Desai size = op_req_q->num_requests * mrioc->facts.op_req_sz; 1757c9566231SKashyap Desai } 1758c9566231SKashyap Desai 1759c9566231SKashyap Desai op_req_q->num_segments = DIV_ROUND_UP(op_req_q->num_requests, 1760c9566231SKashyap Desai op_req_q->segment_qd); 1761c9566231SKashyap Desai 1762c9566231SKashyap Desai op_req_q->q_segments = kcalloc(op_req_q->num_segments, 1763c9566231SKashyap Desai sizeof(struct segments), GFP_KERNEL); 1764c9566231SKashyap Desai if (!op_req_q->q_segments) 1765c9566231SKashyap Desai return -ENOMEM; 1766c9566231SKashyap Desai 1767c9566231SKashyap Desai segments = op_req_q->q_segments; 1768c9566231SKashyap Desai for (i = 0; i < op_req_q->num_segments; i++) { 1769c9566231SKashyap Desai segments[i].segment = 1770c9566231SKashyap Desai dma_alloc_coherent(&mrioc->pdev->dev, 1771c9566231SKashyap Desai size, &segments[i].segment_dma, GFP_KERNEL); 1772c9566231SKashyap Desai if (!segments[i].segment) 1773c9566231SKashyap Desai return -ENOMEM; 1774c9566231SKashyap Desai if (mrioc->enable_segqueue) 1775c9566231SKashyap Desai q_segment_list_entry[i] = 1776c9566231SKashyap Desai (unsigned long)segments[i].segment_dma; 1777c9566231SKashyap Desai } 1778c9566231SKashyap Desai 1779c9566231SKashyap Desai return 0; 1780c9566231SKashyap Desai } 1781c9566231SKashyap Desai 1782c9566231SKashyap Desai /** 1783c9566231SKashyap Desai * mpi3mr_create_op_reply_q - create operational reply queue 1784c9566231SKashyap Desai * @mrioc: Adapter instance reference 1785c9566231SKashyap Desai * @qidx: operational reply queue index 1786c9566231SKashyap Desai * 1787c9566231SKashyap Desai * Create operatinal reply queue by issuing MPI request 1788c9566231SKashyap Desai * through admin queue. 1789c9566231SKashyap Desai * 1790c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1791c9566231SKashyap Desai */ 1792c9566231SKashyap Desai static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) 1793c9566231SKashyap Desai { 1794c9566231SKashyap Desai struct mpi3_create_reply_queue_request create_req; 1795c9566231SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 1796c9566231SKashyap Desai int retval = 0; 1797c9566231SKashyap Desai u16 reply_qid = 0, midx; 1798c9566231SKashyap Desai 1799c9566231SKashyap Desai reply_qid = op_reply_q->qid; 1800c9566231SKashyap Desai 1801c9566231SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset); 1802c9566231SKashyap Desai 1803c9566231SKashyap Desai if (reply_qid) { 1804c9566231SKashyap Desai retval = -1; 1805c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: called for duplicate qid %d\n", 1806c9566231SKashyap Desai reply_qid); 1807c9566231SKashyap Desai 1808c9566231SKashyap Desai return retval; 1809c9566231SKashyap Desai } 1810c9566231SKashyap Desai 1811c9566231SKashyap Desai reply_qid = qidx + 1; 1812c9566231SKashyap Desai op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; 1813c9566231SKashyap Desai op_reply_q->ci = 0; 1814c9566231SKashyap Desai op_reply_q->ephase = 1; 1815463429f8SKashyap Desai atomic_set(&op_reply_q->pend_ios, 0); 1816463429f8SKashyap Desai atomic_set(&op_reply_q->in_use, 0); 1817463429f8SKashyap Desai op_reply_q->enable_irq_poll = false; 1818c9566231SKashyap Desai 1819c9566231SKashyap Desai if (!op_reply_q->q_segments) { 1820c9566231SKashyap Desai retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx); 1821c9566231SKashyap Desai if (retval) { 1822c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, qidx); 1823c9566231SKashyap Desai goto out; 1824c9566231SKashyap Desai } 1825c9566231SKashyap Desai } 1826c9566231SKashyap Desai 1827c9566231SKashyap Desai memset(&create_req, 0, sizeof(create_req)); 1828c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1829c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1830c9566231SKashyap Desai retval = -1; 1831c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: Init command is in use\n"); 1832f9dc034dSYang Yingliang goto out_unlock; 1833c9566231SKashyap Desai } 1834c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1835c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1836c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 1837c9566231SKashyap Desai create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1838c9566231SKashyap Desai create_req.function = MPI3_FUNCTION_CREATE_REPLY_QUEUE; 1839c9566231SKashyap Desai create_req.queue_id = cpu_to_le16(reply_qid); 1840*afd3a579SSreekanth Reddy 1841*afd3a579SSreekanth Reddy if (midx < (mrioc->intr_info_count - mrioc->requested_poll_qcount)) 1842*afd3a579SSreekanth Reddy op_reply_q->qtype = MPI3MR_DEFAULT_QUEUE; 1843*afd3a579SSreekanth Reddy else 1844*afd3a579SSreekanth Reddy op_reply_q->qtype = MPI3MR_POLL_QUEUE; 1845*afd3a579SSreekanth Reddy 1846*afd3a579SSreekanth Reddy if (op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) { 1847*afd3a579SSreekanth Reddy create_req.flags = 1848*afd3a579SSreekanth Reddy MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE; 1849*afd3a579SSreekanth Reddy create_req.msix_index = 1850*afd3a579SSreekanth Reddy cpu_to_le16(mrioc->intr_info[midx].msix_index); 1851*afd3a579SSreekanth Reddy } else { 1852*afd3a579SSreekanth Reddy create_req.msix_index = cpu_to_le16(mrioc->intr_info_count - 1); 1853*afd3a579SSreekanth Reddy ioc_info(mrioc, "create reply queue(polled): for qid(%d), midx(%d)\n", 1854*afd3a579SSreekanth Reddy reply_qid, midx); 1855*afd3a579SSreekanth Reddy if (!mrioc->active_poll_qcount) 1856*afd3a579SSreekanth Reddy disable_irq_nosync(pci_irq_vector(mrioc->pdev, 1857*afd3a579SSreekanth Reddy mrioc->intr_info_count - 1)); 1858*afd3a579SSreekanth Reddy } 1859*afd3a579SSreekanth Reddy 1860c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1861c9566231SKashyap Desai create_req.flags |= 1862c9566231SKashyap Desai MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED; 1863c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1864c9566231SKashyap Desai op_reply_q->q_segment_list_dma); 1865c9566231SKashyap Desai } else 1866c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1867c9566231SKashyap Desai op_reply_q->q_segments[0].segment_dma); 1868c9566231SKashyap Desai 1869c9566231SKashyap Desai create_req.size = cpu_to_le16(op_reply_q->num_replies); 1870c9566231SKashyap Desai 1871c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 1872c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &create_req, 1873c9566231SKashyap Desai sizeof(create_req), 1); 1874c9566231SKashyap Desai if (retval) { 1875c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: Admin Post failed\n"); 1876c9566231SKashyap Desai goto out_unlock; 1877c9566231SKashyap Desai } 1878c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1879c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1880c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1881a6856cc4SSreekanth Reddy ioc_err(mrioc, "create reply queue timed out\n"); 1882a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 1883c9566231SKashyap Desai MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT); 1884c9566231SKashyap Desai retval = -1; 1885c9566231SKashyap Desai goto out_unlock; 1886c9566231SKashyap Desai } 1887c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1888c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1889c9566231SKashyap Desai ioc_err(mrioc, 1890c9566231SKashyap Desai "CreateRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1891c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1892c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 1893c9566231SKashyap Desai retval = -1; 1894c9566231SKashyap Desai goto out_unlock; 1895c9566231SKashyap Desai } 1896c9566231SKashyap Desai op_reply_q->qid = reply_qid; 1897fe6db615SSreekanth Reddy if (midx < mrioc->intr_info_count) 1898c9566231SKashyap Desai mrioc->intr_info[midx].op_reply_q = op_reply_q; 1899c9566231SKashyap Desai 1900*afd3a579SSreekanth Reddy (op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) ? mrioc->default_qcount++ : 1901*afd3a579SSreekanth Reddy mrioc->active_poll_qcount++; 1902*afd3a579SSreekanth Reddy 1903c9566231SKashyap Desai out_unlock: 1904c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 1905c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1906c9566231SKashyap Desai out: 1907c9566231SKashyap Desai 1908c9566231SKashyap Desai return retval; 1909c9566231SKashyap Desai } 1910c9566231SKashyap Desai 1911c9566231SKashyap Desai /** 1912c9566231SKashyap Desai * mpi3mr_create_op_req_q - create operational request queue 1913c9566231SKashyap Desai * @mrioc: Adapter instance reference 1914c9566231SKashyap Desai * @idx: operational request queue index 1915c9566231SKashyap Desai * @reply_qid: Reply queue ID 1916c9566231SKashyap Desai * 1917c9566231SKashyap Desai * Create operatinal request queue by issuing MPI request 1918c9566231SKashyap Desai * through admin queue. 1919c9566231SKashyap Desai * 1920c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1921c9566231SKashyap Desai */ 1922c9566231SKashyap Desai static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx, 1923c9566231SKashyap Desai u16 reply_qid) 1924c9566231SKashyap Desai { 1925c9566231SKashyap Desai struct mpi3_create_request_queue_request create_req; 1926c9566231SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + idx; 1927c9566231SKashyap Desai int retval = 0; 1928c9566231SKashyap Desai u16 req_qid = 0; 1929c9566231SKashyap Desai 1930c9566231SKashyap Desai req_qid = op_req_q->qid; 1931c9566231SKashyap Desai 1932c9566231SKashyap Desai if (req_qid) { 1933c9566231SKashyap Desai retval = -1; 1934c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: called for duplicate qid %d\n", 1935c9566231SKashyap Desai req_qid); 1936c9566231SKashyap Desai 1937c9566231SKashyap Desai return retval; 1938c9566231SKashyap Desai } 1939c9566231SKashyap Desai req_qid = idx + 1; 1940c9566231SKashyap Desai 1941c9566231SKashyap Desai op_req_q->num_requests = MPI3MR_OP_REQ_Q_QD; 1942c9566231SKashyap Desai op_req_q->ci = 0; 1943c9566231SKashyap Desai op_req_q->pi = 0; 1944c9566231SKashyap Desai op_req_q->reply_qid = reply_qid; 1945c9566231SKashyap Desai spin_lock_init(&op_req_q->q_lock); 1946c9566231SKashyap Desai 1947c9566231SKashyap Desai if (!op_req_q->q_segments) { 1948c9566231SKashyap Desai retval = mpi3mr_alloc_op_req_q_segments(mrioc, idx); 1949c9566231SKashyap Desai if (retval) { 1950c9566231SKashyap Desai mpi3mr_free_op_req_q_segments(mrioc, idx); 1951c9566231SKashyap Desai goto out; 1952c9566231SKashyap Desai } 1953c9566231SKashyap Desai } 1954c9566231SKashyap Desai 1955c9566231SKashyap Desai memset(&create_req, 0, sizeof(create_req)); 1956c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1957c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1958c9566231SKashyap Desai retval = -1; 1959c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: Init command is in use\n"); 1960f9dc034dSYang Yingliang goto out_unlock; 1961c9566231SKashyap Desai } 1962c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1963c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1964c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 1965c9566231SKashyap Desai create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1966c9566231SKashyap Desai create_req.function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE; 1967c9566231SKashyap Desai create_req.queue_id = cpu_to_le16(req_qid); 1968c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1969c9566231SKashyap Desai create_req.flags = 1970c9566231SKashyap Desai MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED; 1971c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1972c9566231SKashyap Desai op_req_q->q_segment_list_dma); 1973c9566231SKashyap Desai } else 1974c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1975c9566231SKashyap Desai op_req_q->q_segments[0].segment_dma); 1976c9566231SKashyap Desai create_req.reply_queue_id = cpu_to_le16(reply_qid); 1977c9566231SKashyap Desai create_req.size = cpu_to_le16(op_req_q->num_requests); 1978c9566231SKashyap Desai 1979c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 1980c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &create_req, 1981c9566231SKashyap Desai sizeof(create_req), 1); 1982c9566231SKashyap Desai if (retval) { 1983c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: Admin Post failed\n"); 1984c9566231SKashyap Desai goto out_unlock; 1985c9566231SKashyap Desai } 1986c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1987c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1988c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1989a6856cc4SSreekanth Reddy ioc_err(mrioc, "create request queue timed out\n"); 1990a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 1991a6856cc4SSreekanth Reddy MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT); 1992c9566231SKashyap Desai retval = -1; 1993c9566231SKashyap Desai goto out_unlock; 1994c9566231SKashyap Desai } 1995c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1996c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1997c9566231SKashyap Desai ioc_err(mrioc, 1998c9566231SKashyap Desai "CreateReqQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1999c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 2000c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 2001c9566231SKashyap Desai retval = -1; 2002c9566231SKashyap Desai goto out_unlock; 2003c9566231SKashyap Desai } 2004c9566231SKashyap Desai op_req_q->qid = req_qid; 2005c9566231SKashyap Desai 2006c9566231SKashyap Desai out_unlock: 2007c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 2008c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2009c9566231SKashyap Desai out: 2010c9566231SKashyap Desai 2011c9566231SKashyap Desai return retval; 2012c9566231SKashyap Desai } 2013c9566231SKashyap Desai 2014c9566231SKashyap Desai /** 2015c9566231SKashyap Desai * mpi3mr_create_op_queues - create operational queue pairs 2016c9566231SKashyap Desai * @mrioc: Adapter instance reference 2017c9566231SKashyap Desai * 2018c9566231SKashyap Desai * Allocate memory for operational queue meta data and call 2019c9566231SKashyap Desai * create request and reply queue functions. 2020c9566231SKashyap Desai * 2021c9566231SKashyap Desai * Return: 0 on success, non-zero on failures. 2022c9566231SKashyap Desai */ 2023c9566231SKashyap Desai static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc) 2024c9566231SKashyap Desai { 2025c9566231SKashyap Desai int retval = 0; 2026c9566231SKashyap Desai u16 num_queues = 0, i = 0, msix_count_op_q = 1; 2027c9566231SKashyap Desai 2028c9566231SKashyap Desai num_queues = min_t(int, mrioc->facts.max_op_reply_q, 2029c9566231SKashyap Desai mrioc->facts.max_op_req_q); 2030c9566231SKashyap Desai 2031c9566231SKashyap Desai msix_count_op_q = 2032c9566231SKashyap Desai mrioc->intr_info_count - mrioc->op_reply_q_offset; 2033c9566231SKashyap Desai if (!mrioc->num_queues) 2034c9566231SKashyap Desai mrioc->num_queues = min_t(int, num_queues, msix_count_op_q); 2035c5758fc7SSreekanth Reddy /* 2036c5758fc7SSreekanth Reddy * During reset set the num_queues to the number of queues 2037c5758fc7SSreekanth Reddy * that was set before the reset. 2038c5758fc7SSreekanth Reddy */ 2039c5758fc7SSreekanth Reddy num_queues = mrioc->num_op_reply_q ? 2040c5758fc7SSreekanth Reddy mrioc->num_op_reply_q : mrioc->num_queues; 2041c5758fc7SSreekanth Reddy ioc_info(mrioc, "trying to create %d operational queue pairs\n", 2042c9566231SKashyap Desai num_queues); 2043c9566231SKashyap Desai 2044c9566231SKashyap Desai if (!mrioc->req_qinfo) { 2045c9566231SKashyap Desai mrioc->req_qinfo = kcalloc(num_queues, 2046c9566231SKashyap Desai sizeof(struct op_req_qinfo), GFP_KERNEL); 2047c9566231SKashyap Desai if (!mrioc->req_qinfo) { 2048c9566231SKashyap Desai retval = -1; 2049c9566231SKashyap Desai goto out_failed; 2050c9566231SKashyap Desai } 2051c9566231SKashyap Desai 2052c9566231SKashyap Desai mrioc->op_reply_qinfo = kzalloc(sizeof(struct op_reply_qinfo) * 2053c9566231SKashyap Desai num_queues, GFP_KERNEL); 2054c9566231SKashyap Desai if (!mrioc->op_reply_qinfo) { 2055c9566231SKashyap Desai retval = -1; 2056c9566231SKashyap Desai goto out_failed; 2057c9566231SKashyap Desai } 2058c9566231SKashyap Desai } 2059c9566231SKashyap Desai 2060c9566231SKashyap Desai if (mrioc->enable_segqueue) 2061c9566231SKashyap Desai ioc_info(mrioc, 2062c9566231SKashyap Desai "allocating operational queues through segmented queues\n"); 2063c9566231SKashyap Desai 2064c9566231SKashyap Desai for (i = 0; i < num_queues; i++) { 2065c9566231SKashyap Desai if (mpi3mr_create_op_reply_q(mrioc, i)) { 2066c9566231SKashyap Desai ioc_err(mrioc, "Cannot create OP RepQ %d\n", i); 2067c9566231SKashyap Desai break; 2068c9566231SKashyap Desai } 2069c9566231SKashyap Desai if (mpi3mr_create_op_req_q(mrioc, i, 2070c9566231SKashyap Desai mrioc->op_reply_qinfo[i].qid)) { 2071c9566231SKashyap Desai ioc_err(mrioc, "Cannot create OP ReqQ %d\n", i); 2072c9566231SKashyap Desai mpi3mr_delete_op_reply_q(mrioc, i); 2073c9566231SKashyap Desai break; 2074c9566231SKashyap Desai } 2075c9566231SKashyap Desai } 2076c9566231SKashyap Desai 2077c9566231SKashyap Desai if (i == 0) { 2078c9566231SKashyap Desai /* Not even one queue is created successfully*/ 2079c9566231SKashyap Desai retval = -1; 2080c9566231SKashyap Desai goto out_failed; 2081c9566231SKashyap Desai } 2082c9566231SKashyap Desai mrioc->num_op_reply_q = mrioc->num_op_req_q = i; 2083*afd3a579SSreekanth Reddy ioc_info(mrioc, 2084*afd3a579SSreekanth Reddy "successfully created %d operational queue pairs(default/polled) queue = (%d/%d)\n", 2085*afd3a579SSreekanth Reddy mrioc->num_op_reply_q, mrioc->default_qcount, 2086*afd3a579SSreekanth Reddy mrioc->active_poll_qcount); 2087c9566231SKashyap Desai 2088c9566231SKashyap Desai return retval; 2089c9566231SKashyap Desai out_failed: 2090c9566231SKashyap Desai kfree(mrioc->req_qinfo); 2091c9566231SKashyap Desai mrioc->req_qinfo = NULL; 2092c9566231SKashyap Desai 2093c9566231SKashyap Desai kfree(mrioc->op_reply_qinfo); 2094c9566231SKashyap Desai mrioc->op_reply_qinfo = NULL; 2095c9566231SKashyap Desai 2096c9566231SKashyap Desai return retval; 2097c9566231SKashyap Desai } 2098c9566231SKashyap Desai 2099c9566231SKashyap Desai /** 2100023ab2a9SKashyap Desai * mpi3mr_op_request_post - Post request to operational queue 2101023ab2a9SKashyap Desai * @mrioc: Adapter reference 2102023ab2a9SKashyap Desai * @op_req_q: Operational request queue info 2103023ab2a9SKashyap Desai * @req: MPI3 request 2104023ab2a9SKashyap Desai * 2105023ab2a9SKashyap Desai * Post the MPI3 request into operational request queue and 2106023ab2a9SKashyap Desai * inform the controller, if the queue is full return 2107023ab2a9SKashyap Desai * appropriate error. 2108023ab2a9SKashyap Desai * 2109023ab2a9SKashyap Desai * Return: 0 on success, non-zero on failure. 2110023ab2a9SKashyap Desai */ 2111023ab2a9SKashyap Desai int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc, 2112023ab2a9SKashyap Desai struct op_req_qinfo *op_req_q, u8 *req) 2113023ab2a9SKashyap Desai { 2114023ab2a9SKashyap Desai u16 pi = 0, max_entries, reply_qidx = 0, midx; 2115023ab2a9SKashyap Desai int retval = 0; 2116023ab2a9SKashyap Desai unsigned long flags; 2117023ab2a9SKashyap Desai u8 *req_entry; 2118023ab2a9SKashyap Desai void *segment_base_addr; 2119023ab2a9SKashyap Desai u16 req_sz = mrioc->facts.op_req_sz; 2120023ab2a9SKashyap Desai struct segments *segments = op_req_q->q_segments; 2121023ab2a9SKashyap Desai 2122023ab2a9SKashyap Desai reply_qidx = op_req_q->reply_qid - 1; 2123023ab2a9SKashyap Desai 2124023ab2a9SKashyap Desai if (mrioc->unrecoverable) 2125023ab2a9SKashyap Desai return -EFAULT; 2126023ab2a9SKashyap Desai 2127023ab2a9SKashyap Desai spin_lock_irqsave(&op_req_q->q_lock, flags); 2128023ab2a9SKashyap Desai pi = op_req_q->pi; 2129023ab2a9SKashyap Desai max_entries = op_req_q->num_requests; 2130023ab2a9SKashyap Desai 2131023ab2a9SKashyap Desai if (mpi3mr_check_req_qfull(op_req_q)) { 2132023ab2a9SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX( 2133023ab2a9SKashyap Desai reply_qidx, mrioc->op_reply_q_offset); 2134*afd3a579SSreekanth Reddy mpi3mr_process_op_reply_q(mrioc, mrioc->intr_info[midx].op_reply_q); 2135023ab2a9SKashyap Desai 2136023ab2a9SKashyap Desai if (mpi3mr_check_req_qfull(op_req_q)) { 2137023ab2a9SKashyap Desai retval = -EAGAIN; 2138023ab2a9SKashyap Desai goto out; 2139023ab2a9SKashyap Desai } 2140023ab2a9SKashyap Desai } 2141023ab2a9SKashyap Desai 2142023ab2a9SKashyap Desai if (mrioc->reset_in_progress) { 2143023ab2a9SKashyap Desai ioc_err(mrioc, "OpReqQ submit reset in progress\n"); 2144023ab2a9SKashyap Desai retval = -EAGAIN; 2145023ab2a9SKashyap Desai goto out; 2146023ab2a9SKashyap Desai } 2147023ab2a9SKashyap Desai 2148023ab2a9SKashyap Desai segment_base_addr = segments[pi / op_req_q->segment_qd].segment; 2149023ab2a9SKashyap Desai req_entry = (u8 *)segment_base_addr + 2150023ab2a9SKashyap Desai ((pi % op_req_q->segment_qd) * req_sz); 2151023ab2a9SKashyap Desai 2152023ab2a9SKashyap Desai memset(req_entry, 0, req_sz); 2153023ab2a9SKashyap Desai memcpy(req_entry, req, MPI3MR_ADMIN_REQ_FRAME_SZ); 2154023ab2a9SKashyap Desai 2155023ab2a9SKashyap Desai if (++pi == max_entries) 2156023ab2a9SKashyap Desai pi = 0; 2157023ab2a9SKashyap Desai op_req_q->pi = pi; 2158023ab2a9SKashyap Desai 2159463429f8SKashyap Desai if (atomic_inc_return(&mrioc->op_reply_qinfo[reply_qidx].pend_ios) 2160463429f8SKashyap Desai > MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT) 2161463429f8SKashyap Desai mrioc->op_reply_qinfo[reply_qidx].enable_irq_poll = true; 2162463429f8SKashyap Desai 2163023ab2a9SKashyap Desai writel(op_req_q->pi, 2164023ab2a9SKashyap Desai &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].producer_index); 2165023ab2a9SKashyap Desai 2166023ab2a9SKashyap Desai out: 2167023ab2a9SKashyap Desai spin_unlock_irqrestore(&op_req_q->q_lock, flags); 2168023ab2a9SKashyap Desai return retval; 2169023ab2a9SKashyap Desai } 2170023ab2a9SKashyap Desai 2171023ab2a9SKashyap Desai /** 2172a6856cc4SSreekanth Reddy * mpi3mr_check_rh_fault_ioc - check reset history and fault 2173a6856cc4SSreekanth Reddy * controller 2174a6856cc4SSreekanth Reddy * @mrioc: Adapter instance reference 2175a6856cc4SSreekanth Reddy * @reason_code, reason code for the fault. 2176a6856cc4SSreekanth Reddy * 2177a6856cc4SSreekanth Reddy * This routine will save snapdump and fault the controller with 2178a6856cc4SSreekanth Reddy * the given reason code if it is not already in the fault or 2179a6856cc4SSreekanth Reddy * not asynchronosuly reset. This will be used to handle 2180a6856cc4SSreekanth Reddy * initilaization time faults/resets/timeout as in those cases 2181a6856cc4SSreekanth Reddy * immediate soft reset invocation is not required. 2182a6856cc4SSreekanth Reddy * 2183a6856cc4SSreekanth Reddy * Return: None. 2184a6856cc4SSreekanth Reddy */ 2185a6856cc4SSreekanth Reddy void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code) 2186a6856cc4SSreekanth Reddy { 2187a6856cc4SSreekanth Reddy u32 ioc_status, host_diagnostic, timeout; 2188a6856cc4SSreekanth Reddy 2189a6856cc4SSreekanth Reddy ioc_status = readl(&mrioc->sysif_regs->ioc_status); 2190a6856cc4SSreekanth Reddy if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) || 2191a6856cc4SSreekanth Reddy (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) { 2192a6856cc4SSreekanth Reddy mpi3mr_print_fault_info(mrioc); 2193a6856cc4SSreekanth Reddy return; 2194a6856cc4SSreekanth Reddy } 2195a6856cc4SSreekanth Reddy mpi3mr_set_diagsave(mrioc); 2196a6856cc4SSreekanth Reddy mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 2197a6856cc4SSreekanth Reddy reason_code); 2198a6856cc4SSreekanth Reddy timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; 2199a6856cc4SSreekanth Reddy do { 2200a6856cc4SSreekanth Reddy host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); 2201a6856cc4SSreekanth Reddy if (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS)) 2202a6856cc4SSreekanth Reddy break; 2203a6856cc4SSreekanth Reddy msleep(100); 2204a6856cc4SSreekanth Reddy } while (--timeout); 2205a6856cc4SSreekanth Reddy } 2206a6856cc4SSreekanth Reddy 2207a6856cc4SSreekanth Reddy /** 220854dfcffbSKashyap Desai * mpi3mr_sync_timestamp - Issue time stamp sync request 220954dfcffbSKashyap Desai * @mrioc: Adapter reference 221054dfcffbSKashyap Desai * 221154dfcffbSKashyap Desai * Issue IO unit control MPI request to synchornize firmware 221254dfcffbSKashyap Desai * timestamp with host time. 221354dfcffbSKashyap Desai * 221454dfcffbSKashyap Desai * Return: 0 on success, non-zero on failure. 221554dfcffbSKashyap Desai */ 221654dfcffbSKashyap Desai static int mpi3mr_sync_timestamp(struct mpi3mr_ioc *mrioc) 221754dfcffbSKashyap Desai { 221854dfcffbSKashyap Desai ktime_t current_time; 221954dfcffbSKashyap Desai struct mpi3_iounit_control_request iou_ctrl; 222054dfcffbSKashyap Desai int retval = 0; 222154dfcffbSKashyap Desai 222254dfcffbSKashyap Desai memset(&iou_ctrl, 0, sizeof(iou_ctrl)); 222354dfcffbSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 222454dfcffbSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 222554dfcffbSKashyap Desai retval = -1; 222654dfcffbSKashyap Desai ioc_err(mrioc, "Issue IOUCTL time_stamp: command is in use\n"); 222754dfcffbSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 222854dfcffbSKashyap Desai goto out; 222954dfcffbSKashyap Desai } 223054dfcffbSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 223154dfcffbSKashyap Desai mrioc->init_cmds.is_waiting = 1; 223254dfcffbSKashyap Desai mrioc->init_cmds.callback = NULL; 223354dfcffbSKashyap Desai iou_ctrl.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 223454dfcffbSKashyap Desai iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL; 223554dfcffbSKashyap Desai iou_ctrl.operation = MPI3_CTRL_OP_UPDATE_TIMESTAMP; 223654dfcffbSKashyap Desai current_time = ktime_get_real(); 223754dfcffbSKashyap Desai iou_ctrl.param64[0] = cpu_to_le64(ktime_to_ms(current_time)); 223854dfcffbSKashyap Desai 223954dfcffbSKashyap Desai init_completion(&mrioc->init_cmds.done); 224054dfcffbSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl, 224154dfcffbSKashyap Desai sizeof(iou_ctrl), 0); 224254dfcffbSKashyap Desai if (retval) { 224354dfcffbSKashyap Desai ioc_err(mrioc, "Issue IOUCTL time_stamp: Admin Post failed\n"); 224454dfcffbSKashyap Desai goto out_unlock; 224554dfcffbSKashyap Desai } 224654dfcffbSKashyap Desai 224754dfcffbSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 224854dfcffbSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 224954dfcffbSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 225054dfcffbSKashyap Desai ioc_err(mrioc, "Issue IOUCTL time_stamp: command timed out\n"); 225154dfcffbSKashyap Desai mrioc->init_cmds.is_waiting = 0; 2252fbaa9aa4SSreekanth Reddy if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET)) 225354dfcffbSKashyap Desai mpi3mr_soft_reset_handler(mrioc, 225454dfcffbSKashyap Desai MPI3MR_RESET_FROM_TSU_TIMEOUT, 1); 225554dfcffbSKashyap Desai retval = -1; 225654dfcffbSKashyap Desai goto out_unlock; 225754dfcffbSKashyap Desai } 225854dfcffbSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 225954dfcffbSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 226054dfcffbSKashyap Desai ioc_err(mrioc, 226154dfcffbSKashyap Desai "Issue IOUCTL time_stamp: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 226254dfcffbSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 226354dfcffbSKashyap Desai mrioc->init_cmds.ioc_loginfo); 226454dfcffbSKashyap Desai retval = -1; 226554dfcffbSKashyap Desai goto out_unlock; 226654dfcffbSKashyap Desai } 226754dfcffbSKashyap Desai 226854dfcffbSKashyap Desai out_unlock: 226954dfcffbSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 227054dfcffbSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 227154dfcffbSKashyap Desai 227254dfcffbSKashyap Desai out: 227354dfcffbSKashyap Desai return retval; 227454dfcffbSKashyap Desai } 227554dfcffbSKashyap Desai 227654dfcffbSKashyap Desai /** 22772ac794baSSreekanth Reddy * mpi3mr_print_pkg_ver - display controller fw package version 22782ac794baSSreekanth Reddy * @mrioc: Adapter reference 22792ac794baSSreekanth Reddy * 22802ac794baSSreekanth Reddy * Retrieve firmware package version from the component image 22812ac794baSSreekanth Reddy * header of the controller flash and display it. 22822ac794baSSreekanth Reddy * 22832ac794baSSreekanth Reddy * Return: 0 on success and non-zero on failure. 22842ac794baSSreekanth Reddy */ 22852ac794baSSreekanth Reddy static int mpi3mr_print_pkg_ver(struct mpi3mr_ioc *mrioc) 22862ac794baSSreekanth Reddy { 22872ac794baSSreekanth Reddy struct mpi3_ci_upload_request ci_upload; 22882ac794baSSreekanth Reddy int retval = -1; 22892ac794baSSreekanth Reddy void *data = NULL; 22902ac794baSSreekanth Reddy dma_addr_t data_dma; 22912ac794baSSreekanth Reddy struct mpi3_ci_manifest_mpi *manifest; 22922ac794baSSreekanth Reddy u32 data_len = sizeof(struct mpi3_ci_manifest_mpi); 22932ac794baSSreekanth Reddy u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 22942ac794baSSreekanth Reddy 22952ac794baSSreekanth Reddy data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, 22962ac794baSSreekanth Reddy GFP_KERNEL); 22972ac794baSSreekanth Reddy if (!data) 22982ac794baSSreekanth Reddy return -ENOMEM; 22992ac794baSSreekanth Reddy 23002ac794baSSreekanth Reddy memset(&ci_upload, 0, sizeof(ci_upload)); 23012ac794baSSreekanth Reddy mutex_lock(&mrioc->init_cmds.mutex); 23022ac794baSSreekanth Reddy if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 23032ac794baSSreekanth Reddy ioc_err(mrioc, "sending get package version failed due to command in use\n"); 23042ac794baSSreekanth Reddy mutex_unlock(&mrioc->init_cmds.mutex); 23052ac794baSSreekanth Reddy goto out; 23062ac794baSSreekanth Reddy } 23072ac794baSSreekanth Reddy mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 23082ac794baSSreekanth Reddy mrioc->init_cmds.is_waiting = 1; 23092ac794baSSreekanth Reddy mrioc->init_cmds.callback = NULL; 23102ac794baSSreekanth Reddy ci_upload.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 23112ac794baSSreekanth Reddy ci_upload.function = MPI3_FUNCTION_CI_UPLOAD; 23122ac794baSSreekanth Reddy ci_upload.msg_flags = MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY; 23132ac794baSSreekanth Reddy ci_upload.signature1 = cpu_to_le32(MPI3_IMAGE_HEADER_SIGNATURE1_MANIFEST); 23142ac794baSSreekanth Reddy ci_upload.image_offset = cpu_to_le32(MPI3_IMAGE_HEADER_SIZE); 23152ac794baSSreekanth Reddy ci_upload.segment_size = cpu_to_le32(data_len); 23162ac794baSSreekanth Reddy 23172ac794baSSreekanth Reddy mpi3mr_add_sg_single(&ci_upload.sgl, sgl_flags, data_len, 23182ac794baSSreekanth Reddy data_dma); 23192ac794baSSreekanth Reddy init_completion(&mrioc->init_cmds.done); 23202ac794baSSreekanth Reddy retval = mpi3mr_admin_request_post(mrioc, &ci_upload, 23212ac794baSSreekanth Reddy sizeof(ci_upload), 1); 23222ac794baSSreekanth Reddy if (retval) { 23232ac794baSSreekanth Reddy ioc_err(mrioc, "posting get package version failed\n"); 23242ac794baSSreekanth Reddy goto out_unlock; 23252ac794baSSreekanth Reddy } 23262ac794baSSreekanth Reddy wait_for_completion_timeout(&mrioc->init_cmds.done, 23272ac794baSSreekanth Reddy (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 23282ac794baSSreekanth Reddy if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 23292ac794baSSreekanth Reddy ioc_err(mrioc, "get package version timed out\n"); 2330a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 2331a6856cc4SSreekanth Reddy MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT); 23322ac794baSSreekanth Reddy retval = -1; 23332ac794baSSreekanth Reddy goto out_unlock; 23342ac794baSSreekanth Reddy } 23352ac794baSSreekanth Reddy if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 23362ac794baSSreekanth Reddy == MPI3_IOCSTATUS_SUCCESS) { 23372ac794baSSreekanth Reddy manifest = (struct mpi3_ci_manifest_mpi *) data; 23382ac794baSSreekanth Reddy if (manifest->manifest_type == MPI3_CI_MANIFEST_TYPE_MPI) { 23392ac794baSSreekanth Reddy ioc_info(mrioc, 23402ac794baSSreekanth Reddy "firmware package version(%d.%d.%d.%d.%05d-%05d)\n", 23412ac794baSSreekanth Reddy manifest->package_version.gen_major, 23422ac794baSSreekanth Reddy manifest->package_version.gen_minor, 23432ac794baSSreekanth Reddy manifest->package_version.phase_major, 23442ac794baSSreekanth Reddy manifest->package_version.phase_minor, 23452ac794baSSreekanth Reddy manifest->package_version.customer_id, 23462ac794baSSreekanth Reddy manifest->package_version.build_num); 23472ac794baSSreekanth Reddy } 23482ac794baSSreekanth Reddy } 23492ac794baSSreekanth Reddy retval = 0; 23502ac794baSSreekanth Reddy out_unlock: 23512ac794baSSreekanth Reddy mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 23522ac794baSSreekanth Reddy mutex_unlock(&mrioc->init_cmds.mutex); 23532ac794baSSreekanth Reddy 23542ac794baSSreekanth Reddy out: 23552ac794baSSreekanth Reddy if (data) 23562ac794baSSreekanth Reddy dma_free_coherent(&mrioc->pdev->dev, data_len, data, 23572ac794baSSreekanth Reddy data_dma); 23582ac794baSSreekanth Reddy return retval; 23592ac794baSSreekanth Reddy } 23602ac794baSSreekanth Reddy 23612ac794baSSreekanth Reddy /** 2362672ae26cSKashyap Desai * mpi3mr_watchdog_work - watchdog thread to monitor faults 2363672ae26cSKashyap Desai * @work: work struct 2364672ae26cSKashyap Desai * 2365672ae26cSKashyap Desai * Watch dog work periodically executed (1 second interval) to 2366672ae26cSKashyap Desai * monitor firmware fault and to issue periodic timer sync to 2367672ae26cSKashyap Desai * the firmware. 2368672ae26cSKashyap Desai * 2369672ae26cSKashyap Desai * Return: Nothing. 2370672ae26cSKashyap Desai */ 2371672ae26cSKashyap Desai static void mpi3mr_watchdog_work(struct work_struct *work) 2372672ae26cSKashyap Desai { 2373672ae26cSKashyap Desai struct mpi3mr_ioc *mrioc = 2374672ae26cSKashyap Desai container_of(work, struct mpi3mr_ioc, watchdog_work.work); 2375672ae26cSKashyap Desai unsigned long flags; 2376672ae26cSKashyap Desai enum mpi3mr_iocstate ioc_state; 237778b76a07SSreekanth Reddy u32 fault, host_diagnostic, ioc_status; 237878b76a07SSreekanth Reddy u32 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH; 2379672ae26cSKashyap Desai 2380b64845a7SSreekanth Reddy if (mrioc->reset_in_progress || mrioc->unrecoverable) 2381b64845a7SSreekanth Reddy return; 2382b64845a7SSreekanth Reddy 238354dfcffbSKashyap Desai if (mrioc->ts_update_counter++ >= MPI3MR_TSUPDATE_INTERVAL) { 238454dfcffbSKashyap Desai mrioc->ts_update_counter = 0; 238554dfcffbSKashyap Desai mpi3mr_sync_timestamp(mrioc); 238654dfcffbSKashyap Desai } 238754dfcffbSKashyap Desai 238878b76a07SSreekanth Reddy if ((mrioc->prepare_for_reset) && 238978b76a07SSreekanth Reddy ((mrioc->prepare_for_reset_timeout_counter++) >= 239078b76a07SSreekanth Reddy MPI3MR_PREPARE_FOR_RESET_TIMEOUT)) { 239178b76a07SSreekanth Reddy mpi3mr_soft_reset_handler(mrioc, 239278b76a07SSreekanth Reddy MPI3MR_RESET_FROM_CIACTVRST_TIMER, 1); 239378b76a07SSreekanth Reddy return; 239478b76a07SSreekanth Reddy } 239578b76a07SSreekanth Reddy 239678b76a07SSreekanth Reddy ioc_status = readl(&mrioc->sysif_regs->ioc_status); 239778b76a07SSreekanth Reddy if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) { 239878b76a07SSreekanth Reddy mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_FIRMWARE, 0); 239978b76a07SSreekanth Reddy return; 240078b76a07SSreekanth Reddy } 240178b76a07SSreekanth Reddy 2402672ae26cSKashyap Desai /*Check for fault state every one second and issue Soft reset*/ 2403672ae26cSKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 240478b76a07SSreekanth Reddy if (ioc_state != MRIOC_STATE_FAULT) 240578b76a07SSreekanth Reddy goto schedule_work; 240678b76a07SSreekanth Reddy 240778b76a07SSreekanth Reddy fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK; 2408672ae26cSKashyap Desai host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); 2409672ae26cSKashyap Desai if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) { 2410672ae26cSKashyap Desai if (!mrioc->diagsave_timeout) { 2411672ae26cSKashyap Desai mpi3mr_print_fault_info(mrioc); 241278b76a07SSreekanth Reddy ioc_warn(mrioc, "diag save in progress\n"); 2413672ae26cSKashyap Desai } 241478b76a07SSreekanth Reddy if ((mrioc->diagsave_timeout++) <= MPI3_SYSIF_DIAG_SAVE_TIMEOUT) 2415672ae26cSKashyap Desai goto schedule_work; 241678b76a07SSreekanth Reddy } 241778b76a07SSreekanth Reddy 2418672ae26cSKashyap Desai mpi3mr_print_fault_info(mrioc); 2419672ae26cSKashyap Desai mrioc->diagsave_timeout = 0; 2420672ae26cSKashyap Desai 242178b76a07SSreekanth Reddy switch (fault) { 242278b76a07SSreekanth Reddy case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED: 2423672ae26cSKashyap Desai ioc_info(mrioc, 242478b76a07SSreekanth Reddy "controller requires system power cycle, marking controller as unrecoverable\n"); 2425672ae26cSKashyap Desai mrioc->unrecoverable = 1; 242678b76a07SSreekanth Reddy return; 242778b76a07SSreekanth Reddy case MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS: 242878b76a07SSreekanth Reddy return; 242978b76a07SSreekanth Reddy case MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET: 243078b76a07SSreekanth Reddy reset_reason = MPI3MR_RESET_FROM_CIACTIV_FAULT; 243178b76a07SSreekanth Reddy break; 243278b76a07SSreekanth Reddy default: 243378b76a07SSreekanth Reddy break; 2434672ae26cSKashyap Desai } 243578b76a07SSreekanth Reddy mpi3mr_soft_reset_handler(mrioc, reset_reason, 0); 243678b76a07SSreekanth Reddy return; 2437672ae26cSKashyap Desai 2438672ae26cSKashyap Desai schedule_work: 2439672ae26cSKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 2440672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 2441672ae26cSKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 2442672ae26cSKashyap Desai &mrioc->watchdog_work, 2443672ae26cSKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 2444672ae26cSKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 2445672ae26cSKashyap Desai return; 2446672ae26cSKashyap Desai } 2447672ae26cSKashyap Desai 2448672ae26cSKashyap Desai /** 2449672ae26cSKashyap Desai * mpi3mr_start_watchdog - Start watchdog 2450672ae26cSKashyap Desai * @mrioc: Adapter instance reference 2451672ae26cSKashyap Desai * 2452672ae26cSKashyap Desai * Create and start the watchdog thread to monitor controller 2453672ae26cSKashyap Desai * faults. 2454672ae26cSKashyap Desai * 2455672ae26cSKashyap Desai * Return: Nothing. 2456672ae26cSKashyap Desai */ 2457672ae26cSKashyap Desai void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc) 2458672ae26cSKashyap Desai { 2459672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 2460672ae26cSKashyap Desai return; 2461672ae26cSKashyap Desai 2462672ae26cSKashyap Desai INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work); 2463672ae26cSKashyap Desai snprintf(mrioc->watchdog_work_q_name, 2464672ae26cSKashyap Desai sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name, 2465672ae26cSKashyap Desai mrioc->id); 2466672ae26cSKashyap Desai mrioc->watchdog_work_q = 2467672ae26cSKashyap Desai create_singlethread_workqueue(mrioc->watchdog_work_q_name); 2468672ae26cSKashyap Desai if (!mrioc->watchdog_work_q) { 2469672ae26cSKashyap Desai ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__); 2470672ae26cSKashyap Desai return; 2471672ae26cSKashyap Desai } 2472672ae26cSKashyap Desai 2473672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 2474672ae26cSKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 2475672ae26cSKashyap Desai &mrioc->watchdog_work, 2476672ae26cSKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 2477672ae26cSKashyap Desai } 2478672ae26cSKashyap Desai 2479672ae26cSKashyap Desai /** 2480672ae26cSKashyap Desai * mpi3mr_stop_watchdog - Stop watchdog 2481672ae26cSKashyap Desai * @mrioc: Adapter instance reference 2482672ae26cSKashyap Desai * 2483672ae26cSKashyap Desai * Stop the watchdog thread created to monitor controller 2484672ae26cSKashyap Desai * faults. 2485672ae26cSKashyap Desai * 2486672ae26cSKashyap Desai * Return: Nothing. 2487672ae26cSKashyap Desai */ 2488672ae26cSKashyap Desai void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc) 2489672ae26cSKashyap Desai { 2490672ae26cSKashyap Desai unsigned long flags; 2491672ae26cSKashyap Desai struct workqueue_struct *wq; 2492672ae26cSKashyap Desai 2493672ae26cSKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 2494672ae26cSKashyap Desai wq = mrioc->watchdog_work_q; 2495672ae26cSKashyap Desai mrioc->watchdog_work_q = NULL; 2496672ae26cSKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 2497672ae26cSKashyap Desai if (wq) { 2498672ae26cSKashyap Desai if (!cancel_delayed_work_sync(&mrioc->watchdog_work)) 2499672ae26cSKashyap Desai flush_workqueue(wq); 2500672ae26cSKashyap Desai destroy_workqueue(wq); 2501672ae26cSKashyap Desai } 2502672ae26cSKashyap Desai } 2503672ae26cSKashyap Desai 2504672ae26cSKashyap Desai /** 2505824a1566SKashyap Desai * mpi3mr_setup_admin_qpair - Setup admin queue pair 2506824a1566SKashyap Desai * @mrioc: Adapter instance reference 2507824a1566SKashyap Desai * 2508824a1566SKashyap Desai * Allocate memory for admin queue pair if required and register 2509824a1566SKashyap Desai * the admin queue with the controller. 2510824a1566SKashyap Desai * 2511824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2512824a1566SKashyap Desai */ 2513824a1566SKashyap Desai static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc) 2514824a1566SKashyap Desai { 2515824a1566SKashyap Desai int retval = 0; 2516824a1566SKashyap Desai u32 num_admin_entries = 0; 2517824a1566SKashyap Desai 2518824a1566SKashyap Desai mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE; 2519824a1566SKashyap Desai mrioc->num_admin_req = mrioc->admin_req_q_sz / 2520824a1566SKashyap Desai MPI3MR_ADMIN_REQ_FRAME_SZ; 2521824a1566SKashyap Desai mrioc->admin_req_ci = mrioc->admin_req_pi = 0; 2522824a1566SKashyap Desai mrioc->admin_req_base = NULL; 2523824a1566SKashyap Desai 2524824a1566SKashyap Desai mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE; 2525824a1566SKashyap Desai mrioc->num_admin_replies = mrioc->admin_reply_q_sz / 2526824a1566SKashyap Desai MPI3MR_ADMIN_REPLY_FRAME_SZ; 2527824a1566SKashyap Desai mrioc->admin_reply_ci = 0; 2528824a1566SKashyap Desai mrioc->admin_reply_ephase = 1; 2529824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 2530824a1566SKashyap Desai 2531824a1566SKashyap Desai if (!mrioc->admin_req_base) { 2532824a1566SKashyap Desai mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev, 2533824a1566SKashyap Desai mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL); 2534824a1566SKashyap Desai 2535824a1566SKashyap Desai if (!mrioc->admin_req_base) { 2536824a1566SKashyap Desai retval = -1; 2537824a1566SKashyap Desai goto out_failed; 2538824a1566SKashyap Desai } 2539824a1566SKashyap Desai 2540824a1566SKashyap Desai mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev, 2541824a1566SKashyap Desai mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma, 2542824a1566SKashyap Desai GFP_KERNEL); 2543824a1566SKashyap Desai 2544824a1566SKashyap Desai if (!mrioc->admin_reply_base) { 2545824a1566SKashyap Desai retval = -1; 2546824a1566SKashyap Desai goto out_failed; 2547824a1566SKashyap Desai } 2548824a1566SKashyap Desai } 2549824a1566SKashyap Desai 2550824a1566SKashyap Desai num_admin_entries = (mrioc->num_admin_replies << 16) | 2551824a1566SKashyap Desai (mrioc->num_admin_req); 2552824a1566SKashyap Desai writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries); 2553824a1566SKashyap Desai mpi3mr_writeq(mrioc->admin_req_dma, 2554824a1566SKashyap Desai &mrioc->sysif_regs->admin_request_queue_address); 2555824a1566SKashyap Desai mpi3mr_writeq(mrioc->admin_reply_dma, 2556824a1566SKashyap Desai &mrioc->sysif_regs->admin_reply_queue_address); 2557824a1566SKashyap Desai writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi); 2558824a1566SKashyap Desai writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); 2559824a1566SKashyap Desai return retval; 2560824a1566SKashyap Desai 2561824a1566SKashyap Desai out_failed: 2562824a1566SKashyap Desai 2563824a1566SKashyap Desai if (mrioc->admin_reply_base) { 2564824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz, 2565824a1566SKashyap Desai mrioc->admin_reply_base, mrioc->admin_reply_dma); 2566824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 2567824a1566SKashyap Desai } 2568824a1566SKashyap Desai if (mrioc->admin_req_base) { 2569824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz, 2570824a1566SKashyap Desai mrioc->admin_req_base, mrioc->admin_req_dma); 2571824a1566SKashyap Desai mrioc->admin_req_base = NULL; 2572824a1566SKashyap Desai } 2573824a1566SKashyap Desai return retval; 2574824a1566SKashyap Desai } 2575824a1566SKashyap Desai 2576824a1566SKashyap Desai /** 2577824a1566SKashyap Desai * mpi3mr_issue_iocfacts - Send IOC Facts 2578824a1566SKashyap Desai * @mrioc: Adapter instance reference 2579824a1566SKashyap Desai * @facts_data: Cached IOC facts data 2580824a1566SKashyap Desai * 2581824a1566SKashyap Desai * Issue IOC Facts MPI request through admin queue and wait for 2582824a1566SKashyap Desai * the completion of it or time out. 2583824a1566SKashyap Desai * 2584824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2585824a1566SKashyap Desai */ 2586824a1566SKashyap Desai static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc, 2587824a1566SKashyap Desai struct mpi3_ioc_facts_data *facts_data) 2588824a1566SKashyap Desai { 2589824a1566SKashyap Desai struct mpi3_ioc_facts_request iocfacts_req; 2590824a1566SKashyap Desai void *data = NULL; 2591824a1566SKashyap Desai dma_addr_t data_dma; 2592824a1566SKashyap Desai u32 data_len = sizeof(*facts_data); 2593824a1566SKashyap Desai int retval = 0; 2594824a1566SKashyap Desai u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 2595824a1566SKashyap Desai 2596824a1566SKashyap Desai data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, 2597824a1566SKashyap Desai GFP_KERNEL); 2598824a1566SKashyap Desai 2599824a1566SKashyap Desai if (!data) { 2600824a1566SKashyap Desai retval = -1; 2601824a1566SKashyap Desai goto out; 2602824a1566SKashyap Desai } 2603824a1566SKashyap Desai 2604824a1566SKashyap Desai memset(&iocfacts_req, 0, sizeof(iocfacts_req)); 2605824a1566SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 2606824a1566SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 2607824a1566SKashyap Desai retval = -1; 2608824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n"); 2609824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2610824a1566SKashyap Desai goto out; 2611824a1566SKashyap Desai } 2612824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 2613824a1566SKashyap Desai mrioc->init_cmds.is_waiting = 1; 2614824a1566SKashyap Desai mrioc->init_cmds.callback = NULL; 2615824a1566SKashyap Desai iocfacts_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 2616824a1566SKashyap Desai iocfacts_req.function = MPI3_FUNCTION_IOC_FACTS; 2617824a1566SKashyap Desai 2618824a1566SKashyap Desai mpi3mr_add_sg_single(&iocfacts_req.sgl, sgl_flags, data_len, 2619824a1566SKashyap Desai data_dma); 2620824a1566SKashyap Desai 2621824a1566SKashyap Desai init_completion(&mrioc->init_cmds.done); 2622824a1566SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req, 2623824a1566SKashyap Desai sizeof(iocfacts_req), 1); 2624824a1566SKashyap Desai if (retval) { 2625824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n"); 2626824a1566SKashyap Desai goto out_unlock; 2627824a1566SKashyap Desai } 2628824a1566SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 2629824a1566SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 2630824a1566SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 2631a6856cc4SSreekanth Reddy ioc_err(mrioc, "ioc_facts timed out\n"); 2632a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 2633824a1566SKashyap Desai MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT); 2634824a1566SKashyap Desai retval = -1; 2635824a1566SKashyap Desai goto out_unlock; 2636824a1566SKashyap Desai } 2637824a1566SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 2638824a1566SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 2639824a1566SKashyap Desai ioc_err(mrioc, 2640824a1566SKashyap Desai "Issue IOCFacts: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 2641824a1566SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 2642824a1566SKashyap Desai mrioc->init_cmds.ioc_loginfo); 2643824a1566SKashyap Desai retval = -1; 2644824a1566SKashyap Desai goto out_unlock; 2645824a1566SKashyap Desai } 2646824a1566SKashyap Desai memcpy(facts_data, (u8 *)data, data_len); 2647c5758fc7SSreekanth Reddy mpi3mr_process_factsdata(mrioc, facts_data); 2648824a1566SKashyap Desai out_unlock: 2649824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 2650824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2651824a1566SKashyap Desai 2652824a1566SKashyap Desai out: 2653824a1566SKashyap Desai if (data) 2654824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma); 2655824a1566SKashyap Desai 2656824a1566SKashyap Desai return retval; 2657824a1566SKashyap Desai } 2658824a1566SKashyap Desai 2659824a1566SKashyap Desai /** 2660824a1566SKashyap Desai * mpi3mr_check_reset_dma_mask - Process IOC facts data 2661824a1566SKashyap Desai * @mrioc: Adapter instance reference 2662824a1566SKashyap Desai * 2663824a1566SKashyap Desai * Check whether the new DMA mask requested through IOCFacts by 2664824a1566SKashyap Desai * firmware needs to be set, if so set it . 2665824a1566SKashyap Desai * 2666824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 2667824a1566SKashyap Desai */ 2668824a1566SKashyap Desai static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc) 2669824a1566SKashyap Desai { 2670824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 2671824a1566SKashyap Desai int r; 2672824a1566SKashyap Desai u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask); 2673824a1566SKashyap Desai 2674824a1566SKashyap Desai if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask)) 2675824a1566SKashyap Desai return 0; 2676824a1566SKashyap Desai 2677824a1566SKashyap Desai ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n", 2678824a1566SKashyap Desai mrioc->dma_mask, facts_dma_mask); 2679824a1566SKashyap Desai 2680824a1566SKashyap Desai r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask); 2681824a1566SKashyap Desai if (r) { 2682824a1566SKashyap Desai ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n", 2683824a1566SKashyap Desai facts_dma_mask, r); 2684824a1566SKashyap Desai return r; 2685824a1566SKashyap Desai } 2686824a1566SKashyap Desai mrioc->dma_mask = facts_dma_mask; 2687824a1566SKashyap Desai return r; 2688824a1566SKashyap Desai } 2689824a1566SKashyap Desai 2690824a1566SKashyap Desai /** 2691824a1566SKashyap Desai * mpi3mr_process_factsdata - Process IOC facts data 2692824a1566SKashyap Desai * @mrioc: Adapter instance reference 2693824a1566SKashyap Desai * @facts_data: Cached IOC facts data 2694824a1566SKashyap Desai * 2695824a1566SKashyap Desai * Convert IOC facts data into cpu endianness and cache it in 2696824a1566SKashyap Desai * the driver . 2697824a1566SKashyap Desai * 2698824a1566SKashyap Desai * Return: Nothing. 2699824a1566SKashyap Desai */ 2700824a1566SKashyap Desai static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, 2701824a1566SKashyap Desai struct mpi3_ioc_facts_data *facts_data) 2702824a1566SKashyap Desai { 2703824a1566SKashyap Desai u32 ioc_config, req_sz, facts_flags; 2704824a1566SKashyap Desai 2705824a1566SKashyap Desai if ((le16_to_cpu(facts_data->ioc_facts_data_length)) != 2706824a1566SKashyap Desai (sizeof(*facts_data) / 4)) { 2707824a1566SKashyap Desai ioc_warn(mrioc, 2708824a1566SKashyap Desai "IOCFactsdata length mismatch driver_sz(%zu) firmware_sz(%d)\n", 2709824a1566SKashyap Desai sizeof(*facts_data), 2710824a1566SKashyap Desai le16_to_cpu(facts_data->ioc_facts_data_length) * 4); 2711824a1566SKashyap Desai } 2712824a1566SKashyap Desai 2713824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 2714824a1566SKashyap Desai req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >> 2715824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT); 2716824a1566SKashyap Desai if (le16_to_cpu(facts_data->ioc_request_frame_size) != (req_sz / 4)) { 2717824a1566SKashyap Desai ioc_err(mrioc, 2718824a1566SKashyap Desai "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n", 2719824a1566SKashyap Desai req_sz / 4, le16_to_cpu(facts_data->ioc_request_frame_size)); 2720824a1566SKashyap Desai } 2721824a1566SKashyap Desai 2722824a1566SKashyap Desai memset(&mrioc->facts, 0, sizeof(mrioc->facts)); 2723824a1566SKashyap Desai 2724824a1566SKashyap Desai facts_flags = le32_to_cpu(facts_data->flags); 2725824a1566SKashyap Desai mrioc->facts.op_req_sz = req_sz; 2726824a1566SKashyap Desai mrioc->op_reply_desc_sz = 1 << ((ioc_config & 2727824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >> 2728824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT); 2729824a1566SKashyap Desai 2730824a1566SKashyap Desai mrioc->facts.ioc_num = facts_data->ioc_number; 2731824a1566SKashyap Desai mrioc->facts.who_init = facts_data->who_init; 2732824a1566SKashyap Desai mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->max_msix_vectors); 2733824a1566SKashyap Desai mrioc->facts.personality = (facts_flags & 2734824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK); 2735824a1566SKashyap Desai mrioc->facts.dma_mask = (facts_flags & 2736824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >> 2737824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT; 2738824a1566SKashyap Desai mrioc->facts.protocol_flags = facts_data->protocol_flags; 2739824a1566SKashyap Desai mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word); 2740824a1566SKashyap Desai mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_request); 2741824a1566SKashyap Desai mrioc->facts.product_id = le16_to_cpu(facts_data->product_id); 2742824a1566SKashyap Desai mrioc->facts.reply_sz = le16_to_cpu(facts_data->reply_frame_size) * 4; 2743824a1566SKashyap Desai mrioc->facts.exceptions = le16_to_cpu(facts_data->ioc_exceptions); 2744824a1566SKashyap Desai mrioc->facts.max_perids = le16_to_cpu(facts_data->max_persistent_id); 2745824a1566SKashyap Desai mrioc->facts.max_vds = le16_to_cpu(facts_data->max_vds); 2746824a1566SKashyap Desai mrioc->facts.max_hpds = le16_to_cpu(facts_data->max_host_pds); 2747ec5ebd2cSSreekanth Reddy mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_adv_host_pds); 2748ec5ebd2cSSreekanth Reddy mrioc->facts.max_raid_pds = le16_to_cpu(facts_data->max_raid_pds); 2749824a1566SKashyap Desai mrioc->facts.max_nvme = le16_to_cpu(facts_data->max_nvme); 2750824a1566SKashyap Desai mrioc->facts.max_pcie_switches = 2751ec5ebd2cSSreekanth Reddy le16_to_cpu(facts_data->max_pcie_switches); 2752824a1566SKashyap Desai mrioc->facts.max_sasexpanders = 2753824a1566SKashyap Desai le16_to_cpu(facts_data->max_sas_expanders); 2754824a1566SKashyap Desai mrioc->facts.max_sasinitiators = 2755824a1566SKashyap Desai le16_to_cpu(facts_data->max_sas_initiators); 2756824a1566SKashyap Desai mrioc->facts.max_enclosures = le16_to_cpu(facts_data->max_enclosures); 2757824a1566SKashyap Desai mrioc->facts.min_devhandle = le16_to_cpu(facts_data->min_dev_handle); 2758824a1566SKashyap Desai mrioc->facts.max_devhandle = le16_to_cpu(facts_data->max_dev_handle); 2759824a1566SKashyap Desai mrioc->facts.max_op_req_q = 2760824a1566SKashyap Desai le16_to_cpu(facts_data->max_operational_request_queues); 2761824a1566SKashyap Desai mrioc->facts.max_op_reply_q = 2762824a1566SKashyap Desai le16_to_cpu(facts_data->max_operational_reply_queues); 2763824a1566SKashyap Desai mrioc->facts.ioc_capabilities = 2764824a1566SKashyap Desai le32_to_cpu(facts_data->ioc_capabilities); 2765824a1566SKashyap Desai mrioc->facts.fw_ver.build_num = 2766824a1566SKashyap Desai le16_to_cpu(facts_data->fw_version.build_num); 2767824a1566SKashyap Desai mrioc->facts.fw_ver.cust_id = 2768824a1566SKashyap Desai le16_to_cpu(facts_data->fw_version.customer_id); 2769824a1566SKashyap Desai mrioc->facts.fw_ver.ph_minor = facts_data->fw_version.phase_minor; 2770824a1566SKashyap Desai mrioc->facts.fw_ver.ph_major = facts_data->fw_version.phase_major; 2771824a1566SKashyap Desai mrioc->facts.fw_ver.gen_minor = facts_data->fw_version.gen_minor; 2772824a1566SKashyap Desai mrioc->facts.fw_ver.gen_major = facts_data->fw_version.gen_major; 2773824a1566SKashyap Desai mrioc->msix_count = min_t(int, mrioc->msix_count, 2774824a1566SKashyap Desai mrioc->facts.max_msix_vectors); 2775824a1566SKashyap Desai mrioc->facts.sge_mod_mask = facts_data->sge_modifier_mask; 2776824a1566SKashyap Desai mrioc->facts.sge_mod_value = facts_data->sge_modifier_value; 2777824a1566SKashyap Desai mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift; 2778824a1566SKashyap Desai mrioc->facts.shutdown_timeout = 2779824a1566SKashyap Desai le16_to_cpu(facts_data->shutdown_timeout); 2780824a1566SKashyap Desai 2781824a1566SKashyap Desai ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),", 2782824a1566SKashyap Desai mrioc->facts.ioc_num, mrioc->facts.max_op_req_q, 2783824a1566SKashyap Desai mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle); 2784824a1566SKashyap Desai ioc_info(mrioc, 2785ec5ebd2cSSreekanth Reddy "maxreqs(%d), mindh(%d) maxvectors(%d) maxperids(%d)\n", 2786824a1566SKashyap Desai mrioc->facts.max_reqs, mrioc->facts.min_devhandle, 2787ec5ebd2cSSreekanth Reddy mrioc->facts.max_msix_vectors, mrioc->facts.max_perids); 2788824a1566SKashyap Desai ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ", 2789824a1566SKashyap Desai mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value, 2790824a1566SKashyap Desai mrioc->facts.sge_mod_shift); 2791824a1566SKashyap Desai ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x\n", 2792824a1566SKashyap Desai mrioc->facts.dma_mask, (facts_flags & 2793824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK)); 2794824a1566SKashyap Desai } 2795824a1566SKashyap Desai 2796824a1566SKashyap Desai /** 2797824a1566SKashyap Desai * mpi3mr_alloc_reply_sense_bufs - Send IOC Init 2798824a1566SKashyap Desai * @mrioc: Adapter instance reference 2799824a1566SKashyap Desai * 2800824a1566SKashyap Desai * Allocate and initialize the reply free buffers, sense 2801824a1566SKashyap Desai * buffers, reply free queue and sense buffer queue. 2802824a1566SKashyap Desai * 2803824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2804824a1566SKashyap Desai */ 2805824a1566SKashyap Desai static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) 2806824a1566SKashyap Desai { 2807824a1566SKashyap Desai int retval = 0; 2808824a1566SKashyap Desai u32 sz, i; 2809824a1566SKashyap Desai 2810824a1566SKashyap Desai if (mrioc->init_cmds.reply) 2811e3605f65SSreekanth Reddy return retval; 2812824a1566SKashyap Desai 2813c5758fc7SSreekanth Reddy mrioc->init_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); 2814824a1566SKashyap Desai if (!mrioc->init_cmds.reply) 2815824a1566SKashyap Desai goto out_failed; 2816824a1566SKashyap Desai 281713ef29eaSKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 2818c5758fc7SSreekanth Reddy mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz, 281913ef29eaSKashyap Desai GFP_KERNEL); 282013ef29eaSKashyap Desai if (!mrioc->dev_rmhs_cmds[i].reply) 282113ef29eaSKashyap Desai goto out_failed; 282213ef29eaSKashyap Desai } 282313ef29eaSKashyap Desai 2824c1af985dSSreekanth Reddy for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { 2825c1af985dSSreekanth Reddy mrioc->evtack_cmds[i].reply = kzalloc(mrioc->reply_sz, 2826c1af985dSSreekanth Reddy GFP_KERNEL); 2827c1af985dSSreekanth Reddy if (!mrioc->evtack_cmds[i].reply) 2828c1af985dSSreekanth Reddy goto out_failed; 2829c1af985dSSreekanth Reddy } 2830c1af985dSSreekanth Reddy 2831c5758fc7SSreekanth Reddy mrioc->host_tm_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); 2832e844adb1SKashyap Desai if (!mrioc->host_tm_cmds.reply) 2833e844adb1SKashyap Desai goto out_failed; 2834e844adb1SKashyap Desai 2835e844adb1SKashyap Desai mrioc->dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8; 2836e844adb1SKashyap Desai if (mrioc->facts.max_devhandle % 8) 2837e844adb1SKashyap Desai mrioc->dev_handle_bitmap_sz++; 2838e844adb1SKashyap Desai mrioc->removepend_bitmap = kzalloc(mrioc->dev_handle_bitmap_sz, 2839e844adb1SKashyap Desai GFP_KERNEL); 2840e844adb1SKashyap Desai if (!mrioc->removepend_bitmap) 2841e844adb1SKashyap Desai goto out_failed; 2842e844adb1SKashyap Desai 2843e844adb1SKashyap Desai mrioc->devrem_bitmap_sz = MPI3MR_NUM_DEVRMCMD / 8; 2844e844adb1SKashyap Desai if (MPI3MR_NUM_DEVRMCMD % 8) 2845e844adb1SKashyap Desai mrioc->devrem_bitmap_sz++; 2846e844adb1SKashyap Desai mrioc->devrem_bitmap = kzalloc(mrioc->devrem_bitmap_sz, 2847e844adb1SKashyap Desai GFP_KERNEL); 2848e844adb1SKashyap Desai if (!mrioc->devrem_bitmap) 2849e844adb1SKashyap Desai goto out_failed; 2850e844adb1SKashyap Desai 2851c1af985dSSreekanth Reddy mrioc->evtack_cmds_bitmap_sz = MPI3MR_NUM_EVTACKCMD / 8; 2852c1af985dSSreekanth Reddy if (MPI3MR_NUM_EVTACKCMD % 8) 2853c1af985dSSreekanth Reddy mrioc->evtack_cmds_bitmap_sz++; 2854c1af985dSSreekanth Reddy mrioc->evtack_cmds_bitmap = kzalloc(mrioc->evtack_cmds_bitmap_sz, 2855c1af985dSSreekanth Reddy GFP_KERNEL); 2856c1af985dSSreekanth Reddy if (!mrioc->evtack_cmds_bitmap) 2857c1af985dSSreekanth Reddy goto out_failed; 2858c1af985dSSreekanth Reddy 2859824a1566SKashyap Desai mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES; 2860824a1566SKashyap Desai mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1; 2861824a1566SKashyap Desai mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR; 2862824a1566SKashyap Desai mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1; 2863824a1566SKashyap Desai 2864824a1566SKashyap Desai /* reply buffer pool, 16 byte align */ 2865c5758fc7SSreekanth Reddy sz = mrioc->num_reply_bufs * mrioc->reply_sz; 2866824a1566SKashyap Desai mrioc->reply_buf_pool = dma_pool_create("reply_buf pool", 2867824a1566SKashyap Desai &mrioc->pdev->dev, sz, 16, 0); 2868824a1566SKashyap Desai if (!mrioc->reply_buf_pool) { 2869824a1566SKashyap Desai ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n"); 2870824a1566SKashyap Desai goto out_failed; 2871824a1566SKashyap Desai } 2872824a1566SKashyap Desai 2873824a1566SKashyap Desai mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL, 2874824a1566SKashyap Desai &mrioc->reply_buf_dma); 2875824a1566SKashyap Desai if (!mrioc->reply_buf) 2876824a1566SKashyap Desai goto out_failed; 2877824a1566SKashyap Desai 2878824a1566SKashyap Desai mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz; 2879824a1566SKashyap Desai 2880824a1566SKashyap Desai /* reply free queue, 8 byte align */ 2881824a1566SKashyap Desai sz = mrioc->reply_free_qsz * 8; 2882824a1566SKashyap Desai mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool", 2883824a1566SKashyap Desai &mrioc->pdev->dev, sz, 8, 0); 2884824a1566SKashyap Desai if (!mrioc->reply_free_q_pool) { 2885824a1566SKashyap Desai ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n"); 2886824a1566SKashyap Desai goto out_failed; 2887824a1566SKashyap Desai } 2888824a1566SKashyap Desai mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool, 2889824a1566SKashyap Desai GFP_KERNEL, &mrioc->reply_free_q_dma); 2890824a1566SKashyap Desai if (!mrioc->reply_free_q) 2891824a1566SKashyap Desai goto out_failed; 2892824a1566SKashyap Desai 2893824a1566SKashyap Desai /* sense buffer pool, 4 byte align */ 2894ec5ebd2cSSreekanth Reddy sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ; 2895824a1566SKashyap Desai mrioc->sense_buf_pool = dma_pool_create("sense_buf pool", 2896824a1566SKashyap Desai &mrioc->pdev->dev, sz, 4, 0); 2897824a1566SKashyap Desai if (!mrioc->sense_buf_pool) { 2898824a1566SKashyap Desai ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n"); 2899824a1566SKashyap Desai goto out_failed; 2900824a1566SKashyap Desai } 2901824a1566SKashyap Desai mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL, 2902824a1566SKashyap Desai &mrioc->sense_buf_dma); 2903824a1566SKashyap Desai if (!mrioc->sense_buf) 2904824a1566SKashyap Desai goto out_failed; 2905824a1566SKashyap Desai 2906824a1566SKashyap Desai /* sense buffer queue, 8 byte align */ 2907824a1566SKashyap Desai sz = mrioc->sense_buf_q_sz * 8; 2908824a1566SKashyap Desai mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool", 2909824a1566SKashyap Desai &mrioc->pdev->dev, sz, 8, 0); 2910824a1566SKashyap Desai if (!mrioc->sense_buf_q_pool) { 2911824a1566SKashyap Desai ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n"); 2912824a1566SKashyap Desai goto out_failed; 2913824a1566SKashyap Desai } 2914824a1566SKashyap Desai mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool, 2915824a1566SKashyap Desai GFP_KERNEL, &mrioc->sense_buf_q_dma); 2916824a1566SKashyap Desai if (!mrioc->sense_buf_q) 2917824a1566SKashyap Desai goto out_failed; 2918824a1566SKashyap Desai 2919e3605f65SSreekanth Reddy return retval; 2920e3605f65SSreekanth Reddy 2921e3605f65SSreekanth Reddy out_failed: 2922e3605f65SSreekanth Reddy retval = -1; 2923e3605f65SSreekanth Reddy return retval; 2924e3605f65SSreekanth Reddy } 2925e3605f65SSreekanth Reddy 2926e3605f65SSreekanth Reddy /** 2927e3605f65SSreekanth Reddy * mpimr_initialize_reply_sbuf_queues - initialize reply sense 2928e3605f65SSreekanth Reddy * buffers 2929e3605f65SSreekanth Reddy * @mrioc: Adapter instance reference 2930e3605f65SSreekanth Reddy * 2931e3605f65SSreekanth Reddy * Helper function to initialize reply and sense buffers along 2932e3605f65SSreekanth Reddy * with some debug prints. 2933e3605f65SSreekanth Reddy * 2934e3605f65SSreekanth Reddy * Return: None. 2935e3605f65SSreekanth Reddy */ 2936e3605f65SSreekanth Reddy static void mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc *mrioc) 2937e3605f65SSreekanth Reddy { 2938e3605f65SSreekanth Reddy u32 sz, i; 2939e3605f65SSreekanth Reddy dma_addr_t phy_addr; 2940e3605f65SSreekanth Reddy 2941c5758fc7SSreekanth Reddy sz = mrioc->num_reply_bufs * mrioc->reply_sz; 2942824a1566SKashyap Desai ioc_info(mrioc, 2943824a1566SKashyap Desai "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n", 2944c5758fc7SSreekanth Reddy mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->reply_sz, 2945824a1566SKashyap Desai (sz / 1024), (unsigned long long)mrioc->reply_buf_dma); 2946824a1566SKashyap Desai sz = mrioc->reply_free_qsz * 8; 2947824a1566SKashyap Desai ioc_info(mrioc, 2948824a1566SKashyap Desai "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n", 2949824a1566SKashyap Desai mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024), 2950824a1566SKashyap Desai (unsigned long long)mrioc->reply_free_q_dma); 2951ec5ebd2cSSreekanth Reddy sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ; 2952824a1566SKashyap Desai ioc_info(mrioc, 2953824a1566SKashyap Desai "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n", 2954ec5ebd2cSSreekanth Reddy mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSE_BUF_SZ, 2955824a1566SKashyap Desai (sz / 1024), (unsigned long long)mrioc->sense_buf_dma); 2956824a1566SKashyap Desai sz = mrioc->sense_buf_q_sz * 8; 2957824a1566SKashyap Desai ioc_info(mrioc, 2958824a1566SKashyap Desai "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n", 2959824a1566SKashyap Desai mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024), 2960824a1566SKashyap Desai (unsigned long long)mrioc->sense_buf_q_dma); 2961824a1566SKashyap Desai 2962824a1566SKashyap Desai /* initialize Reply buffer Queue */ 2963824a1566SKashyap Desai for (i = 0, phy_addr = mrioc->reply_buf_dma; 2964c5758fc7SSreekanth Reddy i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->reply_sz) 2965824a1566SKashyap Desai mrioc->reply_free_q[i] = cpu_to_le64(phy_addr); 2966824a1566SKashyap Desai mrioc->reply_free_q[i] = cpu_to_le64(0); 2967824a1566SKashyap Desai 2968824a1566SKashyap Desai /* initialize Sense Buffer Queue */ 2969824a1566SKashyap Desai for (i = 0, phy_addr = mrioc->sense_buf_dma; 2970ec5ebd2cSSreekanth Reddy i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSE_BUF_SZ) 2971824a1566SKashyap Desai mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr); 2972824a1566SKashyap Desai mrioc->sense_buf_q[i] = cpu_to_le64(0); 2973824a1566SKashyap Desai } 2974824a1566SKashyap Desai 2975824a1566SKashyap Desai /** 2976824a1566SKashyap Desai * mpi3mr_issue_iocinit - Send IOC Init 2977824a1566SKashyap Desai * @mrioc: Adapter instance reference 2978824a1566SKashyap Desai * 2979824a1566SKashyap Desai * Issue IOC Init MPI request through admin queue and wait for 2980824a1566SKashyap Desai * the completion of it or time out. 2981824a1566SKashyap Desai * 2982824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2983824a1566SKashyap Desai */ 2984824a1566SKashyap Desai static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc) 2985824a1566SKashyap Desai { 2986824a1566SKashyap Desai struct mpi3_ioc_init_request iocinit_req; 2987824a1566SKashyap Desai struct mpi3_driver_info_layout *drv_info; 2988824a1566SKashyap Desai dma_addr_t data_dma; 2989824a1566SKashyap Desai u32 data_len = sizeof(*drv_info); 2990824a1566SKashyap Desai int retval = 0; 2991824a1566SKashyap Desai ktime_t current_time; 2992824a1566SKashyap Desai 2993824a1566SKashyap Desai drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, 2994824a1566SKashyap Desai GFP_KERNEL); 2995824a1566SKashyap Desai if (!drv_info) { 2996824a1566SKashyap Desai retval = -1; 2997824a1566SKashyap Desai goto out; 2998824a1566SKashyap Desai } 2999e3605f65SSreekanth Reddy mpimr_initialize_reply_sbuf_queues(mrioc); 3000e3605f65SSreekanth Reddy 3001824a1566SKashyap Desai drv_info->information_length = cpu_to_le32(data_len); 3002aa0dc6a7SSreekanth Reddy strscpy(drv_info->driver_signature, "Broadcom", sizeof(drv_info->driver_signature)); 3003aa0dc6a7SSreekanth Reddy strscpy(drv_info->os_name, utsname()->sysname, sizeof(drv_info->os_name)); 3004aa0dc6a7SSreekanth Reddy strscpy(drv_info->os_version, utsname()->release, sizeof(drv_info->os_version)); 3005aa0dc6a7SSreekanth Reddy strscpy(drv_info->driver_name, MPI3MR_DRIVER_NAME, sizeof(drv_info->driver_name)); 3006aa0dc6a7SSreekanth Reddy strscpy(drv_info->driver_version, MPI3MR_DRIVER_VERSION, sizeof(drv_info->driver_version)); 3007aa0dc6a7SSreekanth Reddy strscpy(drv_info->driver_release_date, MPI3MR_DRIVER_RELDATE, 3008aa0dc6a7SSreekanth Reddy sizeof(drv_info->driver_release_date)); 3009824a1566SKashyap Desai drv_info->driver_capabilities = 0; 3010824a1566SKashyap Desai memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info, 3011824a1566SKashyap Desai sizeof(mrioc->driver_info)); 3012824a1566SKashyap Desai 3013824a1566SKashyap Desai memset(&iocinit_req, 0, sizeof(iocinit_req)); 3014824a1566SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 3015824a1566SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 3016824a1566SKashyap Desai retval = -1; 3017824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCInit: Init command is in use\n"); 3018824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 3019824a1566SKashyap Desai goto out; 3020824a1566SKashyap Desai } 3021824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 3022824a1566SKashyap Desai mrioc->init_cmds.is_waiting = 1; 3023824a1566SKashyap Desai mrioc->init_cmds.callback = NULL; 3024824a1566SKashyap Desai iocinit_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 3025824a1566SKashyap Desai iocinit_req.function = MPI3_FUNCTION_IOC_INIT; 3026824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.dev = MPI3_VERSION_DEV; 3027824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.unit = MPI3_VERSION_UNIT; 3028824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.major = MPI3_VERSION_MAJOR; 3029824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.minor = MPI3_VERSION_MINOR; 3030824a1566SKashyap Desai iocinit_req.who_init = MPI3_WHOINIT_HOST_DRIVER; 3031824a1566SKashyap Desai iocinit_req.reply_free_queue_depth = cpu_to_le16(mrioc->reply_free_qsz); 3032824a1566SKashyap Desai iocinit_req.reply_free_queue_address = 3033824a1566SKashyap Desai cpu_to_le64(mrioc->reply_free_q_dma); 3034ec5ebd2cSSreekanth Reddy iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSE_BUF_SZ); 3035824a1566SKashyap Desai iocinit_req.sense_buffer_free_queue_depth = 3036824a1566SKashyap Desai cpu_to_le16(mrioc->sense_buf_q_sz); 3037824a1566SKashyap Desai iocinit_req.sense_buffer_free_queue_address = 3038824a1566SKashyap Desai cpu_to_le64(mrioc->sense_buf_q_dma); 3039824a1566SKashyap Desai iocinit_req.driver_information_address = cpu_to_le64(data_dma); 3040824a1566SKashyap Desai 3041824a1566SKashyap Desai current_time = ktime_get_real(); 3042824a1566SKashyap Desai iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time)); 3043824a1566SKashyap Desai 3044824a1566SKashyap Desai init_completion(&mrioc->init_cmds.done); 3045824a1566SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iocinit_req, 3046824a1566SKashyap Desai sizeof(iocinit_req), 1); 3047824a1566SKashyap Desai if (retval) { 3048824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n"); 3049824a1566SKashyap Desai goto out_unlock; 3050824a1566SKashyap Desai } 3051824a1566SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 3052824a1566SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 3053824a1566SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 3054a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 3055824a1566SKashyap Desai MPI3MR_RESET_FROM_IOCINIT_TIMEOUT); 3056a6856cc4SSreekanth Reddy ioc_err(mrioc, "ioc_init timed out\n"); 3057824a1566SKashyap Desai retval = -1; 3058824a1566SKashyap Desai goto out_unlock; 3059824a1566SKashyap Desai } 3060824a1566SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 3061824a1566SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 3062824a1566SKashyap Desai ioc_err(mrioc, 3063824a1566SKashyap Desai "Issue IOCInit: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 3064824a1566SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 3065824a1566SKashyap Desai mrioc->init_cmds.ioc_loginfo); 3066824a1566SKashyap Desai retval = -1; 3067824a1566SKashyap Desai goto out_unlock; 3068824a1566SKashyap Desai } 3069824a1566SKashyap Desai 3070e3605f65SSreekanth Reddy mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs; 3071e3605f65SSreekanth Reddy writel(mrioc->reply_free_queue_host_index, 3072e3605f65SSreekanth Reddy &mrioc->sysif_regs->reply_free_host_index); 3073e3605f65SSreekanth Reddy 3074e3605f65SSreekanth Reddy mrioc->sbq_host_index = mrioc->num_sense_bufs; 3075e3605f65SSreekanth Reddy writel(mrioc->sbq_host_index, 3076e3605f65SSreekanth Reddy &mrioc->sysif_regs->sense_buffer_free_host_index); 3077824a1566SKashyap Desai out_unlock: 3078824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 3079824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 3080824a1566SKashyap Desai 3081824a1566SKashyap Desai out: 3082824a1566SKashyap Desai if (drv_info) 3083824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info, 3084824a1566SKashyap Desai data_dma); 3085824a1566SKashyap Desai 3086824a1566SKashyap Desai return retval; 3087824a1566SKashyap Desai } 3088824a1566SKashyap Desai 3089824a1566SKashyap Desai /** 309013ef29eaSKashyap Desai * mpi3mr_unmask_events - Unmask events in event mask bitmap 309113ef29eaSKashyap Desai * @mrioc: Adapter instance reference 309213ef29eaSKashyap Desai * @event: MPI event ID 309313ef29eaSKashyap Desai * 309413ef29eaSKashyap Desai * Un mask the specific event by resetting the event_mask 309513ef29eaSKashyap Desai * bitmap. 309613ef29eaSKashyap Desai * 309713ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 309813ef29eaSKashyap Desai */ 309913ef29eaSKashyap Desai static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event) 310013ef29eaSKashyap Desai { 310113ef29eaSKashyap Desai u32 desired_event; 310213ef29eaSKashyap Desai u8 word; 310313ef29eaSKashyap Desai 310413ef29eaSKashyap Desai if (event >= 128) 310513ef29eaSKashyap Desai return; 310613ef29eaSKashyap Desai 310713ef29eaSKashyap Desai desired_event = (1 << (event % 32)); 310813ef29eaSKashyap Desai word = event / 32; 310913ef29eaSKashyap Desai 311013ef29eaSKashyap Desai mrioc->event_masks[word] &= ~desired_event; 311113ef29eaSKashyap Desai } 311213ef29eaSKashyap Desai 311313ef29eaSKashyap Desai /** 311413ef29eaSKashyap Desai * mpi3mr_issue_event_notification - Send event notification 311513ef29eaSKashyap Desai * @mrioc: Adapter instance reference 311613ef29eaSKashyap Desai * 311713ef29eaSKashyap Desai * Issue event notification MPI request through admin queue and 311813ef29eaSKashyap Desai * wait for the completion of it or time out. 311913ef29eaSKashyap Desai * 312013ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 312113ef29eaSKashyap Desai */ 312213ef29eaSKashyap Desai static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc) 312313ef29eaSKashyap Desai { 312413ef29eaSKashyap Desai struct mpi3_event_notification_request evtnotify_req; 312513ef29eaSKashyap Desai int retval = 0; 312613ef29eaSKashyap Desai u8 i; 312713ef29eaSKashyap Desai 312813ef29eaSKashyap Desai memset(&evtnotify_req, 0, sizeof(evtnotify_req)); 312913ef29eaSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 313013ef29eaSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 313113ef29eaSKashyap Desai retval = -1; 313213ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: Init command is in use\n"); 313313ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 313413ef29eaSKashyap Desai goto out; 313513ef29eaSKashyap Desai } 313613ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 313713ef29eaSKashyap Desai mrioc->init_cmds.is_waiting = 1; 313813ef29eaSKashyap Desai mrioc->init_cmds.callback = NULL; 313913ef29eaSKashyap Desai evtnotify_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 314013ef29eaSKashyap Desai evtnotify_req.function = MPI3_FUNCTION_EVENT_NOTIFICATION; 314113ef29eaSKashyap Desai for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 314213ef29eaSKashyap Desai evtnotify_req.event_masks[i] = 314313ef29eaSKashyap Desai cpu_to_le32(mrioc->event_masks[i]); 314413ef29eaSKashyap Desai init_completion(&mrioc->init_cmds.done); 314513ef29eaSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &evtnotify_req, 314613ef29eaSKashyap Desai sizeof(evtnotify_req), 1); 314713ef29eaSKashyap Desai if (retval) { 314813ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: Admin Post failed\n"); 314913ef29eaSKashyap Desai goto out_unlock; 315013ef29eaSKashyap Desai } 315113ef29eaSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 315213ef29eaSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 315313ef29eaSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 3154a6856cc4SSreekanth Reddy ioc_err(mrioc, "event notification timed out\n"); 3155a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 315613ef29eaSKashyap Desai MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT); 315713ef29eaSKashyap Desai retval = -1; 315813ef29eaSKashyap Desai goto out_unlock; 315913ef29eaSKashyap Desai } 316013ef29eaSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 316113ef29eaSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 316213ef29eaSKashyap Desai ioc_err(mrioc, 316313ef29eaSKashyap Desai "Issue EvtNotify: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 316413ef29eaSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 316513ef29eaSKashyap Desai mrioc->init_cmds.ioc_loginfo); 316613ef29eaSKashyap Desai retval = -1; 316713ef29eaSKashyap Desai goto out_unlock; 316813ef29eaSKashyap Desai } 316913ef29eaSKashyap Desai 317013ef29eaSKashyap Desai out_unlock: 317113ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 317213ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 317313ef29eaSKashyap Desai out: 317413ef29eaSKashyap Desai return retval; 317513ef29eaSKashyap Desai } 317613ef29eaSKashyap Desai 317713ef29eaSKashyap Desai /** 3178c1af985dSSreekanth Reddy * mpi3mr_process_event_ack - Process event acknowledgment 317913ef29eaSKashyap Desai * @mrioc: Adapter instance reference 318013ef29eaSKashyap Desai * @event: MPI3 event ID 3181c1af985dSSreekanth Reddy * @event_ctx: event context 318213ef29eaSKashyap Desai * 318313ef29eaSKashyap Desai * Send event acknowledgment through admin queue and wait for 318413ef29eaSKashyap Desai * it to complete. 318513ef29eaSKashyap Desai * 318613ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 318713ef29eaSKashyap Desai */ 3188c1af985dSSreekanth Reddy int mpi3mr_process_event_ack(struct mpi3mr_ioc *mrioc, u8 event, 318913ef29eaSKashyap Desai u32 event_ctx) 319013ef29eaSKashyap Desai { 319113ef29eaSKashyap Desai struct mpi3_event_ack_request evtack_req; 319213ef29eaSKashyap Desai int retval = 0; 319313ef29eaSKashyap Desai 319413ef29eaSKashyap Desai memset(&evtack_req, 0, sizeof(evtack_req)); 319513ef29eaSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 319613ef29eaSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 319713ef29eaSKashyap Desai retval = -1; 319813ef29eaSKashyap Desai ioc_err(mrioc, "Send EvtAck: Init command is in use\n"); 319913ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 320013ef29eaSKashyap Desai goto out; 320113ef29eaSKashyap Desai } 320213ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 320313ef29eaSKashyap Desai mrioc->init_cmds.is_waiting = 1; 320413ef29eaSKashyap Desai mrioc->init_cmds.callback = NULL; 320513ef29eaSKashyap Desai evtack_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 320613ef29eaSKashyap Desai evtack_req.function = MPI3_FUNCTION_EVENT_ACK; 320713ef29eaSKashyap Desai evtack_req.event = event; 320813ef29eaSKashyap Desai evtack_req.event_context = cpu_to_le32(event_ctx); 320913ef29eaSKashyap Desai 321013ef29eaSKashyap Desai init_completion(&mrioc->init_cmds.done); 321113ef29eaSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &evtack_req, 321213ef29eaSKashyap Desai sizeof(evtack_req), 1); 321313ef29eaSKashyap Desai if (retval) { 321413ef29eaSKashyap Desai ioc_err(mrioc, "Send EvtAck: Admin Post failed\n"); 321513ef29eaSKashyap Desai goto out_unlock; 321613ef29eaSKashyap Desai } 321713ef29eaSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 321813ef29eaSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 321913ef29eaSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 322013ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: command timed out\n"); 3221fbaa9aa4SSreekanth Reddy if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET)) 322213ef29eaSKashyap Desai mpi3mr_soft_reset_handler(mrioc, 322313ef29eaSKashyap Desai MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1); 322413ef29eaSKashyap Desai retval = -1; 322513ef29eaSKashyap Desai goto out_unlock; 322613ef29eaSKashyap Desai } 322713ef29eaSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 322813ef29eaSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 322913ef29eaSKashyap Desai ioc_err(mrioc, 323013ef29eaSKashyap Desai "Send EvtAck: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 323113ef29eaSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 323213ef29eaSKashyap Desai mrioc->init_cmds.ioc_loginfo); 323313ef29eaSKashyap Desai retval = -1; 323413ef29eaSKashyap Desai goto out_unlock; 323513ef29eaSKashyap Desai } 323613ef29eaSKashyap Desai 323713ef29eaSKashyap Desai out_unlock: 323813ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 323913ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 324013ef29eaSKashyap Desai out: 324113ef29eaSKashyap Desai return retval; 324213ef29eaSKashyap Desai } 324313ef29eaSKashyap Desai 324413ef29eaSKashyap Desai /** 3245824a1566SKashyap Desai * mpi3mr_alloc_chain_bufs - Allocate chain buffers 3246824a1566SKashyap Desai * @mrioc: Adapter instance reference 3247824a1566SKashyap Desai * 3248824a1566SKashyap Desai * Allocate chain buffers and set a bitmap to indicate free 3249824a1566SKashyap Desai * chain buffers. Chain buffers are used to pass the SGE 3250824a1566SKashyap Desai * information along with MPI3 SCSI IO requests for host I/O. 3251824a1566SKashyap Desai * 3252824a1566SKashyap Desai * Return: 0 on success, non-zero on failure 3253824a1566SKashyap Desai */ 3254824a1566SKashyap Desai static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc) 3255824a1566SKashyap Desai { 3256824a1566SKashyap Desai int retval = 0; 3257824a1566SKashyap Desai u32 sz, i; 3258824a1566SKashyap Desai u16 num_chains; 3259824a1566SKashyap Desai 3260fe6db615SSreekanth Reddy if (mrioc->chain_sgl_list) 3261fe6db615SSreekanth Reddy return retval; 3262fe6db615SSreekanth Reddy 3263824a1566SKashyap Desai num_chains = mrioc->max_host_ios / MPI3MR_CHAINBUF_FACTOR; 3264824a1566SKashyap Desai 326574e1f30aSKashyap Desai if (prot_mask & (SHOST_DIX_TYPE0_PROTECTION 326674e1f30aSKashyap Desai | SHOST_DIX_TYPE1_PROTECTION 326774e1f30aSKashyap Desai | SHOST_DIX_TYPE2_PROTECTION 326874e1f30aSKashyap Desai | SHOST_DIX_TYPE3_PROTECTION)) 326974e1f30aSKashyap Desai num_chains += (num_chains / MPI3MR_CHAINBUFDIX_FACTOR); 327074e1f30aSKashyap Desai 3271824a1566SKashyap Desai mrioc->chain_buf_count = num_chains; 3272824a1566SKashyap Desai sz = sizeof(struct chain_element) * num_chains; 3273824a1566SKashyap Desai mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL); 3274824a1566SKashyap Desai if (!mrioc->chain_sgl_list) 3275824a1566SKashyap Desai goto out_failed; 3276824a1566SKashyap Desai 3277824a1566SKashyap Desai sz = MPI3MR_PAGE_SIZE_4K; 3278824a1566SKashyap Desai mrioc->chain_buf_pool = dma_pool_create("chain_buf pool", 3279824a1566SKashyap Desai &mrioc->pdev->dev, sz, 16, 0); 3280824a1566SKashyap Desai if (!mrioc->chain_buf_pool) { 3281824a1566SKashyap Desai ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n"); 3282824a1566SKashyap Desai goto out_failed; 3283824a1566SKashyap Desai } 3284824a1566SKashyap Desai 3285824a1566SKashyap Desai for (i = 0; i < num_chains; i++) { 3286824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr = 3287824a1566SKashyap Desai dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL, 3288824a1566SKashyap Desai &mrioc->chain_sgl_list[i].dma_addr); 3289824a1566SKashyap Desai 3290824a1566SKashyap Desai if (!mrioc->chain_sgl_list[i].addr) 3291824a1566SKashyap Desai goto out_failed; 3292824a1566SKashyap Desai } 3293824a1566SKashyap Desai mrioc->chain_bitmap_sz = num_chains / 8; 3294824a1566SKashyap Desai if (num_chains % 8) 3295824a1566SKashyap Desai mrioc->chain_bitmap_sz++; 3296824a1566SKashyap Desai mrioc->chain_bitmap = kzalloc(mrioc->chain_bitmap_sz, GFP_KERNEL); 3297824a1566SKashyap Desai if (!mrioc->chain_bitmap) 3298824a1566SKashyap Desai goto out_failed; 3299824a1566SKashyap Desai return retval; 3300824a1566SKashyap Desai out_failed: 3301824a1566SKashyap Desai retval = -1; 3302824a1566SKashyap Desai return retval; 3303824a1566SKashyap Desai } 3304824a1566SKashyap Desai 3305824a1566SKashyap Desai /** 3306023ab2a9SKashyap Desai * mpi3mr_port_enable_complete - Mark port enable complete 3307023ab2a9SKashyap Desai * @mrioc: Adapter instance reference 3308023ab2a9SKashyap Desai * @drv_cmd: Internal command tracker 3309023ab2a9SKashyap Desai * 3310023ab2a9SKashyap Desai * Call back for asynchronous port enable request sets the 3311023ab2a9SKashyap Desai * driver command to indicate port enable request is complete. 3312023ab2a9SKashyap Desai * 3313023ab2a9SKashyap Desai * Return: Nothing 3314023ab2a9SKashyap Desai */ 3315023ab2a9SKashyap Desai static void mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc, 3316023ab2a9SKashyap Desai struct mpi3mr_drv_cmd *drv_cmd) 3317023ab2a9SKashyap Desai { 3318023ab2a9SKashyap Desai drv_cmd->state = MPI3MR_CMD_NOTUSED; 3319023ab2a9SKashyap Desai drv_cmd->callback = NULL; 3320023ab2a9SKashyap Desai mrioc->scan_failed = drv_cmd->ioc_status; 3321023ab2a9SKashyap Desai mrioc->scan_started = 0; 3322023ab2a9SKashyap Desai } 3323023ab2a9SKashyap Desai 3324023ab2a9SKashyap Desai /** 3325023ab2a9SKashyap Desai * mpi3mr_issue_port_enable - Issue Port Enable 3326023ab2a9SKashyap Desai * @mrioc: Adapter instance reference 3327023ab2a9SKashyap Desai * @async: Flag to wait for completion or not 3328023ab2a9SKashyap Desai * 3329023ab2a9SKashyap Desai * Issue Port Enable MPI request through admin queue and if the 3330023ab2a9SKashyap Desai * async flag is not set wait for the completion of the port 3331023ab2a9SKashyap Desai * enable or time out. 3332023ab2a9SKashyap Desai * 3333023ab2a9SKashyap Desai * Return: 0 on success, non-zero on failures. 3334023ab2a9SKashyap Desai */ 3335023ab2a9SKashyap Desai int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async) 3336023ab2a9SKashyap Desai { 3337023ab2a9SKashyap Desai struct mpi3_port_enable_request pe_req; 3338023ab2a9SKashyap Desai int retval = 0; 3339023ab2a9SKashyap Desai u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT; 3340023ab2a9SKashyap Desai 3341023ab2a9SKashyap Desai memset(&pe_req, 0, sizeof(pe_req)); 3342023ab2a9SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 3343023ab2a9SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 3344023ab2a9SKashyap Desai retval = -1; 3345023ab2a9SKashyap Desai ioc_err(mrioc, "Issue PortEnable: Init command is in use\n"); 3346023ab2a9SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 3347023ab2a9SKashyap Desai goto out; 3348023ab2a9SKashyap Desai } 3349023ab2a9SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 3350023ab2a9SKashyap Desai if (async) { 3351023ab2a9SKashyap Desai mrioc->init_cmds.is_waiting = 0; 3352023ab2a9SKashyap Desai mrioc->init_cmds.callback = mpi3mr_port_enable_complete; 3353023ab2a9SKashyap Desai } else { 3354023ab2a9SKashyap Desai mrioc->init_cmds.is_waiting = 1; 3355023ab2a9SKashyap Desai mrioc->init_cmds.callback = NULL; 3356023ab2a9SKashyap Desai init_completion(&mrioc->init_cmds.done); 3357023ab2a9SKashyap Desai } 3358023ab2a9SKashyap Desai pe_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 3359023ab2a9SKashyap Desai pe_req.function = MPI3_FUNCTION_PORT_ENABLE; 3360023ab2a9SKashyap Desai 3361023ab2a9SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &pe_req, sizeof(pe_req), 1); 3362023ab2a9SKashyap Desai if (retval) { 3363023ab2a9SKashyap Desai ioc_err(mrioc, "Issue PortEnable: Admin Post failed\n"); 3364023ab2a9SKashyap Desai goto out_unlock; 3365023ab2a9SKashyap Desai } 3366a6856cc4SSreekanth Reddy if (async) { 3367a6856cc4SSreekanth Reddy mutex_unlock(&mrioc->init_cmds.mutex); 3368a6856cc4SSreekanth Reddy goto out; 3369a6856cc4SSreekanth Reddy } 3370a6856cc4SSreekanth Reddy 3371a6856cc4SSreekanth Reddy wait_for_completion_timeout(&mrioc->init_cmds.done, (pe_timeout * HZ)); 3372023ab2a9SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 3373a6856cc4SSreekanth Reddy ioc_err(mrioc, "port enable timed out\n"); 3374023ab2a9SKashyap Desai retval = -1; 3375a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, MPI3MR_RESET_FROM_PE_TIMEOUT); 3376023ab2a9SKashyap Desai goto out_unlock; 3377023ab2a9SKashyap Desai } 3378023ab2a9SKashyap Desai mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds); 3379a6856cc4SSreekanth Reddy 3380023ab2a9SKashyap Desai out_unlock: 3381a6856cc4SSreekanth Reddy mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 3382023ab2a9SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 3383023ab2a9SKashyap Desai out: 3384023ab2a9SKashyap Desai return retval; 3385023ab2a9SKashyap Desai } 3386023ab2a9SKashyap Desai 3387ff9561e9SKashyap Desai /* Protocol type to name mapper structure */ 3388ff9561e9SKashyap Desai static const struct { 3389ff9561e9SKashyap Desai u8 protocol; 3390ff9561e9SKashyap Desai char *name; 3391ff9561e9SKashyap Desai } mpi3mr_protocols[] = { 3392ff9561e9SKashyap Desai { MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR, "Initiator" }, 3393ff9561e9SKashyap Desai { MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET, "Target" }, 3394ff9561e9SKashyap Desai { MPI3_IOCFACTS_PROTOCOL_NVME, "NVMe attachment" }, 3395ff9561e9SKashyap Desai }; 3396ff9561e9SKashyap Desai 3397ff9561e9SKashyap Desai /* Capability to name mapper structure*/ 3398ff9561e9SKashyap Desai static const struct { 3399ff9561e9SKashyap Desai u32 capability; 3400ff9561e9SKashyap Desai char *name; 3401ff9561e9SKashyap Desai } mpi3mr_capabilities[] = { 3402ff9561e9SKashyap Desai { MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE, "RAID" }, 3403ff9561e9SKashyap Desai }; 3404ff9561e9SKashyap Desai 3405ff9561e9SKashyap Desai /** 3406ff9561e9SKashyap Desai * mpi3mr_print_ioc_info - Display controller information 3407ff9561e9SKashyap Desai * @mrioc: Adapter instance reference 3408ff9561e9SKashyap Desai * 3409ff9561e9SKashyap Desai * Display controller personalit, capability, supported 3410ff9561e9SKashyap Desai * protocols etc. 3411ff9561e9SKashyap Desai * 3412ff9561e9SKashyap Desai * Return: Nothing 3413ff9561e9SKashyap Desai */ 3414ff9561e9SKashyap Desai static void 3415ff9561e9SKashyap Desai mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc) 3416ff9561e9SKashyap Desai { 341776a4f7ccSDan Carpenter int i = 0, bytes_written = 0; 3418ff9561e9SKashyap Desai char personality[16]; 3419ff9561e9SKashyap Desai char protocol[50] = {0}; 3420ff9561e9SKashyap Desai char capabilities[100] = {0}; 3421ff9561e9SKashyap Desai struct mpi3mr_compimg_ver *fwver = &mrioc->facts.fw_ver; 3422ff9561e9SKashyap Desai 3423ff9561e9SKashyap Desai switch (mrioc->facts.personality) { 3424ff9561e9SKashyap Desai case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA: 3425ff9561e9SKashyap Desai strncpy(personality, "Enhanced HBA", sizeof(personality)); 3426ff9561e9SKashyap Desai break; 3427ff9561e9SKashyap Desai case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR: 3428ff9561e9SKashyap Desai strncpy(personality, "RAID", sizeof(personality)); 3429ff9561e9SKashyap Desai break; 3430ff9561e9SKashyap Desai default: 3431ff9561e9SKashyap Desai strncpy(personality, "Unknown", sizeof(personality)); 3432ff9561e9SKashyap Desai break; 3433ff9561e9SKashyap Desai } 3434ff9561e9SKashyap Desai 3435ff9561e9SKashyap Desai ioc_info(mrioc, "Running in %s Personality", personality); 3436ff9561e9SKashyap Desai 3437ff9561e9SKashyap Desai ioc_info(mrioc, "FW version(%d.%d.%d.%d.%d.%d)\n", 3438ff9561e9SKashyap Desai fwver->gen_major, fwver->gen_minor, fwver->ph_major, 3439ff9561e9SKashyap Desai fwver->ph_minor, fwver->cust_id, fwver->build_num); 3440ff9561e9SKashyap Desai 3441ff9561e9SKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_protocols); i++) { 3442ff9561e9SKashyap Desai if (mrioc->facts.protocol_flags & 3443ff9561e9SKashyap Desai mpi3mr_protocols[i].protocol) { 344430e99f05SDan Carpenter bytes_written += scnprintf(protocol + bytes_written, 344576a4f7ccSDan Carpenter sizeof(protocol) - bytes_written, "%s%s", 344676a4f7ccSDan Carpenter bytes_written ? "," : "", 3447ff9561e9SKashyap Desai mpi3mr_protocols[i].name); 3448ff9561e9SKashyap Desai } 3449ff9561e9SKashyap Desai } 3450ff9561e9SKashyap Desai 345176a4f7ccSDan Carpenter bytes_written = 0; 3452ff9561e9SKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_capabilities); i++) { 3453ff9561e9SKashyap Desai if (mrioc->facts.protocol_flags & 3454ff9561e9SKashyap Desai mpi3mr_capabilities[i].capability) { 345530e99f05SDan Carpenter bytes_written += scnprintf(capabilities + bytes_written, 345676a4f7ccSDan Carpenter sizeof(capabilities) - bytes_written, "%s%s", 345776a4f7ccSDan Carpenter bytes_written ? "," : "", 3458ff9561e9SKashyap Desai mpi3mr_capabilities[i].name); 3459ff9561e9SKashyap Desai } 3460ff9561e9SKashyap Desai } 3461ff9561e9SKashyap Desai 3462ff9561e9SKashyap Desai ioc_info(mrioc, "Protocol=(%s), Capabilities=(%s)\n", 3463ff9561e9SKashyap Desai protocol, capabilities); 3464ff9561e9SKashyap Desai } 3465ff9561e9SKashyap Desai 3466023ab2a9SKashyap Desai /** 3467824a1566SKashyap Desai * mpi3mr_cleanup_resources - Free PCI resources 3468824a1566SKashyap Desai * @mrioc: Adapter instance reference 3469824a1566SKashyap Desai * 3470824a1566SKashyap Desai * Unmap PCI device memory and disable PCI device. 3471824a1566SKashyap Desai * 3472824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 3473824a1566SKashyap Desai */ 3474824a1566SKashyap Desai void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc) 3475824a1566SKashyap Desai { 3476824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 3477824a1566SKashyap Desai 3478824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 3479824a1566SKashyap Desai 3480824a1566SKashyap Desai if (mrioc->sysif_regs) { 3481824a1566SKashyap Desai iounmap((void __iomem *)mrioc->sysif_regs); 3482824a1566SKashyap Desai mrioc->sysif_regs = NULL; 3483824a1566SKashyap Desai } 3484824a1566SKashyap Desai 3485824a1566SKashyap Desai if (pci_is_enabled(pdev)) { 3486824a1566SKashyap Desai if (mrioc->bars) 3487824a1566SKashyap Desai pci_release_selected_regions(pdev, mrioc->bars); 3488824a1566SKashyap Desai pci_disable_device(pdev); 3489824a1566SKashyap Desai } 3490824a1566SKashyap Desai } 3491824a1566SKashyap Desai 3492824a1566SKashyap Desai /** 3493824a1566SKashyap Desai * mpi3mr_setup_resources - Enable PCI resources 3494824a1566SKashyap Desai * @mrioc: Adapter instance reference 3495824a1566SKashyap Desai * 3496824a1566SKashyap Desai * Enable PCI device memory, MSI-x registers and set DMA mask. 3497824a1566SKashyap Desai * 3498824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 3499824a1566SKashyap Desai */ 3500824a1566SKashyap Desai int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc) 3501824a1566SKashyap Desai { 3502824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 3503824a1566SKashyap Desai u32 memap_sz = 0; 3504824a1566SKashyap Desai int i, retval = 0, capb = 0; 3505824a1566SKashyap Desai u16 message_control; 3506824a1566SKashyap Desai u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask : 3507824a1566SKashyap Desai (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) && 3508824a1566SKashyap Desai (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32)); 3509824a1566SKashyap Desai 3510824a1566SKashyap Desai if (pci_enable_device_mem(pdev)) { 3511824a1566SKashyap Desai ioc_err(mrioc, "pci_enable_device_mem: failed\n"); 3512824a1566SKashyap Desai retval = -ENODEV; 3513824a1566SKashyap Desai goto out_failed; 3514824a1566SKashyap Desai } 3515824a1566SKashyap Desai 3516824a1566SKashyap Desai capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX); 3517824a1566SKashyap Desai if (!capb) { 3518824a1566SKashyap Desai ioc_err(mrioc, "Unable to find MSI-X Capabilities\n"); 3519824a1566SKashyap Desai retval = -ENODEV; 3520824a1566SKashyap Desai goto out_failed; 3521824a1566SKashyap Desai } 3522824a1566SKashyap Desai mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); 3523824a1566SKashyap Desai 3524824a1566SKashyap Desai if (pci_request_selected_regions(pdev, mrioc->bars, 3525824a1566SKashyap Desai mrioc->driver_name)) { 3526824a1566SKashyap Desai ioc_err(mrioc, "pci_request_selected_regions: failed\n"); 3527824a1566SKashyap Desai retval = -ENODEV; 3528824a1566SKashyap Desai goto out_failed; 3529824a1566SKashyap Desai } 3530824a1566SKashyap Desai 3531824a1566SKashyap Desai for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) { 3532824a1566SKashyap Desai if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { 3533824a1566SKashyap Desai mrioc->sysif_regs_phys = pci_resource_start(pdev, i); 3534824a1566SKashyap Desai memap_sz = pci_resource_len(pdev, i); 3535824a1566SKashyap Desai mrioc->sysif_regs = 3536824a1566SKashyap Desai ioremap(mrioc->sysif_regs_phys, memap_sz); 3537824a1566SKashyap Desai break; 3538824a1566SKashyap Desai } 3539824a1566SKashyap Desai } 3540824a1566SKashyap Desai 3541824a1566SKashyap Desai pci_set_master(pdev); 3542824a1566SKashyap Desai 3543824a1566SKashyap Desai retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask); 3544824a1566SKashyap Desai if (retval) { 3545824a1566SKashyap Desai if (dma_mask != DMA_BIT_MASK(32)) { 3546824a1566SKashyap Desai ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n"); 3547824a1566SKashyap Desai dma_mask = DMA_BIT_MASK(32); 3548824a1566SKashyap Desai retval = dma_set_mask_and_coherent(&pdev->dev, 3549824a1566SKashyap Desai dma_mask); 3550824a1566SKashyap Desai } 3551824a1566SKashyap Desai if (retval) { 3552824a1566SKashyap Desai mrioc->dma_mask = 0; 3553824a1566SKashyap Desai ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n"); 3554824a1566SKashyap Desai goto out_failed; 3555824a1566SKashyap Desai } 3556824a1566SKashyap Desai } 3557824a1566SKashyap Desai mrioc->dma_mask = dma_mask; 3558824a1566SKashyap Desai 3559824a1566SKashyap Desai if (!mrioc->sysif_regs) { 3560824a1566SKashyap Desai ioc_err(mrioc, 3561824a1566SKashyap Desai "Unable to map adapter memory or resource not found\n"); 3562824a1566SKashyap Desai retval = -EINVAL; 3563824a1566SKashyap Desai goto out_failed; 3564824a1566SKashyap Desai } 3565824a1566SKashyap Desai 3566824a1566SKashyap Desai pci_read_config_word(pdev, capb + 2, &message_control); 3567824a1566SKashyap Desai mrioc->msix_count = (message_control & 0x3FF) + 1; 3568824a1566SKashyap Desai 3569824a1566SKashyap Desai pci_save_state(pdev); 3570824a1566SKashyap Desai 3571824a1566SKashyap Desai pci_set_drvdata(pdev, mrioc->shost); 3572824a1566SKashyap Desai 3573824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 3574824a1566SKashyap Desai 3575824a1566SKashyap Desai ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n", 3576824a1566SKashyap Desai (unsigned long long)mrioc->sysif_regs_phys, 3577824a1566SKashyap Desai mrioc->sysif_regs, memap_sz); 3578824a1566SKashyap Desai ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n", 3579824a1566SKashyap Desai mrioc->msix_count); 3580*afd3a579SSreekanth Reddy 3581*afd3a579SSreekanth Reddy if (!reset_devices && poll_queues > 0) 3582*afd3a579SSreekanth Reddy mrioc->requested_poll_qcount = min_t(int, poll_queues, 3583*afd3a579SSreekanth Reddy mrioc->msix_count - 2); 3584824a1566SKashyap Desai return retval; 3585824a1566SKashyap Desai 3586824a1566SKashyap Desai out_failed: 3587824a1566SKashyap Desai mpi3mr_cleanup_resources(mrioc); 3588824a1566SKashyap Desai return retval; 3589824a1566SKashyap Desai } 3590824a1566SKashyap Desai 3591824a1566SKashyap Desai /** 3592e3605f65SSreekanth Reddy * mpi3mr_enable_events - Enable required events 3593e3605f65SSreekanth Reddy * @mrioc: Adapter instance reference 3594e3605f65SSreekanth Reddy * 3595e3605f65SSreekanth Reddy * This routine unmasks the events required by the driver by 3596e3605f65SSreekanth Reddy * sennding appropriate event mask bitmapt through an event 3597e3605f65SSreekanth Reddy * notification request. 3598e3605f65SSreekanth Reddy * 3599e3605f65SSreekanth Reddy * Return: 0 on success and non-zero on failure. 3600e3605f65SSreekanth Reddy */ 3601e3605f65SSreekanth Reddy static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc) 3602e3605f65SSreekanth Reddy { 3603e3605f65SSreekanth Reddy int retval = 0; 3604e3605f65SSreekanth Reddy u32 i; 3605e3605f65SSreekanth Reddy 3606e3605f65SSreekanth Reddy for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 3607e3605f65SSreekanth Reddy mrioc->event_masks[i] = -1; 3608e3605f65SSreekanth Reddy 3609e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED); 3610e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED); 3611e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE); 3612e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE); 3613e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST); 3614e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY); 3615e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR); 3616e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE); 3617e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST); 3618e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION); 361978b76a07SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_PREPARE_FOR_RESET); 3620e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT); 3621e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE); 362295cca8d5SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_TEMP_THRESHOLD); 3623e3605f65SSreekanth Reddy 3624e3605f65SSreekanth Reddy retval = mpi3mr_issue_event_notification(mrioc); 3625e3605f65SSreekanth Reddy if (retval) 3626e3605f65SSreekanth Reddy ioc_err(mrioc, "failed to issue event notification %d\n", 3627e3605f65SSreekanth Reddy retval); 3628e3605f65SSreekanth Reddy return retval; 3629e3605f65SSreekanth Reddy } 3630e3605f65SSreekanth Reddy 3631e3605f65SSreekanth Reddy /** 3632824a1566SKashyap Desai * mpi3mr_init_ioc - Initialize the controller 3633824a1566SKashyap Desai * @mrioc: Adapter instance reference 36340da66348SKashyap Desai * @init_type: Flag to indicate is the init_type 3635824a1566SKashyap Desai * 3636824a1566SKashyap Desai * This the controller initialization routine, executed either 3637824a1566SKashyap Desai * after soft reset or from pci probe callback. 3638824a1566SKashyap Desai * Setup the required resources, memory map the controller 3639824a1566SKashyap Desai * registers, create admin and operational reply queue pairs, 3640824a1566SKashyap Desai * allocate required memory for reply pool, sense buffer pool, 3641824a1566SKashyap Desai * issue IOC init request to the firmware, unmask the events and 3642824a1566SKashyap Desai * issue port enable to discover SAS/SATA/NVMe devies and RAID 3643824a1566SKashyap Desai * volumes. 3644824a1566SKashyap Desai * 3645824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 3646824a1566SKashyap Desai */ 3647fe6db615SSreekanth Reddy int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc) 3648824a1566SKashyap Desai { 3649824a1566SKashyap Desai int retval = 0; 3650fe6db615SSreekanth Reddy u8 retry = 0; 3651824a1566SKashyap Desai struct mpi3_ioc_facts_data facts_data; 3652824a1566SKashyap Desai 3653fe6db615SSreekanth Reddy retry_init: 3654824a1566SKashyap Desai retval = mpi3mr_bring_ioc_ready(mrioc); 3655824a1566SKashyap Desai if (retval) { 3656824a1566SKashyap Desai ioc_err(mrioc, "Failed to bring ioc ready: error %d\n", 3657824a1566SKashyap Desai retval); 3658fe6db615SSreekanth Reddy goto out_failed_noretry; 3659824a1566SKashyap Desai } 3660824a1566SKashyap Desai 3661824a1566SKashyap Desai retval = mpi3mr_setup_isr(mrioc, 1); 3662824a1566SKashyap Desai if (retval) { 3663824a1566SKashyap Desai ioc_err(mrioc, "Failed to setup ISR error %d\n", 3664824a1566SKashyap Desai retval); 3665fe6db615SSreekanth Reddy goto out_failed_noretry; 3666824a1566SKashyap Desai } 3667824a1566SKashyap Desai 3668824a1566SKashyap Desai retval = mpi3mr_issue_iocfacts(mrioc, &facts_data); 3669824a1566SKashyap Desai if (retval) { 3670824a1566SKashyap Desai ioc_err(mrioc, "Failed to Issue IOC Facts %d\n", 3671824a1566SKashyap Desai retval); 3672824a1566SKashyap Desai goto out_failed; 3673824a1566SKashyap Desai } 3674824a1566SKashyap Desai 3675c5758fc7SSreekanth Reddy mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD; 3676c5758fc7SSreekanth Reddy 3677c5758fc7SSreekanth Reddy if (reset_devices) 3678c5758fc7SSreekanth Reddy mrioc->max_host_ios = min_t(int, mrioc->max_host_ios, 3679c5758fc7SSreekanth Reddy MPI3MR_HOST_IOS_KDUMP); 3680c5758fc7SSreekanth Reddy 3681c5758fc7SSreekanth Reddy mrioc->reply_sz = mrioc->facts.reply_sz; 3682fe6db615SSreekanth Reddy 3683824a1566SKashyap Desai retval = mpi3mr_check_reset_dma_mask(mrioc); 3684824a1566SKashyap Desai if (retval) { 3685824a1566SKashyap Desai ioc_err(mrioc, "Resetting dma mask failed %d\n", 3686824a1566SKashyap Desai retval); 3687fe6db615SSreekanth Reddy goto out_failed_noretry; 3688fb9b0457SKashyap Desai } 3689824a1566SKashyap Desai 3690ff9561e9SKashyap Desai mpi3mr_print_ioc_info(mrioc); 3691ff9561e9SKashyap Desai 3692824a1566SKashyap Desai retval = mpi3mr_alloc_reply_sense_bufs(mrioc); 3693824a1566SKashyap Desai if (retval) { 3694824a1566SKashyap Desai ioc_err(mrioc, 3695824a1566SKashyap Desai "%s :Failed to allocated reply sense buffers %d\n", 3696824a1566SKashyap Desai __func__, retval); 3697fe6db615SSreekanth Reddy goto out_failed_noretry; 3698824a1566SKashyap Desai } 3699824a1566SKashyap Desai 3700824a1566SKashyap Desai retval = mpi3mr_alloc_chain_bufs(mrioc); 3701824a1566SKashyap Desai if (retval) { 3702824a1566SKashyap Desai ioc_err(mrioc, "Failed to allocated chain buffers %d\n", 3703824a1566SKashyap Desai retval); 3704fe6db615SSreekanth Reddy goto out_failed_noretry; 3705fb9b0457SKashyap Desai } 3706824a1566SKashyap Desai 3707824a1566SKashyap Desai retval = mpi3mr_issue_iocinit(mrioc); 3708824a1566SKashyap Desai if (retval) { 3709824a1566SKashyap Desai ioc_err(mrioc, "Failed to Issue IOC Init %d\n", 3710824a1566SKashyap Desai retval); 3711824a1566SKashyap Desai goto out_failed; 3712824a1566SKashyap Desai } 3713824a1566SKashyap Desai 37142ac794baSSreekanth Reddy retval = mpi3mr_print_pkg_ver(mrioc); 37152ac794baSSreekanth Reddy if (retval) { 37162ac794baSSreekanth Reddy ioc_err(mrioc, "failed to get package version\n"); 37172ac794baSSreekanth Reddy goto out_failed; 37182ac794baSSreekanth Reddy } 37192ac794baSSreekanth Reddy 3720824a1566SKashyap Desai retval = mpi3mr_setup_isr(mrioc, 0); 3721824a1566SKashyap Desai if (retval) { 3722824a1566SKashyap Desai ioc_err(mrioc, "Failed to re-setup ISR, error %d\n", 3723824a1566SKashyap Desai retval); 3724fe6db615SSreekanth Reddy goto out_failed_noretry; 3725fb9b0457SKashyap Desai } 3726824a1566SKashyap Desai 3727c9566231SKashyap Desai retval = mpi3mr_create_op_queues(mrioc); 3728c9566231SKashyap Desai if (retval) { 3729c9566231SKashyap Desai ioc_err(mrioc, "Failed to create OpQueues error %d\n", 3730c9566231SKashyap Desai retval); 3731c9566231SKashyap Desai goto out_failed; 3732c9566231SKashyap Desai } 3733c9566231SKashyap Desai 3734e3605f65SSreekanth Reddy retval = mpi3mr_enable_events(mrioc); 373513ef29eaSKashyap Desai if (retval) { 3736e3605f65SSreekanth Reddy ioc_err(mrioc, "failed to enable events %d\n", 373713ef29eaSKashyap Desai retval); 373813ef29eaSKashyap Desai goto out_failed; 373913ef29eaSKashyap Desai } 374013ef29eaSKashyap Desai 3741fe6db615SSreekanth Reddy ioc_info(mrioc, "controller initialization completed successfully\n"); 3742824a1566SKashyap Desai return retval; 3743824a1566SKashyap Desai out_failed: 3744fe6db615SSreekanth Reddy if (retry < 2) { 3745fe6db615SSreekanth Reddy retry++; 3746fe6db615SSreekanth Reddy ioc_warn(mrioc, "retrying controller initialization, retry_count:%d\n", 3747fe6db615SSreekanth Reddy retry); 3748fe6db615SSreekanth Reddy mpi3mr_memset_buffers(mrioc); 3749fe6db615SSreekanth Reddy goto retry_init; 3750fe6db615SSreekanth Reddy } 3751fe6db615SSreekanth Reddy out_failed_noretry: 3752fe6db615SSreekanth Reddy ioc_err(mrioc, "controller initialization failed\n"); 3753fe6db615SSreekanth Reddy mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 3754fe6db615SSreekanth Reddy MPI3MR_RESET_FROM_CTLR_CLEANUP); 3755fe6db615SSreekanth Reddy mrioc->unrecoverable = 1; 3756824a1566SKashyap Desai return retval; 3757824a1566SKashyap Desai } 3758824a1566SKashyap Desai 3759c0b00a93SSreekanth Reddy /** 3760c0b00a93SSreekanth Reddy * mpi3mr_reinit_ioc - Re-Initialize the controller 3761c0b00a93SSreekanth Reddy * @mrioc: Adapter instance reference 3762c0b00a93SSreekanth Reddy * @is_resume: Called from resume or reset path 3763c0b00a93SSreekanth Reddy * 3764c0b00a93SSreekanth Reddy * This the controller re-initialization routine, executed from 3765c0b00a93SSreekanth Reddy * the soft reset handler or resume callback. Creates 3766c0b00a93SSreekanth Reddy * operational reply queue pairs, allocate required memory for 3767c0b00a93SSreekanth Reddy * reply pool, sense buffer pool, issue IOC init request to the 3768c0b00a93SSreekanth Reddy * firmware, unmask the events and issue port enable to discover 3769c0b00a93SSreekanth Reddy * SAS/SATA/NVMe devices and RAID volumes. 3770c0b00a93SSreekanth Reddy * 3771c0b00a93SSreekanth Reddy * Return: 0 on success and non-zero on failure. 3772c0b00a93SSreekanth Reddy */ 3773fe6db615SSreekanth Reddy int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume) 3774fe6db615SSreekanth Reddy { 3775c0b00a93SSreekanth Reddy int retval = 0; 3776c0b00a93SSreekanth Reddy u8 retry = 0; 3777c0b00a93SSreekanth Reddy struct mpi3_ioc_facts_data facts_data; 3778fe6db615SSreekanth Reddy 3779c0b00a93SSreekanth Reddy retry_init: 3780c0b00a93SSreekanth Reddy dprint_reset(mrioc, "bringing up the controller to ready state\n"); 3781c0b00a93SSreekanth Reddy retval = mpi3mr_bring_ioc_ready(mrioc); 3782c0b00a93SSreekanth Reddy if (retval) { 3783c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to bring to ready state\n"); 3784c0b00a93SSreekanth Reddy goto out_failed_noretry; 3785c0b00a93SSreekanth Reddy } 3786c0b00a93SSreekanth Reddy 3787c0b00a93SSreekanth Reddy if (is_resume) { 3788c0b00a93SSreekanth Reddy dprint_reset(mrioc, "setting up single ISR\n"); 3789c0b00a93SSreekanth Reddy retval = mpi3mr_setup_isr(mrioc, 1); 3790c0b00a93SSreekanth Reddy if (retval) { 3791c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to setup ISR\n"); 3792c0b00a93SSreekanth Reddy goto out_failed_noretry; 3793c0b00a93SSreekanth Reddy } 3794c0b00a93SSreekanth Reddy } else 3795c0b00a93SSreekanth Reddy mpi3mr_ioc_enable_intr(mrioc); 3796c0b00a93SSreekanth Reddy 3797c0b00a93SSreekanth Reddy dprint_reset(mrioc, "getting ioc_facts\n"); 3798c0b00a93SSreekanth Reddy retval = mpi3mr_issue_iocfacts(mrioc, &facts_data); 3799c0b00a93SSreekanth Reddy if (retval) { 3800c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to get ioc_facts\n"); 3801c0b00a93SSreekanth Reddy goto out_failed; 3802c0b00a93SSreekanth Reddy } 3803c0b00a93SSreekanth Reddy 3804c5758fc7SSreekanth Reddy dprint_reset(mrioc, "validating ioc_facts\n"); 3805c5758fc7SSreekanth Reddy retval = mpi3mr_revalidate_factsdata(mrioc); 3806c5758fc7SSreekanth Reddy if (retval) { 3807c5758fc7SSreekanth Reddy ioc_err(mrioc, "failed to revalidate ioc_facts data\n"); 3808c5758fc7SSreekanth Reddy goto out_failed_noretry; 3809c5758fc7SSreekanth Reddy } 3810c0b00a93SSreekanth Reddy 3811c0b00a93SSreekanth Reddy mpi3mr_print_ioc_info(mrioc); 3812c0b00a93SSreekanth Reddy 3813c0b00a93SSreekanth Reddy dprint_reset(mrioc, "sending ioc_init\n"); 3814c0b00a93SSreekanth Reddy retval = mpi3mr_issue_iocinit(mrioc); 3815c0b00a93SSreekanth Reddy if (retval) { 3816c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to send ioc_init\n"); 3817c0b00a93SSreekanth Reddy goto out_failed; 3818c0b00a93SSreekanth Reddy } 3819c0b00a93SSreekanth Reddy 3820c0b00a93SSreekanth Reddy dprint_reset(mrioc, "getting package version\n"); 3821c0b00a93SSreekanth Reddy retval = mpi3mr_print_pkg_ver(mrioc); 3822c0b00a93SSreekanth Reddy if (retval) { 3823c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to get package version\n"); 3824c0b00a93SSreekanth Reddy goto out_failed; 3825c0b00a93SSreekanth Reddy } 3826c0b00a93SSreekanth Reddy 3827c0b00a93SSreekanth Reddy if (is_resume) { 3828c0b00a93SSreekanth Reddy dprint_reset(mrioc, "setting up multiple ISR\n"); 3829c0b00a93SSreekanth Reddy retval = mpi3mr_setup_isr(mrioc, 0); 3830c0b00a93SSreekanth Reddy if (retval) { 3831c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to re-setup ISR\n"); 3832c0b00a93SSreekanth Reddy goto out_failed_noretry; 3833c0b00a93SSreekanth Reddy } 3834c0b00a93SSreekanth Reddy } 3835c0b00a93SSreekanth Reddy 3836c0b00a93SSreekanth Reddy dprint_reset(mrioc, "creating operational queue pairs\n"); 3837c0b00a93SSreekanth Reddy retval = mpi3mr_create_op_queues(mrioc); 3838c0b00a93SSreekanth Reddy if (retval) { 3839c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to create operational queue pairs\n"); 3840c0b00a93SSreekanth Reddy goto out_failed; 3841c0b00a93SSreekanth Reddy } 3842c0b00a93SSreekanth Reddy 3843c0b00a93SSreekanth Reddy if (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q) { 3844c0b00a93SSreekanth Reddy ioc_err(mrioc, 3845c0b00a93SSreekanth Reddy "cannot create minimum number of operatioanl queues expected:%d created:%d\n", 3846c0b00a93SSreekanth Reddy mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q); 3847c0b00a93SSreekanth Reddy goto out_failed_noretry; 3848c0b00a93SSreekanth Reddy } 3849c0b00a93SSreekanth Reddy 3850c0b00a93SSreekanth Reddy dprint_reset(mrioc, "enabling events\n"); 3851c0b00a93SSreekanth Reddy retval = mpi3mr_enable_events(mrioc); 3852c0b00a93SSreekanth Reddy if (retval) { 3853c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to enable events\n"); 3854c0b00a93SSreekanth Reddy goto out_failed; 3855c0b00a93SSreekanth Reddy } 3856c0b00a93SSreekanth Reddy 3857c0b00a93SSreekanth Reddy ioc_info(mrioc, "sending port enable\n"); 3858c0b00a93SSreekanth Reddy retval = mpi3mr_issue_port_enable(mrioc, 0); 3859c0b00a93SSreekanth Reddy if (retval) { 3860c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to issue port enable\n"); 3861c0b00a93SSreekanth Reddy goto out_failed; 3862c0b00a93SSreekanth Reddy } 3863c0b00a93SSreekanth Reddy 3864c0b00a93SSreekanth Reddy ioc_info(mrioc, "controller %s completed successfully\n", 3865c0b00a93SSreekanth Reddy (is_resume)?"resume":"re-initialization"); 3866c0b00a93SSreekanth Reddy return retval; 3867c0b00a93SSreekanth Reddy out_failed: 3868c0b00a93SSreekanth Reddy if (retry < 2) { 3869c0b00a93SSreekanth Reddy retry++; 3870c0b00a93SSreekanth Reddy ioc_warn(mrioc, "retrying controller %s, retry_count:%d\n", 3871c0b00a93SSreekanth Reddy (is_resume)?"resume":"re-initialization", retry); 3872c0b00a93SSreekanth Reddy mpi3mr_memset_buffers(mrioc); 3873c0b00a93SSreekanth Reddy goto retry_init; 3874c0b00a93SSreekanth Reddy } 3875c0b00a93SSreekanth Reddy out_failed_noretry: 3876c0b00a93SSreekanth Reddy ioc_err(mrioc, "controller %s is failed\n", 3877c0b00a93SSreekanth Reddy (is_resume)?"resume":"re-initialization"); 3878c0b00a93SSreekanth Reddy mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 3879c0b00a93SSreekanth Reddy MPI3MR_RESET_FROM_CTLR_CLEANUP); 3880c0b00a93SSreekanth Reddy mrioc->unrecoverable = 1; 3881c0b00a93SSreekanth Reddy return retval; 3882fe6db615SSreekanth Reddy } 3883fe6db615SSreekanth Reddy 3884824a1566SKashyap Desai /** 3885fb9b0457SKashyap Desai * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's 3886fb9b0457SKashyap Desai * segments 3887fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3888fb9b0457SKashyap Desai * @qidx: Operational reply queue index 3889fb9b0457SKashyap Desai * 3890fb9b0457SKashyap Desai * Return: Nothing. 3891fb9b0457SKashyap Desai */ 3892fb9b0457SKashyap Desai static void mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx) 3893fb9b0457SKashyap Desai { 3894fb9b0457SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 3895fb9b0457SKashyap Desai struct segments *segments; 3896fb9b0457SKashyap Desai int i, size; 3897fb9b0457SKashyap Desai 3898fb9b0457SKashyap Desai if (!op_reply_q->q_segments) 3899fb9b0457SKashyap Desai return; 3900fb9b0457SKashyap Desai 3901fb9b0457SKashyap Desai size = op_reply_q->segment_qd * mrioc->op_reply_desc_sz; 3902fb9b0457SKashyap Desai segments = op_reply_q->q_segments; 3903fb9b0457SKashyap Desai for (i = 0; i < op_reply_q->num_segments; i++) 3904fb9b0457SKashyap Desai memset(segments[i].segment, 0, size); 3905fb9b0457SKashyap Desai } 3906fb9b0457SKashyap Desai 3907fb9b0457SKashyap Desai /** 3908fb9b0457SKashyap Desai * mpi3mr_memset_op_req_q_buffers - memset the operational request queue's 3909fb9b0457SKashyap Desai * segments 3910fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3911fb9b0457SKashyap Desai * @qidx: Operational request queue index 3912fb9b0457SKashyap Desai * 3913fb9b0457SKashyap Desai * Return: Nothing. 3914fb9b0457SKashyap Desai */ 3915fb9b0457SKashyap Desai static void mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx) 3916fb9b0457SKashyap Desai { 3917fb9b0457SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx; 3918fb9b0457SKashyap Desai struct segments *segments; 3919fb9b0457SKashyap Desai int i, size; 3920fb9b0457SKashyap Desai 3921fb9b0457SKashyap Desai if (!op_req_q->q_segments) 3922fb9b0457SKashyap Desai return; 3923fb9b0457SKashyap Desai 3924fb9b0457SKashyap Desai size = op_req_q->segment_qd * mrioc->facts.op_req_sz; 3925fb9b0457SKashyap Desai segments = op_req_q->q_segments; 3926fb9b0457SKashyap Desai for (i = 0; i < op_req_q->num_segments; i++) 3927fb9b0457SKashyap Desai memset(segments[i].segment, 0, size); 3928fb9b0457SKashyap Desai } 3929fb9b0457SKashyap Desai 3930fb9b0457SKashyap Desai /** 3931fb9b0457SKashyap Desai * mpi3mr_memset_buffers - memset memory for a controller 3932fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3933fb9b0457SKashyap Desai * 3934fb9b0457SKashyap Desai * clear all the memory allocated for a controller, typically 3935fb9b0457SKashyap Desai * called post reset to reuse the memory allocated during the 3936fb9b0457SKashyap Desai * controller init. 3937fb9b0457SKashyap Desai * 3938fb9b0457SKashyap Desai * Return: Nothing. 3939fb9b0457SKashyap Desai */ 39400da66348SKashyap Desai void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) 3941fb9b0457SKashyap Desai { 3942fb9b0457SKashyap Desai u16 i; 3943fb9b0457SKashyap Desai 3944fe6db615SSreekanth Reddy mrioc->change_count = 0; 3945*afd3a579SSreekanth Reddy mrioc->active_poll_qcount = 0; 3946*afd3a579SSreekanth Reddy mrioc->default_qcount = 0; 3947fe6db615SSreekanth Reddy if (mrioc->admin_req_base) 3948fb9b0457SKashyap Desai memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz); 3949fe6db615SSreekanth Reddy if (mrioc->admin_reply_base) 3950fb9b0457SKashyap Desai memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz); 3951fb9b0457SKashyap Desai 3952fe6db615SSreekanth Reddy if (mrioc->init_cmds.reply) { 3953fb9b0457SKashyap Desai memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply)); 3954e844adb1SKashyap Desai memset(mrioc->host_tm_cmds.reply, 0, 3955e844adb1SKashyap Desai sizeof(*mrioc->host_tm_cmds.reply)); 3956fb9b0457SKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) 3957fb9b0457SKashyap Desai memset(mrioc->dev_rmhs_cmds[i].reply, 0, 3958fb9b0457SKashyap Desai sizeof(*mrioc->dev_rmhs_cmds[i].reply)); 3959c1af985dSSreekanth Reddy for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) 3960c1af985dSSreekanth Reddy memset(mrioc->evtack_cmds[i].reply, 0, 3961c1af985dSSreekanth Reddy sizeof(*mrioc->evtack_cmds[i].reply)); 3962fb9b0457SKashyap Desai memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); 3963fb9b0457SKashyap Desai memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); 3964c1af985dSSreekanth Reddy memset(mrioc->evtack_cmds_bitmap, 0, 3965c1af985dSSreekanth Reddy mrioc->evtack_cmds_bitmap_sz); 3966fe6db615SSreekanth Reddy } 3967fb9b0457SKashyap Desai 3968fb9b0457SKashyap Desai for (i = 0; i < mrioc->num_queues; i++) { 3969fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].qid = 0; 3970fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].ci = 0; 3971fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].num_replies = 0; 3972fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].ephase = 0; 3973463429f8SKashyap Desai atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0); 3974463429f8SKashyap Desai atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0); 3975fb9b0457SKashyap Desai mpi3mr_memset_op_reply_q_buffers(mrioc, i); 3976fb9b0457SKashyap Desai 3977fb9b0457SKashyap Desai mrioc->req_qinfo[i].ci = 0; 3978fb9b0457SKashyap Desai mrioc->req_qinfo[i].pi = 0; 3979fb9b0457SKashyap Desai mrioc->req_qinfo[i].num_requests = 0; 3980fb9b0457SKashyap Desai mrioc->req_qinfo[i].qid = 0; 3981fb9b0457SKashyap Desai mrioc->req_qinfo[i].reply_qid = 0; 3982fb9b0457SKashyap Desai spin_lock_init(&mrioc->req_qinfo[i].q_lock); 3983fb9b0457SKashyap Desai mpi3mr_memset_op_req_q_buffers(mrioc, i); 3984fb9b0457SKashyap Desai } 3985fb9b0457SKashyap Desai } 3986fb9b0457SKashyap Desai 3987fb9b0457SKashyap Desai /** 3988824a1566SKashyap Desai * mpi3mr_free_mem - Free memory allocated for a controller 3989824a1566SKashyap Desai * @mrioc: Adapter instance reference 3990824a1566SKashyap Desai * 3991824a1566SKashyap Desai * Free all the memory allocated for a controller. 3992824a1566SKashyap Desai * 3993824a1566SKashyap Desai * Return: Nothing. 3994824a1566SKashyap Desai */ 3995fe6db615SSreekanth Reddy void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) 3996824a1566SKashyap Desai { 3997824a1566SKashyap Desai u16 i; 3998824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info; 3999824a1566SKashyap Desai 4000824a1566SKashyap Desai if (mrioc->sense_buf_pool) { 4001824a1566SKashyap Desai if (mrioc->sense_buf) 4002824a1566SKashyap Desai dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf, 4003824a1566SKashyap Desai mrioc->sense_buf_dma); 4004824a1566SKashyap Desai dma_pool_destroy(mrioc->sense_buf_pool); 4005824a1566SKashyap Desai mrioc->sense_buf = NULL; 4006824a1566SKashyap Desai mrioc->sense_buf_pool = NULL; 4007824a1566SKashyap Desai } 4008824a1566SKashyap Desai if (mrioc->sense_buf_q_pool) { 4009824a1566SKashyap Desai if (mrioc->sense_buf_q) 4010824a1566SKashyap Desai dma_pool_free(mrioc->sense_buf_q_pool, 4011824a1566SKashyap Desai mrioc->sense_buf_q, mrioc->sense_buf_q_dma); 4012824a1566SKashyap Desai dma_pool_destroy(mrioc->sense_buf_q_pool); 4013824a1566SKashyap Desai mrioc->sense_buf_q = NULL; 4014824a1566SKashyap Desai mrioc->sense_buf_q_pool = NULL; 4015824a1566SKashyap Desai } 4016824a1566SKashyap Desai 4017824a1566SKashyap Desai if (mrioc->reply_buf_pool) { 4018824a1566SKashyap Desai if (mrioc->reply_buf) 4019824a1566SKashyap Desai dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf, 4020824a1566SKashyap Desai mrioc->reply_buf_dma); 4021824a1566SKashyap Desai dma_pool_destroy(mrioc->reply_buf_pool); 4022824a1566SKashyap Desai mrioc->reply_buf = NULL; 4023824a1566SKashyap Desai mrioc->reply_buf_pool = NULL; 4024824a1566SKashyap Desai } 4025824a1566SKashyap Desai if (mrioc->reply_free_q_pool) { 4026824a1566SKashyap Desai if (mrioc->reply_free_q) 4027824a1566SKashyap Desai dma_pool_free(mrioc->reply_free_q_pool, 4028824a1566SKashyap Desai mrioc->reply_free_q, mrioc->reply_free_q_dma); 4029824a1566SKashyap Desai dma_pool_destroy(mrioc->reply_free_q_pool); 4030824a1566SKashyap Desai mrioc->reply_free_q = NULL; 4031824a1566SKashyap Desai mrioc->reply_free_q_pool = NULL; 4032824a1566SKashyap Desai } 4033824a1566SKashyap Desai 4034c9566231SKashyap Desai for (i = 0; i < mrioc->num_op_req_q; i++) 4035c9566231SKashyap Desai mpi3mr_free_op_req_q_segments(mrioc, i); 4036c9566231SKashyap Desai 4037c9566231SKashyap Desai for (i = 0; i < mrioc->num_op_reply_q; i++) 4038c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, i); 4039c9566231SKashyap Desai 4040824a1566SKashyap Desai for (i = 0; i < mrioc->intr_info_count; i++) { 4041824a1566SKashyap Desai intr_info = mrioc->intr_info + i; 4042824a1566SKashyap Desai intr_info->op_reply_q = NULL; 4043824a1566SKashyap Desai } 4044824a1566SKashyap Desai 4045824a1566SKashyap Desai kfree(mrioc->req_qinfo); 4046824a1566SKashyap Desai mrioc->req_qinfo = NULL; 4047824a1566SKashyap Desai mrioc->num_op_req_q = 0; 4048824a1566SKashyap Desai 4049824a1566SKashyap Desai kfree(mrioc->op_reply_qinfo); 4050824a1566SKashyap Desai mrioc->op_reply_qinfo = NULL; 4051824a1566SKashyap Desai mrioc->num_op_reply_q = 0; 4052824a1566SKashyap Desai 4053824a1566SKashyap Desai kfree(mrioc->init_cmds.reply); 4054824a1566SKashyap Desai mrioc->init_cmds.reply = NULL; 4055824a1566SKashyap Desai 4056e844adb1SKashyap Desai kfree(mrioc->host_tm_cmds.reply); 4057e844adb1SKashyap Desai mrioc->host_tm_cmds.reply = NULL; 4058e844adb1SKashyap Desai 4059c1af985dSSreekanth Reddy for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { 4060c1af985dSSreekanth Reddy kfree(mrioc->evtack_cmds[i].reply); 4061c1af985dSSreekanth Reddy mrioc->evtack_cmds[i].reply = NULL; 4062c1af985dSSreekanth Reddy } 4063c1af985dSSreekanth Reddy 4064e844adb1SKashyap Desai kfree(mrioc->removepend_bitmap); 4065e844adb1SKashyap Desai mrioc->removepend_bitmap = NULL; 4066e844adb1SKashyap Desai 4067e844adb1SKashyap Desai kfree(mrioc->devrem_bitmap); 4068e844adb1SKashyap Desai mrioc->devrem_bitmap = NULL; 4069e844adb1SKashyap Desai 4070c1af985dSSreekanth Reddy kfree(mrioc->evtack_cmds_bitmap); 4071c1af985dSSreekanth Reddy mrioc->evtack_cmds_bitmap = NULL; 4072c1af985dSSreekanth Reddy 4073824a1566SKashyap Desai kfree(mrioc->chain_bitmap); 4074824a1566SKashyap Desai mrioc->chain_bitmap = NULL; 4075824a1566SKashyap Desai 407613ef29eaSKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 407713ef29eaSKashyap Desai kfree(mrioc->dev_rmhs_cmds[i].reply); 407813ef29eaSKashyap Desai mrioc->dev_rmhs_cmds[i].reply = NULL; 407913ef29eaSKashyap Desai } 408013ef29eaSKashyap Desai 4081824a1566SKashyap Desai if (mrioc->chain_buf_pool) { 4082824a1566SKashyap Desai for (i = 0; i < mrioc->chain_buf_count; i++) { 4083824a1566SKashyap Desai if (mrioc->chain_sgl_list[i].addr) { 4084824a1566SKashyap Desai dma_pool_free(mrioc->chain_buf_pool, 4085824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr, 4086824a1566SKashyap Desai mrioc->chain_sgl_list[i].dma_addr); 4087824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr = NULL; 4088824a1566SKashyap Desai } 4089824a1566SKashyap Desai } 4090824a1566SKashyap Desai dma_pool_destroy(mrioc->chain_buf_pool); 4091824a1566SKashyap Desai mrioc->chain_buf_pool = NULL; 4092824a1566SKashyap Desai } 4093824a1566SKashyap Desai 4094824a1566SKashyap Desai kfree(mrioc->chain_sgl_list); 4095824a1566SKashyap Desai mrioc->chain_sgl_list = NULL; 4096824a1566SKashyap Desai 4097824a1566SKashyap Desai if (mrioc->admin_reply_base) { 4098824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz, 4099824a1566SKashyap Desai mrioc->admin_reply_base, mrioc->admin_reply_dma); 4100824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 4101824a1566SKashyap Desai } 4102824a1566SKashyap Desai if (mrioc->admin_req_base) { 4103824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz, 4104824a1566SKashyap Desai mrioc->admin_req_base, mrioc->admin_req_dma); 4105824a1566SKashyap Desai mrioc->admin_req_base = NULL; 4106824a1566SKashyap Desai } 4107824a1566SKashyap Desai } 4108824a1566SKashyap Desai 4109824a1566SKashyap Desai /** 4110824a1566SKashyap Desai * mpi3mr_issue_ioc_shutdown - shutdown controller 4111824a1566SKashyap Desai * @mrioc: Adapter instance reference 4112824a1566SKashyap Desai * 4113824a1566SKashyap Desai * Send shutodwn notification to the controller and wait for the 4114824a1566SKashyap Desai * shutdown_timeout for it to be completed. 4115824a1566SKashyap Desai * 4116824a1566SKashyap Desai * Return: Nothing. 4117824a1566SKashyap Desai */ 4118824a1566SKashyap Desai static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc) 4119824a1566SKashyap Desai { 4120824a1566SKashyap Desai u32 ioc_config, ioc_status; 4121824a1566SKashyap Desai u8 retval = 1; 4122824a1566SKashyap Desai u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10; 4123824a1566SKashyap Desai 4124824a1566SKashyap Desai ioc_info(mrioc, "Issuing shutdown Notification\n"); 4125824a1566SKashyap Desai if (mrioc->unrecoverable) { 4126824a1566SKashyap Desai ioc_warn(mrioc, 4127824a1566SKashyap Desai "IOC is unrecoverable shutdown is not issued\n"); 4128824a1566SKashyap Desai return; 4129824a1566SKashyap Desai } 4130824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 4131824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 4132824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) { 4133824a1566SKashyap Desai ioc_info(mrioc, "shutdown already in progress\n"); 4134824a1566SKashyap Desai return; 4135824a1566SKashyap Desai } 4136824a1566SKashyap Desai 4137824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 4138824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL; 4139ec5ebd2cSSreekanth Reddy ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ; 4140824a1566SKashyap Desai 4141824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 4142824a1566SKashyap Desai 4143824a1566SKashyap Desai if (mrioc->facts.shutdown_timeout) 4144824a1566SKashyap Desai timeout = mrioc->facts.shutdown_timeout * 10; 4145824a1566SKashyap Desai 4146824a1566SKashyap Desai do { 4147824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 4148824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 4149824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) { 4150824a1566SKashyap Desai retval = 0; 4151824a1566SKashyap Desai break; 4152824a1566SKashyap Desai } 4153824a1566SKashyap Desai msleep(100); 4154824a1566SKashyap Desai } while (--timeout); 4155824a1566SKashyap Desai 4156824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 4157824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 4158824a1566SKashyap Desai 4159824a1566SKashyap Desai if (retval) { 4160824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 4161824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) 4162824a1566SKashyap Desai ioc_warn(mrioc, 4163824a1566SKashyap Desai "shutdown still in progress after timeout\n"); 4164824a1566SKashyap Desai } 4165824a1566SKashyap Desai 4166824a1566SKashyap Desai ioc_info(mrioc, 4167824a1566SKashyap Desai "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n", 4168824a1566SKashyap Desai (!retval) ? "successful" : "failed", ioc_status, 4169824a1566SKashyap Desai ioc_config); 4170824a1566SKashyap Desai } 4171824a1566SKashyap Desai 4172824a1566SKashyap Desai /** 4173824a1566SKashyap Desai * mpi3mr_cleanup_ioc - Cleanup controller 4174824a1566SKashyap Desai * @mrioc: Adapter instance reference 4175fe6db615SSreekanth Reddy 4176824a1566SKashyap Desai * controller cleanup handler, Message unit reset or soft reset 4177fe6db615SSreekanth Reddy * and shutdown notification is issued to the controller. 4178824a1566SKashyap Desai * 4179824a1566SKashyap Desai * Return: Nothing. 4180824a1566SKashyap Desai */ 4181fe6db615SSreekanth Reddy void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc) 4182824a1566SKashyap Desai { 4183824a1566SKashyap Desai enum mpi3mr_iocstate ioc_state; 4184824a1566SKashyap Desai 4185fe6db615SSreekanth Reddy dprint_exit(mrioc, "cleaning up the controller\n"); 4186824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 4187824a1566SKashyap Desai 4188824a1566SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 4189824a1566SKashyap Desai 4190824a1566SKashyap Desai if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) && 4191824a1566SKashyap Desai (ioc_state == MRIOC_STATE_READY)) { 4192824a1566SKashyap Desai if (mpi3mr_issue_and_process_mur(mrioc, 4193824a1566SKashyap Desai MPI3MR_RESET_FROM_CTLR_CLEANUP)) 4194824a1566SKashyap Desai mpi3mr_issue_reset(mrioc, 4195824a1566SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, 4196824a1566SKashyap Desai MPI3MR_RESET_FROM_MUR_FAILURE); 4197824a1566SKashyap Desai mpi3mr_issue_ioc_shutdown(mrioc); 4198824a1566SKashyap Desai } 4199fe6db615SSreekanth Reddy dprint_exit(mrioc, "controller cleanup completed\n"); 4200fb9b0457SKashyap Desai } 4201fb9b0457SKashyap Desai 4202fb9b0457SKashyap Desai /** 4203fb9b0457SKashyap Desai * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command 4204fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 4205fb9b0457SKashyap Desai * @cmdptr: Internal command tracker 4206fb9b0457SKashyap Desai * 4207fb9b0457SKashyap Desai * Complete an internal driver commands with state indicating it 4208fb9b0457SKashyap Desai * is completed due to reset. 4209fb9b0457SKashyap Desai * 4210fb9b0457SKashyap Desai * Return: Nothing. 4211fb9b0457SKashyap Desai */ 4212fb9b0457SKashyap Desai static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc *mrioc, 4213fb9b0457SKashyap Desai struct mpi3mr_drv_cmd *cmdptr) 4214fb9b0457SKashyap Desai { 4215fb9b0457SKashyap Desai if (cmdptr->state & MPI3MR_CMD_PENDING) { 4216fb9b0457SKashyap Desai cmdptr->state |= MPI3MR_CMD_RESET; 4217fb9b0457SKashyap Desai cmdptr->state &= ~MPI3MR_CMD_PENDING; 4218fb9b0457SKashyap Desai if (cmdptr->is_waiting) { 4219fb9b0457SKashyap Desai complete(&cmdptr->done); 4220fb9b0457SKashyap Desai cmdptr->is_waiting = 0; 4221fb9b0457SKashyap Desai } else if (cmdptr->callback) 4222fb9b0457SKashyap Desai cmdptr->callback(mrioc, cmdptr); 4223fb9b0457SKashyap Desai } 4224fb9b0457SKashyap Desai } 4225fb9b0457SKashyap Desai 4226fb9b0457SKashyap Desai /** 4227fb9b0457SKashyap Desai * mpi3mr_flush_drv_cmds - Flush internaldriver commands 4228fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 4229fb9b0457SKashyap Desai * 4230fb9b0457SKashyap Desai * Flush all internal driver commands post reset 4231fb9b0457SKashyap Desai * 4232fb9b0457SKashyap Desai * Return: Nothing. 4233fb9b0457SKashyap Desai */ 4234fb9b0457SKashyap Desai static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc) 4235fb9b0457SKashyap Desai { 4236fb9b0457SKashyap Desai struct mpi3mr_drv_cmd *cmdptr; 4237fb9b0457SKashyap Desai u8 i; 4238fb9b0457SKashyap Desai 4239fb9b0457SKashyap Desai cmdptr = &mrioc->init_cmds; 4240fb9b0457SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 4241e844adb1SKashyap Desai cmdptr = &mrioc->host_tm_cmds; 4242e844adb1SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 4243fb9b0457SKashyap Desai 4244fb9b0457SKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 4245fb9b0457SKashyap Desai cmdptr = &mrioc->dev_rmhs_cmds[i]; 4246fb9b0457SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 4247fb9b0457SKashyap Desai } 4248c1af985dSSreekanth Reddy 4249c1af985dSSreekanth Reddy for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { 4250c1af985dSSreekanth Reddy cmdptr = &mrioc->evtack_cmds[i]; 4251c1af985dSSreekanth Reddy mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 4252c1af985dSSreekanth Reddy } 4253fb9b0457SKashyap Desai } 4254fb9b0457SKashyap Desai 4255fb9b0457SKashyap Desai /** 4256824a1566SKashyap Desai * mpi3mr_soft_reset_handler - Reset the controller 4257824a1566SKashyap Desai * @mrioc: Adapter instance reference 4258824a1566SKashyap Desai * @reset_reason: Reset reason code 4259824a1566SKashyap Desai * @snapdump: Flag to generate snapdump in firmware or not 4260824a1566SKashyap Desai * 4261fb9b0457SKashyap Desai * This is an handler for recovering controller by issuing soft 4262fb9b0457SKashyap Desai * reset are diag fault reset. This is a blocking function and 4263fb9b0457SKashyap Desai * when one reset is executed if any other resets they will be 4264fb9b0457SKashyap Desai * blocked. All IOCTLs/IO will be blocked during the reset. If 4265fb9b0457SKashyap Desai * controller reset is successful then the controller will be 4266fb9b0457SKashyap Desai * reinitalized, otherwise the controller will be marked as not 4267fb9b0457SKashyap Desai * recoverable 4268fb9b0457SKashyap Desai * 4269fb9b0457SKashyap Desai * In snapdump bit is set, the controller is issued with diag 4270fb9b0457SKashyap Desai * fault reset so that the firmware can create a snap dump and 4271fb9b0457SKashyap Desai * post that the firmware will result in F000 fault and the 4272fb9b0457SKashyap Desai * driver will issue soft reset to recover from that. 4273824a1566SKashyap Desai * 4274824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 4275824a1566SKashyap Desai */ 4276824a1566SKashyap Desai int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, 4277824a1566SKashyap Desai u32 reset_reason, u8 snapdump) 4278824a1566SKashyap Desai { 4279fb9b0457SKashyap Desai int retval = 0, i; 4280fb9b0457SKashyap Desai unsigned long flags; 4281fb9b0457SKashyap Desai u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; 4282fb9b0457SKashyap Desai 4283b64845a7SSreekanth Reddy /* Block the reset handler until diag save in progress*/ 4284b64845a7SSreekanth Reddy dprint_reset(mrioc, 4285b64845a7SSreekanth Reddy "soft_reset_handler: check and block on diagsave_timeout(%d)\n", 4286b64845a7SSreekanth Reddy mrioc->diagsave_timeout); 4287b64845a7SSreekanth Reddy while (mrioc->diagsave_timeout) 4288b64845a7SSreekanth Reddy ssleep(1); 4289fb9b0457SKashyap Desai /* 4290fb9b0457SKashyap Desai * Block new resets until the currently executing one is finished and 4291fb9b0457SKashyap Desai * return the status of the existing reset for all blocked resets 4292fb9b0457SKashyap Desai */ 4293b64845a7SSreekanth Reddy dprint_reset(mrioc, "soft_reset_handler: acquiring reset_mutex\n"); 4294fb9b0457SKashyap Desai if (!mutex_trylock(&mrioc->reset_mutex)) { 4295b64845a7SSreekanth Reddy ioc_info(mrioc, 4296b64845a7SSreekanth Reddy "controller reset triggered by %s is blocked due to another reset in progress\n", 4297b64845a7SSreekanth Reddy mpi3mr_reset_rc_name(reset_reason)); 4298b64845a7SSreekanth Reddy do { 4299b64845a7SSreekanth Reddy ssleep(1); 4300b64845a7SSreekanth Reddy } while (mrioc->reset_in_progress == 1); 4301b64845a7SSreekanth Reddy ioc_info(mrioc, 4302b64845a7SSreekanth Reddy "returning previous reset result(%d) for the reset triggered by %s\n", 4303b64845a7SSreekanth Reddy mrioc->prev_reset_result, 4304b64845a7SSreekanth Reddy mpi3mr_reset_rc_name(reset_reason)); 4305b64845a7SSreekanth Reddy return mrioc->prev_reset_result; 4306fb9b0457SKashyap Desai } 4307b64845a7SSreekanth Reddy ioc_info(mrioc, "controller reset is triggered by %s\n", 4308b64845a7SSreekanth Reddy mpi3mr_reset_rc_name(reset_reason)); 4309b64845a7SSreekanth Reddy 4310fb9b0457SKashyap Desai mrioc->reset_in_progress = 1; 4311b64845a7SSreekanth Reddy mrioc->prev_reset_result = -1; 4312fb9b0457SKashyap Desai 4313fb9b0457SKashyap Desai if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) && 4314b64845a7SSreekanth Reddy (reset_reason != MPI3MR_RESET_FROM_FIRMWARE) && 4315fb9b0457SKashyap Desai (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) { 4316fb9b0457SKashyap Desai for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 4317fb9b0457SKashyap Desai mrioc->event_masks[i] = -1; 4318fb9b0457SKashyap Desai 4319b64845a7SSreekanth Reddy dprint_reset(mrioc, "soft_reset_handler: masking events\n"); 4320b64845a7SSreekanth Reddy mpi3mr_issue_event_notification(mrioc); 4321fb9b0457SKashyap Desai } 4322fb9b0457SKashyap Desai 432344dc724fSKashyap Desai mpi3mr_wait_for_host_io(mrioc, MPI3MR_RESET_HOST_IOWAIT_TIMEOUT); 432444dc724fSKashyap Desai 4325fb9b0457SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 4326fb9b0457SKashyap Desai 4327fb9b0457SKashyap Desai if (snapdump) { 4328fb9b0457SKashyap Desai mpi3mr_set_diagsave(mrioc); 4329fb9b0457SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 4330fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); 4331fb9b0457SKashyap Desai if (!retval) { 4332fb9b0457SKashyap Desai do { 4333fb9b0457SKashyap Desai host_diagnostic = 4334fb9b0457SKashyap Desai readl(&mrioc->sysif_regs->host_diagnostic); 4335fb9b0457SKashyap Desai if (!(host_diagnostic & 4336fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS)) 4337fb9b0457SKashyap Desai break; 4338fb9b0457SKashyap Desai msleep(100); 4339fb9b0457SKashyap Desai } while (--timeout); 4340fb9b0457SKashyap Desai } 4341fb9b0457SKashyap Desai } 4342fb9b0457SKashyap Desai 4343fb9b0457SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 4344fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason); 4345fb9b0457SKashyap Desai if (retval) { 4346fb9b0457SKashyap Desai ioc_err(mrioc, "Failed to issue soft reset to the ioc\n"); 4347fb9b0457SKashyap Desai goto out; 4348fb9b0457SKashyap Desai } 4349fb9b0457SKashyap Desai 4350c1af985dSSreekanth Reddy mpi3mr_flush_delayed_cmd_lists(mrioc); 4351fb9b0457SKashyap Desai mpi3mr_flush_drv_cmds(mrioc); 4352fb9b0457SKashyap Desai memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); 4353fb9b0457SKashyap Desai memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); 4354c1af985dSSreekanth Reddy memset(mrioc->evtack_cmds_bitmap, 0, mrioc->evtack_cmds_bitmap_sz); 4355fb9b0457SKashyap Desai mpi3mr_cleanup_fwevt_list(mrioc); 4356fb9b0457SKashyap Desai mpi3mr_flush_host_io(mrioc); 4357fb9b0457SKashyap Desai mpi3mr_invalidate_devhandles(mrioc); 435878b76a07SSreekanth Reddy if (mrioc->prepare_for_reset) { 435978b76a07SSreekanth Reddy mrioc->prepare_for_reset = 0; 436078b76a07SSreekanth Reddy mrioc->prepare_for_reset_timeout_counter = 0; 436178b76a07SSreekanth Reddy } 4362fb9b0457SKashyap Desai mpi3mr_memset_buffers(mrioc); 4363fe6db615SSreekanth Reddy retval = mpi3mr_reinit_ioc(mrioc, 0); 4364fb9b0457SKashyap Desai if (retval) { 4365fb9b0457SKashyap Desai pr_err(IOCNAME "reinit after soft reset failed: reason %d\n", 4366fb9b0457SKashyap Desai mrioc->name, reset_reason); 4367fb9b0457SKashyap Desai goto out; 4368fb9b0457SKashyap Desai } 4369fb9b0457SKashyap Desai ssleep(10); 4370fb9b0457SKashyap Desai 4371fb9b0457SKashyap Desai out: 4372fb9b0457SKashyap Desai if (!retval) { 4373b64845a7SSreekanth Reddy mrioc->diagsave_timeout = 0; 4374fb9b0457SKashyap Desai mrioc->reset_in_progress = 0; 4375fb9b0457SKashyap Desai mpi3mr_rfresh_tgtdevs(mrioc); 437654dfcffbSKashyap Desai mrioc->ts_update_counter = 0; 4377fb9b0457SKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 4378fb9b0457SKashyap Desai if (mrioc->watchdog_work_q) 4379fb9b0457SKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 4380fb9b0457SKashyap Desai &mrioc->watchdog_work, 4381fb9b0457SKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 4382fb9b0457SKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 4383fb9b0457SKashyap Desai } else { 4384fb9b0457SKashyap Desai mpi3mr_issue_reset(mrioc, 4385fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); 4386fb9b0457SKashyap Desai mrioc->unrecoverable = 1; 4387fb9b0457SKashyap Desai mrioc->reset_in_progress = 0; 4388fb9b0457SKashyap Desai retval = -1; 4389fb9b0457SKashyap Desai } 4390b64845a7SSreekanth Reddy mrioc->prev_reset_result = retval; 4391fb9b0457SKashyap Desai mutex_unlock(&mrioc->reset_mutex); 4392b64845a7SSreekanth Reddy ioc_info(mrioc, "controller reset is %s\n", 4393b64845a7SSreekanth Reddy ((retval == 0) ? "successful" : "failed")); 4394fb9b0457SKashyap Desai return retval; 4395824a1566SKashyap Desai } 4396