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 19824a1566SKashyap Desai #if defined(writeq) && defined(CONFIG_64BIT) 20824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) 21824a1566SKashyap Desai { 22824a1566SKashyap Desai writeq(b, addr); 23824a1566SKashyap Desai } 24824a1566SKashyap Desai #else 25824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) 26824a1566SKashyap Desai { 27824a1566SKashyap Desai __u64 data_out = b; 28824a1566SKashyap Desai 29824a1566SKashyap Desai writel((u32)(data_out), addr); 30824a1566SKashyap Desai writel((u32)(data_out >> 32), (addr + 4)); 31824a1566SKashyap Desai } 32824a1566SKashyap Desai #endif 33824a1566SKashyap Desai 34023ab2a9SKashyap Desai static inline bool 35023ab2a9SKashyap Desai mpi3mr_check_req_qfull(struct op_req_qinfo *op_req_q) 36023ab2a9SKashyap Desai { 37023ab2a9SKashyap Desai u16 pi, ci, max_entries; 38023ab2a9SKashyap Desai bool is_qfull = false; 39023ab2a9SKashyap Desai 40023ab2a9SKashyap Desai pi = op_req_q->pi; 41023ab2a9SKashyap Desai ci = READ_ONCE(op_req_q->ci); 42023ab2a9SKashyap Desai max_entries = op_req_q->num_requests; 43023ab2a9SKashyap Desai 44023ab2a9SKashyap Desai if ((ci == (pi + 1)) || ((!ci) && (pi == (max_entries - 1)))) 45023ab2a9SKashyap Desai is_qfull = true; 46023ab2a9SKashyap Desai 47023ab2a9SKashyap Desai return is_qfull; 48023ab2a9SKashyap Desai } 49023ab2a9SKashyap Desai 50824a1566SKashyap Desai static void mpi3mr_sync_irqs(struct mpi3mr_ioc *mrioc) 51824a1566SKashyap Desai { 52824a1566SKashyap Desai u16 i, max_vectors; 53824a1566SKashyap Desai 54824a1566SKashyap Desai max_vectors = mrioc->intr_info_count; 55824a1566SKashyap Desai 56824a1566SKashyap Desai for (i = 0; i < max_vectors; i++) 57824a1566SKashyap Desai synchronize_irq(pci_irq_vector(mrioc->pdev, i)); 58824a1566SKashyap Desai } 59824a1566SKashyap Desai 60824a1566SKashyap Desai void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc) 61824a1566SKashyap Desai { 62824a1566SKashyap Desai mrioc->intr_enabled = 0; 63824a1566SKashyap Desai mpi3mr_sync_irqs(mrioc); 64824a1566SKashyap Desai } 65824a1566SKashyap Desai 66824a1566SKashyap Desai void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc) 67824a1566SKashyap Desai { 68824a1566SKashyap Desai mrioc->intr_enabled = 1; 69824a1566SKashyap Desai } 70824a1566SKashyap Desai 71824a1566SKashyap Desai static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc) 72824a1566SKashyap Desai { 73824a1566SKashyap Desai u16 i; 74824a1566SKashyap Desai 75824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 76824a1566SKashyap Desai 77824a1566SKashyap Desai if (!mrioc->intr_info) 78824a1566SKashyap Desai return; 79824a1566SKashyap Desai 80824a1566SKashyap Desai for (i = 0; i < mrioc->intr_info_count; i++) 81824a1566SKashyap Desai free_irq(pci_irq_vector(mrioc->pdev, i), 82824a1566SKashyap Desai (mrioc->intr_info + i)); 83824a1566SKashyap Desai 84824a1566SKashyap Desai kfree(mrioc->intr_info); 85824a1566SKashyap Desai mrioc->intr_info = NULL; 86824a1566SKashyap Desai mrioc->intr_info_count = 0; 87fe6db615SSreekanth Reddy mrioc->is_intr_info_set = false; 88824a1566SKashyap Desai pci_free_irq_vectors(mrioc->pdev); 89824a1566SKashyap Desai } 90824a1566SKashyap Desai 91824a1566SKashyap Desai void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length, 92824a1566SKashyap Desai dma_addr_t dma_addr) 93824a1566SKashyap Desai { 94824a1566SKashyap Desai struct mpi3_sge_common *sgel = paddr; 95824a1566SKashyap Desai 96824a1566SKashyap Desai sgel->flags = flags; 97824a1566SKashyap Desai sgel->length = cpu_to_le32(length); 98824a1566SKashyap Desai sgel->address = cpu_to_le64(dma_addr); 99824a1566SKashyap Desai } 100824a1566SKashyap Desai 101824a1566SKashyap Desai void mpi3mr_build_zero_len_sge(void *paddr) 102824a1566SKashyap Desai { 103824a1566SKashyap Desai u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 104824a1566SKashyap Desai 105824a1566SKashyap Desai mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1); 106824a1566SKashyap Desai } 107824a1566SKashyap Desai 108824a1566SKashyap Desai void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc, 109824a1566SKashyap Desai dma_addr_t phys_addr) 110824a1566SKashyap Desai { 111824a1566SKashyap Desai if (!phys_addr) 112824a1566SKashyap Desai return NULL; 113824a1566SKashyap Desai 114824a1566SKashyap Desai if ((phys_addr < mrioc->reply_buf_dma) || 115824a1566SKashyap Desai (phys_addr > mrioc->reply_buf_dma_max_address)) 116824a1566SKashyap Desai return NULL; 117824a1566SKashyap Desai 118824a1566SKashyap Desai return mrioc->reply_buf + (phys_addr - mrioc->reply_buf_dma); 119824a1566SKashyap Desai } 120824a1566SKashyap Desai 121824a1566SKashyap Desai void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc, 122824a1566SKashyap Desai dma_addr_t phys_addr) 123824a1566SKashyap Desai { 124824a1566SKashyap Desai if (!phys_addr) 125824a1566SKashyap Desai return NULL; 126824a1566SKashyap Desai 127824a1566SKashyap Desai return mrioc->sense_buf + (phys_addr - mrioc->sense_buf_dma); 128824a1566SKashyap Desai } 129824a1566SKashyap Desai 130824a1566SKashyap Desai static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc, 131824a1566SKashyap Desai u64 reply_dma) 132824a1566SKashyap Desai { 133824a1566SKashyap Desai u32 old_idx = 0; 134a83ec831SSreekanth Reddy unsigned long flags; 135824a1566SKashyap Desai 136a83ec831SSreekanth Reddy spin_lock_irqsave(&mrioc->reply_free_queue_lock, flags); 137824a1566SKashyap Desai old_idx = mrioc->reply_free_queue_host_index; 138824a1566SKashyap Desai mrioc->reply_free_queue_host_index = ( 139824a1566SKashyap Desai (mrioc->reply_free_queue_host_index == 140824a1566SKashyap Desai (mrioc->reply_free_qsz - 1)) ? 0 : 141824a1566SKashyap Desai (mrioc->reply_free_queue_host_index + 1)); 142824a1566SKashyap Desai mrioc->reply_free_q[old_idx] = cpu_to_le64(reply_dma); 143824a1566SKashyap Desai writel(mrioc->reply_free_queue_host_index, 144824a1566SKashyap Desai &mrioc->sysif_regs->reply_free_host_index); 145a83ec831SSreekanth Reddy spin_unlock_irqrestore(&mrioc->reply_free_queue_lock, flags); 146824a1566SKashyap Desai } 147824a1566SKashyap Desai 148824a1566SKashyap Desai void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc, 149824a1566SKashyap Desai u64 sense_buf_dma) 150824a1566SKashyap Desai { 151824a1566SKashyap Desai u32 old_idx = 0; 152a83ec831SSreekanth Reddy unsigned long flags; 153824a1566SKashyap Desai 154a83ec831SSreekanth Reddy spin_lock_irqsave(&mrioc->sbq_lock, flags); 155824a1566SKashyap Desai old_idx = mrioc->sbq_host_index; 156824a1566SKashyap Desai mrioc->sbq_host_index = ((mrioc->sbq_host_index == 157824a1566SKashyap Desai (mrioc->sense_buf_q_sz - 1)) ? 0 : 158824a1566SKashyap Desai (mrioc->sbq_host_index + 1)); 159824a1566SKashyap Desai mrioc->sense_buf_q[old_idx] = cpu_to_le64(sense_buf_dma); 160824a1566SKashyap Desai writel(mrioc->sbq_host_index, 161824a1566SKashyap Desai &mrioc->sysif_regs->sense_buffer_free_host_index); 162a83ec831SSreekanth Reddy spin_unlock_irqrestore(&mrioc->sbq_lock, flags); 163824a1566SKashyap Desai } 164824a1566SKashyap Desai 1659fc4abfeSKashyap Desai static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc, 1669fc4abfeSKashyap Desai struct mpi3_event_notification_reply *event_reply) 1679fc4abfeSKashyap Desai { 1689fc4abfeSKashyap Desai char *desc = NULL; 1699fc4abfeSKashyap Desai u16 event; 1709fc4abfeSKashyap Desai 1719fc4abfeSKashyap Desai event = event_reply->event; 1729fc4abfeSKashyap Desai 1739fc4abfeSKashyap Desai switch (event) { 1749fc4abfeSKashyap Desai case MPI3_EVENT_LOG_DATA: 1759fc4abfeSKashyap Desai desc = "Log Data"; 1769fc4abfeSKashyap Desai break; 1779fc4abfeSKashyap Desai case MPI3_EVENT_CHANGE: 1789fc4abfeSKashyap Desai desc = "Event Change"; 1799fc4abfeSKashyap Desai break; 1809fc4abfeSKashyap Desai case MPI3_EVENT_GPIO_INTERRUPT: 1819fc4abfeSKashyap Desai desc = "GPIO Interrupt"; 1829fc4abfeSKashyap Desai break; 1839fc4abfeSKashyap Desai case MPI3_EVENT_TEMP_THRESHOLD: 1849fc4abfeSKashyap Desai desc = "Temperature Threshold"; 1859fc4abfeSKashyap Desai break; 1869fc4abfeSKashyap Desai case MPI3_EVENT_CABLE_MGMT: 1879fc4abfeSKashyap Desai desc = "Cable Management"; 1889fc4abfeSKashyap Desai break; 1899fc4abfeSKashyap Desai case MPI3_EVENT_ENERGY_PACK_CHANGE: 1909fc4abfeSKashyap Desai desc = "Energy Pack Change"; 1919fc4abfeSKashyap Desai break; 1929fc4abfeSKashyap Desai case MPI3_EVENT_DEVICE_ADDED: 1939fc4abfeSKashyap Desai { 1949fc4abfeSKashyap Desai struct mpi3_device_page0 *event_data = 1959fc4abfeSKashyap Desai (struct mpi3_device_page0 *)event_reply->event_data; 1969fc4abfeSKashyap Desai ioc_info(mrioc, "Device Added: dev=0x%04x Form=0x%x\n", 1979fc4abfeSKashyap Desai event_data->dev_handle, event_data->device_form); 1989fc4abfeSKashyap Desai return; 1999fc4abfeSKashyap Desai } 2009fc4abfeSKashyap Desai case MPI3_EVENT_DEVICE_INFO_CHANGED: 2019fc4abfeSKashyap Desai { 2029fc4abfeSKashyap Desai struct mpi3_device_page0 *event_data = 2039fc4abfeSKashyap Desai (struct mpi3_device_page0 *)event_reply->event_data; 2049fc4abfeSKashyap Desai ioc_info(mrioc, "Device Info Changed: dev=0x%04x Form=0x%x\n", 2059fc4abfeSKashyap Desai event_data->dev_handle, event_data->device_form); 2069fc4abfeSKashyap Desai return; 2079fc4abfeSKashyap Desai } 2089fc4abfeSKashyap Desai case MPI3_EVENT_DEVICE_STATUS_CHANGE: 2099fc4abfeSKashyap Desai { 2109fc4abfeSKashyap Desai struct mpi3_event_data_device_status_change *event_data = 2119fc4abfeSKashyap Desai (struct mpi3_event_data_device_status_change *)event_reply->event_data; 2129fc4abfeSKashyap Desai ioc_info(mrioc, "Device status Change: dev=0x%04x RC=0x%x\n", 2139fc4abfeSKashyap Desai event_data->dev_handle, event_data->reason_code); 2149fc4abfeSKashyap Desai return; 2159fc4abfeSKashyap Desai } 2169fc4abfeSKashyap Desai case MPI3_EVENT_SAS_DISCOVERY: 2179fc4abfeSKashyap Desai { 2189fc4abfeSKashyap Desai struct mpi3_event_data_sas_discovery *event_data = 2199fc4abfeSKashyap Desai (struct mpi3_event_data_sas_discovery *)event_reply->event_data; 2209fc4abfeSKashyap Desai ioc_info(mrioc, "SAS Discovery: (%s) status (0x%08x)\n", 2219fc4abfeSKashyap Desai (event_data->reason_code == MPI3_EVENT_SAS_DISC_RC_STARTED) ? 2229fc4abfeSKashyap Desai "start" : "stop", 2239fc4abfeSKashyap Desai le32_to_cpu(event_data->discovery_status)); 2249fc4abfeSKashyap Desai return; 2259fc4abfeSKashyap Desai } 2269fc4abfeSKashyap Desai case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE: 2279fc4abfeSKashyap Desai desc = "SAS Broadcast Primitive"; 2289fc4abfeSKashyap Desai break; 2299fc4abfeSKashyap Desai case MPI3_EVENT_SAS_NOTIFY_PRIMITIVE: 2309fc4abfeSKashyap Desai desc = "SAS Notify Primitive"; 2319fc4abfeSKashyap Desai break; 2329fc4abfeSKashyap Desai case MPI3_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: 2339fc4abfeSKashyap Desai desc = "SAS Init Device Status Change"; 2349fc4abfeSKashyap Desai break; 2359fc4abfeSKashyap Desai case MPI3_EVENT_SAS_INIT_TABLE_OVERFLOW: 2369fc4abfeSKashyap Desai desc = "SAS Init Table Overflow"; 2379fc4abfeSKashyap Desai break; 2389fc4abfeSKashyap Desai case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST: 2399fc4abfeSKashyap Desai desc = "SAS Topology Change List"; 2409fc4abfeSKashyap Desai break; 2419fc4abfeSKashyap Desai case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE: 2429fc4abfeSKashyap Desai desc = "Enclosure Device Status Change"; 2439fc4abfeSKashyap Desai break; 2449fc4abfeSKashyap Desai case MPI3_EVENT_HARD_RESET_RECEIVED: 2459fc4abfeSKashyap Desai desc = "Hard Reset Received"; 2469fc4abfeSKashyap Desai break; 2479fc4abfeSKashyap Desai case MPI3_EVENT_SAS_PHY_COUNTER: 2489fc4abfeSKashyap Desai desc = "SAS PHY Counter"; 2499fc4abfeSKashyap Desai break; 2509fc4abfeSKashyap Desai case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR: 2519fc4abfeSKashyap Desai desc = "SAS Device Discovery Error"; 2529fc4abfeSKashyap Desai break; 2539fc4abfeSKashyap Desai case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: 2549fc4abfeSKashyap Desai desc = "PCIE Topology Change List"; 2559fc4abfeSKashyap Desai break; 2569fc4abfeSKashyap Desai case MPI3_EVENT_PCIE_ENUMERATION: 2579fc4abfeSKashyap Desai { 2589fc4abfeSKashyap Desai struct mpi3_event_data_pcie_enumeration *event_data = 2599fc4abfeSKashyap Desai (struct mpi3_event_data_pcie_enumeration *)event_reply->event_data; 2609fc4abfeSKashyap Desai ioc_info(mrioc, "PCIE Enumeration: (%s)", 2619fc4abfeSKashyap Desai (event_data->reason_code == 2629fc4abfeSKashyap Desai MPI3_EVENT_PCIE_ENUM_RC_STARTED) ? "start" : "stop"); 2639fc4abfeSKashyap Desai if (event_data->enumeration_status) 2649fc4abfeSKashyap Desai ioc_info(mrioc, "enumeration_status(0x%08x)\n", 2659fc4abfeSKashyap Desai le32_to_cpu(event_data->enumeration_status)); 2669fc4abfeSKashyap Desai return; 2679fc4abfeSKashyap Desai } 2689fc4abfeSKashyap Desai case MPI3_EVENT_PREPARE_FOR_RESET: 2699fc4abfeSKashyap Desai desc = "Prepare For Reset"; 2709fc4abfeSKashyap Desai break; 2719fc4abfeSKashyap Desai } 2729fc4abfeSKashyap Desai 2739fc4abfeSKashyap Desai if (!desc) 2749fc4abfeSKashyap Desai return; 2759fc4abfeSKashyap Desai 2769fc4abfeSKashyap Desai ioc_info(mrioc, "%s\n", desc); 2779fc4abfeSKashyap Desai } 2789fc4abfeSKashyap Desai 279824a1566SKashyap Desai static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc, 280824a1566SKashyap Desai struct mpi3_default_reply *def_reply) 281824a1566SKashyap Desai { 282824a1566SKashyap Desai struct mpi3_event_notification_reply *event_reply = 283824a1566SKashyap Desai (struct mpi3_event_notification_reply *)def_reply; 284824a1566SKashyap Desai 285824a1566SKashyap Desai mrioc->change_count = le16_to_cpu(event_reply->ioc_change_count); 2869fc4abfeSKashyap Desai mpi3mr_print_event_data(mrioc, event_reply); 28713ef29eaSKashyap Desai mpi3mr_os_handle_events(mrioc, event_reply); 288824a1566SKashyap Desai } 289824a1566SKashyap Desai 290824a1566SKashyap Desai static struct mpi3mr_drv_cmd * 291824a1566SKashyap Desai mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag, 292824a1566SKashyap Desai struct mpi3_default_reply *def_reply) 293824a1566SKashyap Desai { 29413ef29eaSKashyap Desai u16 idx; 29513ef29eaSKashyap Desai 296824a1566SKashyap Desai switch (host_tag) { 297824a1566SKashyap Desai case MPI3MR_HOSTTAG_INITCMDS: 298824a1566SKashyap Desai return &mrioc->init_cmds; 299e844adb1SKashyap Desai case MPI3MR_HOSTTAG_BLK_TMS: 300e844adb1SKashyap Desai return &mrioc->host_tm_cmds; 301824a1566SKashyap Desai case MPI3MR_HOSTTAG_INVALID: 302824a1566SKashyap Desai if (def_reply && def_reply->function == 303824a1566SKashyap Desai MPI3_FUNCTION_EVENT_NOTIFICATION) 304824a1566SKashyap Desai mpi3mr_handle_events(mrioc, def_reply); 305824a1566SKashyap Desai return NULL; 306824a1566SKashyap Desai default: 307824a1566SKashyap Desai break; 308824a1566SKashyap Desai } 30913ef29eaSKashyap Desai if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN && 31013ef29eaSKashyap Desai host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX) { 31113ef29eaSKashyap Desai idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN; 31213ef29eaSKashyap Desai return &mrioc->dev_rmhs_cmds[idx]; 31313ef29eaSKashyap Desai } 314824a1566SKashyap Desai 315c1af985dSSreekanth Reddy if (host_tag >= MPI3MR_HOSTTAG_EVTACKCMD_MIN && 316c1af985dSSreekanth Reddy host_tag <= MPI3MR_HOSTTAG_EVTACKCMD_MAX) { 317c1af985dSSreekanth Reddy idx = host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN; 318c1af985dSSreekanth Reddy return &mrioc->evtack_cmds[idx]; 319c1af985dSSreekanth Reddy } 320c1af985dSSreekanth Reddy 321824a1566SKashyap Desai return NULL; 322824a1566SKashyap Desai } 323824a1566SKashyap Desai 324824a1566SKashyap Desai static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, 325824a1566SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma) 326824a1566SKashyap Desai { 327824a1566SKashyap Desai u16 reply_desc_type, host_tag = 0; 328824a1566SKashyap Desai u16 ioc_status = MPI3_IOCSTATUS_SUCCESS; 329824a1566SKashyap Desai u32 ioc_loginfo = 0; 330824a1566SKashyap Desai struct mpi3_status_reply_descriptor *status_desc; 331824a1566SKashyap Desai struct mpi3_address_reply_descriptor *addr_desc; 332824a1566SKashyap Desai struct mpi3_success_reply_descriptor *success_desc; 333824a1566SKashyap Desai struct mpi3_default_reply *def_reply = NULL; 334824a1566SKashyap Desai struct mpi3mr_drv_cmd *cmdptr = NULL; 335824a1566SKashyap Desai struct mpi3_scsi_io_reply *scsi_reply; 336824a1566SKashyap Desai u8 *sense_buf = NULL; 337824a1566SKashyap Desai 338824a1566SKashyap Desai *reply_dma = 0; 339824a1566SKashyap Desai reply_desc_type = le16_to_cpu(reply_desc->reply_flags) & 340824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK; 341824a1566SKashyap Desai switch (reply_desc_type) { 342824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS: 343824a1566SKashyap Desai status_desc = (struct mpi3_status_reply_descriptor *)reply_desc; 344824a1566SKashyap Desai host_tag = le16_to_cpu(status_desc->host_tag); 345824a1566SKashyap Desai ioc_status = le16_to_cpu(status_desc->ioc_status); 346824a1566SKashyap Desai if (ioc_status & 347824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) 348824a1566SKashyap Desai ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info); 349824a1566SKashyap Desai ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; 350824a1566SKashyap Desai break; 351824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY: 352824a1566SKashyap Desai addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc; 353824a1566SKashyap Desai *reply_dma = le64_to_cpu(addr_desc->reply_frame_address); 354824a1566SKashyap Desai def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma); 355824a1566SKashyap Desai if (!def_reply) 356824a1566SKashyap Desai goto out; 357824a1566SKashyap Desai host_tag = le16_to_cpu(def_reply->host_tag); 358824a1566SKashyap Desai ioc_status = le16_to_cpu(def_reply->ioc_status); 359824a1566SKashyap Desai if (ioc_status & 360824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) 361824a1566SKashyap Desai ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info); 362824a1566SKashyap Desai ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; 363824a1566SKashyap Desai if (def_reply->function == MPI3_FUNCTION_SCSI_IO) { 364824a1566SKashyap Desai scsi_reply = (struct mpi3_scsi_io_reply *)def_reply; 365824a1566SKashyap Desai sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc, 366824a1566SKashyap Desai le64_to_cpu(scsi_reply->sense_data_buffer_address)); 367824a1566SKashyap Desai } 368824a1566SKashyap Desai break; 369824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS: 370824a1566SKashyap Desai success_desc = (struct mpi3_success_reply_descriptor *)reply_desc; 371824a1566SKashyap Desai host_tag = le16_to_cpu(success_desc->host_tag); 372824a1566SKashyap Desai break; 373824a1566SKashyap Desai default: 374824a1566SKashyap Desai break; 375824a1566SKashyap Desai } 376824a1566SKashyap Desai 377824a1566SKashyap Desai cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply); 378824a1566SKashyap Desai if (cmdptr) { 379824a1566SKashyap Desai if (cmdptr->state & MPI3MR_CMD_PENDING) { 380824a1566SKashyap Desai cmdptr->state |= MPI3MR_CMD_COMPLETE; 381824a1566SKashyap Desai cmdptr->ioc_loginfo = ioc_loginfo; 382824a1566SKashyap Desai cmdptr->ioc_status = ioc_status; 383824a1566SKashyap Desai cmdptr->state &= ~MPI3MR_CMD_PENDING; 384824a1566SKashyap Desai if (def_reply) { 385824a1566SKashyap Desai cmdptr->state |= MPI3MR_CMD_REPLY_VALID; 386824a1566SKashyap Desai memcpy((u8 *)cmdptr->reply, (u8 *)def_reply, 387c5758fc7SSreekanth Reddy mrioc->reply_sz); 388824a1566SKashyap Desai } 389824a1566SKashyap Desai if (cmdptr->is_waiting) { 390824a1566SKashyap Desai complete(&cmdptr->done); 391824a1566SKashyap Desai cmdptr->is_waiting = 0; 392824a1566SKashyap Desai } else if (cmdptr->callback) 393824a1566SKashyap Desai cmdptr->callback(mrioc, cmdptr); 394824a1566SKashyap Desai } 395824a1566SKashyap Desai } 396824a1566SKashyap Desai out: 397824a1566SKashyap Desai if (sense_buf) 398824a1566SKashyap Desai mpi3mr_repost_sense_buf(mrioc, 399824a1566SKashyap Desai le64_to_cpu(scsi_reply->sense_data_buffer_address)); 400824a1566SKashyap Desai } 401824a1566SKashyap Desai 402824a1566SKashyap Desai static int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) 403824a1566SKashyap Desai { 404824a1566SKashyap Desai u32 exp_phase = mrioc->admin_reply_ephase; 405824a1566SKashyap Desai u32 admin_reply_ci = mrioc->admin_reply_ci; 406824a1566SKashyap Desai u32 num_admin_replies = 0; 407824a1566SKashyap Desai u64 reply_dma = 0; 408824a1566SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc; 409824a1566SKashyap Desai 410824a1566SKashyap Desai reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base + 411824a1566SKashyap Desai admin_reply_ci; 412824a1566SKashyap Desai 413824a1566SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 414824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 415824a1566SKashyap Desai return 0; 416824a1566SKashyap Desai 417824a1566SKashyap Desai do { 418824a1566SKashyap Desai mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci); 419824a1566SKashyap Desai mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma); 420824a1566SKashyap Desai if (reply_dma) 421824a1566SKashyap Desai mpi3mr_repost_reply_buf(mrioc, reply_dma); 422824a1566SKashyap Desai num_admin_replies++; 423824a1566SKashyap Desai if (++admin_reply_ci == mrioc->num_admin_replies) { 424824a1566SKashyap Desai admin_reply_ci = 0; 425824a1566SKashyap Desai exp_phase ^= 1; 426824a1566SKashyap Desai } 427824a1566SKashyap Desai reply_desc = 428824a1566SKashyap Desai (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base + 429824a1566SKashyap Desai admin_reply_ci; 430824a1566SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 431824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 432824a1566SKashyap Desai break; 433824a1566SKashyap Desai } while (1); 434824a1566SKashyap Desai 435824a1566SKashyap Desai writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); 436824a1566SKashyap Desai mrioc->admin_reply_ci = admin_reply_ci; 437824a1566SKashyap Desai mrioc->admin_reply_ephase = exp_phase; 438824a1566SKashyap Desai 439824a1566SKashyap Desai return num_admin_replies; 440824a1566SKashyap Desai } 441824a1566SKashyap Desai 442023ab2a9SKashyap Desai /** 443023ab2a9SKashyap Desai * mpi3mr_get_reply_desc - get reply descriptor frame corresponding to 444023ab2a9SKashyap Desai * queue's consumer index from operational reply descriptor queue. 445023ab2a9SKashyap Desai * @op_reply_q: op_reply_qinfo object 446023ab2a9SKashyap Desai * @reply_ci: operational reply descriptor's queue consumer index 447023ab2a9SKashyap Desai * 448023ab2a9SKashyap Desai * Returns reply descriptor frame address 449023ab2a9SKashyap Desai */ 450023ab2a9SKashyap Desai static inline struct mpi3_default_reply_descriptor * 451023ab2a9SKashyap Desai mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci) 452023ab2a9SKashyap Desai { 453023ab2a9SKashyap Desai void *segment_base_addr; 454023ab2a9SKashyap Desai struct segments *segments = op_reply_q->q_segments; 455023ab2a9SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc = NULL; 456023ab2a9SKashyap Desai 457023ab2a9SKashyap Desai segment_base_addr = 458023ab2a9SKashyap Desai segments[reply_ci / op_reply_q->segment_qd].segment; 459023ab2a9SKashyap Desai reply_desc = (struct mpi3_default_reply_descriptor *)segment_base_addr + 460023ab2a9SKashyap Desai (reply_ci % op_reply_q->segment_qd); 461023ab2a9SKashyap Desai return reply_desc; 462023ab2a9SKashyap Desai } 463023ab2a9SKashyap Desai 464023ab2a9SKashyap Desai static int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, 465023ab2a9SKashyap Desai struct mpi3mr_intr_info *intr_info) 466023ab2a9SKashyap Desai { 467023ab2a9SKashyap Desai struct op_reply_qinfo *op_reply_q = intr_info->op_reply_q; 468023ab2a9SKashyap Desai struct op_req_qinfo *op_req_q; 469023ab2a9SKashyap Desai u32 exp_phase; 470023ab2a9SKashyap Desai u32 reply_ci; 471023ab2a9SKashyap Desai u32 num_op_reply = 0; 472023ab2a9SKashyap Desai u64 reply_dma = 0; 473023ab2a9SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc; 474023ab2a9SKashyap Desai u16 req_q_idx = 0, reply_qidx; 475023ab2a9SKashyap Desai 476023ab2a9SKashyap Desai reply_qidx = op_reply_q->qid - 1; 477023ab2a9SKashyap Desai 478463429f8SKashyap Desai if (!atomic_add_unless(&op_reply_q->in_use, 1, 1)) 479463429f8SKashyap Desai return 0; 480463429f8SKashyap Desai 481023ab2a9SKashyap Desai exp_phase = op_reply_q->ephase; 482023ab2a9SKashyap Desai reply_ci = op_reply_q->ci; 483023ab2a9SKashyap Desai 484023ab2a9SKashyap Desai reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci); 485023ab2a9SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 486023ab2a9SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) { 487463429f8SKashyap Desai atomic_dec(&op_reply_q->in_use); 488023ab2a9SKashyap Desai return 0; 489023ab2a9SKashyap Desai } 490023ab2a9SKashyap Desai 491023ab2a9SKashyap Desai do { 492023ab2a9SKashyap Desai req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1; 493023ab2a9SKashyap Desai op_req_q = &mrioc->req_qinfo[req_q_idx]; 494023ab2a9SKashyap Desai 495023ab2a9SKashyap Desai WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci)); 496023ab2a9SKashyap Desai mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma, 497023ab2a9SKashyap Desai reply_qidx); 498463429f8SKashyap Desai atomic_dec(&op_reply_q->pend_ios); 499023ab2a9SKashyap Desai if (reply_dma) 500023ab2a9SKashyap Desai mpi3mr_repost_reply_buf(mrioc, reply_dma); 501023ab2a9SKashyap Desai num_op_reply++; 502023ab2a9SKashyap Desai 503023ab2a9SKashyap Desai if (++reply_ci == op_reply_q->num_replies) { 504023ab2a9SKashyap Desai reply_ci = 0; 505023ab2a9SKashyap Desai exp_phase ^= 1; 506023ab2a9SKashyap Desai } 507023ab2a9SKashyap Desai 508023ab2a9SKashyap Desai reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci); 509023ab2a9SKashyap Desai 510023ab2a9SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 511023ab2a9SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 512023ab2a9SKashyap Desai break; 513463429f8SKashyap Desai /* 514463429f8SKashyap Desai * Exit completion loop to avoid CPU lockup 515463429f8SKashyap Desai * Ensure remaining completion happens from threaded ISR. 516463429f8SKashyap Desai */ 517463429f8SKashyap Desai if (num_op_reply > mrioc->max_host_ios) { 518463429f8SKashyap Desai intr_info->op_reply_q->enable_irq_poll = true; 519463429f8SKashyap Desai break; 520463429f8SKashyap Desai } 521023ab2a9SKashyap Desai 522023ab2a9SKashyap Desai } while (1); 523023ab2a9SKashyap Desai 524023ab2a9SKashyap Desai writel(reply_ci, 525023ab2a9SKashyap Desai &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index); 526023ab2a9SKashyap Desai op_reply_q->ci = reply_ci; 527023ab2a9SKashyap Desai op_reply_q->ephase = exp_phase; 528023ab2a9SKashyap Desai 529463429f8SKashyap Desai atomic_dec(&op_reply_q->in_use); 530023ab2a9SKashyap Desai return num_op_reply; 531023ab2a9SKashyap Desai } 532023ab2a9SKashyap Desai 533824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata) 534824a1566SKashyap Desai { 535824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = privdata; 536824a1566SKashyap Desai struct mpi3mr_ioc *mrioc; 537824a1566SKashyap Desai u16 midx; 538463429f8SKashyap Desai u32 num_admin_replies = 0, num_op_reply = 0; 539824a1566SKashyap Desai 540824a1566SKashyap Desai if (!intr_info) 541824a1566SKashyap Desai return IRQ_NONE; 542824a1566SKashyap Desai 543824a1566SKashyap Desai mrioc = intr_info->mrioc; 544824a1566SKashyap Desai 545824a1566SKashyap Desai if (!mrioc->intr_enabled) 546824a1566SKashyap Desai return IRQ_NONE; 547824a1566SKashyap Desai 548824a1566SKashyap Desai midx = intr_info->msix_index; 549824a1566SKashyap Desai 550824a1566SKashyap Desai if (!midx) 551824a1566SKashyap Desai num_admin_replies = mpi3mr_process_admin_reply_q(mrioc); 552463429f8SKashyap Desai if (intr_info->op_reply_q) 553463429f8SKashyap Desai num_op_reply = mpi3mr_process_op_reply_q(mrioc, intr_info); 554824a1566SKashyap Desai 555463429f8SKashyap Desai if (num_admin_replies || num_op_reply) 556824a1566SKashyap Desai return IRQ_HANDLED; 557824a1566SKashyap Desai else 558824a1566SKashyap Desai return IRQ_NONE; 559824a1566SKashyap Desai } 560824a1566SKashyap Desai 561824a1566SKashyap Desai static irqreturn_t mpi3mr_isr(int irq, void *privdata) 562824a1566SKashyap Desai { 563824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = privdata; 564463429f8SKashyap Desai struct mpi3mr_ioc *mrioc; 565463429f8SKashyap Desai u16 midx; 566824a1566SKashyap Desai int ret; 567824a1566SKashyap Desai 568824a1566SKashyap Desai if (!intr_info) 569824a1566SKashyap Desai return IRQ_NONE; 570824a1566SKashyap Desai 571463429f8SKashyap Desai mrioc = intr_info->mrioc; 572463429f8SKashyap Desai midx = intr_info->msix_index; 573824a1566SKashyap Desai /* Call primary ISR routine */ 574824a1566SKashyap Desai ret = mpi3mr_isr_primary(irq, privdata); 575824a1566SKashyap Desai 576463429f8SKashyap Desai /* 577463429f8SKashyap Desai * If more IOs are expected, schedule IRQ polling thread. 578463429f8SKashyap Desai * Otherwise exit from ISR. 579463429f8SKashyap Desai */ 580463429f8SKashyap Desai if (!intr_info->op_reply_q) 581824a1566SKashyap Desai return ret; 582463429f8SKashyap Desai 583463429f8SKashyap Desai if (!intr_info->op_reply_q->enable_irq_poll || 584463429f8SKashyap Desai !atomic_read(&intr_info->op_reply_q->pend_ios)) 585463429f8SKashyap Desai return ret; 586463429f8SKashyap Desai 587463429f8SKashyap Desai disable_irq_nosync(pci_irq_vector(mrioc->pdev, midx)); 588463429f8SKashyap Desai 589463429f8SKashyap Desai return IRQ_WAKE_THREAD; 590824a1566SKashyap Desai } 591824a1566SKashyap Desai 592824a1566SKashyap Desai /** 593824a1566SKashyap Desai * mpi3mr_isr_poll - Reply queue polling routine 594824a1566SKashyap Desai * @irq: IRQ 595824a1566SKashyap Desai * @privdata: Interrupt info 596824a1566SKashyap Desai * 597824a1566SKashyap Desai * poll for pending I/O completions in a loop until pending I/Os 598824a1566SKashyap Desai * present or controller queue depth I/Os are processed. 599824a1566SKashyap Desai * 600824a1566SKashyap Desai * Return: IRQ_NONE or IRQ_HANDLED 601824a1566SKashyap Desai */ 602824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata) 603824a1566SKashyap Desai { 604463429f8SKashyap Desai struct mpi3mr_intr_info *intr_info = privdata; 605463429f8SKashyap Desai struct mpi3mr_ioc *mrioc; 606463429f8SKashyap Desai u16 midx; 607463429f8SKashyap Desai u32 num_op_reply = 0; 608463429f8SKashyap Desai 609463429f8SKashyap Desai if (!intr_info || !intr_info->op_reply_q) 610463429f8SKashyap Desai return IRQ_NONE; 611463429f8SKashyap Desai 612463429f8SKashyap Desai mrioc = intr_info->mrioc; 613463429f8SKashyap Desai midx = intr_info->msix_index; 614463429f8SKashyap Desai 615463429f8SKashyap Desai /* Poll for pending IOs completions */ 616463429f8SKashyap Desai do { 617463429f8SKashyap Desai if (!mrioc->intr_enabled) 618463429f8SKashyap Desai break; 619463429f8SKashyap Desai 620463429f8SKashyap Desai if (!midx) 621463429f8SKashyap Desai mpi3mr_process_admin_reply_q(mrioc); 622463429f8SKashyap Desai if (intr_info->op_reply_q) 623463429f8SKashyap Desai num_op_reply += 624463429f8SKashyap Desai mpi3mr_process_op_reply_q(mrioc, intr_info); 625463429f8SKashyap Desai 626463429f8SKashyap Desai usleep_range(mrioc->irqpoll_sleep, 10 * mrioc->irqpoll_sleep); 627463429f8SKashyap Desai 628463429f8SKashyap Desai } while (atomic_read(&intr_info->op_reply_q->pend_ios) && 629463429f8SKashyap Desai (num_op_reply < mrioc->max_host_ios)); 630463429f8SKashyap Desai 631463429f8SKashyap Desai intr_info->op_reply_q->enable_irq_poll = false; 632463429f8SKashyap Desai enable_irq(pci_irq_vector(mrioc->pdev, midx)); 633463429f8SKashyap Desai 634824a1566SKashyap Desai return IRQ_HANDLED; 635824a1566SKashyap Desai } 636824a1566SKashyap Desai 637824a1566SKashyap Desai /** 638824a1566SKashyap Desai * mpi3mr_request_irq - Request IRQ and register ISR 639824a1566SKashyap Desai * @mrioc: Adapter instance reference 640824a1566SKashyap Desai * @index: IRQ vector index 641824a1566SKashyap Desai * 642824a1566SKashyap Desai * Request threaded ISR with primary ISR and secondary 643824a1566SKashyap Desai * 644824a1566SKashyap Desai * Return: 0 on success and non zero on failures. 645824a1566SKashyap Desai */ 646824a1566SKashyap Desai static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index) 647824a1566SKashyap Desai { 648824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 649824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index; 650824a1566SKashyap Desai int retval = 0; 651824a1566SKashyap Desai 652824a1566SKashyap Desai intr_info->mrioc = mrioc; 653824a1566SKashyap Desai intr_info->msix_index = index; 654824a1566SKashyap Desai intr_info->op_reply_q = NULL; 655824a1566SKashyap Desai 656824a1566SKashyap Desai snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d", 657824a1566SKashyap Desai mrioc->driver_name, mrioc->id, index); 658824a1566SKashyap Desai 659824a1566SKashyap Desai retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr, 660824a1566SKashyap Desai mpi3mr_isr_poll, IRQF_SHARED, intr_info->name, intr_info); 661824a1566SKashyap Desai if (retval) { 662824a1566SKashyap Desai ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n", 663824a1566SKashyap Desai intr_info->name, pci_irq_vector(pdev, index)); 664824a1566SKashyap Desai return retval; 665824a1566SKashyap Desai } 666824a1566SKashyap Desai 667824a1566SKashyap Desai return retval; 668824a1566SKashyap Desai } 669824a1566SKashyap Desai 670824a1566SKashyap Desai /** 671824a1566SKashyap Desai * mpi3mr_setup_isr - Setup ISR for the controller 672824a1566SKashyap Desai * @mrioc: Adapter instance reference 673824a1566SKashyap Desai * @setup_one: Request one IRQ or more 674824a1566SKashyap Desai * 675824a1566SKashyap Desai * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR 676824a1566SKashyap Desai * 677824a1566SKashyap Desai * Return: 0 on success and non zero on failures. 678824a1566SKashyap Desai */ 679824a1566SKashyap Desai static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one) 680824a1566SKashyap Desai { 681824a1566SKashyap Desai unsigned int irq_flags = PCI_IRQ_MSIX; 6822938beddSDan Carpenter int max_vectors; 6832938beddSDan Carpenter int retval; 6842938beddSDan Carpenter int i; 685824a1566SKashyap Desai struct irq_affinity desc = { .pre_vectors = 1}; 686824a1566SKashyap Desai 687fe6db615SSreekanth Reddy if (mrioc->is_intr_info_set) 688fe6db615SSreekanth Reddy return 0; 689fe6db615SSreekanth Reddy 690824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 691824a1566SKashyap Desai 692824a1566SKashyap Desai if (setup_one || reset_devices) 693824a1566SKashyap Desai max_vectors = 1; 694824a1566SKashyap Desai else { 695824a1566SKashyap Desai max_vectors = 696824a1566SKashyap Desai min_t(int, mrioc->cpu_count + 1, mrioc->msix_count); 697824a1566SKashyap Desai 698824a1566SKashyap Desai ioc_info(mrioc, 699824a1566SKashyap Desai "MSI-X vectors supported: %d, no of cores: %d,", 700824a1566SKashyap Desai mrioc->msix_count, mrioc->cpu_count); 701824a1566SKashyap Desai ioc_info(mrioc, 702824a1566SKashyap Desai "MSI-x vectors requested: %d\n", max_vectors); 703824a1566SKashyap Desai } 704824a1566SKashyap Desai 705824a1566SKashyap Desai irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES; 706824a1566SKashyap Desai 707c9566231SKashyap Desai mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0; 7082938beddSDan Carpenter retval = pci_alloc_irq_vectors_affinity(mrioc->pdev, 709824a1566SKashyap Desai 1, max_vectors, irq_flags, &desc); 7102938beddSDan Carpenter if (retval < 0) { 711824a1566SKashyap Desai ioc_err(mrioc, "Cannot alloc irq vectors\n"); 712824a1566SKashyap Desai goto out_failed; 713824a1566SKashyap Desai } 7142938beddSDan Carpenter if (retval != max_vectors) { 715824a1566SKashyap Desai ioc_info(mrioc, 716824a1566SKashyap Desai "allocated vectors (%d) are less than configured (%d)\n", 7172938beddSDan Carpenter retval, max_vectors); 718c9566231SKashyap Desai /* 719c9566231SKashyap Desai * If only one MSI-x is allocated, then MSI-x 0 will be shared 720c9566231SKashyap Desai * between Admin queue and operational queue 721c9566231SKashyap Desai */ 7222938beddSDan Carpenter if (retval == 1) 723c9566231SKashyap Desai mrioc->op_reply_q_offset = 0; 724824a1566SKashyap Desai 7252938beddSDan Carpenter max_vectors = retval; 726824a1566SKashyap Desai } 727824a1566SKashyap Desai mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info) * max_vectors, 728824a1566SKashyap Desai GFP_KERNEL); 729824a1566SKashyap Desai if (!mrioc->intr_info) { 7302938beddSDan Carpenter retval = -ENOMEM; 731824a1566SKashyap Desai pci_free_irq_vectors(mrioc->pdev); 732824a1566SKashyap Desai goto out_failed; 733824a1566SKashyap Desai } 734824a1566SKashyap Desai for (i = 0; i < max_vectors; i++) { 735824a1566SKashyap Desai retval = mpi3mr_request_irq(mrioc, i); 736824a1566SKashyap Desai if (retval) { 737824a1566SKashyap Desai mrioc->intr_info_count = i; 738824a1566SKashyap Desai goto out_failed; 739824a1566SKashyap Desai } 740824a1566SKashyap Desai } 741fe6db615SSreekanth Reddy if (reset_devices || !setup_one) 742fe6db615SSreekanth Reddy mrioc->is_intr_info_set = true; 743824a1566SKashyap Desai mrioc->intr_info_count = max_vectors; 744824a1566SKashyap Desai mpi3mr_ioc_enable_intr(mrioc); 7452938beddSDan Carpenter return 0; 7462938beddSDan Carpenter 747824a1566SKashyap Desai out_failed: 748824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 749824a1566SKashyap Desai 750824a1566SKashyap Desai return retval; 751824a1566SKashyap Desai } 752824a1566SKashyap Desai 753824a1566SKashyap Desai static const struct { 754824a1566SKashyap Desai enum mpi3mr_iocstate value; 755824a1566SKashyap Desai char *name; 756824a1566SKashyap Desai } mrioc_states[] = { 757824a1566SKashyap Desai { MRIOC_STATE_READY, "ready" }, 758824a1566SKashyap Desai { MRIOC_STATE_FAULT, "fault" }, 759824a1566SKashyap Desai { MRIOC_STATE_RESET, "reset" }, 760824a1566SKashyap Desai { MRIOC_STATE_BECOMING_READY, "becoming ready" }, 761824a1566SKashyap Desai { MRIOC_STATE_RESET_REQUESTED, "reset requested" }, 762824a1566SKashyap Desai { MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" }, 763824a1566SKashyap Desai }; 764824a1566SKashyap Desai 765824a1566SKashyap Desai static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state) 766824a1566SKashyap Desai { 767824a1566SKashyap Desai int i; 768824a1566SKashyap Desai char *name = NULL; 769824a1566SKashyap Desai 770824a1566SKashyap Desai for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) { 771824a1566SKashyap Desai if (mrioc_states[i].value == mrioc_state) { 772824a1566SKashyap Desai name = mrioc_states[i].name; 773824a1566SKashyap Desai break; 774824a1566SKashyap Desai } 775824a1566SKashyap Desai } 776824a1566SKashyap Desai return name; 777824a1566SKashyap Desai } 778824a1566SKashyap Desai 779f061178eSKashyap Desai /* Reset reason to name mapper structure*/ 780f061178eSKashyap Desai static const struct { 781f061178eSKashyap Desai enum mpi3mr_reset_reason value; 782f061178eSKashyap Desai char *name; 783f061178eSKashyap Desai } mpi3mr_reset_reason_codes[] = { 784f061178eSKashyap Desai { MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" }, 785f061178eSKashyap Desai { MPI3MR_RESET_FROM_FAULT_WATCH, "fault" }, 786f061178eSKashyap Desai { MPI3MR_RESET_FROM_IOCTL, "application invocation" }, 787f061178eSKashyap Desai { MPI3MR_RESET_FROM_EH_HOS, "error handling" }, 788f061178eSKashyap Desai { MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" }, 789f061178eSKashyap Desai { MPI3MR_RESET_FROM_IOCTL_TIMEOUT, "IOCTL timeout" }, 790f061178eSKashyap Desai { MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" }, 791f061178eSKashyap Desai { MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" }, 792f061178eSKashyap Desai { MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" }, 793f061178eSKashyap Desai { MPI3MR_RESET_FROM_PE_TIMEOUT, "port enable timeout" }, 794f061178eSKashyap Desai { MPI3MR_RESET_FROM_TSU_TIMEOUT, "time stamp update timeout" }, 795f061178eSKashyap Desai { MPI3MR_RESET_FROM_DELREQQ_TIMEOUT, "delete request queue timeout" }, 796f061178eSKashyap Desai { MPI3MR_RESET_FROM_DELREPQ_TIMEOUT, "delete reply queue timeout" }, 797f061178eSKashyap Desai { 798f061178eSKashyap Desai MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT, 799f061178eSKashyap Desai "create request queue timeout" 800f061178eSKashyap Desai }, 801f061178eSKashyap Desai { 802f061178eSKashyap Desai MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT, 803f061178eSKashyap Desai "create reply queue timeout" 804f061178eSKashyap Desai }, 805f061178eSKashyap Desai { MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT, "IOC facts timeout" }, 806f061178eSKashyap Desai { MPI3MR_RESET_FROM_IOCINIT_TIMEOUT, "IOC init timeout" }, 807f061178eSKashyap Desai { MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT, "event notify timeout" }, 808f061178eSKashyap Desai { MPI3MR_RESET_FROM_EVTACK_TIMEOUT, "event acknowledgment timeout" }, 809f061178eSKashyap Desai { 810f061178eSKashyap Desai MPI3MR_RESET_FROM_CIACTVRST_TIMER, 811f061178eSKashyap Desai "component image activation timeout" 812f061178eSKashyap Desai }, 813f061178eSKashyap Desai { 814f061178eSKashyap Desai MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT, 815f061178eSKashyap Desai "get package version timeout" 816f061178eSKashyap Desai }, 817f061178eSKashyap Desai { MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" }, 818f061178eSKashyap Desai { MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" }, 819b64845a7SSreekanth Reddy { MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronus reset" }, 820f061178eSKashyap Desai }; 821f061178eSKashyap Desai 822f061178eSKashyap Desai /** 823f061178eSKashyap Desai * mpi3mr_reset_rc_name - get reset reason code name 824f061178eSKashyap Desai * @reason_code: reset reason code value 825f061178eSKashyap Desai * 826f061178eSKashyap Desai * Map reset reason to an NULL terminated ASCII string 827f061178eSKashyap Desai * 828f061178eSKashyap Desai * Return: name corresponding to reset reason value or NULL. 829f061178eSKashyap Desai */ 830f061178eSKashyap Desai static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code) 831f061178eSKashyap Desai { 832f061178eSKashyap Desai int i; 833f061178eSKashyap Desai char *name = NULL; 834f061178eSKashyap Desai 835f061178eSKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_reason_codes); i++) { 836f061178eSKashyap Desai if (mpi3mr_reset_reason_codes[i].value == reason_code) { 837f061178eSKashyap Desai name = mpi3mr_reset_reason_codes[i].name; 838f061178eSKashyap Desai break; 839f061178eSKashyap Desai } 840f061178eSKashyap Desai } 841f061178eSKashyap Desai return name; 842f061178eSKashyap Desai } 843f061178eSKashyap Desai 844f061178eSKashyap Desai /* Reset type to name mapper structure*/ 845f061178eSKashyap Desai static const struct { 846f061178eSKashyap Desai u16 reset_type; 847f061178eSKashyap Desai char *name; 848f061178eSKashyap Desai } mpi3mr_reset_types[] = { 849f061178eSKashyap Desai { MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, "soft" }, 850f061178eSKashyap Desai { MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, "diag fault" }, 851f061178eSKashyap Desai }; 852f061178eSKashyap Desai 853f061178eSKashyap Desai /** 854f061178eSKashyap Desai * mpi3mr_reset_type_name - get reset type name 855f061178eSKashyap Desai * @reset_type: reset type value 856f061178eSKashyap Desai * 857f061178eSKashyap Desai * Map reset type to an NULL terminated ASCII string 858f061178eSKashyap Desai * 859f061178eSKashyap Desai * Return: name corresponding to reset type value or NULL. 860f061178eSKashyap Desai */ 861f061178eSKashyap Desai static const char *mpi3mr_reset_type_name(u16 reset_type) 862f061178eSKashyap Desai { 863f061178eSKashyap Desai int i; 864f061178eSKashyap Desai char *name = NULL; 865f061178eSKashyap Desai 866f061178eSKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_types); i++) { 867f061178eSKashyap Desai if (mpi3mr_reset_types[i].reset_type == reset_type) { 868f061178eSKashyap Desai name = mpi3mr_reset_types[i].name; 869f061178eSKashyap Desai break; 870f061178eSKashyap Desai } 871f061178eSKashyap Desai } 872f061178eSKashyap Desai return name; 873f061178eSKashyap Desai } 874f061178eSKashyap Desai 875824a1566SKashyap Desai /** 876824a1566SKashyap Desai * mpi3mr_print_fault_info - Display fault information 877824a1566SKashyap Desai * @mrioc: Adapter instance reference 878824a1566SKashyap Desai * 879824a1566SKashyap Desai * Display the controller fault information if there is a 880824a1566SKashyap Desai * controller fault. 881824a1566SKashyap Desai * 882824a1566SKashyap Desai * Return: Nothing. 883824a1566SKashyap Desai */ 884b64845a7SSreekanth Reddy void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc) 885824a1566SKashyap Desai { 886824a1566SKashyap Desai u32 ioc_status, code, code1, code2, code3; 887824a1566SKashyap Desai 888824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 889824a1566SKashyap Desai 890824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { 891824a1566SKashyap Desai code = readl(&mrioc->sysif_regs->fault); 892824a1566SKashyap Desai code1 = readl(&mrioc->sysif_regs->fault_info[0]); 893824a1566SKashyap Desai code2 = readl(&mrioc->sysif_regs->fault_info[1]); 894824a1566SKashyap Desai code3 = readl(&mrioc->sysif_regs->fault_info[2]); 895824a1566SKashyap Desai 896824a1566SKashyap Desai ioc_info(mrioc, 897824a1566SKashyap Desai "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n", 898824a1566SKashyap Desai code, code1, code2, code3); 899824a1566SKashyap Desai } 900824a1566SKashyap Desai } 901824a1566SKashyap Desai 902824a1566SKashyap Desai /** 903824a1566SKashyap Desai * mpi3mr_get_iocstate - Get IOC State 904824a1566SKashyap Desai * @mrioc: Adapter instance reference 905824a1566SKashyap Desai * 906824a1566SKashyap Desai * Return a proper IOC state enum based on the IOC status and 907824a1566SKashyap Desai * IOC configuration and unrcoverable state of the controller. 908824a1566SKashyap Desai * 909824a1566SKashyap Desai * Return: Current IOC state. 910824a1566SKashyap Desai */ 911824a1566SKashyap Desai enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc) 912824a1566SKashyap Desai { 913824a1566SKashyap Desai u32 ioc_status, ioc_config; 914824a1566SKashyap Desai u8 ready, enabled; 915824a1566SKashyap Desai 916824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 917824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 918824a1566SKashyap Desai 919824a1566SKashyap Desai if (mrioc->unrecoverable) 920824a1566SKashyap Desai return MRIOC_STATE_UNRECOVERABLE; 921824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) 922824a1566SKashyap Desai return MRIOC_STATE_FAULT; 923824a1566SKashyap Desai 924824a1566SKashyap Desai ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY); 925824a1566SKashyap Desai enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC); 926824a1566SKashyap Desai 927824a1566SKashyap Desai if (ready && enabled) 928824a1566SKashyap Desai return MRIOC_STATE_READY; 929824a1566SKashyap Desai if ((!ready) && (!enabled)) 930824a1566SKashyap Desai return MRIOC_STATE_RESET; 931824a1566SKashyap Desai if ((!ready) && (enabled)) 932824a1566SKashyap Desai return MRIOC_STATE_BECOMING_READY; 933824a1566SKashyap Desai 934824a1566SKashyap Desai return MRIOC_STATE_RESET_REQUESTED; 935824a1566SKashyap Desai } 936824a1566SKashyap Desai 937824a1566SKashyap Desai /** 938824a1566SKashyap Desai * mpi3mr_clear_reset_history - clear reset history 939824a1566SKashyap Desai * @mrioc: Adapter instance reference 940824a1566SKashyap Desai * 941824a1566SKashyap Desai * Write the reset history bit in IOC status to clear the bit, 942824a1566SKashyap Desai * if it is already set. 943824a1566SKashyap Desai * 944824a1566SKashyap Desai * Return: Nothing. 945824a1566SKashyap Desai */ 946824a1566SKashyap Desai static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc) 947824a1566SKashyap Desai { 948824a1566SKashyap Desai u32 ioc_status; 949824a1566SKashyap Desai 950824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 951824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) 952824a1566SKashyap Desai writel(ioc_status, &mrioc->sysif_regs->ioc_status); 953824a1566SKashyap Desai } 954824a1566SKashyap Desai 955824a1566SKashyap Desai /** 956824a1566SKashyap Desai * mpi3mr_issue_and_process_mur - Message unit Reset handler 957824a1566SKashyap Desai * @mrioc: Adapter instance reference 958824a1566SKashyap Desai * @reset_reason: Reset reason code 959824a1566SKashyap Desai * 960824a1566SKashyap Desai * Issue Message unit Reset to the controller and wait for it to 961824a1566SKashyap Desai * be complete. 962824a1566SKashyap Desai * 963824a1566SKashyap Desai * Return: 0 on success, -1 on failure. 964824a1566SKashyap Desai */ 965824a1566SKashyap Desai static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc, 966824a1566SKashyap Desai u32 reset_reason) 967824a1566SKashyap Desai { 968824a1566SKashyap Desai u32 ioc_config, timeout, ioc_status; 969824a1566SKashyap Desai int retval = -1; 970824a1566SKashyap Desai 971824a1566SKashyap Desai ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n"); 972824a1566SKashyap Desai if (mrioc->unrecoverable) { 973824a1566SKashyap Desai ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n"); 974824a1566SKashyap Desai return retval; 975824a1566SKashyap Desai } 976824a1566SKashyap Desai mpi3mr_clear_reset_history(mrioc); 977824a1566SKashyap Desai writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); 978824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 979824a1566SKashyap Desai ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; 980824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 981824a1566SKashyap Desai 982b64845a7SSreekanth Reddy timeout = MPI3MR_RESET_ACK_TIMEOUT * 10; 983824a1566SKashyap Desai do { 984824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 985824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) { 986824a1566SKashyap Desai mpi3mr_clear_reset_history(mrioc); 987824a1566SKashyap Desai break; 988824a1566SKashyap Desai } 989b64845a7SSreekanth Reddy if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { 990b64845a7SSreekanth Reddy mpi3mr_print_fault_info(mrioc); 991b64845a7SSreekanth Reddy break; 992824a1566SKashyap Desai } 993824a1566SKashyap Desai msleep(100); 994824a1566SKashyap Desai } while (--timeout); 995824a1566SKashyap Desai 996824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 997b64845a7SSreekanth Reddy if (timeout && !((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || 998b64845a7SSreekanth Reddy (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) || 999b64845a7SSreekanth Reddy (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) 1000b64845a7SSreekanth Reddy retval = 0; 1001824a1566SKashyap Desai 1002824a1566SKashyap Desai ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n", 1003824a1566SKashyap Desai (!retval) ? "successful" : "failed", ioc_status, ioc_config); 1004824a1566SKashyap Desai return retval; 1005824a1566SKashyap Desai } 1006824a1566SKashyap Desai 1007824a1566SKashyap Desai /** 1008c5758fc7SSreekanth Reddy * mpi3mr_revalidate_factsdata - validate IOCFacts parameters 1009c5758fc7SSreekanth Reddy * during reset/resume 1010c5758fc7SSreekanth Reddy * @mrioc: Adapter instance reference 1011c5758fc7SSreekanth Reddy * 1012c5758fc7SSreekanth Reddy * Return zero if the new IOCFacts parameters value is compatible with 1013c5758fc7SSreekanth Reddy * older values else return -EPERM 1014c5758fc7SSreekanth Reddy */ 1015c5758fc7SSreekanth Reddy static int 1016c5758fc7SSreekanth Reddy mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc) 1017c5758fc7SSreekanth Reddy { 1018c5758fc7SSreekanth Reddy u16 dev_handle_bitmap_sz; 1019c5758fc7SSreekanth Reddy void *removepend_bitmap; 1020c5758fc7SSreekanth Reddy 1021c5758fc7SSreekanth Reddy if (mrioc->facts.reply_sz > mrioc->reply_sz) { 1022c5758fc7SSreekanth Reddy ioc_err(mrioc, 1023c5758fc7SSreekanth Reddy "cannot increase reply size from %d to %d\n", 1024c5758fc7SSreekanth Reddy mrioc->reply_sz, mrioc->facts.reply_sz); 1025c5758fc7SSreekanth Reddy return -EPERM; 1026c5758fc7SSreekanth Reddy } 1027c5758fc7SSreekanth Reddy 1028c5758fc7SSreekanth Reddy if (mrioc->facts.max_op_reply_q < mrioc->num_op_reply_q) { 1029c5758fc7SSreekanth Reddy ioc_err(mrioc, 1030c5758fc7SSreekanth Reddy "cannot reduce number of operational reply queues from %d to %d\n", 1031c5758fc7SSreekanth Reddy mrioc->num_op_reply_q, 1032c5758fc7SSreekanth Reddy mrioc->facts.max_op_reply_q); 1033c5758fc7SSreekanth Reddy return -EPERM; 1034c5758fc7SSreekanth Reddy } 1035c5758fc7SSreekanth Reddy 1036c5758fc7SSreekanth Reddy if (mrioc->facts.max_op_req_q < mrioc->num_op_req_q) { 1037c5758fc7SSreekanth Reddy ioc_err(mrioc, 1038c5758fc7SSreekanth Reddy "cannot reduce number of operational request queues from %d to %d\n", 1039c5758fc7SSreekanth Reddy mrioc->num_op_req_q, mrioc->facts.max_op_req_q); 1040c5758fc7SSreekanth Reddy return -EPERM; 1041c5758fc7SSreekanth Reddy } 1042c5758fc7SSreekanth Reddy 1043c5758fc7SSreekanth Reddy dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8; 1044c5758fc7SSreekanth Reddy if (mrioc->facts.max_devhandle % 8) 1045c5758fc7SSreekanth Reddy dev_handle_bitmap_sz++; 1046c5758fc7SSreekanth Reddy if (dev_handle_bitmap_sz > mrioc->dev_handle_bitmap_sz) { 1047c5758fc7SSreekanth Reddy removepend_bitmap = krealloc(mrioc->removepend_bitmap, 1048c5758fc7SSreekanth Reddy dev_handle_bitmap_sz, GFP_KERNEL); 1049c5758fc7SSreekanth Reddy if (!removepend_bitmap) { 1050c5758fc7SSreekanth Reddy ioc_err(mrioc, 1051c5758fc7SSreekanth Reddy "failed to increase removepend_bitmap sz from: %d to %d\n", 1052c5758fc7SSreekanth Reddy mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz); 1053c5758fc7SSreekanth Reddy return -EPERM; 1054c5758fc7SSreekanth Reddy } 1055c5758fc7SSreekanth Reddy memset(removepend_bitmap + mrioc->dev_handle_bitmap_sz, 0, 1056c5758fc7SSreekanth Reddy dev_handle_bitmap_sz - mrioc->dev_handle_bitmap_sz); 1057c5758fc7SSreekanth Reddy mrioc->removepend_bitmap = removepend_bitmap; 1058c5758fc7SSreekanth Reddy ioc_info(mrioc, 1059c5758fc7SSreekanth Reddy "increased dev_handle_bitmap_sz from %d to %d\n", 1060c5758fc7SSreekanth Reddy mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz); 1061c5758fc7SSreekanth Reddy mrioc->dev_handle_bitmap_sz = dev_handle_bitmap_sz; 1062c5758fc7SSreekanth Reddy } 1063c5758fc7SSreekanth Reddy 1064c5758fc7SSreekanth Reddy return 0; 1065c5758fc7SSreekanth Reddy } 1066c5758fc7SSreekanth Reddy 1067c5758fc7SSreekanth Reddy /** 1068824a1566SKashyap Desai * mpi3mr_bring_ioc_ready - Bring controller to ready state 1069824a1566SKashyap Desai * @mrioc: Adapter instance reference 1070824a1566SKashyap Desai * 1071824a1566SKashyap Desai * Set Enable IOC bit in IOC configuration register and wait for 1072824a1566SKashyap Desai * the controller to become ready. 1073824a1566SKashyap Desai * 107459bd9cfeSSreekanth Reddy * Return: 0 on success, appropriate error on failure. 1075824a1566SKashyap Desai */ 1076824a1566SKashyap Desai static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) 1077824a1566SKashyap Desai { 107859bd9cfeSSreekanth Reddy u32 ioc_config, ioc_status, timeout; 107959bd9cfeSSreekanth Reddy int retval = 0; 108059bd9cfeSSreekanth Reddy enum mpi3mr_iocstate ioc_state; 108159bd9cfeSSreekanth Reddy u64 base_info; 1082824a1566SKashyap Desai 108359bd9cfeSSreekanth Reddy ioc_status = readl(&mrioc->sysif_regs->ioc_status); 108459bd9cfeSSreekanth Reddy ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 108559bd9cfeSSreekanth Reddy base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information); 108659bd9cfeSSreekanth Reddy ioc_info(mrioc, "ioc_status(0x%08x), ioc_config(0x%08x), ioc_info(0x%016llx) at the bringup\n", 108759bd9cfeSSreekanth Reddy ioc_status, ioc_config, base_info); 108859bd9cfeSSreekanth Reddy 108959bd9cfeSSreekanth Reddy /*The timeout value is in 2sec unit, changing it to seconds*/ 109059bd9cfeSSreekanth Reddy mrioc->ready_timeout = 109159bd9cfeSSreekanth Reddy ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >> 109259bd9cfeSSreekanth Reddy MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2; 109359bd9cfeSSreekanth Reddy 109459bd9cfeSSreekanth Reddy ioc_info(mrioc, "ready timeout: %d seconds\n", mrioc->ready_timeout); 109559bd9cfeSSreekanth Reddy 109659bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 109759bd9cfeSSreekanth Reddy ioc_info(mrioc, "controller is in %s state during detection\n", 109859bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 109959bd9cfeSSreekanth Reddy 110059bd9cfeSSreekanth Reddy if (ioc_state == MRIOC_STATE_BECOMING_READY || 110159bd9cfeSSreekanth Reddy ioc_state == MRIOC_STATE_RESET_REQUESTED) { 110259bd9cfeSSreekanth Reddy timeout = mrioc->ready_timeout * 10; 110359bd9cfeSSreekanth Reddy do { 110459bd9cfeSSreekanth Reddy msleep(100); 110559bd9cfeSSreekanth Reddy } while (--timeout); 110659bd9cfeSSreekanth Reddy 110759bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 110859bd9cfeSSreekanth Reddy ioc_info(mrioc, 110959bd9cfeSSreekanth Reddy "controller is in %s state after waiting to reset\n", 111059bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 111159bd9cfeSSreekanth Reddy } 111259bd9cfeSSreekanth Reddy 111359bd9cfeSSreekanth Reddy if (ioc_state == MRIOC_STATE_READY) { 111459bd9cfeSSreekanth Reddy ioc_info(mrioc, "issuing message unit reset (MUR) to bring to reset state\n"); 111559bd9cfeSSreekanth Reddy retval = mpi3mr_issue_and_process_mur(mrioc, 111659bd9cfeSSreekanth Reddy MPI3MR_RESET_FROM_BRINGUP); 111759bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 111859bd9cfeSSreekanth Reddy if (retval) 111959bd9cfeSSreekanth Reddy ioc_err(mrioc, 112059bd9cfeSSreekanth Reddy "message unit reset failed with error %d current state %s\n", 112159bd9cfeSSreekanth Reddy retval, mpi3mr_iocstate_name(ioc_state)); 112259bd9cfeSSreekanth Reddy } 112359bd9cfeSSreekanth Reddy if (ioc_state != MRIOC_STATE_RESET) { 112459bd9cfeSSreekanth Reddy mpi3mr_print_fault_info(mrioc); 112559bd9cfeSSreekanth Reddy ioc_info(mrioc, "issuing soft reset to bring to reset state\n"); 112659bd9cfeSSreekanth Reddy retval = mpi3mr_issue_reset(mrioc, 112759bd9cfeSSreekanth Reddy MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, 112859bd9cfeSSreekanth Reddy MPI3MR_RESET_FROM_BRINGUP); 112959bd9cfeSSreekanth Reddy if (retval) { 113059bd9cfeSSreekanth Reddy ioc_err(mrioc, 113159bd9cfeSSreekanth Reddy "soft reset failed with error %d\n", retval); 113259bd9cfeSSreekanth Reddy goto out_failed; 113359bd9cfeSSreekanth Reddy } 113459bd9cfeSSreekanth Reddy } 113559bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 113659bd9cfeSSreekanth Reddy if (ioc_state != MRIOC_STATE_RESET) { 113759bd9cfeSSreekanth Reddy ioc_err(mrioc, 113859bd9cfeSSreekanth Reddy "cannot bring controller to reset state, current state: %s\n", 113959bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 114059bd9cfeSSreekanth Reddy goto out_failed; 114159bd9cfeSSreekanth Reddy } 114259bd9cfeSSreekanth Reddy mpi3mr_clear_reset_history(mrioc); 114359bd9cfeSSreekanth Reddy retval = mpi3mr_setup_admin_qpair(mrioc); 114459bd9cfeSSreekanth Reddy if (retval) { 114559bd9cfeSSreekanth Reddy ioc_err(mrioc, "failed to setup admin queues: error %d\n", 114659bd9cfeSSreekanth Reddy retval); 114759bd9cfeSSreekanth Reddy goto out_failed; 114859bd9cfeSSreekanth Reddy } 114959bd9cfeSSreekanth Reddy 115059bd9cfeSSreekanth Reddy ioc_info(mrioc, "bringing controller to ready state\n"); 1151824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1152824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; 1153824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 1154824a1566SKashyap Desai 1155824a1566SKashyap Desai timeout = mrioc->ready_timeout * 10; 1156824a1566SKashyap Desai do { 115759bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 115859bd9cfeSSreekanth Reddy if (ioc_state == MRIOC_STATE_READY) { 115959bd9cfeSSreekanth Reddy ioc_info(mrioc, 116059bd9cfeSSreekanth Reddy "successfully transistioned to %s state\n", 116159bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 1162824a1566SKashyap Desai return 0; 116359bd9cfeSSreekanth Reddy } 1164824a1566SKashyap Desai msleep(100); 1165824a1566SKashyap Desai } while (--timeout); 1166824a1566SKashyap Desai 116759bd9cfeSSreekanth Reddy out_failed: 116859bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 116959bd9cfeSSreekanth Reddy ioc_err(mrioc, 117059bd9cfeSSreekanth Reddy "failed to bring to ready state, current state: %s\n", 117159bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 117259bd9cfeSSreekanth Reddy return retval; 1173824a1566SKashyap Desai } 1174824a1566SKashyap Desai 1175824a1566SKashyap Desai /** 1176f061178eSKashyap Desai * mpi3mr_soft_reset_success - Check softreset is success or not 1177f061178eSKashyap Desai * @ioc_status: IOC status register value 1178f061178eSKashyap Desai * @ioc_config: IOC config register value 1179f061178eSKashyap Desai * 1180f061178eSKashyap Desai * Check whether the soft reset is successful or not based on 1181f061178eSKashyap Desai * IOC status and IOC config register values. 1182f061178eSKashyap Desai * 1183f061178eSKashyap Desai * Return: True when the soft reset is success, false otherwise. 1184f061178eSKashyap Desai */ 1185f061178eSKashyap Desai static inline bool 1186f061178eSKashyap Desai mpi3mr_soft_reset_success(u32 ioc_status, u32 ioc_config) 1187f061178eSKashyap Desai { 1188f061178eSKashyap Desai if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || 1189f061178eSKashyap Desai (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) 1190f061178eSKashyap Desai return true; 1191f061178eSKashyap Desai return false; 1192f061178eSKashyap Desai } 1193f061178eSKashyap Desai 1194f061178eSKashyap Desai /** 1195f061178eSKashyap Desai * mpi3mr_diagfault_success - Check diag fault is success or not 1196f061178eSKashyap Desai * @mrioc: Adapter reference 1197f061178eSKashyap Desai * @ioc_status: IOC status register value 1198f061178eSKashyap Desai * 1199f061178eSKashyap Desai * Check whether the controller hit diag reset fault code. 1200f061178eSKashyap Desai * 1201f061178eSKashyap Desai * Return: True when there is diag fault, false otherwise. 1202f061178eSKashyap Desai */ 1203f061178eSKashyap Desai static inline bool mpi3mr_diagfault_success(struct mpi3mr_ioc *mrioc, 1204f061178eSKashyap Desai u32 ioc_status) 1205f061178eSKashyap Desai { 1206f061178eSKashyap Desai u32 fault; 1207f061178eSKashyap Desai 1208f061178eSKashyap Desai if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) 1209f061178eSKashyap Desai return false; 1210f061178eSKashyap Desai fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK; 1211b64845a7SSreekanth Reddy if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) { 1212b64845a7SSreekanth Reddy mpi3mr_print_fault_info(mrioc); 1213f061178eSKashyap Desai return true; 1214b64845a7SSreekanth Reddy } 1215f061178eSKashyap Desai return false; 1216f061178eSKashyap Desai } 1217f061178eSKashyap Desai 1218f061178eSKashyap Desai /** 1219824a1566SKashyap Desai * mpi3mr_set_diagsave - Set diag save bit for snapdump 1220824a1566SKashyap Desai * @mrioc: Adapter reference 1221824a1566SKashyap Desai * 1222824a1566SKashyap Desai * Set diag save bit in IOC configuration register to enable 1223824a1566SKashyap Desai * snapdump. 1224824a1566SKashyap Desai * 1225824a1566SKashyap Desai * Return: Nothing. 1226824a1566SKashyap Desai */ 1227824a1566SKashyap Desai static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc) 1228824a1566SKashyap Desai { 1229824a1566SKashyap Desai u32 ioc_config; 1230824a1566SKashyap Desai 1231824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1232824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE; 1233824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 1234824a1566SKashyap Desai } 1235824a1566SKashyap Desai 1236824a1566SKashyap Desai /** 1237824a1566SKashyap Desai * mpi3mr_issue_reset - Issue reset to the controller 1238824a1566SKashyap Desai * @mrioc: Adapter reference 1239824a1566SKashyap Desai * @reset_type: Reset type 1240824a1566SKashyap Desai * @reset_reason: Reset reason code 1241824a1566SKashyap Desai * 1242f061178eSKashyap Desai * Unlock the host diagnostic registers and write the specific 1243f061178eSKashyap Desai * reset type to that, wait for reset acknowledgment from the 1244f061178eSKashyap Desai * controller, if the reset is not successful retry for the 1245f061178eSKashyap Desai * predefined number of times. 1246824a1566SKashyap Desai * 1247824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 1248824a1566SKashyap Desai */ 1249824a1566SKashyap Desai static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, 1250824a1566SKashyap Desai u32 reset_reason) 1251824a1566SKashyap Desai { 1252f061178eSKashyap Desai int retval = -1; 1253b64845a7SSreekanth Reddy u8 unlock_retry_count = 0; 1254b64845a7SSreekanth Reddy u32 host_diagnostic, ioc_status, ioc_config; 1255b64845a7SSreekanth Reddy u32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10; 1256f061178eSKashyap Desai 1257f061178eSKashyap Desai if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) && 1258f061178eSKashyap Desai (reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT)) 1259b64845a7SSreekanth Reddy return retval; 1260f061178eSKashyap Desai if (mrioc->unrecoverable) 1261b64845a7SSreekanth Reddy return retval; 1262b64845a7SSreekanth Reddy if (reset_reason == MPI3MR_RESET_FROM_FIRMWARE) { 1263b64845a7SSreekanth Reddy retval = 0; 1264b64845a7SSreekanth Reddy return retval; 1265b64845a7SSreekanth Reddy } 1266b64845a7SSreekanth Reddy 1267b64845a7SSreekanth Reddy ioc_info(mrioc, "%s reset due to %s(0x%x)\n", 1268b64845a7SSreekanth Reddy mpi3mr_reset_type_name(reset_type), 1269b64845a7SSreekanth Reddy mpi3mr_reset_rc_name(reset_reason), reset_reason); 1270b64845a7SSreekanth Reddy 1271f061178eSKashyap Desai mpi3mr_clear_reset_history(mrioc); 1272f061178eSKashyap Desai do { 1273f061178eSKashyap Desai ioc_info(mrioc, 1274f061178eSKashyap Desai "Write magic sequence to unlock host diag register (retry=%d)\n", 1275f061178eSKashyap Desai ++unlock_retry_count); 1276f061178eSKashyap Desai if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) { 1277b64845a7SSreekanth Reddy ioc_err(mrioc, 1278b64845a7SSreekanth Reddy "%s reset failed due to unlock failure, host_diagnostic(0x%08x)\n", 1279b64845a7SSreekanth Reddy mpi3mr_reset_type_name(reset_type), 1280b64845a7SSreekanth Reddy host_diagnostic); 1281f061178eSKashyap Desai mrioc->unrecoverable = 1; 1282b64845a7SSreekanth Reddy return retval; 1283f061178eSKashyap Desai } 1284f061178eSKashyap Desai 1285f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH, 1286f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1287f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST, 1288f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1289f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND, 1290f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1291f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD, 1292f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1293f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH, 1294f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1295f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH, 1296f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1297f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH, 1298f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1299f061178eSKashyap Desai usleep_range(1000, 1100); 1300f061178eSKashyap Desai host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); 1301f061178eSKashyap Desai ioc_info(mrioc, 1302f061178eSKashyap Desai "wrote magic sequence: retry_count(%d), host_diagnostic(0x%08x)\n", 1303f061178eSKashyap Desai unlock_retry_count, host_diagnostic); 1304f061178eSKashyap Desai } while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE)); 1305f061178eSKashyap Desai 1306f061178eSKashyap Desai writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); 1307f061178eSKashyap Desai writel(host_diagnostic | reset_type, 1308f061178eSKashyap Desai &mrioc->sysif_regs->host_diagnostic); 1309b64845a7SSreekanth Reddy switch (reset_type) { 1310b64845a7SSreekanth Reddy case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET: 1311f061178eSKashyap Desai do { 1312f061178eSKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1313f061178eSKashyap Desai ioc_config = 1314f061178eSKashyap Desai readl(&mrioc->sysif_regs->ioc_configuration); 1315b64845a7SSreekanth Reddy if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) 1316b64845a7SSreekanth Reddy && mpi3mr_soft_reset_success(ioc_status, ioc_config) 1317b64845a7SSreekanth Reddy ) { 1318b64845a7SSreekanth Reddy mpi3mr_clear_reset_history(mrioc); 1319f061178eSKashyap Desai retval = 0; 1320f061178eSKashyap Desai break; 1321f061178eSKashyap Desai } 1322f061178eSKashyap Desai msleep(100); 1323f061178eSKashyap Desai } while (--timeout); 1324b64845a7SSreekanth Reddy mpi3mr_print_fault_info(mrioc); 1325b64845a7SSreekanth Reddy break; 1326b64845a7SSreekanth Reddy case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT: 1327f061178eSKashyap Desai do { 1328f061178eSKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1329f061178eSKashyap Desai if (mpi3mr_diagfault_success(mrioc, ioc_status)) { 1330f061178eSKashyap Desai retval = 0; 1331f061178eSKashyap Desai break; 1332f061178eSKashyap Desai } 1333f061178eSKashyap Desai msleep(100); 1334f061178eSKashyap Desai } while (--timeout); 1335b64845a7SSreekanth Reddy break; 1336b64845a7SSreekanth Reddy default: 1337b64845a7SSreekanth Reddy break; 1338b64845a7SSreekanth Reddy } 1339b64845a7SSreekanth Reddy 1340f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND, 1341f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1342f061178eSKashyap Desai 1343f061178eSKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1344b64845a7SSreekanth Reddy ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1345f061178eSKashyap Desai ioc_info(mrioc, 1346b64845a7SSreekanth Reddy "ioc_status/ioc_onfig after %s reset is (0x%x)/(0x%x)\n", 1347f061178eSKashyap Desai (!retval)?"successful":"failed", ioc_status, 1348f061178eSKashyap Desai ioc_config); 1349b64845a7SSreekanth Reddy if (retval) 1350b64845a7SSreekanth Reddy mrioc->unrecoverable = 1; 1351f061178eSKashyap Desai return retval; 1352824a1566SKashyap Desai } 1353824a1566SKashyap Desai 1354824a1566SKashyap Desai /** 1355824a1566SKashyap Desai * mpi3mr_admin_request_post - Post request to admin queue 1356824a1566SKashyap Desai * @mrioc: Adapter reference 1357824a1566SKashyap Desai * @admin_req: MPI3 request 1358824a1566SKashyap Desai * @admin_req_sz: Request size 1359824a1566SKashyap Desai * @ignore_reset: Ignore reset in process 1360824a1566SKashyap Desai * 1361824a1566SKashyap Desai * Post the MPI3 request into admin request queue and 1362824a1566SKashyap Desai * inform the controller, if the queue is full return 1363824a1566SKashyap Desai * appropriate error. 1364824a1566SKashyap Desai * 1365824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 1366824a1566SKashyap Desai */ 1367824a1566SKashyap Desai int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req, 1368824a1566SKashyap Desai u16 admin_req_sz, u8 ignore_reset) 1369824a1566SKashyap Desai { 1370824a1566SKashyap Desai u16 areq_pi = 0, areq_ci = 0, max_entries = 0; 1371824a1566SKashyap Desai int retval = 0; 1372824a1566SKashyap Desai unsigned long flags; 1373824a1566SKashyap Desai u8 *areq_entry; 1374824a1566SKashyap Desai 1375824a1566SKashyap Desai if (mrioc->unrecoverable) { 1376824a1566SKashyap Desai ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__); 1377824a1566SKashyap Desai return -EFAULT; 1378824a1566SKashyap Desai } 1379824a1566SKashyap Desai 1380824a1566SKashyap Desai spin_lock_irqsave(&mrioc->admin_req_lock, flags); 1381824a1566SKashyap Desai areq_pi = mrioc->admin_req_pi; 1382824a1566SKashyap Desai areq_ci = mrioc->admin_req_ci; 1383824a1566SKashyap Desai max_entries = mrioc->num_admin_req; 1384824a1566SKashyap Desai if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) && 1385824a1566SKashyap Desai (areq_pi == (max_entries - 1)))) { 1386824a1566SKashyap Desai ioc_err(mrioc, "AdminReqQ full condition detected\n"); 1387824a1566SKashyap Desai retval = -EAGAIN; 1388824a1566SKashyap Desai goto out; 1389824a1566SKashyap Desai } 1390824a1566SKashyap Desai if (!ignore_reset && mrioc->reset_in_progress) { 1391824a1566SKashyap Desai ioc_err(mrioc, "AdminReqQ submit reset in progress\n"); 1392824a1566SKashyap Desai retval = -EAGAIN; 1393824a1566SKashyap Desai goto out; 1394824a1566SKashyap Desai } 1395824a1566SKashyap Desai areq_entry = (u8 *)mrioc->admin_req_base + 1396824a1566SKashyap Desai (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ); 1397824a1566SKashyap Desai memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ); 1398824a1566SKashyap Desai memcpy(areq_entry, (u8 *)admin_req, admin_req_sz); 1399824a1566SKashyap Desai 1400824a1566SKashyap Desai if (++areq_pi == max_entries) 1401824a1566SKashyap Desai areq_pi = 0; 1402824a1566SKashyap Desai mrioc->admin_req_pi = areq_pi; 1403824a1566SKashyap Desai 1404824a1566SKashyap Desai writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi); 1405824a1566SKashyap Desai 1406824a1566SKashyap Desai out: 1407824a1566SKashyap Desai spin_unlock_irqrestore(&mrioc->admin_req_lock, flags); 1408824a1566SKashyap Desai 1409824a1566SKashyap Desai return retval; 1410824a1566SKashyap Desai } 1411824a1566SKashyap Desai 1412824a1566SKashyap Desai /** 1413c9566231SKashyap Desai * mpi3mr_free_op_req_q_segments - free request memory segments 1414c9566231SKashyap Desai * @mrioc: Adapter instance reference 1415c9566231SKashyap Desai * @q_idx: operational request queue index 1416c9566231SKashyap Desai * 1417c9566231SKashyap Desai * Free memory segments allocated for operational request queue 1418c9566231SKashyap Desai * 1419c9566231SKashyap Desai * Return: Nothing. 1420c9566231SKashyap Desai */ 1421c9566231SKashyap Desai static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) 1422c9566231SKashyap Desai { 1423c9566231SKashyap Desai u16 j; 1424c9566231SKashyap Desai int size; 1425c9566231SKashyap Desai struct segments *segments; 1426c9566231SKashyap Desai 1427c9566231SKashyap Desai segments = mrioc->req_qinfo[q_idx].q_segments; 1428c9566231SKashyap Desai if (!segments) 1429c9566231SKashyap Desai return; 1430c9566231SKashyap Desai 1431c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1432c9566231SKashyap Desai size = MPI3MR_OP_REQ_Q_SEG_SIZE; 1433c9566231SKashyap Desai if (mrioc->req_qinfo[q_idx].q_segment_list) { 1434c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 1435c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, 1436c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segment_list, 1437c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segment_list_dma); 1438c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL; 1439c9566231SKashyap Desai } 1440c9566231SKashyap Desai } else 1441c9566231SKashyap Desai size = mrioc->req_qinfo[q_idx].num_requests * 1442c9566231SKashyap Desai mrioc->facts.op_req_sz; 1443c9566231SKashyap Desai 1444c9566231SKashyap Desai for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) { 1445c9566231SKashyap Desai if (!segments[j].segment) 1446c9566231SKashyap Desai continue; 1447c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 1448c9566231SKashyap Desai size, segments[j].segment, segments[j].segment_dma); 1449c9566231SKashyap Desai segments[j].segment = NULL; 1450c9566231SKashyap Desai } 1451c9566231SKashyap Desai kfree(mrioc->req_qinfo[q_idx].q_segments); 1452c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segments = NULL; 1453c9566231SKashyap Desai mrioc->req_qinfo[q_idx].qid = 0; 1454c9566231SKashyap Desai } 1455c9566231SKashyap Desai 1456c9566231SKashyap Desai /** 1457c9566231SKashyap Desai * mpi3mr_free_op_reply_q_segments - free reply memory segments 1458c9566231SKashyap Desai * @mrioc: Adapter instance reference 1459c9566231SKashyap Desai * @q_idx: operational reply queue index 1460c9566231SKashyap Desai * 1461c9566231SKashyap Desai * Free memory segments allocated for operational reply queue 1462c9566231SKashyap Desai * 1463c9566231SKashyap Desai * Return: Nothing. 1464c9566231SKashyap Desai */ 1465c9566231SKashyap Desai static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) 1466c9566231SKashyap Desai { 1467c9566231SKashyap Desai u16 j; 1468c9566231SKashyap Desai int size; 1469c9566231SKashyap Desai struct segments *segments; 1470c9566231SKashyap Desai 1471c9566231SKashyap Desai segments = mrioc->op_reply_qinfo[q_idx].q_segments; 1472c9566231SKashyap Desai if (!segments) 1473c9566231SKashyap Desai return; 1474c9566231SKashyap Desai 1475c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1476c9566231SKashyap Desai size = MPI3MR_OP_REP_Q_SEG_SIZE; 1477c9566231SKashyap Desai if (mrioc->op_reply_qinfo[q_idx].q_segment_list) { 1478c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 1479c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, 1480c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list, 1481c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list_dma); 1482c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL; 1483c9566231SKashyap Desai } 1484c9566231SKashyap Desai } else 1485c9566231SKashyap Desai size = mrioc->op_reply_qinfo[q_idx].segment_qd * 1486c9566231SKashyap Desai mrioc->op_reply_desc_sz; 1487c9566231SKashyap Desai 1488c9566231SKashyap Desai for (j = 0; j < mrioc->op_reply_qinfo[q_idx].num_segments; j++) { 1489c9566231SKashyap Desai if (!segments[j].segment) 1490c9566231SKashyap Desai continue; 1491c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 1492c9566231SKashyap Desai size, segments[j].segment, segments[j].segment_dma); 1493c9566231SKashyap Desai segments[j].segment = NULL; 1494c9566231SKashyap Desai } 1495c9566231SKashyap Desai 1496c9566231SKashyap Desai kfree(mrioc->op_reply_qinfo[q_idx].q_segments); 1497c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segments = NULL; 1498c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].qid = 0; 1499c9566231SKashyap Desai } 1500c9566231SKashyap Desai 1501c9566231SKashyap Desai /** 1502c9566231SKashyap Desai * mpi3mr_delete_op_reply_q - delete operational reply queue 1503c9566231SKashyap Desai * @mrioc: Adapter instance reference 1504c9566231SKashyap Desai * @qidx: operational reply queue index 1505c9566231SKashyap Desai * 1506c9566231SKashyap Desai * Delete operatinal reply queue by issuing MPI request 1507c9566231SKashyap Desai * through admin queue. 1508c9566231SKashyap Desai * 1509c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1510c9566231SKashyap Desai */ 1511c9566231SKashyap Desai static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) 1512c9566231SKashyap Desai { 1513c9566231SKashyap Desai struct mpi3_delete_reply_queue_request delq_req; 1514c9566231SKashyap Desai int retval = 0; 1515c9566231SKashyap Desai u16 reply_qid = 0, midx; 1516c9566231SKashyap Desai 1517c9566231SKashyap Desai reply_qid = mrioc->op_reply_qinfo[qidx].qid; 1518c9566231SKashyap Desai 1519c9566231SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset); 1520c9566231SKashyap Desai 1521c9566231SKashyap Desai if (!reply_qid) { 1522c9566231SKashyap Desai retval = -1; 1523c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: called with invalid ReqQID\n"); 1524c9566231SKashyap Desai goto out; 1525c9566231SKashyap Desai } 1526c9566231SKashyap Desai 1527c9566231SKashyap Desai memset(&delq_req, 0, sizeof(delq_req)); 1528c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1529c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1530c9566231SKashyap Desai retval = -1; 1531c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: Init command is in use\n"); 1532c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1533c9566231SKashyap Desai goto out; 1534c9566231SKashyap Desai } 1535c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1536c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1537c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 1538c9566231SKashyap Desai delq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1539c9566231SKashyap Desai delq_req.function = MPI3_FUNCTION_DELETE_REPLY_QUEUE; 1540c9566231SKashyap Desai delq_req.queue_id = cpu_to_le16(reply_qid); 1541c9566231SKashyap Desai 1542c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 1543c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &delq_req, sizeof(delq_req), 1544c9566231SKashyap Desai 1); 1545c9566231SKashyap Desai if (retval) { 1546c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: Admin Post failed\n"); 1547c9566231SKashyap Desai goto out_unlock; 1548c9566231SKashyap Desai } 1549c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1550c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1551c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1552a6856cc4SSreekanth Reddy ioc_err(mrioc, "delete reply queue timed out\n"); 1553a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 1554c9566231SKashyap Desai MPI3MR_RESET_FROM_DELREPQ_TIMEOUT); 1555c9566231SKashyap Desai retval = -1; 1556c9566231SKashyap Desai goto out_unlock; 1557c9566231SKashyap Desai } 1558c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1559c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1560c9566231SKashyap Desai ioc_err(mrioc, 1561c9566231SKashyap Desai "Issue DelRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1562c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1563c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 1564c9566231SKashyap Desai retval = -1; 1565c9566231SKashyap Desai goto out_unlock; 1566c9566231SKashyap Desai } 1567c9566231SKashyap Desai mrioc->intr_info[midx].op_reply_q = NULL; 1568c9566231SKashyap Desai 1569c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, qidx); 1570c9566231SKashyap Desai out_unlock: 1571c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 1572c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1573c9566231SKashyap Desai out: 1574c9566231SKashyap Desai 1575c9566231SKashyap Desai return retval; 1576c9566231SKashyap Desai } 1577c9566231SKashyap Desai 1578c9566231SKashyap Desai /** 1579c9566231SKashyap Desai * mpi3mr_alloc_op_reply_q_segments -Alloc segmented reply pool 1580c9566231SKashyap Desai * @mrioc: Adapter instance reference 1581c9566231SKashyap Desai * @qidx: request queue index 1582c9566231SKashyap Desai * 1583c9566231SKashyap Desai * Allocate segmented memory pools for operational reply 1584c9566231SKashyap Desai * queue. 1585c9566231SKashyap Desai * 1586c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1587c9566231SKashyap Desai */ 1588c9566231SKashyap Desai static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) 1589c9566231SKashyap Desai { 1590c9566231SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 1591c9566231SKashyap Desai int i, size; 1592c9566231SKashyap Desai u64 *q_segment_list_entry = NULL; 1593c9566231SKashyap Desai struct segments *segments; 1594c9566231SKashyap Desai 1595c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1596c9566231SKashyap Desai op_reply_q->segment_qd = 1597c9566231SKashyap Desai MPI3MR_OP_REP_Q_SEG_SIZE / mrioc->op_reply_desc_sz; 1598c9566231SKashyap Desai 1599c9566231SKashyap Desai size = MPI3MR_OP_REP_Q_SEG_SIZE; 1600c9566231SKashyap Desai 1601c9566231SKashyap Desai op_reply_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev, 1602c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, &op_reply_q->q_segment_list_dma, 1603c9566231SKashyap Desai GFP_KERNEL); 1604c9566231SKashyap Desai if (!op_reply_q->q_segment_list) 1605c9566231SKashyap Desai return -ENOMEM; 1606c9566231SKashyap Desai q_segment_list_entry = (u64 *)op_reply_q->q_segment_list; 1607c9566231SKashyap Desai } else { 1608c9566231SKashyap Desai op_reply_q->segment_qd = op_reply_q->num_replies; 1609c9566231SKashyap Desai size = op_reply_q->num_replies * mrioc->op_reply_desc_sz; 1610c9566231SKashyap Desai } 1611c9566231SKashyap Desai 1612c9566231SKashyap Desai op_reply_q->num_segments = DIV_ROUND_UP(op_reply_q->num_replies, 1613c9566231SKashyap Desai op_reply_q->segment_qd); 1614c9566231SKashyap Desai 1615c9566231SKashyap Desai op_reply_q->q_segments = kcalloc(op_reply_q->num_segments, 1616c9566231SKashyap Desai sizeof(struct segments), GFP_KERNEL); 1617c9566231SKashyap Desai if (!op_reply_q->q_segments) 1618c9566231SKashyap Desai return -ENOMEM; 1619c9566231SKashyap Desai 1620c9566231SKashyap Desai segments = op_reply_q->q_segments; 1621c9566231SKashyap Desai for (i = 0; i < op_reply_q->num_segments; i++) { 1622c9566231SKashyap Desai segments[i].segment = 1623c9566231SKashyap Desai dma_alloc_coherent(&mrioc->pdev->dev, 1624c9566231SKashyap Desai size, &segments[i].segment_dma, GFP_KERNEL); 1625c9566231SKashyap Desai if (!segments[i].segment) 1626c9566231SKashyap Desai return -ENOMEM; 1627c9566231SKashyap Desai if (mrioc->enable_segqueue) 1628c9566231SKashyap Desai q_segment_list_entry[i] = 1629c9566231SKashyap Desai (unsigned long)segments[i].segment_dma; 1630c9566231SKashyap Desai } 1631c9566231SKashyap Desai 1632c9566231SKashyap Desai return 0; 1633c9566231SKashyap Desai } 1634c9566231SKashyap Desai 1635c9566231SKashyap Desai /** 1636c9566231SKashyap Desai * mpi3mr_alloc_op_req_q_segments - Alloc segmented req pool. 1637c9566231SKashyap Desai * @mrioc: Adapter instance reference 1638c9566231SKashyap Desai * @qidx: request queue index 1639c9566231SKashyap Desai * 1640c9566231SKashyap Desai * Allocate segmented memory pools for operational request 1641c9566231SKashyap Desai * queue. 1642c9566231SKashyap Desai * 1643c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1644c9566231SKashyap Desai */ 1645c9566231SKashyap Desai static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) 1646c9566231SKashyap Desai { 1647c9566231SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx; 1648c9566231SKashyap Desai int i, size; 1649c9566231SKashyap Desai u64 *q_segment_list_entry = NULL; 1650c9566231SKashyap Desai struct segments *segments; 1651c9566231SKashyap Desai 1652c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1653c9566231SKashyap Desai op_req_q->segment_qd = 1654c9566231SKashyap Desai MPI3MR_OP_REQ_Q_SEG_SIZE / mrioc->facts.op_req_sz; 1655c9566231SKashyap Desai 1656c9566231SKashyap Desai size = MPI3MR_OP_REQ_Q_SEG_SIZE; 1657c9566231SKashyap Desai 1658c9566231SKashyap Desai op_req_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev, 1659c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, &op_req_q->q_segment_list_dma, 1660c9566231SKashyap Desai GFP_KERNEL); 1661c9566231SKashyap Desai if (!op_req_q->q_segment_list) 1662c9566231SKashyap Desai return -ENOMEM; 1663c9566231SKashyap Desai q_segment_list_entry = (u64 *)op_req_q->q_segment_list; 1664c9566231SKashyap Desai 1665c9566231SKashyap Desai } else { 1666c9566231SKashyap Desai op_req_q->segment_qd = op_req_q->num_requests; 1667c9566231SKashyap Desai size = op_req_q->num_requests * mrioc->facts.op_req_sz; 1668c9566231SKashyap Desai } 1669c9566231SKashyap Desai 1670c9566231SKashyap Desai op_req_q->num_segments = DIV_ROUND_UP(op_req_q->num_requests, 1671c9566231SKashyap Desai op_req_q->segment_qd); 1672c9566231SKashyap Desai 1673c9566231SKashyap Desai op_req_q->q_segments = kcalloc(op_req_q->num_segments, 1674c9566231SKashyap Desai sizeof(struct segments), GFP_KERNEL); 1675c9566231SKashyap Desai if (!op_req_q->q_segments) 1676c9566231SKashyap Desai return -ENOMEM; 1677c9566231SKashyap Desai 1678c9566231SKashyap Desai segments = op_req_q->q_segments; 1679c9566231SKashyap Desai for (i = 0; i < op_req_q->num_segments; i++) { 1680c9566231SKashyap Desai segments[i].segment = 1681c9566231SKashyap Desai dma_alloc_coherent(&mrioc->pdev->dev, 1682c9566231SKashyap Desai size, &segments[i].segment_dma, GFP_KERNEL); 1683c9566231SKashyap Desai if (!segments[i].segment) 1684c9566231SKashyap Desai return -ENOMEM; 1685c9566231SKashyap Desai if (mrioc->enable_segqueue) 1686c9566231SKashyap Desai q_segment_list_entry[i] = 1687c9566231SKashyap Desai (unsigned long)segments[i].segment_dma; 1688c9566231SKashyap Desai } 1689c9566231SKashyap Desai 1690c9566231SKashyap Desai return 0; 1691c9566231SKashyap Desai } 1692c9566231SKashyap Desai 1693c9566231SKashyap Desai /** 1694c9566231SKashyap Desai * mpi3mr_create_op_reply_q - create operational reply queue 1695c9566231SKashyap Desai * @mrioc: Adapter instance reference 1696c9566231SKashyap Desai * @qidx: operational reply queue index 1697c9566231SKashyap Desai * 1698c9566231SKashyap Desai * Create operatinal reply queue by issuing MPI request 1699c9566231SKashyap Desai * through admin queue. 1700c9566231SKashyap Desai * 1701c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1702c9566231SKashyap Desai */ 1703c9566231SKashyap Desai static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) 1704c9566231SKashyap Desai { 1705c9566231SKashyap Desai struct mpi3_create_reply_queue_request create_req; 1706c9566231SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 1707c9566231SKashyap Desai int retval = 0; 1708c9566231SKashyap Desai u16 reply_qid = 0, midx; 1709c9566231SKashyap Desai 1710c9566231SKashyap Desai reply_qid = op_reply_q->qid; 1711c9566231SKashyap Desai 1712c9566231SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset); 1713c9566231SKashyap Desai 1714c9566231SKashyap Desai if (reply_qid) { 1715c9566231SKashyap Desai retval = -1; 1716c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: called for duplicate qid %d\n", 1717c9566231SKashyap Desai reply_qid); 1718c9566231SKashyap Desai 1719c9566231SKashyap Desai return retval; 1720c9566231SKashyap Desai } 1721c9566231SKashyap Desai 1722c9566231SKashyap Desai reply_qid = qidx + 1; 1723c9566231SKashyap Desai op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; 1724c9566231SKashyap Desai op_reply_q->ci = 0; 1725c9566231SKashyap Desai op_reply_q->ephase = 1; 1726463429f8SKashyap Desai atomic_set(&op_reply_q->pend_ios, 0); 1727463429f8SKashyap Desai atomic_set(&op_reply_q->in_use, 0); 1728463429f8SKashyap Desai op_reply_q->enable_irq_poll = false; 1729c9566231SKashyap Desai 1730c9566231SKashyap Desai if (!op_reply_q->q_segments) { 1731c9566231SKashyap Desai retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx); 1732c9566231SKashyap Desai if (retval) { 1733c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, qidx); 1734c9566231SKashyap Desai goto out; 1735c9566231SKashyap Desai } 1736c9566231SKashyap Desai } 1737c9566231SKashyap Desai 1738c9566231SKashyap Desai memset(&create_req, 0, sizeof(create_req)); 1739c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1740c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1741c9566231SKashyap Desai retval = -1; 1742c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: Init command is in use\n"); 1743f9dc034dSYang Yingliang goto out_unlock; 1744c9566231SKashyap Desai } 1745c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1746c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1747c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 1748c9566231SKashyap Desai create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1749c9566231SKashyap Desai create_req.function = MPI3_FUNCTION_CREATE_REPLY_QUEUE; 1750c9566231SKashyap Desai create_req.queue_id = cpu_to_le16(reply_qid); 1751c9566231SKashyap Desai create_req.flags = MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE; 1752c9566231SKashyap Desai create_req.msix_index = cpu_to_le16(mrioc->intr_info[midx].msix_index); 1753c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1754c9566231SKashyap Desai create_req.flags |= 1755c9566231SKashyap Desai MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED; 1756c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1757c9566231SKashyap Desai op_reply_q->q_segment_list_dma); 1758c9566231SKashyap Desai } else 1759c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1760c9566231SKashyap Desai op_reply_q->q_segments[0].segment_dma); 1761c9566231SKashyap Desai 1762c9566231SKashyap Desai create_req.size = cpu_to_le16(op_reply_q->num_replies); 1763c9566231SKashyap Desai 1764c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 1765c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &create_req, 1766c9566231SKashyap Desai sizeof(create_req), 1); 1767c9566231SKashyap Desai if (retval) { 1768c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: Admin Post failed\n"); 1769c9566231SKashyap Desai goto out_unlock; 1770c9566231SKashyap Desai } 1771c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1772c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1773c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1774a6856cc4SSreekanth Reddy ioc_err(mrioc, "create reply queue timed out\n"); 1775a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 1776c9566231SKashyap Desai MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT); 1777c9566231SKashyap Desai retval = -1; 1778c9566231SKashyap Desai goto out_unlock; 1779c9566231SKashyap Desai } 1780c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1781c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1782c9566231SKashyap Desai ioc_err(mrioc, 1783c9566231SKashyap Desai "CreateRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1784c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1785c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 1786c9566231SKashyap Desai retval = -1; 1787c9566231SKashyap Desai goto out_unlock; 1788c9566231SKashyap Desai } 1789c9566231SKashyap Desai op_reply_q->qid = reply_qid; 1790fe6db615SSreekanth Reddy if (midx < mrioc->intr_info_count) 1791c9566231SKashyap Desai mrioc->intr_info[midx].op_reply_q = op_reply_q; 1792c9566231SKashyap Desai 1793c9566231SKashyap Desai out_unlock: 1794c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 1795c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1796c9566231SKashyap Desai out: 1797c9566231SKashyap Desai 1798c9566231SKashyap Desai return retval; 1799c9566231SKashyap Desai } 1800c9566231SKashyap Desai 1801c9566231SKashyap Desai /** 1802c9566231SKashyap Desai * mpi3mr_create_op_req_q - create operational request queue 1803c9566231SKashyap Desai * @mrioc: Adapter instance reference 1804c9566231SKashyap Desai * @idx: operational request queue index 1805c9566231SKashyap Desai * @reply_qid: Reply queue ID 1806c9566231SKashyap Desai * 1807c9566231SKashyap Desai * Create operatinal request queue by issuing MPI request 1808c9566231SKashyap Desai * through admin queue. 1809c9566231SKashyap Desai * 1810c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1811c9566231SKashyap Desai */ 1812c9566231SKashyap Desai static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx, 1813c9566231SKashyap Desai u16 reply_qid) 1814c9566231SKashyap Desai { 1815c9566231SKashyap Desai struct mpi3_create_request_queue_request create_req; 1816c9566231SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + idx; 1817c9566231SKashyap Desai int retval = 0; 1818c9566231SKashyap Desai u16 req_qid = 0; 1819c9566231SKashyap Desai 1820c9566231SKashyap Desai req_qid = op_req_q->qid; 1821c9566231SKashyap Desai 1822c9566231SKashyap Desai if (req_qid) { 1823c9566231SKashyap Desai retval = -1; 1824c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: called for duplicate qid %d\n", 1825c9566231SKashyap Desai req_qid); 1826c9566231SKashyap Desai 1827c9566231SKashyap Desai return retval; 1828c9566231SKashyap Desai } 1829c9566231SKashyap Desai req_qid = idx + 1; 1830c9566231SKashyap Desai 1831c9566231SKashyap Desai op_req_q->num_requests = MPI3MR_OP_REQ_Q_QD; 1832c9566231SKashyap Desai op_req_q->ci = 0; 1833c9566231SKashyap Desai op_req_q->pi = 0; 1834c9566231SKashyap Desai op_req_q->reply_qid = reply_qid; 1835c9566231SKashyap Desai spin_lock_init(&op_req_q->q_lock); 1836c9566231SKashyap Desai 1837c9566231SKashyap Desai if (!op_req_q->q_segments) { 1838c9566231SKashyap Desai retval = mpi3mr_alloc_op_req_q_segments(mrioc, idx); 1839c9566231SKashyap Desai if (retval) { 1840c9566231SKashyap Desai mpi3mr_free_op_req_q_segments(mrioc, idx); 1841c9566231SKashyap Desai goto out; 1842c9566231SKashyap Desai } 1843c9566231SKashyap Desai } 1844c9566231SKashyap Desai 1845c9566231SKashyap Desai memset(&create_req, 0, sizeof(create_req)); 1846c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1847c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1848c9566231SKashyap Desai retval = -1; 1849c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: Init command is in use\n"); 1850f9dc034dSYang Yingliang goto out_unlock; 1851c9566231SKashyap Desai } 1852c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1853c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1854c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 1855c9566231SKashyap Desai create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1856c9566231SKashyap Desai create_req.function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE; 1857c9566231SKashyap Desai create_req.queue_id = cpu_to_le16(req_qid); 1858c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1859c9566231SKashyap Desai create_req.flags = 1860c9566231SKashyap Desai MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED; 1861c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1862c9566231SKashyap Desai op_req_q->q_segment_list_dma); 1863c9566231SKashyap Desai } else 1864c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1865c9566231SKashyap Desai op_req_q->q_segments[0].segment_dma); 1866c9566231SKashyap Desai create_req.reply_queue_id = cpu_to_le16(reply_qid); 1867c9566231SKashyap Desai create_req.size = cpu_to_le16(op_req_q->num_requests); 1868c9566231SKashyap Desai 1869c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 1870c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &create_req, 1871c9566231SKashyap Desai sizeof(create_req), 1); 1872c9566231SKashyap Desai if (retval) { 1873c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: Admin Post failed\n"); 1874c9566231SKashyap Desai goto out_unlock; 1875c9566231SKashyap Desai } 1876c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1877c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1878c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1879a6856cc4SSreekanth Reddy ioc_err(mrioc, "create request queue timed out\n"); 1880a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 1881a6856cc4SSreekanth Reddy MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT); 1882c9566231SKashyap Desai retval = -1; 1883c9566231SKashyap Desai goto out_unlock; 1884c9566231SKashyap Desai } 1885c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1886c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1887c9566231SKashyap Desai ioc_err(mrioc, 1888c9566231SKashyap Desai "CreateReqQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1889c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1890c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 1891c9566231SKashyap Desai retval = -1; 1892c9566231SKashyap Desai goto out_unlock; 1893c9566231SKashyap Desai } 1894c9566231SKashyap Desai op_req_q->qid = req_qid; 1895c9566231SKashyap Desai 1896c9566231SKashyap Desai out_unlock: 1897c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 1898c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1899c9566231SKashyap Desai out: 1900c9566231SKashyap Desai 1901c9566231SKashyap Desai return retval; 1902c9566231SKashyap Desai } 1903c9566231SKashyap Desai 1904c9566231SKashyap Desai /** 1905c9566231SKashyap Desai * mpi3mr_create_op_queues - create operational queue pairs 1906c9566231SKashyap Desai * @mrioc: Adapter instance reference 1907c9566231SKashyap Desai * 1908c9566231SKashyap Desai * Allocate memory for operational queue meta data and call 1909c9566231SKashyap Desai * create request and reply queue functions. 1910c9566231SKashyap Desai * 1911c9566231SKashyap Desai * Return: 0 on success, non-zero on failures. 1912c9566231SKashyap Desai */ 1913c9566231SKashyap Desai static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc) 1914c9566231SKashyap Desai { 1915c9566231SKashyap Desai int retval = 0; 1916c9566231SKashyap Desai u16 num_queues = 0, i = 0, msix_count_op_q = 1; 1917c9566231SKashyap Desai 1918c9566231SKashyap Desai num_queues = min_t(int, mrioc->facts.max_op_reply_q, 1919c9566231SKashyap Desai mrioc->facts.max_op_req_q); 1920c9566231SKashyap Desai 1921c9566231SKashyap Desai msix_count_op_q = 1922c9566231SKashyap Desai mrioc->intr_info_count - mrioc->op_reply_q_offset; 1923c9566231SKashyap Desai if (!mrioc->num_queues) 1924c9566231SKashyap Desai mrioc->num_queues = min_t(int, num_queues, msix_count_op_q); 1925c5758fc7SSreekanth Reddy /* 1926c5758fc7SSreekanth Reddy * During reset set the num_queues to the number of queues 1927c5758fc7SSreekanth Reddy * that was set before the reset. 1928c5758fc7SSreekanth Reddy */ 1929c5758fc7SSreekanth Reddy num_queues = mrioc->num_op_reply_q ? 1930c5758fc7SSreekanth Reddy mrioc->num_op_reply_q : mrioc->num_queues; 1931c5758fc7SSreekanth Reddy ioc_info(mrioc, "trying to create %d operational queue pairs\n", 1932c9566231SKashyap Desai num_queues); 1933c9566231SKashyap Desai 1934c9566231SKashyap Desai if (!mrioc->req_qinfo) { 1935c9566231SKashyap Desai mrioc->req_qinfo = kcalloc(num_queues, 1936c9566231SKashyap Desai sizeof(struct op_req_qinfo), GFP_KERNEL); 1937c9566231SKashyap Desai if (!mrioc->req_qinfo) { 1938c9566231SKashyap Desai retval = -1; 1939c9566231SKashyap Desai goto out_failed; 1940c9566231SKashyap Desai } 1941c9566231SKashyap Desai 1942c9566231SKashyap Desai mrioc->op_reply_qinfo = kzalloc(sizeof(struct op_reply_qinfo) * 1943c9566231SKashyap Desai num_queues, GFP_KERNEL); 1944c9566231SKashyap Desai if (!mrioc->op_reply_qinfo) { 1945c9566231SKashyap Desai retval = -1; 1946c9566231SKashyap Desai goto out_failed; 1947c9566231SKashyap Desai } 1948c9566231SKashyap Desai } 1949c9566231SKashyap Desai 1950c9566231SKashyap Desai if (mrioc->enable_segqueue) 1951c9566231SKashyap Desai ioc_info(mrioc, 1952c9566231SKashyap Desai "allocating operational queues through segmented queues\n"); 1953c9566231SKashyap Desai 1954c9566231SKashyap Desai for (i = 0; i < num_queues; i++) { 1955c9566231SKashyap Desai if (mpi3mr_create_op_reply_q(mrioc, i)) { 1956c9566231SKashyap Desai ioc_err(mrioc, "Cannot create OP RepQ %d\n", i); 1957c9566231SKashyap Desai break; 1958c9566231SKashyap Desai } 1959c9566231SKashyap Desai if (mpi3mr_create_op_req_q(mrioc, i, 1960c9566231SKashyap Desai mrioc->op_reply_qinfo[i].qid)) { 1961c9566231SKashyap Desai ioc_err(mrioc, "Cannot create OP ReqQ %d\n", i); 1962c9566231SKashyap Desai mpi3mr_delete_op_reply_q(mrioc, i); 1963c9566231SKashyap Desai break; 1964c9566231SKashyap Desai } 1965c9566231SKashyap Desai } 1966c9566231SKashyap Desai 1967c9566231SKashyap Desai if (i == 0) { 1968c9566231SKashyap Desai /* Not even one queue is created successfully*/ 1969c9566231SKashyap Desai retval = -1; 1970c9566231SKashyap Desai goto out_failed; 1971c9566231SKashyap Desai } 1972c9566231SKashyap Desai mrioc->num_op_reply_q = mrioc->num_op_req_q = i; 1973c9566231SKashyap Desai ioc_info(mrioc, "Successfully created %d Operational Q pairs\n", 1974c9566231SKashyap Desai mrioc->num_op_reply_q); 1975c9566231SKashyap Desai 1976c9566231SKashyap Desai return retval; 1977c9566231SKashyap Desai out_failed: 1978c9566231SKashyap Desai kfree(mrioc->req_qinfo); 1979c9566231SKashyap Desai mrioc->req_qinfo = NULL; 1980c9566231SKashyap Desai 1981c9566231SKashyap Desai kfree(mrioc->op_reply_qinfo); 1982c9566231SKashyap Desai mrioc->op_reply_qinfo = NULL; 1983c9566231SKashyap Desai 1984c9566231SKashyap Desai return retval; 1985c9566231SKashyap Desai } 1986c9566231SKashyap Desai 1987c9566231SKashyap Desai /** 1988023ab2a9SKashyap Desai * mpi3mr_op_request_post - Post request to operational queue 1989023ab2a9SKashyap Desai * @mrioc: Adapter reference 1990023ab2a9SKashyap Desai * @op_req_q: Operational request queue info 1991023ab2a9SKashyap Desai * @req: MPI3 request 1992023ab2a9SKashyap Desai * 1993023ab2a9SKashyap Desai * Post the MPI3 request into operational request queue and 1994023ab2a9SKashyap Desai * inform the controller, if the queue is full return 1995023ab2a9SKashyap Desai * appropriate error. 1996023ab2a9SKashyap Desai * 1997023ab2a9SKashyap Desai * Return: 0 on success, non-zero on failure. 1998023ab2a9SKashyap Desai */ 1999023ab2a9SKashyap Desai int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc, 2000023ab2a9SKashyap Desai struct op_req_qinfo *op_req_q, u8 *req) 2001023ab2a9SKashyap Desai { 2002023ab2a9SKashyap Desai u16 pi = 0, max_entries, reply_qidx = 0, midx; 2003023ab2a9SKashyap Desai int retval = 0; 2004023ab2a9SKashyap Desai unsigned long flags; 2005023ab2a9SKashyap Desai u8 *req_entry; 2006023ab2a9SKashyap Desai void *segment_base_addr; 2007023ab2a9SKashyap Desai u16 req_sz = mrioc->facts.op_req_sz; 2008023ab2a9SKashyap Desai struct segments *segments = op_req_q->q_segments; 2009023ab2a9SKashyap Desai 2010023ab2a9SKashyap Desai reply_qidx = op_req_q->reply_qid - 1; 2011023ab2a9SKashyap Desai 2012023ab2a9SKashyap Desai if (mrioc->unrecoverable) 2013023ab2a9SKashyap Desai return -EFAULT; 2014023ab2a9SKashyap Desai 2015023ab2a9SKashyap Desai spin_lock_irqsave(&op_req_q->q_lock, flags); 2016023ab2a9SKashyap Desai pi = op_req_q->pi; 2017023ab2a9SKashyap Desai max_entries = op_req_q->num_requests; 2018023ab2a9SKashyap Desai 2019023ab2a9SKashyap Desai if (mpi3mr_check_req_qfull(op_req_q)) { 2020023ab2a9SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX( 2021023ab2a9SKashyap Desai reply_qidx, mrioc->op_reply_q_offset); 2022023ab2a9SKashyap Desai mpi3mr_process_op_reply_q(mrioc, &mrioc->intr_info[midx]); 2023023ab2a9SKashyap Desai 2024023ab2a9SKashyap Desai if (mpi3mr_check_req_qfull(op_req_q)) { 2025023ab2a9SKashyap Desai retval = -EAGAIN; 2026023ab2a9SKashyap Desai goto out; 2027023ab2a9SKashyap Desai } 2028023ab2a9SKashyap Desai } 2029023ab2a9SKashyap Desai 2030023ab2a9SKashyap Desai if (mrioc->reset_in_progress) { 2031023ab2a9SKashyap Desai ioc_err(mrioc, "OpReqQ submit reset in progress\n"); 2032023ab2a9SKashyap Desai retval = -EAGAIN; 2033023ab2a9SKashyap Desai goto out; 2034023ab2a9SKashyap Desai } 2035023ab2a9SKashyap Desai 2036023ab2a9SKashyap Desai segment_base_addr = segments[pi / op_req_q->segment_qd].segment; 2037023ab2a9SKashyap Desai req_entry = (u8 *)segment_base_addr + 2038023ab2a9SKashyap Desai ((pi % op_req_q->segment_qd) * req_sz); 2039023ab2a9SKashyap Desai 2040023ab2a9SKashyap Desai memset(req_entry, 0, req_sz); 2041023ab2a9SKashyap Desai memcpy(req_entry, req, MPI3MR_ADMIN_REQ_FRAME_SZ); 2042023ab2a9SKashyap Desai 2043023ab2a9SKashyap Desai if (++pi == max_entries) 2044023ab2a9SKashyap Desai pi = 0; 2045023ab2a9SKashyap Desai op_req_q->pi = pi; 2046023ab2a9SKashyap Desai 2047463429f8SKashyap Desai if (atomic_inc_return(&mrioc->op_reply_qinfo[reply_qidx].pend_ios) 2048463429f8SKashyap Desai > MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT) 2049463429f8SKashyap Desai mrioc->op_reply_qinfo[reply_qidx].enable_irq_poll = true; 2050463429f8SKashyap Desai 2051023ab2a9SKashyap Desai writel(op_req_q->pi, 2052023ab2a9SKashyap Desai &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].producer_index); 2053023ab2a9SKashyap Desai 2054023ab2a9SKashyap Desai out: 2055023ab2a9SKashyap Desai spin_unlock_irqrestore(&op_req_q->q_lock, flags); 2056023ab2a9SKashyap Desai return retval; 2057023ab2a9SKashyap Desai } 2058023ab2a9SKashyap Desai 2059023ab2a9SKashyap Desai /** 2060a6856cc4SSreekanth Reddy * mpi3mr_check_rh_fault_ioc - check reset history and fault 2061a6856cc4SSreekanth Reddy * controller 2062a6856cc4SSreekanth Reddy * @mrioc: Adapter instance reference 2063a6856cc4SSreekanth Reddy * @reason_code, reason code for the fault. 2064a6856cc4SSreekanth Reddy * 2065a6856cc4SSreekanth Reddy * This routine will save snapdump and fault the controller with 2066a6856cc4SSreekanth Reddy * the given reason code if it is not already in the fault or 2067a6856cc4SSreekanth Reddy * not asynchronosuly reset. This will be used to handle 2068a6856cc4SSreekanth Reddy * initilaization time faults/resets/timeout as in those cases 2069a6856cc4SSreekanth Reddy * immediate soft reset invocation is not required. 2070a6856cc4SSreekanth Reddy * 2071a6856cc4SSreekanth Reddy * Return: None. 2072a6856cc4SSreekanth Reddy */ 2073a6856cc4SSreekanth Reddy void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code) 2074a6856cc4SSreekanth Reddy { 2075a6856cc4SSreekanth Reddy u32 ioc_status, host_diagnostic, timeout; 2076a6856cc4SSreekanth Reddy 2077a6856cc4SSreekanth Reddy ioc_status = readl(&mrioc->sysif_regs->ioc_status); 2078a6856cc4SSreekanth Reddy if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) || 2079a6856cc4SSreekanth Reddy (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) { 2080a6856cc4SSreekanth Reddy mpi3mr_print_fault_info(mrioc); 2081a6856cc4SSreekanth Reddy return; 2082a6856cc4SSreekanth Reddy } 2083a6856cc4SSreekanth Reddy mpi3mr_set_diagsave(mrioc); 2084a6856cc4SSreekanth Reddy mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 2085a6856cc4SSreekanth Reddy reason_code); 2086a6856cc4SSreekanth Reddy timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; 2087a6856cc4SSreekanth Reddy do { 2088a6856cc4SSreekanth Reddy host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); 2089a6856cc4SSreekanth Reddy if (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS)) 2090a6856cc4SSreekanth Reddy break; 2091a6856cc4SSreekanth Reddy msleep(100); 2092a6856cc4SSreekanth Reddy } while (--timeout); 2093a6856cc4SSreekanth Reddy } 2094a6856cc4SSreekanth Reddy 2095a6856cc4SSreekanth Reddy /** 209654dfcffbSKashyap Desai * mpi3mr_sync_timestamp - Issue time stamp sync request 209754dfcffbSKashyap Desai * @mrioc: Adapter reference 209854dfcffbSKashyap Desai * 209954dfcffbSKashyap Desai * Issue IO unit control MPI request to synchornize firmware 210054dfcffbSKashyap Desai * timestamp with host time. 210154dfcffbSKashyap Desai * 210254dfcffbSKashyap Desai * Return: 0 on success, non-zero on failure. 210354dfcffbSKashyap Desai */ 210454dfcffbSKashyap Desai static int mpi3mr_sync_timestamp(struct mpi3mr_ioc *mrioc) 210554dfcffbSKashyap Desai { 210654dfcffbSKashyap Desai ktime_t current_time; 210754dfcffbSKashyap Desai struct mpi3_iounit_control_request iou_ctrl; 210854dfcffbSKashyap Desai int retval = 0; 210954dfcffbSKashyap Desai 211054dfcffbSKashyap Desai memset(&iou_ctrl, 0, sizeof(iou_ctrl)); 211154dfcffbSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 211254dfcffbSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 211354dfcffbSKashyap Desai retval = -1; 211454dfcffbSKashyap Desai ioc_err(mrioc, "Issue IOUCTL time_stamp: command is in use\n"); 211554dfcffbSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 211654dfcffbSKashyap Desai goto out; 211754dfcffbSKashyap Desai } 211854dfcffbSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 211954dfcffbSKashyap Desai mrioc->init_cmds.is_waiting = 1; 212054dfcffbSKashyap Desai mrioc->init_cmds.callback = NULL; 212154dfcffbSKashyap Desai iou_ctrl.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 212254dfcffbSKashyap Desai iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL; 212354dfcffbSKashyap Desai iou_ctrl.operation = MPI3_CTRL_OP_UPDATE_TIMESTAMP; 212454dfcffbSKashyap Desai current_time = ktime_get_real(); 212554dfcffbSKashyap Desai iou_ctrl.param64[0] = cpu_to_le64(ktime_to_ms(current_time)); 212654dfcffbSKashyap Desai 212754dfcffbSKashyap Desai init_completion(&mrioc->init_cmds.done); 212854dfcffbSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl, 212954dfcffbSKashyap Desai sizeof(iou_ctrl), 0); 213054dfcffbSKashyap Desai if (retval) { 213154dfcffbSKashyap Desai ioc_err(mrioc, "Issue IOUCTL time_stamp: Admin Post failed\n"); 213254dfcffbSKashyap Desai goto out_unlock; 213354dfcffbSKashyap Desai } 213454dfcffbSKashyap Desai 213554dfcffbSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 213654dfcffbSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 213754dfcffbSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 213854dfcffbSKashyap Desai ioc_err(mrioc, "Issue IOUCTL time_stamp: command timed out\n"); 213954dfcffbSKashyap Desai mrioc->init_cmds.is_waiting = 0; 2140fbaa9aa4SSreekanth Reddy if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET)) 214154dfcffbSKashyap Desai mpi3mr_soft_reset_handler(mrioc, 214254dfcffbSKashyap Desai MPI3MR_RESET_FROM_TSU_TIMEOUT, 1); 214354dfcffbSKashyap Desai retval = -1; 214454dfcffbSKashyap Desai goto out_unlock; 214554dfcffbSKashyap Desai } 214654dfcffbSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 214754dfcffbSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 214854dfcffbSKashyap Desai ioc_err(mrioc, 214954dfcffbSKashyap Desai "Issue IOUCTL time_stamp: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 215054dfcffbSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 215154dfcffbSKashyap Desai mrioc->init_cmds.ioc_loginfo); 215254dfcffbSKashyap Desai retval = -1; 215354dfcffbSKashyap Desai goto out_unlock; 215454dfcffbSKashyap Desai } 215554dfcffbSKashyap Desai 215654dfcffbSKashyap Desai out_unlock: 215754dfcffbSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 215854dfcffbSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 215954dfcffbSKashyap Desai 216054dfcffbSKashyap Desai out: 216154dfcffbSKashyap Desai return retval; 216254dfcffbSKashyap Desai } 216354dfcffbSKashyap Desai 216454dfcffbSKashyap Desai /** 21652ac794baSSreekanth Reddy * mpi3mr_print_pkg_ver - display controller fw package version 21662ac794baSSreekanth Reddy * @mrioc: Adapter reference 21672ac794baSSreekanth Reddy * 21682ac794baSSreekanth Reddy * Retrieve firmware package version from the component image 21692ac794baSSreekanth Reddy * header of the controller flash and display it. 21702ac794baSSreekanth Reddy * 21712ac794baSSreekanth Reddy * Return: 0 on success and non-zero on failure. 21722ac794baSSreekanth Reddy */ 21732ac794baSSreekanth Reddy static int mpi3mr_print_pkg_ver(struct mpi3mr_ioc *mrioc) 21742ac794baSSreekanth Reddy { 21752ac794baSSreekanth Reddy struct mpi3_ci_upload_request ci_upload; 21762ac794baSSreekanth Reddy int retval = -1; 21772ac794baSSreekanth Reddy void *data = NULL; 21782ac794baSSreekanth Reddy dma_addr_t data_dma; 21792ac794baSSreekanth Reddy struct mpi3_ci_manifest_mpi *manifest; 21802ac794baSSreekanth Reddy u32 data_len = sizeof(struct mpi3_ci_manifest_mpi); 21812ac794baSSreekanth Reddy u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 21822ac794baSSreekanth Reddy 21832ac794baSSreekanth Reddy data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, 21842ac794baSSreekanth Reddy GFP_KERNEL); 21852ac794baSSreekanth Reddy if (!data) 21862ac794baSSreekanth Reddy return -ENOMEM; 21872ac794baSSreekanth Reddy 21882ac794baSSreekanth Reddy memset(&ci_upload, 0, sizeof(ci_upload)); 21892ac794baSSreekanth Reddy mutex_lock(&mrioc->init_cmds.mutex); 21902ac794baSSreekanth Reddy if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 21912ac794baSSreekanth Reddy ioc_err(mrioc, "sending get package version failed due to command in use\n"); 21922ac794baSSreekanth Reddy mutex_unlock(&mrioc->init_cmds.mutex); 21932ac794baSSreekanth Reddy goto out; 21942ac794baSSreekanth Reddy } 21952ac794baSSreekanth Reddy mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 21962ac794baSSreekanth Reddy mrioc->init_cmds.is_waiting = 1; 21972ac794baSSreekanth Reddy mrioc->init_cmds.callback = NULL; 21982ac794baSSreekanth Reddy ci_upload.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 21992ac794baSSreekanth Reddy ci_upload.function = MPI3_FUNCTION_CI_UPLOAD; 22002ac794baSSreekanth Reddy ci_upload.msg_flags = MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY; 22012ac794baSSreekanth Reddy ci_upload.signature1 = cpu_to_le32(MPI3_IMAGE_HEADER_SIGNATURE1_MANIFEST); 22022ac794baSSreekanth Reddy ci_upload.image_offset = cpu_to_le32(MPI3_IMAGE_HEADER_SIZE); 22032ac794baSSreekanth Reddy ci_upload.segment_size = cpu_to_le32(data_len); 22042ac794baSSreekanth Reddy 22052ac794baSSreekanth Reddy mpi3mr_add_sg_single(&ci_upload.sgl, sgl_flags, data_len, 22062ac794baSSreekanth Reddy data_dma); 22072ac794baSSreekanth Reddy init_completion(&mrioc->init_cmds.done); 22082ac794baSSreekanth Reddy retval = mpi3mr_admin_request_post(mrioc, &ci_upload, 22092ac794baSSreekanth Reddy sizeof(ci_upload), 1); 22102ac794baSSreekanth Reddy if (retval) { 22112ac794baSSreekanth Reddy ioc_err(mrioc, "posting get package version failed\n"); 22122ac794baSSreekanth Reddy goto out_unlock; 22132ac794baSSreekanth Reddy } 22142ac794baSSreekanth Reddy wait_for_completion_timeout(&mrioc->init_cmds.done, 22152ac794baSSreekanth Reddy (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 22162ac794baSSreekanth Reddy if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 22172ac794baSSreekanth Reddy ioc_err(mrioc, "get package version timed out\n"); 2218a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 2219a6856cc4SSreekanth Reddy MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT); 22202ac794baSSreekanth Reddy retval = -1; 22212ac794baSSreekanth Reddy goto out_unlock; 22222ac794baSSreekanth Reddy } 22232ac794baSSreekanth Reddy if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 22242ac794baSSreekanth Reddy == MPI3_IOCSTATUS_SUCCESS) { 22252ac794baSSreekanth Reddy manifest = (struct mpi3_ci_manifest_mpi *) data; 22262ac794baSSreekanth Reddy if (manifest->manifest_type == MPI3_CI_MANIFEST_TYPE_MPI) { 22272ac794baSSreekanth Reddy ioc_info(mrioc, 22282ac794baSSreekanth Reddy "firmware package version(%d.%d.%d.%d.%05d-%05d)\n", 22292ac794baSSreekanth Reddy manifest->package_version.gen_major, 22302ac794baSSreekanth Reddy manifest->package_version.gen_minor, 22312ac794baSSreekanth Reddy manifest->package_version.phase_major, 22322ac794baSSreekanth Reddy manifest->package_version.phase_minor, 22332ac794baSSreekanth Reddy manifest->package_version.customer_id, 22342ac794baSSreekanth Reddy manifest->package_version.build_num); 22352ac794baSSreekanth Reddy } 22362ac794baSSreekanth Reddy } 22372ac794baSSreekanth Reddy retval = 0; 22382ac794baSSreekanth Reddy out_unlock: 22392ac794baSSreekanth Reddy mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 22402ac794baSSreekanth Reddy mutex_unlock(&mrioc->init_cmds.mutex); 22412ac794baSSreekanth Reddy 22422ac794baSSreekanth Reddy out: 22432ac794baSSreekanth Reddy if (data) 22442ac794baSSreekanth Reddy dma_free_coherent(&mrioc->pdev->dev, data_len, data, 22452ac794baSSreekanth Reddy data_dma); 22462ac794baSSreekanth Reddy return retval; 22472ac794baSSreekanth Reddy } 22482ac794baSSreekanth Reddy 22492ac794baSSreekanth Reddy /** 2250672ae26cSKashyap Desai * mpi3mr_watchdog_work - watchdog thread to monitor faults 2251672ae26cSKashyap Desai * @work: work struct 2252672ae26cSKashyap Desai * 2253672ae26cSKashyap Desai * Watch dog work periodically executed (1 second interval) to 2254672ae26cSKashyap Desai * monitor firmware fault and to issue periodic timer sync to 2255672ae26cSKashyap Desai * the firmware. 2256672ae26cSKashyap Desai * 2257672ae26cSKashyap Desai * Return: Nothing. 2258672ae26cSKashyap Desai */ 2259672ae26cSKashyap Desai static void mpi3mr_watchdog_work(struct work_struct *work) 2260672ae26cSKashyap Desai { 2261672ae26cSKashyap Desai struct mpi3mr_ioc *mrioc = 2262672ae26cSKashyap Desai container_of(work, struct mpi3mr_ioc, watchdog_work.work); 2263672ae26cSKashyap Desai unsigned long flags; 2264672ae26cSKashyap Desai enum mpi3mr_iocstate ioc_state; 2265*78b76a07SSreekanth Reddy u32 fault, host_diagnostic, ioc_status; 2266*78b76a07SSreekanth Reddy u32 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH; 2267672ae26cSKashyap Desai 2268b64845a7SSreekanth Reddy if (mrioc->reset_in_progress || mrioc->unrecoverable) 2269b64845a7SSreekanth Reddy return; 2270b64845a7SSreekanth Reddy 227154dfcffbSKashyap Desai if (mrioc->ts_update_counter++ >= MPI3MR_TSUPDATE_INTERVAL) { 227254dfcffbSKashyap Desai mrioc->ts_update_counter = 0; 227354dfcffbSKashyap Desai mpi3mr_sync_timestamp(mrioc); 227454dfcffbSKashyap Desai } 227554dfcffbSKashyap Desai 2276*78b76a07SSreekanth Reddy if ((mrioc->prepare_for_reset) && 2277*78b76a07SSreekanth Reddy ((mrioc->prepare_for_reset_timeout_counter++) >= 2278*78b76a07SSreekanth Reddy MPI3MR_PREPARE_FOR_RESET_TIMEOUT)) { 2279*78b76a07SSreekanth Reddy mpi3mr_soft_reset_handler(mrioc, 2280*78b76a07SSreekanth Reddy MPI3MR_RESET_FROM_CIACTVRST_TIMER, 1); 2281*78b76a07SSreekanth Reddy return; 2282*78b76a07SSreekanth Reddy } 2283*78b76a07SSreekanth Reddy 2284*78b76a07SSreekanth Reddy ioc_status = readl(&mrioc->sysif_regs->ioc_status); 2285*78b76a07SSreekanth Reddy if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) { 2286*78b76a07SSreekanth Reddy mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_FIRMWARE, 0); 2287*78b76a07SSreekanth Reddy return; 2288*78b76a07SSreekanth Reddy } 2289*78b76a07SSreekanth Reddy 2290672ae26cSKashyap Desai /*Check for fault state every one second and issue Soft reset*/ 2291672ae26cSKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 2292*78b76a07SSreekanth Reddy if (ioc_state != MRIOC_STATE_FAULT) 2293*78b76a07SSreekanth Reddy goto schedule_work; 2294*78b76a07SSreekanth Reddy 2295*78b76a07SSreekanth Reddy fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK; 2296672ae26cSKashyap Desai host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); 2297672ae26cSKashyap Desai if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) { 2298672ae26cSKashyap Desai if (!mrioc->diagsave_timeout) { 2299672ae26cSKashyap Desai mpi3mr_print_fault_info(mrioc); 2300*78b76a07SSreekanth Reddy ioc_warn(mrioc, "diag save in progress\n"); 2301672ae26cSKashyap Desai } 2302*78b76a07SSreekanth Reddy if ((mrioc->diagsave_timeout++) <= MPI3_SYSIF_DIAG_SAVE_TIMEOUT) 2303672ae26cSKashyap Desai goto schedule_work; 2304*78b76a07SSreekanth Reddy } 2305*78b76a07SSreekanth Reddy 2306672ae26cSKashyap Desai mpi3mr_print_fault_info(mrioc); 2307672ae26cSKashyap Desai mrioc->diagsave_timeout = 0; 2308672ae26cSKashyap Desai 2309*78b76a07SSreekanth Reddy switch (fault) { 2310*78b76a07SSreekanth Reddy case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED: 2311672ae26cSKashyap Desai ioc_info(mrioc, 2312*78b76a07SSreekanth Reddy "controller requires system power cycle, marking controller as unrecoverable\n"); 2313672ae26cSKashyap Desai mrioc->unrecoverable = 1; 2314*78b76a07SSreekanth Reddy return; 2315*78b76a07SSreekanth Reddy case MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS: 2316*78b76a07SSreekanth Reddy return; 2317*78b76a07SSreekanth Reddy case MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET: 2318*78b76a07SSreekanth Reddy reset_reason = MPI3MR_RESET_FROM_CIACTIV_FAULT; 2319*78b76a07SSreekanth Reddy break; 2320*78b76a07SSreekanth Reddy default: 2321*78b76a07SSreekanth Reddy break; 2322672ae26cSKashyap Desai } 2323*78b76a07SSreekanth Reddy mpi3mr_soft_reset_handler(mrioc, reset_reason, 0); 2324*78b76a07SSreekanth Reddy return; 2325672ae26cSKashyap Desai 2326672ae26cSKashyap Desai schedule_work: 2327672ae26cSKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 2328672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 2329672ae26cSKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 2330672ae26cSKashyap Desai &mrioc->watchdog_work, 2331672ae26cSKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 2332672ae26cSKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 2333672ae26cSKashyap Desai return; 2334672ae26cSKashyap Desai } 2335672ae26cSKashyap Desai 2336672ae26cSKashyap Desai /** 2337672ae26cSKashyap Desai * mpi3mr_start_watchdog - Start watchdog 2338672ae26cSKashyap Desai * @mrioc: Adapter instance reference 2339672ae26cSKashyap Desai * 2340672ae26cSKashyap Desai * Create and start the watchdog thread to monitor controller 2341672ae26cSKashyap Desai * faults. 2342672ae26cSKashyap Desai * 2343672ae26cSKashyap Desai * Return: Nothing. 2344672ae26cSKashyap Desai */ 2345672ae26cSKashyap Desai void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc) 2346672ae26cSKashyap Desai { 2347672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 2348672ae26cSKashyap Desai return; 2349672ae26cSKashyap Desai 2350672ae26cSKashyap Desai INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work); 2351672ae26cSKashyap Desai snprintf(mrioc->watchdog_work_q_name, 2352672ae26cSKashyap Desai sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name, 2353672ae26cSKashyap Desai mrioc->id); 2354672ae26cSKashyap Desai mrioc->watchdog_work_q = 2355672ae26cSKashyap Desai create_singlethread_workqueue(mrioc->watchdog_work_q_name); 2356672ae26cSKashyap Desai if (!mrioc->watchdog_work_q) { 2357672ae26cSKashyap Desai ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__); 2358672ae26cSKashyap Desai return; 2359672ae26cSKashyap Desai } 2360672ae26cSKashyap Desai 2361672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 2362672ae26cSKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 2363672ae26cSKashyap Desai &mrioc->watchdog_work, 2364672ae26cSKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 2365672ae26cSKashyap Desai } 2366672ae26cSKashyap Desai 2367672ae26cSKashyap Desai /** 2368672ae26cSKashyap Desai * mpi3mr_stop_watchdog - Stop watchdog 2369672ae26cSKashyap Desai * @mrioc: Adapter instance reference 2370672ae26cSKashyap Desai * 2371672ae26cSKashyap Desai * Stop the watchdog thread created to monitor controller 2372672ae26cSKashyap Desai * faults. 2373672ae26cSKashyap Desai * 2374672ae26cSKashyap Desai * Return: Nothing. 2375672ae26cSKashyap Desai */ 2376672ae26cSKashyap Desai void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc) 2377672ae26cSKashyap Desai { 2378672ae26cSKashyap Desai unsigned long flags; 2379672ae26cSKashyap Desai struct workqueue_struct *wq; 2380672ae26cSKashyap Desai 2381672ae26cSKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 2382672ae26cSKashyap Desai wq = mrioc->watchdog_work_q; 2383672ae26cSKashyap Desai mrioc->watchdog_work_q = NULL; 2384672ae26cSKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 2385672ae26cSKashyap Desai if (wq) { 2386672ae26cSKashyap Desai if (!cancel_delayed_work_sync(&mrioc->watchdog_work)) 2387672ae26cSKashyap Desai flush_workqueue(wq); 2388672ae26cSKashyap Desai destroy_workqueue(wq); 2389672ae26cSKashyap Desai } 2390672ae26cSKashyap Desai } 2391672ae26cSKashyap Desai 2392672ae26cSKashyap Desai /** 2393824a1566SKashyap Desai * mpi3mr_setup_admin_qpair - Setup admin queue pair 2394824a1566SKashyap Desai * @mrioc: Adapter instance reference 2395824a1566SKashyap Desai * 2396824a1566SKashyap Desai * Allocate memory for admin queue pair if required and register 2397824a1566SKashyap Desai * the admin queue with the controller. 2398824a1566SKashyap Desai * 2399824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2400824a1566SKashyap Desai */ 2401824a1566SKashyap Desai static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc) 2402824a1566SKashyap Desai { 2403824a1566SKashyap Desai int retval = 0; 2404824a1566SKashyap Desai u32 num_admin_entries = 0; 2405824a1566SKashyap Desai 2406824a1566SKashyap Desai mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE; 2407824a1566SKashyap Desai mrioc->num_admin_req = mrioc->admin_req_q_sz / 2408824a1566SKashyap Desai MPI3MR_ADMIN_REQ_FRAME_SZ; 2409824a1566SKashyap Desai mrioc->admin_req_ci = mrioc->admin_req_pi = 0; 2410824a1566SKashyap Desai mrioc->admin_req_base = NULL; 2411824a1566SKashyap Desai 2412824a1566SKashyap Desai mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE; 2413824a1566SKashyap Desai mrioc->num_admin_replies = mrioc->admin_reply_q_sz / 2414824a1566SKashyap Desai MPI3MR_ADMIN_REPLY_FRAME_SZ; 2415824a1566SKashyap Desai mrioc->admin_reply_ci = 0; 2416824a1566SKashyap Desai mrioc->admin_reply_ephase = 1; 2417824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 2418824a1566SKashyap Desai 2419824a1566SKashyap Desai if (!mrioc->admin_req_base) { 2420824a1566SKashyap Desai mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev, 2421824a1566SKashyap Desai mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL); 2422824a1566SKashyap Desai 2423824a1566SKashyap Desai if (!mrioc->admin_req_base) { 2424824a1566SKashyap Desai retval = -1; 2425824a1566SKashyap Desai goto out_failed; 2426824a1566SKashyap Desai } 2427824a1566SKashyap Desai 2428824a1566SKashyap Desai mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev, 2429824a1566SKashyap Desai mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma, 2430824a1566SKashyap Desai GFP_KERNEL); 2431824a1566SKashyap Desai 2432824a1566SKashyap Desai if (!mrioc->admin_reply_base) { 2433824a1566SKashyap Desai retval = -1; 2434824a1566SKashyap Desai goto out_failed; 2435824a1566SKashyap Desai } 2436824a1566SKashyap Desai } 2437824a1566SKashyap Desai 2438824a1566SKashyap Desai num_admin_entries = (mrioc->num_admin_replies << 16) | 2439824a1566SKashyap Desai (mrioc->num_admin_req); 2440824a1566SKashyap Desai writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries); 2441824a1566SKashyap Desai mpi3mr_writeq(mrioc->admin_req_dma, 2442824a1566SKashyap Desai &mrioc->sysif_regs->admin_request_queue_address); 2443824a1566SKashyap Desai mpi3mr_writeq(mrioc->admin_reply_dma, 2444824a1566SKashyap Desai &mrioc->sysif_regs->admin_reply_queue_address); 2445824a1566SKashyap Desai writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi); 2446824a1566SKashyap Desai writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); 2447824a1566SKashyap Desai return retval; 2448824a1566SKashyap Desai 2449824a1566SKashyap Desai out_failed: 2450824a1566SKashyap Desai 2451824a1566SKashyap Desai if (mrioc->admin_reply_base) { 2452824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz, 2453824a1566SKashyap Desai mrioc->admin_reply_base, mrioc->admin_reply_dma); 2454824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 2455824a1566SKashyap Desai } 2456824a1566SKashyap Desai if (mrioc->admin_req_base) { 2457824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz, 2458824a1566SKashyap Desai mrioc->admin_req_base, mrioc->admin_req_dma); 2459824a1566SKashyap Desai mrioc->admin_req_base = NULL; 2460824a1566SKashyap Desai } 2461824a1566SKashyap Desai return retval; 2462824a1566SKashyap Desai } 2463824a1566SKashyap Desai 2464824a1566SKashyap Desai /** 2465824a1566SKashyap Desai * mpi3mr_issue_iocfacts - Send IOC Facts 2466824a1566SKashyap Desai * @mrioc: Adapter instance reference 2467824a1566SKashyap Desai * @facts_data: Cached IOC facts data 2468824a1566SKashyap Desai * 2469824a1566SKashyap Desai * Issue IOC Facts MPI request through admin queue and wait for 2470824a1566SKashyap Desai * the completion of it or time out. 2471824a1566SKashyap Desai * 2472824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2473824a1566SKashyap Desai */ 2474824a1566SKashyap Desai static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc, 2475824a1566SKashyap Desai struct mpi3_ioc_facts_data *facts_data) 2476824a1566SKashyap Desai { 2477824a1566SKashyap Desai struct mpi3_ioc_facts_request iocfacts_req; 2478824a1566SKashyap Desai void *data = NULL; 2479824a1566SKashyap Desai dma_addr_t data_dma; 2480824a1566SKashyap Desai u32 data_len = sizeof(*facts_data); 2481824a1566SKashyap Desai int retval = 0; 2482824a1566SKashyap Desai u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 2483824a1566SKashyap Desai 2484824a1566SKashyap Desai data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, 2485824a1566SKashyap Desai GFP_KERNEL); 2486824a1566SKashyap Desai 2487824a1566SKashyap Desai if (!data) { 2488824a1566SKashyap Desai retval = -1; 2489824a1566SKashyap Desai goto out; 2490824a1566SKashyap Desai } 2491824a1566SKashyap Desai 2492824a1566SKashyap Desai memset(&iocfacts_req, 0, sizeof(iocfacts_req)); 2493824a1566SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 2494824a1566SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 2495824a1566SKashyap Desai retval = -1; 2496824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n"); 2497824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2498824a1566SKashyap Desai goto out; 2499824a1566SKashyap Desai } 2500824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 2501824a1566SKashyap Desai mrioc->init_cmds.is_waiting = 1; 2502824a1566SKashyap Desai mrioc->init_cmds.callback = NULL; 2503824a1566SKashyap Desai iocfacts_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 2504824a1566SKashyap Desai iocfacts_req.function = MPI3_FUNCTION_IOC_FACTS; 2505824a1566SKashyap Desai 2506824a1566SKashyap Desai mpi3mr_add_sg_single(&iocfacts_req.sgl, sgl_flags, data_len, 2507824a1566SKashyap Desai data_dma); 2508824a1566SKashyap Desai 2509824a1566SKashyap Desai init_completion(&mrioc->init_cmds.done); 2510824a1566SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req, 2511824a1566SKashyap Desai sizeof(iocfacts_req), 1); 2512824a1566SKashyap Desai if (retval) { 2513824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n"); 2514824a1566SKashyap Desai goto out_unlock; 2515824a1566SKashyap Desai } 2516824a1566SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 2517824a1566SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 2518824a1566SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 2519a6856cc4SSreekanth Reddy ioc_err(mrioc, "ioc_facts timed out\n"); 2520a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 2521824a1566SKashyap Desai MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT); 2522824a1566SKashyap Desai retval = -1; 2523824a1566SKashyap Desai goto out_unlock; 2524824a1566SKashyap Desai } 2525824a1566SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 2526824a1566SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 2527824a1566SKashyap Desai ioc_err(mrioc, 2528824a1566SKashyap Desai "Issue IOCFacts: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 2529824a1566SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 2530824a1566SKashyap Desai mrioc->init_cmds.ioc_loginfo); 2531824a1566SKashyap Desai retval = -1; 2532824a1566SKashyap Desai goto out_unlock; 2533824a1566SKashyap Desai } 2534824a1566SKashyap Desai memcpy(facts_data, (u8 *)data, data_len); 2535c5758fc7SSreekanth Reddy mpi3mr_process_factsdata(mrioc, facts_data); 2536824a1566SKashyap Desai out_unlock: 2537824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 2538824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2539824a1566SKashyap Desai 2540824a1566SKashyap Desai out: 2541824a1566SKashyap Desai if (data) 2542824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma); 2543824a1566SKashyap Desai 2544824a1566SKashyap Desai return retval; 2545824a1566SKashyap Desai } 2546824a1566SKashyap Desai 2547824a1566SKashyap Desai /** 2548824a1566SKashyap Desai * mpi3mr_check_reset_dma_mask - Process IOC facts data 2549824a1566SKashyap Desai * @mrioc: Adapter instance reference 2550824a1566SKashyap Desai * 2551824a1566SKashyap Desai * Check whether the new DMA mask requested through IOCFacts by 2552824a1566SKashyap Desai * firmware needs to be set, if so set it . 2553824a1566SKashyap Desai * 2554824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 2555824a1566SKashyap Desai */ 2556824a1566SKashyap Desai static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc) 2557824a1566SKashyap Desai { 2558824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 2559824a1566SKashyap Desai int r; 2560824a1566SKashyap Desai u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask); 2561824a1566SKashyap Desai 2562824a1566SKashyap Desai if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask)) 2563824a1566SKashyap Desai return 0; 2564824a1566SKashyap Desai 2565824a1566SKashyap Desai ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n", 2566824a1566SKashyap Desai mrioc->dma_mask, facts_dma_mask); 2567824a1566SKashyap Desai 2568824a1566SKashyap Desai r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask); 2569824a1566SKashyap Desai if (r) { 2570824a1566SKashyap Desai ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n", 2571824a1566SKashyap Desai facts_dma_mask, r); 2572824a1566SKashyap Desai return r; 2573824a1566SKashyap Desai } 2574824a1566SKashyap Desai mrioc->dma_mask = facts_dma_mask; 2575824a1566SKashyap Desai return r; 2576824a1566SKashyap Desai } 2577824a1566SKashyap Desai 2578824a1566SKashyap Desai /** 2579824a1566SKashyap Desai * mpi3mr_process_factsdata - Process IOC facts data 2580824a1566SKashyap Desai * @mrioc: Adapter instance reference 2581824a1566SKashyap Desai * @facts_data: Cached IOC facts data 2582824a1566SKashyap Desai * 2583824a1566SKashyap Desai * Convert IOC facts data into cpu endianness and cache it in 2584824a1566SKashyap Desai * the driver . 2585824a1566SKashyap Desai * 2586824a1566SKashyap Desai * Return: Nothing. 2587824a1566SKashyap Desai */ 2588824a1566SKashyap Desai static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, 2589824a1566SKashyap Desai struct mpi3_ioc_facts_data *facts_data) 2590824a1566SKashyap Desai { 2591824a1566SKashyap Desai u32 ioc_config, req_sz, facts_flags; 2592824a1566SKashyap Desai 2593824a1566SKashyap Desai if ((le16_to_cpu(facts_data->ioc_facts_data_length)) != 2594824a1566SKashyap Desai (sizeof(*facts_data) / 4)) { 2595824a1566SKashyap Desai ioc_warn(mrioc, 2596824a1566SKashyap Desai "IOCFactsdata length mismatch driver_sz(%zu) firmware_sz(%d)\n", 2597824a1566SKashyap Desai sizeof(*facts_data), 2598824a1566SKashyap Desai le16_to_cpu(facts_data->ioc_facts_data_length) * 4); 2599824a1566SKashyap Desai } 2600824a1566SKashyap Desai 2601824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 2602824a1566SKashyap Desai req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >> 2603824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT); 2604824a1566SKashyap Desai if (le16_to_cpu(facts_data->ioc_request_frame_size) != (req_sz / 4)) { 2605824a1566SKashyap Desai ioc_err(mrioc, 2606824a1566SKashyap Desai "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n", 2607824a1566SKashyap Desai req_sz / 4, le16_to_cpu(facts_data->ioc_request_frame_size)); 2608824a1566SKashyap Desai } 2609824a1566SKashyap Desai 2610824a1566SKashyap Desai memset(&mrioc->facts, 0, sizeof(mrioc->facts)); 2611824a1566SKashyap Desai 2612824a1566SKashyap Desai facts_flags = le32_to_cpu(facts_data->flags); 2613824a1566SKashyap Desai mrioc->facts.op_req_sz = req_sz; 2614824a1566SKashyap Desai mrioc->op_reply_desc_sz = 1 << ((ioc_config & 2615824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >> 2616824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT); 2617824a1566SKashyap Desai 2618824a1566SKashyap Desai mrioc->facts.ioc_num = facts_data->ioc_number; 2619824a1566SKashyap Desai mrioc->facts.who_init = facts_data->who_init; 2620824a1566SKashyap Desai mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->max_msix_vectors); 2621824a1566SKashyap Desai mrioc->facts.personality = (facts_flags & 2622824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK); 2623824a1566SKashyap Desai mrioc->facts.dma_mask = (facts_flags & 2624824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >> 2625824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT; 2626824a1566SKashyap Desai mrioc->facts.protocol_flags = facts_data->protocol_flags; 2627824a1566SKashyap Desai mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word); 2628824a1566SKashyap Desai mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_request); 2629824a1566SKashyap Desai mrioc->facts.product_id = le16_to_cpu(facts_data->product_id); 2630824a1566SKashyap Desai mrioc->facts.reply_sz = le16_to_cpu(facts_data->reply_frame_size) * 4; 2631824a1566SKashyap Desai mrioc->facts.exceptions = le16_to_cpu(facts_data->ioc_exceptions); 2632824a1566SKashyap Desai mrioc->facts.max_perids = le16_to_cpu(facts_data->max_persistent_id); 2633824a1566SKashyap Desai mrioc->facts.max_vds = le16_to_cpu(facts_data->max_vds); 2634824a1566SKashyap Desai mrioc->facts.max_hpds = le16_to_cpu(facts_data->max_host_pds); 2635ec5ebd2cSSreekanth Reddy mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_adv_host_pds); 2636ec5ebd2cSSreekanth Reddy mrioc->facts.max_raid_pds = le16_to_cpu(facts_data->max_raid_pds); 2637824a1566SKashyap Desai mrioc->facts.max_nvme = le16_to_cpu(facts_data->max_nvme); 2638824a1566SKashyap Desai mrioc->facts.max_pcie_switches = 2639ec5ebd2cSSreekanth Reddy le16_to_cpu(facts_data->max_pcie_switches); 2640824a1566SKashyap Desai mrioc->facts.max_sasexpanders = 2641824a1566SKashyap Desai le16_to_cpu(facts_data->max_sas_expanders); 2642824a1566SKashyap Desai mrioc->facts.max_sasinitiators = 2643824a1566SKashyap Desai le16_to_cpu(facts_data->max_sas_initiators); 2644824a1566SKashyap Desai mrioc->facts.max_enclosures = le16_to_cpu(facts_data->max_enclosures); 2645824a1566SKashyap Desai mrioc->facts.min_devhandle = le16_to_cpu(facts_data->min_dev_handle); 2646824a1566SKashyap Desai mrioc->facts.max_devhandle = le16_to_cpu(facts_data->max_dev_handle); 2647824a1566SKashyap Desai mrioc->facts.max_op_req_q = 2648824a1566SKashyap Desai le16_to_cpu(facts_data->max_operational_request_queues); 2649824a1566SKashyap Desai mrioc->facts.max_op_reply_q = 2650824a1566SKashyap Desai le16_to_cpu(facts_data->max_operational_reply_queues); 2651824a1566SKashyap Desai mrioc->facts.ioc_capabilities = 2652824a1566SKashyap Desai le32_to_cpu(facts_data->ioc_capabilities); 2653824a1566SKashyap Desai mrioc->facts.fw_ver.build_num = 2654824a1566SKashyap Desai le16_to_cpu(facts_data->fw_version.build_num); 2655824a1566SKashyap Desai mrioc->facts.fw_ver.cust_id = 2656824a1566SKashyap Desai le16_to_cpu(facts_data->fw_version.customer_id); 2657824a1566SKashyap Desai mrioc->facts.fw_ver.ph_minor = facts_data->fw_version.phase_minor; 2658824a1566SKashyap Desai mrioc->facts.fw_ver.ph_major = facts_data->fw_version.phase_major; 2659824a1566SKashyap Desai mrioc->facts.fw_ver.gen_minor = facts_data->fw_version.gen_minor; 2660824a1566SKashyap Desai mrioc->facts.fw_ver.gen_major = facts_data->fw_version.gen_major; 2661824a1566SKashyap Desai mrioc->msix_count = min_t(int, mrioc->msix_count, 2662824a1566SKashyap Desai mrioc->facts.max_msix_vectors); 2663824a1566SKashyap Desai mrioc->facts.sge_mod_mask = facts_data->sge_modifier_mask; 2664824a1566SKashyap Desai mrioc->facts.sge_mod_value = facts_data->sge_modifier_value; 2665824a1566SKashyap Desai mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift; 2666824a1566SKashyap Desai mrioc->facts.shutdown_timeout = 2667824a1566SKashyap Desai le16_to_cpu(facts_data->shutdown_timeout); 2668824a1566SKashyap Desai 2669824a1566SKashyap Desai ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),", 2670824a1566SKashyap Desai mrioc->facts.ioc_num, mrioc->facts.max_op_req_q, 2671824a1566SKashyap Desai mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle); 2672824a1566SKashyap Desai ioc_info(mrioc, 2673ec5ebd2cSSreekanth Reddy "maxreqs(%d), mindh(%d) maxvectors(%d) maxperids(%d)\n", 2674824a1566SKashyap Desai mrioc->facts.max_reqs, mrioc->facts.min_devhandle, 2675ec5ebd2cSSreekanth Reddy mrioc->facts.max_msix_vectors, mrioc->facts.max_perids); 2676824a1566SKashyap Desai ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ", 2677824a1566SKashyap Desai mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value, 2678824a1566SKashyap Desai mrioc->facts.sge_mod_shift); 2679824a1566SKashyap Desai ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x\n", 2680824a1566SKashyap Desai mrioc->facts.dma_mask, (facts_flags & 2681824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK)); 2682824a1566SKashyap Desai } 2683824a1566SKashyap Desai 2684824a1566SKashyap Desai /** 2685824a1566SKashyap Desai * mpi3mr_alloc_reply_sense_bufs - Send IOC Init 2686824a1566SKashyap Desai * @mrioc: Adapter instance reference 2687824a1566SKashyap Desai * 2688824a1566SKashyap Desai * Allocate and initialize the reply free buffers, sense 2689824a1566SKashyap Desai * buffers, reply free queue and sense buffer queue. 2690824a1566SKashyap Desai * 2691824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2692824a1566SKashyap Desai */ 2693824a1566SKashyap Desai static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) 2694824a1566SKashyap Desai { 2695824a1566SKashyap Desai int retval = 0; 2696824a1566SKashyap Desai u32 sz, i; 2697824a1566SKashyap Desai 2698824a1566SKashyap Desai if (mrioc->init_cmds.reply) 2699e3605f65SSreekanth Reddy return retval; 2700824a1566SKashyap Desai 2701c5758fc7SSreekanth Reddy mrioc->init_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); 2702824a1566SKashyap Desai if (!mrioc->init_cmds.reply) 2703824a1566SKashyap Desai goto out_failed; 2704824a1566SKashyap Desai 270513ef29eaSKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 2706c5758fc7SSreekanth Reddy mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz, 270713ef29eaSKashyap Desai GFP_KERNEL); 270813ef29eaSKashyap Desai if (!mrioc->dev_rmhs_cmds[i].reply) 270913ef29eaSKashyap Desai goto out_failed; 271013ef29eaSKashyap Desai } 271113ef29eaSKashyap Desai 2712c1af985dSSreekanth Reddy for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { 2713c1af985dSSreekanth Reddy mrioc->evtack_cmds[i].reply = kzalloc(mrioc->reply_sz, 2714c1af985dSSreekanth Reddy GFP_KERNEL); 2715c1af985dSSreekanth Reddy if (!mrioc->evtack_cmds[i].reply) 2716c1af985dSSreekanth Reddy goto out_failed; 2717c1af985dSSreekanth Reddy } 2718c1af985dSSreekanth Reddy 2719c5758fc7SSreekanth Reddy mrioc->host_tm_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); 2720e844adb1SKashyap Desai if (!mrioc->host_tm_cmds.reply) 2721e844adb1SKashyap Desai goto out_failed; 2722e844adb1SKashyap Desai 2723e844adb1SKashyap Desai mrioc->dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8; 2724e844adb1SKashyap Desai if (mrioc->facts.max_devhandle % 8) 2725e844adb1SKashyap Desai mrioc->dev_handle_bitmap_sz++; 2726e844adb1SKashyap Desai mrioc->removepend_bitmap = kzalloc(mrioc->dev_handle_bitmap_sz, 2727e844adb1SKashyap Desai GFP_KERNEL); 2728e844adb1SKashyap Desai if (!mrioc->removepend_bitmap) 2729e844adb1SKashyap Desai goto out_failed; 2730e844adb1SKashyap Desai 2731e844adb1SKashyap Desai mrioc->devrem_bitmap_sz = MPI3MR_NUM_DEVRMCMD / 8; 2732e844adb1SKashyap Desai if (MPI3MR_NUM_DEVRMCMD % 8) 2733e844adb1SKashyap Desai mrioc->devrem_bitmap_sz++; 2734e844adb1SKashyap Desai mrioc->devrem_bitmap = kzalloc(mrioc->devrem_bitmap_sz, 2735e844adb1SKashyap Desai GFP_KERNEL); 2736e844adb1SKashyap Desai if (!mrioc->devrem_bitmap) 2737e844adb1SKashyap Desai goto out_failed; 2738e844adb1SKashyap Desai 2739c1af985dSSreekanth Reddy mrioc->evtack_cmds_bitmap_sz = MPI3MR_NUM_EVTACKCMD / 8; 2740c1af985dSSreekanth Reddy if (MPI3MR_NUM_EVTACKCMD % 8) 2741c1af985dSSreekanth Reddy mrioc->evtack_cmds_bitmap_sz++; 2742c1af985dSSreekanth Reddy mrioc->evtack_cmds_bitmap = kzalloc(mrioc->evtack_cmds_bitmap_sz, 2743c1af985dSSreekanth Reddy GFP_KERNEL); 2744c1af985dSSreekanth Reddy if (!mrioc->evtack_cmds_bitmap) 2745c1af985dSSreekanth Reddy goto out_failed; 2746c1af985dSSreekanth Reddy 2747824a1566SKashyap Desai mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES; 2748824a1566SKashyap Desai mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1; 2749824a1566SKashyap Desai mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR; 2750824a1566SKashyap Desai mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1; 2751824a1566SKashyap Desai 2752824a1566SKashyap Desai /* reply buffer pool, 16 byte align */ 2753c5758fc7SSreekanth Reddy sz = mrioc->num_reply_bufs * mrioc->reply_sz; 2754824a1566SKashyap Desai mrioc->reply_buf_pool = dma_pool_create("reply_buf pool", 2755824a1566SKashyap Desai &mrioc->pdev->dev, sz, 16, 0); 2756824a1566SKashyap Desai if (!mrioc->reply_buf_pool) { 2757824a1566SKashyap Desai ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n"); 2758824a1566SKashyap Desai goto out_failed; 2759824a1566SKashyap Desai } 2760824a1566SKashyap Desai 2761824a1566SKashyap Desai mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL, 2762824a1566SKashyap Desai &mrioc->reply_buf_dma); 2763824a1566SKashyap Desai if (!mrioc->reply_buf) 2764824a1566SKashyap Desai goto out_failed; 2765824a1566SKashyap Desai 2766824a1566SKashyap Desai mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz; 2767824a1566SKashyap Desai 2768824a1566SKashyap Desai /* reply free queue, 8 byte align */ 2769824a1566SKashyap Desai sz = mrioc->reply_free_qsz * 8; 2770824a1566SKashyap Desai mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool", 2771824a1566SKashyap Desai &mrioc->pdev->dev, sz, 8, 0); 2772824a1566SKashyap Desai if (!mrioc->reply_free_q_pool) { 2773824a1566SKashyap Desai ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n"); 2774824a1566SKashyap Desai goto out_failed; 2775824a1566SKashyap Desai } 2776824a1566SKashyap Desai mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool, 2777824a1566SKashyap Desai GFP_KERNEL, &mrioc->reply_free_q_dma); 2778824a1566SKashyap Desai if (!mrioc->reply_free_q) 2779824a1566SKashyap Desai goto out_failed; 2780824a1566SKashyap Desai 2781824a1566SKashyap Desai /* sense buffer pool, 4 byte align */ 2782ec5ebd2cSSreekanth Reddy sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ; 2783824a1566SKashyap Desai mrioc->sense_buf_pool = dma_pool_create("sense_buf pool", 2784824a1566SKashyap Desai &mrioc->pdev->dev, sz, 4, 0); 2785824a1566SKashyap Desai if (!mrioc->sense_buf_pool) { 2786824a1566SKashyap Desai ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n"); 2787824a1566SKashyap Desai goto out_failed; 2788824a1566SKashyap Desai } 2789824a1566SKashyap Desai mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL, 2790824a1566SKashyap Desai &mrioc->sense_buf_dma); 2791824a1566SKashyap Desai if (!mrioc->sense_buf) 2792824a1566SKashyap Desai goto out_failed; 2793824a1566SKashyap Desai 2794824a1566SKashyap Desai /* sense buffer queue, 8 byte align */ 2795824a1566SKashyap Desai sz = mrioc->sense_buf_q_sz * 8; 2796824a1566SKashyap Desai mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool", 2797824a1566SKashyap Desai &mrioc->pdev->dev, sz, 8, 0); 2798824a1566SKashyap Desai if (!mrioc->sense_buf_q_pool) { 2799824a1566SKashyap Desai ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n"); 2800824a1566SKashyap Desai goto out_failed; 2801824a1566SKashyap Desai } 2802824a1566SKashyap Desai mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool, 2803824a1566SKashyap Desai GFP_KERNEL, &mrioc->sense_buf_q_dma); 2804824a1566SKashyap Desai if (!mrioc->sense_buf_q) 2805824a1566SKashyap Desai goto out_failed; 2806824a1566SKashyap Desai 2807e3605f65SSreekanth Reddy return retval; 2808e3605f65SSreekanth Reddy 2809e3605f65SSreekanth Reddy out_failed: 2810e3605f65SSreekanth Reddy retval = -1; 2811e3605f65SSreekanth Reddy return retval; 2812e3605f65SSreekanth Reddy } 2813e3605f65SSreekanth Reddy 2814e3605f65SSreekanth Reddy /** 2815e3605f65SSreekanth Reddy * mpimr_initialize_reply_sbuf_queues - initialize reply sense 2816e3605f65SSreekanth Reddy * buffers 2817e3605f65SSreekanth Reddy * @mrioc: Adapter instance reference 2818e3605f65SSreekanth Reddy * 2819e3605f65SSreekanth Reddy * Helper function to initialize reply and sense buffers along 2820e3605f65SSreekanth Reddy * with some debug prints. 2821e3605f65SSreekanth Reddy * 2822e3605f65SSreekanth Reddy * Return: None. 2823e3605f65SSreekanth Reddy */ 2824e3605f65SSreekanth Reddy static void mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc *mrioc) 2825e3605f65SSreekanth Reddy { 2826e3605f65SSreekanth Reddy u32 sz, i; 2827e3605f65SSreekanth Reddy dma_addr_t phy_addr; 2828e3605f65SSreekanth Reddy 2829c5758fc7SSreekanth Reddy sz = mrioc->num_reply_bufs * mrioc->reply_sz; 2830824a1566SKashyap Desai ioc_info(mrioc, 2831824a1566SKashyap Desai "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n", 2832c5758fc7SSreekanth Reddy mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->reply_sz, 2833824a1566SKashyap Desai (sz / 1024), (unsigned long long)mrioc->reply_buf_dma); 2834824a1566SKashyap Desai sz = mrioc->reply_free_qsz * 8; 2835824a1566SKashyap Desai ioc_info(mrioc, 2836824a1566SKashyap Desai "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n", 2837824a1566SKashyap Desai mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024), 2838824a1566SKashyap Desai (unsigned long long)mrioc->reply_free_q_dma); 2839ec5ebd2cSSreekanth Reddy sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ; 2840824a1566SKashyap Desai ioc_info(mrioc, 2841824a1566SKashyap Desai "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n", 2842ec5ebd2cSSreekanth Reddy mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSE_BUF_SZ, 2843824a1566SKashyap Desai (sz / 1024), (unsigned long long)mrioc->sense_buf_dma); 2844824a1566SKashyap Desai sz = mrioc->sense_buf_q_sz * 8; 2845824a1566SKashyap Desai ioc_info(mrioc, 2846824a1566SKashyap Desai "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n", 2847824a1566SKashyap Desai mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024), 2848824a1566SKashyap Desai (unsigned long long)mrioc->sense_buf_q_dma); 2849824a1566SKashyap Desai 2850824a1566SKashyap Desai /* initialize Reply buffer Queue */ 2851824a1566SKashyap Desai for (i = 0, phy_addr = mrioc->reply_buf_dma; 2852c5758fc7SSreekanth Reddy i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->reply_sz) 2853824a1566SKashyap Desai mrioc->reply_free_q[i] = cpu_to_le64(phy_addr); 2854824a1566SKashyap Desai mrioc->reply_free_q[i] = cpu_to_le64(0); 2855824a1566SKashyap Desai 2856824a1566SKashyap Desai /* initialize Sense Buffer Queue */ 2857824a1566SKashyap Desai for (i = 0, phy_addr = mrioc->sense_buf_dma; 2858ec5ebd2cSSreekanth Reddy i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSE_BUF_SZ) 2859824a1566SKashyap Desai mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr); 2860824a1566SKashyap Desai mrioc->sense_buf_q[i] = cpu_to_le64(0); 2861824a1566SKashyap Desai } 2862824a1566SKashyap Desai 2863824a1566SKashyap Desai /** 2864824a1566SKashyap Desai * mpi3mr_issue_iocinit - Send IOC Init 2865824a1566SKashyap Desai * @mrioc: Adapter instance reference 2866824a1566SKashyap Desai * 2867824a1566SKashyap Desai * Issue IOC Init MPI request through admin queue and wait for 2868824a1566SKashyap Desai * the completion of it or time out. 2869824a1566SKashyap Desai * 2870824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2871824a1566SKashyap Desai */ 2872824a1566SKashyap Desai static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc) 2873824a1566SKashyap Desai { 2874824a1566SKashyap Desai struct mpi3_ioc_init_request iocinit_req; 2875824a1566SKashyap Desai struct mpi3_driver_info_layout *drv_info; 2876824a1566SKashyap Desai dma_addr_t data_dma; 2877824a1566SKashyap Desai u32 data_len = sizeof(*drv_info); 2878824a1566SKashyap Desai int retval = 0; 2879824a1566SKashyap Desai ktime_t current_time; 2880824a1566SKashyap Desai 2881824a1566SKashyap Desai drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, 2882824a1566SKashyap Desai GFP_KERNEL); 2883824a1566SKashyap Desai if (!drv_info) { 2884824a1566SKashyap Desai retval = -1; 2885824a1566SKashyap Desai goto out; 2886824a1566SKashyap Desai } 2887e3605f65SSreekanth Reddy mpimr_initialize_reply_sbuf_queues(mrioc); 2888e3605f65SSreekanth Reddy 2889824a1566SKashyap Desai drv_info->information_length = cpu_to_le32(data_len); 2890aa0dc6a7SSreekanth Reddy strscpy(drv_info->driver_signature, "Broadcom", sizeof(drv_info->driver_signature)); 2891aa0dc6a7SSreekanth Reddy strscpy(drv_info->os_name, utsname()->sysname, sizeof(drv_info->os_name)); 2892aa0dc6a7SSreekanth Reddy strscpy(drv_info->os_version, utsname()->release, sizeof(drv_info->os_version)); 2893aa0dc6a7SSreekanth Reddy strscpy(drv_info->driver_name, MPI3MR_DRIVER_NAME, sizeof(drv_info->driver_name)); 2894aa0dc6a7SSreekanth Reddy strscpy(drv_info->driver_version, MPI3MR_DRIVER_VERSION, sizeof(drv_info->driver_version)); 2895aa0dc6a7SSreekanth Reddy strscpy(drv_info->driver_release_date, MPI3MR_DRIVER_RELDATE, 2896aa0dc6a7SSreekanth Reddy sizeof(drv_info->driver_release_date)); 2897824a1566SKashyap Desai drv_info->driver_capabilities = 0; 2898824a1566SKashyap Desai memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info, 2899824a1566SKashyap Desai sizeof(mrioc->driver_info)); 2900824a1566SKashyap Desai 2901824a1566SKashyap Desai memset(&iocinit_req, 0, sizeof(iocinit_req)); 2902824a1566SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 2903824a1566SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 2904824a1566SKashyap Desai retval = -1; 2905824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCInit: Init command is in use\n"); 2906824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2907824a1566SKashyap Desai goto out; 2908824a1566SKashyap Desai } 2909824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 2910824a1566SKashyap Desai mrioc->init_cmds.is_waiting = 1; 2911824a1566SKashyap Desai mrioc->init_cmds.callback = NULL; 2912824a1566SKashyap Desai iocinit_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 2913824a1566SKashyap Desai iocinit_req.function = MPI3_FUNCTION_IOC_INIT; 2914824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.dev = MPI3_VERSION_DEV; 2915824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.unit = MPI3_VERSION_UNIT; 2916824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.major = MPI3_VERSION_MAJOR; 2917824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.minor = MPI3_VERSION_MINOR; 2918824a1566SKashyap Desai iocinit_req.who_init = MPI3_WHOINIT_HOST_DRIVER; 2919824a1566SKashyap Desai iocinit_req.reply_free_queue_depth = cpu_to_le16(mrioc->reply_free_qsz); 2920824a1566SKashyap Desai iocinit_req.reply_free_queue_address = 2921824a1566SKashyap Desai cpu_to_le64(mrioc->reply_free_q_dma); 2922ec5ebd2cSSreekanth Reddy iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSE_BUF_SZ); 2923824a1566SKashyap Desai iocinit_req.sense_buffer_free_queue_depth = 2924824a1566SKashyap Desai cpu_to_le16(mrioc->sense_buf_q_sz); 2925824a1566SKashyap Desai iocinit_req.sense_buffer_free_queue_address = 2926824a1566SKashyap Desai cpu_to_le64(mrioc->sense_buf_q_dma); 2927824a1566SKashyap Desai iocinit_req.driver_information_address = cpu_to_le64(data_dma); 2928824a1566SKashyap Desai 2929824a1566SKashyap Desai current_time = ktime_get_real(); 2930824a1566SKashyap Desai iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time)); 2931824a1566SKashyap Desai 2932824a1566SKashyap Desai init_completion(&mrioc->init_cmds.done); 2933824a1566SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iocinit_req, 2934824a1566SKashyap Desai sizeof(iocinit_req), 1); 2935824a1566SKashyap Desai if (retval) { 2936824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n"); 2937824a1566SKashyap Desai goto out_unlock; 2938824a1566SKashyap Desai } 2939824a1566SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 2940824a1566SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 2941824a1566SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 2942a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 2943824a1566SKashyap Desai MPI3MR_RESET_FROM_IOCINIT_TIMEOUT); 2944a6856cc4SSreekanth Reddy ioc_err(mrioc, "ioc_init timed out\n"); 2945824a1566SKashyap Desai retval = -1; 2946824a1566SKashyap Desai goto out_unlock; 2947824a1566SKashyap Desai } 2948824a1566SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 2949824a1566SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 2950824a1566SKashyap Desai ioc_err(mrioc, 2951824a1566SKashyap Desai "Issue IOCInit: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 2952824a1566SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 2953824a1566SKashyap Desai mrioc->init_cmds.ioc_loginfo); 2954824a1566SKashyap Desai retval = -1; 2955824a1566SKashyap Desai goto out_unlock; 2956824a1566SKashyap Desai } 2957824a1566SKashyap Desai 2958e3605f65SSreekanth Reddy mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs; 2959e3605f65SSreekanth Reddy writel(mrioc->reply_free_queue_host_index, 2960e3605f65SSreekanth Reddy &mrioc->sysif_regs->reply_free_host_index); 2961e3605f65SSreekanth Reddy 2962e3605f65SSreekanth Reddy mrioc->sbq_host_index = mrioc->num_sense_bufs; 2963e3605f65SSreekanth Reddy writel(mrioc->sbq_host_index, 2964e3605f65SSreekanth Reddy &mrioc->sysif_regs->sense_buffer_free_host_index); 2965824a1566SKashyap Desai out_unlock: 2966824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 2967824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2968824a1566SKashyap Desai 2969824a1566SKashyap Desai out: 2970824a1566SKashyap Desai if (drv_info) 2971824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info, 2972824a1566SKashyap Desai data_dma); 2973824a1566SKashyap Desai 2974824a1566SKashyap Desai return retval; 2975824a1566SKashyap Desai } 2976824a1566SKashyap Desai 2977824a1566SKashyap Desai /** 297813ef29eaSKashyap Desai * mpi3mr_unmask_events - Unmask events in event mask bitmap 297913ef29eaSKashyap Desai * @mrioc: Adapter instance reference 298013ef29eaSKashyap Desai * @event: MPI event ID 298113ef29eaSKashyap Desai * 298213ef29eaSKashyap Desai * Un mask the specific event by resetting the event_mask 298313ef29eaSKashyap Desai * bitmap. 298413ef29eaSKashyap Desai * 298513ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 298613ef29eaSKashyap Desai */ 298713ef29eaSKashyap Desai static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event) 298813ef29eaSKashyap Desai { 298913ef29eaSKashyap Desai u32 desired_event; 299013ef29eaSKashyap Desai u8 word; 299113ef29eaSKashyap Desai 299213ef29eaSKashyap Desai if (event >= 128) 299313ef29eaSKashyap Desai return; 299413ef29eaSKashyap Desai 299513ef29eaSKashyap Desai desired_event = (1 << (event % 32)); 299613ef29eaSKashyap Desai word = event / 32; 299713ef29eaSKashyap Desai 299813ef29eaSKashyap Desai mrioc->event_masks[word] &= ~desired_event; 299913ef29eaSKashyap Desai } 300013ef29eaSKashyap Desai 300113ef29eaSKashyap Desai /** 300213ef29eaSKashyap Desai * mpi3mr_issue_event_notification - Send event notification 300313ef29eaSKashyap Desai * @mrioc: Adapter instance reference 300413ef29eaSKashyap Desai * 300513ef29eaSKashyap Desai * Issue event notification MPI request through admin queue and 300613ef29eaSKashyap Desai * wait for the completion of it or time out. 300713ef29eaSKashyap Desai * 300813ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 300913ef29eaSKashyap Desai */ 301013ef29eaSKashyap Desai static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc) 301113ef29eaSKashyap Desai { 301213ef29eaSKashyap Desai struct mpi3_event_notification_request evtnotify_req; 301313ef29eaSKashyap Desai int retval = 0; 301413ef29eaSKashyap Desai u8 i; 301513ef29eaSKashyap Desai 301613ef29eaSKashyap Desai memset(&evtnotify_req, 0, sizeof(evtnotify_req)); 301713ef29eaSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 301813ef29eaSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 301913ef29eaSKashyap Desai retval = -1; 302013ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: Init command is in use\n"); 302113ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 302213ef29eaSKashyap Desai goto out; 302313ef29eaSKashyap Desai } 302413ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 302513ef29eaSKashyap Desai mrioc->init_cmds.is_waiting = 1; 302613ef29eaSKashyap Desai mrioc->init_cmds.callback = NULL; 302713ef29eaSKashyap Desai evtnotify_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 302813ef29eaSKashyap Desai evtnotify_req.function = MPI3_FUNCTION_EVENT_NOTIFICATION; 302913ef29eaSKashyap Desai for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 303013ef29eaSKashyap Desai evtnotify_req.event_masks[i] = 303113ef29eaSKashyap Desai cpu_to_le32(mrioc->event_masks[i]); 303213ef29eaSKashyap Desai init_completion(&mrioc->init_cmds.done); 303313ef29eaSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &evtnotify_req, 303413ef29eaSKashyap Desai sizeof(evtnotify_req), 1); 303513ef29eaSKashyap Desai if (retval) { 303613ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: Admin Post failed\n"); 303713ef29eaSKashyap Desai goto out_unlock; 303813ef29eaSKashyap Desai } 303913ef29eaSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 304013ef29eaSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 304113ef29eaSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 3042a6856cc4SSreekanth Reddy ioc_err(mrioc, "event notification timed out\n"); 3043a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 304413ef29eaSKashyap Desai MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT); 304513ef29eaSKashyap Desai retval = -1; 304613ef29eaSKashyap Desai goto out_unlock; 304713ef29eaSKashyap Desai } 304813ef29eaSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 304913ef29eaSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 305013ef29eaSKashyap Desai ioc_err(mrioc, 305113ef29eaSKashyap Desai "Issue EvtNotify: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 305213ef29eaSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 305313ef29eaSKashyap Desai mrioc->init_cmds.ioc_loginfo); 305413ef29eaSKashyap Desai retval = -1; 305513ef29eaSKashyap Desai goto out_unlock; 305613ef29eaSKashyap Desai } 305713ef29eaSKashyap Desai 305813ef29eaSKashyap Desai out_unlock: 305913ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 306013ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 306113ef29eaSKashyap Desai out: 306213ef29eaSKashyap Desai return retval; 306313ef29eaSKashyap Desai } 306413ef29eaSKashyap Desai 306513ef29eaSKashyap Desai /** 3066c1af985dSSreekanth Reddy * mpi3mr_process_event_ack - Process event acknowledgment 306713ef29eaSKashyap Desai * @mrioc: Adapter instance reference 306813ef29eaSKashyap Desai * @event: MPI3 event ID 3069c1af985dSSreekanth Reddy * @event_ctx: event context 307013ef29eaSKashyap Desai * 307113ef29eaSKashyap Desai * Send event acknowledgment through admin queue and wait for 307213ef29eaSKashyap Desai * it to complete. 307313ef29eaSKashyap Desai * 307413ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 307513ef29eaSKashyap Desai */ 3076c1af985dSSreekanth Reddy int mpi3mr_process_event_ack(struct mpi3mr_ioc *mrioc, u8 event, 307713ef29eaSKashyap Desai u32 event_ctx) 307813ef29eaSKashyap Desai { 307913ef29eaSKashyap Desai struct mpi3_event_ack_request evtack_req; 308013ef29eaSKashyap Desai int retval = 0; 308113ef29eaSKashyap Desai 308213ef29eaSKashyap Desai memset(&evtack_req, 0, sizeof(evtack_req)); 308313ef29eaSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 308413ef29eaSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 308513ef29eaSKashyap Desai retval = -1; 308613ef29eaSKashyap Desai ioc_err(mrioc, "Send EvtAck: Init command is in use\n"); 308713ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 308813ef29eaSKashyap Desai goto out; 308913ef29eaSKashyap Desai } 309013ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 309113ef29eaSKashyap Desai mrioc->init_cmds.is_waiting = 1; 309213ef29eaSKashyap Desai mrioc->init_cmds.callback = NULL; 309313ef29eaSKashyap Desai evtack_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 309413ef29eaSKashyap Desai evtack_req.function = MPI3_FUNCTION_EVENT_ACK; 309513ef29eaSKashyap Desai evtack_req.event = event; 309613ef29eaSKashyap Desai evtack_req.event_context = cpu_to_le32(event_ctx); 309713ef29eaSKashyap Desai 309813ef29eaSKashyap Desai init_completion(&mrioc->init_cmds.done); 309913ef29eaSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &evtack_req, 310013ef29eaSKashyap Desai sizeof(evtack_req), 1); 310113ef29eaSKashyap Desai if (retval) { 310213ef29eaSKashyap Desai ioc_err(mrioc, "Send EvtAck: Admin Post failed\n"); 310313ef29eaSKashyap Desai goto out_unlock; 310413ef29eaSKashyap Desai } 310513ef29eaSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 310613ef29eaSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 310713ef29eaSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 310813ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: command timed out\n"); 3109fbaa9aa4SSreekanth Reddy if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET)) 311013ef29eaSKashyap Desai mpi3mr_soft_reset_handler(mrioc, 311113ef29eaSKashyap Desai MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1); 311213ef29eaSKashyap Desai retval = -1; 311313ef29eaSKashyap Desai goto out_unlock; 311413ef29eaSKashyap Desai } 311513ef29eaSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 311613ef29eaSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 311713ef29eaSKashyap Desai ioc_err(mrioc, 311813ef29eaSKashyap Desai "Send EvtAck: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 311913ef29eaSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 312013ef29eaSKashyap Desai mrioc->init_cmds.ioc_loginfo); 312113ef29eaSKashyap Desai retval = -1; 312213ef29eaSKashyap Desai goto out_unlock; 312313ef29eaSKashyap Desai } 312413ef29eaSKashyap Desai 312513ef29eaSKashyap Desai out_unlock: 312613ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 312713ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 312813ef29eaSKashyap Desai out: 312913ef29eaSKashyap Desai return retval; 313013ef29eaSKashyap Desai } 313113ef29eaSKashyap Desai 313213ef29eaSKashyap Desai /** 3133824a1566SKashyap Desai * mpi3mr_alloc_chain_bufs - Allocate chain buffers 3134824a1566SKashyap Desai * @mrioc: Adapter instance reference 3135824a1566SKashyap Desai * 3136824a1566SKashyap Desai * Allocate chain buffers and set a bitmap to indicate free 3137824a1566SKashyap Desai * chain buffers. Chain buffers are used to pass the SGE 3138824a1566SKashyap Desai * information along with MPI3 SCSI IO requests for host I/O. 3139824a1566SKashyap Desai * 3140824a1566SKashyap Desai * Return: 0 on success, non-zero on failure 3141824a1566SKashyap Desai */ 3142824a1566SKashyap Desai static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc) 3143824a1566SKashyap Desai { 3144824a1566SKashyap Desai int retval = 0; 3145824a1566SKashyap Desai u32 sz, i; 3146824a1566SKashyap Desai u16 num_chains; 3147824a1566SKashyap Desai 3148fe6db615SSreekanth Reddy if (mrioc->chain_sgl_list) 3149fe6db615SSreekanth Reddy return retval; 3150fe6db615SSreekanth Reddy 3151824a1566SKashyap Desai num_chains = mrioc->max_host_ios / MPI3MR_CHAINBUF_FACTOR; 3152824a1566SKashyap Desai 315374e1f30aSKashyap Desai if (prot_mask & (SHOST_DIX_TYPE0_PROTECTION 315474e1f30aSKashyap Desai | SHOST_DIX_TYPE1_PROTECTION 315574e1f30aSKashyap Desai | SHOST_DIX_TYPE2_PROTECTION 315674e1f30aSKashyap Desai | SHOST_DIX_TYPE3_PROTECTION)) 315774e1f30aSKashyap Desai num_chains += (num_chains / MPI3MR_CHAINBUFDIX_FACTOR); 315874e1f30aSKashyap Desai 3159824a1566SKashyap Desai mrioc->chain_buf_count = num_chains; 3160824a1566SKashyap Desai sz = sizeof(struct chain_element) * num_chains; 3161824a1566SKashyap Desai mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL); 3162824a1566SKashyap Desai if (!mrioc->chain_sgl_list) 3163824a1566SKashyap Desai goto out_failed; 3164824a1566SKashyap Desai 3165824a1566SKashyap Desai sz = MPI3MR_PAGE_SIZE_4K; 3166824a1566SKashyap Desai mrioc->chain_buf_pool = dma_pool_create("chain_buf pool", 3167824a1566SKashyap Desai &mrioc->pdev->dev, sz, 16, 0); 3168824a1566SKashyap Desai if (!mrioc->chain_buf_pool) { 3169824a1566SKashyap Desai ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n"); 3170824a1566SKashyap Desai goto out_failed; 3171824a1566SKashyap Desai } 3172824a1566SKashyap Desai 3173824a1566SKashyap Desai for (i = 0; i < num_chains; i++) { 3174824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr = 3175824a1566SKashyap Desai dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL, 3176824a1566SKashyap Desai &mrioc->chain_sgl_list[i].dma_addr); 3177824a1566SKashyap Desai 3178824a1566SKashyap Desai if (!mrioc->chain_sgl_list[i].addr) 3179824a1566SKashyap Desai goto out_failed; 3180824a1566SKashyap Desai } 3181824a1566SKashyap Desai mrioc->chain_bitmap_sz = num_chains / 8; 3182824a1566SKashyap Desai if (num_chains % 8) 3183824a1566SKashyap Desai mrioc->chain_bitmap_sz++; 3184824a1566SKashyap Desai mrioc->chain_bitmap = kzalloc(mrioc->chain_bitmap_sz, GFP_KERNEL); 3185824a1566SKashyap Desai if (!mrioc->chain_bitmap) 3186824a1566SKashyap Desai goto out_failed; 3187824a1566SKashyap Desai return retval; 3188824a1566SKashyap Desai out_failed: 3189824a1566SKashyap Desai retval = -1; 3190824a1566SKashyap Desai return retval; 3191824a1566SKashyap Desai } 3192824a1566SKashyap Desai 3193824a1566SKashyap Desai /** 3194023ab2a9SKashyap Desai * mpi3mr_port_enable_complete - Mark port enable complete 3195023ab2a9SKashyap Desai * @mrioc: Adapter instance reference 3196023ab2a9SKashyap Desai * @drv_cmd: Internal command tracker 3197023ab2a9SKashyap Desai * 3198023ab2a9SKashyap Desai * Call back for asynchronous port enable request sets the 3199023ab2a9SKashyap Desai * driver command to indicate port enable request is complete. 3200023ab2a9SKashyap Desai * 3201023ab2a9SKashyap Desai * Return: Nothing 3202023ab2a9SKashyap Desai */ 3203023ab2a9SKashyap Desai static void mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc, 3204023ab2a9SKashyap Desai struct mpi3mr_drv_cmd *drv_cmd) 3205023ab2a9SKashyap Desai { 3206023ab2a9SKashyap Desai drv_cmd->state = MPI3MR_CMD_NOTUSED; 3207023ab2a9SKashyap Desai drv_cmd->callback = NULL; 3208023ab2a9SKashyap Desai mrioc->scan_failed = drv_cmd->ioc_status; 3209023ab2a9SKashyap Desai mrioc->scan_started = 0; 3210023ab2a9SKashyap Desai } 3211023ab2a9SKashyap Desai 3212023ab2a9SKashyap Desai /** 3213023ab2a9SKashyap Desai * mpi3mr_issue_port_enable - Issue Port Enable 3214023ab2a9SKashyap Desai * @mrioc: Adapter instance reference 3215023ab2a9SKashyap Desai * @async: Flag to wait for completion or not 3216023ab2a9SKashyap Desai * 3217023ab2a9SKashyap Desai * Issue Port Enable MPI request through admin queue and if the 3218023ab2a9SKashyap Desai * async flag is not set wait for the completion of the port 3219023ab2a9SKashyap Desai * enable or time out. 3220023ab2a9SKashyap Desai * 3221023ab2a9SKashyap Desai * Return: 0 on success, non-zero on failures. 3222023ab2a9SKashyap Desai */ 3223023ab2a9SKashyap Desai int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async) 3224023ab2a9SKashyap Desai { 3225023ab2a9SKashyap Desai struct mpi3_port_enable_request pe_req; 3226023ab2a9SKashyap Desai int retval = 0; 3227023ab2a9SKashyap Desai u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT; 3228023ab2a9SKashyap Desai 3229023ab2a9SKashyap Desai memset(&pe_req, 0, sizeof(pe_req)); 3230023ab2a9SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 3231023ab2a9SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 3232023ab2a9SKashyap Desai retval = -1; 3233023ab2a9SKashyap Desai ioc_err(mrioc, "Issue PortEnable: Init command is in use\n"); 3234023ab2a9SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 3235023ab2a9SKashyap Desai goto out; 3236023ab2a9SKashyap Desai } 3237023ab2a9SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 3238023ab2a9SKashyap Desai if (async) { 3239023ab2a9SKashyap Desai mrioc->init_cmds.is_waiting = 0; 3240023ab2a9SKashyap Desai mrioc->init_cmds.callback = mpi3mr_port_enable_complete; 3241023ab2a9SKashyap Desai } else { 3242023ab2a9SKashyap Desai mrioc->init_cmds.is_waiting = 1; 3243023ab2a9SKashyap Desai mrioc->init_cmds.callback = NULL; 3244023ab2a9SKashyap Desai init_completion(&mrioc->init_cmds.done); 3245023ab2a9SKashyap Desai } 3246023ab2a9SKashyap Desai pe_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 3247023ab2a9SKashyap Desai pe_req.function = MPI3_FUNCTION_PORT_ENABLE; 3248023ab2a9SKashyap Desai 3249023ab2a9SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &pe_req, sizeof(pe_req), 1); 3250023ab2a9SKashyap Desai if (retval) { 3251023ab2a9SKashyap Desai ioc_err(mrioc, "Issue PortEnable: Admin Post failed\n"); 3252023ab2a9SKashyap Desai goto out_unlock; 3253023ab2a9SKashyap Desai } 3254a6856cc4SSreekanth Reddy if (async) { 3255a6856cc4SSreekanth Reddy mutex_unlock(&mrioc->init_cmds.mutex); 3256a6856cc4SSreekanth Reddy goto out; 3257a6856cc4SSreekanth Reddy } 3258a6856cc4SSreekanth Reddy 3259a6856cc4SSreekanth Reddy wait_for_completion_timeout(&mrioc->init_cmds.done, (pe_timeout * HZ)); 3260023ab2a9SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 3261a6856cc4SSreekanth Reddy ioc_err(mrioc, "port enable timed out\n"); 3262023ab2a9SKashyap Desai retval = -1; 3263a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, MPI3MR_RESET_FROM_PE_TIMEOUT); 3264023ab2a9SKashyap Desai goto out_unlock; 3265023ab2a9SKashyap Desai } 3266023ab2a9SKashyap Desai mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds); 3267a6856cc4SSreekanth Reddy 3268023ab2a9SKashyap Desai out_unlock: 3269a6856cc4SSreekanth Reddy mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 3270023ab2a9SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 3271023ab2a9SKashyap Desai out: 3272023ab2a9SKashyap Desai return retval; 3273023ab2a9SKashyap Desai } 3274023ab2a9SKashyap Desai 3275ff9561e9SKashyap Desai /* Protocol type to name mapper structure */ 3276ff9561e9SKashyap Desai static const struct { 3277ff9561e9SKashyap Desai u8 protocol; 3278ff9561e9SKashyap Desai char *name; 3279ff9561e9SKashyap Desai } mpi3mr_protocols[] = { 3280ff9561e9SKashyap Desai { MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR, "Initiator" }, 3281ff9561e9SKashyap Desai { MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET, "Target" }, 3282ff9561e9SKashyap Desai { MPI3_IOCFACTS_PROTOCOL_NVME, "NVMe attachment" }, 3283ff9561e9SKashyap Desai }; 3284ff9561e9SKashyap Desai 3285ff9561e9SKashyap Desai /* Capability to name mapper structure*/ 3286ff9561e9SKashyap Desai static const struct { 3287ff9561e9SKashyap Desai u32 capability; 3288ff9561e9SKashyap Desai char *name; 3289ff9561e9SKashyap Desai } mpi3mr_capabilities[] = { 3290ff9561e9SKashyap Desai { MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE, "RAID" }, 3291ff9561e9SKashyap Desai }; 3292ff9561e9SKashyap Desai 3293ff9561e9SKashyap Desai /** 3294ff9561e9SKashyap Desai * mpi3mr_print_ioc_info - Display controller information 3295ff9561e9SKashyap Desai * @mrioc: Adapter instance reference 3296ff9561e9SKashyap Desai * 3297ff9561e9SKashyap Desai * Display controller personalit, capability, supported 3298ff9561e9SKashyap Desai * protocols etc. 3299ff9561e9SKashyap Desai * 3300ff9561e9SKashyap Desai * Return: Nothing 3301ff9561e9SKashyap Desai */ 3302ff9561e9SKashyap Desai static void 3303ff9561e9SKashyap Desai mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc) 3304ff9561e9SKashyap Desai { 330576a4f7ccSDan Carpenter int i = 0, bytes_written = 0; 3306ff9561e9SKashyap Desai char personality[16]; 3307ff9561e9SKashyap Desai char protocol[50] = {0}; 3308ff9561e9SKashyap Desai char capabilities[100] = {0}; 3309ff9561e9SKashyap Desai struct mpi3mr_compimg_ver *fwver = &mrioc->facts.fw_ver; 3310ff9561e9SKashyap Desai 3311ff9561e9SKashyap Desai switch (mrioc->facts.personality) { 3312ff9561e9SKashyap Desai case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA: 3313ff9561e9SKashyap Desai strncpy(personality, "Enhanced HBA", sizeof(personality)); 3314ff9561e9SKashyap Desai break; 3315ff9561e9SKashyap Desai case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR: 3316ff9561e9SKashyap Desai strncpy(personality, "RAID", sizeof(personality)); 3317ff9561e9SKashyap Desai break; 3318ff9561e9SKashyap Desai default: 3319ff9561e9SKashyap Desai strncpy(personality, "Unknown", sizeof(personality)); 3320ff9561e9SKashyap Desai break; 3321ff9561e9SKashyap Desai } 3322ff9561e9SKashyap Desai 3323ff9561e9SKashyap Desai ioc_info(mrioc, "Running in %s Personality", personality); 3324ff9561e9SKashyap Desai 3325ff9561e9SKashyap Desai ioc_info(mrioc, "FW version(%d.%d.%d.%d.%d.%d)\n", 3326ff9561e9SKashyap Desai fwver->gen_major, fwver->gen_minor, fwver->ph_major, 3327ff9561e9SKashyap Desai fwver->ph_minor, fwver->cust_id, fwver->build_num); 3328ff9561e9SKashyap Desai 3329ff9561e9SKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_protocols); i++) { 3330ff9561e9SKashyap Desai if (mrioc->facts.protocol_flags & 3331ff9561e9SKashyap Desai mpi3mr_protocols[i].protocol) { 333230e99f05SDan Carpenter bytes_written += scnprintf(protocol + bytes_written, 333376a4f7ccSDan Carpenter sizeof(protocol) - bytes_written, "%s%s", 333476a4f7ccSDan Carpenter bytes_written ? "," : "", 3335ff9561e9SKashyap Desai mpi3mr_protocols[i].name); 3336ff9561e9SKashyap Desai } 3337ff9561e9SKashyap Desai } 3338ff9561e9SKashyap Desai 333976a4f7ccSDan Carpenter bytes_written = 0; 3340ff9561e9SKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_capabilities); i++) { 3341ff9561e9SKashyap Desai if (mrioc->facts.protocol_flags & 3342ff9561e9SKashyap Desai mpi3mr_capabilities[i].capability) { 334330e99f05SDan Carpenter bytes_written += scnprintf(capabilities + bytes_written, 334476a4f7ccSDan Carpenter sizeof(capabilities) - bytes_written, "%s%s", 334576a4f7ccSDan Carpenter bytes_written ? "," : "", 3346ff9561e9SKashyap Desai mpi3mr_capabilities[i].name); 3347ff9561e9SKashyap Desai } 3348ff9561e9SKashyap Desai } 3349ff9561e9SKashyap Desai 3350ff9561e9SKashyap Desai ioc_info(mrioc, "Protocol=(%s), Capabilities=(%s)\n", 3351ff9561e9SKashyap Desai protocol, capabilities); 3352ff9561e9SKashyap Desai } 3353ff9561e9SKashyap Desai 3354023ab2a9SKashyap Desai /** 3355824a1566SKashyap Desai * mpi3mr_cleanup_resources - Free PCI resources 3356824a1566SKashyap Desai * @mrioc: Adapter instance reference 3357824a1566SKashyap Desai * 3358824a1566SKashyap Desai * Unmap PCI device memory and disable PCI device. 3359824a1566SKashyap Desai * 3360824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 3361824a1566SKashyap Desai */ 3362824a1566SKashyap Desai void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc) 3363824a1566SKashyap Desai { 3364824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 3365824a1566SKashyap Desai 3366824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 3367824a1566SKashyap Desai 3368824a1566SKashyap Desai if (mrioc->sysif_regs) { 3369824a1566SKashyap Desai iounmap((void __iomem *)mrioc->sysif_regs); 3370824a1566SKashyap Desai mrioc->sysif_regs = NULL; 3371824a1566SKashyap Desai } 3372824a1566SKashyap Desai 3373824a1566SKashyap Desai if (pci_is_enabled(pdev)) { 3374824a1566SKashyap Desai if (mrioc->bars) 3375824a1566SKashyap Desai pci_release_selected_regions(pdev, mrioc->bars); 3376824a1566SKashyap Desai pci_disable_device(pdev); 3377824a1566SKashyap Desai } 3378824a1566SKashyap Desai } 3379824a1566SKashyap Desai 3380824a1566SKashyap Desai /** 3381824a1566SKashyap Desai * mpi3mr_setup_resources - Enable PCI resources 3382824a1566SKashyap Desai * @mrioc: Adapter instance reference 3383824a1566SKashyap Desai * 3384824a1566SKashyap Desai * Enable PCI device memory, MSI-x registers and set DMA mask. 3385824a1566SKashyap Desai * 3386824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 3387824a1566SKashyap Desai */ 3388824a1566SKashyap Desai int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc) 3389824a1566SKashyap Desai { 3390824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 3391824a1566SKashyap Desai u32 memap_sz = 0; 3392824a1566SKashyap Desai int i, retval = 0, capb = 0; 3393824a1566SKashyap Desai u16 message_control; 3394824a1566SKashyap Desai u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask : 3395824a1566SKashyap Desai (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) && 3396824a1566SKashyap Desai (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32)); 3397824a1566SKashyap Desai 3398824a1566SKashyap Desai if (pci_enable_device_mem(pdev)) { 3399824a1566SKashyap Desai ioc_err(mrioc, "pci_enable_device_mem: failed\n"); 3400824a1566SKashyap Desai retval = -ENODEV; 3401824a1566SKashyap Desai goto out_failed; 3402824a1566SKashyap Desai } 3403824a1566SKashyap Desai 3404824a1566SKashyap Desai capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX); 3405824a1566SKashyap Desai if (!capb) { 3406824a1566SKashyap Desai ioc_err(mrioc, "Unable to find MSI-X Capabilities\n"); 3407824a1566SKashyap Desai retval = -ENODEV; 3408824a1566SKashyap Desai goto out_failed; 3409824a1566SKashyap Desai } 3410824a1566SKashyap Desai mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); 3411824a1566SKashyap Desai 3412824a1566SKashyap Desai if (pci_request_selected_regions(pdev, mrioc->bars, 3413824a1566SKashyap Desai mrioc->driver_name)) { 3414824a1566SKashyap Desai ioc_err(mrioc, "pci_request_selected_regions: failed\n"); 3415824a1566SKashyap Desai retval = -ENODEV; 3416824a1566SKashyap Desai goto out_failed; 3417824a1566SKashyap Desai } 3418824a1566SKashyap Desai 3419824a1566SKashyap Desai for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) { 3420824a1566SKashyap Desai if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { 3421824a1566SKashyap Desai mrioc->sysif_regs_phys = pci_resource_start(pdev, i); 3422824a1566SKashyap Desai memap_sz = pci_resource_len(pdev, i); 3423824a1566SKashyap Desai mrioc->sysif_regs = 3424824a1566SKashyap Desai ioremap(mrioc->sysif_regs_phys, memap_sz); 3425824a1566SKashyap Desai break; 3426824a1566SKashyap Desai } 3427824a1566SKashyap Desai } 3428824a1566SKashyap Desai 3429824a1566SKashyap Desai pci_set_master(pdev); 3430824a1566SKashyap Desai 3431824a1566SKashyap Desai retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask); 3432824a1566SKashyap Desai if (retval) { 3433824a1566SKashyap Desai if (dma_mask != DMA_BIT_MASK(32)) { 3434824a1566SKashyap Desai ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n"); 3435824a1566SKashyap Desai dma_mask = DMA_BIT_MASK(32); 3436824a1566SKashyap Desai retval = dma_set_mask_and_coherent(&pdev->dev, 3437824a1566SKashyap Desai dma_mask); 3438824a1566SKashyap Desai } 3439824a1566SKashyap Desai if (retval) { 3440824a1566SKashyap Desai mrioc->dma_mask = 0; 3441824a1566SKashyap Desai ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n"); 3442824a1566SKashyap Desai goto out_failed; 3443824a1566SKashyap Desai } 3444824a1566SKashyap Desai } 3445824a1566SKashyap Desai mrioc->dma_mask = dma_mask; 3446824a1566SKashyap Desai 3447824a1566SKashyap Desai if (!mrioc->sysif_regs) { 3448824a1566SKashyap Desai ioc_err(mrioc, 3449824a1566SKashyap Desai "Unable to map adapter memory or resource not found\n"); 3450824a1566SKashyap Desai retval = -EINVAL; 3451824a1566SKashyap Desai goto out_failed; 3452824a1566SKashyap Desai } 3453824a1566SKashyap Desai 3454824a1566SKashyap Desai pci_read_config_word(pdev, capb + 2, &message_control); 3455824a1566SKashyap Desai mrioc->msix_count = (message_control & 0x3FF) + 1; 3456824a1566SKashyap Desai 3457824a1566SKashyap Desai pci_save_state(pdev); 3458824a1566SKashyap Desai 3459824a1566SKashyap Desai pci_set_drvdata(pdev, mrioc->shost); 3460824a1566SKashyap Desai 3461824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 3462824a1566SKashyap Desai 3463824a1566SKashyap Desai ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n", 3464824a1566SKashyap Desai (unsigned long long)mrioc->sysif_regs_phys, 3465824a1566SKashyap Desai mrioc->sysif_regs, memap_sz); 3466824a1566SKashyap Desai ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n", 3467824a1566SKashyap Desai mrioc->msix_count); 3468824a1566SKashyap Desai return retval; 3469824a1566SKashyap Desai 3470824a1566SKashyap Desai out_failed: 3471824a1566SKashyap Desai mpi3mr_cleanup_resources(mrioc); 3472824a1566SKashyap Desai return retval; 3473824a1566SKashyap Desai } 3474824a1566SKashyap Desai 3475824a1566SKashyap Desai /** 3476e3605f65SSreekanth Reddy * mpi3mr_enable_events - Enable required events 3477e3605f65SSreekanth Reddy * @mrioc: Adapter instance reference 3478e3605f65SSreekanth Reddy * 3479e3605f65SSreekanth Reddy * This routine unmasks the events required by the driver by 3480e3605f65SSreekanth Reddy * sennding appropriate event mask bitmapt through an event 3481e3605f65SSreekanth Reddy * notification request. 3482e3605f65SSreekanth Reddy * 3483e3605f65SSreekanth Reddy * Return: 0 on success and non-zero on failure. 3484e3605f65SSreekanth Reddy */ 3485e3605f65SSreekanth Reddy static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc) 3486e3605f65SSreekanth Reddy { 3487e3605f65SSreekanth Reddy int retval = 0; 3488e3605f65SSreekanth Reddy u32 i; 3489e3605f65SSreekanth Reddy 3490e3605f65SSreekanth Reddy for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 3491e3605f65SSreekanth Reddy mrioc->event_masks[i] = -1; 3492e3605f65SSreekanth Reddy 3493e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED); 3494e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED); 3495e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE); 3496e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE); 3497e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST); 3498e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY); 3499e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR); 3500e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE); 3501e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST); 3502e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION); 3503*78b76a07SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_PREPARE_FOR_RESET); 3504e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT); 3505e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE); 3506e3605f65SSreekanth Reddy 3507e3605f65SSreekanth Reddy retval = mpi3mr_issue_event_notification(mrioc); 3508e3605f65SSreekanth Reddy if (retval) 3509e3605f65SSreekanth Reddy ioc_err(mrioc, "failed to issue event notification %d\n", 3510e3605f65SSreekanth Reddy retval); 3511e3605f65SSreekanth Reddy return retval; 3512e3605f65SSreekanth Reddy } 3513e3605f65SSreekanth Reddy 3514e3605f65SSreekanth Reddy /** 3515824a1566SKashyap Desai * mpi3mr_init_ioc - Initialize the controller 3516824a1566SKashyap Desai * @mrioc: Adapter instance reference 35170da66348SKashyap Desai * @init_type: Flag to indicate is the init_type 3518824a1566SKashyap Desai * 3519824a1566SKashyap Desai * This the controller initialization routine, executed either 3520824a1566SKashyap Desai * after soft reset or from pci probe callback. 3521824a1566SKashyap Desai * Setup the required resources, memory map the controller 3522824a1566SKashyap Desai * registers, create admin and operational reply queue pairs, 3523824a1566SKashyap Desai * allocate required memory for reply pool, sense buffer pool, 3524824a1566SKashyap Desai * issue IOC init request to the firmware, unmask the events and 3525824a1566SKashyap Desai * issue port enable to discover SAS/SATA/NVMe devies and RAID 3526824a1566SKashyap Desai * volumes. 3527824a1566SKashyap Desai * 3528824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 3529824a1566SKashyap Desai */ 3530fe6db615SSreekanth Reddy int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc) 3531824a1566SKashyap Desai { 3532824a1566SKashyap Desai int retval = 0; 3533fe6db615SSreekanth Reddy u8 retry = 0; 3534824a1566SKashyap Desai struct mpi3_ioc_facts_data facts_data; 3535824a1566SKashyap Desai 3536fe6db615SSreekanth Reddy retry_init: 3537824a1566SKashyap Desai retval = mpi3mr_bring_ioc_ready(mrioc); 3538824a1566SKashyap Desai if (retval) { 3539824a1566SKashyap Desai ioc_err(mrioc, "Failed to bring ioc ready: error %d\n", 3540824a1566SKashyap Desai retval); 3541fe6db615SSreekanth Reddy goto out_failed_noretry; 3542824a1566SKashyap Desai } 3543824a1566SKashyap Desai 3544824a1566SKashyap Desai retval = mpi3mr_setup_isr(mrioc, 1); 3545824a1566SKashyap Desai if (retval) { 3546824a1566SKashyap Desai ioc_err(mrioc, "Failed to setup ISR error %d\n", 3547824a1566SKashyap Desai retval); 3548fe6db615SSreekanth Reddy goto out_failed_noretry; 3549824a1566SKashyap Desai } 3550824a1566SKashyap Desai 3551824a1566SKashyap Desai retval = mpi3mr_issue_iocfacts(mrioc, &facts_data); 3552824a1566SKashyap Desai if (retval) { 3553824a1566SKashyap Desai ioc_err(mrioc, "Failed to Issue IOC Facts %d\n", 3554824a1566SKashyap Desai retval); 3555824a1566SKashyap Desai goto out_failed; 3556824a1566SKashyap Desai } 3557824a1566SKashyap Desai 3558c5758fc7SSreekanth Reddy mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD; 3559c5758fc7SSreekanth Reddy 3560c5758fc7SSreekanth Reddy if (reset_devices) 3561c5758fc7SSreekanth Reddy mrioc->max_host_ios = min_t(int, mrioc->max_host_ios, 3562c5758fc7SSreekanth Reddy MPI3MR_HOST_IOS_KDUMP); 3563c5758fc7SSreekanth Reddy 3564c5758fc7SSreekanth Reddy mrioc->reply_sz = mrioc->facts.reply_sz; 3565fe6db615SSreekanth Reddy 3566824a1566SKashyap Desai retval = mpi3mr_check_reset_dma_mask(mrioc); 3567824a1566SKashyap Desai if (retval) { 3568824a1566SKashyap Desai ioc_err(mrioc, "Resetting dma mask failed %d\n", 3569824a1566SKashyap Desai retval); 3570fe6db615SSreekanth Reddy goto out_failed_noretry; 3571fb9b0457SKashyap Desai } 3572824a1566SKashyap Desai 3573ff9561e9SKashyap Desai mpi3mr_print_ioc_info(mrioc); 3574ff9561e9SKashyap Desai 3575824a1566SKashyap Desai retval = mpi3mr_alloc_reply_sense_bufs(mrioc); 3576824a1566SKashyap Desai if (retval) { 3577824a1566SKashyap Desai ioc_err(mrioc, 3578824a1566SKashyap Desai "%s :Failed to allocated reply sense buffers %d\n", 3579824a1566SKashyap Desai __func__, retval); 3580fe6db615SSreekanth Reddy goto out_failed_noretry; 3581824a1566SKashyap Desai } 3582824a1566SKashyap Desai 3583824a1566SKashyap Desai retval = mpi3mr_alloc_chain_bufs(mrioc); 3584824a1566SKashyap Desai if (retval) { 3585824a1566SKashyap Desai ioc_err(mrioc, "Failed to allocated chain buffers %d\n", 3586824a1566SKashyap Desai retval); 3587fe6db615SSreekanth Reddy goto out_failed_noretry; 3588fb9b0457SKashyap Desai } 3589824a1566SKashyap Desai 3590824a1566SKashyap Desai retval = mpi3mr_issue_iocinit(mrioc); 3591824a1566SKashyap Desai if (retval) { 3592824a1566SKashyap Desai ioc_err(mrioc, "Failed to Issue IOC Init %d\n", 3593824a1566SKashyap Desai retval); 3594824a1566SKashyap Desai goto out_failed; 3595824a1566SKashyap Desai } 3596824a1566SKashyap Desai 35972ac794baSSreekanth Reddy retval = mpi3mr_print_pkg_ver(mrioc); 35982ac794baSSreekanth Reddy if (retval) { 35992ac794baSSreekanth Reddy ioc_err(mrioc, "failed to get package version\n"); 36002ac794baSSreekanth Reddy goto out_failed; 36012ac794baSSreekanth Reddy } 36022ac794baSSreekanth Reddy 3603824a1566SKashyap Desai retval = mpi3mr_setup_isr(mrioc, 0); 3604824a1566SKashyap Desai if (retval) { 3605824a1566SKashyap Desai ioc_err(mrioc, "Failed to re-setup ISR, error %d\n", 3606824a1566SKashyap Desai retval); 3607fe6db615SSreekanth Reddy goto out_failed_noretry; 3608fb9b0457SKashyap Desai } 3609824a1566SKashyap Desai 3610c9566231SKashyap Desai retval = mpi3mr_create_op_queues(mrioc); 3611c9566231SKashyap Desai if (retval) { 3612c9566231SKashyap Desai ioc_err(mrioc, "Failed to create OpQueues error %d\n", 3613c9566231SKashyap Desai retval); 3614c9566231SKashyap Desai goto out_failed; 3615c9566231SKashyap Desai } 3616c9566231SKashyap Desai 3617e3605f65SSreekanth Reddy retval = mpi3mr_enable_events(mrioc); 361813ef29eaSKashyap Desai if (retval) { 3619e3605f65SSreekanth Reddy ioc_err(mrioc, "failed to enable events %d\n", 362013ef29eaSKashyap Desai retval); 362113ef29eaSKashyap Desai goto out_failed; 362213ef29eaSKashyap Desai } 362313ef29eaSKashyap Desai 3624fe6db615SSreekanth Reddy ioc_info(mrioc, "controller initialization completed successfully\n"); 3625824a1566SKashyap Desai return retval; 3626824a1566SKashyap Desai out_failed: 3627fe6db615SSreekanth Reddy if (retry < 2) { 3628fe6db615SSreekanth Reddy retry++; 3629fe6db615SSreekanth Reddy ioc_warn(mrioc, "retrying controller initialization, retry_count:%d\n", 3630fe6db615SSreekanth Reddy retry); 3631fe6db615SSreekanth Reddy mpi3mr_memset_buffers(mrioc); 3632fe6db615SSreekanth Reddy goto retry_init; 3633fe6db615SSreekanth Reddy } 3634fe6db615SSreekanth Reddy out_failed_noretry: 3635fe6db615SSreekanth Reddy ioc_err(mrioc, "controller initialization failed\n"); 3636fe6db615SSreekanth Reddy mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 3637fe6db615SSreekanth Reddy MPI3MR_RESET_FROM_CTLR_CLEANUP); 3638fe6db615SSreekanth Reddy mrioc->unrecoverable = 1; 3639824a1566SKashyap Desai return retval; 3640824a1566SKashyap Desai } 3641824a1566SKashyap Desai 3642c0b00a93SSreekanth Reddy /** 3643c0b00a93SSreekanth Reddy * mpi3mr_reinit_ioc - Re-Initialize the controller 3644c0b00a93SSreekanth Reddy * @mrioc: Adapter instance reference 3645c0b00a93SSreekanth Reddy * @is_resume: Called from resume or reset path 3646c0b00a93SSreekanth Reddy * 3647c0b00a93SSreekanth Reddy * This the controller re-initialization routine, executed from 3648c0b00a93SSreekanth Reddy * the soft reset handler or resume callback. Creates 3649c0b00a93SSreekanth Reddy * operational reply queue pairs, allocate required memory for 3650c0b00a93SSreekanth Reddy * reply pool, sense buffer pool, issue IOC init request to the 3651c0b00a93SSreekanth Reddy * firmware, unmask the events and issue port enable to discover 3652c0b00a93SSreekanth Reddy * SAS/SATA/NVMe devices and RAID volumes. 3653c0b00a93SSreekanth Reddy * 3654c0b00a93SSreekanth Reddy * Return: 0 on success and non-zero on failure. 3655c0b00a93SSreekanth Reddy */ 3656fe6db615SSreekanth Reddy int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume) 3657fe6db615SSreekanth Reddy { 3658c0b00a93SSreekanth Reddy int retval = 0; 3659c0b00a93SSreekanth Reddy u8 retry = 0; 3660c0b00a93SSreekanth Reddy struct mpi3_ioc_facts_data facts_data; 3661fe6db615SSreekanth Reddy 3662c0b00a93SSreekanth Reddy retry_init: 3663c0b00a93SSreekanth Reddy dprint_reset(mrioc, "bringing up the controller to ready state\n"); 3664c0b00a93SSreekanth Reddy retval = mpi3mr_bring_ioc_ready(mrioc); 3665c0b00a93SSreekanth Reddy if (retval) { 3666c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to bring to ready state\n"); 3667c0b00a93SSreekanth Reddy goto out_failed_noretry; 3668c0b00a93SSreekanth Reddy } 3669c0b00a93SSreekanth Reddy 3670c0b00a93SSreekanth Reddy if (is_resume) { 3671c0b00a93SSreekanth Reddy dprint_reset(mrioc, "setting up single ISR\n"); 3672c0b00a93SSreekanth Reddy retval = mpi3mr_setup_isr(mrioc, 1); 3673c0b00a93SSreekanth Reddy if (retval) { 3674c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to setup ISR\n"); 3675c0b00a93SSreekanth Reddy goto out_failed_noretry; 3676c0b00a93SSreekanth Reddy } 3677c0b00a93SSreekanth Reddy } else 3678c0b00a93SSreekanth Reddy mpi3mr_ioc_enable_intr(mrioc); 3679c0b00a93SSreekanth Reddy 3680c0b00a93SSreekanth Reddy dprint_reset(mrioc, "getting ioc_facts\n"); 3681c0b00a93SSreekanth Reddy retval = mpi3mr_issue_iocfacts(mrioc, &facts_data); 3682c0b00a93SSreekanth Reddy if (retval) { 3683c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to get ioc_facts\n"); 3684c0b00a93SSreekanth Reddy goto out_failed; 3685c0b00a93SSreekanth Reddy } 3686c0b00a93SSreekanth Reddy 3687c5758fc7SSreekanth Reddy dprint_reset(mrioc, "validating ioc_facts\n"); 3688c5758fc7SSreekanth Reddy retval = mpi3mr_revalidate_factsdata(mrioc); 3689c5758fc7SSreekanth Reddy if (retval) { 3690c5758fc7SSreekanth Reddy ioc_err(mrioc, "failed to revalidate ioc_facts data\n"); 3691c5758fc7SSreekanth Reddy goto out_failed_noretry; 3692c5758fc7SSreekanth Reddy } 3693c0b00a93SSreekanth Reddy 3694c0b00a93SSreekanth Reddy mpi3mr_print_ioc_info(mrioc); 3695c0b00a93SSreekanth Reddy 3696c0b00a93SSreekanth Reddy dprint_reset(mrioc, "sending ioc_init\n"); 3697c0b00a93SSreekanth Reddy retval = mpi3mr_issue_iocinit(mrioc); 3698c0b00a93SSreekanth Reddy if (retval) { 3699c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to send ioc_init\n"); 3700c0b00a93SSreekanth Reddy goto out_failed; 3701c0b00a93SSreekanth Reddy } 3702c0b00a93SSreekanth Reddy 3703c0b00a93SSreekanth Reddy dprint_reset(mrioc, "getting package version\n"); 3704c0b00a93SSreekanth Reddy retval = mpi3mr_print_pkg_ver(mrioc); 3705c0b00a93SSreekanth Reddy if (retval) { 3706c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to get package version\n"); 3707c0b00a93SSreekanth Reddy goto out_failed; 3708c0b00a93SSreekanth Reddy } 3709c0b00a93SSreekanth Reddy 3710c0b00a93SSreekanth Reddy if (is_resume) { 3711c0b00a93SSreekanth Reddy dprint_reset(mrioc, "setting up multiple ISR\n"); 3712c0b00a93SSreekanth Reddy retval = mpi3mr_setup_isr(mrioc, 0); 3713c0b00a93SSreekanth Reddy if (retval) { 3714c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to re-setup ISR\n"); 3715c0b00a93SSreekanth Reddy goto out_failed_noretry; 3716c0b00a93SSreekanth Reddy } 3717c0b00a93SSreekanth Reddy } 3718c0b00a93SSreekanth Reddy 3719c0b00a93SSreekanth Reddy dprint_reset(mrioc, "creating operational queue pairs\n"); 3720c0b00a93SSreekanth Reddy retval = mpi3mr_create_op_queues(mrioc); 3721c0b00a93SSreekanth Reddy if (retval) { 3722c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to create operational queue pairs\n"); 3723c0b00a93SSreekanth Reddy goto out_failed; 3724c0b00a93SSreekanth Reddy } 3725c0b00a93SSreekanth Reddy 3726c0b00a93SSreekanth Reddy if (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q) { 3727c0b00a93SSreekanth Reddy ioc_err(mrioc, 3728c0b00a93SSreekanth Reddy "cannot create minimum number of operatioanl queues expected:%d created:%d\n", 3729c0b00a93SSreekanth Reddy mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q); 3730c0b00a93SSreekanth Reddy goto out_failed_noretry; 3731c0b00a93SSreekanth Reddy } 3732c0b00a93SSreekanth Reddy 3733c0b00a93SSreekanth Reddy dprint_reset(mrioc, "enabling events\n"); 3734c0b00a93SSreekanth Reddy retval = mpi3mr_enable_events(mrioc); 3735c0b00a93SSreekanth Reddy if (retval) { 3736c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to enable events\n"); 3737c0b00a93SSreekanth Reddy goto out_failed; 3738c0b00a93SSreekanth Reddy } 3739c0b00a93SSreekanth Reddy 3740c0b00a93SSreekanth Reddy ioc_info(mrioc, "sending port enable\n"); 3741c0b00a93SSreekanth Reddy retval = mpi3mr_issue_port_enable(mrioc, 0); 3742c0b00a93SSreekanth Reddy if (retval) { 3743c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to issue port enable\n"); 3744c0b00a93SSreekanth Reddy goto out_failed; 3745c0b00a93SSreekanth Reddy } 3746c0b00a93SSreekanth Reddy 3747c0b00a93SSreekanth Reddy ioc_info(mrioc, "controller %s completed successfully\n", 3748c0b00a93SSreekanth Reddy (is_resume)?"resume":"re-initialization"); 3749c0b00a93SSreekanth Reddy return retval; 3750c0b00a93SSreekanth Reddy out_failed: 3751c0b00a93SSreekanth Reddy if (retry < 2) { 3752c0b00a93SSreekanth Reddy retry++; 3753c0b00a93SSreekanth Reddy ioc_warn(mrioc, "retrying controller %s, retry_count:%d\n", 3754c0b00a93SSreekanth Reddy (is_resume)?"resume":"re-initialization", retry); 3755c0b00a93SSreekanth Reddy mpi3mr_memset_buffers(mrioc); 3756c0b00a93SSreekanth Reddy goto retry_init; 3757c0b00a93SSreekanth Reddy } 3758c0b00a93SSreekanth Reddy out_failed_noretry: 3759c0b00a93SSreekanth Reddy ioc_err(mrioc, "controller %s is failed\n", 3760c0b00a93SSreekanth Reddy (is_resume)?"resume":"re-initialization"); 3761c0b00a93SSreekanth Reddy mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 3762c0b00a93SSreekanth Reddy MPI3MR_RESET_FROM_CTLR_CLEANUP); 3763c0b00a93SSreekanth Reddy mrioc->unrecoverable = 1; 3764c0b00a93SSreekanth Reddy return retval; 3765fe6db615SSreekanth Reddy } 3766fe6db615SSreekanth Reddy 3767824a1566SKashyap Desai /** 3768fb9b0457SKashyap Desai * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's 3769fb9b0457SKashyap Desai * segments 3770fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3771fb9b0457SKashyap Desai * @qidx: Operational reply queue index 3772fb9b0457SKashyap Desai * 3773fb9b0457SKashyap Desai * Return: Nothing. 3774fb9b0457SKashyap Desai */ 3775fb9b0457SKashyap Desai static void mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx) 3776fb9b0457SKashyap Desai { 3777fb9b0457SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 3778fb9b0457SKashyap Desai struct segments *segments; 3779fb9b0457SKashyap Desai int i, size; 3780fb9b0457SKashyap Desai 3781fb9b0457SKashyap Desai if (!op_reply_q->q_segments) 3782fb9b0457SKashyap Desai return; 3783fb9b0457SKashyap Desai 3784fb9b0457SKashyap Desai size = op_reply_q->segment_qd * mrioc->op_reply_desc_sz; 3785fb9b0457SKashyap Desai segments = op_reply_q->q_segments; 3786fb9b0457SKashyap Desai for (i = 0; i < op_reply_q->num_segments; i++) 3787fb9b0457SKashyap Desai memset(segments[i].segment, 0, size); 3788fb9b0457SKashyap Desai } 3789fb9b0457SKashyap Desai 3790fb9b0457SKashyap Desai /** 3791fb9b0457SKashyap Desai * mpi3mr_memset_op_req_q_buffers - memset the operational request queue's 3792fb9b0457SKashyap Desai * segments 3793fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3794fb9b0457SKashyap Desai * @qidx: Operational request queue index 3795fb9b0457SKashyap Desai * 3796fb9b0457SKashyap Desai * Return: Nothing. 3797fb9b0457SKashyap Desai */ 3798fb9b0457SKashyap Desai static void mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx) 3799fb9b0457SKashyap Desai { 3800fb9b0457SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx; 3801fb9b0457SKashyap Desai struct segments *segments; 3802fb9b0457SKashyap Desai int i, size; 3803fb9b0457SKashyap Desai 3804fb9b0457SKashyap Desai if (!op_req_q->q_segments) 3805fb9b0457SKashyap Desai return; 3806fb9b0457SKashyap Desai 3807fb9b0457SKashyap Desai size = op_req_q->segment_qd * mrioc->facts.op_req_sz; 3808fb9b0457SKashyap Desai segments = op_req_q->q_segments; 3809fb9b0457SKashyap Desai for (i = 0; i < op_req_q->num_segments; i++) 3810fb9b0457SKashyap Desai memset(segments[i].segment, 0, size); 3811fb9b0457SKashyap Desai } 3812fb9b0457SKashyap Desai 3813fb9b0457SKashyap Desai /** 3814fb9b0457SKashyap Desai * mpi3mr_memset_buffers - memset memory for a controller 3815fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3816fb9b0457SKashyap Desai * 3817fb9b0457SKashyap Desai * clear all the memory allocated for a controller, typically 3818fb9b0457SKashyap Desai * called post reset to reuse the memory allocated during the 3819fb9b0457SKashyap Desai * controller init. 3820fb9b0457SKashyap Desai * 3821fb9b0457SKashyap Desai * Return: Nothing. 3822fb9b0457SKashyap Desai */ 38230da66348SKashyap Desai void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) 3824fb9b0457SKashyap Desai { 3825fb9b0457SKashyap Desai u16 i; 3826fb9b0457SKashyap Desai 3827fe6db615SSreekanth Reddy mrioc->change_count = 0; 3828fe6db615SSreekanth Reddy if (mrioc->admin_req_base) 3829fb9b0457SKashyap Desai memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz); 3830fe6db615SSreekanth Reddy if (mrioc->admin_reply_base) 3831fb9b0457SKashyap Desai memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz); 3832fb9b0457SKashyap Desai 3833fe6db615SSreekanth Reddy if (mrioc->init_cmds.reply) { 3834fb9b0457SKashyap Desai memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply)); 3835e844adb1SKashyap Desai memset(mrioc->host_tm_cmds.reply, 0, 3836e844adb1SKashyap Desai sizeof(*mrioc->host_tm_cmds.reply)); 3837fb9b0457SKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) 3838fb9b0457SKashyap Desai memset(mrioc->dev_rmhs_cmds[i].reply, 0, 3839fb9b0457SKashyap Desai sizeof(*mrioc->dev_rmhs_cmds[i].reply)); 3840c1af985dSSreekanth Reddy for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) 3841c1af985dSSreekanth Reddy memset(mrioc->evtack_cmds[i].reply, 0, 3842c1af985dSSreekanth Reddy sizeof(*mrioc->evtack_cmds[i].reply)); 3843fb9b0457SKashyap Desai memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); 3844fb9b0457SKashyap Desai memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); 3845c1af985dSSreekanth Reddy memset(mrioc->evtack_cmds_bitmap, 0, 3846c1af985dSSreekanth Reddy mrioc->evtack_cmds_bitmap_sz); 3847fe6db615SSreekanth Reddy } 3848fb9b0457SKashyap Desai 3849fb9b0457SKashyap Desai for (i = 0; i < mrioc->num_queues; i++) { 3850fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].qid = 0; 3851fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].ci = 0; 3852fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].num_replies = 0; 3853fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].ephase = 0; 3854463429f8SKashyap Desai atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0); 3855463429f8SKashyap Desai atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0); 3856fb9b0457SKashyap Desai mpi3mr_memset_op_reply_q_buffers(mrioc, i); 3857fb9b0457SKashyap Desai 3858fb9b0457SKashyap Desai mrioc->req_qinfo[i].ci = 0; 3859fb9b0457SKashyap Desai mrioc->req_qinfo[i].pi = 0; 3860fb9b0457SKashyap Desai mrioc->req_qinfo[i].num_requests = 0; 3861fb9b0457SKashyap Desai mrioc->req_qinfo[i].qid = 0; 3862fb9b0457SKashyap Desai mrioc->req_qinfo[i].reply_qid = 0; 3863fb9b0457SKashyap Desai spin_lock_init(&mrioc->req_qinfo[i].q_lock); 3864fb9b0457SKashyap Desai mpi3mr_memset_op_req_q_buffers(mrioc, i); 3865fb9b0457SKashyap Desai } 3866fb9b0457SKashyap Desai } 3867fb9b0457SKashyap Desai 3868fb9b0457SKashyap Desai /** 3869824a1566SKashyap Desai * mpi3mr_free_mem - Free memory allocated for a controller 3870824a1566SKashyap Desai * @mrioc: Adapter instance reference 3871824a1566SKashyap Desai * 3872824a1566SKashyap Desai * Free all the memory allocated for a controller. 3873824a1566SKashyap Desai * 3874824a1566SKashyap Desai * Return: Nothing. 3875824a1566SKashyap Desai */ 3876fe6db615SSreekanth Reddy void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) 3877824a1566SKashyap Desai { 3878824a1566SKashyap Desai u16 i; 3879824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info; 3880824a1566SKashyap Desai 3881824a1566SKashyap Desai if (mrioc->sense_buf_pool) { 3882824a1566SKashyap Desai if (mrioc->sense_buf) 3883824a1566SKashyap Desai dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf, 3884824a1566SKashyap Desai mrioc->sense_buf_dma); 3885824a1566SKashyap Desai dma_pool_destroy(mrioc->sense_buf_pool); 3886824a1566SKashyap Desai mrioc->sense_buf = NULL; 3887824a1566SKashyap Desai mrioc->sense_buf_pool = NULL; 3888824a1566SKashyap Desai } 3889824a1566SKashyap Desai if (mrioc->sense_buf_q_pool) { 3890824a1566SKashyap Desai if (mrioc->sense_buf_q) 3891824a1566SKashyap Desai dma_pool_free(mrioc->sense_buf_q_pool, 3892824a1566SKashyap Desai mrioc->sense_buf_q, mrioc->sense_buf_q_dma); 3893824a1566SKashyap Desai dma_pool_destroy(mrioc->sense_buf_q_pool); 3894824a1566SKashyap Desai mrioc->sense_buf_q = NULL; 3895824a1566SKashyap Desai mrioc->sense_buf_q_pool = NULL; 3896824a1566SKashyap Desai } 3897824a1566SKashyap Desai 3898824a1566SKashyap Desai if (mrioc->reply_buf_pool) { 3899824a1566SKashyap Desai if (mrioc->reply_buf) 3900824a1566SKashyap Desai dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf, 3901824a1566SKashyap Desai mrioc->reply_buf_dma); 3902824a1566SKashyap Desai dma_pool_destroy(mrioc->reply_buf_pool); 3903824a1566SKashyap Desai mrioc->reply_buf = NULL; 3904824a1566SKashyap Desai mrioc->reply_buf_pool = NULL; 3905824a1566SKashyap Desai } 3906824a1566SKashyap Desai if (mrioc->reply_free_q_pool) { 3907824a1566SKashyap Desai if (mrioc->reply_free_q) 3908824a1566SKashyap Desai dma_pool_free(mrioc->reply_free_q_pool, 3909824a1566SKashyap Desai mrioc->reply_free_q, mrioc->reply_free_q_dma); 3910824a1566SKashyap Desai dma_pool_destroy(mrioc->reply_free_q_pool); 3911824a1566SKashyap Desai mrioc->reply_free_q = NULL; 3912824a1566SKashyap Desai mrioc->reply_free_q_pool = NULL; 3913824a1566SKashyap Desai } 3914824a1566SKashyap Desai 3915c9566231SKashyap Desai for (i = 0; i < mrioc->num_op_req_q; i++) 3916c9566231SKashyap Desai mpi3mr_free_op_req_q_segments(mrioc, i); 3917c9566231SKashyap Desai 3918c9566231SKashyap Desai for (i = 0; i < mrioc->num_op_reply_q; i++) 3919c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, i); 3920c9566231SKashyap Desai 3921824a1566SKashyap Desai for (i = 0; i < mrioc->intr_info_count; i++) { 3922824a1566SKashyap Desai intr_info = mrioc->intr_info + i; 3923824a1566SKashyap Desai intr_info->op_reply_q = NULL; 3924824a1566SKashyap Desai } 3925824a1566SKashyap Desai 3926824a1566SKashyap Desai kfree(mrioc->req_qinfo); 3927824a1566SKashyap Desai mrioc->req_qinfo = NULL; 3928824a1566SKashyap Desai mrioc->num_op_req_q = 0; 3929824a1566SKashyap Desai 3930824a1566SKashyap Desai kfree(mrioc->op_reply_qinfo); 3931824a1566SKashyap Desai mrioc->op_reply_qinfo = NULL; 3932824a1566SKashyap Desai mrioc->num_op_reply_q = 0; 3933824a1566SKashyap Desai 3934824a1566SKashyap Desai kfree(mrioc->init_cmds.reply); 3935824a1566SKashyap Desai mrioc->init_cmds.reply = NULL; 3936824a1566SKashyap Desai 3937e844adb1SKashyap Desai kfree(mrioc->host_tm_cmds.reply); 3938e844adb1SKashyap Desai mrioc->host_tm_cmds.reply = NULL; 3939e844adb1SKashyap Desai 3940c1af985dSSreekanth Reddy for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { 3941c1af985dSSreekanth Reddy kfree(mrioc->evtack_cmds[i].reply); 3942c1af985dSSreekanth Reddy mrioc->evtack_cmds[i].reply = NULL; 3943c1af985dSSreekanth Reddy } 3944c1af985dSSreekanth Reddy 3945e844adb1SKashyap Desai kfree(mrioc->removepend_bitmap); 3946e844adb1SKashyap Desai mrioc->removepend_bitmap = NULL; 3947e844adb1SKashyap Desai 3948e844adb1SKashyap Desai kfree(mrioc->devrem_bitmap); 3949e844adb1SKashyap Desai mrioc->devrem_bitmap = NULL; 3950e844adb1SKashyap Desai 3951c1af985dSSreekanth Reddy kfree(mrioc->evtack_cmds_bitmap); 3952c1af985dSSreekanth Reddy mrioc->evtack_cmds_bitmap = NULL; 3953c1af985dSSreekanth Reddy 3954824a1566SKashyap Desai kfree(mrioc->chain_bitmap); 3955824a1566SKashyap Desai mrioc->chain_bitmap = NULL; 3956824a1566SKashyap Desai 395713ef29eaSKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 395813ef29eaSKashyap Desai kfree(mrioc->dev_rmhs_cmds[i].reply); 395913ef29eaSKashyap Desai mrioc->dev_rmhs_cmds[i].reply = NULL; 396013ef29eaSKashyap Desai } 396113ef29eaSKashyap Desai 3962824a1566SKashyap Desai if (mrioc->chain_buf_pool) { 3963824a1566SKashyap Desai for (i = 0; i < mrioc->chain_buf_count; i++) { 3964824a1566SKashyap Desai if (mrioc->chain_sgl_list[i].addr) { 3965824a1566SKashyap Desai dma_pool_free(mrioc->chain_buf_pool, 3966824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr, 3967824a1566SKashyap Desai mrioc->chain_sgl_list[i].dma_addr); 3968824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr = NULL; 3969824a1566SKashyap Desai } 3970824a1566SKashyap Desai } 3971824a1566SKashyap Desai dma_pool_destroy(mrioc->chain_buf_pool); 3972824a1566SKashyap Desai mrioc->chain_buf_pool = NULL; 3973824a1566SKashyap Desai } 3974824a1566SKashyap Desai 3975824a1566SKashyap Desai kfree(mrioc->chain_sgl_list); 3976824a1566SKashyap Desai mrioc->chain_sgl_list = NULL; 3977824a1566SKashyap Desai 3978824a1566SKashyap Desai if (mrioc->admin_reply_base) { 3979824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz, 3980824a1566SKashyap Desai mrioc->admin_reply_base, mrioc->admin_reply_dma); 3981824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 3982824a1566SKashyap Desai } 3983824a1566SKashyap Desai if (mrioc->admin_req_base) { 3984824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz, 3985824a1566SKashyap Desai mrioc->admin_req_base, mrioc->admin_req_dma); 3986824a1566SKashyap Desai mrioc->admin_req_base = NULL; 3987824a1566SKashyap Desai } 3988824a1566SKashyap Desai } 3989824a1566SKashyap Desai 3990824a1566SKashyap Desai /** 3991824a1566SKashyap Desai * mpi3mr_issue_ioc_shutdown - shutdown controller 3992824a1566SKashyap Desai * @mrioc: Adapter instance reference 3993824a1566SKashyap Desai * 3994824a1566SKashyap Desai * Send shutodwn notification to the controller and wait for the 3995824a1566SKashyap Desai * shutdown_timeout for it to be completed. 3996824a1566SKashyap Desai * 3997824a1566SKashyap Desai * Return: Nothing. 3998824a1566SKashyap Desai */ 3999824a1566SKashyap Desai static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc) 4000824a1566SKashyap Desai { 4001824a1566SKashyap Desai u32 ioc_config, ioc_status; 4002824a1566SKashyap Desai u8 retval = 1; 4003824a1566SKashyap Desai u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10; 4004824a1566SKashyap Desai 4005824a1566SKashyap Desai ioc_info(mrioc, "Issuing shutdown Notification\n"); 4006824a1566SKashyap Desai if (mrioc->unrecoverable) { 4007824a1566SKashyap Desai ioc_warn(mrioc, 4008824a1566SKashyap Desai "IOC is unrecoverable shutdown is not issued\n"); 4009824a1566SKashyap Desai return; 4010824a1566SKashyap Desai } 4011824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 4012824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 4013824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) { 4014824a1566SKashyap Desai ioc_info(mrioc, "shutdown already in progress\n"); 4015824a1566SKashyap Desai return; 4016824a1566SKashyap Desai } 4017824a1566SKashyap Desai 4018824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 4019824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL; 4020ec5ebd2cSSreekanth Reddy ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ; 4021824a1566SKashyap Desai 4022824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 4023824a1566SKashyap Desai 4024824a1566SKashyap Desai if (mrioc->facts.shutdown_timeout) 4025824a1566SKashyap Desai timeout = mrioc->facts.shutdown_timeout * 10; 4026824a1566SKashyap Desai 4027824a1566SKashyap Desai do { 4028824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 4029824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 4030824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) { 4031824a1566SKashyap Desai retval = 0; 4032824a1566SKashyap Desai break; 4033824a1566SKashyap Desai } 4034824a1566SKashyap Desai msleep(100); 4035824a1566SKashyap Desai } while (--timeout); 4036824a1566SKashyap Desai 4037824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 4038824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 4039824a1566SKashyap Desai 4040824a1566SKashyap Desai if (retval) { 4041824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 4042824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) 4043824a1566SKashyap Desai ioc_warn(mrioc, 4044824a1566SKashyap Desai "shutdown still in progress after timeout\n"); 4045824a1566SKashyap Desai } 4046824a1566SKashyap Desai 4047824a1566SKashyap Desai ioc_info(mrioc, 4048824a1566SKashyap Desai "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n", 4049824a1566SKashyap Desai (!retval) ? "successful" : "failed", ioc_status, 4050824a1566SKashyap Desai ioc_config); 4051824a1566SKashyap Desai } 4052824a1566SKashyap Desai 4053824a1566SKashyap Desai /** 4054824a1566SKashyap Desai * mpi3mr_cleanup_ioc - Cleanup controller 4055824a1566SKashyap Desai * @mrioc: Adapter instance reference 4056fe6db615SSreekanth Reddy 4057824a1566SKashyap Desai * controller cleanup handler, Message unit reset or soft reset 4058fe6db615SSreekanth Reddy * and shutdown notification is issued to the controller. 4059824a1566SKashyap Desai * 4060824a1566SKashyap Desai * Return: Nothing. 4061824a1566SKashyap Desai */ 4062fe6db615SSreekanth Reddy void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc) 4063824a1566SKashyap Desai { 4064824a1566SKashyap Desai enum mpi3mr_iocstate ioc_state; 4065824a1566SKashyap Desai 4066fe6db615SSreekanth Reddy dprint_exit(mrioc, "cleaning up the controller\n"); 4067824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 4068824a1566SKashyap Desai 4069824a1566SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 4070824a1566SKashyap Desai 4071824a1566SKashyap Desai if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) && 4072824a1566SKashyap Desai (ioc_state == MRIOC_STATE_READY)) { 4073824a1566SKashyap Desai if (mpi3mr_issue_and_process_mur(mrioc, 4074824a1566SKashyap Desai MPI3MR_RESET_FROM_CTLR_CLEANUP)) 4075824a1566SKashyap Desai mpi3mr_issue_reset(mrioc, 4076824a1566SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, 4077824a1566SKashyap Desai MPI3MR_RESET_FROM_MUR_FAILURE); 4078824a1566SKashyap Desai mpi3mr_issue_ioc_shutdown(mrioc); 4079824a1566SKashyap Desai } 4080fe6db615SSreekanth Reddy dprint_exit(mrioc, "controller cleanup completed\n"); 4081fb9b0457SKashyap Desai } 4082fb9b0457SKashyap Desai 4083fb9b0457SKashyap Desai /** 4084fb9b0457SKashyap Desai * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command 4085fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 4086fb9b0457SKashyap Desai * @cmdptr: Internal command tracker 4087fb9b0457SKashyap Desai * 4088fb9b0457SKashyap Desai * Complete an internal driver commands with state indicating it 4089fb9b0457SKashyap Desai * is completed due to reset. 4090fb9b0457SKashyap Desai * 4091fb9b0457SKashyap Desai * Return: Nothing. 4092fb9b0457SKashyap Desai */ 4093fb9b0457SKashyap Desai static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc *mrioc, 4094fb9b0457SKashyap Desai struct mpi3mr_drv_cmd *cmdptr) 4095fb9b0457SKashyap Desai { 4096fb9b0457SKashyap Desai if (cmdptr->state & MPI3MR_CMD_PENDING) { 4097fb9b0457SKashyap Desai cmdptr->state |= MPI3MR_CMD_RESET; 4098fb9b0457SKashyap Desai cmdptr->state &= ~MPI3MR_CMD_PENDING; 4099fb9b0457SKashyap Desai if (cmdptr->is_waiting) { 4100fb9b0457SKashyap Desai complete(&cmdptr->done); 4101fb9b0457SKashyap Desai cmdptr->is_waiting = 0; 4102fb9b0457SKashyap Desai } else if (cmdptr->callback) 4103fb9b0457SKashyap Desai cmdptr->callback(mrioc, cmdptr); 4104fb9b0457SKashyap Desai } 4105fb9b0457SKashyap Desai } 4106fb9b0457SKashyap Desai 4107fb9b0457SKashyap Desai /** 4108fb9b0457SKashyap Desai * mpi3mr_flush_drv_cmds - Flush internaldriver commands 4109fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 4110fb9b0457SKashyap Desai * 4111fb9b0457SKashyap Desai * Flush all internal driver commands post reset 4112fb9b0457SKashyap Desai * 4113fb9b0457SKashyap Desai * Return: Nothing. 4114fb9b0457SKashyap Desai */ 4115fb9b0457SKashyap Desai static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc) 4116fb9b0457SKashyap Desai { 4117fb9b0457SKashyap Desai struct mpi3mr_drv_cmd *cmdptr; 4118fb9b0457SKashyap Desai u8 i; 4119fb9b0457SKashyap Desai 4120fb9b0457SKashyap Desai cmdptr = &mrioc->init_cmds; 4121fb9b0457SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 4122e844adb1SKashyap Desai cmdptr = &mrioc->host_tm_cmds; 4123e844adb1SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 4124fb9b0457SKashyap Desai 4125fb9b0457SKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 4126fb9b0457SKashyap Desai cmdptr = &mrioc->dev_rmhs_cmds[i]; 4127fb9b0457SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 4128fb9b0457SKashyap Desai } 4129c1af985dSSreekanth Reddy 4130c1af985dSSreekanth Reddy for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { 4131c1af985dSSreekanth Reddy cmdptr = &mrioc->evtack_cmds[i]; 4132c1af985dSSreekanth Reddy mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 4133c1af985dSSreekanth Reddy } 4134fb9b0457SKashyap Desai } 4135fb9b0457SKashyap Desai 4136fb9b0457SKashyap Desai /** 4137824a1566SKashyap Desai * mpi3mr_soft_reset_handler - Reset the controller 4138824a1566SKashyap Desai * @mrioc: Adapter instance reference 4139824a1566SKashyap Desai * @reset_reason: Reset reason code 4140824a1566SKashyap Desai * @snapdump: Flag to generate snapdump in firmware or not 4141824a1566SKashyap Desai * 4142fb9b0457SKashyap Desai * This is an handler for recovering controller by issuing soft 4143fb9b0457SKashyap Desai * reset are diag fault reset. This is a blocking function and 4144fb9b0457SKashyap Desai * when one reset is executed if any other resets they will be 4145fb9b0457SKashyap Desai * blocked. All IOCTLs/IO will be blocked during the reset. If 4146fb9b0457SKashyap Desai * controller reset is successful then the controller will be 4147fb9b0457SKashyap Desai * reinitalized, otherwise the controller will be marked as not 4148fb9b0457SKashyap Desai * recoverable 4149fb9b0457SKashyap Desai * 4150fb9b0457SKashyap Desai * In snapdump bit is set, the controller is issued with diag 4151fb9b0457SKashyap Desai * fault reset so that the firmware can create a snap dump and 4152fb9b0457SKashyap Desai * post that the firmware will result in F000 fault and the 4153fb9b0457SKashyap Desai * driver will issue soft reset to recover from that. 4154824a1566SKashyap Desai * 4155824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 4156824a1566SKashyap Desai */ 4157824a1566SKashyap Desai int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, 4158824a1566SKashyap Desai u32 reset_reason, u8 snapdump) 4159824a1566SKashyap Desai { 4160fb9b0457SKashyap Desai int retval = 0, i; 4161fb9b0457SKashyap Desai unsigned long flags; 4162fb9b0457SKashyap Desai u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; 4163fb9b0457SKashyap Desai 4164b64845a7SSreekanth Reddy /* Block the reset handler until diag save in progress*/ 4165b64845a7SSreekanth Reddy dprint_reset(mrioc, 4166b64845a7SSreekanth Reddy "soft_reset_handler: check and block on diagsave_timeout(%d)\n", 4167b64845a7SSreekanth Reddy mrioc->diagsave_timeout); 4168b64845a7SSreekanth Reddy while (mrioc->diagsave_timeout) 4169b64845a7SSreekanth Reddy ssleep(1); 4170fb9b0457SKashyap Desai /* 4171fb9b0457SKashyap Desai * Block new resets until the currently executing one is finished and 4172fb9b0457SKashyap Desai * return the status of the existing reset for all blocked resets 4173fb9b0457SKashyap Desai */ 4174b64845a7SSreekanth Reddy dprint_reset(mrioc, "soft_reset_handler: acquiring reset_mutex\n"); 4175fb9b0457SKashyap Desai if (!mutex_trylock(&mrioc->reset_mutex)) { 4176b64845a7SSreekanth Reddy ioc_info(mrioc, 4177b64845a7SSreekanth Reddy "controller reset triggered by %s is blocked due to another reset in progress\n", 4178b64845a7SSreekanth Reddy mpi3mr_reset_rc_name(reset_reason)); 4179b64845a7SSreekanth Reddy do { 4180b64845a7SSreekanth Reddy ssleep(1); 4181b64845a7SSreekanth Reddy } while (mrioc->reset_in_progress == 1); 4182b64845a7SSreekanth Reddy ioc_info(mrioc, 4183b64845a7SSreekanth Reddy "returning previous reset result(%d) for the reset triggered by %s\n", 4184b64845a7SSreekanth Reddy mrioc->prev_reset_result, 4185b64845a7SSreekanth Reddy mpi3mr_reset_rc_name(reset_reason)); 4186b64845a7SSreekanth Reddy return mrioc->prev_reset_result; 4187fb9b0457SKashyap Desai } 4188b64845a7SSreekanth Reddy ioc_info(mrioc, "controller reset is triggered by %s\n", 4189b64845a7SSreekanth Reddy mpi3mr_reset_rc_name(reset_reason)); 4190b64845a7SSreekanth Reddy 4191fb9b0457SKashyap Desai mrioc->reset_in_progress = 1; 4192b64845a7SSreekanth Reddy mrioc->prev_reset_result = -1; 4193fb9b0457SKashyap Desai 4194fb9b0457SKashyap Desai if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) && 4195b64845a7SSreekanth Reddy (reset_reason != MPI3MR_RESET_FROM_FIRMWARE) && 4196fb9b0457SKashyap Desai (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) { 4197fb9b0457SKashyap Desai for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 4198fb9b0457SKashyap Desai mrioc->event_masks[i] = -1; 4199fb9b0457SKashyap Desai 4200b64845a7SSreekanth Reddy dprint_reset(mrioc, "soft_reset_handler: masking events\n"); 4201b64845a7SSreekanth Reddy mpi3mr_issue_event_notification(mrioc); 4202fb9b0457SKashyap Desai } 4203fb9b0457SKashyap Desai 420444dc724fSKashyap Desai mpi3mr_wait_for_host_io(mrioc, MPI3MR_RESET_HOST_IOWAIT_TIMEOUT); 420544dc724fSKashyap Desai 4206fb9b0457SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 4207fb9b0457SKashyap Desai 4208fb9b0457SKashyap Desai if (snapdump) { 4209fb9b0457SKashyap Desai mpi3mr_set_diagsave(mrioc); 4210fb9b0457SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 4211fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); 4212fb9b0457SKashyap Desai if (!retval) { 4213fb9b0457SKashyap Desai do { 4214fb9b0457SKashyap Desai host_diagnostic = 4215fb9b0457SKashyap Desai readl(&mrioc->sysif_regs->host_diagnostic); 4216fb9b0457SKashyap Desai if (!(host_diagnostic & 4217fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS)) 4218fb9b0457SKashyap Desai break; 4219fb9b0457SKashyap Desai msleep(100); 4220fb9b0457SKashyap Desai } while (--timeout); 4221fb9b0457SKashyap Desai } 4222fb9b0457SKashyap Desai } 4223fb9b0457SKashyap Desai 4224fb9b0457SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 4225fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason); 4226fb9b0457SKashyap Desai if (retval) { 4227fb9b0457SKashyap Desai ioc_err(mrioc, "Failed to issue soft reset to the ioc\n"); 4228fb9b0457SKashyap Desai goto out; 4229fb9b0457SKashyap Desai } 4230fb9b0457SKashyap Desai 4231c1af985dSSreekanth Reddy mpi3mr_flush_delayed_cmd_lists(mrioc); 4232fb9b0457SKashyap Desai mpi3mr_flush_drv_cmds(mrioc); 4233fb9b0457SKashyap Desai memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); 4234fb9b0457SKashyap Desai memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); 4235c1af985dSSreekanth Reddy memset(mrioc->evtack_cmds_bitmap, 0, mrioc->evtack_cmds_bitmap_sz); 4236fb9b0457SKashyap Desai mpi3mr_cleanup_fwevt_list(mrioc); 4237fb9b0457SKashyap Desai mpi3mr_flush_host_io(mrioc); 4238fb9b0457SKashyap Desai mpi3mr_invalidate_devhandles(mrioc); 4239*78b76a07SSreekanth Reddy if (mrioc->prepare_for_reset) { 4240*78b76a07SSreekanth Reddy mrioc->prepare_for_reset = 0; 4241*78b76a07SSreekanth Reddy mrioc->prepare_for_reset_timeout_counter = 0; 4242*78b76a07SSreekanth Reddy } 4243fb9b0457SKashyap Desai mpi3mr_memset_buffers(mrioc); 4244fe6db615SSreekanth Reddy retval = mpi3mr_reinit_ioc(mrioc, 0); 4245fb9b0457SKashyap Desai if (retval) { 4246fb9b0457SKashyap Desai pr_err(IOCNAME "reinit after soft reset failed: reason %d\n", 4247fb9b0457SKashyap Desai mrioc->name, reset_reason); 4248fb9b0457SKashyap Desai goto out; 4249fb9b0457SKashyap Desai } 4250fb9b0457SKashyap Desai ssleep(10); 4251fb9b0457SKashyap Desai 4252fb9b0457SKashyap Desai out: 4253fb9b0457SKashyap Desai if (!retval) { 4254b64845a7SSreekanth Reddy mrioc->diagsave_timeout = 0; 4255fb9b0457SKashyap Desai mrioc->reset_in_progress = 0; 4256fb9b0457SKashyap Desai mpi3mr_rfresh_tgtdevs(mrioc); 425754dfcffbSKashyap Desai mrioc->ts_update_counter = 0; 4258fb9b0457SKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 4259fb9b0457SKashyap Desai if (mrioc->watchdog_work_q) 4260fb9b0457SKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 4261fb9b0457SKashyap Desai &mrioc->watchdog_work, 4262fb9b0457SKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 4263fb9b0457SKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 4264fb9b0457SKashyap Desai } else { 4265fb9b0457SKashyap Desai mpi3mr_issue_reset(mrioc, 4266fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); 4267fb9b0457SKashyap Desai mrioc->unrecoverable = 1; 4268fb9b0457SKashyap Desai mrioc->reset_in_progress = 0; 4269fb9b0457SKashyap Desai retval = -1; 4270fb9b0457SKashyap Desai } 4271b64845a7SSreekanth Reddy mrioc->prev_reset_result = retval; 4272fb9b0457SKashyap Desai mutex_unlock(&mrioc->reset_mutex); 4273b64845a7SSreekanth Reddy ioc_info(mrioc, "controller reset is %s\n", 4274b64845a7SSreekanth Reddy ((retval == 0) ? "successful" : "failed")); 4275fb9b0457SKashyap Desai return retval; 4276824a1566SKashyap Desai } 4277