1824a1566SKashyap Desai // SPDX-License-Identifier: GPL-2.0-or-later 2824a1566SKashyap Desai /* 3824a1566SKashyap Desai * Driver for Broadcom MPI3 Storage Controllers 4824a1566SKashyap Desai * 5e74f2fbdSRanjan Kumar * Copyright (C) 2017-2023 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); 1843ca1100SSumit Saxena static void mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc, 1943ca1100SSumit Saxena struct mpi3mr_drv_cmd *drv_cmd); 2059bd9cfeSSreekanth Reddy 21afd3a579SSreekanth Reddy static int poll_queues; 22afd3a579SSreekanth Reddy module_param(poll_queues, int, 0444); 23afd3a579SSreekanth Reddy MODULE_PARM_DESC(poll_queues, "Number of queues for io_uring poll mode. (Range 1 - 126)"); 24afd3a579SSreekanth Reddy 25824a1566SKashyap Desai #if defined(writeq) && defined(CONFIG_64BIT) 26824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) 27824a1566SKashyap Desai { 28824a1566SKashyap Desai writeq(b, addr); 29824a1566SKashyap Desai } 30824a1566SKashyap Desai #else 31824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) 32824a1566SKashyap Desai { 33824a1566SKashyap Desai __u64 data_out = b; 34824a1566SKashyap Desai 35824a1566SKashyap Desai writel((u32)(data_out), addr); 36824a1566SKashyap Desai writel((u32)(data_out >> 32), (addr + 4)); 37824a1566SKashyap Desai } 38824a1566SKashyap Desai #endif 39824a1566SKashyap Desai 40023ab2a9SKashyap Desai static inline bool 41023ab2a9SKashyap Desai mpi3mr_check_req_qfull(struct op_req_qinfo *op_req_q) 42023ab2a9SKashyap Desai { 43023ab2a9SKashyap Desai u16 pi, ci, max_entries; 44023ab2a9SKashyap Desai bool is_qfull = false; 45023ab2a9SKashyap Desai 46023ab2a9SKashyap Desai pi = op_req_q->pi; 47023ab2a9SKashyap Desai ci = READ_ONCE(op_req_q->ci); 48023ab2a9SKashyap Desai max_entries = op_req_q->num_requests; 49023ab2a9SKashyap Desai 50023ab2a9SKashyap Desai if ((ci == (pi + 1)) || ((!ci) && (pi == (max_entries - 1)))) 51023ab2a9SKashyap Desai is_qfull = true; 52023ab2a9SKashyap Desai 53023ab2a9SKashyap Desai return is_qfull; 54023ab2a9SKashyap Desai } 55023ab2a9SKashyap Desai 56824a1566SKashyap Desai static void mpi3mr_sync_irqs(struct mpi3mr_ioc *mrioc) 57824a1566SKashyap Desai { 58824a1566SKashyap Desai u16 i, max_vectors; 59824a1566SKashyap Desai 60824a1566SKashyap Desai max_vectors = mrioc->intr_info_count; 61824a1566SKashyap Desai 62824a1566SKashyap Desai for (i = 0; i < max_vectors; i++) 63824a1566SKashyap Desai synchronize_irq(pci_irq_vector(mrioc->pdev, i)); 64824a1566SKashyap Desai } 65824a1566SKashyap Desai 66824a1566SKashyap Desai void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc) 67824a1566SKashyap Desai { 68824a1566SKashyap Desai mrioc->intr_enabled = 0; 69824a1566SKashyap Desai mpi3mr_sync_irqs(mrioc); 70824a1566SKashyap Desai } 71824a1566SKashyap Desai 72824a1566SKashyap Desai void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc) 73824a1566SKashyap Desai { 74824a1566SKashyap Desai mrioc->intr_enabled = 1; 75824a1566SKashyap Desai } 76824a1566SKashyap Desai 77824a1566SKashyap Desai static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc) 78824a1566SKashyap Desai { 79824a1566SKashyap Desai u16 i; 80824a1566SKashyap Desai 81824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 82824a1566SKashyap Desai 83824a1566SKashyap Desai if (!mrioc->intr_info) 84824a1566SKashyap Desai return; 85824a1566SKashyap Desai 86824a1566SKashyap Desai for (i = 0; i < mrioc->intr_info_count; i++) 87824a1566SKashyap Desai free_irq(pci_irq_vector(mrioc->pdev, i), 88824a1566SKashyap Desai (mrioc->intr_info + i)); 89824a1566SKashyap Desai 90824a1566SKashyap Desai kfree(mrioc->intr_info); 91824a1566SKashyap Desai mrioc->intr_info = NULL; 92824a1566SKashyap Desai mrioc->intr_info_count = 0; 93fe6db615SSreekanth Reddy mrioc->is_intr_info_set = false; 94824a1566SKashyap Desai pci_free_irq_vectors(mrioc->pdev); 95824a1566SKashyap Desai } 96824a1566SKashyap Desai 97824a1566SKashyap Desai void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length, 98824a1566SKashyap Desai dma_addr_t dma_addr) 99824a1566SKashyap Desai { 100824a1566SKashyap Desai struct mpi3_sge_common *sgel = paddr; 101824a1566SKashyap Desai 102824a1566SKashyap Desai sgel->flags = flags; 103824a1566SKashyap Desai sgel->length = cpu_to_le32(length); 104824a1566SKashyap Desai sgel->address = cpu_to_le64(dma_addr); 105824a1566SKashyap Desai } 106824a1566SKashyap Desai 107824a1566SKashyap Desai void mpi3mr_build_zero_len_sge(void *paddr) 108824a1566SKashyap Desai { 109824a1566SKashyap Desai u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 110824a1566SKashyap Desai 111824a1566SKashyap Desai mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1); 112824a1566SKashyap Desai } 113824a1566SKashyap Desai 114824a1566SKashyap Desai void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc, 115824a1566SKashyap Desai dma_addr_t phys_addr) 116824a1566SKashyap Desai { 117824a1566SKashyap Desai if (!phys_addr) 118824a1566SKashyap Desai return NULL; 119824a1566SKashyap Desai 120824a1566SKashyap Desai if ((phys_addr < mrioc->reply_buf_dma) || 121824a1566SKashyap Desai (phys_addr > mrioc->reply_buf_dma_max_address)) 122824a1566SKashyap Desai return NULL; 123824a1566SKashyap Desai 124824a1566SKashyap Desai return mrioc->reply_buf + (phys_addr - mrioc->reply_buf_dma); 125824a1566SKashyap Desai } 126824a1566SKashyap Desai 127824a1566SKashyap Desai void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc, 128824a1566SKashyap Desai dma_addr_t phys_addr) 129824a1566SKashyap Desai { 130824a1566SKashyap Desai if (!phys_addr) 131824a1566SKashyap Desai return NULL; 132824a1566SKashyap Desai 133824a1566SKashyap Desai return mrioc->sense_buf + (phys_addr - mrioc->sense_buf_dma); 134824a1566SKashyap Desai } 135824a1566SKashyap Desai 136824a1566SKashyap Desai static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc, 137824a1566SKashyap Desai u64 reply_dma) 138824a1566SKashyap Desai { 139824a1566SKashyap Desai u32 old_idx = 0; 140a83ec831SSreekanth Reddy unsigned long flags; 141824a1566SKashyap Desai 142a83ec831SSreekanth Reddy spin_lock_irqsave(&mrioc->reply_free_queue_lock, flags); 143824a1566SKashyap Desai old_idx = mrioc->reply_free_queue_host_index; 144824a1566SKashyap Desai mrioc->reply_free_queue_host_index = ( 145824a1566SKashyap Desai (mrioc->reply_free_queue_host_index == 146824a1566SKashyap Desai (mrioc->reply_free_qsz - 1)) ? 0 : 147824a1566SKashyap Desai (mrioc->reply_free_queue_host_index + 1)); 148824a1566SKashyap Desai mrioc->reply_free_q[old_idx] = cpu_to_le64(reply_dma); 149824a1566SKashyap Desai writel(mrioc->reply_free_queue_host_index, 150824a1566SKashyap Desai &mrioc->sysif_regs->reply_free_host_index); 151a83ec831SSreekanth Reddy spin_unlock_irqrestore(&mrioc->reply_free_queue_lock, flags); 152824a1566SKashyap Desai } 153824a1566SKashyap Desai 154824a1566SKashyap Desai void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc, 155824a1566SKashyap Desai u64 sense_buf_dma) 156824a1566SKashyap Desai { 157824a1566SKashyap Desai u32 old_idx = 0; 158a83ec831SSreekanth Reddy unsigned long flags; 159824a1566SKashyap Desai 160a83ec831SSreekanth Reddy spin_lock_irqsave(&mrioc->sbq_lock, flags); 161824a1566SKashyap Desai old_idx = mrioc->sbq_host_index; 162824a1566SKashyap Desai mrioc->sbq_host_index = ((mrioc->sbq_host_index == 163824a1566SKashyap Desai (mrioc->sense_buf_q_sz - 1)) ? 0 : 164824a1566SKashyap Desai (mrioc->sbq_host_index + 1)); 165824a1566SKashyap Desai mrioc->sense_buf_q[old_idx] = cpu_to_le64(sense_buf_dma); 166824a1566SKashyap Desai writel(mrioc->sbq_host_index, 167824a1566SKashyap Desai &mrioc->sysif_regs->sense_buffer_free_host_index); 168a83ec831SSreekanth Reddy spin_unlock_irqrestore(&mrioc->sbq_lock, flags); 169824a1566SKashyap Desai } 170824a1566SKashyap Desai 1719fc4abfeSKashyap Desai static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc, 1729fc4abfeSKashyap Desai struct mpi3_event_notification_reply *event_reply) 1739fc4abfeSKashyap Desai { 1749fc4abfeSKashyap Desai char *desc = NULL; 1759fc4abfeSKashyap Desai u16 event; 1769fc4abfeSKashyap Desai 1779fc4abfeSKashyap Desai event = event_reply->event; 1789fc4abfeSKashyap Desai 1799fc4abfeSKashyap Desai switch (event) { 1809fc4abfeSKashyap Desai case MPI3_EVENT_LOG_DATA: 1819fc4abfeSKashyap Desai desc = "Log Data"; 1829fc4abfeSKashyap Desai break; 1839fc4abfeSKashyap Desai case MPI3_EVENT_CHANGE: 1849fc4abfeSKashyap Desai desc = "Event Change"; 1859fc4abfeSKashyap Desai break; 1869fc4abfeSKashyap Desai case MPI3_EVENT_GPIO_INTERRUPT: 1879fc4abfeSKashyap Desai desc = "GPIO Interrupt"; 1889fc4abfeSKashyap Desai break; 1899fc4abfeSKashyap Desai case MPI3_EVENT_CABLE_MGMT: 1909fc4abfeSKashyap Desai desc = "Cable Management"; 1919fc4abfeSKashyap Desai break; 1929fc4abfeSKashyap Desai case MPI3_EVENT_ENERGY_PACK_CHANGE: 1939fc4abfeSKashyap Desai desc = "Energy Pack Change"; 1949fc4abfeSKashyap Desai break; 1959fc4abfeSKashyap Desai case MPI3_EVENT_DEVICE_ADDED: 1969fc4abfeSKashyap Desai { 1979fc4abfeSKashyap Desai struct mpi3_device_page0 *event_data = 1989fc4abfeSKashyap Desai (struct mpi3_device_page0 *)event_reply->event_data; 1999fc4abfeSKashyap Desai ioc_info(mrioc, "Device Added: dev=0x%04x Form=0x%x\n", 2009fc4abfeSKashyap Desai event_data->dev_handle, event_data->device_form); 2019fc4abfeSKashyap Desai return; 2029fc4abfeSKashyap Desai } 2039fc4abfeSKashyap Desai case MPI3_EVENT_DEVICE_INFO_CHANGED: 2049fc4abfeSKashyap Desai { 2059fc4abfeSKashyap Desai struct mpi3_device_page0 *event_data = 2069fc4abfeSKashyap Desai (struct mpi3_device_page0 *)event_reply->event_data; 2079fc4abfeSKashyap Desai ioc_info(mrioc, "Device Info Changed: dev=0x%04x Form=0x%x\n", 2089fc4abfeSKashyap Desai event_data->dev_handle, event_data->device_form); 2099fc4abfeSKashyap Desai return; 2109fc4abfeSKashyap Desai } 2119fc4abfeSKashyap Desai case MPI3_EVENT_DEVICE_STATUS_CHANGE: 2129fc4abfeSKashyap Desai { 2139fc4abfeSKashyap Desai struct mpi3_event_data_device_status_change *event_data = 2149fc4abfeSKashyap Desai (struct mpi3_event_data_device_status_change *)event_reply->event_data; 2159fc4abfeSKashyap Desai ioc_info(mrioc, "Device status Change: dev=0x%04x RC=0x%x\n", 2169fc4abfeSKashyap Desai event_data->dev_handle, event_data->reason_code); 2179fc4abfeSKashyap Desai return; 2189fc4abfeSKashyap Desai } 2199fc4abfeSKashyap Desai case MPI3_EVENT_SAS_DISCOVERY: 2209fc4abfeSKashyap Desai { 2219fc4abfeSKashyap Desai struct mpi3_event_data_sas_discovery *event_data = 2229fc4abfeSKashyap Desai (struct mpi3_event_data_sas_discovery *)event_reply->event_data; 2239fc4abfeSKashyap Desai ioc_info(mrioc, "SAS Discovery: (%s) status (0x%08x)\n", 2249fc4abfeSKashyap Desai (event_data->reason_code == MPI3_EVENT_SAS_DISC_RC_STARTED) ? 2259fc4abfeSKashyap Desai "start" : "stop", 2269fc4abfeSKashyap Desai le32_to_cpu(event_data->discovery_status)); 2279fc4abfeSKashyap Desai return; 2289fc4abfeSKashyap Desai } 2299fc4abfeSKashyap Desai case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE: 2309fc4abfeSKashyap Desai desc = "SAS Broadcast Primitive"; 2319fc4abfeSKashyap Desai break; 2329fc4abfeSKashyap Desai case MPI3_EVENT_SAS_NOTIFY_PRIMITIVE: 2339fc4abfeSKashyap Desai desc = "SAS Notify Primitive"; 2349fc4abfeSKashyap Desai break; 2359fc4abfeSKashyap Desai case MPI3_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: 2369fc4abfeSKashyap Desai desc = "SAS Init Device Status Change"; 2379fc4abfeSKashyap Desai break; 2389fc4abfeSKashyap Desai case MPI3_EVENT_SAS_INIT_TABLE_OVERFLOW: 2399fc4abfeSKashyap Desai desc = "SAS Init Table Overflow"; 2409fc4abfeSKashyap Desai break; 2419fc4abfeSKashyap Desai case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST: 2429fc4abfeSKashyap Desai desc = "SAS Topology Change List"; 2439fc4abfeSKashyap Desai break; 2449fc4abfeSKashyap Desai case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE: 2459fc4abfeSKashyap Desai desc = "Enclosure Device Status Change"; 2469fc4abfeSKashyap Desai break; 2477188c03fSSreekanth Reddy case MPI3_EVENT_ENCL_DEVICE_ADDED: 2487188c03fSSreekanth Reddy desc = "Enclosure Added"; 2497188c03fSSreekanth Reddy break; 2509fc4abfeSKashyap Desai case MPI3_EVENT_HARD_RESET_RECEIVED: 2519fc4abfeSKashyap Desai desc = "Hard Reset Received"; 2529fc4abfeSKashyap Desai break; 2539fc4abfeSKashyap Desai case MPI3_EVENT_SAS_PHY_COUNTER: 2549fc4abfeSKashyap Desai desc = "SAS PHY Counter"; 2559fc4abfeSKashyap Desai break; 2569fc4abfeSKashyap Desai case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR: 2579fc4abfeSKashyap Desai desc = "SAS Device Discovery Error"; 2589fc4abfeSKashyap Desai break; 2599fc4abfeSKashyap Desai case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: 2609fc4abfeSKashyap Desai desc = "PCIE Topology Change List"; 2619fc4abfeSKashyap Desai break; 2629fc4abfeSKashyap Desai case MPI3_EVENT_PCIE_ENUMERATION: 2639fc4abfeSKashyap Desai { 2649fc4abfeSKashyap Desai struct mpi3_event_data_pcie_enumeration *event_data = 2659fc4abfeSKashyap Desai (struct mpi3_event_data_pcie_enumeration *)event_reply->event_data; 2669fc4abfeSKashyap Desai ioc_info(mrioc, "PCIE Enumeration: (%s)", 2679fc4abfeSKashyap Desai (event_data->reason_code == 2689fc4abfeSKashyap Desai MPI3_EVENT_PCIE_ENUM_RC_STARTED) ? "start" : "stop"); 2699fc4abfeSKashyap Desai if (event_data->enumeration_status) 2709fc4abfeSKashyap Desai ioc_info(mrioc, "enumeration_status(0x%08x)\n", 2719fc4abfeSKashyap Desai le32_to_cpu(event_data->enumeration_status)); 2729fc4abfeSKashyap Desai return; 2739fc4abfeSKashyap Desai } 2749fc4abfeSKashyap Desai case MPI3_EVENT_PREPARE_FOR_RESET: 2759fc4abfeSKashyap Desai desc = "Prepare For Reset"; 2769fc4abfeSKashyap Desai break; 2779fc4abfeSKashyap Desai } 2789fc4abfeSKashyap Desai 2799fc4abfeSKashyap Desai if (!desc) 2809fc4abfeSKashyap Desai return; 2819fc4abfeSKashyap Desai 2829fc4abfeSKashyap Desai ioc_info(mrioc, "%s\n", desc); 2839fc4abfeSKashyap Desai } 2849fc4abfeSKashyap Desai 285824a1566SKashyap Desai static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc, 286824a1566SKashyap Desai struct mpi3_default_reply *def_reply) 287824a1566SKashyap Desai { 288824a1566SKashyap Desai struct mpi3_event_notification_reply *event_reply = 289824a1566SKashyap Desai (struct mpi3_event_notification_reply *)def_reply; 290824a1566SKashyap Desai 291824a1566SKashyap Desai mrioc->change_count = le16_to_cpu(event_reply->ioc_change_count); 2929fc4abfeSKashyap Desai mpi3mr_print_event_data(mrioc, event_reply); 29313ef29eaSKashyap Desai mpi3mr_os_handle_events(mrioc, event_reply); 294824a1566SKashyap Desai } 295824a1566SKashyap Desai 296824a1566SKashyap Desai static struct mpi3mr_drv_cmd * 297824a1566SKashyap Desai mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag, 298824a1566SKashyap Desai struct mpi3_default_reply *def_reply) 299824a1566SKashyap Desai { 30013ef29eaSKashyap Desai u16 idx; 30113ef29eaSKashyap Desai 302824a1566SKashyap Desai switch (host_tag) { 303824a1566SKashyap Desai case MPI3MR_HOSTTAG_INITCMDS: 304824a1566SKashyap Desai return &mrioc->init_cmds; 30532d457d5SSreekanth Reddy case MPI3MR_HOSTTAG_CFG_CMDS: 30632d457d5SSreekanth Reddy return &mrioc->cfg_cmds; 307f5e6d5a3SSumit Saxena case MPI3MR_HOSTTAG_BSG_CMDS: 308f5e6d5a3SSumit Saxena return &mrioc->bsg_cmds; 309e844adb1SKashyap Desai case MPI3MR_HOSTTAG_BLK_TMS: 310e844adb1SKashyap Desai return &mrioc->host_tm_cmds; 31143ca1100SSumit Saxena case MPI3MR_HOSTTAG_PEL_ABORT: 31243ca1100SSumit Saxena return &mrioc->pel_abort_cmd; 31343ca1100SSumit Saxena case MPI3MR_HOSTTAG_PEL_WAIT: 31443ca1100SSumit Saxena return &mrioc->pel_cmds; 3152bd37e28SSreekanth Reddy case MPI3MR_HOSTTAG_TRANSPORT_CMDS: 3162bd37e28SSreekanth Reddy return &mrioc->transport_cmds; 317824a1566SKashyap Desai case MPI3MR_HOSTTAG_INVALID: 318824a1566SKashyap Desai if (def_reply && def_reply->function == 319824a1566SKashyap Desai MPI3_FUNCTION_EVENT_NOTIFICATION) 320824a1566SKashyap Desai mpi3mr_handle_events(mrioc, def_reply); 321824a1566SKashyap Desai return NULL; 322824a1566SKashyap Desai default: 323824a1566SKashyap Desai break; 324824a1566SKashyap Desai } 32513ef29eaSKashyap Desai if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN && 32613ef29eaSKashyap Desai host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX) { 32713ef29eaSKashyap Desai idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN; 32813ef29eaSKashyap Desai return &mrioc->dev_rmhs_cmds[idx]; 32913ef29eaSKashyap Desai } 330824a1566SKashyap Desai 331c1af985dSSreekanth Reddy if (host_tag >= MPI3MR_HOSTTAG_EVTACKCMD_MIN && 332c1af985dSSreekanth Reddy host_tag <= MPI3MR_HOSTTAG_EVTACKCMD_MAX) { 333c1af985dSSreekanth Reddy idx = host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN; 334c1af985dSSreekanth Reddy return &mrioc->evtack_cmds[idx]; 335c1af985dSSreekanth Reddy } 336c1af985dSSreekanth Reddy 337824a1566SKashyap Desai return NULL; 338824a1566SKashyap Desai } 339824a1566SKashyap Desai 340824a1566SKashyap Desai static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, 341824a1566SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma) 342824a1566SKashyap Desai { 343824a1566SKashyap Desai u16 reply_desc_type, host_tag = 0; 344824a1566SKashyap Desai u16 ioc_status = MPI3_IOCSTATUS_SUCCESS; 345824a1566SKashyap Desai u32 ioc_loginfo = 0; 346824a1566SKashyap Desai struct mpi3_status_reply_descriptor *status_desc; 347824a1566SKashyap Desai struct mpi3_address_reply_descriptor *addr_desc; 348824a1566SKashyap Desai struct mpi3_success_reply_descriptor *success_desc; 349824a1566SKashyap Desai struct mpi3_default_reply *def_reply = NULL; 350824a1566SKashyap Desai struct mpi3mr_drv_cmd *cmdptr = NULL; 351824a1566SKashyap Desai struct mpi3_scsi_io_reply *scsi_reply; 352824a1566SKashyap Desai u8 *sense_buf = NULL; 353824a1566SKashyap Desai 354824a1566SKashyap Desai *reply_dma = 0; 355824a1566SKashyap Desai reply_desc_type = le16_to_cpu(reply_desc->reply_flags) & 356824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK; 357824a1566SKashyap Desai switch (reply_desc_type) { 358824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS: 359824a1566SKashyap Desai status_desc = (struct mpi3_status_reply_descriptor *)reply_desc; 360824a1566SKashyap Desai host_tag = le16_to_cpu(status_desc->host_tag); 361824a1566SKashyap Desai ioc_status = le16_to_cpu(status_desc->ioc_status); 362824a1566SKashyap Desai if (ioc_status & 363824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) 364824a1566SKashyap Desai ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info); 365824a1566SKashyap Desai ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; 366824a1566SKashyap Desai break; 367824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY: 368824a1566SKashyap Desai addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc; 369824a1566SKashyap Desai *reply_dma = le64_to_cpu(addr_desc->reply_frame_address); 370824a1566SKashyap Desai def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma); 371824a1566SKashyap Desai if (!def_reply) 372824a1566SKashyap Desai goto out; 373824a1566SKashyap Desai host_tag = le16_to_cpu(def_reply->host_tag); 374824a1566SKashyap Desai ioc_status = le16_to_cpu(def_reply->ioc_status); 375824a1566SKashyap Desai if (ioc_status & 376824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) 377824a1566SKashyap Desai ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info); 378824a1566SKashyap Desai ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; 379824a1566SKashyap Desai if (def_reply->function == MPI3_FUNCTION_SCSI_IO) { 380824a1566SKashyap Desai scsi_reply = (struct mpi3_scsi_io_reply *)def_reply; 381824a1566SKashyap Desai sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc, 382824a1566SKashyap Desai le64_to_cpu(scsi_reply->sense_data_buffer_address)); 383824a1566SKashyap Desai } 384824a1566SKashyap Desai break; 385824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS: 386824a1566SKashyap Desai success_desc = (struct mpi3_success_reply_descriptor *)reply_desc; 387824a1566SKashyap Desai host_tag = le16_to_cpu(success_desc->host_tag); 388824a1566SKashyap Desai break; 389824a1566SKashyap Desai default: 390824a1566SKashyap Desai break; 391824a1566SKashyap Desai } 392824a1566SKashyap Desai 393824a1566SKashyap Desai cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply); 394824a1566SKashyap Desai if (cmdptr) { 395824a1566SKashyap Desai if (cmdptr->state & MPI3MR_CMD_PENDING) { 396824a1566SKashyap Desai cmdptr->state |= MPI3MR_CMD_COMPLETE; 397824a1566SKashyap Desai cmdptr->ioc_loginfo = ioc_loginfo; 398824a1566SKashyap Desai cmdptr->ioc_status = ioc_status; 399824a1566SKashyap Desai cmdptr->state &= ~MPI3MR_CMD_PENDING; 400824a1566SKashyap Desai if (def_reply) { 401824a1566SKashyap Desai cmdptr->state |= MPI3MR_CMD_REPLY_VALID; 402824a1566SKashyap Desai memcpy((u8 *)cmdptr->reply, (u8 *)def_reply, 403c5758fc7SSreekanth Reddy mrioc->reply_sz); 404824a1566SKashyap Desai } 405f762326bSSathya Prakash if (sense_buf && cmdptr->sensebuf) { 406f762326bSSathya Prakash cmdptr->is_sense = 1; 407f762326bSSathya Prakash memcpy(cmdptr->sensebuf, sense_buf, 408f762326bSSathya Prakash MPI3MR_SENSE_BUF_SZ); 409f762326bSSathya Prakash } 410824a1566SKashyap Desai if (cmdptr->is_waiting) { 411824a1566SKashyap Desai complete(&cmdptr->done); 412824a1566SKashyap Desai cmdptr->is_waiting = 0; 413824a1566SKashyap Desai } else if (cmdptr->callback) 414824a1566SKashyap Desai cmdptr->callback(mrioc, cmdptr); 415824a1566SKashyap Desai } 416824a1566SKashyap Desai } 417824a1566SKashyap Desai out: 418824a1566SKashyap Desai if (sense_buf) 419824a1566SKashyap Desai mpi3mr_repost_sense_buf(mrioc, 420824a1566SKashyap Desai le64_to_cpu(scsi_reply->sense_data_buffer_address)); 421824a1566SKashyap Desai } 422824a1566SKashyap Desai 42302ca7da2SRanjan Kumar int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) 424824a1566SKashyap Desai { 425824a1566SKashyap Desai u32 exp_phase = mrioc->admin_reply_ephase; 426824a1566SKashyap Desai u32 admin_reply_ci = mrioc->admin_reply_ci; 427824a1566SKashyap Desai u32 num_admin_replies = 0; 428824a1566SKashyap Desai u64 reply_dma = 0; 429824a1566SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc; 430824a1566SKashyap Desai 43102ca7da2SRanjan Kumar if (!atomic_add_unless(&mrioc->admin_reply_q_in_use, 1, 1)) 43202ca7da2SRanjan Kumar return 0; 43302ca7da2SRanjan Kumar 434824a1566SKashyap Desai reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base + 435824a1566SKashyap Desai admin_reply_ci; 436824a1566SKashyap Desai 437824a1566SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 43802ca7da2SRanjan Kumar MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) { 43902ca7da2SRanjan Kumar atomic_dec(&mrioc->admin_reply_q_in_use); 440824a1566SKashyap Desai return 0; 44102ca7da2SRanjan Kumar } 442824a1566SKashyap Desai 443824a1566SKashyap Desai do { 444f2a79d20SSreekanth Reddy if (mrioc->unrecoverable) 445f2a79d20SSreekanth Reddy break; 446f2a79d20SSreekanth Reddy 447824a1566SKashyap Desai mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci); 448824a1566SKashyap Desai mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma); 449824a1566SKashyap Desai if (reply_dma) 450824a1566SKashyap Desai mpi3mr_repost_reply_buf(mrioc, reply_dma); 451824a1566SKashyap Desai num_admin_replies++; 452824a1566SKashyap Desai if (++admin_reply_ci == mrioc->num_admin_replies) { 453824a1566SKashyap Desai admin_reply_ci = 0; 454824a1566SKashyap Desai exp_phase ^= 1; 455824a1566SKashyap Desai } 456824a1566SKashyap Desai reply_desc = 457824a1566SKashyap Desai (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base + 458824a1566SKashyap Desai admin_reply_ci; 459824a1566SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 460824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 461824a1566SKashyap Desai break; 462824a1566SKashyap Desai } while (1); 463824a1566SKashyap Desai 464824a1566SKashyap Desai writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); 465824a1566SKashyap Desai mrioc->admin_reply_ci = admin_reply_ci; 466824a1566SKashyap Desai mrioc->admin_reply_ephase = exp_phase; 46702ca7da2SRanjan Kumar atomic_dec(&mrioc->admin_reply_q_in_use); 468824a1566SKashyap Desai 469824a1566SKashyap Desai return num_admin_replies; 470824a1566SKashyap Desai } 471824a1566SKashyap Desai 472023ab2a9SKashyap Desai /** 473023ab2a9SKashyap Desai * mpi3mr_get_reply_desc - get reply descriptor frame corresponding to 474023ab2a9SKashyap Desai * queue's consumer index from operational reply descriptor queue. 475023ab2a9SKashyap Desai * @op_reply_q: op_reply_qinfo object 476023ab2a9SKashyap Desai * @reply_ci: operational reply descriptor's queue consumer index 477023ab2a9SKashyap Desai * 478023ab2a9SKashyap Desai * Returns reply descriptor frame address 479023ab2a9SKashyap Desai */ 480023ab2a9SKashyap Desai static inline struct mpi3_default_reply_descriptor * 481023ab2a9SKashyap Desai mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci) 482023ab2a9SKashyap Desai { 483023ab2a9SKashyap Desai void *segment_base_addr; 484023ab2a9SKashyap Desai struct segments *segments = op_reply_q->q_segments; 485023ab2a9SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc = NULL; 486023ab2a9SKashyap Desai 487023ab2a9SKashyap Desai segment_base_addr = 488023ab2a9SKashyap Desai segments[reply_ci / op_reply_q->segment_qd].segment; 489023ab2a9SKashyap Desai reply_desc = (struct mpi3_default_reply_descriptor *)segment_base_addr + 490023ab2a9SKashyap Desai (reply_ci % op_reply_q->segment_qd); 491023ab2a9SKashyap Desai return reply_desc; 492023ab2a9SKashyap Desai } 493023ab2a9SKashyap Desai 494afd3a579SSreekanth Reddy /** 495afd3a579SSreekanth Reddy * mpi3mr_process_op_reply_q - Operational reply queue handler 496afd3a579SSreekanth Reddy * @mrioc: Adapter instance reference 497afd3a579SSreekanth Reddy * @op_reply_q: Operational reply queue info 498afd3a579SSreekanth Reddy * 499afd3a579SSreekanth Reddy * Checks the specific operational reply queue and drains the 500afd3a579SSreekanth Reddy * reply queue entries until the queue is empty and process the 501afd3a579SSreekanth Reddy * individual reply descriptors. 502afd3a579SSreekanth Reddy * 503afd3a579SSreekanth Reddy * Return: 0 if queue is already processed,or number of reply 504afd3a579SSreekanth Reddy * descriptors processed. 505afd3a579SSreekanth Reddy */ 506afd3a579SSreekanth Reddy int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, 507afd3a579SSreekanth Reddy struct op_reply_qinfo *op_reply_q) 508023ab2a9SKashyap Desai { 509023ab2a9SKashyap Desai struct op_req_qinfo *op_req_q; 510023ab2a9SKashyap Desai u32 exp_phase; 511023ab2a9SKashyap Desai u32 reply_ci; 512023ab2a9SKashyap Desai u32 num_op_reply = 0; 513023ab2a9SKashyap Desai u64 reply_dma = 0; 514023ab2a9SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc; 515023ab2a9SKashyap Desai u16 req_q_idx = 0, reply_qidx; 516023ab2a9SKashyap Desai 517023ab2a9SKashyap Desai reply_qidx = op_reply_q->qid - 1; 518023ab2a9SKashyap Desai 519463429f8SKashyap Desai if (!atomic_add_unless(&op_reply_q->in_use, 1, 1)) 520463429f8SKashyap Desai return 0; 521463429f8SKashyap Desai 522023ab2a9SKashyap Desai exp_phase = op_reply_q->ephase; 523023ab2a9SKashyap Desai reply_ci = op_reply_q->ci; 524023ab2a9SKashyap Desai 525023ab2a9SKashyap Desai reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci); 526023ab2a9SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 527023ab2a9SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) { 528463429f8SKashyap Desai atomic_dec(&op_reply_q->in_use); 529023ab2a9SKashyap Desai return 0; 530023ab2a9SKashyap Desai } 531023ab2a9SKashyap Desai 532023ab2a9SKashyap Desai do { 533f2a79d20SSreekanth Reddy if (mrioc->unrecoverable) 534f2a79d20SSreekanth Reddy break; 535f2a79d20SSreekanth Reddy 536023ab2a9SKashyap Desai req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1; 537023ab2a9SKashyap Desai op_req_q = &mrioc->req_qinfo[req_q_idx]; 538023ab2a9SKashyap Desai 539023ab2a9SKashyap Desai WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci)); 540023ab2a9SKashyap Desai mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma, 541023ab2a9SKashyap Desai reply_qidx); 542463429f8SKashyap Desai atomic_dec(&op_reply_q->pend_ios); 543023ab2a9SKashyap Desai if (reply_dma) 544023ab2a9SKashyap Desai mpi3mr_repost_reply_buf(mrioc, reply_dma); 545023ab2a9SKashyap Desai num_op_reply++; 546023ab2a9SKashyap Desai 547023ab2a9SKashyap Desai if (++reply_ci == op_reply_q->num_replies) { 548023ab2a9SKashyap Desai reply_ci = 0; 549023ab2a9SKashyap Desai exp_phase ^= 1; 550023ab2a9SKashyap Desai } 551023ab2a9SKashyap Desai 552023ab2a9SKashyap Desai reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci); 553023ab2a9SKashyap Desai 554023ab2a9SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 555023ab2a9SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 556023ab2a9SKashyap Desai break; 5577f9f953dSSreekanth Reddy #ifndef CONFIG_PREEMPT_RT 558463429f8SKashyap Desai /* 559463429f8SKashyap Desai * Exit completion loop to avoid CPU lockup 560463429f8SKashyap Desai * Ensure remaining completion happens from threaded ISR. 561463429f8SKashyap Desai */ 562463429f8SKashyap Desai if (num_op_reply > mrioc->max_host_ios) { 563afd3a579SSreekanth Reddy op_reply_q->enable_irq_poll = true; 564463429f8SKashyap Desai break; 565463429f8SKashyap Desai } 5667f9f953dSSreekanth Reddy #endif 567023ab2a9SKashyap Desai } while (1); 568023ab2a9SKashyap Desai 569023ab2a9SKashyap Desai writel(reply_ci, 570023ab2a9SKashyap Desai &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index); 571023ab2a9SKashyap Desai op_reply_q->ci = reply_ci; 572023ab2a9SKashyap Desai op_reply_q->ephase = exp_phase; 573023ab2a9SKashyap Desai 574463429f8SKashyap Desai atomic_dec(&op_reply_q->in_use); 575023ab2a9SKashyap Desai return num_op_reply; 576023ab2a9SKashyap Desai } 577023ab2a9SKashyap Desai 578afd3a579SSreekanth Reddy /** 579afd3a579SSreekanth Reddy * mpi3mr_blk_mq_poll - Operational reply queue handler 580afd3a579SSreekanth Reddy * @shost: SCSI Host reference 581afd3a579SSreekanth Reddy * @queue_num: Request queue number (w.r.t OS it is hardware context number) 582afd3a579SSreekanth Reddy * 583afd3a579SSreekanth Reddy * Checks the specific operational reply queue and drains the 584afd3a579SSreekanth Reddy * reply queue entries until the queue is empty and process the 585afd3a579SSreekanth Reddy * individual reply descriptors. 586afd3a579SSreekanth Reddy * 587afd3a579SSreekanth Reddy * Return: 0 if queue is already processed,or number of reply 588afd3a579SSreekanth Reddy * descriptors processed. 589afd3a579SSreekanth Reddy */ 590afd3a579SSreekanth Reddy int mpi3mr_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num) 591afd3a579SSreekanth Reddy { 592afd3a579SSreekanth Reddy int num_entries = 0; 593afd3a579SSreekanth Reddy struct mpi3mr_ioc *mrioc; 594afd3a579SSreekanth Reddy 595afd3a579SSreekanth Reddy mrioc = (struct mpi3mr_ioc *)shost->hostdata; 596afd3a579SSreekanth Reddy 597f2a79d20SSreekanth Reddy if ((mrioc->reset_in_progress || mrioc->prepare_for_reset || 598f2a79d20SSreekanth Reddy mrioc->unrecoverable)) 599afd3a579SSreekanth Reddy return 0; 600afd3a579SSreekanth Reddy 601afd3a579SSreekanth Reddy num_entries = mpi3mr_process_op_reply_q(mrioc, 602afd3a579SSreekanth Reddy &mrioc->op_reply_qinfo[queue_num]); 603afd3a579SSreekanth Reddy 604afd3a579SSreekanth Reddy return num_entries; 605afd3a579SSreekanth Reddy } 606afd3a579SSreekanth Reddy 607824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata) 608824a1566SKashyap Desai { 609824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = privdata; 610824a1566SKashyap Desai struct mpi3mr_ioc *mrioc; 611824a1566SKashyap Desai u16 midx; 612463429f8SKashyap Desai u32 num_admin_replies = 0, num_op_reply = 0; 613824a1566SKashyap Desai 614824a1566SKashyap Desai if (!intr_info) 615824a1566SKashyap Desai return IRQ_NONE; 616824a1566SKashyap Desai 617824a1566SKashyap Desai mrioc = intr_info->mrioc; 618824a1566SKashyap Desai 619824a1566SKashyap Desai if (!mrioc->intr_enabled) 620824a1566SKashyap Desai return IRQ_NONE; 621824a1566SKashyap Desai 622824a1566SKashyap Desai midx = intr_info->msix_index; 623824a1566SKashyap Desai 624824a1566SKashyap Desai if (!midx) 625824a1566SKashyap Desai num_admin_replies = mpi3mr_process_admin_reply_q(mrioc); 626463429f8SKashyap Desai if (intr_info->op_reply_q) 627afd3a579SSreekanth Reddy num_op_reply = mpi3mr_process_op_reply_q(mrioc, 628afd3a579SSreekanth Reddy intr_info->op_reply_q); 629824a1566SKashyap Desai 630463429f8SKashyap Desai if (num_admin_replies || num_op_reply) 631824a1566SKashyap Desai return IRQ_HANDLED; 632824a1566SKashyap Desai else 633824a1566SKashyap Desai return IRQ_NONE; 634824a1566SKashyap Desai } 635824a1566SKashyap Desai 6367f9f953dSSreekanth Reddy #ifndef CONFIG_PREEMPT_RT 6377f9f953dSSreekanth Reddy 638824a1566SKashyap Desai static irqreturn_t mpi3mr_isr(int irq, void *privdata) 639824a1566SKashyap Desai { 640824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = privdata; 641824a1566SKashyap Desai int ret; 642824a1566SKashyap Desai 643824a1566SKashyap Desai if (!intr_info) 644824a1566SKashyap Desai return IRQ_NONE; 645824a1566SKashyap Desai 646824a1566SKashyap Desai /* Call primary ISR routine */ 647824a1566SKashyap Desai ret = mpi3mr_isr_primary(irq, privdata); 648824a1566SKashyap Desai 649463429f8SKashyap Desai /* 650463429f8SKashyap Desai * If more IOs are expected, schedule IRQ polling thread. 651463429f8SKashyap Desai * Otherwise exit from ISR. 652463429f8SKashyap Desai */ 653463429f8SKashyap Desai if (!intr_info->op_reply_q) 654824a1566SKashyap Desai return ret; 655463429f8SKashyap Desai 656463429f8SKashyap Desai if (!intr_info->op_reply_q->enable_irq_poll || 657463429f8SKashyap Desai !atomic_read(&intr_info->op_reply_q->pend_ios)) 658463429f8SKashyap Desai return ret; 659463429f8SKashyap Desai 6602e31be86SSreekanth Reddy disable_irq_nosync(intr_info->os_irq); 661463429f8SKashyap Desai 662463429f8SKashyap Desai return IRQ_WAKE_THREAD; 663824a1566SKashyap Desai } 664824a1566SKashyap Desai 665824a1566SKashyap Desai /** 666824a1566SKashyap Desai * mpi3mr_isr_poll - Reply queue polling routine 667824a1566SKashyap Desai * @irq: IRQ 668824a1566SKashyap Desai * @privdata: Interrupt info 669824a1566SKashyap Desai * 670824a1566SKashyap Desai * poll for pending I/O completions in a loop until pending I/Os 671824a1566SKashyap Desai * present or controller queue depth I/Os are processed. 672824a1566SKashyap Desai * 673824a1566SKashyap Desai * Return: IRQ_NONE or IRQ_HANDLED 674824a1566SKashyap Desai */ 675824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata) 676824a1566SKashyap Desai { 677463429f8SKashyap Desai struct mpi3mr_intr_info *intr_info = privdata; 678463429f8SKashyap Desai struct mpi3mr_ioc *mrioc; 679463429f8SKashyap Desai u16 midx; 680463429f8SKashyap Desai u32 num_op_reply = 0; 681463429f8SKashyap Desai 682463429f8SKashyap Desai if (!intr_info || !intr_info->op_reply_q) 683463429f8SKashyap Desai return IRQ_NONE; 684463429f8SKashyap Desai 685463429f8SKashyap Desai mrioc = intr_info->mrioc; 686463429f8SKashyap Desai midx = intr_info->msix_index; 687463429f8SKashyap Desai 688463429f8SKashyap Desai /* Poll for pending IOs completions */ 689463429f8SKashyap Desai do { 690f2a79d20SSreekanth Reddy if (!mrioc->intr_enabled || mrioc->unrecoverable) 691463429f8SKashyap Desai break; 692463429f8SKashyap Desai 693463429f8SKashyap Desai if (!midx) 694463429f8SKashyap Desai mpi3mr_process_admin_reply_q(mrioc); 695463429f8SKashyap Desai if (intr_info->op_reply_q) 696463429f8SKashyap Desai num_op_reply += 697afd3a579SSreekanth Reddy mpi3mr_process_op_reply_q(mrioc, 698afd3a579SSreekanth Reddy intr_info->op_reply_q); 699463429f8SKashyap Desai 700afd3a579SSreekanth Reddy usleep_range(MPI3MR_IRQ_POLL_SLEEP, 10 * MPI3MR_IRQ_POLL_SLEEP); 701463429f8SKashyap Desai 702463429f8SKashyap Desai } while (atomic_read(&intr_info->op_reply_q->pend_ios) && 703463429f8SKashyap Desai (num_op_reply < mrioc->max_host_ios)); 704463429f8SKashyap Desai 705463429f8SKashyap Desai intr_info->op_reply_q->enable_irq_poll = false; 7062e31be86SSreekanth Reddy enable_irq(intr_info->os_irq); 707463429f8SKashyap Desai 708824a1566SKashyap Desai return IRQ_HANDLED; 709824a1566SKashyap Desai } 710824a1566SKashyap Desai 7117f9f953dSSreekanth Reddy #endif 7127f9f953dSSreekanth Reddy 713824a1566SKashyap Desai /** 714824a1566SKashyap Desai * mpi3mr_request_irq - Request IRQ and register ISR 715824a1566SKashyap Desai * @mrioc: Adapter instance reference 716824a1566SKashyap Desai * @index: IRQ vector index 717824a1566SKashyap Desai * 718824a1566SKashyap Desai * Request threaded ISR with primary ISR and secondary 719824a1566SKashyap Desai * 720824a1566SKashyap Desai * Return: 0 on success and non zero on failures. 721824a1566SKashyap Desai */ 722824a1566SKashyap Desai static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index) 723824a1566SKashyap Desai { 724824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 725824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index; 726824a1566SKashyap Desai int retval = 0; 727824a1566SKashyap Desai 728824a1566SKashyap Desai intr_info->mrioc = mrioc; 729824a1566SKashyap Desai intr_info->msix_index = index; 730824a1566SKashyap Desai intr_info->op_reply_q = NULL; 731824a1566SKashyap Desai 732824a1566SKashyap Desai snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d", 733824a1566SKashyap Desai mrioc->driver_name, mrioc->id, index); 734824a1566SKashyap Desai 7357f9f953dSSreekanth Reddy #ifndef CONFIG_PREEMPT_RT 736824a1566SKashyap Desai retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr, 737824a1566SKashyap Desai mpi3mr_isr_poll, IRQF_SHARED, intr_info->name, intr_info); 7387f9f953dSSreekanth Reddy #else 7397f9f953dSSreekanth Reddy retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr_primary, 7407f9f953dSSreekanth Reddy NULL, IRQF_SHARED, intr_info->name, intr_info); 7417f9f953dSSreekanth Reddy #endif 742824a1566SKashyap Desai if (retval) { 743824a1566SKashyap Desai ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n", 744824a1566SKashyap Desai intr_info->name, pci_irq_vector(pdev, index)); 745824a1566SKashyap Desai return retval; 746824a1566SKashyap Desai } 747824a1566SKashyap Desai 7482e31be86SSreekanth Reddy intr_info->os_irq = pci_irq_vector(pdev, index); 749824a1566SKashyap Desai return retval; 750824a1566SKashyap Desai } 751824a1566SKashyap Desai 752afd3a579SSreekanth Reddy static void mpi3mr_calc_poll_queues(struct mpi3mr_ioc *mrioc, u16 max_vectors) 753afd3a579SSreekanth Reddy { 754afd3a579SSreekanth Reddy if (!mrioc->requested_poll_qcount) 755afd3a579SSreekanth Reddy return; 756afd3a579SSreekanth Reddy 757afd3a579SSreekanth Reddy /* Reserved for Admin and Default Queue */ 758afd3a579SSreekanth Reddy if (max_vectors > 2 && 759afd3a579SSreekanth Reddy (mrioc->requested_poll_qcount < max_vectors - 2)) { 760afd3a579SSreekanth Reddy ioc_info(mrioc, 761afd3a579SSreekanth Reddy "enabled polled queues (%d) msix (%d)\n", 762afd3a579SSreekanth Reddy mrioc->requested_poll_qcount, max_vectors); 763afd3a579SSreekanth Reddy } else { 764afd3a579SSreekanth Reddy ioc_info(mrioc, 765afd3a579SSreekanth Reddy "disabled polled queues (%d) msix (%d) because of no resources for default queue\n", 766afd3a579SSreekanth Reddy mrioc->requested_poll_qcount, max_vectors); 767afd3a579SSreekanth Reddy mrioc->requested_poll_qcount = 0; 768afd3a579SSreekanth Reddy } 769afd3a579SSreekanth Reddy } 770afd3a579SSreekanth Reddy 771824a1566SKashyap Desai /** 772824a1566SKashyap Desai * mpi3mr_setup_isr - Setup ISR for the controller 773824a1566SKashyap Desai * @mrioc: Adapter instance reference 774824a1566SKashyap Desai * @setup_one: Request one IRQ or more 775824a1566SKashyap Desai * 776824a1566SKashyap Desai * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR 777824a1566SKashyap Desai * 778824a1566SKashyap Desai * Return: 0 on success and non zero on failures. 779824a1566SKashyap Desai */ 780824a1566SKashyap Desai static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one) 781824a1566SKashyap Desai { 782824a1566SKashyap Desai unsigned int irq_flags = PCI_IRQ_MSIX; 783afd3a579SSreekanth Reddy int max_vectors, min_vec; 7842938beddSDan Carpenter int retval; 7852938beddSDan Carpenter int i; 786afd3a579SSreekanth Reddy struct irq_affinity desc = { .pre_vectors = 1, .post_vectors = 1 }; 787824a1566SKashyap Desai 788fe6db615SSreekanth Reddy if (mrioc->is_intr_info_set) 789fe6db615SSreekanth Reddy return 0; 790fe6db615SSreekanth Reddy 791824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 792824a1566SKashyap Desai 793afd3a579SSreekanth Reddy if (setup_one || reset_devices) { 794824a1566SKashyap Desai max_vectors = 1; 795afd3a579SSreekanth Reddy retval = pci_alloc_irq_vectors(mrioc->pdev, 796afd3a579SSreekanth Reddy 1, max_vectors, irq_flags); 797afd3a579SSreekanth Reddy if (retval < 0) { 798afd3a579SSreekanth Reddy ioc_err(mrioc, "cannot allocate irq vectors, ret %d\n", 799afd3a579SSreekanth Reddy retval); 800afd3a579SSreekanth Reddy goto out_failed; 801afd3a579SSreekanth Reddy } 802afd3a579SSreekanth Reddy } else { 803824a1566SKashyap Desai max_vectors = 804afd3a579SSreekanth Reddy min_t(int, mrioc->cpu_count + 1 + 805afd3a579SSreekanth Reddy mrioc->requested_poll_qcount, mrioc->msix_count); 806afd3a579SSreekanth Reddy 807afd3a579SSreekanth Reddy mpi3mr_calc_poll_queues(mrioc, max_vectors); 808824a1566SKashyap Desai 809824a1566SKashyap Desai ioc_info(mrioc, 810824a1566SKashyap Desai "MSI-X vectors supported: %d, no of cores: %d,", 811824a1566SKashyap Desai mrioc->msix_count, mrioc->cpu_count); 812824a1566SKashyap Desai ioc_info(mrioc, 813afd3a579SSreekanth Reddy "MSI-x vectors requested: %d poll_queues %d\n", 814afd3a579SSreekanth Reddy max_vectors, mrioc->requested_poll_qcount); 815824a1566SKashyap Desai 816afd3a579SSreekanth Reddy desc.post_vectors = mrioc->requested_poll_qcount; 817afd3a579SSreekanth Reddy min_vec = desc.pre_vectors + desc.post_vectors; 818824a1566SKashyap Desai irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES; 819824a1566SKashyap Desai 8202938beddSDan Carpenter retval = pci_alloc_irq_vectors_affinity(mrioc->pdev, 821afd3a579SSreekanth Reddy min_vec, max_vectors, irq_flags, &desc); 822afd3a579SSreekanth Reddy 8232938beddSDan Carpenter if (retval < 0) { 824afd3a579SSreekanth Reddy ioc_err(mrioc, "cannot allocate irq vectors, ret %d\n", 825afd3a579SSreekanth Reddy retval); 826824a1566SKashyap Desai goto out_failed; 827824a1566SKashyap Desai } 828afd3a579SSreekanth Reddy 829afd3a579SSreekanth Reddy 830c9566231SKashyap Desai /* 831c9566231SKashyap Desai * If only one MSI-x is allocated, then MSI-x 0 will be shared 832c9566231SKashyap Desai * between Admin queue and operational queue 833c9566231SKashyap Desai */ 834afd3a579SSreekanth Reddy if (retval == min_vec) 835c9566231SKashyap Desai mrioc->op_reply_q_offset = 0; 836afd3a579SSreekanth Reddy else if (retval != (max_vectors)) { 837afd3a579SSreekanth Reddy ioc_info(mrioc, 838afd3a579SSreekanth Reddy "allocated vectors (%d) are less than configured (%d)\n", 839afd3a579SSreekanth Reddy retval, max_vectors); 840afd3a579SSreekanth Reddy } 841824a1566SKashyap Desai 8422938beddSDan Carpenter max_vectors = retval; 843afd3a579SSreekanth Reddy mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0; 844afd3a579SSreekanth Reddy 845afd3a579SSreekanth Reddy mpi3mr_calc_poll_queues(mrioc, max_vectors); 846afd3a579SSreekanth Reddy 847824a1566SKashyap Desai } 848afd3a579SSreekanth Reddy 849824a1566SKashyap Desai mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info) * max_vectors, 850824a1566SKashyap Desai GFP_KERNEL); 851824a1566SKashyap Desai if (!mrioc->intr_info) { 8522938beddSDan Carpenter retval = -ENOMEM; 853824a1566SKashyap Desai pci_free_irq_vectors(mrioc->pdev); 854824a1566SKashyap Desai goto out_failed; 855824a1566SKashyap Desai } 856824a1566SKashyap Desai for (i = 0; i < max_vectors; i++) { 857824a1566SKashyap Desai retval = mpi3mr_request_irq(mrioc, i); 858824a1566SKashyap Desai if (retval) { 859824a1566SKashyap Desai mrioc->intr_info_count = i; 860824a1566SKashyap Desai goto out_failed; 861824a1566SKashyap Desai } 862824a1566SKashyap Desai } 863fe6db615SSreekanth Reddy if (reset_devices || !setup_one) 864fe6db615SSreekanth Reddy mrioc->is_intr_info_set = true; 865824a1566SKashyap Desai mrioc->intr_info_count = max_vectors; 866824a1566SKashyap Desai mpi3mr_ioc_enable_intr(mrioc); 8672938beddSDan Carpenter return 0; 8682938beddSDan Carpenter 869824a1566SKashyap Desai out_failed: 870824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 871824a1566SKashyap Desai 872824a1566SKashyap Desai return retval; 873824a1566SKashyap Desai } 874824a1566SKashyap Desai 875824a1566SKashyap Desai static const struct { 876824a1566SKashyap Desai enum mpi3mr_iocstate value; 877824a1566SKashyap Desai char *name; 878824a1566SKashyap Desai } mrioc_states[] = { 879824a1566SKashyap Desai { MRIOC_STATE_READY, "ready" }, 880824a1566SKashyap Desai { MRIOC_STATE_FAULT, "fault" }, 881824a1566SKashyap Desai { MRIOC_STATE_RESET, "reset" }, 882824a1566SKashyap Desai { MRIOC_STATE_BECOMING_READY, "becoming ready" }, 883824a1566SKashyap Desai { MRIOC_STATE_RESET_REQUESTED, "reset requested" }, 884824a1566SKashyap Desai { MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" }, 885824a1566SKashyap Desai }; 886824a1566SKashyap Desai 887824a1566SKashyap Desai static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state) 888824a1566SKashyap Desai { 889824a1566SKashyap Desai int i; 890824a1566SKashyap Desai char *name = NULL; 891824a1566SKashyap Desai 892824a1566SKashyap Desai for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) { 893824a1566SKashyap Desai if (mrioc_states[i].value == mrioc_state) { 894824a1566SKashyap Desai name = mrioc_states[i].name; 895824a1566SKashyap Desai break; 896824a1566SKashyap Desai } 897824a1566SKashyap Desai } 898824a1566SKashyap Desai return name; 899824a1566SKashyap Desai } 900824a1566SKashyap Desai 901f061178eSKashyap Desai /* Reset reason to name mapper structure*/ 902f061178eSKashyap Desai static const struct { 903f061178eSKashyap Desai enum mpi3mr_reset_reason value; 904f061178eSKashyap Desai char *name; 905f061178eSKashyap Desai } mpi3mr_reset_reason_codes[] = { 906f061178eSKashyap Desai { MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" }, 907f061178eSKashyap Desai { MPI3MR_RESET_FROM_FAULT_WATCH, "fault" }, 908f5e6d5a3SSumit Saxena { MPI3MR_RESET_FROM_APP, "application invocation" }, 909f061178eSKashyap Desai { MPI3MR_RESET_FROM_EH_HOS, "error handling" }, 910f061178eSKashyap Desai { MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" }, 911f5e6d5a3SSumit Saxena { MPI3MR_RESET_FROM_APP_TIMEOUT, "application command timeout" }, 912f061178eSKashyap Desai { MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" }, 913f061178eSKashyap Desai { MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" }, 914f061178eSKashyap Desai { MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" }, 915f061178eSKashyap Desai { MPI3MR_RESET_FROM_PE_TIMEOUT, "port enable timeout" }, 916f061178eSKashyap Desai { MPI3MR_RESET_FROM_TSU_TIMEOUT, "time stamp update timeout" }, 917f061178eSKashyap Desai { MPI3MR_RESET_FROM_DELREQQ_TIMEOUT, "delete request queue timeout" }, 918f061178eSKashyap Desai { MPI3MR_RESET_FROM_DELREPQ_TIMEOUT, "delete reply queue timeout" }, 919f061178eSKashyap Desai { 920f061178eSKashyap Desai MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT, 921f061178eSKashyap Desai "create request queue timeout" 922f061178eSKashyap Desai }, 923f061178eSKashyap Desai { 924f061178eSKashyap Desai MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT, 925f061178eSKashyap Desai "create reply queue timeout" 926f061178eSKashyap Desai }, 927f061178eSKashyap Desai { MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT, "IOC facts timeout" }, 928f061178eSKashyap Desai { MPI3MR_RESET_FROM_IOCINIT_TIMEOUT, "IOC init timeout" }, 929f061178eSKashyap Desai { MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT, "event notify timeout" }, 930f061178eSKashyap Desai { MPI3MR_RESET_FROM_EVTACK_TIMEOUT, "event acknowledgment timeout" }, 931f061178eSKashyap Desai { 932f061178eSKashyap Desai MPI3MR_RESET_FROM_CIACTVRST_TIMER, 933f061178eSKashyap Desai "component image activation timeout" 934f061178eSKashyap Desai }, 935f061178eSKashyap Desai { 936f061178eSKashyap Desai MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT, 937f061178eSKashyap Desai "get package version timeout" 938f061178eSKashyap Desai }, 939f061178eSKashyap Desai { MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" }, 940f061178eSKashyap Desai { MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" }, 9415867b856SColin Ian King { MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronous reset" }, 94232d457d5SSreekanth Reddy { MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT, "configuration request timeout"}, 9432bd37e28SSreekanth Reddy { MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT, "timeout of a SAS transport layer request" }, 944f061178eSKashyap Desai }; 945f061178eSKashyap Desai 946f061178eSKashyap Desai /** 947f061178eSKashyap Desai * mpi3mr_reset_rc_name - get reset reason code name 948f061178eSKashyap Desai * @reason_code: reset reason code value 949f061178eSKashyap Desai * 950f061178eSKashyap Desai * Map reset reason to an NULL terminated ASCII string 951f061178eSKashyap Desai * 952f061178eSKashyap Desai * Return: name corresponding to reset reason value or NULL. 953f061178eSKashyap Desai */ 954f061178eSKashyap Desai static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code) 955f061178eSKashyap Desai { 956f061178eSKashyap Desai int i; 957f061178eSKashyap Desai char *name = NULL; 958f061178eSKashyap Desai 959f061178eSKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_reason_codes); i++) { 960f061178eSKashyap Desai if (mpi3mr_reset_reason_codes[i].value == reason_code) { 961f061178eSKashyap Desai name = mpi3mr_reset_reason_codes[i].name; 962f061178eSKashyap Desai break; 963f061178eSKashyap Desai } 964f061178eSKashyap Desai } 965f061178eSKashyap Desai return name; 966f061178eSKashyap Desai } 967f061178eSKashyap Desai 968f061178eSKashyap Desai /* Reset type to name mapper structure*/ 969f061178eSKashyap Desai static const struct { 970f061178eSKashyap Desai u16 reset_type; 971f061178eSKashyap Desai char *name; 972f061178eSKashyap Desai } mpi3mr_reset_types[] = { 973f061178eSKashyap Desai { MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, "soft" }, 974f061178eSKashyap Desai { MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, "diag fault" }, 975f061178eSKashyap Desai }; 976f061178eSKashyap Desai 977f061178eSKashyap Desai /** 978f061178eSKashyap Desai * mpi3mr_reset_type_name - get reset type name 979f061178eSKashyap Desai * @reset_type: reset type value 980f061178eSKashyap Desai * 981f061178eSKashyap Desai * Map reset type to an NULL terminated ASCII string 982f061178eSKashyap Desai * 983f061178eSKashyap Desai * Return: name corresponding to reset type value or NULL. 984f061178eSKashyap Desai */ 985f061178eSKashyap Desai static const char *mpi3mr_reset_type_name(u16 reset_type) 986f061178eSKashyap Desai { 987f061178eSKashyap Desai int i; 988f061178eSKashyap Desai char *name = NULL; 989f061178eSKashyap Desai 990f061178eSKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_types); i++) { 991f061178eSKashyap Desai if (mpi3mr_reset_types[i].reset_type == reset_type) { 992f061178eSKashyap Desai name = mpi3mr_reset_types[i].name; 993f061178eSKashyap Desai break; 994f061178eSKashyap Desai } 995f061178eSKashyap Desai } 996f061178eSKashyap Desai return name; 997f061178eSKashyap Desai } 998f061178eSKashyap Desai 999824a1566SKashyap Desai /** 1000824a1566SKashyap Desai * mpi3mr_print_fault_info - Display fault information 1001824a1566SKashyap Desai * @mrioc: Adapter instance reference 1002824a1566SKashyap Desai * 1003824a1566SKashyap Desai * Display the controller fault information if there is a 1004824a1566SKashyap Desai * controller fault. 1005824a1566SKashyap Desai * 1006824a1566SKashyap Desai * Return: Nothing. 1007824a1566SKashyap Desai */ 1008b64845a7SSreekanth Reddy void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc) 1009824a1566SKashyap Desai { 1010824a1566SKashyap Desai u32 ioc_status, code, code1, code2, code3; 1011824a1566SKashyap Desai 1012824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1013824a1566SKashyap Desai 1014824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { 1015824a1566SKashyap Desai code = readl(&mrioc->sysif_regs->fault); 1016824a1566SKashyap Desai code1 = readl(&mrioc->sysif_regs->fault_info[0]); 1017824a1566SKashyap Desai code2 = readl(&mrioc->sysif_regs->fault_info[1]); 1018824a1566SKashyap Desai code3 = readl(&mrioc->sysif_regs->fault_info[2]); 1019824a1566SKashyap Desai 1020824a1566SKashyap Desai ioc_info(mrioc, 1021824a1566SKashyap Desai "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n", 1022824a1566SKashyap Desai code, code1, code2, code3); 1023824a1566SKashyap Desai } 1024824a1566SKashyap Desai } 1025824a1566SKashyap Desai 1026824a1566SKashyap Desai /** 1027824a1566SKashyap Desai * mpi3mr_get_iocstate - Get IOC State 1028824a1566SKashyap Desai * @mrioc: Adapter instance reference 1029824a1566SKashyap Desai * 1030824a1566SKashyap Desai * Return a proper IOC state enum based on the IOC status and 1031824a1566SKashyap Desai * IOC configuration and unrcoverable state of the controller. 1032824a1566SKashyap Desai * 1033824a1566SKashyap Desai * Return: Current IOC state. 1034824a1566SKashyap Desai */ 1035824a1566SKashyap Desai enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc) 1036824a1566SKashyap Desai { 1037824a1566SKashyap Desai u32 ioc_status, ioc_config; 1038824a1566SKashyap Desai u8 ready, enabled; 1039824a1566SKashyap Desai 1040824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1041824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1042824a1566SKashyap Desai 1043824a1566SKashyap Desai if (mrioc->unrecoverable) 1044824a1566SKashyap Desai return MRIOC_STATE_UNRECOVERABLE; 1045824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) 1046824a1566SKashyap Desai return MRIOC_STATE_FAULT; 1047824a1566SKashyap Desai 1048824a1566SKashyap Desai ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY); 1049824a1566SKashyap Desai enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC); 1050824a1566SKashyap Desai 1051824a1566SKashyap Desai if (ready && enabled) 1052824a1566SKashyap Desai return MRIOC_STATE_READY; 1053824a1566SKashyap Desai if ((!ready) && (!enabled)) 1054824a1566SKashyap Desai return MRIOC_STATE_RESET; 1055824a1566SKashyap Desai if ((!ready) && (enabled)) 1056824a1566SKashyap Desai return MRIOC_STATE_BECOMING_READY; 1057824a1566SKashyap Desai 1058824a1566SKashyap Desai return MRIOC_STATE_RESET_REQUESTED; 1059824a1566SKashyap Desai } 1060824a1566SKashyap Desai 1061824a1566SKashyap Desai /** 1062824a1566SKashyap Desai * mpi3mr_clear_reset_history - clear reset history 1063824a1566SKashyap Desai * @mrioc: Adapter instance reference 1064824a1566SKashyap Desai * 1065824a1566SKashyap Desai * Write the reset history bit in IOC status to clear the bit, 1066824a1566SKashyap Desai * if it is already set. 1067824a1566SKashyap Desai * 1068824a1566SKashyap Desai * Return: Nothing. 1069824a1566SKashyap Desai */ 1070824a1566SKashyap Desai static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc) 1071824a1566SKashyap Desai { 1072824a1566SKashyap Desai u32 ioc_status; 1073824a1566SKashyap Desai 1074824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1075824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) 1076824a1566SKashyap Desai writel(ioc_status, &mrioc->sysif_regs->ioc_status); 1077824a1566SKashyap Desai } 1078824a1566SKashyap Desai 1079824a1566SKashyap Desai /** 1080824a1566SKashyap Desai * mpi3mr_issue_and_process_mur - Message unit Reset handler 1081824a1566SKashyap Desai * @mrioc: Adapter instance reference 1082824a1566SKashyap Desai * @reset_reason: Reset reason code 1083824a1566SKashyap Desai * 1084824a1566SKashyap Desai * Issue Message unit Reset to the controller and wait for it to 1085824a1566SKashyap Desai * be complete. 1086824a1566SKashyap Desai * 1087824a1566SKashyap Desai * Return: 0 on success, -1 on failure. 1088824a1566SKashyap Desai */ 1089824a1566SKashyap Desai static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc, 1090824a1566SKashyap Desai u32 reset_reason) 1091824a1566SKashyap Desai { 1092824a1566SKashyap Desai u32 ioc_config, timeout, ioc_status; 1093824a1566SKashyap Desai int retval = -1; 1094824a1566SKashyap Desai 1095824a1566SKashyap Desai ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n"); 1096824a1566SKashyap Desai if (mrioc->unrecoverable) { 1097824a1566SKashyap Desai ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n"); 1098824a1566SKashyap Desai return retval; 1099824a1566SKashyap Desai } 1100824a1566SKashyap Desai mpi3mr_clear_reset_history(mrioc); 1101824a1566SKashyap Desai writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); 1102824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1103824a1566SKashyap Desai ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; 1104824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 1105824a1566SKashyap Desai 110622beef38SRanjan Kumar timeout = MPI3MR_MUR_TIMEOUT * 10; 1107824a1566SKashyap Desai do { 1108824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1109824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) { 1110824a1566SKashyap Desai mpi3mr_clear_reset_history(mrioc); 1111824a1566SKashyap Desai break; 1112824a1566SKashyap Desai } 1113b64845a7SSreekanth Reddy if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { 1114b64845a7SSreekanth Reddy mpi3mr_print_fault_info(mrioc); 1115b64845a7SSreekanth Reddy break; 1116824a1566SKashyap Desai } 1117824a1566SKashyap Desai msleep(100); 1118824a1566SKashyap Desai } while (--timeout); 1119824a1566SKashyap Desai 1120824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1121b64845a7SSreekanth Reddy if (timeout && !((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || 1122b64845a7SSreekanth Reddy (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) || 1123b64845a7SSreekanth Reddy (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) 1124b64845a7SSreekanth Reddy retval = 0; 1125824a1566SKashyap Desai 1126824a1566SKashyap Desai ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n", 1127824a1566SKashyap Desai (!retval) ? "successful" : "failed", ioc_status, ioc_config); 1128824a1566SKashyap Desai return retval; 1129824a1566SKashyap Desai } 1130824a1566SKashyap Desai 1131824a1566SKashyap Desai /** 1132c5758fc7SSreekanth Reddy * mpi3mr_revalidate_factsdata - validate IOCFacts parameters 1133c5758fc7SSreekanth Reddy * during reset/resume 1134c5758fc7SSreekanth Reddy * @mrioc: Adapter instance reference 1135c5758fc7SSreekanth Reddy * 1136c5758fc7SSreekanth Reddy * Return zero if the new IOCFacts parameters value is compatible with 1137c5758fc7SSreekanth Reddy * older values else return -EPERM 1138c5758fc7SSreekanth Reddy */ 1139c5758fc7SSreekanth Reddy static int 1140c5758fc7SSreekanth Reddy mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc) 1141c5758fc7SSreekanth Reddy { 1142144679dfSChristophe JAILLET unsigned long *removepend_bitmap; 1143c5758fc7SSreekanth Reddy 1144c5758fc7SSreekanth Reddy if (mrioc->facts.reply_sz > mrioc->reply_sz) { 1145c5758fc7SSreekanth Reddy ioc_err(mrioc, 1146c5758fc7SSreekanth Reddy "cannot increase reply size from %d to %d\n", 1147c5758fc7SSreekanth Reddy mrioc->reply_sz, mrioc->facts.reply_sz); 1148c5758fc7SSreekanth Reddy return -EPERM; 1149c5758fc7SSreekanth Reddy } 1150c5758fc7SSreekanth Reddy 1151c5758fc7SSreekanth Reddy if (mrioc->facts.max_op_reply_q < mrioc->num_op_reply_q) { 1152c5758fc7SSreekanth Reddy ioc_err(mrioc, 1153c5758fc7SSreekanth Reddy "cannot reduce number of operational reply queues from %d to %d\n", 1154c5758fc7SSreekanth Reddy mrioc->num_op_reply_q, 1155c5758fc7SSreekanth Reddy mrioc->facts.max_op_reply_q); 1156c5758fc7SSreekanth Reddy return -EPERM; 1157c5758fc7SSreekanth Reddy } 1158c5758fc7SSreekanth Reddy 1159c5758fc7SSreekanth Reddy if (mrioc->facts.max_op_req_q < mrioc->num_op_req_q) { 1160c5758fc7SSreekanth Reddy ioc_err(mrioc, 1161c5758fc7SSreekanth Reddy "cannot reduce number of operational request queues from %d to %d\n", 1162c5758fc7SSreekanth Reddy mrioc->num_op_req_q, mrioc->facts.max_op_req_q); 1163c5758fc7SSreekanth Reddy return -EPERM; 1164c5758fc7SSreekanth Reddy } 1165c5758fc7SSreekanth Reddy 1166d9adb81eSRanjan Kumar if (mrioc->shost->max_sectors != (mrioc->facts.max_data_length / 512)) 1167d9adb81eSRanjan Kumar ioc_err(mrioc, "Warning: The maximum data transfer length\n" 1168d9adb81eSRanjan Kumar "\tchanged after reset: previous(%d), new(%d),\n" 1169d9adb81eSRanjan Kumar "the driver cannot change this at run time\n", 1170d9adb81eSRanjan Kumar mrioc->shost->max_sectors * 512, mrioc->facts.max_data_length); 1171d9adb81eSRanjan Kumar 1172c4723e68SSreekanth Reddy if ((mrioc->sas_transport_enabled) && (mrioc->facts.ioc_capabilities & 1173c4723e68SSreekanth Reddy MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED)) 1174c4723e68SSreekanth Reddy ioc_err(mrioc, 1175c4723e68SSreekanth Reddy "critical error: multipath capability is enabled at the\n" 1176c4723e68SSreekanth Reddy "\tcontroller while sas transport support is enabled at the\n" 1177c4723e68SSreekanth Reddy "\tdriver, please reboot the system or reload the driver\n"); 1178c4723e68SSreekanth Reddy 1179339e6156SShin'ichiro Kawasaki if (mrioc->facts.max_devhandle > mrioc->dev_handle_bitmap_bits) { 1180339e6156SShin'ichiro Kawasaki removepend_bitmap = bitmap_zalloc(mrioc->facts.max_devhandle, 1181339e6156SShin'ichiro Kawasaki GFP_KERNEL); 1182c5758fc7SSreekanth Reddy if (!removepend_bitmap) { 1183c5758fc7SSreekanth Reddy ioc_err(mrioc, 1184339e6156SShin'ichiro Kawasaki "failed to increase removepend_bitmap bits from %d to %d\n", 1185339e6156SShin'ichiro Kawasaki mrioc->dev_handle_bitmap_bits, 1186339e6156SShin'ichiro Kawasaki mrioc->facts.max_devhandle); 1187c5758fc7SSreekanth Reddy return -EPERM; 1188c5758fc7SSreekanth Reddy } 1189339e6156SShin'ichiro Kawasaki bitmap_free(mrioc->removepend_bitmap); 1190c5758fc7SSreekanth Reddy mrioc->removepend_bitmap = removepend_bitmap; 1191c5758fc7SSreekanth Reddy ioc_info(mrioc, 1192339e6156SShin'ichiro Kawasaki "increased bits of dev_handle_bitmap from %d to %d\n", 1193339e6156SShin'ichiro Kawasaki mrioc->dev_handle_bitmap_bits, 1194339e6156SShin'ichiro Kawasaki mrioc->facts.max_devhandle); 1195339e6156SShin'ichiro Kawasaki mrioc->dev_handle_bitmap_bits = mrioc->facts.max_devhandle; 1196c5758fc7SSreekanth Reddy } 1197c5758fc7SSreekanth Reddy 1198c5758fc7SSreekanth Reddy return 0; 1199c5758fc7SSreekanth Reddy } 1200c5758fc7SSreekanth Reddy 1201c5758fc7SSreekanth Reddy /** 1202824a1566SKashyap Desai * mpi3mr_bring_ioc_ready - Bring controller to ready state 1203824a1566SKashyap Desai * @mrioc: Adapter instance reference 1204824a1566SKashyap Desai * 1205824a1566SKashyap Desai * Set Enable IOC bit in IOC configuration register and wait for 1206824a1566SKashyap Desai * the controller to become ready. 1207824a1566SKashyap Desai * 120859bd9cfeSSreekanth Reddy * Return: 0 on success, appropriate error on failure. 1209824a1566SKashyap Desai */ 1210824a1566SKashyap Desai static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) 1211824a1566SKashyap Desai { 12120a319f16SRanjan Kumar u32 ioc_config, ioc_status, timeout, host_diagnostic; 121359bd9cfeSSreekanth Reddy int retval = 0; 121459bd9cfeSSreekanth Reddy enum mpi3mr_iocstate ioc_state; 121559bd9cfeSSreekanth Reddy u64 base_info; 1216824a1566SKashyap Desai 121759bd9cfeSSreekanth Reddy ioc_status = readl(&mrioc->sysif_regs->ioc_status); 121859bd9cfeSSreekanth Reddy ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 121959bd9cfeSSreekanth Reddy base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information); 122059bd9cfeSSreekanth Reddy ioc_info(mrioc, "ioc_status(0x%08x), ioc_config(0x%08x), ioc_info(0x%016llx) at the bringup\n", 122159bd9cfeSSreekanth Reddy ioc_status, ioc_config, base_info); 122259bd9cfeSSreekanth Reddy 122359bd9cfeSSreekanth Reddy /*The timeout value is in 2sec unit, changing it to seconds*/ 122459bd9cfeSSreekanth Reddy mrioc->ready_timeout = 122559bd9cfeSSreekanth Reddy ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >> 122659bd9cfeSSreekanth Reddy MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2; 122759bd9cfeSSreekanth Reddy 122859bd9cfeSSreekanth Reddy ioc_info(mrioc, "ready timeout: %d seconds\n", mrioc->ready_timeout); 122959bd9cfeSSreekanth Reddy 123059bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 123159bd9cfeSSreekanth Reddy ioc_info(mrioc, "controller is in %s state during detection\n", 123259bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 123359bd9cfeSSreekanth Reddy 123459bd9cfeSSreekanth Reddy if (ioc_state == MRIOC_STATE_BECOMING_READY || 123559bd9cfeSSreekanth Reddy ioc_state == MRIOC_STATE_RESET_REQUESTED) { 123659bd9cfeSSreekanth Reddy timeout = mrioc->ready_timeout * 10; 123759bd9cfeSSreekanth Reddy do { 123859bd9cfeSSreekanth Reddy msleep(100); 123959bd9cfeSSreekanth Reddy } while (--timeout); 124059bd9cfeSSreekanth Reddy 1241f2a79d20SSreekanth Reddy if (!pci_device_is_present(mrioc->pdev)) { 1242f2a79d20SSreekanth Reddy mrioc->unrecoverable = 1; 1243f2a79d20SSreekanth Reddy ioc_err(mrioc, 1244f2a79d20SSreekanth Reddy "controller is not present while waiting to reset\n"); 1245f2a79d20SSreekanth Reddy retval = -1; 1246f2a79d20SSreekanth Reddy goto out_device_not_present; 1247f2a79d20SSreekanth Reddy } 1248f2a79d20SSreekanth Reddy 124959bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 125059bd9cfeSSreekanth Reddy ioc_info(mrioc, 125159bd9cfeSSreekanth Reddy "controller is in %s state after waiting to reset\n", 125259bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 125359bd9cfeSSreekanth Reddy } 125459bd9cfeSSreekanth Reddy 125559bd9cfeSSreekanth Reddy if (ioc_state == MRIOC_STATE_READY) { 125659bd9cfeSSreekanth Reddy ioc_info(mrioc, "issuing message unit reset (MUR) to bring to reset state\n"); 125759bd9cfeSSreekanth Reddy retval = mpi3mr_issue_and_process_mur(mrioc, 125859bd9cfeSSreekanth Reddy MPI3MR_RESET_FROM_BRINGUP); 125959bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 126059bd9cfeSSreekanth Reddy if (retval) 126159bd9cfeSSreekanth Reddy ioc_err(mrioc, 126259bd9cfeSSreekanth Reddy "message unit reset failed with error %d current state %s\n", 126359bd9cfeSSreekanth Reddy retval, mpi3mr_iocstate_name(ioc_state)); 126459bd9cfeSSreekanth Reddy } 126559bd9cfeSSreekanth Reddy if (ioc_state != MRIOC_STATE_RESET) { 12660a319f16SRanjan Kumar if (ioc_state == MRIOC_STATE_FAULT) { 12670a319f16SRanjan Kumar timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; 12680a319f16SRanjan Kumar mpi3mr_print_fault_info(mrioc); 12690a319f16SRanjan Kumar do { 12700a319f16SRanjan Kumar host_diagnostic = 12710a319f16SRanjan Kumar readl(&mrioc->sysif_regs->host_diagnostic); 12720a319f16SRanjan Kumar if (!(host_diagnostic & 12730a319f16SRanjan Kumar MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS)) 12740a319f16SRanjan Kumar break; 12750a319f16SRanjan Kumar if (!pci_device_is_present(mrioc->pdev)) { 12760a319f16SRanjan Kumar mrioc->unrecoverable = 1; 12770a319f16SRanjan Kumar ioc_err(mrioc, "controller is not present at the bringup\n"); 12780a319f16SRanjan Kumar goto out_device_not_present; 12790a319f16SRanjan Kumar } 12800a319f16SRanjan Kumar msleep(100); 12810a319f16SRanjan Kumar } while (--timeout); 12820a319f16SRanjan Kumar } 128359bd9cfeSSreekanth Reddy mpi3mr_print_fault_info(mrioc); 128459bd9cfeSSreekanth Reddy ioc_info(mrioc, "issuing soft reset to bring to reset state\n"); 128559bd9cfeSSreekanth Reddy retval = mpi3mr_issue_reset(mrioc, 128659bd9cfeSSreekanth Reddy MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, 128759bd9cfeSSreekanth Reddy MPI3MR_RESET_FROM_BRINGUP); 128859bd9cfeSSreekanth Reddy if (retval) { 128959bd9cfeSSreekanth Reddy ioc_err(mrioc, 129059bd9cfeSSreekanth Reddy "soft reset failed with error %d\n", retval); 129159bd9cfeSSreekanth Reddy goto out_failed; 129259bd9cfeSSreekanth Reddy } 129359bd9cfeSSreekanth Reddy } 129459bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 129559bd9cfeSSreekanth Reddy if (ioc_state != MRIOC_STATE_RESET) { 129659bd9cfeSSreekanth Reddy ioc_err(mrioc, 129759bd9cfeSSreekanth Reddy "cannot bring controller to reset state, current state: %s\n", 129859bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 129959bd9cfeSSreekanth Reddy goto out_failed; 130059bd9cfeSSreekanth Reddy } 130159bd9cfeSSreekanth Reddy mpi3mr_clear_reset_history(mrioc); 130259bd9cfeSSreekanth Reddy retval = mpi3mr_setup_admin_qpair(mrioc); 130359bd9cfeSSreekanth Reddy if (retval) { 130459bd9cfeSSreekanth Reddy ioc_err(mrioc, "failed to setup admin queues: error %d\n", 130559bd9cfeSSreekanth Reddy retval); 130659bd9cfeSSreekanth Reddy goto out_failed; 130759bd9cfeSSreekanth Reddy } 130859bd9cfeSSreekanth Reddy 130959bd9cfeSSreekanth Reddy ioc_info(mrioc, "bringing controller to ready state\n"); 1310824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1311824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; 1312824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 1313824a1566SKashyap Desai 1314824a1566SKashyap Desai timeout = mrioc->ready_timeout * 10; 1315824a1566SKashyap Desai do { 131659bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 131759bd9cfeSSreekanth Reddy if (ioc_state == MRIOC_STATE_READY) { 131859bd9cfeSSreekanth Reddy ioc_info(mrioc, 13195867b856SColin Ian King "successfully transitioned to %s state\n", 132059bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 1321824a1566SKashyap Desai return 0; 132259bd9cfeSSreekanth Reddy } 1323f2a79d20SSreekanth Reddy if (!pci_device_is_present(mrioc->pdev)) { 1324f2a79d20SSreekanth Reddy mrioc->unrecoverable = 1; 1325f2a79d20SSreekanth Reddy ioc_err(mrioc, 1326f2a79d20SSreekanth Reddy "controller is not present at the bringup\n"); 1327f2a79d20SSreekanth Reddy retval = -1; 1328f2a79d20SSreekanth Reddy goto out_device_not_present; 1329f2a79d20SSreekanth Reddy } 1330824a1566SKashyap Desai msleep(100); 1331824a1566SKashyap Desai } while (--timeout); 1332824a1566SKashyap Desai 133359bd9cfeSSreekanth Reddy out_failed: 133459bd9cfeSSreekanth Reddy ioc_state = mpi3mr_get_iocstate(mrioc); 133559bd9cfeSSreekanth Reddy ioc_err(mrioc, 133659bd9cfeSSreekanth Reddy "failed to bring to ready state, current state: %s\n", 133759bd9cfeSSreekanth Reddy mpi3mr_iocstate_name(ioc_state)); 1338f2a79d20SSreekanth Reddy out_device_not_present: 133959bd9cfeSSreekanth Reddy return retval; 1340824a1566SKashyap Desai } 1341824a1566SKashyap Desai 1342824a1566SKashyap Desai /** 1343f061178eSKashyap Desai * mpi3mr_soft_reset_success - Check softreset is success or not 1344f061178eSKashyap Desai * @ioc_status: IOC status register value 1345f061178eSKashyap Desai * @ioc_config: IOC config register value 1346f061178eSKashyap Desai * 1347f061178eSKashyap Desai * Check whether the soft reset is successful or not based on 1348f061178eSKashyap Desai * IOC status and IOC config register values. 1349f061178eSKashyap Desai * 1350f061178eSKashyap Desai * Return: True when the soft reset is success, false otherwise. 1351f061178eSKashyap Desai */ 1352f061178eSKashyap Desai static inline bool 1353f061178eSKashyap Desai mpi3mr_soft_reset_success(u32 ioc_status, u32 ioc_config) 1354f061178eSKashyap Desai { 1355f061178eSKashyap Desai if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || 1356f061178eSKashyap Desai (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) 1357f061178eSKashyap Desai return true; 1358f061178eSKashyap Desai return false; 1359f061178eSKashyap Desai } 1360f061178eSKashyap Desai 1361f061178eSKashyap Desai /** 1362f061178eSKashyap Desai * mpi3mr_diagfault_success - Check diag fault is success or not 1363f061178eSKashyap Desai * @mrioc: Adapter reference 1364f061178eSKashyap Desai * @ioc_status: IOC status register value 1365f061178eSKashyap Desai * 1366f061178eSKashyap Desai * Check whether the controller hit diag reset fault code. 1367f061178eSKashyap Desai * 1368f061178eSKashyap Desai * Return: True when there is diag fault, false otherwise. 1369f061178eSKashyap Desai */ 1370f061178eSKashyap Desai static inline bool mpi3mr_diagfault_success(struct mpi3mr_ioc *mrioc, 1371f061178eSKashyap Desai u32 ioc_status) 1372f061178eSKashyap Desai { 1373f061178eSKashyap Desai u32 fault; 1374f061178eSKashyap Desai 1375f061178eSKashyap Desai if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) 1376f061178eSKashyap Desai return false; 1377f061178eSKashyap Desai fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK; 1378b64845a7SSreekanth Reddy if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) { 1379b64845a7SSreekanth Reddy mpi3mr_print_fault_info(mrioc); 1380f061178eSKashyap Desai return true; 1381b64845a7SSreekanth Reddy } 1382f061178eSKashyap Desai return false; 1383f061178eSKashyap Desai } 1384f061178eSKashyap Desai 1385f061178eSKashyap Desai /** 1386824a1566SKashyap Desai * mpi3mr_set_diagsave - Set diag save bit for snapdump 1387824a1566SKashyap Desai * @mrioc: Adapter reference 1388824a1566SKashyap Desai * 1389824a1566SKashyap Desai * Set diag save bit in IOC configuration register to enable 1390824a1566SKashyap Desai * snapdump. 1391824a1566SKashyap Desai * 1392824a1566SKashyap Desai * Return: Nothing. 1393824a1566SKashyap Desai */ 1394824a1566SKashyap Desai static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc) 1395824a1566SKashyap Desai { 1396824a1566SKashyap Desai u32 ioc_config; 1397824a1566SKashyap Desai 1398824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1399824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE; 1400824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 1401824a1566SKashyap Desai } 1402824a1566SKashyap Desai 1403824a1566SKashyap Desai /** 1404824a1566SKashyap Desai * mpi3mr_issue_reset - Issue reset to the controller 1405824a1566SKashyap Desai * @mrioc: Adapter reference 1406824a1566SKashyap Desai * @reset_type: Reset type 1407824a1566SKashyap Desai * @reset_reason: Reset reason code 1408824a1566SKashyap Desai * 1409f061178eSKashyap Desai * Unlock the host diagnostic registers and write the specific 1410f061178eSKashyap Desai * reset type to that, wait for reset acknowledgment from the 1411f061178eSKashyap Desai * controller, if the reset is not successful retry for the 1412f061178eSKashyap Desai * predefined number of times. 1413824a1566SKashyap Desai * 1414824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 1415824a1566SKashyap Desai */ 1416824a1566SKashyap Desai static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, 1417824a1566SKashyap Desai u32 reset_reason) 1418824a1566SKashyap Desai { 1419f061178eSKashyap Desai int retval = -1; 1420b64845a7SSreekanth Reddy u8 unlock_retry_count = 0; 1421b64845a7SSreekanth Reddy u32 host_diagnostic, ioc_status, ioc_config; 1422b64845a7SSreekanth Reddy u32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10; 1423f061178eSKashyap Desai 1424f061178eSKashyap Desai if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) && 1425f061178eSKashyap Desai (reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT)) 1426b64845a7SSreekanth Reddy return retval; 1427f061178eSKashyap Desai if (mrioc->unrecoverable) 1428b64845a7SSreekanth Reddy return retval; 1429b64845a7SSreekanth Reddy if (reset_reason == MPI3MR_RESET_FROM_FIRMWARE) { 1430b64845a7SSreekanth Reddy retval = 0; 1431b64845a7SSreekanth Reddy return retval; 1432b64845a7SSreekanth Reddy } 1433b64845a7SSreekanth Reddy 1434b64845a7SSreekanth Reddy ioc_info(mrioc, "%s reset due to %s(0x%x)\n", 1435b64845a7SSreekanth Reddy mpi3mr_reset_type_name(reset_type), 1436b64845a7SSreekanth Reddy mpi3mr_reset_rc_name(reset_reason), reset_reason); 1437b64845a7SSreekanth Reddy 1438f061178eSKashyap Desai mpi3mr_clear_reset_history(mrioc); 1439f061178eSKashyap Desai do { 1440f061178eSKashyap Desai ioc_info(mrioc, 1441f061178eSKashyap Desai "Write magic sequence to unlock host diag register (retry=%d)\n", 1442f061178eSKashyap Desai ++unlock_retry_count); 1443f061178eSKashyap Desai if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) { 1444b64845a7SSreekanth Reddy ioc_err(mrioc, 1445b64845a7SSreekanth Reddy "%s reset failed due to unlock failure, host_diagnostic(0x%08x)\n", 1446b64845a7SSreekanth Reddy mpi3mr_reset_type_name(reset_type), 1447b64845a7SSreekanth Reddy host_diagnostic); 1448f061178eSKashyap Desai mrioc->unrecoverable = 1; 1449b64845a7SSreekanth Reddy return retval; 1450f061178eSKashyap Desai } 1451f061178eSKashyap Desai 1452f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH, 1453f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1454f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST, 1455f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1456f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND, 1457f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1458f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD, 1459f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1460f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH, 1461f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1462f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH, 1463f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1464f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH, 1465f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1466f061178eSKashyap Desai usleep_range(1000, 1100); 1467f061178eSKashyap Desai host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); 1468f061178eSKashyap Desai ioc_info(mrioc, 1469f061178eSKashyap Desai "wrote magic sequence: retry_count(%d), host_diagnostic(0x%08x)\n", 1470f061178eSKashyap Desai unlock_retry_count, host_diagnostic); 1471f061178eSKashyap Desai } while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE)); 1472f061178eSKashyap Desai 1473f061178eSKashyap Desai writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); 1474f061178eSKashyap Desai writel(host_diagnostic | reset_type, 1475f061178eSKashyap Desai &mrioc->sysif_regs->host_diagnostic); 1476b64845a7SSreekanth Reddy switch (reset_type) { 1477b64845a7SSreekanth Reddy case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET: 1478f061178eSKashyap Desai do { 1479f061178eSKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1480f061178eSKashyap Desai ioc_config = 1481f061178eSKashyap Desai readl(&mrioc->sysif_regs->ioc_configuration); 1482b64845a7SSreekanth Reddy if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) 1483b64845a7SSreekanth Reddy && mpi3mr_soft_reset_success(ioc_status, ioc_config) 1484b64845a7SSreekanth Reddy ) { 1485b64845a7SSreekanth Reddy mpi3mr_clear_reset_history(mrioc); 1486f061178eSKashyap Desai retval = 0; 1487f061178eSKashyap Desai break; 1488f061178eSKashyap Desai } 1489f061178eSKashyap Desai msleep(100); 1490f061178eSKashyap Desai } while (--timeout); 1491b64845a7SSreekanth Reddy mpi3mr_print_fault_info(mrioc); 1492b64845a7SSreekanth Reddy break; 1493b64845a7SSreekanth Reddy case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT: 1494f061178eSKashyap Desai do { 1495f061178eSKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1496f061178eSKashyap Desai if (mpi3mr_diagfault_success(mrioc, ioc_status)) { 1497f061178eSKashyap Desai retval = 0; 1498f061178eSKashyap Desai break; 1499f061178eSKashyap Desai } 1500f061178eSKashyap Desai msleep(100); 1501f061178eSKashyap Desai } while (--timeout); 1502b64845a7SSreekanth Reddy break; 1503b64845a7SSreekanth Reddy default: 1504b64845a7SSreekanth Reddy break; 1505b64845a7SSreekanth Reddy } 1506b64845a7SSreekanth Reddy 1507f061178eSKashyap Desai writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND, 1508f061178eSKashyap Desai &mrioc->sysif_regs->write_sequence); 1509f061178eSKashyap Desai 1510f061178eSKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1511b64845a7SSreekanth Reddy ioc_status = readl(&mrioc->sysif_regs->ioc_status); 1512f061178eSKashyap Desai ioc_info(mrioc, 1513b64845a7SSreekanth Reddy "ioc_status/ioc_onfig after %s reset is (0x%x)/(0x%x)\n", 1514f061178eSKashyap Desai (!retval)?"successful":"failed", ioc_status, 1515f061178eSKashyap Desai ioc_config); 1516b64845a7SSreekanth Reddy if (retval) 1517b64845a7SSreekanth Reddy mrioc->unrecoverable = 1; 1518f061178eSKashyap Desai return retval; 1519824a1566SKashyap Desai } 1520824a1566SKashyap Desai 1521824a1566SKashyap Desai /** 1522824a1566SKashyap Desai * mpi3mr_admin_request_post - Post request to admin queue 1523824a1566SKashyap Desai * @mrioc: Adapter reference 1524824a1566SKashyap Desai * @admin_req: MPI3 request 1525824a1566SKashyap Desai * @admin_req_sz: Request size 1526824a1566SKashyap Desai * @ignore_reset: Ignore reset in process 1527824a1566SKashyap Desai * 1528824a1566SKashyap Desai * Post the MPI3 request into admin request queue and 1529824a1566SKashyap Desai * inform the controller, if the queue is full return 1530824a1566SKashyap Desai * appropriate error. 1531824a1566SKashyap Desai * 1532824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 1533824a1566SKashyap Desai */ 1534824a1566SKashyap Desai int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req, 1535824a1566SKashyap Desai u16 admin_req_sz, u8 ignore_reset) 1536824a1566SKashyap Desai { 1537824a1566SKashyap Desai u16 areq_pi = 0, areq_ci = 0, max_entries = 0; 1538824a1566SKashyap Desai int retval = 0; 1539824a1566SKashyap Desai unsigned long flags; 1540824a1566SKashyap Desai u8 *areq_entry; 1541824a1566SKashyap Desai 1542824a1566SKashyap Desai if (mrioc->unrecoverable) { 1543824a1566SKashyap Desai ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__); 1544824a1566SKashyap Desai return -EFAULT; 1545824a1566SKashyap Desai } 1546824a1566SKashyap Desai 1547824a1566SKashyap Desai spin_lock_irqsave(&mrioc->admin_req_lock, flags); 1548824a1566SKashyap Desai areq_pi = mrioc->admin_req_pi; 1549824a1566SKashyap Desai areq_ci = mrioc->admin_req_ci; 1550824a1566SKashyap Desai max_entries = mrioc->num_admin_req; 1551824a1566SKashyap Desai if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) && 1552824a1566SKashyap Desai (areq_pi == (max_entries - 1)))) { 1553824a1566SKashyap Desai ioc_err(mrioc, "AdminReqQ full condition detected\n"); 1554824a1566SKashyap Desai retval = -EAGAIN; 1555824a1566SKashyap Desai goto out; 1556824a1566SKashyap Desai } 1557824a1566SKashyap Desai if (!ignore_reset && mrioc->reset_in_progress) { 1558824a1566SKashyap Desai ioc_err(mrioc, "AdminReqQ submit reset in progress\n"); 1559824a1566SKashyap Desai retval = -EAGAIN; 1560824a1566SKashyap Desai goto out; 1561824a1566SKashyap Desai } 1562824a1566SKashyap Desai areq_entry = (u8 *)mrioc->admin_req_base + 1563824a1566SKashyap Desai (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ); 1564824a1566SKashyap Desai memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ); 1565824a1566SKashyap Desai memcpy(areq_entry, (u8 *)admin_req, admin_req_sz); 1566824a1566SKashyap Desai 1567824a1566SKashyap Desai if (++areq_pi == max_entries) 1568824a1566SKashyap Desai areq_pi = 0; 1569824a1566SKashyap Desai mrioc->admin_req_pi = areq_pi; 1570824a1566SKashyap Desai 1571824a1566SKashyap Desai writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi); 1572824a1566SKashyap Desai 1573824a1566SKashyap Desai out: 1574824a1566SKashyap Desai spin_unlock_irqrestore(&mrioc->admin_req_lock, flags); 1575824a1566SKashyap Desai 1576824a1566SKashyap Desai return retval; 1577824a1566SKashyap Desai } 1578824a1566SKashyap Desai 1579824a1566SKashyap Desai /** 1580c9566231SKashyap Desai * mpi3mr_free_op_req_q_segments - free request memory segments 1581c9566231SKashyap Desai * @mrioc: Adapter instance reference 1582c9566231SKashyap Desai * @q_idx: operational request queue index 1583c9566231SKashyap Desai * 1584c9566231SKashyap Desai * Free memory segments allocated for operational request queue 1585c9566231SKashyap Desai * 1586c9566231SKashyap Desai * Return: Nothing. 1587c9566231SKashyap Desai */ 1588c9566231SKashyap Desai static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) 1589c9566231SKashyap Desai { 1590c9566231SKashyap Desai u16 j; 1591c9566231SKashyap Desai int size; 1592c9566231SKashyap Desai struct segments *segments; 1593c9566231SKashyap Desai 1594c9566231SKashyap Desai segments = mrioc->req_qinfo[q_idx].q_segments; 1595c9566231SKashyap Desai if (!segments) 1596c9566231SKashyap Desai return; 1597c9566231SKashyap Desai 1598c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1599c9566231SKashyap Desai size = MPI3MR_OP_REQ_Q_SEG_SIZE; 1600c9566231SKashyap Desai if (mrioc->req_qinfo[q_idx].q_segment_list) { 1601c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 1602c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, 1603c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segment_list, 1604c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segment_list_dma); 1605d44b5fefSSreekanth Reddy mrioc->req_qinfo[q_idx].q_segment_list = NULL; 1606c9566231SKashyap Desai } 1607c9566231SKashyap Desai } else 1608243bcc8eSSreekanth Reddy size = mrioc->req_qinfo[q_idx].segment_qd * 1609c9566231SKashyap Desai mrioc->facts.op_req_sz; 1610c9566231SKashyap Desai 1611c9566231SKashyap Desai for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) { 1612c9566231SKashyap Desai if (!segments[j].segment) 1613c9566231SKashyap Desai continue; 1614c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 1615c9566231SKashyap Desai size, segments[j].segment, segments[j].segment_dma); 1616c9566231SKashyap Desai segments[j].segment = NULL; 1617c9566231SKashyap Desai } 1618c9566231SKashyap Desai kfree(mrioc->req_qinfo[q_idx].q_segments); 1619c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segments = NULL; 1620c9566231SKashyap Desai mrioc->req_qinfo[q_idx].qid = 0; 1621c9566231SKashyap Desai } 1622c9566231SKashyap Desai 1623c9566231SKashyap Desai /** 1624c9566231SKashyap Desai * mpi3mr_free_op_reply_q_segments - free reply memory segments 1625c9566231SKashyap Desai * @mrioc: Adapter instance reference 1626c9566231SKashyap Desai * @q_idx: operational reply queue index 1627c9566231SKashyap Desai * 1628c9566231SKashyap Desai * Free memory segments allocated for operational reply queue 1629c9566231SKashyap Desai * 1630c9566231SKashyap Desai * Return: Nothing. 1631c9566231SKashyap Desai */ 1632c9566231SKashyap Desai static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) 1633c9566231SKashyap Desai { 1634c9566231SKashyap Desai u16 j; 1635c9566231SKashyap Desai int size; 1636c9566231SKashyap Desai struct segments *segments; 1637c9566231SKashyap Desai 1638c9566231SKashyap Desai segments = mrioc->op_reply_qinfo[q_idx].q_segments; 1639c9566231SKashyap Desai if (!segments) 1640c9566231SKashyap Desai return; 1641c9566231SKashyap Desai 1642c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1643c9566231SKashyap Desai size = MPI3MR_OP_REP_Q_SEG_SIZE; 1644c9566231SKashyap Desai if (mrioc->op_reply_qinfo[q_idx].q_segment_list) { 1645c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 1646c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, 1647c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list, 1648c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list_dma); 1649c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL; 1650c9566231SKashyap Desai } 1651c9566231SKashyap Desai } else 1652c9566231SKashyap Desai size = mrioc->op_reply_qinfo[q_idx].segment_qd * 1653c9566231SKashyap Desai mrioc->op_reply_desc_sz; 1654c9566231SKashyap Desai 1655c9566231SKashyap Desai for (j = 0; j < mrioc->op_reply_qinfo[q_idx].num_segments; j++) { 1656c9566231SKashyap Desai if (!segments[j].segment) 1657c9566231SKashyap Desai continue; 1658c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 1659c9566231SKashyap Desai size, segments[j].segment, segments[j].segment_dma); 1660c9566231SKashyap Desai segments[j].segment = NULL; 1661c9566231SKashyap Desai } 1662c9566231SKashyap Desai 1663c9566231SKashyap Desai kfree(mrioc->op_reply_qinfo[q_idx].q_segments); 1664c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segments = NULL; 1665c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].qid = 0; 1666c9566231SKashyap Desai } 1667c9566231SKashyap Desai 1668c9566231SKashyap Desai /** 1669c9566231SKashyap Desai * mpi3mr_delete_op_reply_q - delete operational reply queue 1670c9566231SKashyap Desai * @mrioc: Adapter instance reference 1671c9566231SKashyap Desai * @qidx: operational reply queue index 1672c9566231SKashyap Desai * 1673c9566231SKashyap Desai * Delete operatinal reply queue by issuing MPI request 1674c9566231SKashyap Desai * through admin queue. 1675c9566231SKashyap Desai * 1676c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1677c9566231SKashyap Desai */ 1678c9566231SKashyap Desai static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) 1679c9566231SKashyap Desai { 1680c9566231SKashyap Desai struct mpi3_delete_reply_queue_request delq_req; 1681afd3a579SSreekanth Reddy struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 1682c9566231SKashyap Desai int retval = 0; 1683c9566231SKashyap Desai u16 reply_qid = 0, midx; 1684c9566231SKashyap Desai 1685afd3a579SSreekanth Reddy reply_qid = op_reply_q->qid; 1686c9566231SKashyap Desai 1687c9566231SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset); 1688c9566231SKashyap Desai 1689c9566231SKashyap Desai if (!reply_qid) { 1690c9566231SKashyap Desai retval = -1; 1691c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: called with invalid ReqQID\n"); 1692c9566231SKashyap Desai goto out; 1693c9566231SKashyap Desai } 1694c9566231SKashyap Desai 1695afd3a579SSreekanth Reddy (op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) ? mrioc->default_qcount-- : 1696afd3a579SSreekanth Reddy mrioc->active_poll_qcount--; 1697afd3a579SSreekanth Reddy 1698c9566231SKashyap Desai memset(&delq_req, 0, sizeof(delq_req)); 1699c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1700c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1701c9566231SKashyap Desai retval = -1; 1702c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: Init command is in use\n"); 1703c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1704c9566231SKashyap Desai goto out; 1705c9566231SKashyap Desai } 1706c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1707c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1708c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 1709c9566231SKashyap Desai delq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1710c9566231SKashyap Desai delq_req.function = MPI3_FUNCTION_DELETE_REPLY_QUEUE; 1711c9566231SKashyap Desai delq_req.queue_id = cpu_to_le16(reply_qid); 1712c9566231SKashyap Desai 1713c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 1714c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &delq_req, sizeof(delq_req), 1715c9566231SKashyap Desai 1); 1716c9566231SKashyap Desai if (retval) { 1717c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: Admin Post failed\n"); 1718c9566231SKashyap Desai goto out_unlock; 1719c9566231SKashyap Desai } 1720c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1721c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1722c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1723a6856cc4SSreekanth Reddy ioc_err(mrioc, "delete reply queue timed out\n"); 1724a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 1725c9566231SKashyap Desai MPI3MR_RESET_FROM_DELREPQ_TIMEOUT); 1726c9566231SKashyap Desai retval = -1; 1727c9566231SKashyap Desai goto out_unlock; 1728c9566231SKashyap Desai } 1729c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1730c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1731c9566231SKashyap Desai ioc_err(mrioc, 1732c9566231SKashyap Desai "Issue DelRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1733c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1734c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 1735c9566231SKashyap Desai retval = -1; 1736c9566231SKashyap Desai goto out_unlock; 1737c9566231SKashyap Desai } 1738c9566231SKashyap Desai mrioc->intr_info[midx].op_reply_q = NULL; 1739c9566231SKashyap Desai 1740c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, qidx); 1741c9566231SKashyap Desai out_unlock: 1742c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 1743c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1744c9566231SKashyap Desai out: 1745c9566231SKashyap Desai 1746c9566231SKashyap Desai return retval; 1747c9566231SKashyap Desai } 1748c9566231SKashyap Desai 1749c9566231SKashyap Desai /** 1750c9566231SKashyap Desai * mpi3mr_alloc_op_reply_q_segments -Alloc segmented reply pool 1751c9566231SKashyap Desai * @mrioc: Adapter instance reference 1752c9566231SKashyap Desai * @qidx: request queue index 1753c9566231SKashyap Desai * 1754c9566231SKashyap Desai * Allocate segmented memory pools for operational reply 1755c9566231SKashyap Desai * queue. 1756c9566231SKashyap Desai * 1757c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1758c9566231SKashyap Desai */ 1759c9566231SKashyap Desai static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) 1760c9566231SKashyap Desai { 1761c9566231SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 1762c9566231SKashyap Desai int i, size; 1763c9566231SKashyap Desai u64 *q_segment_list_entry = NULL; 1764c9566231SKashyap Desai struct segments *segments; 1765c9566231SKashyap Desai 1766c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1767c9566231SKashyap Desai op_reply_q->segment_qd = 1768c9566231SKashyap Desai MPI3MR_OP_REP_Q_SEG_SIZE / mrioc->op_reply_desc_sz; 1769c9566231SKashyap Desai 1770c9566231SKashyap Desai size = MPI3MR_OP_REP_Q_SEG_SIZE; 1771c9566231SKashyap Desai 1772c9566231SKashyap Desai op_reply_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev, 1773c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, &op_reply_q->q_segment_list_dma, 1774c9566231SKashyap Desai GFP_KERNEL); 1775c9566231SKashyap Desai if (!op_reply_q->q_segment_list) 1776c9566231SKashyap Desai return -ENOMEM; 1777c9566231SKashyap Desai q_segment_list_entry = (u64 *)op_reply_q->q_segment_list; 1778c9566231SKashyap Desai } else { 1779c9566231SKashyap Desai op_reply_q->segment_qd = op_reply_q->num_replies; 1780c9566231SKashyap Desai size = op_reply_q->num_replies * mrioc->op_reply_desc_sz; 1781c9566231SKashyap Desai } 1782c9566231SKashyap Desai 1783c9566231SKashyap Desai op_reply_q->num_segments = DIV_ROUND_UP(op_reply_q->num_replies, 1784c9566231SKashyap Desai op_reply_q->segment_qd); 1785c9566231SKashyap Desai 1786c9566231SKashyap Desai op_reply_q->q_segments = kcalloc(op_reply_q->num_segments, 1787c9566231SKashyap Desai sizeof(struct segments), GFP_KERNEL); 1788c9566231SKashyap Desai if (!op_reply_q->q_segments) 1789c9566231SKashyap Desai return -ENOMEM; 1790c9566231SKashyap Desai 1791c9566231SKashyap Desai segments = op_reply_q->q_segments; 1792c9566231SKashyap Desai for (i = 0; i < op_reply_q->num_segments; i++) { 1793c9566231SKashyap Desai segments[i].segment = 1794c9566231SKashyap Desai dma_alloc_coherent(&mrioc->pdev->dev, 1795c9566231SKashyap Desai size, &segments[i].segment_dma, GFP_KERNEL); 1796c9566231SKashyap Desai if (!segments[i].segment) 1797c9566231SKashyap Desai return -ENOMEM; 1798c9566231SKashyap Desai if (mrioc->enable_segqueue) 1799c9566231SKashyap Desai q_segment_list_entry[i] = 1800c9566231SKashyap Desai (unsigned long)segments[i].segment_dma; 1801c9566231SKashyap Desai } 1802c9566231SKashyap Desai 1803c9566231SKashyap Desai return 0; 1804c9566231SKashyap Desai } 1805c9566231SKashyap Desai 1806c9566231SKashyap Desai /** 1807c9566231SKashyap Desai * mpi3mr_alloc_op_req_q_segments - Alloc segmented req pool. 1808c9566231SKashyap Desai * @mrioc: Adapter instance reference 1809c9566231SKashyap Desai * @qidx: request queue index 1810c9566231SKashyap Desai * 1811c9566231SKashyap Desai * Allocate segmented memory pools for operational request 1812c9566231SKashyap Desai * queue. 1813c9566231SKashyap Desai * 1814c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1815c9566231SKashyap Desai */ 1816c9566231SKashyap Desai static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) 1817c9566231SKashyap Desai { 1818c9566231SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx; 1819c9566231SKashyap Desai int i, size; 1820c9566231SKashyap Desai u64 *q_segment_list_entry = NULL; 1821c9566231SKashyap Desai struct segments *segments; 1822c9566231SKashyap Desai 1823c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1824c9566231SKashyap Desai op_req_q->segment_qd = 1825c9566231SKashyap Desai MPI3MR_OP_REQ_Q_SEG_SIZE / mrioc->facts.op_req_sz; 1826c9566231SKashyap Desai 1827c9566231SKashyap Desai size = MPI3MR_OP_REQ_Q_SEG_SIZE; 1828c9566231SKashyap Desai 1829c9566231SKashyap Desai op_req_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev, 1830c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, &op_req_q->q_segment_list_dma, 1831c9566231SKashyap Desai GFP_KERNEL); 1832c9566231SKashyap Desai if (!op_req_q->q_segment_list) 1833c9566231SKashyap Desai return -ENOMEM; 1834c9566231SKashyap Desai q_segment_list_entry = (u64 *)op_req_q->q_segment_list; 1835c9566231SKashyap Desai 1836c9566231SKashyap Desai } else { 1837c9566231SKashyap Desai op_req_q->segment_qd = op_req_q->num_requests; 1838c9566231SKashyap Desai size = op_req_q->num_requests * mrioc->facts.op_req_sz; 1839c9566231SKashyap Desai } 1840c9566231SKashyap Desai 1841c9566231SKashyap Desai op_req_q->num_segments = DIV_ROUND_UP(op_req_q->num_requests, 1842c9566231SKashyap Desai op_req_q->segment_qd); 1843c9566231SKashyap Desai 1844c9566231SKashyap Desai op_req_q->q_segments = kcalloc(op_req_q->num_segments, 1845c9566231SKashyap Desai sizeof(struct segments), GFP_KERNEL); 1846c9566231SKashyap Desai if (!op_req_q->q_segments) 1847c9566231SKashyap Desai return -ENOMEM; 1848c9566231SKashyap Desai 1849c9566231SKashyap Desai segments = op_req_q->q_segments; 1850c9566231SKashyap Desai for (i = 0; i < op_req_q->num_segments; i++) { 1851c9566231SKashyap Desai segments[i].segment = 1852c9566231SKashyap Desai dma_alloc_coherent(&mrioc->pdev->dev, 1853c9566231SKashyap Desai size, &segments[i].segment_dma, GFP_KERNEL); 1854c9566231SKashyap Desai if (!segments[i].segment) 1855c9566231SKashyap Desai return -ENOMEM; 1856c9566231SKashyap Desai if (mrioc->enable_segqueue) 1857c9566231SKashyap Desai q_segment_list_entry[i] = 1858c9566231SKashyap Desai (unsigned long)segments[i].segment_dma; 1859c9566231SKashyap Desai } 1860c9566231SKashyap Desai 1861c9566231SKashyap Desai return 0; 1862c9566231SKashyap Desai } 1863c9566231SKashyap Desai 1864c9566231SKashyap Desai /** 1865c9566231SKashyap Desai * mpi3mr_create_op_reply_q - create operational reply queue 1866c9566231SKashyap Desai * @mrioc: Adapter instance reference 1867c9566231SKashyap Desai * @qidx: operational reply queue index 1868c9566231SKashyap Desai * 1869c9566231SKashyap Desai * Create operatinal reply queue by issuing MPI request 1870c9566231SKashyap Desai * through admin queue. 1871c9566231SKashyap Desai * 1872c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1873c9566231SKashyap Desai */ 1874c9566231SKashyap Desai static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) 1875c9566231SKashyap Desai { 1876c9566231SKashyap Desai struct mpi3_create_reply_queue_request create_req; 1877c9566231SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 1878c9566231SKashyap Desai int retval = 0; 1879c9566231SKashyap Desai u16 reply_qid = 0, midx; 1880c9566231SKashyap Desai 1881c9566231SKashyap Desai reply_qid = op_reply_q->qid; 1882c9566231SKashyap Desai 1883c9566231SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset); 1884c9566231SKashyap Desai 1885c9566231SKashyap Desai if (reply_qid) { 1886c9566231SKashyap Desai retval = -1; 1887c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: called for duplicate qid %d\n", 1888c9566231SKashyap Desai reply_qid); 1889c9566231SKashyap Desai 1890c9566231SKashyap Desai return retval; 1891c9566231SKashyap Desai } 1892c9566231SKashyap Desai 1893c9566231SKashyap Desai reply_qid = qidx + 1; 1894c9566231SKashyap Desai op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; 1895c9260ff2SSumit Saxena if ((mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) && 1896c9260ff2SSumit Saxena !mrioc->pdev->revision) 1897243bcc8eSSreekanth Reddy op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K; 1898c9566231SKashyap Desai op_reply_q->ci = 0; 1899c9566231SKashyap Desai op_reply_q->ephase = 1; 1900463429f8SKashyap Desai atomic_set(&op_reply_q->pend_ios, 0); 1901463429f8SKashyap Desai atomic_set(&op_reply_q->in_use, 0); 1902463429f8SKashyap Desai op_reply_q->enable_irq_poll = false; 1903c9566231SKashyap Desai 1904c9566231SKashyap Desai if (!op_reply_q->q_segments) { 1905c9566231SKashyap Desai retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx); 1906c9566231SKashyap Desai if (retval) { 1907c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, qidx); 1908c9566231SKashyap Desai goto out; 1909c9566231SKashyap Desai } 1910c9566231SKashyap Desai } 1911c9566231SKashyap Desai 1912c9566231SKashyap Desai memset(&create_req, 0, sizeof(create_req)); 1913c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1914c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1915c9566231SKashyap Desai retval = -1; 1916c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: Init command is in use\n"); 1917f9dc034dSYang Yingliang goto out_unlock; 1918c9566231SKashyap Desai } 1919c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1920c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1921c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 1922c9566231SKashyap Desai create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1923c9566231SKashyap Desai create_req.function = MPI3_FUNCTION_CREATE_REPLY_QUEUE; 1924c9566231SKashyap Desai create_req.queue_id = cpu_to_le16(reply_qid); 1925afd3a579SSreekanth Reddy 1926afd3a579SSreekanth Reddy if (midx < (mrioc->intr_info_count - mrioc->requested_poll_qcount)) 1927afd3a579SSreekanth Reddy op_reply_q->qtype = MPI3MR_DEFAULT_QUEUE; 1928afd3a579SSreekanth Reddy else 1929afd3a579SSreekanth Reddy op_reply_q->qtype = MPI3MR_POLL_QUEUE; 1930afd3a579SSreekanth Reddy 1931afd3a579SSreekanth Reddy if (op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) { 1932afd3a579SSreekanth Reddy create_req.flags = 1933afd3a579SSreekanth Reddy MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE; 1934afd3a579SSreekanth Reddy create_req.msix_index = 1935afd3a579SSreekanth Reddy cpu_to_le16(mrioc->intr_info[midx].msix_index); 1936afd3a579SSreekanth Reddy } else { 1937afd3a579SSreekanth Reddy create_req.msix_index = cpu_to_le16(mrioc->intr_info_count - 1); 1938afd3a579SSreekanth Reddy ioc_info(mrioc, "create reply queue(polled): for qid(%d), midx(%d)\n", 1939afd3a579SSreekanth Reddy reply_qid, midx); 1940afd3a579SSreekanth Reddy if (!mrioc->active_poll_qcount) 1941afd3a579SSreekanth Reddy disable_irq_nosync(pci_irq_vector(mrioc->pdev, 1942afd3a579SSreekanth Reddy mrioc->intr_info_count - 1)); 1943afd3a579SSreekanth Reddy } 1944afd3a579SSreekanth Reddy 1945c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1946c9566231SKashyap Desai create_req.flags |= 1947c9566231SKashyap Desai MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED; 1948c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1949c9566231SKashyap Desai op_reply_q->q_segment_list_dma); 1950c9566231SKashyap Desai } else 1951c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1952c9566231SKashyap Desai op_reply_q->q_segments[0].segment_dma); 1953c9566231SKashyap Desai 1954c9566231SKashyap Desai create_req.size = cpu_to_le16(op_reply_q->num_replies); 1955c9566231SKashyap Desai 1956c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 1957c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &create_req, 1958c9566231SKashyap Desai sizeof(create_req), 1); 1959c9566231SKashyap Desai if (retval) { 1960c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: Admin Post failed\n"); 1961c9566231SKashyap Desai goto out_unlock; 1962c9566231SKashyap Desai } 1963c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1964c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1965c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1966a6856cc4SSreekanth Reddy ioc_err(mrioc, "create reply queue timed out\n"); 1967a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 1968c9566231SKashyap Desai MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT); 1969c9566231SKashyap Desai retval = -1; 1970c9566231SKashyap Desai goto out_unlock; 1971c9566231SKashyap Desai } 1972c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1973c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1974c9566231SKashyap Desai ioc_err(mrioc, 1975c9566231SKashyap Desai "CreateRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1976c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1977c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 1978c9566231SKashyap Desai retval = -1; 1979c9566231SKashyap Desai goto out_unlock; 1980c9566231SKashyap Desai } 1981c9566231SKashyap Desai op_reply_q->qid = reply_qid; 1982fe6db615SSreekanth Reddy if (midx < mrioc->intr_info_count) 1983c9566231SKashyap Desai mrioc->intr_info[midx].op_reply_q = op_reply_q; 1984c9566231SKashyap Desai 1985afd3a579SSreekanth Reddy (op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) ? mrioc->default_qcount++ : 1986afd3a579SSreekanth Reddy mrioc->active_poll_qcount++; 1987afd3a579SSreekanth Reddy 1988c9566231SKashyap Desai out_unlock: 1989c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 1990c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1991c9566231SKashyap Desai out: 1992c9566231SKashyap Desai 1993c9566231SKashyap Desai return retval; 1994c9566231SKashyap Desai } 1995c9566231SKashyap Desai 1996c9566231SKashyap Desai /** 1997c9566231SKashyap Desai * mpi3mr_create_op_req_q - create operational request queue 1998c9566231SKashyap Desai * @mrioc: Adapter instance reference 1999c9566231SKashyap Desai * @idx: operational request queue index 2000c9566231SKashyap Desai * @reply_qid: Reply queue ID 2001c9566231SKashyap Desai * 2002c9566231SKashyap Desai * Create operatinal request queue by issuing MPI request 2003c9566231SKashyap Desai * through admin queue. 2004c9566231SKashyap Desai * 2005c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 2006c9566231SKashyap Desai */ 2007c9566231SKashyap Desai static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx, 2008c9566231SKashyap Desai u16 reply_qid) 2009c9566231SKashyap Desai { 2010c9566231SKashyap Desai struct mpi3_create_request_queue_request create_req; 2011c9566231SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + idx; 2012c9566231SKashyap Desai int retval = 0; 2013c9566231SKashyap Desai u16 req_qid = 0; 2014c9566231SKashyap Desai 2015c9566231SKashyap Desai req_qid = op_req_q->qid; 2016c9566231SKashyap Desai 2017c9566231SKashyap Desai if (req_qid) { 2018c9566231SKashyap Desai retval = -1; 2019c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: called for duplicate qid %d\n", 2020c9566231SKashyap Desai req_qid); 2021c9566231SKashyap Desai 2022c9566231SKashyap Desai return retval; 2023c9566231SKashyap Desai } 2024c9566231SKashyap Desai req_qid = idx + 1; 2025c9566231SKashyap Desai 2026c9566231SKashyap Desai op_req_q->num_requests = MPI3MR_OP_REQ_Q_QD; 2027c9566231SKashyap Desai op_req_q->ci = 0; 2028c9566231SKashyap Desai op_req_q->pi = 0; 2029c9566231SKashyap Desai op_req_q->reply_qid = reply_qid; 2030c9566231SKashyap Desai spin_lock_init(&op_req_q->q_lock); 2031c9566231SKashyap Desai 2032c9566231SKashyap Desai if (!op_req_q->q_segments) { 2033c9566231SKashyap Desai retval = mpi3mr_alloc_op_req_q_segments(mrioc, idx); 2034c9566231SKashyap Desai if (retval) { 2035c9566231SKashyap Desai mpi3mr_free_op_req_q_segments(mrioc, idx); 2036c9566231SKashyap Desai goto out; 2037c9566231SKashyap Desai } 2038c9566231SKashyap Desai } 2039c9566231SKashyap Desai 2040c9566231SKashyap Desai memset(&create_req, 0, sizeof(create_req)); 2041c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 2042c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 2043c9566231SKashyap Desai retval = -1; 2044c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: Init command is in use\n"); 2045f9dc034dSYang Yingliang goto out_unlock; 2046c9566231SKashyap Desai } 2047c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 2048c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 2049c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 2050c9566231SKashyap Desai create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 2051c9566231SKashyap Desai create_req.function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE; 2052c9566231SKashyap Desai create_req.queue_id = cpu_to_le16(req_qid); 2053c9566231SKashyap Desai if (mrioc->enable_segqueue) { 2054c9566231SKashyap Desai create_req.flags = 2055c9566231SKashyap Desai MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED; 2056c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 2057c9566231SKashyap Desai op_req_q->q_segment_list_dma); 2058c9566231SKashyap Desai } else 2059c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 2060c9566231SKashyap Desai op_req_q->q_segments[0].segment_dma); 2061c9566231SKashyap Desai create_req.reply_queue_id = cpu_to_le16(reply_qid); 2062c9566231SKashyap Desai create_req.size = cpu_to_le16(op_req_q->num_requests); 2063c9566231SKashyap Desai 2064c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 2065c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &create_req, 2066c9566231SKashyap Desai sizeof(create_req), 1); 2067c9566231SKashyap Desai if (retval) { 2068c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: Admin Post failed\n"); 2069c9566231SKashyap Desai goto out_unlock; 2070c9566231SKashyap Desai } 2071c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 2072c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 2073c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 2074a6856cc4SSreekanth Reddy ioc_err(mrioc, "create request queue timed out\n"); 2075a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 2076a6856cc4SSreekanth Reddy MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT); 2077c9566231SKashyap Desai retval = -1; 2078c9566231SKashyap Desai goto out_unlock; 2079c9566231SKashyap Desai } 2080c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 2081c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 2082c9566231SKashyap Desai ioc_err(mrioc, 2083c9566231SKashyap Desai "CreateReqQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 2084c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 2085c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 2086c9566231SKashyap Desai retval = -1; 2087c9566231SKashyap Desai goto out_unlock; 2088c9566231SKashyap Desai } 2089c9566231SKashyap Desai op_req_q->qid = req_qid; 2090c9566231SKashyap Desai 2091c9566231SKashyap Desai out_unlock: 2092c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 2093c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2094c9566231SKashyap Desai out: 2095c9566231SKashyap Desai 2096c9566231SKashyap Desai return retval; 2097c9566231SKashyap Desai } 2098c9566231SKashyap Desai 2099c9566231SKashyap Desai /** 2100c9566231SKashyap Desai * mpi3mr_create_op_queues - create operational queue pairs 2101c9566231SKashyap Desai * @mrioc: Adapter instance reference 2102c9566231SKashyap Desai * 2103c9566231SKashyap Desai * Allocate memory for operational queue meta data and call 2104c9566231SKashyap Desai * create request and reply queue functions. 2105c9566231SKashyap Desai * 2106c9566231SKashyap Desai * Return: 0 on success, non-zero on failures. 2107c9566231SKashyap Desai */ 2108c9566231SKashyap Desai static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc) 2109c9566231SKashyap Desai { 2110c9566231SKashyap Desai int retval = 0; 2111c9566231SKashyap Desai u16 num_queues = 0, i = 0, msix_count_op_q = 1; 2112c9566231SKashyap Desai 2113c9566231SKashyap Desai num_queues = min_t(int, mrioc->facts.max_op_reply_q, 2114c9566231SKashyap Desai mrioc->facts.max_op_req_q); 2115c9566231SKashyap Desai 2116c9566231SKashyap Desai msix_count_op_q = 2117c9566231SKashyap Desai mrioc->intr_info_count - mrioc->op_reply_q_offset; 2118c9566231SKashyap Desai if (!mrioc->num_queues) 2119c9566231SKashyap Desai mrioc->num_queues = min_t(int, num_queues, msix_count_op_q); 2120c5758fc7SSreekanth Reddy /* 2121c5758fc7SSreekanth Reddy * During reset set the num_queues to the number of queues 2122c5758fc7SSreekanth Reddy * that was set before the reset. 2123c5758fc7SSreekanth Reddy */ 2124c5758fc7SSreekanth Reddy num_queues = mrioc->num_op_reply_q ? 2125c5758fc7SSreekanth Reddy mrioc->num_op_reply_q : mrioc->num_queues; 2126c5758fc7SSreekanth Reddy ioc_info(mrioc, "trying to create %d operational queue pairs\n", 2127c9566231SKashyap Desai num_queues); 2128c9566231SKashyap Desai 2129c9566231SKashyap Desai if (!mrioc->req_qinfo) { 2130c9566231SKashyap Desai mrioc->req_qinfo = kcalloc(num_queues, 2131c9566231SKashyap Desai sizeof(struct op_req_qinfo), GFP_KERNEL); 2132c9566231SKashyap Desai if (!mrioc->req_qinfo) { 2133c9566231SKashyap Desai retval = -1; 2134c9566231SKashyap Desai goto out_failed; 2135c9566231SKashyap Desai } 2136c9566231SKashyap Desai 2137c9566231SKashyap Desai mrioc->op_reply_qinfo = kzalloc(sizeof(struct op_reply_qinfo) * 2138c9566231SKashyap Desai num_queues, GFP_KERNEL); 2139c9566231SKashyap Desai if (!mrioc->op_reply_qinfo) { 2140c9566231SKashyap Desai retval = -1; 2141c9566231SKashyap Desai goto out_failed; 2142c9566231SKashyap Desai } 2143c9566231SKashyap Desai } 2144c9566231SKashyap Desai 2145c9566231SKashyap Desai if (mrioc->enable_segqueue) 2146c9566231SKashyap Desai ioc_info(mrioc, 2147c9566231SKashyap Desai "allocating operational queues through segmented queues\n"); 2148c9566231SKashyap Desai 2149c9566231SKashyap Desai for (i = 0; i < num_queues; i++) { 2150c9566231SKashyap Desai if (mpi3mr_create_op_reply_q(mrioc, i)) { 2151c9566231SKashyap Desai ioc_err(mrioc, "Cannot create OP RepQ %d\n", i); 2152c9566231SKashyap Desai break; 2153c9566231SKashyap Desai } 2154c9566231SKashyap Desai if (mpi3mr_create_op_req_q(mrioc, i, 2155c9566231SKashyap Desai mrioc->op_reply_qinfo[i].qid)) { 2156c9566231SKashyap Desai ioc_err(mrioc, "Cannot create OP ReqQ %d\n", i); 2157c9566231SKashyap Desai mpi3mr_delete_op_reply_q(mrioc, i); 2158c9566231SKashyap Desai break; 2159c9566231SKashyap Desai } 2160c9566231SKashyap Desai } 2161c9566231SKashyap Desai 2162c9566231SKashyap Desai if (i == 0) { 2163c9566231SKashyap Desai /* Not even one queue is created successfully*/ 2164c9566231SKashyap Desai retval = -1; 2165c9566231SKashyap Desai goto out_failed; 2166c9566231SKashyap Desai } 2167c9566231SKashyap Desai mrioc->num_op_reply_q = mrioc->num_op_req_q = i; 2168afd3a579SSreekanth Reddy ioc_info(mrioc, 2169afd3a579SSreekanth Reddy "successfully created %d operational queue pairs(default/polled) queue = (%d/%d)\n", 2170afd3a579SSreekanth Reddy mrioc->num_op_reply_q, mrioc->default_qcount, 2171afd3a579SSreekanth Reddy mrioc->active_poll_qcount); 2172c9566231SKashyap Desai 2173c9566231SKashyap Desai return retval; 2174c9566231SKashyap Desai out_failed: 2175c9566231SKashyap Desai kfree(mrioc->req_qinfo); 2176c9566231SKashyap Desai mrioc->req_qinfo = NULL; 2177c9566231SKashyap Desai 2178c9566231SKashyap Desai kfree(mrioc->op_reply_qinfo); 2179c9566231SKashyap Desai mrioc->op_reply_qinfo = NULL; 2180c9566231SKashyap Desai 2181c9566231SKashyap Desai return retval; 2182c9566231SKashyap Desai } 2183c9566231SKashyap Desai 2184c9566231SKashyap Desai /** 2185023ab2a9SKashyap Desai * mpi3mr_op_request_post - Post request to operational queue 2186023ab2a9SKashyap Desai * @mrioc: Adapter reference 2187023ab2a9SKashyap Desai * @op_req_q: Operational request queue info 2188023ab2a9SKashyap Desai * @req: MPI3 request 2189023ab2a9SKashyap Desai * 2190023ab2a9SKashyap Desai * Post the MPI3 request into operational request queue and 2191023ab2a9SKashyap Desai * inform the controller, if the queue is full return 2192023ab2a9SKashyap Desai * appropriate error. 2193023ab2a9SKashyap Desai * 2194023ab2a9SKashyap Desai * Return: 0 on success, non-zero on failure. 2195023ab2a9SKashyap Desai */ 2196023ab2a9SKashyap Desai int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc, 2197023ab2a9SKashyap Desai struct op_req_qinfo *op_req_q, u8 *req) 2198023ab2a9SKashyap Desai { 2199023ab2a9SKashyap Desai u16 pi = 0, max_entries, reply_qidx = 0, midx; 2200023ab2a9SKashyap Desai int retval = 0; 2201023ab2a9SKashyap Desai unsigned long flags; 2202023ab2a9SKashyap Desai u8 *req_entry; 2203023ab2a9SKashyap Desai void *segment_base_addr; 2204023ab2a9SKashyap Desai u16 req_sz = mrioc->facts.op_req_sz; 2205023ab2a9SKashyap Desai struct segments *segments = op_req_q->q_segments; 2206023ab2a9SKashyap Desai 2207023ab2a9SKashyap Desai reply_qidx = op_req_q->reply_qid - 1; 2208023ab2a9SKashyap Desai 2209023ab2a9SKashyap Desai if (mrioc->unrecoverable) 2210023ab2a9SKashyap Desai return -EFAULT; 2211023ab2a9SKashyap Desai 2212023ab2a9SKashyap Desai spin_lock_irqsave(&op_req_q->q_lock, flags); 2213023ab2a9SKashyap Desai pi = op_req_q->pi; 2214023ab2a9SKashyap Desai max_entries = op_req_q->num_requests; 2215023ab2a9SKashyap Desai 2216023ab2a9SKashyap Desai if (mpi3mr_check_req_qfull(op_req_q)) { 2217023ab2a9SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX( 2218023ab2a9SKashyap Desai reply_qidx, mrioc->op_reply_q_offset); 2219afd3a579SSreekanth Reddy mpi3mr_process_op_reply_q(mrioc, mrioc->intr_info[midx].op_reply_q); 2220023ab2a9SKashyap Desai 2221023ab2a9SKashyap Desai if (mpi3mr_check_req_qfull(op_req_q)) { 2222023ab2a9SKashyap Desai retval = -EAGAIN; 2223023ab2a9SKashyap Desai goto out; 2224023ab2a9SKashyap Desai } 2225023ab2a9SKashyap Desai } 2226023ab2a9SKashyap Desai 2227023ab2a9SKashyap Desai if (mrioc->reset_in_progress) { 2228023ab2a9SKashyap Desai ioc_err(mrioc, "OpReqQ submit reset in progress\n"); 2229023ab2a9SKashyap Desai retval = -EAGAIN; 2230023ab2a9SKashyap Desai goto out; 2231023ab2a9SKashyap Desai } 2232023ab2a9SKashyap Desai 2233023ab2a9SKashyap Desai segment_base_addr = segments[pi / op_req_q->segment_qd].segment; 2234023ab2a9SKashyap Desai req_entry = (u8 *)segment_base_addr + 2235023ab2a9SKashyap Desai ((pi % op_req_q->segment_qd) * req_sz); 2236023ab2a9SKashyap Desai 2237023ab2a9SKashyap Desai memset(req_entry, 0, req_sz); 2238023ab2a9SKashyap Desai memcpy(req_entry, req, MPI3MR_ADMIN_REQ_FRAME_SZ); 2239023ab2a9SKashyap Desai 2240023ab2a9SKashyap Desai if (++pi == max_entries) 2241023ab2a9SKashyap Desai pi = 0; 2242023ab2a9SKashyap Desai op_req_q->pi = pi; 2243023ab2a9SKashyap Desai 22447f9f953dSSreekanth Reddy #ifndef CONFIG_PREEMPT_RT 2245463429f8SKashyap Desai if (atomic_inc_return(&mrioc->op_reply_qinfo[reply_qidx].pend_ios) 2246463429f8SKashyap Desai > MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT) 2247463429f8SKashyap Desai mrioc->op_reply_qinfo[reply_qidx].enable_irq_poll = true; 22487f9f953dSSreekanth Reddy #else 22497f9f953dSSreekanth Reddy atomic_inc_return(&mrioc->op_reply_qinfo[reply_qidx].pend_ios); 22507f9f953dSSreekanth Reddy #endif 2251463429f8SKashyap Desai 2252023ab2a9SKashyap Desai writel(op_req_q->pi, 2253023ab2a9SKashyap Desai &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].producer_index); 2254023ab2a9SKashyap Desai 2255023ab2a9SKashyap Desai out: 2256023ab2a9SKashyap Desai spin_unlock_irqrestore(&op_req_q->q_lock, flags); 2257023ab2a9SKashyap Desai return retval; 2258023ab2a9SKashyap Desai } 2259023ab2a9SKashyap Desai 2260023ab2a9SKashyap Desai /** 2261a6856cc4SSreekanth Reddy * mpi3mr_check_rh_fault_ioc - check reset history and fault 2262a6856cc4SSreekanth Reddy * controller 2263a6856cc4SSreekanth Reddy * @mrioc: Adapter instance reference 22643bb3c24eSYang Li * @reason_code: reason code for the fault. 2265a6856cc4SSreekanth Reddy * 2266a6856cc4SSreekanth Reddy * This routine will save snapdump and fault the controller with 2267a6856cc4SSreekanth Reddy * the given reason code if it is not already in the fault or 2268a6856cc4SSreekanth Reddy * not asynchronosuly reset. This will be used to handle 2269a6856cc4SSreekanth Reddy * initilaization time faults/resets/timeout as in those cases 2270a6856cc4SSreekanth Reddy * immediate soft reset invocation is not required. 2271a6856cc4SSreekanth Reddy * 2272a6856cc4SSreekanth Reddy * Return: None. 2273a6856cc4SSreekanth Reddy */ 2274a6856cc4SSreekanth Reddy void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code) 2275a6856cc4SSreekanth Reddy { 2276a6856cc4SSreekanth Reddy u32 ioc_status, host_diagnostic, timeout; 2277a6856cc4SSreekanth Reddy 2278f2a79d20SSreekanth Reddy if (mrioc->unrecoverable) { 2279f2a79d20SSreekanth Reddy ioc_err(mrioc, "controller is unrecoverable\n"); 2280f2a79d20SSreekanth Reddy return; 2281f2a79d20SSreekanth Reddy } 2282f2a79d20SSreekanth Reddy 2283f2a79d20SSreekanth Reddy if (!pci_device_is_present(mrioc->pdev)) { 2284f2a79d20SSreekanth Reddy mrioc->unrecoverable = 1; 2285f2a79d20SSreekanth Reddy ioc_err(mrioc, "controller is not present\n"); 2286f2a79d20SSreekanth Reddy return; 2287f2a79d20SSreekanth Reddy } 2288f2a79d20SSreekanth Reddy 2289a6856cc4SSreekanth Reddy ioc_status = readl(&mrioc->sysif_regs->ioc_status); 2290a6856cc4SSreekanth Reddy if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) || 2291a6856cc4SSreekanth Reddy (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) { 2292a6856cc4SSreekanth Reddy mpi3mr_print_fault_info(mrioc); 2293a6856cc4SSreekanth Reddy return; 2294a6856cc4SSreekanth Reddy } 2295a6856cc4SSreekanth Reddy mpi3mr_set_diagsave(mrioc); 2296a6856cc4SSreekanth Reddy mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 2297a6856cc4SSreekanth Reddy reason_code); 2298a6856cc4SSreekanth Reddy timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; 2299a6856cc4SSreekanth Reddy do { 2300a6856cc4SSreekanth Reddy host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); 2301a6856cc4SSreekanth Reddy if (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS)) 2302a6856cc4SSreekanth Reddy break; 2303a6856cc4SSreekanth Reddy msleep(100); 2304a6856cc4SSreekanth Reddy } while (--timeout); 2305a6856cc4SSreekanth Reddy } 2306a6856cc4SSreekanth Reddy 2307a6856cc4SSreekanth Reddy /** 230854dfcffbSKashyap Desai * mpi3mr_sync_timestamp - Issue time stamp sync request 230954dfcffbSKashyap Desai * @mrioc: Adapter reference 231054dfcffbSKashyap Desai * 231154dfcffbSKashyap Desai * Issue IO unit control MPI request to synchornize firmware 231254dfcffbSKashyap Desai * timestamp with host time. 231354dfcffbSKashyap Desai * 231454dfcffbSKashyap Desai * Return: 0 on success, non-zero on failure. 231554dfcffbSKashyap Desai */ 231654dfcffbSKashyap Desai static int mpi3mr_sync_timestamp(struct mpi3mr_ioc *mrioc) 231754dfcffbSKashyap Desai { 231854dfcffbSKashyap Desai ktime_t current_time; 231954dfcffbSKashyap Desai struct mpi3_iounit_control_request iou_ctrl; 232054dfcffbSKashyap Desai int retval = 0; 232154dfcffbSKashyap Desai 232254dfcffbSKashyap Desai memset(&iou_ctrl, 0, sizeof(iou_ctrl)); 232354dfcffbSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 232454dfcffbSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 232554dfcffbSKashyap Desai retval = -1; 232654dfcffbSKashyap Desai ioc_err(mrioc, "Issue IOUCTL time_stamp: command is in use\n"); 232754dfcffbSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 232854dfcffbSKashyap Desai goto out; 232954dfcffbSKashyap Desai } 233054dfcffbSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 233154dfcffbSKashyap Desai mrioc->init_cmds.is_waiting = 1; 233254dfcffbSKashyap Desai mrioc->init_cmds.callback = NULL; 233354dfcffbSKashyap Desai iou_ctrl.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 233454dfcffbSKashyap Desai iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL; 233554dfcffbSKashyap Desai iou_ctrl.operation = MPI3_CTRL_OP_UPDATE_TIMESTAMP; 233654dfcffbSKashyap Desai current_time = ktime_get_real(); 233754dfcffbSKashyap Desai iou_ctrl.param64[0] = cpu_to_le64(ktime_to_ms(current_time)); 233854dfcffbSKashyap Desai 233954dfcffbSKashyap Desai init_completion(&mrioc->init_cmds.done); 234054dfcffbSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl, 234154dfcffbSKashyap Desai sizeof(iou_ctrl), 0); 234254dfcffbSKashyap Desai if (retval) { 234354dfcffbSKashyap Desai ioc_err(mrioc, "Issue IOUCTL time_stamp: Admin Post failed\n"); 234454dfcffbSKashyap Desai goto out_unlock; 234554dfcffbSKashyap Desai } 234654dfcffbSKashyap Desai 234754dfcffbSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 234854dfcffbSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 234954dfcffbSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 235054dfcffbSKashyap Desai ioc_err(mrioc, "Issue IOUCTL time_stamp: command timed out\n"); 235154dfcffbSKashyap Desai mrioc->init_cmds.is_waiting = 0; 2352fbaa9aa4SSreekanth Reddy if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET)) 23539134211fSRanjan Kumar mpi3mr_check_rh_fault_ioc(mrioc, 23549134211fSRanjan Kumar MPI3MR_RESET_FROM_TSU_TIMEOUT); 235554dfcffbSKashyap Desai retval = -1; 235654dfcffbSKashyap Desai goto out_unlock; 235754dfcffbSKashyap Desai } 235854dfcffbSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 235954dfcffbSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 236054dfcffbSKashyap Desai ioc_err(mrioc, 236154dfcffbSKashyap Desai "Issue IOUCTL time_stamp: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 236254dfcffbSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 236354dfcffbSKashyap Desai mrioc->init_cmds.ioc_loginfo); 236454dfcffbSKashyap Desai retval = -1; 236554dfcffbSKashyap Desai goto out_unlock; 236654dfcffbSKashyap Desai } 236754dfcffbSKashyap Desai 236854dfcffbSKashyap Desai out_unlock: 236954dfcffbSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 237054dfcffbSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 237154dfcffbSKashyap Desai 237254dfcffbSKashyap Desai out: 237354dfcffbSKashyap Desai return retval; 237454dfcffbSKashyap Desai } 237554dfcffbSKashyap Desai 237654dfcffbSKashyap Desai /** 23772ac794baSSreekanth Reddy * mpi3mr_print_pkg_ver - display controller fw package version 23782ac794baSSreekanth Reddy * @mrioc: Adapter reference 23792ac794baSSreekanth Reddy * 23802ac794baSSreekanth Reddy * Retrieve firmware package version from the component image 23812ac794baSSreekanth Reddy * header of the controller flash and display it. 23822ac794baSSreekanth Reddy * 23832ac794baSSreekanth Reddy * Return: 0 on success and non-zero on failure. 23842ac794baSSreekanth Reddy */ 23852ac794baSSreekanth Reddy static int mpi3mr_print_pkg_ver(struct mpi3mr_ioc *mrioc) 23862ac794baSSreekanth Reddy { 23872ac794baSSreekanth Reddy struct mpi3_ci_upload_request ci_upload; 23882ac794baSSreekanth Reddy int retval = -1; 23892ac794baSSreekanth Reddy void *data = NULL; 23902ac794baSSreekanth Reddy dma_addr_t data_dma; 23912ac794baSSreekanth Reddy struct mpi3_ci_manifest_mpi *manifest; 23922ac794baSSreekanth Reddy u32 data_len = sizeof(struct mpi3_ci_manifest_mpi); 23932ac794baSSreekanth Reddy u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 23942ac794baSSreekanth Reddy 23952ac794baSSreekanth Reddy data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, 23962ac794baSSreekanth Reddy GFP_KERNEL); 23972ac794baSSreekanth Reddy if (!data) 23982ac794baSSreekanth Reddy return -ENOMEM; 23992ac794baSSreekanth Reddy 24002ac794baSSreekanth Reddy memset(&ci_upload, 0, sizeof(ci_upload)); 24012ac794baSSreekanth Reddy mutex_lock(&mrioc->init_cmds.mutex); 24022ac794baSSreekanth Reddy if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 24032ac794baSSreekanth Reddy ioc_err(mrioc, "sending get package version failed due to command in use\n"); 24042ac794baSSreekanth Reddy mutex_unlock(&mrioc->init_cmds.mutex); 24052ac794baSSreekanth Reddy goto out; 24062ac794baSSreekanth Reddy } 24072ac794baSSreekanth Reddy mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 24082ac794baSSreekanth Reddy mrioc->init_cmds.is_waiting = 1; 24092ac794baSSreekanth Reddy mrioc->init_cmds.callback = NULL; 24102ac794baSSreekanth Reddy ci_upload.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 24112ac794baSSreekanth Reddy ci_upload.function = MPI3_FUNCTION_CI_UPLOAD; 24122ac794baSSreekanth Reddy ci_upload.msg_flags = MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY; 24132ac794baSSreekanth Reddy ci_upload.signature1 = cpu_to_le32(MPI3_IMAGE_HEADER_SIGNATURE1_MANIFEST); 24142ac794baSSreekanth Reddy ci_upload.image_offset = cpu_to_le32(MPI3_IMAGE_HEADER_SIZE); 24152ac794baSSreekanth Reddy ci_upload.segment_size = cpu_to_le32(data_len); 24162ac794baSSreekanth Reddy 24172ac794baSSreekanth Reddy mpi3mr_add_sg_single(&ci_upload.sgl, sgl_flags, data_len, 24182ac794baSSreekanth Reddy data_dma); 24192ac794baSSreekanth Reddy init_completion(&mrioc->init_cmds.done); 24202ac794baSSreekanth Reddy retval = mpi3mr_admin_request_post(mrioc, &ci_upload, 24212ac794baSSreekanth Reddy sizeof(ci_upload), 1); 24222ac794baSSreekanth Reddy if (retval) { 24232ac794baSSreekanth Reddy ioc_err(mrioc, "posting get package version failed\n"); 24242ac794baSSreekanth Reddy goto out_unlock; 24252ac794baSSreekanth Reddy } 24262ac794baSSreekanth Reddy wait_for_completion_timeout(&mrioc->init_cmds.done, 24272ac794baSSreekanth Reddy (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 24282ac794baSSreekanth Reddy if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 24292ac794baSSreekanth Reddy ioc_err(mrioc, "get package version timed out\n"); 2430a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 2431a6856cc4SSreekanth Reddy MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT); 24322ac794baSSreekanth Reddy retval = -1; 24332ac794baSSreekanth Reddy goto out_unlock; 24342ac794baSSreekanth Reddy } 24352ac794baSSreekanth Reddy if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 24362ac794baSSreekanth Reddy == MPI3_IOCSTATUS_SUCCESS) { 24372ac794baSSreekanth Reddy manifest = (struct mpi3_ci_manifest_mpi *) data; 24382ac794baSSreekanth Reddy if (manifest->manifest_type == MPI3_CI_MANIFEST_TYPE_MPI) { 24392ac794baSSreekanth Reddy ioc_info(mrioc, 24402ac794baSSreekanth Reddy "firmware package version(%d.%d.%d.%d.%05d-%05d)\n", 24412ac794baSSreekanth Reddy manifest->package_version.gen_major, 24422ac794baSSreekanth Reddy manifest->package_version.gen_minor, 24432ac794baSSreekanth Reddy manifest->package_version.phase_major, 24442ac794baSSreekanth Reddy manifest->package_version.phase_minor, 24452ac794baSSreekanth Reddy manifest->package_version.customer_id, 24462ac794baSSreekanth Reddy manifest->package_version.build_num); 24472ac794baSSreekanth Reddy } 24482ac794baSSreekanth Reddy } 24492ac794baSSreekanth Reddy retval = 0; 24502ac794baSSreekanth Reddy out_unlock: 24512ac794baSSreekanth Reddy mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 24522ac794baSSreekanth Reddy mutex_unlock(&mrioc->init_cmds.mutex); 24532ac794baSSreekanth Reddy 24542ac794baSSreekanth Reddy out: 24552ac794baSSreekanth Reddy if (data) 24562ac794baSSreekanth Reddy dma_free_coherent(&mrioc->pdev->dev, data_len, data, 24572ac794baSSreekanth Reddy data_dma); 24582ac794baSSreekanth Reddy return retval; 24592ac794baSSreekanth Reddy } 24602ac794baSSreekanth Reddy 24612ac794baSSreekanth Reddy /** 2462672ae26cSKashyap Desai * mpi3mr_watchdog_work - watchdog thread to monitor faults 2463672ae26cSKashyap Desai * @work: work struct 2464672ae26cSKashyap Desai * 2465672ae26cSKashyap Desai * Watch dog work periodically executed (1 second interval) to 2466672ae26cSKashyap Desai * monitor firmware fault and to issue periodic timer sync to 2467672ae26cSKashyap Desai * the firmware. 2468672ae26cSKashyap Desai * 2469672ae26cSKashyap Desai * Return: Nothing. 2470672ae26cSKashyap Desai */ 2471672ae26cSKashyap Desai static void mpi3mr_watchdog_work(struct work_struct *work) 2472672ae26cSKashyap Desai { 2473672ae26cSKashyap Desai struct mpi3mr_ioc *mrioc = 2474672ae26cSKashyap Desai container_of(work, struct mpi3mr_ioc, watchdog_work.work); 2475672ae26cSKashyap Desai unsigned long flags; 2476672ae26cSKashyap Desai enum mpi3mr_iocstate ioc_state; 247778b76a07SSreekanth Reddy u32 fault, host_diagnostic, ioc_status; 247878b76a07SSreekanth Reddy u32 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH; 2479672ae26cSKashyap Desai 2480f2a79d20SSreekanth Reddy if (mrioc->reset_in_progress) 2481b64845a7SSreekanth Reddy return; 2482b64845a7SSreekanth Reddy 2483f2a79d20SSreekanth Reddy if (!mrioc->unrecoverable && !pci_device_is_present(mrioc->pdev)) { 2484f2a79d20SSreekanth Reddy ioc_err(mrioc, "watchdog could not detect the controller\n"); 2485f2a79d20SSreekanth Reddy mrioc->unrecoverable = 1; 2486f2a79d20SSreekanth Reddy } 2487f2a79d20SSreekanth Reddy 2488f2a79d20SSreekanth Reddy if (mrioc->unrecoverable) { 2489f2a79d20SSreekanth Reddy ioc_err(mrioc, 2490f2a79d20SSreekanth Reddy "flush pending commands for unrecoverable controller\n"); 2491f2a79d20SSreekanth Reddy mpi3mr_flush_cmds_for_unrecovered_controller(mrioc); 2492f2a79d20SSreekanth Reddy return; 2493f2a79d20SSreekanth Reddy } 2494f2a79d20SSreekanth Reddy 249554dfcffbSKashyap Desai if (mrioc->ts_update_counter++ >= MPI3MR_TSUPDATE_INTERVAL) { 249654dfcffbSKashyap Desai mrioc->ts_update_counter = 0; 249754dfcffbSKashyap Desai mpi3mr_sync_timestamp(mrioc); 249854dfcffbSKashyap Desai } 249954dfcffbSKashyap Desai 250078b76a07SSreekanth Reddy if ((mrioc->prepare_for_reset) && 250178b76a07SSreekanth Reddy ((mrioc->prepare_for_reset_timeout_counter++) >= 250278b76a07SSreekanth Reddy MPI3MR_PREPARE_FOR_RESET_TIMEOUT)) { 250378b76a07SSreekanth Reddy mpi3mr_soft_reset_handler(mrioc, 250478b76a07SSreekanth Reddy MPI3MR_RESET_FROM_CIACTVRST_TIMER, 1); 250578b76a07SSreekanth Reddy return; 250678b76a07SSreekanth Reddy } 250778b76a07SSreekanth Reddy 250878b76a07SSreekanth Reddy ioc_status = readl(&mrioc->sysif_regs->ioc_status); 250978b76a07SSreekanth Reddy if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) { 251078b76a07SSreekanth Reddy mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_FIRMWARE, 0); 251178b76a07SSreekanth Reddy return; 251278b76a07SSreekanth Reddy } 251378b76a07SSreekanth Reddy 2514672ae26cSKashyap Desai /*Check for fault state every one second and issue Soft reset*/ 2515672ae26cSKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 251678b76a07SSreekanth Reddy if (ioc_state != MRIOC_STATE_FAULT) 251778b76a07SSreekanth Reddy goto schedule_work; 251878b76a07SSreekanth Reddy 251978b76a07SSreekanth Reddy fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK; 2520672ae26cSKashyap Desai host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); 2521672ae26cSKashyap Desai if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) { 2522672ae26cSKashyap Desai if (!mrioc->diagsave_timeout) { 2523672ae26cSKashyap Desai mpi3mr_print_fault_info(mrioc); 252478b76a07SSreekanth Reddy ioc_warn(mrioc, "diag save in progress\n"); 2525672ae26cSKashyap Desai } 252678b76a07SSreekanth Reddy if ((mrioc->diagsave_timeout++) <= MPI3_SYSIF_DIAG_SAVE_TIMEOUT) 2527672ae26cSKashyap Desai goto schedule_work; 252878b76a07SSreekanth Reddy } 252978b76a07SSreekanth Reddy 2530672ae26cSKashyap Desai mpi3mr_print_fault_info(mrioc); 2531672ae26cSKashyap Desai mrioc->diagsave_timeout = 0; 2532672ae26cSKashyap Desai 253378b76a07SSreekanth Reddy switch (fault) { 2534bad2f28dSSreekanth Reddy case MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED: 253578b76a07SSreekanth Reddy case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED: 2536bad2f28dSSreekanth Reddy ioc_warn(mrioc, 253778b76a07SSreekanth Reddy "controller requires system power cycle, marking controller as unrecoverable\n"); 2538672ae26cSKashyap Desai mrioc->unrecoverable = 1; 2539f2a79d20SSreekanth Reddy goto schedule_work; 254078b76a07SSreekanth Reddy case MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS: 2541a3d27dfdSRanjan Kumar goto schedule_work; 254278b76a07SSreekanth Reddy case MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET: 254378b76a07SSreekanth Reddy reset_reason = MPI3MR_RESET_FROM_CIACTIV_FAULT; 254478b76a07SSreekanth Reddy break; 254578b76a07SSreekanth Reddy default: 254678b76a07SSreekanth Reddy break; 2547672ae26cSKashyap Desai } 254878b76a07SSreekanth Reddy mpi3mr_soft_reset_handler(mrioc, reset_reason, 0); 254978b76a07SSreekanth Reddy return; 2550672ae26cSKashyap Desai 2551672ae26cSKashyap Desai schedule_work: 2552672ae26cSKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 2553672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 2554672ae26cSKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 2555672ae26cSKashyap Desai &mrioc->watchdog_work, 2556672ae26cSKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 2557672ae26cSKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 2558672ae26cSKashyap Desai return; 2559672ae26cSKashyap Desai } 2560672ae26cSKashyap Desai 2561672ae26cSKashyap Desai /** 2562672ae26cSKashyap Desai * mpi3mr_start_watchdog - Start watchdog 2563672ae26cSKashyap Desai * @mrioc: Adapter instance reference 2564672ae26cSKashyap Desai * 2565672ae26cSKashyap Desai * Create and start the watchdog thread to monitor controller 2566672ae26cSKashyap Desai * faults. 2567672ae26cSKashyap Desai * 2568672ae26cSKashyap Desai * Return: Nothing. 2569672ae26cSKashyap Desai */ 2570672ae26cSKashyap Desai void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc) 2571672ae26cSKashyap Desai { 2572672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 2573672ae26cSKashyap Desai return; 2574672ae26cSKashyap Desai 2575672ae26cSKashyap Desai INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work); 2576672ae26cSKashyap Desai snprintf(mrioc->watchdog_work_q_name, 2577672ae26cSKashyap Desai sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name, 2578672ae26cSKashyap Desai mrioc->id); 2579672ae26cSKashyap Desai mrioc->watchdog_work_q = 2580672ae26cSKashyap Desai create_singlethread_workqueue(mrioc->watchdog_work_q_name); 2581672ae26cSKashyap Desai if (!mrioc->watchdog_work_q) { 2582672ae26cSKashyap Desai ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__); 2583672ae26cSKashyap Desai return; 2584672ae26cSKashyap Desai } 2585672ae26cSKashyap Desai 2586672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 2587672ae26cSKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 2588672ae26cSKashyap Desai &mrioc->watchdog_work, 2589672ae26cSKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 2590672ae26cSKashyap Desai } 2591672ae26cSKashyap Desai 2592672ae26cSKashyap Desai /** 2593672ae26cSKashyap Desai * mpi3mr_stop_watchdog - Stop watchdog 2594672ae26cSKashyap Desai * @mrioc: Adapter instance reference 2595672ae26cSKashyap Desai * 2596672ae26cSKashyap Desai * Stop the watchdog thread created to monitor controller 2597672ae26cSKashyap Desai * faults. 2598672ae26cSKashyap Desai * 2599672ae26cSKashyap Desai * Return: Nothing. 2600672ae26cSKashyap Desai */ 2601672ae26cSKashyap Desai void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc) 2602672ae26cSKashyap Desai { 2603672ae26cSKashyap Desai unsigned long flags; 2604672ae26cSKashyap Desai struct workqueue_struct *wq; 2605672ae26cSKashyap Desai 2606672ae26cSKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 2607672ae26cSKashyap Desai wq = mrioc->watchdog_work_q; 2608672ae26cSKashyap Desai mrioc->watchdog_work_q = NULL; 2609672ae26cSKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 2610672ae26cSKashyap Desai if (wq) { 2611672ae26cSKashyap Desai if (!cancel_delayed_work_sync(&mrioc->watchdog_work)) 2612672ae26cSKashyap Desai flush_workqueue(wq); 2613672ae26cSKashyap Desai destroy_workqueue(wq); 2614672ae26cSKashyap Desai } 2615672ae26cSKashyap Desai } 2616672ae26cSKashyap Desai 2617672ae26cSKashyap Desai /** 2618824a1566SKashyap Desai * mpi3mr_setup_admin_qpair - Setup admin queue pair 2619824a1566SKashyap Desai * @mrioc: Adapter instance reference 2620824a1566SKashyap Desai * 2621824a1566SKashyap Desai * Allocate memory for admin queue pair if required and register 2622824a1566SKashyap Desai * the admin queue with the controller. 2623824a1566SKashyap Desai * 2624824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2625824a1566SKashyap Desai */ 2626824a1566SKashyap Desai static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc) 2627824a1566SKashyap Desai { 2628824a1566SKashyap Desai int retval = 0; 2629824a1566SKashyap Desai u32 num_admin_entries = 0; 2630824a1566SKashyap Desai 2631824a1566SKashyap Desai mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE; 2632824a1566SKashyap Desai mrioc->num_admin_req = mrioc->admin_req_q_sz / 2633824a1566SKashyap Desai MPI3MR_ADMIN_REQ_FRAME_SZ; 2634824a1566SKashyap Desai mrioc->admin_req_ci = mrioc->admin_req_pi = 0; 2635824a1566SKashyap Desai 2636824a1566SKashyap Desai mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE; 2637824a1566SKashyap Desai mrioc->num_admin_replies = mrioc->admin_reply_q_sz / 2638824a1566SKashyap Desai MPI3MR_ADMIN_REPLY_FRAME_SZ; 2639824a1566SKashyap Desai mrioc->admin_reply_ci = 0; 2640824a1566SKashyap Desai mrioc->admin_reply_ephase = 1; 264102ca7da2SRanjan Kumar atomic_set(&mrioc->admin_reply_q_in_use, 0); 2642824a1566SKashyap Desai 2643824a1566SKashyap Desai if (!mrioc->admin_req_base) { 2644824a1566SKashyap Desai mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev, 2645824a1566SKashyap Desai mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL); 2646824a1566SKashyap Desai 2647824a1566SKashyap Desai if (!mrioc->admin_req_base) { 2648824a1566SKashyap Desai retval = -1; 2649824a1566SKashyap Desai goto out_failed; 2650824a1566SKashyap Desai } 2651824a1566SKashyap Desai 2652824a1566SKashyap Desai mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev, 2653824a1566SKashyap Desai mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma, 2654824a1566SKashyap Desai GFP_KERNEL); 2655824a1566SKashyap Desai 2656824a1566SKashyap Desai if (!mrioc->admin_reply_base) { 2657824a1566SKashyap Desai retval = -1; 2658824a1566SKashyap Desai goto out_failed; 2659824a1566SKashyap Desai } 2660824a1566SKashyap Desai } 2661824a1566SKashyap Desai 2662824a1566SKashyap Desai num_admin_entries = (mrioc->num_admin_replies << 16) | 2663824a1566SKashyap Desai (mrioc->num_admin_req); 2664824a1566SKashyap Desai writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries); 2665824a1566SKashyap Desai mpi3mr_writeq(mrioc->admin_req_dma, 2666824a1566SKashyap Desai &mrioc->sysif_regs->admin_request_queue_address); 2667824a1566SKashyap Desai mpi3mr_writeq(mrioc->admin_reply_dma, 2668824a1566SKashyap Desai &mrioc->sysif_regs->admin_reply_queue_address); 2669824a1566SKashyap Desai writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi); 2670824a1566SKashyap Desai writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); 2671824a1566SKashyap Desai return retval; 2672824a1566SKashyap Desai 2673824a1566SKashyap Desai out_failed: 2674824a1566SKashyap Desai 2675824a1566SKashyap Desai if (mrioc->admin_reply_base) { 2676824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz, 2677824a1566SKashyap Desai mrioc->admin_reply_base, mrioc->admin_reply_dma); 2678824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 2679824a1566SKashyap Desai } 2680824a1566SKashyap Desai if (mrioc->admin_req_base) { 2681824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz, 2682824a1566SKashyap Desai mrioc->admin_req_base, mrioc->admin_req_dma); 2683824a1566SKashyap Desai mrioc->admin_req_base = NULL; 2684824a1566SKashyap Desai } 2685824a1566SKashyap Desai return retval; 2686824a1566SKashyap Desai } 2687824a1566SKashyap Desai 2688824a1566SKashyap Desai /** 2689824a1566SKashyap Desai * mpi3mr_issue_iocfacts - Send IOC Facts 2690824a1566SKashyap Desai * @mrioc: Adapter instance reference 2691824a1566SKashyap Desai * @facts_data: Cached IOC facts data 2692824a1566SKashyap Desai * 2693824a1566SKashyap Desai * Issue IOC Facts MPI request through admin queue and wait for 2694824a1566SKashyap Desai * the completion of it or time out. 2695824a1566SKashyap Desai * 2696824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2697824a1566SKashyap Desai */ 2698824a1566SKashyap Desai static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc, 2699824a1566SKashyap Desai struct mpi3_ioc_facts_data *facts_data) 2700824a1566SKashyap Desai { 2701824a1566SKashyap Desai struct mpi3_ioc_facts_request iocfacts_req; 2702824a1566SKashyap Desai void *data = NULL; 2703824a1566SKashyap Desai dma_addr_t data_dma; 2704824a1566SKashyap Desai u32 data_len = sizeof(*facts_data); 2705824a1566SKashyap Desai int retval = 0; 2706824a1566SKashyap Desai u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 2707824a1566SKashyap Desai 2708824a1566SKashyap Desai data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, 2709824a1566SKashyap Desai GFP_KERNEL); 2710824a1566SKashyap Desai 2711824a1566SKashyap Desai if (!data) { 2712824a1566SKashyap Desai retval = -1; 2713824a1566SKashyap Desai goto out; 2714824a1566SKashyap Desai } 2715824a1566SKashyap Desai 2716824a1566SKashyap Desai memset(&iocfacts_req, 0, sizeof(iocfacts_req)); 2717824a1566SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 2718824a1566SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 2719824a1566SKashyap Desai retval = -1; 2720824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n"); 2721824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2722824a1566SKashyap Desai goto out; 2723824a1566SKashyap Desai } 2724824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 2725824a1566SKashyap Desai mrioc->init_cmds.is_waiting = 1; 2726824a1566SKashyap Desai mrioc->init_cmds.callback = NULL; 2727824a1566SKashyap Desai iocfacts_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 2728824a1566SKashyap Desai iocfacts_req.function = MPI3_FUNCTION_IOC_FACTS; 2729824a1566SKashyap Desai 2730824a1566SKashyap Desai mpi3mr_add_sg_single(&iocfacts_req.sgl, sgl_flags, data_len, 2731824a1566SKashyap Desai data_dma); 2732824a1566SKashyap Desai 2733824a1566SKashyap Desai init_completion(&mrioc->init_cmds.done); 2734824a1566SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req, 2735824a1566SKashyap Desai sizeof(iocfacts_req), 1); 2736824a1566SKashyap Desai if (retval) { 2737824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n"); 2738824a1566SKashyap Desai goto out_unlock; 2739824a1566SKashyap Desai } 2740824a1566SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 2741824a1566SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 2742824a1566SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 2743a6856cc4SSreekanth Reddy ioc_err(mrioc, "ioc_facts timed out\n"); 2744a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 2745824a1566SKashyap Desai MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT); 2746824a1566SKashyap Desai retval = -1; 2747824a1566SKashyap Desai goto out_unlock; 2748824a1566SKashyap Desai } 2749824a1566SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 2750824a1566SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 2751824a1566SKashyap Desai ioc_err(mrioc, 2752824a1566SKashyap Desai "Issue IOCFacts: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 2753824a1566SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 2754824a1566SKashyap Desai mrioc->init_cmds.ioc_loginfo); 2755824a1566SKashyap Desai retval = -1; 2756824a1566SKashyap Desai goto out_unlock; 2757824a1566SKashyap Desai } 2758824a1566SKashyap Desai memcpy(facts_data, (u8 *)data, data_len); 2759c5758fc7SSreekanth Reddy mpi3mr_process_factsdata(mrioc, facts_data); 2760824a1566SKashyap Desai out_unlock: 2761824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 2762824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2763824a1566SKashyap Desai 2764824a1566SKashyap Desai out: 2765824a1566SKashyap Desai if (data) 2766824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma); 2767824a1566SKashyap Desai 2768824a1566SKashyap Desai return retval; 2769824a1566SKashyap Desai } 2770824a1566SKashyap Desai 2771824a1566SKashyap Desai /** 2772824a1566SKashyap Desai * mpi3mr_check_reset_dma_mask - Process IOC facts data 2773824a1566SKashyap Desai * @mrioc: Adapter instance reference 2774824a1566SKashyap Desai * 2775824a1566SKashyap Desai * Check whether the new DMA mask requested through IOCFacts by 2776824a1566SKashyap Desai * firmware needs to be set, if so set it . 2777824a1566SKashyap Desai * 2778824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 2779824a1566SKashyap Desai */ 2780824a1566SKashyap Desai static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc) 2781824a1566SKashyap Desai { 2782824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 2783824a1566SKashyap Desai int r; 2784824a1566SKashyap Desai u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask); 2785824a1566SKashyap Desai 2786824a1566SKashyap Desai if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask)) 2787824a1566SKashyap Desai return 0; 2788824a1566SKashyap Desai 2789824a1566SKashyap Desai ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n", 2790824a1566SKashyap Desai mrioc->dma_mask, facts_dma_mask); 2791824a1566SKashyap Desai 2792824a1566SKashyap Desai r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask); 2793824a1566SKashyap Desai if (r) { 2794824a1566SKashyap Desai ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n", 2795824a1566SKashyap Desai facts_dma_mask, r); 2796824a1566SKashyap Desai return r; 2797824a1566SKashyap Desai } 2798824a1566SKashyap Desai mrioc->dma_mask = facts_dma_mask; 2799824a1566SKashyap Desai return r; 2800824a1566SKashyap Desai } 2801824a1566SKashyap Desai 2802824a1566SKashyap Desai /** 2803824a1566SKashyap Desai * mpi3mr_process_factsdata - Process IOC facts data 2804824a1566SKashyap Desai * @mrioc: Adapter instance reference 2805824a1566SKashyap Desai * @facts_data: Cached IOC facts data 2806824a1566SKashyap Desai * 2807824a1566SKashyap Desai * Convert IOC facts data into cpu endianness and cache it in 2808824a1566SKashyap Desai * the driver . 2809824a1566SKashyap Desai * 2810824a1566SKashyap Desai * Return: Nothing. 2811824a1566SKashyap Desai */ 2812824a1566SKashyap Desai static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, 2813824a1566SKashyap Desai struct mpi3_ioc_facts_data *facts_data) 2814824a1566SKashyap Desai { 2815824a1566SKashyap Desai u32 ioc_config, req_sz, facts_flags; 2816824a1566SKashyap Desai 2817824a1566SKashyap Desai if ((le16_to_cpu(facts_data->ioc_facts_data_length)) != 2818824a1566SKashyap Desai (sizeof(*facts_data) / 4)) { 2819824a1566SKashyap Desai ioc_warn(mrioc, 2820824a1566SKashyap Desai "IOCFactsdata length mismatch driver_sz(%zu) firmware_sz(%d)\n", 2821824a1566SKashyap Desai sizeof(*facts_data), 2822824a1566SKashyap Desai le16_to_cpu(facts_data->ioc_facts_data_length) * 4); 2823824a1566SKashyap Desai } 2824824a1566SKashyap Desai 2825824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 2826824a1566SKashyap Desai req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >> 2827824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT); 2828824a1566SKashyap Desai if (le16_to_cpu(facts_data->ioc_request_frame_size) != (req_sz / 4)) { 2829824a1566SKashyap Desai ioc_err(mrioc, 2830824a1566SKashyap Desai "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n", 2831824a1566SKashyap Desai req_sz / 4, le16_to_cpu(facts_data->ioc_request_frame_size)); 2832824a1566SKashyap Desai } 2833824a1566SKashyap Desai 2834824a1566SKashyap Desai memset(&mrioc->facts, 0, sizeof(mrioc->facts)); 2835824a1566SKashyap Desai 2836824a1566SKashyap Desai facts_flags = le32_to_cpu(facts_data->flags); 2837824a1566SKashyap Desai mrioc->facts.op_req_sz = req_sz; 2838824a1566SKashyap Desai mrioc->op_reply_desc_sz = 1 << ((ioc_config & 2839824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >> 2840824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT); 2841824a1566SKashyap Desai 2842824a1566SKashyap Desai mrioc->facts.ioc_num = facts_data->ioc_number; 2843824a1566SKashyap Desai mrioc->facts.who_init = facts_data->who_init; 2844824a1566SKashyap Desai mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->max_msix_vectors); 2845824a1566SKashyap Desai mrioc->facts.personality = (facts_flags & 2846824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK); 2847824a1566SKashyap Desai mrioc->facts.dma_mask = (facts_flags & 2848824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >> 2849824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT; 2850824a1566SKashyap Desai mrioc->facts.protocol_flags = facts_data->protocol_flags; 2851824a1566SKashyap Desai mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word); 285204b27e53SSreekanth Reddy mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_requests); 2853824a1566SKashyap Desai mrioc->facts.product_id = le16_to_cpu(facts_data->product_id); 2854824a1566SKashyap Desai mrioc->facts.reply_sz = le16_to_cpu(facts_data->reply_frame_size) * 4; 2855824a1566SKashyap Desai mrioc->facts.exceptions = le16_to_cpu(facts_data->ioc_exceptions); 2856824a1566SKashyap Desai mrioc->facts.max_perids = le16_to_cpu(facts_data->max_persistent_id); 2857824a1566SKashyap Desai mrioc->facts.max_vds = le16_to_cpu(facts_data->max_vds); 2858824a1566SKashyap Desai mrioc->facts.max_hpds = le16_to_cpu(facts_data->max_host_pds); 2859ec5ebd2cSSreekanth Reddy mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_adv_host_pds); 2860ec5ebd2cSSreekanth Reddy mrioc->facts.max_raid_pds = le16_to_cpu(facts_data->max_raid_pds); 2861824a1566SKashyap Desai mrioc->facts.max_nvme = le16_to_cpu(facts_data->max_nvme); 2862824a1566SKashyap Desai mrioc->facts.max_pcie_switches = 2863ec5ebd2cSSreekanth Reddy le16_to_cpu(facts_data->max_pcie_switches); 2864824a1566SKashyap Desai mrioc->facts.max_sasexpanders = 2865824a1566SKashyap Desai le16_to_cpu(facts_data->max_sas_expanders); 2866d9adb81eSRanjan Kumar mrioc->facts.max_data_length = le16_to_cpu(facts_data->max_data_length); 2867824a1566SKashyap Desai mrioc->facts.max_sasinitiators = 2868824a1566SKashyap Desai le16_to_cpu(facts_data->max_sas_initiators); 2869824a1566SKashyap Desai mrioc->facts.max_enclosures = le16_to_cpu(facts_data->max_enclosures); 2870824a1566SKashyap Desai mrioc->facts.min_devhandle = le16_to_cpu(facts_data->min_dev_handle); 2871824a1566SKashyap Desai mrioc->facts.max_devhandle = le16_to_cpu(facts_data->max_dev_handle); 2872824a1566SKashyap Desai mrioc->facts.max_op_req_q = 2873824a1566SKashyap Desai le16_to_cpu(facts_data->max_operational_request_queues); 2874824a1566SKashyap Desai mrioc->facts.max_op_reply_q = 2875824a1566SKashyap Desai le16_to_cpu(facts_data->max_operational_reply_queues); 2876824a1566SKashyap Desai mrioc->facts.ioc_capabilities = 2877824a1566SKashyap Desai le32_to_cpu(facts_data->ioc_capabilities); 2878824a1566SKashyap Desai mrioc->facts.fw_ver.build_num = 2879824a1566SKashyap Desai le16_to_cpu(facts_data->fw_version.build_num); 2880824a1566SKashyap Desai mrioc->facts.fw_ver.cust_id = 2881824a1566SKashyap Desai le16_to_cpu(facts_data->fw_version.customer_id); 2882824a1566SKashyap Desai mrioc->facts.fw_ver.ph_minor = facts_data->fw_version.phase_minor; 2883824a1566SKashyap Desai mrioc->facts.fw_ver.ph_major = facts_data->fw_version.phase_major; 2884824a1566SKashyap Desai mrioc->facts.fw_ver.gen_minor = facts_data->fw_version.gen_minor; 2885824a1566SKashyap Desai mrioc->facts.fw_ver.gen_major = facts_data->fw_version.gen_major; 2886824a1566SKashyap Desai mrioc->msix_count = min_t(int, mrioc->msix_count, 2887824a1566SKashyap Desai mrioc->facts.max_msix_vectors); 2888824a1566SKashyap Desai mrioc->facts.sge_mod_mask = facts_data->sge_modifier_mask; 2889824a1566SKashyap Desai mrioc->facts.sge_mod_value = facts_data->sge_modifier_value; 2890824a1566SKashyap Desai mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift; 2891824a1566SKashyap Desai mrioc->facts.shutdown_timeout = 2892824a1566SKashyap Desai le16_to_cpu(facts_data->shutdown_timeout); 2893824a1566SKashyap Desai 2894f10af057SSreekanth Reddy mrioc->facts.max_dev_per_tg = 2895f10af057SSreekanth Reddy facts_data->max_devices_per_throttle_group; 2896f10af057SSreekanth Reddy mrioc->facts.io_throttle_data_length = 2897f10af057SSreekanth Reddy le16_to_cpu(facts_data->io_throttle_data_length); 2898f10af057SSreekanth Reddy mrioc->facts.max_io_throttle_group = 2899f10af057SSreekanth Reddy le16_to_cpu(facts_data->max_io_throttle_group); 2900f10af057SSreekanth Reddy mrioc->facts.io_throttle_low = le16_to_cpu(facts_data->io_throttle_low); 2901f10af057SSreekanth Reddy mrioc->facts.io_throttle_high = 2902f10af057SSreekanth Reddy le16_to_cpu(facts_data->io_throttle_high); 2903f10af057SSreekanth Reddy 2904d9adb81eSRanjan Kumar if (mrioc->facts.max_data_length == 2905d9adb81eSRanjan Kumar MPI3_IOCFACTS_MAX_DATA_LENGTH_NOT_REPORTED) 2906d9adb81eSRanjan Kumar mrioc->facts.max_data_length = MPI3MR_DEFAULT_MAX_IO_SIZE; 2907d9adb81eSRanjan Kumar else 2908d9adb81eSRanjan Kumar mrioc->facts.max_data_length *= MPI3MR_PAGE_SIZE_4K; 2909f10af057SSreekanth Reddy /* Store in 512b block count */ 2910f10af057SSreekanth Reddy if (mrioc->facts.io_throttle_data_length) 2911f10af057SSreekanth Reddy mrioc->io_throttle_data_length = 2912f10af057SSreekanth Reddy (mrioc->facts.io_throttle_data_length * 2 * 4); 2913f10af057SSreekanth Reddy else 2914f10af057SSreekanth Reddy /* set the length to 1MB + 1K to disable throttle */ 2915d9adb81eSRanjan Kumar mrioc->io_throttle_data_length = (mrioc->facts.max_data_length / 512) + 2; 2916f10af057SSreekanth Reddy 2917f10af057SSreekanth Reddy mrioc->io_throttle_high = (mrioc->facts.io_throttle_high * 2 * 1024); 2918f10af057SSreekanth Reddy mrioc->io_throttle_low = (mrioc->facts.io_throttle_low * 2 * 1024); 2919f10af057SSreekanth Reddy 2920824a1566SKashyap Desai ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),", 2921824a1566SKashyap Desai mrioc->facts.ioc_num, mrioc->facts.max_op_req_q, 2922824a1566SKashyap Desai mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle); 2923824a1566SKashyap Desai ioc_info(mrioc, 2924ec5ebd2cSSreekanth Reddy "maxreqs(%d), mindh(%d) maxvectors(%d) maxperids(%d)\n", 2925824a1566SKashyap Desai mrioc->facts.max_reqs, mrioc->facts.min_devhandle, 2926ec5ebd2cSSreekanth Reddy mrioc->facts.max_msix_vectors, mrioc->facts.max_perids); 2927824a1566SKashyap Desai ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ", 2928824a1566SKashyap Desai mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value, 2929824a1566SKashyap Desai mrioc->facts.sge_mod_shift); 2930d9adb81eSRanjan Kumar ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x max_data_len (%d)\n", 2931824a1566SKashyap Desai mrioc->facts.dma_mask, (facts_flags & 2932d9adb81eSRanjan Kumar MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK), mrioc->facts.max_data_length); 2933f10af057SSreekanth Reddy ioc_info(mrioc, 2934f10af057SSreekanth Reddy "max_dev_per_throttle_group(%d), max_throttle_groups(%d)\n", 2935f10af057SSreekanth Reddy mrioc->facts.max_dev_per_tg, mrioc->facts.max_io_throttle_group); 2936f10af057SSreekanth Reddy ioc_info(mrioc, 2937f10af057SSreekanth Reddy "io_throttle_data_len(%dKiB), io_throttle_high(%dMiB), io_throttle_low(%dMiB)\n", 2938f10af057SSreekanth Reddy mrioc->facts.io_throttle_data_length * 4, 2939f10af057SSreekanth Reddy mrioc->facts.io_throttle_high, mrioc->facts.io_throttle_low); 2940824a1566SKashyap Desai } 2941824a1566SKashyap Desai 2942824a1566SKashyap Desai /** 2943824a1566SKashyap Desai * mpi3mr_alloc_reply_sense_bufs - Send IOC Init 2944824a1566SKashyap Desai * @mrioc: Adapter instance reference 2945824a1566SKashyap Desai * 2946824a1566SKashyap Desai * Allocate and initialize the reply free buffers, sense 2947824a1566SKashyap Desai * buffers, reply free queue and sense buffer queue. 2948824a1566SKashyap Desai * 2949824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2950824a1566SKashyap Desai */ 2951824a1566SKashyap Desai static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) 2952824a1566SKashyap Desai { 2953824a1566SKashyap Desai int retval = 0; 2954824a1566SKashyap Desai u32 sz, i; 2955824a1566SKashyap Desai 2956824a1566SKashyap Desai if (mrioc->init_cmds.reply) 2957e3605f65SSreekanth Reddy return retval; 2958824a1566SKashyap Desai 2959c5758fc7SSreekanth Reddy mrioc->init_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); 2960824a1566SKashyap Desai if (!mrioc->init_cmds.reply) 2961824a1566SKashyap Desai goto out_failed; 2962824a1566SKashyap Desai 2963f5e6d5a3SSumit Saxena mrioc->bsg_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); 2964f5e6d5a3SSumit Saxena if (!mrioc->bsg_cmds.reply) 2965f5e6d5a3SSumit Saxena goto out_failed; 2966f5e6d5a3SSumit Saxena 29672bd37e28SSreekanth Reddy mrioc->transport_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); 29682bd37e28SSreekanth Reddy if (!mrioc->transport_cmds.reply) 29692bd37e28SSreekanth Reddy goto out_failed; 29702bd37e28SSreekanth Reddy 297113ef29eaSKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 2972c5758fc7SSreekanth Reddy mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz, 297313ef29eaSKashyap Desai GFP_KERNEL); 297413ef29eaSKashyap Desai if (!mrioc->dev_rmhs_cmds[i].reply) 297513ef29eaSKashyap Desai goto out_failed; 297613ef29eaSKashyap Desai } 297713ef29eaSKashyap Desai 2978c1af985dSSreekanth Reddy for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { 2979c1af985dSSreekanth Reddy mrioc->evtack_cmds[i].reply = kzalloc(mrioc->reply_sz, 2980c1af985dSSreekanth Reddy GFP_KERNEL); 2981c1af985dSSreekanth Reddy if (!mrioc->evtack_cmds[i].reply) 2982c1af985dSSreekanth Reddy goto out_failed; 2983c1af985dSSreekanth Reddy } 2984c1af985dSSreekanth Reddy 2985c5758fc7SSreekanth Reddy mrioc->host_tm_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); 2986e844adb1SKashyap Desai if (!mrioc->host_tm_cmds.reply) 2987e844adb1SKashyap Desai goto out_failed; 2988e844adb1SKashyap Desai 298943ca1100SSumit Saxena mrioc->pel_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); 299043ca1100SSumit Saxena if (!mrioc->pel_cmds.reply) 299143ca1100SSumit Saxena goto out_failed; 299243ca1100SSumit Saxena 299343ca1100SSumit Saxena mrioc->pel_abort_cmd.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); 299443ca1100SSumit Saxena if (!mrioc->pel_abort_cmd.reply) 299543ca1100SSumit Saxena goto out_failed; 299643ca1100SSumit Saxena 2997339e6156SShin'ichiro Kawasaki mrioc->dev_handle_bitmap_bits = mrioc->facts.max_devhandle; 2998339e6156SShin'ichiro Kawasaki mrioc->removepend_bitmap = bitmap_zalloc(mrioc->dev_handle_bitmap_bits, 2999e844adb1SKashyap Desai GFP_KERNEL); 3000e844adb1SKashyap Desai if (!mrioc->removepend_bitmap) 3001e844adb1SKashyap Desai goto out_failed; 3002e844adb1SKashyap Desai 3003339e6156SShin'ichiro Kawasaki mrioc->devrem_bitmap = bitmap_zalloc(MPI3MR_NUM_DEVRMCMD, GFP_KERNEL); 3004e844adb1SKashyap Desai if (!mrioc->devrem_bitmap) 3005e844adb1SKashyap Desai goto out_failed; 3006e844adb1SKashyap Desai 3007339e6156SShin'ichiro Kawasaki mrioc->evtack_cmds_bitmap = bitmap_zalloc(MPI3MR_NUM_EVTACKCMD, 3008c1af985dSSreekanth Reddy GFP_KERNEL); 3009c1af985dSSreekanth Reddy if (!mrioc->evtack_cmds_bitmap) 3010c1af985dSSreekanth Reddy goto out_failed; 3011c1af985dSSreekanth Reddy 3012824a1566SKashyap Desai mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES; 3013824a1566SKashyap Desai mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1; 3014824a1566SKashyap Desai mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR; 3015824a1566SKashyap Desai mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1; 3016824a1566SKashyap Desai 3017824a1566SKashyap Desai /* reply buffer pool, 16 byte align */ 3018c5758fc7SSreekanth Reddy sz = mrioc->num_reply_bufs * mrioc->reply_sz; 3019824a1566SKashyap Desai mrioc->reply_buf_pool = dma_pool_create("reply_buf pool", 3020824a1566SKashyap Desai &mrioc->pdev->dev, sz, 16, 0); 3021824a1566SKashyap Desai if (!mrioc->reply_buf_pool) { 3022824a1566SKashyap Desai ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n"); 3023824a1566SKashyap Desai goto out_failed; 3024824a1566SKashyap Desai } 3025824a1566SKashyap Desai 3026824a1566SKashyap Desai mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL, 3027824a1566SKashyap Desai &mrioc->reply_buf_dma); 3028824a1566SKashyap Desai if (!mrioc->reply_buf) 3029824a1566SKashyap Desai goto out_failed; 3030824a1566SKashyap Desai 3031824a1566SKashyap Desai mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz; 3032824a1566SKashyap Desai 3033824a1566SKashyap Desai /* reply free queue, 8 byte align */ 3034824a1566SKashyap Desai sz = mrioc->reply_free_qsz * 8; 3035824a1566SKashyap Desai mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool", 3036824a1566SKashyap Desai &mrioc->pdev->dev, sz, 8, 0); 3037824a1566SKashyap Desai if (!mrioc->reply_free_q_pool) { 3038824a1566SKashyap Desai ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n"); 3039824a1566SKashyap Desai goto out_failed; 3040824a1566SKashyap Desai } 3041824a1566SKashyap Desai mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool, 3042824a1566SKashyap Desai GFP_KERNEL, &mrioc->reply_free_q_dma); 3043824a1566SKashyap Desai if (!mrioc->reply_free_q) 3044824a1566SKashyap Desai goto out_failed; 3045824a1566SKashyap Desai 3046824a1566SKashyap Desai /* sense buffer pool, 4 byte align */ 3047ec5ebd2cSSreekanth Reddy sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ; 3048824a1566SKashyap Desai mrioc->sense_buf_pool = dma_pool_create("sense_buf pool", 3049824a1566SKashyap Desai &mrioc->pdev->dev, sz, 4, 0); 3050824a1566SKashyap Desai if (!mrioc->sense_buf_pool) { 3051824a1566SKashyap Desai ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n"); 3052824a1566SKashyap Desai goto out_failed; 3053824a1566SKashyap Desai } 3054824a1566SKashyap Desai mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL, 3055824a1566SKashyap Desai &mrioc->sense_buf_dma); 3056824a1566SKashyap Desai if (!mrioc->sense_buf) 3057824a1566SKashyap Desai goto out_failed; 3058824a1566SKashyap Desai 3059824a1566SKashyap Desai /* sense buffer queue, 8 byte align */ 3060824a1566SKashyap Desai sz = mrioc->sense_buf_q_sz * 8; 3061824a1566SKashyap Desai mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool", 3062824a1566SKashyap Desai &mrioc->pdev->dev, sz, 8, 0); 3063824a1566SKashyap Desai if (!mrioc->sense_buf_q_pool) { 3064824a1566SKashyap Desai ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n"); 3065824a1566SKashyap Desai goto out_failed; 3066824a1566SKashyap Desai } 3067824a1566SKashyap Desai mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool, 3068824a1566SKashyap Desai GFP_KERNEL, &mrioc->sense_buf_q_dma); 3069824a1566SKashyap Desai if (!mrioc->sense_buf_q) 3070824a1566SKashyap Desai goto out_failed; 3071824a1566SKashyap Desai 3072e3605f65SSreekanth Reddy return retval; 3073e3605f65SSreekanth Reddy 3074e3605f65SSreekanth Reddy out_failed: 3075e3605f65SSreekanth Reddy retval = -1; 3076e3605f65SSreekanth Reddy return retval; 3077e3605f65SSreekanth Reddy } 3078e3605f65SSreekanth Reddy 3079e3605f65SSreekanth Reddy /** 3080e3605f65SSreekanth Reddy * mpimr_initialize_reply_sbuf_queues - initialize reply sense 3081e3605f65SSreekanth Reddy * buffers 3082e3605f65SSreekanth Reddy * @mrioc: Adapter instance reference 3083e3605f65SSreekanth Reddy * 3084e3605f65SSreekanth Reddy * Helper function to initialize reply and sense buffers along 3085e3605f65SSreekanth Reddy * with some debug prints. 3086e3605f65SSreekanth Reddy * 3087e3605f65SSreekanth Reddy * Return: None. 3088e3605f65SSreekanth Reddy */ 3089e3605f65SSreekanth Reddy static void mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc *mrioc) 3090e3605f65SSreekanth Reddy { 3091e3605f65SSreekanth Reddy u32 sz, i; 3092e3605f65SSreekanth Reddy dma_addr_t phy_addr; 3093e3605f65SSreekanth Reddy 3094c5758fc7SSreekanth Reddy sz = mrioc->num_reply_bufs * mrioc->reply_sz; 3095824a1566SKashyap Desai ioc_info(mrioc, 3096824a1566SKashyap Desai "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n", 3097c5758fc7SSreekanth Reddy mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->reply_sz, 3098824a1566SKashyap Desai (sz / 1024), (unsigned long long)mrioc->reply_buf_dma); 3099824a1566SKashyap Desai sz = mrioc->reply_free_qsz * 8; 3100824a1566SKashyap Desai ioc_info(mrioc, 3101824a1566SKashyap Desai "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n", 3102824a1566SKashyap Desai mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024), 3103824a1566SKashyap Desai (unsigned long long)mrioc->reply_free_q_dma); 3104ec5ebd2cSSreekanth Reddy sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ; 3105824a1566SKashyap Desai ioc_info(mrioc, 3106824a1566SKashyap Desai "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n", 3107ec5ebd2cSSreekanth Reddy mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSE_BUF_SZ, 3108824a1566SKashyap Desai (sz / 1024), (unsigned long long)mrioc->sense_buf_dma); 3109824a1566SKashyap Desai sz = mrioc->sense_buf_q_sz * 8; 3110824a1566SKashyap Desai ioc_info(mrioc, 3111824a1566SKashyap Desai "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n", 3112824a1566SKashyap Desai mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024), 3113824a1566SKashyap Desai (unsigned long long)mrioc->sense_buf_q_dma); 3114824a1566SKashyap Desai 3115824a1566SKashyap Desai /* initialize Reply buffer Queue */ 3116824a1566SKashyap Desai for (i = 0, phy_addr = mrioc->reply_buf_dma; 3117c5758fc7SSreekanth Reddy i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->reply_sz) 3118824a1566SKashyap Desai mrioc->reply_free_q[i] = cpu_to_le64(phy_addr); 3119824a1566SKashyap Desai mrioc->reply_free_q[i] = cpu_to_le64(0); 3120824a1566SKashyap Desai 3121824a1566SKashyap Desai /* initialize Sense Buffer Queue */ 3122824a1566SKashyap Desai for (i = 0, phy_addr = mrioc->sense_buf_dma; 3123ec5ebd2cSSreekanth Reddy i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSE_BUF_SZ) 3124824a1566SKashyap Desai mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr); 3125824a1566SKashyap Desai mrioc->sense_buf_q[i] = cpu_to_le64(0); 3126824a1566SKashyap Desai } 3127824a1566SKashyap Desai 3128824a1566SKashyap Desai /** 3129824a1566SKashyap Desai * mpi3mr_issue_iocinit - Send IOC Init 3130824a1566SKashyap Desai * @mrioc: Adapter instance reference 3131824a1566SKashyap Desai * 3132824a1566SKashyap Desai * Issue IOC Init MPI request through admin queue and wait for 3133824a1566SKashyap Desai * the completion of it or time out. 3134824a1566SKashyap Desai * 3135824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 3136824a1566SKashyap Desai */ 3137824a1566SKashyap Desai static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc) 3138824a1566SKashyap Desai { 3139824a1566SKashyap Desai struct mpi3_ioc_init_request iocinit_req; 3140824a1566SKashyap Desai struct mpi3_driver_info_layout *drv_info; 3141824a1566SKashyap Desai dma_addr_t data_dma; 3142824a1566SKashyap Desai u32 data_len = sizeof(*drv_info); 3143824a1566SKashyap Desai int retval = 0; 3144824a1566SKashyap Desai ktime_t current_time; 3145824a1566SKashyap Desai 3146824a1566SKashyap Desai drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, 3147824a1566SKashyap Desai GFP_KERNEL); 3148824a1566SKashyap Desai if (!drv_info) { 3149824a1566SKashyap Desai retval = -1; 3150824a1566SKashyap Desai goto out; 3151824a1566SKashyap Desai } 3152e3605f65SSreekanth Reddy mpimr_initialize_reply_sbuf_queues(mrioc); 3153e3605f65SSreekanth Reddy 3154824a1566SKashyap Desai drv_info->information_length = cpu_to_le32(data_len); 3155aa0dc6a7SSreekanth Reddy strscpy(drv_info->driver_signature, "Broadcom", sizeof(drv_info->driver_signature)); 3156aa0dc6a7SSreekanth Reddy strscpy(drv_info->os_name, utsname()->sysname, sizeof(drv_info->os_name)); 3157aa0dc6a7SSreekanth Reddy strscpy(drv_info->os_version, utsname()->release, sizeof(drv_info->os_version)); 3158aa0dc6a7SSreekanth Reddy strscpy(drv_info->driver_name, MPI3MR_DRIVER_NAME, sizeof(drv_info->driver_name)); 3159aa0dc6a7SSreekanth Reddy strscpy(drv_info->driver_version, MPI3MR_DRIVER_VERSION, sizeof(drv_info->driver_version)); 3160aa0dc6a7SSreekanth Reddy strscpy(drv_info->driver_release_date, MPI3MR_DRIVER_RELDATE, 3161aa0dc6a7SSreekanth Reddy sizeof(drv_info->driver_release_date)); 3162824a1566SKashyap Desai drv_info->driver_capabilities = 0; 3163824a1566SKashyap Desai memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info, 3164824a1566SKashyap Desai sizeof(mrioc->driver_info)); 3165824a1566SKashyap Desai 3166824a1566SKashyap Desai memset(&iocinit_req, 0, sizeof(iocinit_req)); 3167824a1566SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 3168824a1566SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 3169824a1566SKashyap Desai retval = -1; 3170824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCInit: Init command is in use\n"); 3171824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 3172824a1566SKashyap Desai goto out; 3173824a1566SKashyap Desai } 3174824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 3175824a1566SKashyap Desai mrioc->init_cmds.is_waiting = 1; 3176824a1566SKashyap Desai mrioc->init_cmds.callback = NULL; 3177824a1566SKashyap Desai iocinit_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 3178824a1566SKashyap Desai iocinit_req.function = MPI3_FUNCTION_IOC_INIT; 3179824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.dev = MPI3_VERSION_DEV; 3180824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.unit = MPI3_VERSION_UNIT; 3181824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.major = MPI3_VERSION_MAJOR; 3182824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.minor = MPI3_VERSION_MINOR; 3183824a1566SKashyap Desai iocinit_req.who_init = MPI3_WHOINIT_HOST_DRIVER; 3184824a1566SKashyap Desai iocinit_req.reply_free_queue_depth = cpu_to_le16(mrioc->reply_free_qsz); 3185824a1566SKashyap Desai iocinit_req.reply_free_queue_address = 3186824a1566SKashyap Desai cpu_to_le64(mrioc->reply_free_q_dma); 3187ec5ebd2cSSreekanth Reddy iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSE_BUF_SZ); 3188824a1566SKashyap Desai iocinit_req.sense_buffer_free_queue_depth = 3189824a1566SKashyap Desai cpu_to_le16(mrioc->sense_buf_q_sz); 3190824a1566SKashyap Desai iocinit_req.sense_buffer_free_queue_address = 3191824a1566SKashyap Desai cpu_to_le64(mrioc->sense_buf_q_dma); 3192824a1566SKashyap Desai iocinit_req.driver_information_address = cpu_to_le64(data_dma); 3193824a1566SKashyap Desai 3194824a1566SKashyap Desai current_time = ktime_get_real(); 3195824a1566SKashyap Desai iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time)); 3196824a1566SKashyap Desai 3197*1193a89dSSumit Saxena iocinit_req.msg_flags |= 3198*1193a89dSSumit Saxena MPI3_IOCINIT_MSGFLAGS_SCSIIOSTATUSREPLY_SUPPORTED; 3199*1193a89dSSumit Saxena 3200824a1566SKashyap Desai init_completion(&mrioc->init_cmds.done); 3201824a1566SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iocinit_req, 3202824a1566SKashyap Desai sizeof(iocinit_req), 1); 3203824a1566SKashyap Desai if (retval) { 3204824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n"); 3205824a1566SKashyap Desai goto out_unlock; 3206824a1566SKashyap Desai } 3207824a1566SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 3208824a1566SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 3209824a1566SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 3210a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 3211824a1566SKashyap Desai MPI3MR_RESET_FROM_IOCINIT_TIMEOUT); 3212a6856cc4SSreekanth Reddy ioc_err(mrioc, "ioc_init timed out\n"); 3213824a1566SKashyap Desai retval = -1; 3214824a1566SKashyap Desai goto out_unlock; 3215824a1566SKashyap Desai } 3216824a1566SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 3217824a1566SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 3218824a1566SKashyap Desai ioc_err(mrioc, 3219824a1566SKashyap Desai "Issue IOCInit: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 3220824a1566SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 3221824a1566SKashyap Desai mrioc->init_cmds.ioc_loginfo); 3222824a1566SKashyap Desai retval = -1; 3223824a1566SKashyap Desai goto out_unlock; 3224824a1566SKashyap Desai } 3225824a1566SKashyap Desai 3226e3605f65SSreekanth Reddy mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs; 3227e3605f65SSreekanth Reddy writel(mrioc->reply_free_queue_host_index, 3228e3605f65SSreekanth Reddy &mrioc->sysif_regs->reply_free_host_index); 3229e3605f65SSreekanth Reddy 3230e3605f65SSreekanth Reddy mrioc->sbq_host_index = mrioc->num_sense_bufs; 3231e3605f65SSreekanth Reddy writel(mrioc->sbq_host_index, 3232e3605f65SSreekanth Reddy &mrioc->sysif_regs->sense_buffer_free_host_index); 3233824a1566SKashyap Desai out_unlock: 3234824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 3235824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 3236824a1566SKashyap Desai 3237824a1566SKashyap Desai out: 3238824a1566SKashyap Desai if (drv_info) 3239824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info, 3240824a1566SKashyap Desai data_dma); 3241824a1566SKashyap Desai 3242824a1566SKashyap Desai return retval; 3243824a1566SKashyap Desai } 3244824a1566SKashyap Desai 3245824a1566SKashyap Desai /** 324613ef29eaSKashyap Desai * mpi3mr_unmask_events - Unmask events in event mask bitmap 324713ef29eaSKashyap Desai * @mrioc: Adapter instance reference 324813ef29eaSKashyap Desai * @event: MPI event ID 324913ef29eaSKashyap Desai * 325013ef29eaSKashyap Desai * Un mask the specific event by resetting the event_mask 325113ef29eaSKashyap Desai * bitmap. 325213ef29eaSKashyap Desai * 325313ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 325413ef29eaSKashyap Desai */ 325513ef29eaSKashyap Desai static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event) 325613ef29eaSKashyap Desai { 325713ef29eaSKashyap Desai u32 desired_event; 325813ef29eaSKashyap Desai u8 word; 325913ef29eaSKashyap Desai 326013ef29eaSKashyap Desai if (event >= 128) 326113ef29eaSKashyap Desai return; 326213ef29eaSKashyap Desai 326313ef29eaSKashyap Desai desired_event = (1 << (event % 32)); 326413ef29eaSKashyap Desai word = event / 32; 326513ef29eaSKashyap Desai 326613ef29eaSKashyap Desai mrioc->event_masks[word] &= ~desired_event; 326713ef29eaSKashyap Desai } 326813ef29eaSKashyap Desai 326913ef29eaSKashyap Desai /** 327013ef29eaSKashyap Desai * mpi3mr_issue_event_notification - Send event notification 327113ef29eaSKashyap Desai * @mrioc: Adapter instance reference 327213ef29eaSKashyap Desai * 327313ef29eaSKashyap Desai * Issue event notification MPI request through admin queue and 327413ef29eaSKashyap Desai * wait for the completion of it or time out. 327513ef29eaSKashyap Desai * 327613ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 327713ef29eaSKashyap Desai */ 327813ef29eaSKashyap Desai static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc) 327913ef29eaSKashyap Desai { 328013ef29eaSKashyap Desai struct mpi3_event_notification_request evtnotify_req; 328113ef29eaSKashyap Desai int retval = 0; 328213ef29eaSKashyap Desai u8 i; 328313ef29eaSKashyap Desai 328413ef29eaSKashyap Desai memset(&evtnotify_req, 0, sizeof(evtnotify_req)); 328513ef29eaSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 328613ef29eaSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 328713ef29eaSKashyap Desai retval = -1; 328813ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: Init command is in use\n"); 328913ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 329013ef29eaSKashyap Desai goto out; 329113ef29eaSKashyap Desai } 329213ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 329313ef29eaSKashyap Desai mrioc->init_cmds.is_waiting = 1; 329413ef29eaSKashyap Desai mrioc->init_cmds.callback = NULL; 329513ef29eaSKashyap Desai evtnotify_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 329613ef29eaSKashyap Desai evtnotify_req.function = MPI3_FUNCTION_EVENT_NOTIFICATION; 329713ef29eaSKashyap Desai for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 329813ef29eaSKashyap Desai evtnotify_req.event_masks[i] = 329913ef29eaSKashyap Desai cpu_to_le32(mrioc->event_masks[i]); 330013ef29eaSKashyap Desai init_completion(&mrioc->init_cmds.done); 330113ef29eaSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &evtnotify_req, 330213ef29eaSKashyap Desai sizeof(evtnotify_req), 1); 330313ef29eaSKashyap Desai if (retval) { 330413ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: Admin Post failed\n"); 330513ef29eaSKashyap Desai goto out_unlock; 330613ef29eaSKashyap Desai } 330713ef29eaSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 330813ef29eaSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 330913ef29eaSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 3310a6856cc4SSreekanth Reddy ioc_err(mrioc, "event notification timed out\n"); 3311a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 331213ef29eaSKashyap Desai MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT); 331313ef29eaSKashyap Desai retval = -1; 331413ef29eaSKashyap Desai goto out_unlock; 331513ef29eaSKashyap Desai } 331613ef29eaSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 331713ef29eaSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 331813ef29eaSKashyap Desai ioc_err(mrioc, 331913ef29eaSKashyap Desai "Issue EvtNotify: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 332013ef29eaSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 332113ef29eaSKashyap Desai mrioc->init_cmds.ioc_loginfo); 332213ef29eaSKashyap Desai retval = -1; 332313ef29eaSKashyap Desai goto out_unlock; 332413ef29eaSKashyap Desai } 332513ef29eaSKashyap Desai 332613ef29eaSKashyap Desai out_unlock: 332713ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 332813ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 332913ef29eaSKashyap Desai out: 333013ef29eaSKashyap Desai return retval; 333113ef29eaSKashyap Desai } 333213ef29eaSKashyap Desai 333313ef29eaSKashyap Desai /** 3334c1af985dSSreekanth Reddy * mpi3mr_process_event_ack - Process event acknowledgment 333513ef29eaSKashyap Desai * @mrioc: Adapter instance reference 333613ef29eaSKashyap Desai * @event: MPI3 event ID 3337c1af985dSSreekanth Reddy * @event_ctx: event context 333813ef29eaSKashyap Desai * 333913ef29eaSKashyap Desai * Send event acknowledgment through admin queue and wait for 334013ef29eaSKashyap Desai * it to complete. 334113ef29eaSKashyap Desai * 334213ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 334313ef29eaSKashyap Desai */ 3344c1af985dSSreekanth Reddy int mpi3mr_process_event_ack(struct mpi3mr_ioc *mrioc, u8 event, 334513ef29eaSKashyap Desai u32 event_ctx) 334613ef29eaSKashyap Desai { 334713ef29eaSKashyap Desai struct mpi3_event_ack_request evtack_req; 334813ef29eaSKashyap Desai int retval = 0; 334913ef29eaSKashyap Desai 335013ef29eaSKashyap Desai memset(&evtack_req, 0, sizeof(evtack_req)); 335113ef29eaSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 335213ef29eaSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 335313ef29eaSKashyap Desai retval = -1; 335413ef29eaSKashyap Desai ioc_err(mrioc, "Send EvtAck: Init command is in use\n"); 335513ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 335613ef29eaSKashyap Desai goto out; 335713ef29eaSKashyap Desai } 335813ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 335913ef29eaSKashyap Desai mrioc->init_cmds.is_waiting = 1; 336013ef29eaSKashyap Desai mrioc->init_cmds.callback = NULL; 336113ef29eaSKashyap Desai evtack_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 336213ef29eaSKashyap Desai evtack_req.function = MPI3_FUNCTION_EVENT_ACK; 336313ef29eaSKashyap Desai evtack_req.event = event; 336413ef29eaSKashyap Desai evtack_req.event_context = cpu_to_le32(event_ctx); 336513ef29eaSKashyap Desai 336613ef29eaSKashyap Desai init_completion(&mrioc->init_cmds.done); 336713ef29eaSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &evtack_req, 336813ef29eaSKashyap Desai sizeof(evtack_req), 1); 336913ef29eaSKashyap Desai if (retval) { 337013ef29eaSKashyap Desai ioc_err(mrioc, "Send EvtAck: Admin Post failed\n"); 337113ef29eaSKashyap Desai goto out_unlock; 337213ef29eaSKashyap Desai } 337313ef29eaSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 337413ef29eaSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 337513ef29eaSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 337613ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: command timed out\n"); 3377fbaa9aa4SSreekanth Reddy if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET)) 33789134211fSRanjan Kumar mpi3mr_check_rh_fault_ioc(mrioc, 33799134211fSRanjan Kumar MPI3MR_RESET_FROM_EVTACK_TIMEOUT); 338013ef29eaSKashyap Desai retval = -1; 338113ef29eaSKashyap Desai goto out_unlock; 338213ef29eaSKashyap Desai } 338313ef29eaSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 338413ef29eaSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 338513ef29eaSKashyap Desai ioc_err(mrioc, 338613ef29eaSKashyap Desai "Send EvtAck: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 338713ef29eaSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 338813ef29eaSKashyap Desai mrioc->init_cmds.ioc_loginfo); 338913ef29eaSKashyap Desai retval = -1; 339013ef29eaSKashyap Desai goto out_unlock; 339113ef29eaSKashyap Desai } 339213ef29eaSKashyap Desai 339313ef29eaSKashyap Desai out_unlock: 339413ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 339513ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 339613ef29eaSKashyap Desai out: 339713ef29eaSKashyap Desai return retval; 339813ef29eaSKashyap Desai } 339913ef29eaSKashyap Desai 340013ef29eaSKashyap Desai /** 3401824a1566SKashyap Desai * mpi3mr_alloc_chain_bufs - Allocate chain buffers 3402824a1566SKashyap Desai * @mrioc: Adapter instance reference 3403824a1566SKashyap Desai * 3404824a1566SKashyap Desai * Allocate chain buffers and set a bitmap to indicate free 3405824a1566SKashyap Desai * chain buffers. Chain buffers are used to pass the SGE 3406824a1566SKashyap Desai * information along with MPI3 SCSI IO requests for host I/O. 3407824a1566SKashyap Desai * 3408824a1566SKashyap Desai * Return: 0 on success, non-zero on failure 3409824a1566SKashyap Desai */ 3410824a1566SKashyap Desai static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc) 3411824a1566SKashyap Desai { 3412824a1566SKashyap Desai int retval = 0; 3413824a1566SKashyap Desai u32 sz, i; 3414824a1566SKashyap Desai u16 num_chains; 3415824a1566SKashyap Desai 3416fe6db615SSreekanth Reddy if (mrioc->chain_sgl_list) 3417fe6db615SSreekanth Reddy return retval; 3418fe6db615SSreekanth Reddy 3419824a1566SKashyap Desai num_chains = mrioc->max_host_ios / MPI3MR_CHAINBUF_FACTOR; 3420824a1566SKashyap Desai 342174e1f30aSKashyap Desai if (prot_mask & (SHOST_DIX_TYPE0_PROTECTION 342274e1f30aSKashyap Desai | SHOST_DIX_TYPE1_PROTECTION 342374e1f30aSKashyap Desai | SHOST_DIX_TYPE2_PROTECTION 342474e1f30aSKashyap Desai | SHOST_DIX_TYPE3_PROTECTION)) 342574e1f30aSKashyap Desai num_chains += (num_chains / MPI3MR_CHAINBUFDIX_FACTOR); 342674e1f30aSKashyap Desai 3427824a1566SKashyap Desai mrioc->chain_buf_count = num_chains; 3428824a1566SKashyap Desai sz = sizeof(struct chain_element) * num_chains; 3429824a1566SKashyap Desai mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL); 3430824a1566SKashyap Desai if (!mrioc->chain_sgl_list) 3431824a1566SKashyap Desai goto out_failed; 3432824a1566SKashyap Desai 3433d9adb81eSRanjan Kumar if (mrioc->max_sgl_entries > (mrioc->facts.max_data_length / 3434d9adb81eSRanjan Kumar MPI3MR_PAGE_SIZE_4K)) 3435d9adb81eSRanjan Kumar mrioc->max_sgl_entries = mrioc->facts.max_data_length / 3436d9adb81eSRanjan Kumar MPI3MR_PAGE_SIZE_4K; 3437d9adb81eSRanjan Kumar sz = mrioc->max_sgl_entries * sizeof(struct mpi3_sge_common); 3438d9adb81eSRanjan Kumar ioc_info(mrioc, "number of sgl entries=%d chain buffer size=%dKB\n", 3439d9adb81eSRanjan Kumar mrioc->max_sgl_entries, sz/1024); 3440d9adb81eSRanjan Kumar 3441824a1566SKashyap Desai mrioc->chain_buf_pool = dma_pool_create("chain_buf pool", 3442824a1566SKashyap Desai &mrioc->pdev->dev, sz, 16, 0); 3443824a1566SKashyap Desai if (!mrioc->chain_buf_pool) { 3444824a1566SKashyap Desai ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n"); 3445824a1566SKashyap Desai goto out_failed; 3446824a1566SKashyap Desai } 3447824a1566SKashyap Desai 3448824a1566SKashyap Desai for (i = 0; i < num_chains; i++) { 3449824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr = 3450824a1566SKashyap Desai dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL, 3451824a1566SKashyap Desai &mrioc->chain_sgl_list[i].dma_addr); 3452824a1566SKashyap Desai 3453824a1566SKashyap Desai if (!mrioc->chain_sgl_list[i].addr) 3454824a1566SKashyap Desai goto out_failed; 3455824a1566SKashyap Desai } 3456339e6156SShin'ichiro Kawasaki mrioc->chain_bitmap = bitmap_zalloc(num_chains, GFP_KERNEL); 3457824a1566SKashyap Desai if (!mrioc->chain_bitmap) 3458824a1566SKashyap Desai goto out_failed; 3459824a1566SKashyap Desai return retval; 3460824a1566SKashyap Desai out_failed: 3461824a1566SKashyap Desai retval = -1; 3462824a1566SKashyap Desai return retval; 3463824a1566SKashyap Desai } 3464824a1566SKashyap Desai 3465824a1566SKashyap Desai /** 3466023ab2a9SKashyap Desai * mpi3mr_port_enable_complete - Mark port enable complete 3467023ab2a9SKashyap Desai * @mrioc: Adapter instance reference 3468023ab2a9SKashyap Desai * @drv_cmd: Internal command tracker 3469023ab2a9SKashyap Desai * 3470023ab2a9SKashyap Desai * Call back for asynchronous port enable request sets the 3471023ab2a9SKashyap Desai * driver command to indicate port enable request is complete. 3472023ab2a9SKashyap Desai * 3473023ab2a9SKashyap Desai * Return: Nothing 3474023ab2a9SKashyap Desai */ 3475023ab2a9SKashyap Desai static void mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc, 3476023ab2a9SKashyap Desai struct mpi3mr_drv_cmd *drv_cmd) 3477023ab2a9SKashyap Desai { 3478023ab2a9SKashyap Desai drv_cmd->callback = NULL; 3479023ab2a9SKashyap Desai mrioc->scan_started = 0; 3480f2a79d20SSreekanth Reddy if (drv_cmd->state & MPI3MR_CMD_RESET) 3481f2a79d20SSreekanth Reddy mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR; 3482f2a79d20SSreekanth Reddy else 3483f2a79d20SSreekanth Reddy mrioc->scan_failed = drv_cmd->ioc_status; 3484f2a79d20SSreekanth Reddy drv_cmd->state = MPI3MR_CMD_NOTUSED; 3485023ab2a9SKashyap Desai } 3486023ab2a9SKashyap Desai 3487023ab2a9SKashyap Desai /** 3488023ab2a9SKashyap Desai * mpi3mr_issue_port_enable - Issue Port Enable 3489023ab2a9SKashyap Desai * @mrioc: Adapter instance reference 3490023ab2a9SKashyap Desai * @async: Flag to wait for completion or not 3491023ab2a9SKashyap Desai * 3492023ab2a9SKashyap Desai * Issue Port Enable MPI request through admin queue and if the 3493023ab2a9SKashyap Desai * async flag is not set wait for the completion of the port 3494023ab2a9SKashyap Desai * enable or time out. 3495023ab2a9SKashyap Desai * 3496023ab2a9SKashyap Desai * Return: 0 on success, non-zero on failures. 3497023ab2a9SKashyap Desai */ 3498023ab2a9SKashyap Desai int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async) 3499023ab2a9SKashyap Desai { 3500023ab2a9SKashyap Desai struct mpi3_port_enable_request pe_req; 3501023ab2a9SKashyap Desai int retval = 0; 3502023ab2a9SKashyap Desai u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT; 3503023ab2a9SKashyap Desai 3504023ab2a9SKashyap Desai memset(&pe_req, 0, sizeof(pe_req)); 3505023ab2a9SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 3506023ab2a9SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 3507023ab2a9SKashyap Desai retval = -1; 3508023ab2a9SKashyap Desai ioc_err(mrioc, "Issue PortEnable: Init command is in use\n"); 3509023ab2a9SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 3510023ab2a9SKashyap Desai goto out; 3511023ab2a9SKashyap Desai } 3512023ab2a9SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 3513023ab2a9SKashyap Desai if (async) { 3514023ab2a9SKashyap Desai mrioc->init_cmds.is_waiting = 0; 3515023ab2a9SKashyap Desai mrioc->init_cmds.callback = mpi3mr_port_enable_complete; 3516023ab2a9SKashyap Desai } else { 3517023ab2a9SKashyap Desai mrioc->init_cmds.is_waiting = 1; 3518023ab2a9SKashyap Desai mrioc->init_cmds.callback = NULL; 3519023ab2a9SKashyap Desai init_completion(&mrioc->init_cmds.done); 3520023ab2a9SKashyap Desai } 3521023ab2a9SKashyap Desai pe_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 3522023ab2a9SKashyap Desai pe_req.function = MPI3_FUNCTION_PORT_ENABLE; 3523023ab2a9SKashyap Desai 3524023ab2a9SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &pe_req, sizeof(pe_req), 1); 3525023ab2a9SKashyap Desai if (retval) { 3526023ab2a9SKashyap Desai ioc_err(mrioc, "Issue PortEnable: Admin Post failed\n"); 3527023ab2a9SKashyap Desai goto out_unlock; 3528023ab2a9SKashyap Desai } 3529a6856cc4SSreekanth Reddy if (async) { 3530a6856cc4SSreekanth Reddy mutex_unlock(&mrioc->init_cmds.mutex); 3531a6856cc4SSreekanth Reddy goto out; 3532a6856cc4SSreekanth Reddy } 3533a6856cc4SSreekanth Reddy 3534a6856cc4SSreekanth Reddy wait_for_completion_timeout(&mrioc->init_cmds.done, (pe_timeout * HZ)); 3535023ab2a9SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 3536a6856cc4SSreekanth Reddy ioc_err(mrioc, "port enable timed out\n"); 3537023ab2a9SKashyap Desai retval = -1; 3538a6856cc4SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, MPI3MR_RESET_FROM_PE_TIMEOUT); 3539023ab2a9SKashyap Desai goto out_unlock; 3540023ab2a9SKashyap Desai } 3541023ab2a9SKashyap Desai mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds); 3542a6856cc4SSreekanth Reddy 3543023ab2a9SKashyap Desai out_unlock: 3544a6856cc4SSreekanth Reddy mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 3545023ab2a9SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 3546023ab2a9SKashyap Desai out: 3547023ab2a9SKashyap Desai return retval; 3548023ab2a9SKashyap Desai } 3549023ab2a9SKashyap Desai 3550ff9561e9SKashyap Desai /* Protocol type to name mapper structure */ 3551ff9561e9SKashyap Desai static const struct { 3552ff9561e9SKashyap Desai u8 protocol; 3553ff9561e9SKashyap Desai char *name; 3554ff9561e9SKashyap Desai } mpi3mr_protocols[] = { 3555ff9561e9SKashyap Desai { MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR, "Initiator" }, 3556ff9561e9SKashyap Desai { MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET, "Target" }, 3557ff9561e9SKashyap Desai { MPI3_IOCFACTS_PROTOCOL_NVME, "NVMe attachment" }, 3558ff9561e9SKashyap Desai }; 3559ff9561e9SKashyap Desai 3560ff9561e9SKashyap Desai /* Capability to name mapper structure*/ 3561ff9561e9SKashyap Desai static const struct { 3562ff9561e9SKashyap Desai u32 capability; 3563ff9561e9SKashyap Desai char *name; 3564ff9561e9SKashyap Desai } mpi3mr_capabilities[] = { 3565ff9561e9SKashyap Desai { MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE, "RAID" }, 3566c4723e68SSreekanth Reddy { MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED, "MultiPath" }, 3567ff9561e9SKashyap Desai }; 3568ff9561e9SKashyap Desai 3569ff9561e9SKashyap Desai /** 3570ff9561e9SKashyap Desai * mpi3mr_print_ioc_info - Display controller information 3571ff9561e9SKashyap Desai * @mrioc: Adapter instance reference 3572ff9561e9SKashyap Desai * 3573ff9561e9SKashyap Desai * Display controller personalit, capability, supported 3574ff9561e9SKashyap Desai * protocols etc. 3575ff9561e9SKashyap Desai * 3576ff9561e9SKashyap Desai * Return: Nothing 3577ff9561e9SKashyap Desai */ 3578ff9561e9SKashyap Desai static void 3579ff9561e9SKashyap Desai mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc) 3580ff9561e9SKashyap Desai { 358176a4f7ccSDan Carpenter int i = 0, bytes_written = 0; 3582ff9561e9SKashyap Desai char personality[16]; 3583ff9561e9SKashyap Desai char protocol[50] = {0}; 3584ff9561e9SKashyap Desai char capabilities[100] = {0}; 3585ff9561e9SKashyap Desai struct mpi3mr_compimg_ver *fwver = &mrioc->facts.fw_ver; 3586ff9561e9SKashyap Desai 3587ff9561e9SKashyap Desai switch (mrioc->facts.personality) { 3588ff9561e9SKashyap Desai case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA: 3589ff9561e9SKashyap Desai strncpy(personality, "Enhanced HBA", sizeof(personality)); 3590ff9561e9SKashyap Desai break; 3591ff9561e9SKashyap Desai case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR: 3592ff9561e9SKashyap Desai strncpy(personality, "RAID", sizeof(personality)); 3593ff9561e9SKashyap Desai break; 3594ff9561e9SKashyap Desai default: 3595ff9561e9SKashyap Desai strncpy(personality, "Unknown", sizeof(personality)); 3596ff9561e9SKashyap Desai break; 3597ff9561e9SKashyap Desai } 3598ff9561e9SKashyap Desai 3599ff9561e9SKashyap Desai ioc_info(mrioc, "Running in %s Personality", personality); 3600ff9561e9SKashyap Desai 3601ff9561e9SKashyap Desai ioc_info(mrioc, "FW version(%d.%d.%d.%d.%d.%d)\n", 3602ff9561e9SKashyap Desai fwver->gen_major, fwver->gen_minor, fwver->ph_major, 3603ff9561e9SKashyap Desai fwver->ph_minor, fwver->cust_id, fwver->build_num); 3604ff9561e9SKashyap Desai 3605ff9561e9SKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_protocols); i++) { 3606ff9561e9SKashyap Desai if (mrioc->facts.protocol_flags & 3607ff9561e9SKashyap Desai mpi3mr_protocols[i].protocol) { 360830e99f05SDan Carpenter bytes_written += scnprintf(protocol + bytes_written, 360976a4f7ccSDan Carpenter sizeof(protocol) - bytes_written, "%s%s", 361076a4f7ccSDan Carpenter bytes_written ? "," : "", 3611ff9561e9SKashyap Desai mpi3mr_protocols[i].name); 3612ff9561e9SKashyap Desai } 3613ff9561e9SKashyap Desai } 3614ff9561e9SKashyap Desai 361576a4f7ccSDan Carpenter bytes_written = 0; 3616ff9561e9SKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_capabilities); i++) { 3617ff9561e9SKashyap Desai if (mrioc->facts.protocol_flags & 3618ff9561e9SKashyap Desai mpi3mr_capabilities[i].capability) { 361930e99f05SDan Carpenter bytes_written += scnprintf(capabilities + bytes_written, 362076a4f7ccSDan Carpenter sizeof(capabilities) - bytes_written, "%s%s", 362176a4f7ccSDan Carpenter bytes_written ? "," : "", 3622ff9561e9SKashyap Desai mpi3mr_capabilities[i].name); 3623ff9561e9SKashyap Desai } 3624ff9561e9SKashyap Desai } 3625ff9561e9SKashyap Desai 3626ff9561e9SKashyap Desai ioc_info(mrioc, "Protocol=(%s), Capabilities=(%s)\n", 3627ff9561e9SKashyap Desai protocol, capabilities); 3628ff9561e9SKashyap Desai } 3629ff9561e9SKashyap Desai 3630023ab2a9SKashyap Desai /** 3631824a1566SKashyap Desai * mpi3mr_cleanup_resources - Free PCI resources 3632824a1566SKashyap Desai * @mrioc: Adapter instance reference 3633824a1566SKashyap Desai * 3634824a1566SKashyap Desai * Unmap PCI device memory and disable PCI device. 3635824a1566SKashyap Desai * 3636824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 3637824a1566SKashyap Desai */ 3638824a1566SKashyap Desai void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc) 3639824a1566SKashyap Desai { 3640824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 3641824a1566SKashyap Desai 3642824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 3643824a1566SKashyap Desai 3644824a1566SKashyap Desai if (mrioc->sysif_regs) { 3645824a1566SKashyap Desai iounmap((void __iomem *)mrioc->sysif_regs); 3646824a1566SKashyap Desai mrioc->sysif_regs = NULL; 3647824a1566SKashyap Desai } 3648824a1566SKashyap Desai 3649824a1566SKashyap Desai if (pci_is_enabled(pdev)) { 3650824a1566SKashyap Desai if (mrioc->bars) 3651824a1566SKashyap Desai pci_release_selected_regions(pdev, mrioc->bars); 3652824a1566SKashyap Desai pci_disable_device(pdev); 3653824a1566SKashyap Desai } 3654824a1566SKashyap Desai } 3655824a1566SKashyap Desai 3656824a1566SKashyap Desai /** 3657824a1566SKashyap Desai * mpi3mr_setup_resources - Enable PCI resources 3658824a1566SKashyap Desai * @mrioc: Adapter instance reference 3659824a1566SKashyap Desai * 3660824a1566SKashyap Desai * Enable PCI device memory, MSI-x registers and set DMA mask. 3661824a1566SKashyap Desai * 3662824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 3663824a1566SKashyap Desai */ 3664824a1566SKashyap Desai int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc) 3665824a1566SKashyap Desai { 3666824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 3667824a1566SKashyap Desai u32 memap_sz = 0; 3668824a1566SKashyap Desai int i, retval = 0, capb = 0; 3669824a1566SKashyap Desai u16 message_control; 3670824a1566SKashyap Desai u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask : 3671d347a951SSreekanth Reddy ((sizeof(dma_addr_t) > 4) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32)); 3672824a1566SKashyap Desai 3673824a1566SKashyap Desai if (pci_enable_device_mem(pdev)) { 3674824a1566SKashyap Desai ioc_err(mrioc, "pci_enable_device_mem: failed\n"); 3675824a1566SKashyap Desai retval = -ENODEV; 3676824a1566SKashyap Desai goto out_failed; 3677824a1566SKashyap Desai } 3678824a1566SKashyap Desai 3679824a1566SKashyap Desai capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX); 3680824a1566SKashyap Desai if (!capb) { 3681824a1566SKashyap Desai ioc_err(mrioc, "Unable to find MSI-X Capabilities\n"); 3682824a1566SKashyap Desai retval = -ENODEV; 3683824a1566SKashyap Desai goto out_failed; 3684824a1566SKashyap Desai } 3685824a1566SKashyap Desai mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); 3686824a1566SKashyap Desai 3687824a1566SKashyap Desai if (pci_request_selected_regions(pdev, mrioc->bars, 3688824a1566SKashyap Desai mrioc->driver_name)) { 3689824a1566SKashyap Desai ioc_err(mrioc, "pci_request_selected_regions: failed\n"); 3690824a1566SKashyap Desai retval = -ENODEV; 3691824a1566SKashyap Desai goto out_failed; 3692824a1566SKashyap Desai } 3693824a1566SKashyap Desai 3694824a1566SKashyap Desai for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) { 3695824a1566SKashyap Desai if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { 3696824a1566SKashyap Desai mrioc->sysif_regs_phys = pci_resource_start(pdev, i); 3697824a1566SKashyap Desai memap_sz = pci_resource_len(pdev, i); 3698824a1566SKashyap Desai mrioc->sysif_regs = 3699824a1566SKashyap Desai ioremap(mrioc->sysif_regs_phys, memap_sz); 3700824a1566SKashyap Desai break; 3701824a1566SKashyap Desai } 3702824a1566SKashyap Desai } 3703824a1566SKashyap Desai 3704824a1566SKashyap Desai pci_set_master(pdev); 3705824a1566SKashyap Desai 3706824a1566SKashyap Desai retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask); 3707824a1566SKashyap Desai if (retval) { 3708824a1566SKashyap Desai if (dma_mask != DMA_BIT_MASK(32)) { 3709824a1566SKashyap Desai ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n"); 3710824a1566SKashyap Desai dma_mask = DMA_BIT_MASK(32); 3711824a1566SKashyap Desai retval = dma_set_mask_and_coherent(&pdev->dev, 3712824a1566SKashyap Desai dma_mask); 3713824a1566SKashyap Desai } 3714824a1566SKashyap Desai if (retval) { 3715824a1566SKashyap Desai mrioc->dma_mask = 0; 3716824a1566SKashyap Desai ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n"); 3717824a1566SKashyap Desai goto out_failed; 3718824a1566SKashyap Desai } 3719824a1566SKashyap Desai } 3720824a1566SKashyap Desai mrioc->dma_mask = dma_mask; 3721824a1566SKashyap Desai 3722824a1566SKashyap Desai if (!mrioc->sysif_regs) { 3723824a1566SKashyap Desai ioc_err(mrioc, 3724824a1566SKashyap Desai "Unable to map adapter memory or resource not found\n"); 3725824a1566SKashyap Desai retval = -EINVAL; 3726824a1566SKashyap Desai goto out_failed; 3727824a1566SKashyap Desai } 3728824a1566SKashyap Desai 3729824a1566SKashyap Desai pci_read_config_word(pdev, capb + 2, &message_control); 3730824a1566SKashyap Desai mrioc->msix_count = (message_control & 0x3FF) + 1; 3731824a1566SKashyap Desai 3732824a1566SKashyap Desai pci_save_state(pdev); 3733824a1566SKashyap Desai 3734824a1566SKashyap Desai pci_set_drvdata(pdev, mrioc->shost); 3735824a1566SKashyap Desai 3736824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 3737824a1566SKashyap Desai 3738824a1566SKashyap Desai ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n", 3739824a1566SKashyap Desai (unsigned long long)mrioc->sysif_regs_phys, 3740824a1566SKashyap Desai mrioc->sysif_regs, memap_sz); 3741824a1566SKashyap Desai ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n", 3742824a1566SKashyap Desai mrioc->msix_count); 3743afd3a579SSreekanth Reddy 3744afd3a579SSreekanth Reddy if (!reset_devices && poll_queues > 0) 3745afd3a579SSreekanth Reddy mrioc->requested_poll_qcount = min_t(int, poll_queues, 3746afd3a579SSreekanth Reddy mrioc->msix_count - 2); 3747824a1566SKashyap Desai return retval; 3748824a1566SKashyap Desai 3749824a1566SKashyap Desai out_failed: 3750824a1566SKashyap Desai mpi3mr_cleanup_resources(mrioc); 3751824a1566SKashyap Desai return retval; 3752824a1566SKashyap Desai } 3753824a1566SKashyap Desai 3754824a1566SKashyap Desai /** 3755e3605f65SSreekanth Reddy * mpi3mr_enable_events - Enable required events 3756e3605f65SSreekanth Reddy * @mrioc: Adapter instance reference 3757e3605f65SSreekanth Reddy * 3758e3605f65SSreekanth Reddy * This routine unmasks the events required by the driver by 3759e3605f65SSreekanth Reddy * sennding appropriate event mask bitmapt through an event 3760e3605f65SSreekanth Reddy * notification request. 3761e3605f65SSreekanth Reddy * 3762e3605f65SSreekanth Reddy * Return: 0 on success and non-zero on failure. 3763e3605f65SSreekanth Reddy */ 3764e3605f65SSreekanth Reddy static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc) 3765e3605f65SSreekanth Reddy { 3766e3605f65SSreekanth Reddy int retval = 0; 3767e3605f65SSreekanth Reddy u32 i; 3768e3605f65SSreekanth Reddy 3769e3605f65SSreekanth Reddy for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 3770e3605f65SSreekanth Reddy mrioc->event_masks[i] = -1; 3771e3605f65SSreekanth Reddy 3772e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED); 3773e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED); 3774e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE); 3775e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE); 37767188c03fSSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_ADDED); 3777e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST); 3778e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY); 3779e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR); 3780e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE); 3781e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST); 3782e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION); 378378b76a07SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_PREPARE_FOR_RESET); 3784e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT); 3785e3605f65SSreekanth Reddy mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE); 3786e3605f65SSreekanth Reddy 3787e3605f65SSreekanth Reddy retval = mpi3mr_issue_event_notification(mrioc); 3788e3605f65SSreekanth Reddy if (retval) 3789e3605f65SSreekanth Reddy ioc_err(mrioc, "failed to issue event notification %d\n", 3790e3605f65SSreekanth Reddy retval); 3791e3605f65SSreekanth Reddy return retval; 3792e3605f65SSreekanth Reddy } 3793e3605f65SSreekanth Reddy 3794e3605f65SSreekanth Reddy /** 3795824a1566SKashyap Desai * mpi3mr_init_ioc - Initialize the controller 3796824a1566SKashyap Desai * @mrioc: Adapter instance reference 3797824a1566SKashyap Desai * 3798824a1566SKashyap Desai * This the controller initialization routine, executed either 3799824a1566SKashyap Desai * after soft reset or from pci probe callback. 3800824a1566SKashyap Desai * Setup the required resources, memory map the controller 3801824a1566SKashyap Desai * registers, create admin and operational reply queue pairs, 3802824a1566SKashyap Desai * allocate required memory for reply pool, sense buffer pool, 3803824a1566SKashyap Desai * issue IOC init request to the firmware, unmask the events and 3804824a1566SKashyap Desai * issue port enable to discover SAS/SATA/NVMe devies and RAID 3805824a1566SKashyap Desai * volumes. 3806824a1566SKashyap Desai * 3807824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 3808824a1566SKashyap Desai */ 3809fe6db615SSreekanth Reddy int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc) 3810824a1566SKashyap Desai { 3811824a1566SKashyap Desai int retval = 0; 3812fe6db615SSreekanth Reddy u8 retry = 0; 3813824a1566SKashyap Desai struct mpi3_ioc_facts_data facts_data; 3814f10af057SSreekanth Reddy u32 sz; 3815824a1566SKashyap Desai 3816fe6db615SSreekanth Reddy retry_init: 3817824a1566SKashyap Desai retval = mpi3mr_bring_ioc_ready(mrioc); 3818824a1566SKashyap Desai if (retval) { 3819824a1566SKashyap Desai ioc_err(mrioc, "Failed to bring ioc ready: error %d\n", 3820824a1566SKashyap Desai retval); 3821fe6db615SSreekanth Reddy goto out_failed_noretry; 3822824a1566SKashyap Desai } 3823824a1566SKashyap Desai 3824824a1566SKashyap Desai retval = mpi3mr_setup_isr(mrioc, 1); 3825824a1566SKashyap Desai if (retval) { 3826824a1566SKashyap Desai ioc_err(mrioc, "Failed to setup ISR error %d\n", 3827824a1566SKashyap Desai retval); 3828fe6db615SSreekanth Reddy goto out_failed_noretry; 3829824a1566SKashyap Desai } 3830824a1566SKashyap Desai 3831824a1566SKashyap Desai retval = mpi3mr_issue_iocfacts(mrioc, &facts_data); 3832824a1566SKashyap Desai if (retval) { 3833824a1566SKashyap Desai ioc_err(mrioc, "Failed to Issue IOC Facts %d\n", 3834824a1566SKashyap Desai retval); 3835824a1566SKashyap Desai goto out_failed; 3836824a1566SKashyap Desai } 3837824a1566SKashyap Desai 3838c5758fc7SSreekanth Reddy mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD; 3839d9adb81eSRanjan Kumar mrioc->shost->max_sectors = mrioc->facts.max_data_length / 512; 3840f10af057SSreekanth Reddy mrioc->num_io_throttle_group = mrioc->facts.max_io_throttle_group; 3841f10af057SSreekanth Reddy atomic_set(&mrioc->pend_large_data_sz, 0); 3842f10af057SSreekanth Reddy 3843c5758fc7SSreekanth Reddy if (reset_devices) 3844c5758fc7SSreekanth Reddy mrioc->max_host_ios = min_t(int, mrioc->max_host_ios, 3845c5758fc7SSreekanth Reddy MPI3MR_HOST_IOS_KDUMP); 3846c5758fc7SSreekanth Reddy 3847c4723e68SSreekanth Reddy if (!(mrioc->facts.ioc_capabilities & 3848c4723e68SSreekanth Reddy MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED)) { 3849c4723e68SSreekanth Reddy mrioc->sas_transport_enabled = 1; 3850626665e9SSreekanth Reddy mrioc->scsi_device_channel = 1; 3851626665e9SSreekanth Reddy mrioc->shost->max_channel = 1; 3852176d4aa6SSreekanth Reddy mrioc->shost->transportt = mpi3mr_transport_template; 3853c4723e68SSreekanth Reddy } 3854c4723e68SSreekanth Reddy 3855c5758fc7SSreekanth Reddy mrioc->reply_sz = mrioc->facts.reply_sz; 3856fe6db615SSreekanth Reddy 3857824a1566SKashyap Desai retval = mpi3mr_check_reset_dma_mask(mrioc); 3858824a1566SKashyap Desai if (retval) { 3859824a1566SKashyap Desai ioc_err(mrioc, "Resetting dma mask failed %d\n", 3860824a1566SKashyap Desai retval); 3861fe6db615SSreekanth Reddy goto out_failed_noretry; 3862fb9b0457SKashyap Desai } 3863824a1566SKashyap Desai 3864ff9561e9SKashyap Desai mpi3mr_print_ioc_info(mrioc); 3865ff9561e9SKashyap Desai 3866c7983044STomas Henzl if (!mrioc->cfg_page) { 386732d457d5SSreekanth Reddy dprint_init(mrioc, "allocating config page buffers\n"); 3868c7983044STomas Henzl mrioc->cfg_page_sz = MPI3MR_DEFAULT_CFG_PAGE_SZ; 386932d457d5SSreekanth Reddy mrioc->cfg_page = dma_alloc_coherent(&mrioc->pdev->dev, 3870c7983044STomas Henzl mrioc->cfg_page_sz, &mrioc->cfg_page_dma, GFP_KERNEL); 3871ba8a9ba4SRanjan Kumar if (!mrioc->cfg_page) { 3872ba8a9ba4SRanjan Kumar retval = -1; 387332d457d5SSreekanth Reddy goto out_failed_noretry; 3874ba8a9ba4SRanjan Kumar } 3875c7983044STomas Henzl } 387632d457d5SSreekanth Reddy 3877c7983044STomas Henzl if (!mrioc->init_cmds.reply) { 3878824a1566SKashyap Desai retval = mpi3mr_alloc_reply_sense_bufs(mrioc); 3879824a1566SKashyap Desai if (retval) { 3880824a1566SKashyap Desai ioc_err(mrioc, 3881824a1566SKashyap Desai "%s :Failed to allocated reply sense buffers %d\n", 3882824a1566SKashyap Desai __func__, retval); 3883fe6db615SSreekanth Reddy goto out_failed_noretry; 3884824a1566SKashyap Desai } 3885c7983044STomas Henzl } 3886824a1566SKashyap Desai 3887c7983044STomas Henzl if (!mrioc->chain_sgl_list) { 3888824a1566SKashyap Desai retval = mpi3mr_alloc_chain_bufs(mrioc); 3889824a1566SKashyap Desai if (retval) { 3890824a1566SKashyap Desai ioc_err(mrioc, "Failed to allocated chain buffers %d\n", 3891824a1566SKashyap Desai retval); 3892fe6db615SSreekanth Reddy goto out_failed_noretry; 3893fb9b0457SKashyap Desai } 3894c7983044STomas Henzl } 3895824a1566SKashyap Desai 3896824a1566SKashyap Desai retval = mpi3mr_issue_iocinit(mrioc); 3897824a1566SKashyap Desai if (retval) { 3898824a1566SKashyap Desai ioc_err(mrioc, "Failed to Issue IOC Init %d\n", 3899824a1566SKashyap Desai retval); 3900824a1566SKashyap Desai goto out_failed; 3901824a1566SKashyap Desai } 3902824a1566SKashyap Desai 39032ac794baSSreekanth Reddy retval = mpi3mr_print_pkg_ver(mrioc); 39042ac794baSSreekanth Reddy if (retval) { 39052ac794baSSreekanth Reddy ioc_err(mrioc, "failed to get package version\n"); 39062ac794baSSreekanth Reddy goto out_failed; 39072ac794baSSreekanth Reddy } 39082ac794baSSreekanth Reddy 3909824a1566SKashyap Desai retval = mpi3mr_setup_isr(mrioc, 0); 3910824a1566SKashyap Desai if (retval) { 3911824a1566SKashyap Desai ioc_err(mrioc, "Failed to re-setup ISR, error %d\n", 3912824a1566SKashyap Desai retval); 3913fe6db615SSreekanth Reddy goto out_failed_noretry; 3914fb9b0457SKashyap Desai } 3915824a1566SKashyap Desai 3916c9566231SKashyap Desai retval = mpi3mr_create_op_queues(mrioc); 3917c9566231SKashyap Desai if (retval) { 3918c9566231SKashyap Desai ioc_err(mrioc, "Failed to create OpQueues error %d\n", 3919c9566231SKashyap Desai retval); 3920c9566231SKashyap Desai goto out_failed; 3921c9566231SKashyap Desai } 3922c9566231SKashyap Desai 392343ca1100SSumit Saxena if (!mrioc->pel_seqnum_virt) { 392443ca1100SSumit Saxena dprint_init(mrioc, "allocating memory for pel_seqnum_virt\n"); 392543ca1100SSumit Saxena mrioc->pel_seqnum_sz = sizeof(struct mpi3_pel_seq); 392643ca1100SSumit Saxena mrioc->pel_seqnum_virt = dma_alloc_coherent(&mrioc->pdev->dev, 392743ca1100SSumit Saxena mrioc->pel_seqnum_sz, &mrioc->pel_seqnum_dma, 392843ca1100SSumit Saxena GFP_KERNEL); 3929bc7896d3SDan Carpenter if (!mrioc->pel_seqnum_virt) { 3930bc7896d3SDan Carpenter retval = -ENOMEM; 393143ca1100SSumit Saxena goto out_failed_noretry; 393243ca1100SSumit Saxena } 3933bc7896d3SDan Carpenter } 393443ca1100SSumit Saxena 3935f10af057SSreekanth Reddy if (!mrioc->throttle_groups && mrioc->num_io_throttle_group) { 3936f10af057SSreekanth Reddy dprint_init(mrioc, "allocating memory for throttle groups\n"); 3937f10af057SSreekanth Reddy sz = sizeof(struct mpi3mr_throttle_group_info); 3938c863a2dcSJules Irenge mrioc->throttle_groups = kcalloc(mrioc->num_io_throttle_group, sz, GFP_KERNEL); 3939ba8a9ba4SRanjan Kumar if (!mrioc->throttle_groups) { 3940ba8a9ba4SRanjan Kumar retval = -1; 3941f10af057SSreekanth Reddy goto out_failed_noretry; 3942f10af057SSreekanth Reddy } 3943ba8a9ba4SRanjan Kumar } 3944f10af057SSreekanth Reddy 3945e3605f65SSreekanth Reddy retval = mpi3mr_enable_events(mrioc); 394613ef29eaSKashyap Desai if (retval) { 3947e3605f65SSreekanth Reddy ioc_err(mrioc, "failed to enable events %d\n", 394813ef29eaSKashyap Desai retval); 394913ef29eaSKashyap Desai goto out_failed; 395013ef29eaSKashyap Desai } 395113ef29eaSKashyap Desai 3952fe6db615SSreekanth Reddy ioc_info(mrioc, "controller initialization completed successfully\n"); 3953824a1566SKashyap Desai return retval; 3954824a1566SKashyap Desai out_failed: 3955fe6db615SSreekanth Reddy if (retry < 2) { 3956fe6db615SSreekanth Reddy retry++; 3957fe6db615SSreekanth Reddy ioc_warn(mrioc, "retrying controller initialization, retry_count:%d\n", 3958fe6db615SSreekanth Reddy retry); 3959fe6db615SSreekanth Reddy mpi3mr_memset_buffers(mrioc); 3960fe6db615SSreekanth Reddy goto retry_init; 3961fe6db615SSreekanth Reddy } 3962ba8a9ba4SRanjan Kumar retval = -1; 3963fe6db615SSreekanth Reddy out_failed_noretry: 3964fe6db615SSreekanth Reddy ioc_err(mrioc, "controller initialization failed\n"); 3965fe6db615SSreekanth Reddy mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 3966fe6db615SSreekanth Reddy MPI3MR_RESET_FROM_CTLR_CLEANUP); 3967fe6db615SSreekanth Reddy mrioc->unrecoverable = 1; 3968824a1566SKashyap Desai return retval; 3969824a1566SKashyap Desai } 3970824a1566SKashyap Desai 3971c0b00a93SSreekanth Reddy /** 3972c0b00a93SSreekanth Reddy * mpi3mr_reinit_ioc - Re-Initialize the controller 3973c0b00a93SSreekanth Reddy * @mrioc: Adapter instance reference 3974c0b00a93SSreekanth Reddy * @is_resume: Called from resume or reset path 3975c0b00a93SSreekanth Reddy * 3976c0b00a93SSreekanth Reddy * This the controller re-initialization routine, executed from 3977c0b00a93SSreekanth Reddy * the soft reset handler or resume callback. Creates 3978c0b00a93SSreekanth Reddy * operational reply queue pairs, allocate required memory for 3979c0b00a93SSreekanth Reddy * reply pool, sense buffer pool, issue IOC init request to the 3980c0b00a93SSreekanth Reddy * firmware, unmask the events and issue port enable to discover 3981c0b00a93SSreekanth Reddy * SAS/SATA/NVMe devices and RAID volumes. 3982c0b00a93SSreekanth Reddy * 3983c0b00a93SSreekanth Reddy * Return: 0 on success and non-zero on failure. 3984c0b00a93SSreekanth Reddy */ 3985fe6db615SSreekanth Reddy int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume) 3986fe6db615SSreekanth Reddy { 3987c0b00a93SSreekanth Reddy int retval = 0; 3988c0b00a93SSreekanth Reddy u8 retry = 0; 3989c0b00a93SSreekanth Reddy struct mpi3_ioc_facts_data facts_data; 3990f2a79d20SSreekanth Reddy u32 pe_timeout, ioc_status; 3991fe6db615SSreekanth Reddy 3992c0b00a93SSreekanth Reddy retry_init: 3993f2a79d20SSreekanth Reddy pe_timeout = 3994f2a79d20SSreekanth Reddy (MPI3MR_PORTENABLE_TIMEOUT / MPI3MR_PORTENABLE_POLL_INTERVAL); 3995f2a79d20SSreekanth Reddy 3996c0b00a93SSreekanth Reddy dprint_reset(mrioc, "bringing up the controller to ready state\n"); 3997c0b00a93SSreekanth Reddy retval = mpi3mr_bring_ioc_ready(mrioc); 3998c0b00a93SSreekanth Reddy if (retval) { 3999c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to bring to ready state\n"); 4000c0b00a93SSreekanth Reddy goto out_failed_noretry; 4001c0b00a93SSreekanth Reddy } 4002c0b00a93SSreekanth Reddy 4003c0b00a93SSreekanth Reddy if (is_resume) { 4004c0b00a93SSreekanth Reddy dprint_reset(mrioc, "setting up single ISR\n"); 4005c0b00a93SSreekanth Reddy retval = mpi3mr_setup_isr(mrioc, 1); 4006c0b00a93SSreekanth Reddy if (retval) { 4007c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to setup ISR\n"); 4008c0b00a93SSreekanth Reddy goto out_failed_noretry; 4009c0b00a93SSreekanth Reddy } 4010c0b00a93SSreekanth Reddy } else 4011c0b00a93SSreekanth Reddy mpi3mr_ioc_enable_intr(mrioc); 4012c0b00a93SSreekanth Reddy 4013c0b00a93SSreekanth Reddy dprint_reset(mrioc, "getting ioc_facts\n"); 4014c0b00a93SSreekanth Reddy retval = mpi3mr_issue_iocfacts(mrioc, &facts_data); 4015c0b00a93SSreekanth Reddy if (retval) { 4016c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to get ioc_facts\n"); 4017c0b00a93SSreekanth Reddy goto out_failed; 4018c0b00a93SSreekanth Reddy } 4019c0b00a93SSreekanth Reddy 4020c5758fc7SSreekanth Reddy dprint_reset(mrioc, "validating ioc_facts\n"); 4021c5758fc7SSreekanth Reddy retval = mpi3mr_revalidate_factsdata(mrioc); 4022c5758fc7SSreekanth Reddy if (retval) { 4023c5758fc7SSreekanth Reddy ioc_err(mrioc, "failed to revalidate ioc_facts data\n"); 4024c5758fc7SSreekanth Reddy goto out_failed_noretry; 4025c5758fc7SSreekanth Reddy } 4026c0b00a93SSreekanth Reddy 4027c0b00a93SSreekanth Reddy mpi3mr_print_ioc_info(mrioc); 4028c0b00a93SSreekanth Reddy 4029c0b00a93SSreekanth Reddy dprint_reset(mrioc, "sending ioc_init\n"); 4030c0b00a93SSreekanth Reddy retval = mpi3mr_issue_iocinit(mrioc); 4031c0b00a93SSreekanth Reddy if (retval) { 4032c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to send ioc_init\n"); 4033c0b00a93SSreekanth Reddy goto out_failed; 4034c0b00a93SSreekanth Reddy } 4035c0b00a93SSreekanth Reddy 4036c0b00a93SSreekanth Reddy dprint_reset(mrioc, "getting package version\n"); 4037c0b00a93SSreekanth Reddy retval = mpi3mr_print_pkg_ver(mrioc); 4038c0b00a93SSreekanth Reddy if (retval) { 4039c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to get package version\n"); 4040c0b00a93SSreekanth Reddy goto out_failed; 4041c0b00a93SSreekanth Reddy } 4042c0b00a93SSreekanth Reddy 4043c0b00a93SSreekanth Reddy if (is_resume) { 4044c0b00a93SSreekanth Reddy dprint_reset(mrioc, "setting up multiple ISR\n"); 4045c0b00a93SSreekanth Reddy retval = mpi3mr_setup_isr(mrioc, 0); 4046c0b00a93SSreekanth Reddy if (retval) { 4047c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to re-setup ISR\n"); 4048c0b00a93SSreekanth Reddy goto out_failed_noretry; 4049c0b00a93SSreekanth Reddy } 4050c0b00a93SSreekanth Reddy } 4051c0b00a93SSreekanth Reddy 4052c0b00a93SSreekanth Reddy dprint_reset(mrioc, "creating operational queue pairs\n"); 4053c0b00a93SSreekanth Reddy retval = mpi3mr_create_op_queues(mrioc); 4054c0b00a93SSreekanth Reddy if (retval) { 4055c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to create operational queue pairs\n"); 4056c0b00a93SSreekanth Reddy goto out_failed; 4057c0b00a93SSreekanth Reddy } 4058c0b00a93SSreekanth Reddy 405943ca1100SSumit Saxena if (!mrioc->pel_seqnum_virt) { 406043ca1100SSumit Saxena dprint_reset(mrioc, "allocating memory for pel_seqnum_virt\n"); 406143ca1100SSumit Saxena mrioc->pel_seqnum_sz = sizeof(struct mpi3_pel_seq); 406243ca1100SSumit Saxena mrioc->pel_seqnum_virt = dma_alloc_coherent(&mrioc->pdev->dev, 406343ca1100SSumit Saxena mrioc->pel_seqnum_sz, &mrioc->pel_seqnum_dma, 406443ca1100SSumit Saxena GFP_KERNEL); 4065bc7896d3SDan Carpenter if (!mrioc->pel_seqnum_virt) { 4066bc7896d3SDan Carpenter retval = -ENOMEM; 406743ca1100SSumit Saxena goto out_failed_noretry; 406843ca1100SSumit Saxena } 4069bc7896d3SDan Carpenter } 407043ca1100SSumit Saxena 4071c0b00a93SSreekanth Reddy if (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q) { 4072c0b00a93SSreekanth Reddy ioc_err(mrioc, 40735867b856SColin Ian King "cannot create minimum number of operational queues expected:%d created:%d\n", 4074c0b00a93SSreekanth Reddy mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q); 4075ba8a9ba4SRanjan Kumar retval = -1; 4076c0b00a93SSreekanth Reddy goto out_failed_noretry; 4077c0b00a93SSreekanth Reddy } 4078c0b00a93SSreekanth Reddy 4079c0b00a93SSreekanth Reddy dprint_reset(mrioc, "enabling events\n"); 4080c0b00a93SSreekanth Reddy retval = mpi3mr_enable_events(mrioc); 4081c0b00a93SSreekanth Reddy if (retval) { 4082c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to enable events\n"); 4083c0b00a93SSreekanth Reddy goto out_failed; 4084c0b00a93SSreekanth Reddy } 4085c0b00a93SSreekanth Reddy 40862745ce0eSSreekanth Reddy mrioc->device_refresh_on = 1; 40872745ce0eSSreekanth Reddy mpi3mr_add_event_wait_for_device_refresh(mrioc); 40882745ce0eSSreekanth Reddy 4089c0b00a93SSreekanth Reddy ioc_info(mrioc, "sending port enable\n"); 4090f2a79d20SSreekanth Reddy retval = mpi3mr_issue_port_enable(mrioc, 1); 4091c0b00a93SSreekanth Reddy if (retval) { 4092c0b00a93SSreekanth Reddy ioc_err(mrioc, "failed to issue port enable\n"); 4093c0b00a93SSreekanth Reddy goto out_failed; 4094c0b00a93SSreekanth Reddy } 4095f2a79d20SSreekanth Reddy do { 4096f2a79d20SSreekanth Reddy ssleep(MPI3MR_PORTENABLE_POLL_INTERVAL); 4097f2a79d20SSreekanth Reddy if (mrioc->init_cmds.state == MPI3MR_CMD_NOTUSED) 4098f2a79d20SSreekanth Reddy break; 4099f2a79d20SSreekanth Reddy if (!pci_device_is_present(mrioc->pdev)) 4100f2a79d20SSreekanth Reddy mrioc->unrecoverable = 1; 4101f2a79d20SSreekanth Reddy if (mrioc->unrecoverable) { 4102f2a79d20SSreekanth Reddy retval = -1; 4103f2a79d20SSreekanth Reddy goto out_failed_noretry; 4104f2a79d20SSreekanth Reddy } 4105f2a79d20SSreekanth Reddy ioc_status = readl(&mrioc->sysif_regs->ioc_status); 4106f2a79d20SSreekanth Reddy if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) || 4107f2a79d20SSreekanth Reddy (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) { 4108f2a79d20SSreekanth Reddy mpi3mr_print_fault_info(mrioc); 4109f2a79d20SSreekanth Reddy mrioc->init_cmds.is_waiting = 0; 4110f2a79d20SSreekanth Reddy mrioc->init_cmds.callback = NULL; 4111f2a79d20SSreekanth Reddy mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 4112f2a79d20SSreekanth Reddy goto out_failed; 4113f2a79d20SSreekanth Reddy } 4114f2a79d20SSreekanth Reddy } while (--pe_timeout); 4115f2a79d20SSreekanth Reddy 4116f2a79d20SSreekanth Reddy if (!pe_timeout) { 4117f2a79d20SSreekanth Reddy ioc_err(mrioc, "port enable timed out\n"); 4118f2a79d20SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 4119f2a79d20SSreekanth Reddy MPI3MR_RESET_FROM_PE_TIMEOUT); 4120f2a79d20SSreekanth Reddy mrioc->init_cmds.is_waiting = 0; 4121f2a79d20SSreekanth Reddy mrioc->init_cmds.callback = NULL; 4122f2a79d20SSreekanth Reddy mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 4123f2a79d20SSreekanth Reddy goto out_failed; 4124f2a79d20SSreekanth Reddy } else if (mrioc->scan_failed) { 4125f2a79d20SSreekanth Reddy ioc_err(mrioc, 4126f2a79d20SSreekanth Reddy "port enable failed with status=0x%04x\n", 4127f2a79d20SSreekanth Reddy mrioc->scan_failed); 4128f2a79d20SSreekanth Reddy } else 4129f2a79d20SSreekanth Reddy ioc_info(mrioc, "port enable completed successfully\n"); 4130c0b00a93SSreekanth Reddy 4131c0b00a93SSreekanth Reddy ioc_info(mrioc, "controller %s completed successfully\n", 4132c0b00a93SSreekanth Reddy (is_resume)?"resume":"re-initialization"); 4133c0b00a93SSreekanth Reddy return retval; 4134c0b00a93SSreekanth Reddy out_failed: 4135c0b00a93SSreekanth Reddy if (retry < 2) { 4136c0b00a93SSreekanth Reddy retry++; 4137c0b00a93SSreekanth Reddy ioc_warn(mrioc, "retrying controller %s, retry_count:%d\n", 4138c0b00a93SSreekanth Reddy (is_resume)?"resume":"re-initialization", retry); 4139c0b00a93SSreekanth Reddy mpi3mr_memset_buffers(mrioc); 4140c0b00a93SSreekanth Reddy goto retry_init; 4141c0b00a93SSreekanth Reddy } 4142ba8a9ba4SRanjan Kumar retval = -1; 4143c0b00a93SSreekanth Reddy out_failed_noretry: 4144c0b00a93SSreekanth Reddy ioc_err(mrioc, "controller %s is failed\n", 4145c0b00a93SSreekanth Reddy (is_resume)?"resume":"re-initialization"); 4146c0b00a93SSreekanth Reddy mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 4147c0b00a93SSreekanth Reddy MPI3MR_RESET_FROM_CTLR_CLEANUP); 4148c0b00a93SSreekanth Reddy mrioc->unrecoverable = 1; 4149c0b00a93SSreekanth Reddy return retval; 4150fe6db615SSreekanth Reddy } 4151fe6db615SSreekanth Reddy 4152824a1566SKashyap Desai /** 4153fb9b0457SKashyap Desai * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's 4154fb9b0457SKashyap Desai * segments 4155fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 4156fb9b0457SKashyap Desai * @qidx: Operational reply queue index 4157fb9b0457SKashyap Desai * 4158fb9b0457SKashyap Desai * Return: Nothing. 4159fb9b0457SKashyap Desai */ 4160fb9b0457SKashyap Desai static void mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx) 4161fb9b0457SKashyap Desai { 4162fb9b0457SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 4163fb9b0457SKashyap Desai struct segments *segments; 4164fb9b0457SKashyap Desai int i, size; 4165fb9b0457SKashyap Desai 4166fb9b0457SKashyap Desai if (!op_reply_q->q_segments) 4167fb9b0457SKashyap Desai return; 4168fb9b0457SKashyap Desai 4169fb9b0457SKashyap Desai size = op_reply_q->segment_qd * mrioc->op_reply_desc_sz; 4170fb9b0457SKashyap Desai segments = op_reply_q->q_segments; 4171fb9b0457SKashyap Desai for (i = 0; i < op_reply_q->num_segments; i++) 4172fb9b0457SKashyap Desai memset(segments[i].segment, 0, size); 4173fb9b0457SKashyap Desai } 4174fb9b0457SKashyap Desai 4175fb9b0457SKashyap Desai /** 4176fb9b0457SKashyap Desai * mpi3mr_memset_op_req_q_buffers - memset the operational request queue's 4177fb9b0457SKashyap Desai * segments 4178fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 4179fb9b0457SKashyap Desai * @qidx: Operational request queue index 4180fb9b0457SKashyap Desai * 4181fb9b0457SKashyap Desai * Return: Nothing. 4182fb9b0457SKashyap Desai */ 4183fb9b0457SKashyap Desai static void mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx) 4184fb9b0457SKashyap Desai { 4185fb9b0457SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx; 4186fb9b0457SKashyap Desai struct segments *segments; 4187fb9b0457SKashyap Desai int i, size; 4188fb9b0457SKashyap Desai 4189fb9b0457SKashyap Desai if (!op_req_q->q_segments) 4190fb9b0457SKashyap Desai return; 4191fb9b0457SKashyap Desai 4192fb9b0457SKashyap Desai size = op_req_q->segment_qd * mrioc->facts.op_req_sz; 4193fb9b0457SKashyap Desai segments = op_req_q->q_segments; 4194fb9b0457SKashyap Desai for (i = 0; i < op_req_q->num_segments; i++) 4195fb9b0457SKashyap Desai memset(segments[i].segment, 0, size); 4196fb9b0457SKashyap Desai } 4197fb9b0457SKashyap Desai 4198fb9b0457SKashyap Desai /** 4199fb9b0457SKashyap Desai * mpi3mr_memset_buffers - memset memory for a controller 4200fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 4201fb9b0457SKashyap Desai * 4202fb9b0457SKashyap Desai * clear all the memory allocated for a controller, typically 4203fb9b0457SKashyap Desai * called post reset to reuse the memory allocated during the 4204fb9b0457SKashyap Desai * controller init. 4205fb9b0457SKashyap Desai * 4206fb9b0457SKashyap Desai * Return: Nothing. 4207fb9b0457SKashyap Desai */ 42080da66348SKashyap Desai void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) 4209fb9b0457SKashyap Desai { 4210fb9b0457SKashyap Desai u16 i; 4211f10af057SSreekanth Reddy struct mpi3mr_throttle_group_info *tg; 4212fb9b0457SKashyap Desai 4213fe6db615SSreekanth Reddy mrioc->change_count = 0; 4214afd3a579SSreekanth Reddy mrioc->active_poll_qcount = 0; 4215afd3a579SSreekanth Reddy mrioc->default_qcount = 0; 4216fe6db615SSreekanth Reddy if (mrioc->admin_req_base) 4217fb9b0457SKashyap Desai memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz); 4218fe6db615SSreekanth Reddy if (mrioc->admin_reply_base) 4219fb9b0457SKashyap Desai memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz); 422002ca7da2SRanjan Kumar atomic_set(&mrioc->admin_reply_q_in_use, 0); 4221fb9b0457SKashyap Desai 4222fe6db615SSreekanth Reddy if (mrioc->init_cmds.reply) { 4223fb9b0457SKashyap Desai memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply)); 4224f5e6d5a3SSumit Saxena memset(mrioc->bsg_cmds.reply, 0, 4225f5e6d5a3SSumit Saxena sizeof(*mrioc->bsg_cmds.reply)); 4226e844adb1SKashyap Desai memset(mrioc->host_tm_cmds.reply, 0, 4227e844adb1SKashyap Desai sizeof(*mrioc->host_tm_cmds.reply)); 422843ca1100SSumit Saxena memset(mrioc->pel_cmds.reply, 0, 422943ca1100SSumit Saxena sizeof(*mrioc->pel_cmds.reply)); 423043ca1100SSumit Saxena memset(mrioc->pel_abort_cmd.reply, 0, 423143ca1100SSumit Saxena sizeof(*mrioc->pel_abort_cmd.reply)); 42322bd37e28SSreekanth Reddy memset(mrioc->transport_cmds.reply, 0, 42332bd37e28SSreekanth Reddy sizeof(*mrioc->transport_cmds.reply)); 4234fb9b0457SKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) 4235fb9b0457SKashyap Desai memset(mrioc->dev_rmhs_cmds[i].reply, 0, 4236fb9b0457SKashyap Desai sizeof(*mrioc->dev_rmhs_cmds[i].reply)); 4237c1af985dSSreekanth Reddy for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) 4238c1af985dSSreekanth Reddy memset(mrioc->evtack_cmds[i].reply, 0, 4239c1af985dSSreekanth Reddy sizeof(*mrioc->evtack_cmds[i].reply)); 4240339e6156SShin'ichiro Kawasaki bitmap_clear(mrioc->removepend_bitmap, 0, 4241339e6156SShin'ichiro Kawasaki mrioc->dev_handle_bitmap_bits); 4242339e6156SShin'ichiro Kawasaki bitmap_clear(mrioc->devrem_bitmap, 0, MPI3MR_NUM_DEVRMCMD); 4243339e6156SShin'ichiro Kawasaki bitmap_clear(mrioc->evtack_cmds_bitmap, 0, 4244339e6156SShin'ichiro Kawasaki MPI3MR_NUM_EVTACKCMD); 4245fe6db615SSreekanth Reddy } 4246fb9b0457SKashyap Desai 4247fb9b0457SKashyap Desai for (i = 0; i < mrioc->num_queues; i++) { 4248fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].qid = 0; 4249fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].ci = 0; 4250fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].num_replies = 0; 4251fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].ephase = 0; 4252463429f8SKashyap Desai atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0); 4253463429f8SKashyap Desai atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0); 4254fb9b0457SKashyap Desai mpi3mr_memset_op_reply_q_buffers(mrioc, i); 4255fb9b0457SKashyap Desai 4256fb9b0457SKashyap Desai mrioc->req_qinfo[i].ci = 0; 4257fb9b0457SKashyap Desai mrioc->req_qinfo[i].pi = 0; 4258fb9b0457SKashyap Desai mrioc->req_qinfo[i].num_requests = 0; 4259fb9b0457SKashyap Desai mrioc->req_qinfo[i].qid = 0; 4260fb9b0457SKashyap Desai mrioc->req_qinfo[i].reply_qid = 0; 4261fb9b0457SKashyap Desai spin_lock_init(&mrioc->req_qinfo[i].q_lock); 4262fb9b0457SKashyap Desai mpi3mr_memset_op_req_q_buffers(mrioc, i); 4263fb9b0457SKashyap Desai } 4264f10af057SSreekanth Reddy 4265f10af057SSreekanth Reddy atomic_set(&mrioc->pend_large_data_sz, 0); 4266f10af057SSreekanth Reddy if (mrioc->throttle_groups) { 4267f10af057SSreekanth Reddy tg = mrioc->throttle_groups; 4268f10af057SSreekanth Reddy for (i = 0; i < mrioc->num_io_throttle_group; i++, tg++) { 4269f10af057SSreekanth Reddy tg->id = 0; 4270cf1ce8b7SSreekanth Reddy tg->fw_qd = 0; 4271cf1ce8b7SSreekanth Reddy tg->modified_qd = 0; 4272f10af057SSreekanth Reddy tg->io_divert = 0; 4273cf1ce8b7SSreekanth Reddy tg->need_qd_reduction = 0; 4274f10af057SSreekanth Reddy tg->high = 0; 4275f10af057SSreekanth Reddy tg->low = 0; 4276cf1ce8b7SSreekanth Reddy tg->qd_reduction = 0; 4277f10af057SSreekanth Reddy atomic_set(&tg->pend_large_data_sz, 0); 4278f10af057SSreekanth Reddy } 4279f10af057SSreekanth Reddy } 4280fb9b0457SKashyap Desai } 4281fb9b0457SKashyap Desai 4282fb9b0457SKashyap Desai /** 4283824a1566SKashyap Desai * mpi3mr_free_mem - Free memory allocated for a controller 4284824a1566SKashyap Desai * @mrioc: Adapter instance reference 4285824a1566SKashyap Desai * 4286824a1566SKashyap Desai * Free all the memory allocated for a controller. 4287824a1566SKashyap Desai * 4288824a1566SKashyap Desai * Return: Nothing. 4289824a1566SKashyap Desai */ 4290fe6db615SSreekanth Reddy void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) 4291824a1566SKashyap Desai { 4292824a1566SKashyap Desai u16 i; 4293824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info; 4294824a1566SKashyap Desai 4295130fc180SSreekanth Reddy mpi3mr_free_enclosure_list(mrioc); 4296130fc180SSreekanth Reddy 4297824a1566SKashyap Desai if (mrioc->sense_buf_pool) { 4298824a1566SKashyap Desai if (mrioc->sense_buf) 4299824a1566SKashyap Desai dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf, 4300824a1566SKashyap Desai mrioc->sense_buf_dma); 4301824a1566SKashyap Desai dma_pool_destroy(mrioc->sense_buf_pool); 4302824a1566SKashyap Desai mrioc->sense_buf = NULL; 4303824a1566SKashyap Desai mrioc->sense_buf_pool = NULL; 4304824a1566SKashyap Desai } 4305824a1566SKashyap Desai if (mrioc->sense_buf_q_pool) { 4306824a1566SKashyap Desai if (mrioc->sense_buf_q) 4307824a1566SKashyap Desai dma_pool_free(mrioc->sense_buf_q_pool, 4308824a1566SKashyap Desai mrioc->sense_buf_q, mrioc->sense_buf_q_dma); 4309824a1566SKashyap Desai dma_pool_destroy(mrioc->sense_buf_q_pool); 4310824a1566SKashyap Desai mrioc->sense_buf_q = NULL; 4311824a1566SKashyap Desai mrioc->sense_buf_q_pool = NULL; 4312824a1566SKashyap Desai } 4313824a1566SKashyap Desai 4314824a1566SKashyap Desai if (mrioc->reply_buf_pool) { 4315824a1566SKashyap Desai if (mrioc->reply_buf) 4316824a1566SKashyap Desai dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf, 4317824a1566SKashyap Desai mrioc->reply_buf_dma); 4318824a1566SKashyap Desai dma_pool_destroy(mrioc->reply_buf_pool); 4319824a1566SKashyap Desai mrioc->reply_buf = NULL; 4320824a1566SKashyap Desai mrioc->reply_buf_pool = NULL; 4321824a1566SKashyap Desai } 4322824a1566SKashyap Desai if (mrioc->reply_free_q_pool) { 4323824a1566SKashyap Desai if (mrioc->reply_free_q) 4324824a1566SKashyap Desai dma_pool_free(mrioc->reply_free_q_pool, 4325824a1566SKashyap Desai mrioc->reply_free_q, mrioc->reply_free_q_dma); 4326824a1566SKashyap Desai dma_pool_destroy(mrioc->reply_free_q_pool); 4327824a1566SKashyap Desai mrioc->reply_free_q = NULL; 4328824a1566SKashyap Desai mrioc->reply_free_q_pool = NULL; 4329824a1566SKashyap Desai } 4330824a1566SKashyap Desai 4331c9566231SKashyap Desai for (i = 0; i < mrioc->num_op_req_q; i++) 4332c9566231SKashyap Desai mpi3mr_free_op_req_q_segments(mrioc, i); 4333c9566231SKashyap Desai 4334c9566231SKashyap Desai for (i = 0; i < mrioc->num_op_reply_q; i++) 4335c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, i); 4336c9566231SKashyap Desai 4337824a1566SKashyap Desai for (i = 0; i < mrioc->intr_info_count; i++) { 4338824a1566SKashyap Desai intr_info = mrioc->intr_info + i; 4339824a1566SKashyap Desai intr_info->op_reply_q = NULL; 4340824a1566SKashyap Desai } 4341824a1566SKashyap Desai 4342824a1566SKashyap Desai kfree(mrioc->req_qinfo); 4343824a1566SKashyap Desai mrioc->req_qinfo = NULL; 4344824a1566SKashyap Desai mrioc->num_op_req_q = 0; 4345824a1566SKashyap Desai 4346824a1566SKashyap Desai kfree(mrioc->op_reply_qinfo); 4347824a1566SKashyap Desai mrioc->op_reply_qinfo = NULL; 4348824a1566SKashyap Desai mrioc->num_op_reply_q = 0; 4349824a1566SKashyap Desai 4350824a1566SKashyap Desai kfree(mrioc->init_cmds.reply); 4351824a1566SKashyap Desai mrioc->init_cmds.reply = NULL; 4352824a1566SKashyap Desai 4353f5e6d5a3SSumit Saxena kfree(mrioc->bsg_cmds.reply); 4354f5e6d5a3SSumit Saxena mrioc->bsg_cmds.reply = NULL; 4355f5e6d5a3SSumit Saxena 4356e844adb1SKashyap Desai kfree(mrioc->host_tm_cmds.reply); 4357e844adb1SKashyap Desai mrioc->host_tm_cmds.reply = NULL; 4358e844adb1SKashyap Desai 435943ca1100SSumit Saxena kfree(mrioc->pel_cmds.reply); 436043ca1100SSumit Saxena mrioc->pel_cmds.reply = NULL; 436143ca1100SSumit Saxena 436243ca1100SSumit Saxena kfree(mrioc->pel_abort_cmd.reply); 436343ca1100SSumit Saxena mrioc->pel_abort_cmd.reply = NULL; 436443ca1100SSumit Saxena 4365c1af985dSSreekanth Reddy for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { 4366c1af985dSSreekanth Reddy kfree(mrioc->evtack_cmds[i].reply); 4367c1af985dSSreekanth Reddy mrioc->evtack_cmds[i].reply = NULL; 4368c1af985dSSreekanth Reddy } 4369c1af985dSSreekanth Reddy 4370339e6156SShin'ichiro Kawasaki bitmap_free(mrioc->removepend_bitmap); 4371e844adb1SKashyap Desai mrioc->removepend_bitmap = NULL; 4372e844adb1SKashyap Desai 4373339e6156SShin'ichiro Kawasaki bitmap_free(mrioc->devrem_bitmap); 4374e844adb1SKashyap Desai mrioc->devrem_bitmap = NULL; 4375e844adb1SKashyap Desai 4376339e6156SShin'ichiro Kawasaki bitmap_free(mrioc->evtack_cmds_bitmap); 4377c1af985dSSreekanth Reddy mrioc->evtack_cmds_bitmap = NULL; 4378c1af985dSSreekanth Reddy 4379339e6156SShin'ichiro Kawasaki bitmap_free(mrioc->chain_bitmap); 4380824a1566SKashyap Desai mrioc->chain_bitmap = NULL; 4381824a1566SKashyap Desai 43822bd37e28SSreekanth Reddy kfree(mrioc->transport_cmds.reply); 43832bd37e28SSreekanth Reddy mrioc->transport_cmds.reply = NULL; 43842bd37e28SSreekanth Reddy 438513ef29eaSKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 438613ef29eaSKashyap Desai kfree(mrioc->dev_rmhs_cmds[i].reply); 438713ef29eaSKashyap Desai mrioc->dev_rmhs_cmds[i].reply = NULL; 438813ef29eaSKashyap Desai } 438913ef29eaSKashyap Desai 4390824a1566SKashyap Desai if (mrioc->chain_buf_pool) { 4391824a1566SKashyap Desai for (i = 0; i < mrioc->chain_buf_count; i++) { 4392824a1566SKashyap Desai if (mrioc->chain_sgl_list[i].addr) { 4393824a1566SKashyap Desai dma_pool_free(mrioc->chain_buf_pool, 4394824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr, 4395824a1566SKashyap Desai mrioc->chain_sgl_list[i].dma_addr); 4396824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr = NULL; 4397824a1566SKashyap Desai } 4398824a1566SKashyap Desai } 4399824a1566SKashyap Desai dma_pool_destroy(mrioc->chain_buf_pool); 4400824a1566SKashyap Desai mrioc->chain_buf_pool = NULL; 4401824a1566SKashyap Desai } 4402824a1566SKashyap Desai 4403824a1566SKashyap Desai kfree(mrioc->chain_sgl_list); 4404824a1566SKashyap Desai mrioc->chain_sgl_list = NULL; 4405824a1566SKashyap Desai 4406824a1566SKashyap Desai if (mrioc->admin_reply_base) { 4407824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz, 4408824a1566SKashyap Desai mrioc->admin_reply_base, mrioc->admin_reply_dma); 4409824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 4410824a1566SKashyap Desai } 4411824a1566SKashyap Desai if (mrioc->admin_req_base) { 4412824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz, 4413824a1566SKashyap Desai mrioc->admin_req_base, mrioc->admin_req_dma); 4414824a1566SKashyap Desai mrioc->admin_req_base = NULL; 4415824a1566SKashyap Desai } 44167d2b0217STomas Henzl if (mrioc->cfg_page) { 44177d2b0217STomas Henzl dma_free_coherent(&mrioc->pdev->dev, mrioc->cfg_page_sz, 44187d2b0217STomas Henzl mrioc->cfg_page, mrioc->cfg_page_dma); 44197d2b0217STomas Henzl mrioc->cfg_page = NULL; 44207d2b0217STomas Henzl } 442143ca1100SSumit Saxena if (mrioc->pel_seqnum_virt) { 442243ca1100SSumit Saxena dma_free_coherent(&mrioc->pdev->dev, mrioc->pel_seqnum_sz, 442343ca1100SSumit Saxena mrioc->pel_seqnum_virt, mrioc->pel_seqnum_dma); 442443ca1100SSumit Saxena mrioc->pel_seqnum_virt = NULL; 442543ca1100SSumit Saxena } 442643ca1100SSumit Saxena 4427f305a7b6STomas Henzl kfree(mrioc->throttle_groups); 4428f305a7b6STomas Henzl mrioc->throttle_groups = NULL; 4429f305a7b6STomas Henzl 443043ca1100SSumit Saxena kfree(mrioc->logdata_buf); 443143ca1100SSumit Saxena mrioc->logdata_buf = NULL; 443243ca1100SSumit Saxena 4433824a1566SKashyap Desai } 4434824a1566SKashyap Desai 4435824a1566SKashyap Desai /** 4436824a1566SKashyap Desai * mpi3mr_issue_ioc_shutdown - shutdown controller 4437824a1566SKashyap Desai * @mrioc: Adapter instance reference 4438824a1566SKashyap Desai * 4439824a1566SKashyap Desai * Send shutodwn notification to the controller and wait for the 4440824a1566SKashyap Desai * shutdown_timeout for it to be completed. 4441824a1566SKashyap Desai * 4442824a1566SKashyap Desai * Return: Nothing. 4443824a1566SKashyap Desai */ 4444824a1566SKashyap Desai static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc) 4445824a1566SKashyap Desai { 4446824a1566SKashyap Desai u32 ioc_config, ioc_status; 4447824a1566SKashyap Desai u8 retval = 1; 4448824a1566SKashyap Desai u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10; 4449824a1566SKashyap Desai 4450824a1566SKashyap Desai ioc_info(mrioc, "Issuing shutdown Notification\n"); 4451824a1566SKashyap Desai if (mrioc->unrecoverable) { 4452824a1566SKashyap Desai ioc_warn(mrioc, 4453824a1566SKashyap Desai "IOC is unrecoverable shutdown is not issued\n"); 4454824a1566SKashyap Desai return; 4455824a1566SKashyap Desai } 4456824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 4457824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 4458824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) { 4459824a1566SKashyap Desai ioc_info(mrioc, "shutdown already in progress\n"); 4460824a1566SKashyap Desai return; 4461824a1566SKashyap Desai } 4462824a1566SKashyap Desai 4463824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 4464824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL; 4465ec5ebd2cSSreekanth Reddy ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ; 4466824a1566SKashyap Desai 4467824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 4468824a1566SKashyap Desai 4469824a1566SKashyap Desai if (mrioc->facts.shutdown_timeout) 4470824a1566SKashyap Desai timeout = mrioc->facts.shutdown_timeout * 10; 4471824a1566SKashyap Desai 4472824a1566SKashyap Desai do { 4473824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 4474824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 4475824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) { 4476824a1566SKashyap Desai retval = 0; 4477824a1566SKashyap Desai break; 4478824a1566SKashyap Desai } 4479824a1566SKashyap Desai msleep(100); 4480824a1566SKashyap Desai } while (--timeout); 4481824a1566SKashyap Desai 4482824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 4483824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 4484824a1566SKashyap Desai 4485824a1566SKashyap Desai if (retval) { 4486824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 4487824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) 4488824a1566SKashyap Desai ioc_warn(mrioc, 4489824a1566SKashyap Desai "shutdown still in progress after timeout\n"); 4490824a1566SKashyap Desai } 4491824a1566SKashyap Desai 4492824a1566SKashyap Desai ioc_info(mrioc, 4493824a1566SKashyap Desai "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n", 4494824a1566SKashyap Desai (!retval) ? "successful" : "failed", ioc_status, 4495824a1566SKashyap Desai ioc_config); 4496824a1566SKashyap Desai } 4497824a1566SKashyap Desai 4498824a1566SKashyap Desai /** 4499824a1566SKashyap Desai * mpi3mr_cleanup_ioc - Cleanup controller 4500824a1566SKashyap Desai * @mrioc: Adapter instance reference 45013bb3c24eSYang Li * 4502824a1566SKashyap Desai * controller cleanup handler, Message unit reset or soft reset 4503fe6db615SSreekanth Reddy * and shutdown notification is issued to the controller. 4504824a1566SKashyap Desai * 4505824a1566SKashyap Desai * Return: Nothing. 4506824a1566SKashyap Desai */ 4507fe6db615SSreekanth Reddy void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc) 4508824a1566SKashyap Desai { 4509824a1566SKashyap Desai enum mpi3mr_iocstate ioc_state; 4510824a1566SKashyap Desai 4511fe6db615SSreekanth Reddy dprint_exit(mrioc, "cleaning up the controller\n"); 4512824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 4513824a1566SKashyap Desai 4514824a1566SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 4515824a1566SKashyap Desai 4516824a1566SKashyap Desai if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) && 4517824a1566SKashyap Desai (ioc_state == MRIOC_STATE_READY)) { 4518824a1566SKashyap Desai if (mpi3mr_issue_and_process_mur(mrioc, 4519824a1566SKashyap Desai MPI3MR_RESET_FROM_CTLR_CLEANUP)) 4520824a1566SKashyap Desai mpi3mr_issue_reset(mrioc, 4521824a1566SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, 4522824a1566SKashyap Desai MPI3MR_RESET_FROM_MUR_FAILURE); 4523824a1566SKashyap Desai mpi3mr_issue_ioc_shutdown(mrioc); 4524824a1566SKashyap Desai } 4525fe6db615SSreekanth Reddy dprint_exit(mrioc, "controller cleanup completed\n"); 4526fb9b0457SKashyap Desai } 4527fb9b0457SKashyap Desai 4528fb9b0457SKashyap Desai /** 4529fb9b0457SKashyap Desai * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command 4530fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 4531fb9b0457SKashyap Desai * @cmdptr: Internal command tracker 4532fb9b0457SKashyap Desai * 4533fb9b0457SKashyap Desai * Complete an internal driver commands with state indicating it 4534fb9b0457SKashyap Desai * is completed due to reset. 4535fb9b0457SKashyap Desai * 4536fb9b0457SKashyap Desai * Return: Nothing. 4537fb9b0457SKashyap Desai */ 4538fb9b0457SKashyap Desai static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc *mrioc, 4539fb9b0457SKashyap Desai struct mpi3mr_drv_cmd *cmdptr) 4540fb9b0457SKashyap Desai { 4541fb9b0457SKashyap Desai if (cmdptr->state & MPI3MR_CMD_PENDING) { 4542fb9b0457SKashyap Desai cmdptr->state |= MPI3MR_CMD_RESET; 4543fb9b0457SKashyap Desai cmdptr->state &= ~MPI3MR_CMD_PENDING; 4544fb9b0457SKashyap Desai if (cmdptr->is_waiting) { 4545fb9b0457SKashyap Desai complete(&cmdptr->done); 4546fb9b0457SKashyap Desai cmdptr->is_waiting = 0; 4547fb9b0457SKashyap Desai } else if (cmdptr->callback) 4548fb9b0457SKashyap Desai cmdptr->callback(mrioc, cmdptr); 4549fb9b0457SKashyap Desai } 4550fb9b0457SKashyap Desai } 4551fb9b0457SKashyap Desai 4552fb9b0457SKashyap Desai /** 4553fb9b0457SKashyap Desai * mpi3mr_flush_drv_cmds - Flush internaldriver commands 4554fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 4555fb9b0457SKashyap Desai * 4556fb9b0457SKashyap Desai * Flush all internal driver commands post reset 4557fb9b0457SKashyap Desai * 4558fb9b0457SKashyap Desai * Return: Nothing. 4559fb9b0457SKashyap Desai */ 4560f2a79d20SSreekanth Reddy void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc) 4561fb9b0457SKashyap Desai { 4562fb9b0457SKashyap Desai struct mpi3mr_drv_cmd *cmdptr; 4563fb9b0457SKashyap Desai u8 i; 4564fb9b0457SKashyap Desai 4565fb9b0457SKashyap Desai cmdptr = &mrioc->init_cmds; 4566fb9b0457SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 456732d457d5SSreekanth Reddy 456832d457d5SSreekanth Reddy cmdptr = &mrioc->cfg_cmds; 456932d457d5SSreekanth Reddy mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 457032d457d5SSreekanth Reddy 4571f5e6d5a3SSumit Saxena cmdptr = &mrioc->bsg_cmds; 4572f5e6d5a3SSumit Saxena mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 4573e844adb1SKashyap Desai cmdptr = &mrioc->host_tm_cmds; 4574e844adb1SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 4575fb9b0457SKashyap Desai 4576fb9b0457SKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 4577fb9b0457SKashyap Desai cmdptr = &mrioc->dev_rmhs_cmds[i]; 4578fb9b0457SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 4579fb9b0457SKashyap Desai } 4580c1af985dSSreekanth Reddy 4581c1af985dSSreekanth Reddy for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { 4582c1af985dSSreekanth Reddy cmdptr = &mrioc->evtack_cmds[i]; 4583c1af985dSSreekanth Reddy mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 4584c1af985dSSreekanth Reddy } 458543ca1100SSumit Saxena 458643ca1100SSumit Saxena cmdptr = &mrioc->pel_cmds; 458743ca1100SSumit Saxena mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 458843ca1100SSumit Saxena 458943ca1100SSumit Saxena cmdptr = &mrioc->pel_abort_cmd; 459043ca1100SSumit Saxena mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 459143ca1100SSumit Saxena 45922bd37e28SSreekanth Reddy cmdptr = &mrioc->transport_cmds; 45932bd37e28SSreekanth Reddy mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 459443ca1100SSumit Saxena } 459543ca1100SSumit Saxena 459643ca1100SSumit Saxena /** 459743ca1100SSumit Saxena * mpi3mr_pel_wait_post - Issue PEL Wait 459843ca1100SSumit Saxena * @mrioc: Adapter instance reference 459943ca1100SSumit Saxena * @drv_cmd: Internal command tracker 460043ca1100SSumit Saxena * 460143ca1100SSumit Saxena * Issue PEL Wait MPI request through admin queue and return. 460243ca1100SSumit Saxena * 460343ca1100SSumit Saxena * Return: Nothing. 460443ca1100SSumit Saxena */ 460543ca1100SSumit Saxena static void mpi3mr_pel_wait_post(struct mpi3mr_ioc *mrioc, 460643ca1100SSumit Saxena struct mpi3mr_drv_cmd *drv_cmd) 460743ca1100SSumit Saxena { 460843ca1100SSumit Saxena struct mpi3_pel_req_action_wait pel_wait; 460943ca1100SSumit Saxena 461043ca1100SSumit Saxena mrioc->pel_abort_requested = false; 461143ca1100SSumit Saxena 461243ca1100SSumit Saxena memset(&pel_wait, 0, sizeof(pel_wait)); 461343ca1100SSumit Saxena drv_cmd->state = MPI3MR_CMD_PENDING; 461443ca1100SSumit Saxena drv_cmd->is_waiting = 0; 461543ca1100SSumit Saxena drv_cmd->callback = mpi3mr_pel_wait_complete; 461643ca1100SSumit Saxena drv_cmd->ioc_status = 0; 461743ca1100SSumit Saxena drv_cmd->ioc_loginfo = 0; 461843ca1100SSumit Saxena pel_wait.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_PEL_WAIT); 461943ca1100SSumit Saxena pel_wait.function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 462043ca1100SSumit Saxena pel_wait.action = MPI3_PEL_ACTION_WAIT; 462143ca1100SSumit Saxena pel_wait.starting_sequence_number = cpu_to_le32(mrioc->pel_newest_seqnum); 462243ca1100SSumit Saxena pel_wait.locale = cpu_to_le16(mrioc->pel_locale); 462343ca1100SSumit Saxena pel_wait.class = cpu_to_le16(mrioc->pel_class); 462443ca1100SSumit Saxena pel_wait.wait_time = MPI3_PEL_WAITTIME_INFINITE_WAIT; 462543ca1100SSumit Saxena dprint_bsg_info(mrioc, "sending pel_wait seqnum(%d), class(%d), locale(0x%08x)\n", 462643ca1100SSumit Saxena mrioc->pel_newest_seqnum, mrioc->pel_class, mrioc->pel_locale); 462743ca1100SSumit Saxena 462843ca1100SSumit Saxena if (mpi3mr_admin_request_post(mrioc, &pel_wait, sizeof(pel_wait), 0)) { 462943ca1100SSumit Saxena dprint_bsg_err(mrioc, 463043ca1100SSumit Saxena "Issuing PELWait: Admin post failed\n"); 463143ca1100SSumit Saxena drv_cmd->state = MPI3MR_CMD_NOTUSED; 463243ca1100SSumit Saxena drv_cmd->callback = NULL; 463343ca1100SSumit Saxena drv_cmd->retry_count = 0; 463443ca1100SSumit Saxena mrioc->pel_enabled = false; 463543ca1100SSumit Saxena } 463643ca1100SSumit Saxena } 463743ca1100SSumit Saxena 463843ca1100SSumit Saxena /** 463943ca1100SSumit Saxena * mpi3mr_pel_get_seqnum_post - Issue PEL Get Sequence number 464043ca1100SSumit Saxena * @mrioc: Adapter instance reference 464143ca1100SSumit Saxena * @drv_cmd: Internal command tracker 464243ca1100SSumit Saxena * 464343ca1100SSumit Saxena * Issue PEL get sequence number MPI request through admin queue 464443ca1100SSumit Saxena * and return. 464543ca1100SSumit Saxena * 464643ca1100SSumit Saxena * Return: 0 on success, non-zero on failure. 464743ca1100SSumit Saxena */ 464843ca1100SSumit Saxena int mpi3mr_pel_get_seqnum_post(struct mpi3mr_ioc *mrioc, 464943ca1100SSumit Saxena struct mpi3mr_drv_cmd *drv_cmd) 465043ca1100SSumit Saxena { 465143ca1100SSumit Saxena struct mpi3_pel_req_action_get_sequence_numbers pel_getseq_req; 465243ca1100SSumit Saxena u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 465343ca1100SSumit Saxena int retval = 0; 465443ca1100SSumit Saxena 465543ca1100SSumit Saxena memset(&pel_getseq_req, 0, sizeof(pel_getseq_req)); 465643ca1100SSumit Saxena mrioc->pel_cmds.state = MPI3MR_CMD_PENDING; 465743ca1100SSumit Saxena mrioc->pel_cmds.is_waiting = 0; 465843ca1100SSumit Saxena mrioc->pel_cmds.ioc_status = 0; 465943ca1100SSumit Saxena mrioc->pel_cmds.ioc_loginfo = 0; 466043ca1100SSumit Saxena mrioc->pel_cmds.callback = mpi3mr_pel_get_seqnum_complete; 466143ca1100SSumit Saxena pel_getseq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_PEL_WAIT); 466243ca1100SSumit Saxena pel_getseq_req.function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 466343ca1100SSumit Saxena pel_getseq_req.action = MPI3_PEL_ACTION_GET_SEQNUM; 466443ca1100SSumit Saxena mpi3mr_add_sg_single(&pel_getseq_req.sgl, sgl_flags, 466543ca1100SSumit Saxena mrioc->pel_seqnum_sz, mrioc->pel_seqnum_dma); 466643ca1100SSumit Saxena 466743ca1100SSumit Saxena retval = mpi3mr_admin_request_post(mrioc, &pel_getseq_req, 466843ca1100SSumit Saxena sizeof(pel_getseq_req), 0); 466943ca1100SSumit Saxena if (retval) { 467043ca1100SSumit Saxena if (drv_cmd) { 467143ca1100SSumit Saxena drv_cmd->state = MPI3MR_CMD_NOTUSED; 467243ca1100SSumit Saxena drv_cmd->callback = NULL; 467343ca1100SSumit Saxena drv_cmd->retry_count = 0; 467443ca1100SSumit Saxena } 467543ca1100SSumit Saxena mrioc->pel_enabled = false; 467643ca1100SSumit Saxena } 467743ca1100SSumit Saxena 467843ca1100SSumit Saxena return retval; 467943ca1100SSumit Saxena } 468043ca1100SSumit Saxena 468143ca1100SSumit Saxena /** 468243ca1100SSumit Saxena * mpi3mr_pel_wait_complete - PELWait Completion callback 468343ca1100SSumit Saxena * @mrioc: Adapter instance reference 468443ca1100SSumit Saxena * @drv_cmd: Internal command tracker 468543ca1100SSumit Saxena * 468643ca1100SSumit Saxena * This is a callback handler for the PELWait request and 468743ca1100SSumit Saxena * firmware completes a PELWait request when it is aborted or a 468843ca1100SSumit Saxena * new PEL entry is available. This sends AEN to the application 468943ca1100SSumit Saxena * and if the PELwait completion is not due to PELAbort then 469043ca1100SSumit Saxena * this will send a request for new PEL Sequence number 469143ca1100SSumit Saxena * 469243ca1100SSumit Saxena * Return: Nothing. 469343ca1100SSumit Saxena */ 469443ca1100SSumit Saxena static void mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc, 469543ca1100SSumit Saxena struct mpi3mr_drv_cmd *drv_cmd) 469643ca1100SSumit Saxena { 469743ca1100SSumit Saxena struct mpi3_pel_reply *pel_reply = NULL; 469843ca1100SSumit Saxena u16 ioc_status, pe_log_status; 469943ca1100SSumit Saxena bool do_retry = false; 470043ca1100SSumit Saxena 470143ca1100SSumit Saxena if (drv_cmd->state & MPI3MR_CMD_RESET) 470243ca1100SSumit Saxena goto cleanup_drv_cmd; 470343ca1100SSumit Saxena 470443ca1100SSumit Saxena ioc_status = drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK; 470543ca1100SSumit Saxena if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { 470643ca1100SSumit Saxena ioc_err(mrioc, "%s: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 470743ca1100SSumit Saxena __func__, ioc_status, drv_cmd->ioc_loginfo); 470843ca1100SSumit Saxena dprint_bsg_err(mrioc, 470943ca1100SSumit Saxena "pel_wait: failed with ioc_status(0x%04x), log_info(0x%08x)\n", 471043ca1100SSumit Saxena ioc_status, drv_cmd->ioc_loginfo); 471143ca1100SSumit Saxena do_retry = true; 471243ca1100SSumit Saxena } 471343ca1100SSumit Saxena 471443ca1100SSumit Saxena if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID) 471543ca1100SSumit Saxena pel_reply = (struct mpi3_pel_reply *)drv_cmd->reply; 471643ca1100SSumit Saxena 471743ca1100SSumit Saxena if (!pel_reply) { 471843ca1100SSumit Saxena dprint_bsg_err(mrioc, 471943ca1100SSumit Saxena "pel_wait: failed due to no reply\n"); 472043ca1100SSumit Saxena goto out_failed; 472143ca1100SSumit Saxena } 472243ca1100SSumit Saxena 472343ca1100SSumit Saxena pe_log_status = le16_to_cpu(pel_reply->pe_log_status); 472443ca1100SSumit Saxena if ((pe_log_status != MPI3_PEL_STATUS_SUCCESS) && 472543ca1100SSumit Saxena (pe_log_status != MPI3_PEL_STATUS_ABORTED)) { 472643ca1100SSumit Saxena ioc_err(mrioc, "%s: Failed pe_log_status(0x%04x)\n", 472743ca1100SSumit Saxena __func__, pe_log_status); 472843ca1100SSumit Saxena dprint_bsg_err(mrioc, 472943ca1100SSumit Saxena "pel_wait: failed due to pel_log_status(0x%04x)\n", 473043ca1100SSumit Saxena pe_log_status); 473143ca1100SSumit Saxena do_retry = true; 473243ca1100SSumit Saxena } 473343ca1100SSumit Saxena 473443ca1100SSumit Saxena if (do_retry) { 473543ca1100SSumit Saxena if (drv_cmd->retry_count < MPI3MR_PEL_RETRY_COUNT) { 473643ca1100SSumit Saxena drv_cmd->retry_count++; 473743ca1100SSumit Saxena dprint_bsg_err(mrioc, "pel_wait: retrying(%d)\n", 473843ca1100SSumit Saxena drv_cmd->retry_count); 473943ca1100SSumit Saxena mpi3mr_pel_wait_post(mrioc, drv_cmd); 474043ca1100SSumit Saxena return; 474143ca1100SSumit Saxena } 474243ca1100SSumit Saxena dprint_bsg_err(mrioc, 474343ca1100SSumit Saxena "pel_wait: failed after all retries(%d)\n", 474443ca1100SSumit Saxena drv_cmd->retry_count); 474543ca1100SSumit Saxena goto out_failed; 474643ca1100SSumit Saxena } 474743ca1100SSumit Saxena atomic64_inc(&event_counter); 474843ca1100SSumit Saxena if (!mrioc->pel_abort_requested) { 474943ca1100SSumit Saxena mrioc->pel_cmds.retry_count = 0; 475043ca1100SSumit Saxena mpi3mr_pel_get_seqnum_post(mrioc, &mrioc->pel_cmds); 475143ca1100SSumit Saxena } 475243ca1100SSumit Saxena 475343ca1100SSumit Saxena return; 475443ca1100SSumit Saxena out_failed: 475543ca1100SSumit Saxena mrioc->pel_enabled = false; 475643ca1100SSumit Saxena cleanup_drv_cmd: 475743ca1100SSumit Saxena drv_cmd->state = MPI3MR_CMD_NOTUSED; 475843ca1100SSumit Saxena drv_cmd->callback = NULL; 475943ca1100SSumit Saxena drv_cmd->retry_count = 0; 476043ca1100SSumit Saxena } 476143ca1100SSumit Saxena 476243ca1100SSumit Saxena /** 476343ca1100SSumit Saxena * mpi3mr_pel_get_seqnum_complete - PELGetSeqNum Completion callback 476443ca1100SSumit Saxena * @mrioc: Adapter instance reference 476543ca1100SSumit Saxena * @drv_cmd: Internal command tracker 476643ca1100SSumit Saxena * 476743ca1100SSumit Saxena * This is a callback handler for the PEL get sequence number 476843ca1100SSumit Saxena * request and a new PEL wait request will be issued to the 476943ca1100SSumit Saxena * firmware from this 477043ca1100SSumit Saxena * 477143ca1100SSumit Saxena * Return: Nothing. 477243ca1100SSumit Saxena */ 477343ca1100SSumit Saxena void mpi3mr_pel_get_seqnum_complete(struct mpi3mr_ioc *mrioc, 477443ca1100SSumit Saxena struct mpi3mr_drv_cmd *drv_cmd) 477543ca1100SSumit Saxena { 477643ca1100SSumit Saxena struct mpi3_pel_reply *pel_reply = NULL; 477743ca1100SSumit Saxena struct mpi3_pel_seq *pel_seqnum_virt; 477843ca1100SSumit Saxena u16 ioc_status; 477943ca1100SSumit Saxena bool do_retry = false; 478043ca1100SSumit Saxena 478143ca1100SSumit Saxena pel_seqnum_virt = (struct mpi3_pel_seq *)mrioc->pel_seqnum_virt; 478243ca1100SSumit Saxena 478343ca1100SSumit Saxena if (drv_cmd->state & MPI3MR_CMD_RESET) 478443ca1100SSumit Saxena goto cleanup_drv_cmd; 478543ca1100SSumit Saxena 478643ca1100SSumit Saxena ioc_status = drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK; 478743ca1100SSumit Saxena if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { 478843ca1100SSumit Saxena dprint_bsg_err(mrioc, 478943ca1100SSumit Saxena "pel_get_seqnum: failed with ioc_status(0x%04x), log_info(0x%08x)\n", 479043ca1100SSumit Saxena ioc_status, drv_cmd->ioc_loginfo); 479143ca1100SSumit Saxena do_retry = true; 479243ca1100SSumit Saxena } 479343ca1100SSumit Saxena 479443ca1100SSumit Saxena if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID) 479543ca1100SSumit Saxena pel_reply = (struct mpi3_pel_reply *)drv_cmd->reply; 479643ca1100SSumit Saxena if (!pel_reply) { 479743ca1100SSumit Saxena dprint_bsg_err(mrioc, 479843ca1100SSumit Saxena "pel_get_seqnum: failed due to no reply\n"); 479943ca1100SSumit Saxena goto out_failed; 480043ca1100SSumit Saxena } 480143ca1100SSumit Saxena 480243ca1100SSumit Saxena if (le16_to_cpu(pel_reply->pe_log_status) != MPI3_PEL_STATUS_SUCCESS) { 480343ca1100SSumit Saxena dprint_bsg_err(mrioc, 480443ca1100SSumit Saxena "pel_get_seqnum: failed due to pel_log_status(0x%04x)\n", 480543ca1100SSumit Saxena le16_to_cpu(pel_reply->pe_log_status)); 480643ca1100SSumit Saxena do_retry = true; 480743ca1100SSumit Saxena } 480843ca1100SSumit Saxena 480943ca1100SSumit Saxena if (do_retry) { 481043ca1100SSumit Saxena if (drv_cmd->retry_count < MPI3MR_PEL_RETRY_COUNT) { 481143ca1100SSumit Saxena drv_cmd->retry_count++; 481243ca1100SSumit Saxena dprint_bsg_err(mrioc, 481343ca1100SSumit Saxena "pel_get_seqnum: retrying(%d)\n", 481443ca1100SSumit Saxena drv_cmd->retry_count); 481543ca1100SSumit Saxena mpi3mr_pel_get_seqnum_post(mrioc, drv_cmd); 481643ca1100SSumit Saxena return; 481743ca1100SSumit Saxena } 481843ca1100SSumit Saxena 481943ca1100SSumit Saxena dprint_bsg_err(mrioc, 482043ca1100SSumit Saxena "pel_get_seqnum: failed after all retries(%d)\n", 482143ca1100SSumit Saxena drv_cmd->retry_count); 482243ca1100SSumit Saxena goto out_failed; 482343ca1100SSumit Saxena } 482443ca1100SSumit Saxena mrioc->pel_newest_seqnum = le32_to_cpu(pel_seqnum_virt->newest) + 1; 482543ca1100SSumit Saxena drv_cmd->retry_count = 0; 482643ca1100SSumit Saxena mpi3mr_pel_wait_post(mrioc, drv_cmd); 482743ca1100SSumit Saxena 482843ca1100SSumit Saxena return; 482943ca1100SSumit Saxena out_failed: 483043ca1100SSumit Saxena mrioc->pel_enabled = false; 483143ca1100SSumit Saxena cleanup_drv_cmd: 483243ca1100SSumit Saxena drv_cmd->state = MPI3MR_CMD_NOTUSED; 483343ca1100SSumit Saxena drv_cmd->callback = NULL; 483443ca1100SSumit Saxena drv_cmd->retry_count = 0; 4835fb9b0457SKashyap Desai } 4836fb9b0457SKashyap Desai 4837fb9b0457SKashyap Desai /** 4838824a1566SKashyap Desai * mpi3mr_soft_reset_handler - Reset the controller 4839824a1566SKashyap Desai * @mrioc: Adapter instance reference 4840824a1566SKashyap Desai * @reset_reason: Reset reason code 4841824a1566SKashyap Desai * @snapdump: Flag to generate snapdump in firmware or not 4842824a1566SKashyap Desai * 4843fb9b0457SKashyap Desai * This is an handler for recovering controller by issuing soft 4844fb9b0457SKashyap Desai * reset are diag fault reset. This is a blocking function and 4845fb9b0457SKashyap Desai * when one reset is executed if any other resets they will be 4846f5e6d5a3SSumit Saxena * blocked. All BSG requests will be blocked during the reset. If 4847fb9b0457SKashyap Desai * controller reset is successful then the controller will be 4848fb9b0457SKashyap Desai * reinitalized, otherwise the controller will be marked as not 4849fb9b0457SKashyap Desai * recoverable 4850fb9b0457SKashyap Desai * 4851fb9b0457SKashyap Desai * In snapdump bit is set, the controller is issued with diag 4852fb9b0457SKashyap Desai * fault reset so that the firmware can create a snap dump and 4853fb9b0457SKashyap Desai * post that the firmware will result in F000 fault and the 4854fb9b0457SKashyap Desai * driver will issue soft reset to recover from that. 4855824a1566SKashyap Desai * 4856824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 4857824a1566SKashyap Desai */ 4858824a1566SKashyap Desai int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, 4859824a1566SKashyap Desai u32 reset_reason, u8 snapdump) 4860824a1566SKashyap Desai { 4861fb9b0457SKashyap Desai int retval = 0, i; 4862fb9b0457SKashyap Desai unsigned long flags; 4863fb9b0457SKashyap Desai u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; 4864fb9b0457SKashyap Desai 4865b64845a7SSreekanth Reddy /* Block the reset handler until diag save in progress*/ 4866b64845a7SSreekanth Reddy dprint_reset(mrioc, 4867b64845a7SSreekanth Reddy "soft_reset_handler: check and block on diagsave_timeout(%d)\n", 4868b64845a7SSreekanth Reddy mrioc->diagsave_timeout); 4869b64845a7SSreekanth Reddy while (mrioc->diagsave_timeout) 4870b64845a7SSreekanth Reddy ssleep(1); 4871fb9b0457SKashyap Desai /* 4872fb9b0457SKashyap Desai * Block new resets until the currently executing one is finished and 4873fb9b0457SKashyap Desai * return the status of the existing reset for all blocked resets 4874fb9b0457SKashyap Desai */ 4875b64845a7SSreekanth Reddy dprint_reset(mrioc, "soft_reset_handler: acquiring reset_mutex\n"); 4876fb9b0457SKashyap Desai if (!mutex_trylock(&mrioc->reset_mutex)) { 4877b64845a7SSreekanth Reddy ioc_info(mrioc, 4878b64845a7SSreekanth Reddy "controller reset triggered by %s is blocked due to another reset in progress\n", 4879b64845a7SSreekanth Reddy mpi3mr_reset_rc_name(reset_reason)); 4880b64845a7SSreekanth Reddy do { 4881b64845a7SSreekanth Reddy ssleep(1); 4882b64845a7SSreekanth Reddy } while (mrioc->reset_in_progress == 1); 4883b64845a7SSreekanth Reddy ioc_info(mrioc, 4884b64845a7SSreekanth Reddy "returning previous reset result(%d) for the reset triggered by %s\n", 4885b64845a7SSreekanth Reddy mrioc->prev_reset_result, 4886b64845a7SSreekanth Reddy mpi3mr_reset_rc_name(reset_reason)); 4887b64845a7SSreekanth Reddy return mrioc->prev_reset_result; 4888fb9b0457SKashyap Desai } 4889b64845a7SSreekanth Reddy ioc_info(mrioc, "controller reset is triggered by %s\n", 4890b64845a7SSreekanth Reddy mpi3mr_reset_rc_name(reset_reason)); 4891b64845a7SSreekanth Reddy 48922745ce0eSSreekanth Reddy mrioc->device_refresh_on = 0; 4893fb9b0457SKashyap Desai mrioc->reset_in_progress = 1; 4894f5e6d5a3SSumit Saxena mrioc->stop_bsgs = 1; 4895b64845a7SSreekanth Reddy mrioc->prev_reset_result = -1; 4896fb9b0457SKashyap Desai 4897fb9b0457SKashyap Desai if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) && 4898b64845a7SSreekanth Reddy (reset_reason != MPI3MR_RESET_FROM_FIRMWARE) && 4899fb9b0457SKashyap Desai (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) { 4900fb9b0457SKashyap Desai for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 4901fb9b0457SKashyap Desai mrioc->event_masks[i] = -1; 4902fb9b0457SKashyap Desai 4903b64845a7SSreekanth Reddy dprint_reset(mrioc, "soft_reset_handler: masking events\n"); 4904b64845a7SSreekanth Reddy mpi3mr_issue_event_notification(mrioc); 4905fb9b0457SKashyap Desai } 4906fb9b0457SKashyap Desai 490744dc724fSKashyap Desai mpi3mr_wait_for_host_io(mrioc, MPI3MR_RESET_HOST_IOWAIT_TIMEOUT); 490844dc724fSKashyap Desai 4909fb9b0457SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 4910fb9b0457SKashyap Desai 4911fb9b0457SKashyap Desai if (snapdump) { 4912fb9b0457SKashyap Desai mpi3mr_set_diagsave(mrioc); 4913fb9b0457SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 4914fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); 4915fb9b0457SKashyap Desai if (!retval) { 4916fb9b0457SKashyap Desai do { 4917fb9b0457SKashyap Desai host_diagnostic = 4918fb9b0457SKashyap Desai readl(&mrioc->sysif_regs->host_diagnostic); 4919fb9b0457SKashyap Desai if (!(host_diagnostic & 4920fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS)) 4921fb9b0457SKashyap Desai break; 4922fb9b0457SKashyap Desai msleep(100); 4923fb9b0457SKashyap Desai } while (--timeout); 4924fb9b0457SKashyap Desai } 4925fb9b0457SKashyap Desai } 4926fb9b0457SKashyap Desai 4927fb9b0457SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 4928fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason); 4929fb9b0457SKashyap Desai if (retval) { 4930fb9b0457SKashyap Desai ioc_err(mrioc, "Failed to issue soft reset to the ioc\n"); 4931fb9b0457SKashyap Desai goto out; 4932fb9b0457SKashyap Desai } 4933f10af057SSreekanth Reddy if (mrioc->num_io_throttle_group != 4934f10af057SSreekanth Reddy mrioc->facts.max_io_throttle_group) { 4935f10af057SSreekanth Reddy ioc_err(mrioc, 4936f10af057SSreekanth Reddy "max io throttle group doesn't match old(%d), new(%d)\n", 4937f10af057SSreekanth Reddy mrioc->num_io_throttle_group, 4938f10af057SSreekanth Reddy mrioc->facts.max_io_throttle_group); 49392a8a0147SDan Carpenter retval = -EPERM; 49402a8a0147SDan Carpenter goto out; 4941f10af057SSreekanth Reddy } 4942fb9b0457SKashyap Desai 4943c1af985dSSreekanth Reddy mpi3mr_flush_delayed_cmd_lists(mrioc); 4944fb9b0457SKashyap Desai mpi3mr_flush_drv_cmds(mrioc); 4945339e6156SShin'ichiro Kawasaki bitmap_clear(mrioc->devrem_bitmap, 0, MPI3MR_NUM_DEVRMCMD); 4946339e6156SShin'ichiro Kawasaki bitmap_clear(mrioc->removepend_bitmap, 0, 4947339e6156SShin'ichiro Kawasaki mrioc->dev_handle_bitmap_bits); 4948339e6156SShin'ichiro Kawasaki bitmap_clear(mrioc->evtack_cmds_bitmap, 0, MPI3MR_NUM_EVTACKCMD); 4949fb9b0457SKashyap Desai mpi3mr_flush_host_io(mrioc); 4950580e6742SSreekanth Reddy mpi3mr_cleanup_fwevt_list(mrioc); 4951fb9b0457SKashyap Desai mpi3mr_invalidate_devhandles(mrioc); 4952130fc180SSreekanth Reddy mpi3mr_free_enclosure_list(mrioc); 4953130fc180SSreekanth Reddy 495478b76a07SSreekanth Reddy if (mrioc->prepare_for_reset) { 495578b76a07SSreekanth Reddy mrioc->prepare_for_reset = 0; 495678b76a07SSreekanth Reddy mrioc->prepare_for_reset_timeout_counter = 0; 495778b76a07SSreekanth Reddy } 4958fb9b0457SKashyap Desai mpi3mr_memset_buffers(mrioc); 4959fe6db615SSreekanth Reddy retval = mpi3mr_reinit_ioc(mrioc, 0); 4960fb9b0457SKashyap Desai if (retval) { 4961fb9b0457SKashyap Desai pr_err(IOCNAME "reinit after soft reset failed: reason %d\n", 4962fb9b0457SKashyap Desai mrioc->name, reset_reason); 4963fb9b0457SKashyap Desai goto out; 4964fb9b0457SKashyap Desai } 4965f84e8b5bSSreekanth Reddy ssleep(MPI3MR_RESET_TOPOLOGY_SETTLE_TIME); 4966fb9b0457SKashyap Desai 4967fb9b0457SKashyap Desai out: 4968fb9b0457SKashyap Desai if (!retval) { 4969b64845a7SSreekanth Reddy mrioc->diagsave_timeout = 0; 4970fb9b0457SKashyap Desai mrioc->reset_in_progress = 0; 497143ca1100SSumit Saxena mrioc->pel_abort_requested = 0; 497243ca1100SSumit Saxena if (mrioc->pel_enabled) { 497343ca1100SSumit Saxena mrioc->pel_cmds.retry_count = 0; 497443ca1100SSumit Saxena mpi3mr_pel_wait_post(mrioc, &mrioc->pel_cmds); 497543ca1100SSumit Saxena } 497643ca1100SSumit Saxena 49772745ce0eSSreekanth Reddy mrioc->device_refresh_on = 0; 49782745ce0eSSreekanth Reddy 497954dfcffbSKashyap Desai mrioc->ts_update_counter = 0; 4980fb9b0457SKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 4981fb9b0457SKashyap Desai if (mrioc->watchdog_work_q) 4982fb9b0457SKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 4983fb9b0457SKashyap Desai &mrioc->watchdog_work, 4984fb9b0457SKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 4985fb9b0457SKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 4986f5e6d5a3SSumit Saxena mrioc->stop_bsgs = 0; 498743ca1100SSumit Saxena if (mrioc->pel_enabled) 498843ca1100SSumit Saxena atomic64_inc(&event_counter); 4989fb9b0457SKashyap Desai } else { 4990fb9b0457SKashyap Desai mpi3mr_issue_reset(mrioc, 4991fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); 49922745ce0eSSreekanth Reddy mrioc->device_refresh_on = 0; 4993fb9b0457SKashyap Desai mrioc->unrecoverable = 1; 4994fb9b0457SKashyap Desai mrioc->reset_in_progress = 0; 4995fb9b0457SKashyap Desai retval = -1; 4996f2a79d20SSreekanth Reddy mpi3mr_flush_cmds_for_unrecovered_controller(mrioc); 4997fb9b0457SKashyap Desai } 4998b64845a7SSreekanth Reddy mrioc->prev_reset_result = retval; 4999fb9b0457SKashyap Desai mutex_unlock(&mrioc->reset_mutex); 5000b64845a7SSreekanth Reddy ioc_info(mrioc, "controller reset is %s\n", 5001b64845a7SSreekanth Reddy ((retval == 0) ? "successful" : "failed")); 5002fb9b0457SKashyap Desai return retval; 5003824a1566SKashyap Desai } 500432d457d5SSreekanth Reddy 500532d457d5SSreekanth Reddy 500632d457d5SSreekanth Reddy /** 500732d457d5SSreekanth Reddy * mpi3mr_free_config_dma_memory - free memory for config page 500832d457d5SSreekanth Reddy * @mrioc: Adapter instance reference 500932d457d5SSreekanth Reddy * @mem_desc: memory descriptor structure 501032d457d5SSreekanth Reddy * 501132d457d5SSreekanth Reddy * Check whether the size of the buffer specified by the memory 501232d457d5SSreekanth Reddy * descriptor is greater than the default page size if so then 501332d457d5SSreekanth Reddy * free the memory pointed by the descriptor. 501432d457d5SSreekanth Reddy * 501532d457d5SSreekanth Reddy * Return: Nothing. 501632d457d5SSreekanth Reddy */ 501732d457d5SSreekanth Reddy static void mpi3mr_free_config_dma_memory(struct mpi3mr_ioc *mrioc, 501832d457d5SSreekanth Reddy struct dma_memory_desc *mem_desc) 501932d457d5SSreekanth Reddy { 502032d457d5SSreekanth Reddy if ((mem_desc->size > mrioc->cfg_page_sz) && mem_desc->addr) { 502132d457d5SSreekanth Reddy dma_free_coherent(&mrioc->pdev->dev, mem_desc->size, 502232d457d5SSreekanth Reddy mem_desc->addr, mem_desc->dma_addr); 502332d457d5SSreekanth Reddy mem_desc->addr = NULL; 502432d457d5SSreekanth Reddy } 502532d457d5SSreekanth Reddy } 502632d457d5SSreekanth Reddy 502732d457d5SSreekanth Reddy /** 502832d457d5SSreekanth Reddy * mpi3mr_alloc_config_dma_memory - Alloc memory for config page 502932d457d5SSreekanth Reddy * @mrioc: Adapter instance reference 503032d457d5SSreekanth Reddy * @mem_desc: Memory descriptor to hold dma memory info 503132d457d5SSreekanth Reddy * 503232d457d5SSreekanth Reddy * This function allocates new dmaable memory or provides the 503332d457d5SSreekanth Reddy * default config page dmaable memory based on the memory size 503432d457d5SSreekanth Reddy * described by the descriptor. 503532d457d5SSreekanth Reddy * 503632d457d5SSreekanth Reddy * Return: 0 on success, non-zero on failure. 503732d457d5SSreekanth Reddy */ 503832d457d5SSreekanth Reddy static int mpi3mr_alloc_config_dma_memory(struct mpi3mr_ioc *mrioc, 503932d457d5SSreekanth Reddy struct dma_memory_desc *mem_desc) 504032d457d5SSreekanth Reddy { 504132d457d5SSreekanth Reddy if (mem_desc->size > mrioc->cfg_page_sz) { 504232d457d5SSreekanth Reddy mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev, 504332d457d5SSreekanth Reddy mem_desc->size, &mem_desc->dma_addr, GFP_KERNEL); 504432d457d5SSreekanth Reddy if (!mem_desc->addr) 504532d457d5SSreekanth Reddy return -ENOMEM; 504632d457d5SSreekanth Reddy } else { 504732d457d5SSreekanth Reddy mem_desc->addr = mrioc->cfg_page; 504832d457d5SSreekanth Reddy mem_desc->dma_addr = mrioc->cfg_page_dma; 504932d457d5SSreekanth Reddy memset(mem_desc->addr, 0, mrioc->cfg_page_sz); 505032d457d5SSreekanth Reddy } 505132d457d5SSreekanth Reddy return 0; 505232d457d5SSreekanth Reddy } 505332d457d5SSreekanth Reddy 505432d457d5SSreekanth Reddy /** 505532d457d5SSreekanth Reddy * mpi3mr_post_cfg_req - Issue config requests and wait 505632d457d5SSreekanth Reddy * @mrioc: Adapter instance reference 505732d457d5SSreekanth Reddy * @cfg_req: Configuration request 505832d457d5SSreekanth Reddy * @timeout: Timeout in seconds 505932d457d5SSreekanth Reddy * @ioc_status: Pointer to return ioc status 506032d457d5SSreekanth Reddy * 506132d457d5SSreekanth Reddy * A generic function for posting MPI3 configuration request to 506232d457d5SSreekanth Reddy * the firmware. This blocks for the completion of request for 506332d457d5SSreekanth Reddy * timeout seconds and if the request times out this function 506432d457d5SSreekanth Reddy * faults the controller with proper reason code. 506532d457d5SSreekanth Reddy * 506632d457d5SSreekanth Reddy * On successful completion of the request this function returns 506732d457d5SSreekanth Reddy * appropriate ioc status from the firmware back to the caller. 506832d457d5SSreekanth Reddy * 506932d457d5SSreekanth Reddy * Return: 0 on success, non-zero on failure. 507032d457d5SSreekanth Reddy */ 507132d457d5SSreekanth Reddy static int mpi3mr_post_cfg_req(struct mpi3mr_ioc *mrioc, 507232d457d5SSreekanth Reddy struct mpi3_config_request *cfg_req, int timeout, u16 *ioc_status) 507332d457d5SSreekanth Reddy { 507432d457d5SSreekanth Reddy int retval = 0; 507532d457d5SSreekanth Reddy 507632d457d5SSreekanth Reddy mutex_lock(&mrioc->cfg_cmds.mutex); 507732d457d5SSreekanth Reddy if (mrioc->cfg_cmds.state & MPI3MR_CMD_PENDING) { 507832d457d5SSreekanth Reddy retval = -1; 507932d457d5SSreekanth Reddy ioc_err(mrioc, "sending config request failed due to command in use\n"); 508032d457d5SSreekanth Reddy mutex_unlock(&mrioc->cfg_cmds.mutex); 508132d457d5SSreekanth Reddy goto out; 508232d457d5SSreekanth Reddy } 508332d457d5SSreekanth Reddy mrioc->cfg_cmds.state = MPI3MR_CMD_PENDING; 508432d457d5SSreekanth Reddy mrioc->cfg_cmds.is_waiting = 1; 508532d457d5SSreekanth Reddy mrioc->cfg_cmds.callback = NULL; 508632d457d5SSreekanth Reddy mrioc->cfg_cmds.ioc_status = 0; 508732d457d5SSreekanth Reddy mrioc->cfg_cmds.ioc_loginfo = 0; 508832d457d5SSreekanth Reddy 508932d457d5SSreekanth Reddy cfg_req->host_tag = cpu_to_le16(MPI3MR_HOSTTAG_CFG_CMDS); 509032d457d5SSreekanth Reddy cfg_req->function = MPI3_FUNCTION_CONFIG; 509132d457d5SSreekanth Reddy 509232d457d5SSreekanth Reddy init_completion(&mrioc->cfg_cmds.done); 509332d457d5SSreekanth Reddy dprint_cfg_info(mrioc, "posting config request\n"); 509432d457d5SSreekanth Reddy if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO) 509532d457d5SSreekanth Reddy dprint_dump(cfg_req, sizeof(struct mpi3_config_request), 509632d457d5SSreekanth Reddy "mpi3_cfg_req"); 509732d457d5SSreekanth Reddy retval = mpi3mr_admin_request_post(mrioc, cfg_req, sizeof(*cfg_req), 1); 509832d457d5SSreekanth Reddy if (retval) { 509932d457d5SSreekanth Reddy ioc_err(mrioc, "posting config request failed\n"); 510032d457d5SSreekanth Reddy goto out_unlock; 510132d457d5SSreekanth Reddy } 510232d457d5SSreekanth Reddy wait_for_completion_timeout(&mrioc->cfg_cmds.done, (timeout * HZ)); 510332d457d5SSreekanth Reddy if (!(mrioc->cfg_cmds.state & MPI3MR_CMD_COMPLETE)) { 510432d457d5SSreekanth Reddy mpi3mr_check_rh_fault_ioc(mrioc, 510532d457d5SSreekanth Reddy MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT); 510632d457d5SSreekanth Reddy ioc_err(mrioc, "config request timed out\n"); 510732d457d5SSreekanth Reddy retval = -1; 510832d457d5SSreekanth Reddy goto out_unlock; 510932d457d5SSreekanth Reddy } 511032d457d5SSreekanth Reddy *ioc_status = mrioc->cfg_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK; 511132d457d5SSreekanth Reddy if ((*ioc_status) != MPI3_IOCSTATUS_SUCCESS) 511232d457d5SSreekanth Reddy dprint_cfg_err(mrioc, 511332d457d5SSreekanth Reddy "cfg_page request returned with ioc_status(0x%04x), log_info(0x%08x)\n", 511432d457d5SSreekanth Reddy *ioc_status, mrioc->cfg_cmds.ioc_loginfo); 511532d457d5SSreekanth Reddy 511632d457d5SSreekanth Reddy out_unlock: 511732d457d5SSreekanth Reddy mrioc->cfg_cmds.state = MPI3MR_CMD_NOTUSED; 511832d457d5SSreekanth Reddy mutex_unlock(&mrioc->cfg_cmds.mutex); 511932d457d5SSreekanth Reddy 512032d457d5SSreekanth Reddy out: 512132d457d5SSreekanth Reddy return retval; 512232d457d5SSreekanth Reddy } 512332d457d5SSreekanth Reddy 512432d457d5SSreekanth Reddy /** 512532d457d5SSreekanth Reddy * mpi3mr_process_cfg_req - config page request processor 512632d457d5SSreekanth Reddy * @mrioc: Adapter instance reference 512732d457d5SSreekanth Reddy * @cfg_req: Configuration request 512832d457d5SSreekanth Reddy * @cfg_hdr: Configuration page header 512932d457d5SSreekanth Reddy * @timeout: Timeout in seconds 513032d457d5SSreekanth Reddy * @ioc_status: Pointer to return ioc status 513132d457d5SSreekanth Reddy * @cfg_buf: Memory pointer to copy config page or header 513232d457d5SSreekanth Reddy * @cfg_buf_sz: Size of the memory to get config page or header 513332d457d5SSreekanth Reddy * 513432d457d5SSreekanth Reddy * This is handler for config page read, write and config page 513532d457d5SSreekanth Reddy * header read operations. 513632d457d5SSreekanth Reddy * 513732d457d5SSreekanth Reddy * This function expects the cfg_req to be populated with page 513832d457d5SSreekanth Reddy * type, page number, action for the header read and with page 513932d457d5SSreekanth Reddy * address for all other operations. 514032d457d5SSreekanth Reddy * 514132d457d5SSreekanth Reddy * The cfg_hdr can be passed as null for reading required header 514232d457d5SSreekanth Reddy * details for read/write pages the cfg_hdr should point valid 514332d457d5SSreekanth Reddy * configuration page header. 514432d457d5SSreekanth Reddy * 514532d457d5SSreekanth Reddy * This allocates dmaable memory based on the size of the config 514632d457d5SSreekanth Reddy * buffer and set the SGE of the cfg_req. 514732d457d5SSreekanth Reddy * 514832d457d5SSreekanth Reddy * For write actions, the config page data has to be passed in 514932d457d5SSreekanth Reddy * the cfg_buf and size of the data has to be mentioned in the 515032d457d5SSreekanth Reddy * cfg_buf_sz. 515132d457d5SSreekanth Reddy * 515232d457d5SSreekanth Reddy * For read/header actions, on successful completion of the 515332d457d5SSreekanth Reddy * request with successful ioc_status the data will be copied 515432d457d5SSreekanth Reddy * into the cfg_buf limited to a minimum of actual page size and 515532d457d5SSreekanth Reddy * cfg_buf_sz 515632d457d5SSreekanth Reddy * 515732d457d5SSreekanth Reddy * 515832d457d5SSreekanth Reddy * Return: 0 on success, non-zero on failure. 515932d457d5SSreekanth Reddy */ 516032d457d5SSreekanth Reddy static int mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc, 516132d457d5SSreekanth Reddy struct mpi3_config_request *cfg_req, 516232d457d5SSreekanth Reddy struct mpi3_config_page_header *cfg_hdr, int timeout, u16 *ioc_status, 516332d457d5SSreekanth Reddy void *cfg_buf, u32 cfg_buf_sz) 516432d457d5SSreekanth Reddy { 516532d457d5SSreekanth Reddy struct dma_memory_desc mem_desc; 516632d457d5SSreekanth Reddy int retval = -1; 516732d457d5SSreekanth Reddy u8 invalid_action = 0; 516832d457d5SSreekanth Reddy u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 516932d457d5SSreekanth Reddy 517032d457d5SSreekanth Reddy memset(&mem_desc, 0, sizeof(struct dma_memory_desc)); 517132d457d5SSreekanth Reddy 517232d457d5SSreekanth Reddy if (cfg_req->action == MPI3_CONFIG_ACTION_PAGE_HEADER) 517332d457d5SSreekanth Reddy mem_desc.size = sizeof(struct mpi3_config_page_header); 517432d457d5SSreekanth Reddy else { 517532d457d5SSreekanth Reddy if (!cfg_hdr) { 517632d457d5SSreekanth Reddy ioc_err(mrioc, "null config header passed for config action(%d), page_type(0x%02x), page_num(%d)\n", 517732d457d5SSreekanth Reddy cfg_req->action, cfg_req->page_type, 517832d457d5SSreekanth Reddy cfg_req->page_number); 517932d457d5SSreekanth Reddy goto out; 518032d457d5SSreekanth Reddy } 518132d457d5SSreekanth Reddy switch (cfg_hdr->page_attribute & MPI3_CONFIG_PAGEATTR_MASK) { 518232d457d5SSreekanth Reddy case MPI3_CONFIG_PAGEATTR_READ_ONLY: 518332d457d5SSreekanth Reddy if (cfg_req->action 518432d457d5SSreekanth Reddy != MPI3_CONFIG_ACTION_READ_CURRENT) 518532d457d5SSreekanth Reddy invalid_action = 1; 518632d457d5SSreekanth Reddy break; 518732d457d5SSreekanth Reddy case MPI3_CONFIG_PAGEATTR_CHANGEABLE: 518832d457d5SSreekanth Reddy if ((cfg_req->action == 518932d457d5SSreekanth Reddy MPI3_CONFIG_ACTION_READ_PERSISTENT) || 519032d457d5SSreekanth Reddy (cfg_req->action == 519132d457d5SSreekanth Reddy MPI3_CONFIG_ACTION_WRITE_PERSISTENT)) 519232d457d5SSreekanth Reddy invalid_action = 1; 519332d457d5SSreekanth Reddy break; 519432d457d5SSreekanth Reddy case MPI3_CONFIG_PAGEATTR_PERSISTENT: 519532d457d5SSreekanth Reddy default: 519632d457d5SSreekanth Reddy break; 519732d457d5SSreekanth Reddy } 519832d457d5SSreekanth Reddy if (invalid_action) { 519932d457d5SSreekanth Reddy ioc_err(mrioc, 520032d457d5SSreekanth Reddy "config action(%d) is not allowed for page_type(0x%02x), page_num(%d) with page_attribute(0x%02x)\n", 520132d457d5SSreekanth Reddy cfg_req->action, cfg_req->page_type, 520232d457d5SSreekanth Reddy cfg_req->page_number, cfg_hdr->page_attribute); 520332d457d5SSreekanth Reddy goto out; 520432d457d5SSreekanth Reddy } 520532d457d5SSreekanth Reddy mem_desc.size = le16_to_cpu(cfg_hdr->page_length) * 4; 520632d457d5SSreekanth Reddy cfg_req->page_length = cfg_hdr->page_length; 520732d457d5SSreekanth Reddy cfg_req->page_version = cfg_hdr->page_version; 520832d457d5SSreekanth Reddy } 520932d457d5SSreekanth Reddy if (mpi3mr_alloc_config_dma_memory(mrioc, &mem_desc)) 521032d457d5SSreekanth Reddy goto out; 521132d457d5SSreekanth Reddy 521232d457d5SSreekanth Reddy mpi3mr_add_sg_single(&cfg_req->sgl, sgl_flags, mem_desc.size, 521332d457d5SSreekanth Reddy mem_desc.dma_addr); 521432d457d5SSreekanth Reddy 521532d457d5SSreekanth Reddy if ((cfg_req->action == MPI3_CONFIG_ACTION_WRITE_PERSISTENT) || 521632d457d5SSreekanth Reddy (cfg_req->action == MPI3_CONFIG_ACTION_WRITE_CURRENT)) { 521732d457d5SSreekanth Reddy memcpy(mem_desc.addr, cfg_buf, min_t(u16, mem_desc.size, 521832d457d5SSreekanth Reddy cfg_buf_sz)); 521932d457d5SSreekanth Reddy dprint_cfg_info(mrioc, "config buffer to be written\n"); 522032d457d5SSreekanth Reddy if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO) 522132d457d5SSreekanth Reddy dprint_dump(mem_desc.addr, mem_desc.size, "cfg_buf"); 522232d457d5SSreekanth Reddy } 522332d457d5SSreekanth Reddy 522432d457d5SSreekanth Reddy if (mpi3mr_post_cfg_req(mrioc, cfg_req, timeout, ioc_status)) 522532d457d5SSreekanth Reddy goto out; 522632d457d5SSreekanth Reddy 522732d457d5SSreekanth Reddy retval = 0; 522832d457d5SSreekanth Reddy if ((*ioc_status == MPI3_IOCSTATUS_SUCCESS) && 522932d457d5SSreekanth Reddy (cfg_req->action != MPI3_CONFIG_ACTION_WRITE_PERSISTENT) && 523032d457d5SSreekanth Reddy (cfg_req->action != MPI3_CONFIG_ACTION_WRITE_CURRENT)) { 523132d457d5SSreekanth Reddy memcpy(cfg_buf, mem_desc.addr, min_t(u16, mem_desc.size, 523232d457d5SSreekanth Reddy cfg_buf_sz)); 523332d457d5SSreekanth Reddy dprint_cfg_info(mrioc, "config buffer read\n"); 523432d457d5SSreekanth Reddy if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO) 523532d457d5SSreekanth Reddy dprint_dump(mem_desc.addr, mem_desc.size, "cfg_buf"); 523632d457d5SSreekanth Reddy } 523732d457d5SSreekanth Reddy 523832d457d5SSreekanth Reddy out: 523932d457d5SSreekanth Reddy mpi3mr_free_config_dma_memory(mrioc, &mem_desc); 524032d457d5SSreekanth Reddy return retval; 524132d457d5SSreekanth Reddy } 524264a8d931SSreekanth Reddy 524364a8d931SSreekanth Reddy /** 524464a8d931SSreekanth Reddy * mpi3mr_cfg_get_dev_pg0 - Read current device page0 524564a8d931SSreekanth Reddy * @mrioc: Adapter instance reference 524664a8d931SSreekanth Reddy * @ioc_status: Pointer to return ioc status 524764a8d931SSreekanth Reddy * @dev_pg0: Pointer to return device page 0 524864a8d931SSreekanth Reddy * @pg_sz: Size of the memory allocated to the page pointer 524964a8d931SSreekanth Reddy * @form: The form to be used for addressing the page 525064a8d931SSreekanth Reddy * @form_spec: Form specific information like device handle 525164a8d931SSreekanth Reddy * 525264a8d931SSreekanth Reddy * This is handler for config page read for a specific device 525364a8d931SSreekanth Reddy * page0. The ioc_status has the controller returned ioc_status. 525464a8d931SSreekanth Reddy * This routine doesn't check ioc_status to decide whether the 525564a8d931SSreekanth Reddy * page read is success or not and it is the callers 525664a8d931SSreekanth Reddy * responsibility. 525764a8d931SSreekanth Reddy * 525864a8d931SSreekanth Reddy * Return: 0 on success, non-zero on failure. 525964a8d931SSreekanth Reddy */ 526064a8d931SSreekanth Reddy int mpi3mr_cfg_get_dev_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status, 526164a8d931SSreekanth Reddy struct mpi3_device_page0 *dev_pg0, u16 pg_sz, u32 form, u32 form_spec) 526264a8d931SSreekanth Reddy { 526364a8d931SSreekanth Reddy struct mpi3_config_page_header cfg_hdr; 526464a8d931SSreekanth Reddy struct mpi3_config_request cfg_req; 526564a8d931SSreekanth Reddy u32 page_address; 526664a8d931SSreekanth Reddy 526764a8d931SSreekanth Reddy memset(dev_pg0, 0, pg_sz); 526864a8d931SSreekanth Reddy memset(&cfg_hdr, 0, sizeof(cfg_hdr)); 526964a8d931SSreekanth Reddy memset(&cfg_req, 0, sizeof(cfg_req)); 527064a8d931SSreekanth Reddy 527164a8d931SSreekanth Reddy cfg_req.function = MPI3_FUNCTION_CONFIG; 527264a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER; 527364a8d931SSreekanth Reddy cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DEVICE; 527464a8d931SSreekanth Reddy cfg_req.page_number = 0; 527564a8d931SSreekanth Reddy cfg_req.page_address = 0; 527664a8d931SSreekanth Reddy 527764a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL, 527864a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) { 527964a8d931SSreekanth Reddy ioc_err(mrioc, "device page0 header read failed\n"); 528064a8d931SSreekanth Reddy goto out_failed; 528164a8d931SSreekanth Reddy } 528264a8d931SSreekanth Reddy if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) { 528364a8d931SSreekanth Reddy ioc_err(mrioc, "device page0 header read failed with ioc_status(0x%04x)\n", 528464a8d931SSreekanth Reddy *ioc_status); 528564a8d931SSreekanth Reddy goto out_failed; 528664a8d931SSreekanth Reddy } 528764a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT; 528864a8d931SSreekanth Reddy page_address = ((form & MPI3_DEVICE_PGAD_FORM_MASK) | 528964a8d931SSreekanth Reddy (form_spec & MPI3_DEVICE_PGAD_HANDLE_MASK)); 529064a8d931SSreekanth Reddy cfg_req.page_address = cpu_to_le32(page_address); 529164a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr, 529264a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, ioc_status, dev_pg0, pg_sz)) { 529364a8d931SSreekanth Reddy ioc_err(mrioc, "device page0 read failed\n"); 529464a8d931SSreekanth Reddy goto out_failed; 529564a8d931SSreekanth Reddy } 529664a8d931SSreekanth Reddy return 0; 529764a8d931SSreekanth Reddy out_failed: 529864a8d931SSreekanth Reddy return -1; 529964a8d931SSreekanth Reddy } 530064a8d931SSreekanth Reddy 530164a8d931SSreekanth Reddy 530264a8d931SSreekanth Reddy /** 530364a8d931SSreekanth Reddy * mpi3mr_cfg_get_sas_phy_pg0 - Read current SAS Phy page0 530464a8d931SSreekanth Reddy * @mrioc: Adapter instance reference 530564a8d931SSreekanth Reddy * @ioc_status: Pointer to return ioc status 530664a8d931SSreekanth Reddy * @phy_pg0: Pointer to return SAS Phy page 0 530764a8d931SSreekanth Reddy * @pg_sz: Size of the memory allocated to the page pointer 530864a8d931SSreekanth Reddy * @form: The form to be used for addressing the page 530964a8d931SSreekanth Reddy * @form_spec: Form specific information like phy number 531064a8d931SSreekanth Reddy * 531164a8d931SSreekanth Reddy * This is handler for config page read for a specific SAS Phy 531264a8d931SSreekanth Reddy * page0. The ioc_status has the controller returned ioc_status. 531364a8d931SSreekanth Reddy * This routine doesn't check ioc_status to decide whether the 531464a8d931SSreekanth Reddy * page read is success or not and it is the callers 531564a8d931SSreekanth Reddy * responsibility. 531664a8d931SSreekanth Reddy * 531764a8d931SSreekanth Reddy * Return: 0 on success, non-zero on failure. 531864a8d931SSreekanth Reddy */ 531964a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_phy_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status, 532064a8d931SSreekanth Reddy struct mpi3_sas_phy_page0 *phy_pg0, u16 pg_sz, u32 form, 532164a8d931SSreekanth Reddy u32 form_spec) 532264a8d931SSreekanth Reddy { 532364a8d931SSreekanth Reddy struct mpi3_config_page_header cfg_hdr; 532464a8d931SSreekanth Reddy struct mpi3_config_request cfg_req; 532564a8d931SSreekanth Reddy u32 page_address; 532664a8d931SSreekanth Reddy 532764a8d931SSreekanth Reddy memset(phy_pg0, 0, pg_sz); 532864a8d931SSreekanth Reddy memset(&cfg_hdr, 0, sizeof(cfg_hdr)); 532964a8d931SSreekanth Reddy memset(&cfg_req, 0, sizeof(cfg_req)); 533064a8d931SSreekanth Reddy 533164a8d931SSreekanth Reddy cfg_req.function = MPI3_FUNCTION_CONFIG; 533264a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER; 533364a8d931SSreekanth Reddy cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_PHY; 533464a8d931SSreekanth Reddy cfg_req.page_number = 0; 533564a8d931SSreekanth Reddy cfg_req.page_address = 0; 533664a8d931SSreekanth Reddy 533764a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL, 533864a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) { 533964a8d931SSreekanth Reddy ioc_err(mrioc, "sas phy page0 header read failed\n"); 534064a8d931SSreekanth Reddy goto out_failed; 534164a8d931SSreekanth Reddy } 534264a8d931SSreekanth Reddy if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) { 534364a8d931SSreekanth Reddy ioc_err(mrioc, "sas phy page0 header read failed with ioc_status(0x%04x)\n", 534464a8d931SSreekanth Reddy *ioc_status); 534564a8d931SSreekanth Reddy goto out_failed; 534664a8d931SSreekanth Reddy } 534764a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT; 534864a8d931SSreekanth Reddy page_address = ((form & MPI3_SAS_PHY_PGAD_FORM_MASK) | 534964a8d931SSreekanth Reddy (form_spec & MPI3_SAS_PHY_PGAD_PHY_NUMBER_MASK)); 535064a8d931SSreekanth Reddy cfg_req.page_address = cpu_to_le32(page_address); 535164a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr, 535264a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, ioc_status, phy_pg0, pg_sz)) { 535364a8d931SSreekanth Reddy ioc_err(mrioc, "sas phy page0 read failed\n"); 535464a8d931SSreekanth Reddy goto out_failed; 535564a8d931SSreekanth Reddy } 535664a8d931SSreekanth Reddy return 0; 535764a8d931SSreekanth Reddy out_failed: 535864a8d931SSreekanth Reddy return -1; 535964a8d931SSreekanth Reddy } 536064a8d931SSreekanth Reddy 536164a8d931SSreekanth Reddy /** 536264a8d931SSreekanth Reddy * mpi3mr_cfg_get_sas_phy_pg1 - Read current SAS Phy page1 536364a8d931SSreekanth Reddy * @mrioc: Adapter instance reference 536464a8d931SSreekanth Reddy * @ioc_status: Pointer to return ioc status 536564a8d931SSreekanth Reddy * @phy_pg1: Pointer to return SAS Phy page 1 536664a8d931SSreekanth Reddy * @pg_sz: Size of the memory allocated to the page pointer 536764a8d931SSreekanth Reddy * @form: The form to be used for addressing the page 536864a8d931SSreekanth Reddy * @form_spec: Form specific information like phy number 536964a8d931SSreekanth Reddy * 537064a8d931SSreekanth Reddy * This is handler for config page read for a specific SAS Phy 537164a8d931SSreekanth Reddy * page1. The ioc_status has the controller returned ioc_status. 537264a8d931SSreekanth Reddy * This routine doesn't check ioc_status to decide whether the 537364a8d931SSreekanth Reddy * page read is success or not and it is the callers 537464a8d931SSreekanth Reddy * responsibility. 537564a8d931SSreekanth Reddy * 537664a8d931SSreekanth Reddy * Return: 0 on success, non-zero on failure. 537764a8d931SSreekanth Reddy */ 537864a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_phy_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status, 537964a8d931SSreekanth Reddy struct mpi3_sas_phy_page1 *phy_pg1, u16 pg_sz, u32 form, 538064a8d931SSreekanth Reddy u32 form_spec) 538164a8d931SSreekanth Reddy { 538264a8d931SSreekanth Reddy struct mpi3_config_page_header cfg_hdr; 538364a8d931SSreekanth Reddy struct mpi3_config_request cfg_req; 538464a8d931SSreekanth Reddy u32 page_address; 538564a8d931SSreekanth Reddy 538664a8d931SSreekanth Reddy memset(phy_pg1, 0, pg_sz); 538764a8d931SSreekanth Reddy memset(&cfg_hdr, 0, sizeof(cfg_hdr)); 538864a8d931SSreekanth Reddy memset(&cfg_req, 0, sizeof(cfg_req)); 538964a8d931SSreekanth Reddy 539064a8d931SSreekanth Reddy cfg_req.function = MPI3_FUNCTION_CONFIG; 539164a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER; 539264a8d931SSreekanth Reddy cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_PHY; 539364a8d931SSreekanth Reddy cfg_req.page_number = 1; 539464a8d931SSreekanth Reddy cfg_req.page_address = 0; 539564a8d931SSreekanth Reddy 539664a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL, 539764a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) { 539864a8d931SSreekanth Reddy ioc_err(mrioc, "sas phy page1 header read failed\n"); 539964a8d931SSreekanth Reddy goto out_failed; 540064a8d931SSreekanth Reddy } 540164a8d931SSreekanth Reddy if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) { 540264a8d931SSreekanth Reddy ioc_err(mrioc, "sas phy page1 header read failed with ioc_status(0x%04x)\n", 540364a8d931SSreekanth Reddy *ioc_status); 540464a8d931SSreekanth Reddy goto out_failed; 540564a8d931SSreekanth Reddy } 540664a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT; 540764a8d931SSreekanth Reddy page_address = ((form & MPI3_SAS_PHY_PGAD_FORM_MASK) | 540864a8d931SSreekanth Reddy (form_spec & MPI3_SAS_PHY_PGAD_PHY_NUMBER_MASK)); 540964a8d931SSreekanth Reddy cfg_req.page_address = cpu_to_le32(page_address); 541064a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr, 541164a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, ioc_status, phy_pg1, pg_sz)) { 541264a8d931SSreekanth Reddy ioc_err(mrioc, "sas phy page1 read failed\n"); 541364a8d931SSreekanth Reddy goto out_failed; 541464a8d931SSreekanth Reddy } 541564a8d931SSreekanth Reddy return 0; 541664a8d931SSreekanth Reddy out_failed: 541764a8d931SSreekanth Reddy return -1; 541864a8d931SSreekanth Reddy } 541964a8d931SSreekanth Reddy 542064a8d931SSreekanth Reddy 542164a8d931SSreekanth Reddy /** 542264a8d931SSreekanth Reddy * mpi3mr_cfg_get_sas_exp_pg0 - Read current SAS Expander page0 542364a8d931SSreekanth Reddy * @mrioc: Adapter instance reference 542464a8d931SSreekanth Reddy * @ioc_status: Pointer to return ioc status 542564a8d931SSreekanth Reddy * @exp_pg0: Pointer to return SAS Expander page 0 542664a8d931SSreekanth Reddy * @pg_sz: Size of the memory allocated to the page pointer 542764a8d931SSreekanth Reddy * @form: The form to be used for addressing the page 542864a8d931SSreekanth Reddy * @form_spec: Form specific information like device handle 542964a8d931SSreekanth Reddy * 543064a8d931SSreekanth Reddy * This is handler for config page read for a specific SAS 543164a8d931SSreekanth Reddy * Expander page0. The ioc_status has the controller returned 543264a8d931SSreekanth Reddy * ioc_status. This routine doesn't check ioc_status to decide 543364a8d931SSreekanth Reddy * whether the page read is success or not and it is the callers 543464a8d931SSreekanth Reddy * responsibility. 543564a8d931SSreekanth Reddy * 543664a8d931SSreekanth Reddy * Return: 0 on success, non-zero on failure. 543764a8d931SSreekanth Reddy */ 543864a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_exp_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status, 543964a8d931SSreekanth Reddy struct mpi3_sas_expander_page0 *exp_pg0, u16 pg_sz, u32 form, 544064a8d931SSreekanth Reddy u32 form_spec) 544164a8d931SSreekanth Reddy { 544264a8d931SSreekanth Reddy struct mpi3_config_page_header cfg_hdr; 544364a8d931SSreekanth Reddy struct mpi3_config_request cfg_req; 544464a8d931SSreekanth Reddy u32 page_address; 544564a8d931SSreekanth Reddy 544664a8d931SSreekanth Reddy memset(exp_pg0, 0, pg_sz); 544764a8d931SSreekanth Reddy memset(&cfg_hdr, 0, sizeof(cfg_hdr)); 544864a8d931SSreekanth Reddy memset(&cfg_req, 0, sizeof(cfg_req)); 544964a8d931SSreekanth Reddy 545064a8d931SSreekanth Reddy cfg_req.function = MPI3_FUNCTION_CONFIG; 545164a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER; 545264a8d931SSreekanth Reddy cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_EXPANDER; 545364a8d931SSreekanth Reddy cfg_req.page_number = 0; 545464a8d931SSreekanth Reddy cfg_req.page_address = 0; 545564a8d931SSreekanth Reddy 545664a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL, 545764a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) { 545864a8d931SSreekanth Reddy ioc_err(mrioc, "expander page0 header read failed\n"); 545964a8d931SSreekanth Reddy goto out_failed; 546064a8d931SSreekanth Reddy } 546164a8d931SSreekanth Reddy if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) { 546264a8d931SSreekanth Reddy ioc_err(mrioc, "expander page0 header read failed with ioc_status(0x%04x)\n", 546364a8d931SSreekanth Reddy *ioc_status); 546464a8d931SSreekanth Reddy goto out_failed; 546564a8d931SSreekanth Reddy } 546664a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT; 546764a8d931SSreekanth Reddy page_address = ((form & MPI3_SAS_EXPAND_PGAD_FORM_MASK) | 546864a8d931SSreekanth Reddy (form_spec & (MPI3_SAS_EXPAND_PGAD_PHYNUM_MASK | 546964a8d931SSreekanth Reddy MPI3_SAS_EXPAND_PGAD_HANDLE_MASK))); 547064a8d931SSreekanth Reddy cfg_req.page_address = cpu_to_le32(page_address); 547164a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr, 547264a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, ioc_status, exp_pg0, pg_sz)) { 547364a8d931SSreekanth Reddy ioc_err(mrioc, "expander page0 read failed\n"); 547464a8d931SSreekanth Reddy goto out_failed; 547564a8d931SSreekanth Reddy } 547664a8d931SSreekanth Reddy return 0; 547764a8d931SSreekanth Reddy out_failed: 547864a8d931SSreekanth Reddy return -1; 547964a8d931SSreekanth Reddy } 548064a8d931SSreekanth Reddy 548164a8d931SSreekanth Reddy /** 548264a8d931SSreekanth Reddy * mpi3mr_cfg_get_sas_exp_pg1 - Read current SAS Expander page1 548364a8d931SSreekanth Reddy * @mrioc: Adapter instance reference 548464a8d931SSreekanth Reddy * @ioc_status: Pointer to return ioc status 548564a8d931SSreekanth Reddy * @exp_pg1: Pointer to return SAS Expander page 1 548664a8d931SSreekanth Reddy * @pg_sz: Size of the memory allocated to the page pointer 548764a8d931SSreekanth Reddy * @form: The form to be used for addressing the page 548864a8d931SSreekanth Reddy * @form_spec: Form specific information like phy number 548964a8d931SSreekanth Reddy * 549064a8d931SSreekanth Reddy * This is handler for config page read for a specific SAS 549164a8d931SSreekanth Reddy * Expander page1. The ioc_status has the controller returned 549264a8d931SSreekanth Reddy * ioc_status. This routine doesn't check ioc_status to decide 549364a8d931SSreekanth Reddy * whether the page read is success or not and it is the callers 549464a8d931SSreekanth Reddy * responsibility. 549564a8d931SSreekanth Reddy * 549664a8d931SSreekanth Reddy * Return: 0 on success, non-zero on failure. 549764a8d931SSreekanth Reddy */ 549864a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_exp_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status, 549964a8d931SSreekanth Reddy struct mpi3_sas_expander_page1 *exp_pg1, u16 pg_sz, u32 form, 550064a8d931SSreekanth Reddy u32 form_spec) 550164a8d931SSreekanth Reddy { 550264a8d931SSreekanth Reddy struct mpi3_config_page_header cfg_hdr; 550364a8d931SSreekanth Reddy struct mpi3_config_request cfg_req; 550464a8d931SSreekanth Reddy u32 page_address; 550564a8d931SSreekanth Reddy 550664a8d931SSreekanth Reddy memset(exp_pg1, 0, pg_sz); 550764a8d931SSreekanth Reddy memset(&cfg_hdr, 0, sizeof(cfg_hdr)); 550864a8d931SSreekanth Reddy memset(&cfg_req, 0, sizeof(cfg_req)); 550964a8d931SSreekanth Reddy 551064a8d931SSreekanth Reddy cfg_req.function = MPI3_FUNCTION_CONFIG; 551164a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER; 551264a8d931SSreekanth Reddy cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_EXPANDER; 551364a8d931SSreekanth Reddy cfg_req.page_number = 1; 551464a8d931SSreekanth Reddy cfg_req.page_address = 0; 551564a8d931SSreekanth Reddy 551664a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL, 551764a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) { 551864a8d931SSreekanth Reddy ioc_err(mrioc, "expander page1 header read failed\n"); 551964a8d931SSreekanth Reddy goto out_failed; 552064a8d931SSreekanth Reddy } 552164a8d931SSreekanth Reddy if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) { 552264a8d931SSreekanth Reddy ioc_err(mrioc, "expander page1 header read failed with ioc_status(0x%04x)\n", 552364a8d931SSreekanth Reddy *ioc_status); 552464a8d931SSreekanth Reddy goto out_failed; 552564a8d931SSreekanth Reddy } 552664a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT; 552764a8d931SSreekanth Reddy page_address = ((form & MPI3_SAS_EXPAND_PGAD_FORM_MASK) | 552864a8d931SSreekanth Reddy (form_spec & (MPI3_SAS_EXPAND_PGAD_PHYNUM_MASK | 552964a8d931SSreekanth Reddy MPI3_SAS_EXPAND_PGAD_HANDLE_MASK))); 553064a8d931SSreekanth Reddy cfg_req.page_address = cpu_to_le32(page_address); 553164a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr, 553264a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, ioc_status, exp_pg1, pg_sz)) { 553364a8d931SSreekanth Reddy ioc_err(mrioc, "expander page1 read failed\n"); 553464a8d931SSreekanth Reddy goto out_failed; 553564a8d931SSreekanth Reddy } 553664a8d931SSreekanth Reddy return 0; 553764a8d931SSreekanth Reddy out_failed: 553864a8d931SSreekanth Reddy return -1; 553964a8d931SSreekanth Reddy } 554064a8d931SSreekanth Reddy 554164a8d931SSreekanth Reddy /** 554264a8d931SSreekanth Reddy * mpi3mr_cfg_get_enclosure_pg0 - Read current Enclosure page0 554364a8d931SSreekanth Reddy * @mrioc: Adapter instance reference 554464a8d931SSreekanth Reddy * @ioc_status: Pointer to return ioc status 554564a8d931SSreekanth Reddy * @encl_pg0: Pointer to return Enclosure page 0 554664a8d931SSreekanth Reddy * @pg_sz: Size of the memory allocated to the page pointer 554764a8d931SSreekanth Reddy * @form: The form to be used for addressing the page 554864a8d931SSreekanth Reddy * @form_spec: Form specific information like device handle 554964a8d931SSreekanth Reddy * 555064a8d931SSreekanth Reddy * This is handler for config page read for a specific Enclosure 555164a8d931SSreekanth Reddy * page0. The ioc_status has the controller returned ioc_status. 555264a8d931SSreekanth Reddy * This routine doesn't check ioc_status to decide whether the 555364a8d931SSreekanth Reddy * page read is success or not and it is the callers 555464a8d931SSreekanth Reddy * responsibility. 555564a8d931SSreekanth Reddy * 555664a8d931SSreekanth Reddy * Return: 0 on success, non-zero on failure. 555764a8d931SSreekanth Reddy */ 555864a8d931SSreekanth Reddy int mpi3mr_cfg_get_enclosure_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status, 555964a8d931SSreekanth Reddy struct mpi3_enclosure_page0 *encl_pg0, u16 pg_sz, u32 form, 556064a8d931SSreekanth Reddy u32 form_spec) 556164a8d931SSreekanth Reddy { 556264a8d931SSreekanth Reddy struct mpi3_config_page_header cfg_hdr; 556364a8d931SSreekanth Reddy struct mpi3_config_request cfg_req; 556464a8d931SSreekanth Reddy u32 page_address; 556564a8d931SSreekanth Reddy 556664a8d931SSreekanth Reddy memset(encl_pg0, 0, pg_sz); 556764a8d931SSreekanth Reddy memset(&cfg_hdr, 0, sizeof(cfg_hdr)); 556864a8d931SSreekanth Reddy memset(&cfg_req, 0, sizeof(cfg_req)); 556964a8d931SSreekanth Reddy 557064a8d931SSreekanth Reddy cfg_req.function = MPI3_FUNCTION_CONFIG; 557164a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER; 557264a8d931SSreekanth Reddy cfg_req.page_type = MPI3_CONFIG_PAGETYPE_ENCLOSURE; 557364a8d931SSreekanth Reddy cfg_req.page_number = 0; 557464a8d931SSreekanth Reddy cfg_req.page_address = 0; 557564a8d931SSreekanth Reddy 557664a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL, 557764a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) { 557864a8d931SSreekanth Reddy ioc_err(mrioc, "enclosure page0 header read failed\n"); 557964a8d931SSreekanth Reddy goto out_failed; 558064a8d931SSreekanth Reddy } 558164a8d931SSreekanth Reddy if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) { 558264a8d931SSreekanth Reddy ioc_err(mrioc, "enclosure page0 header read failed with ioc_status(0x%04x)\n", 558364a8d931SSreekanth Reddy *ioc_status); 558464a8d931SSreekanth Reddy goto out_failed; 558564a8d931SSreekanth Reddy } 558664a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT; 558764a8d931SSreekanth Reddy page_address = ((form & MPI3_ENCLOS_PGAD_FORM_MASK) | 558864a8d931SSreekanth Reddy (form_spec & MPI3_ENCLOS_PGAD_HANDLE_MASK)); 558964a8d931SSreekanth Reddy cfg_req.page_address = cpu_to_le32(page_address); 559064a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr, 559164a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, ioc_status, encl_pg0, pg_sz)) { 559264a8d931SSreekanth Reddy ioc_err(mrioc, "enclosure page0 read failed\n"); 559364a8d931SSreekanth Reddy goto out_failed; 559464a8d931SSreekanth Reddy } 559564a8d931SSreekanth Reddy return 0; 559664a8d931SSreekanth Reddy out_failed: 559764a8d931SSreekanth Reddy return -1; 559864a8d931SSreekanth Reddy } 559964a8d931SSreekanth Reddy 560064a8d931SSreekanth Reddy 560164a8d931SSreekanth Reddy /** 560264a8d931SSreekanth Reddy * mpi3mr_cfg_get_sas_io_unit_pg0 - Read current SASIOUnit page0 560364a8d931SSreekanth Reddy * @mrioc: Adapter instance reference 560464a8d931SSreekanth Reddy * @sas_io_unit_pg0: Pointer to return SAS IO Unit page 0 560564a8d931SSreekanth Reddy * @pg_sz: Size of the memory allocated to the page pointer 560664a8d931SSreekanth Reddy * 560764a8d931SSreekanth Reddy * This is handler for config page read for the SAS IO Unit 560864a8d931SSreekanth Reddy * page0. This routine checks ioc_status to decide whether the 560964a8d931SSreekanth Reddy * page read is success or not. 561064a8d931SSreekanth Reddy * 561164a8d931SSreekanth Reddy * Return: 0 on success, non-zero on failure. 561264a8d931SSreekanth Reddy */ 561364a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_io_unit_pg0(struct mpi3mr_ioc *mrioc, 561464a8d931SSreekanth Reddy struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0, u16 pg_sz) 561564a8d931SSreekanth Reddy { 561664a8d931SSreekanth Reddy struct mpi3_config_page_header cfg_hdr; 561764a8d931SSreekanth Reddy struct mpi3_config_request cfg_req; 561864a8d931SSreekanth Reddy u16 ioc_status = 0; 561964a8d931SSreekanth Reddy 562064a8d931SSreekanth Reddy memset(sas_io_unit_pg0, 0, pg_sz); 562164a8d931SSreekanth Reddy memset(&cfg_hdr, 0, sizeof(cfg_hdr)); 562264a8d931SSreekanth Reddy memset(&cfg_req, 0, sizeof(cfg_req)); 562364a8d931SSreekanth Reddy 562464a8d931SSreekanth Reddy cfg_req.function = MPI3_FUNCTION_CONFIG; 562564a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER; 562664a8d931SSreekanth Reddy cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT; 562764a8d931SSreekanth Reddy cfg_req.page_number = 0; 562864a8d931SSreekanth Reddy cfg_req.page_address = 0; 562964a8d931SSreekanth Reddy 563064a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL, 563164a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) { 563264a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page0 header read failed\n"); 563364a8d931SSreekanth Reddy goto out_failed; 563464a8d931SSreekanth Reddy } 563564a8d931SSreekanth Reddy if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { 563664a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page0 header read failed with ioc_status(0x%04x)\n", 563764a8d931SSreekanth Reddy ioc_status); 563864a8d931SSreekanth Reddy goto out_failed; 563964a8d931SSreekanth Reddy } 564064a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT; 564164a8d931SSreekanth Reddy 564264a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr, 564364a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg0, pg_sz)) { 564464a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page0 read failed\n"); 564564a8d931SSreekanth Reddy goto out_failed; 564664a8d931SSreekanth Reddy } 564764a8d931SSreekanth Reddy if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { 564864a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page0 read failed with ioc_status(0x%04x)\n", 564964a8d931SSreekanth Reddy ioc_status); 565064a8d931SSreekanth Reddy goto out_failed; 565164a8d931SSreekanth Reddy } 565264a8d931SSreekanth Reddy return 0; 565364a8d931SSreekanth Reddy out_failed: 565464a8d931SSreekanth Reddy return -1; 565564a8d931SSreekanth Reddy } 565664a8d931SSreekanth Reddy 565764a8d931SSreekanth Reddy /** 565864a8d931SSreekanth Reddy * mpi3mr_cfg_get_sas_io_unit_pg1 - Read current SASIOUnit page1 565964a8d931SSreekanth Reddy * @mrioc: Adapter instance reference 566064a8d931SSreekanth Reddy * @sas_io_unit_pg1: Pointer to return SAS IO Unit page 1 566164a8d931SSreekanth Reddy * @pg_sz: Size of the memory allocated to the page pointer 566264a8d931SSreekanth Reddy * 566364a8d931SSreekanth Reddy * This is handler for config page read for the SAS IO Unit 566464a8d931SSreekanth Reddy * page1. This routine checks ioc_status to decide whether the 566564a8d931SSreekanth Reddy * page read is success or not. 566664a8d931SSreekanth Reddy * 566764a8d931SSreekanth Reddy * Return: 0 on success, non-zero on failure. 566864a8d931SSreekanth Reddy */ 566964a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc, 567064a8d931SSreekanth Reddy struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz) 567164a8d931SSreekanth Reddy { 567264a8d931SSreekanth Reddy struct mpi3_config_page_header cfg_hdr; 567364a8d931SSreekanth Reddy struct mpi3_config_request cfg_req; 567464a8d931SSreekanth Reddy u16 ioc_status = 0; 567564a8d931SSreekanth Reddy 567664a8d931SSreekanth Reddy memset(sas_io_unit_pg1, 0, pg_sz); 567764a8d931SSreekanth Reddy memset(&cfg_hdr, 0, sizeof(cfg_hdr)); 567864a8d931SSreekanth Reddy memset(&cfg_req, 0, sizeof(cfg_req)); 567964a8d931SSreekanth Reddy 568064a8d931SSreekanth Reddy cfg_req.function = MPI3_FUNCTION_CONFIG; 568164a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER; 568264a8d931SSreekanth Reddy cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT; 568364a8d931SSreekanth Reddy cfg_req.page_number = 1; 568464a8d931SSreekanth Reddy cfg_req.page_address = 0; 568564a8d931SSreekanth Reddy 568664a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL, 568764a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) { 568864a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page1 header read failed\n"); 568964a8d931SSreekanth Reddy goto out_failed; 569064a8d931SSreekanth Reddy } 569164a8d931SSreekanth Reddy if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { 569264a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page1 header read failed with ioc_status(0x%04x)\n", 569364a8d931SSreekanth Reddy ioc_status); 569464a8d931SSreekanth Reddy goto out_failed; 569564a8d931SSreekanth Reddy } 569664a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT; 569764a8d931SSreekanth Reddy 569864a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr, 569964a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) { 570064a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page1 read failed\n"); 570164a8d931SSreekanth Reddy goto out_failed; 570264a8d931SSreekanth Reddy } 570364a8d931SSreekanth Reddy if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { 570464a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page1 read failed with ioc_status(0x%04x)\n", 570564a8d931SSreekanth Reddy ioc_status); 570664a8d931SSreekanth Reddy goto out_failed; 570764a8d931SSreekanth Reddy } 570864a8d931SSreekanth Reddy return 0; 570964a8d931SSreekanth Reddy out_failed: 571064a8d931SSreekanth Reddy return -1; 571164a8d931SSreekanth Reddy } 571264a8d931SSreekanth Reddy 571364a8d931SSreekanth Reddy /** 571464a8d931SSreekanth Reddy * mpi3mr_cfg_set_sas_io_unit_pg1 - Write SASIOUnit page1 571564a8d931SSreekanth Reddy * @mrioc: Adapter instance reference 571664a8d931SSreekanth Reddy * @sas_io_unit_pg1: Pointer to the SAS IO Unit page 1 to write 571764a8d931SSreekanth Reddy * @pg_sz: Size of the memory allocated to the page pointer 571864a8d931SSreekanth Reddy * 571964a8d931SSreekanth Reddy * This is handler for config page write for the SAS IO Unit 572064a8d931SSreekanth Reddy * page1. This routine checks ioc_status to decide whether the 572164a8d931SSreekanth Reddy * page read is success or not. This will modify both current 572264a8d931SSreekanth Reddy * and persistent page. 572364a8d931SSreekanth Reddy * 572464a8d931SSreekanth Reddy * Return: 0 on success, non-zero on failure. 572564a8d931SSreekanth Reddy */ 572664a8d931SSreekanth Reddy int mpi3mr_cfg_set_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc, 572764a8d931SSreekanth Reddy struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz) 572864a8d931SSreekanth Reddy { 572964a8d931SSreekanth Reddy struct mpi3_config_page_header cfg_hdr; 573064a8d931SSreekanth Reddy struct mpi3_config_request cfg_req; 573164a8d931SSreekanth Reddy u16 ioc_status = 0; 573264a8d931SSreekanth Reddy 573364a8d931SSreekanth Reddy memset(&cfg_hdr, 0, sizeof(cfg_hdr)); 573464a8d931SSreekanth Reddy memset(&cfg_req, 0, sizeof(cfg_req)); 573564a8d931SSreekanth Reddy 573664a8d931SSreekanth Reddy cfg_req.function = MPI3_FUNCTION_CONFIG; 573764a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER; 573864a8d931SSreekanth Reddy cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT; 573964a8d931SSreekanth Reddy cfg_req.page_number = 1; 574064a8d931SSreekanth Reddy cfg_req.page_address = 0; 574164a8d931SSreekanth Reddy 574264a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL, 574364a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) { 574464a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page1 header read failed\n"); 574564a8d931SSreekanth Reddy goto out_failed; 574664a8d931SSreekanth Reddy } 574764a8d931SSreekanth Reddy if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { 574864a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page1 header read failed with ioc_status(0x%04x)\n", 574964a8d931SSreekanth Reddy ioc_status); 575064a8d931SSreekanth Reddy goto out_failed; 575164a8d931SSreekanth Reddy } 575264a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_WRITE_CURRENT; 575364a8d931SSreekanth Reddy 575464a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr, 575564a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) { 575664a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page1 write current failed\n"); 575764a8d931SSreekanth Reddy goto out_failed; 575864a8d931SSreekanth Reddy } 575964a8d931SSreekanth Reddy if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { 576064a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page1 write current failed with ioc_status(0x%04x)\n", 576164a8d931SSreekanth Reddy ioc_status); 576264a8d931SSreekanth Reddy goto out_failed; 576364a8d931SSreekanth Reddy } 576464a8d931SSreekanth Reddy 576564a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_WRITE_PERSISTENT; 576664a8d931SSreekanth Reddy 576764a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr, 576864a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) { 576964a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page1 write persistent failed\n"); 577064a8d931SSreekanth Reddy goto out_failed; 577164a8d931SSreekanth Reddy } 577264a8d931SSreekanth Reddy if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { 577364a8d931SSreekanth Reddy ioc_err(mrioc, "sas io unit page1 write persistent failed with ioc_status(0x%04x)\n", 577464a8d931SSreekanth Reddy ioc_status); 577564a8d931SSreekanth Reddy goto out_failed; 577664a8d931SSreekanth Reddy } 577764a8d931SSreekanth Reddy return 0; 577864a8d931SSreekanth Reddy out_failed: 577964a8d931SSreekanth Reddy return -1; 578064a8d931SSreekanth Reddy } 578164a8d931SSreekanth Reddy 578264a8d931SSreekanth Reddy /** 578364a8d931SSreekanth Reddy * mpi3mr_cfg_get_driver_pg1 - Read current Driver page1 578464a8d931SSreekanth Reddy * @mrioc: Adapter instance reference 578564a8d931SSreekanth Reddy * @driver_pg1: Pointer to return Driver page 1 578664a8d931SSreekanth Reddy * @pg_sz: Size of the memory allocated to the page pointer 578764a8d931SSreekanth Reddy * 578864a8d931SSreekanth Reddy * This is handler for config page read for the Driver page1. 578964a8d931SSreekanth Reddy * This routine checks ioc_status to decide whether the page 579064a8d931SSreekanth Reddy * read is success or not. 579164a8d931SSreekanth Reddy * 579264a8d931SSreekanth Reddy * Return: 0 on success, non-zero on failure. 579364a8d931SSreekanth Reddy */ 579464a8d931SSreekanth Reddy int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc, 579564a8d931SSreekanth Reddy struct mpi3_driver_page1 *driver_pg1, u16 pg_sz) 579664a8d931SSreekanth Reddy { 579764a8d931SSreekanth Reddy struct mpi3_config_page_header cfg_hdr; 579864a8d931SSreekanth Reddy struct mpi3_config_request cfg_req; 579964a8d931SSreekanth Reddy u16 ioc_status = 0; 580064a8d931SSreekanth Reddy 580164a8d931SSreekanth Reddy memset(driver_pg1, 0, pg_sz); 580264a8d931SSreekanth Reddy memset(&cfg_hdr, 0, sizeof(cfg_hdr)); 580364a8d931SSreekanth Reddy memset(&cfg_req, 0, sizeof(cfg_req)); 580464a8d931SSreekanth Reddy 580564a8d931SSreekanth Reddy cfg_req.function = MPI3_FUNCTION_CONFIG; 580664a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER; 580764a8d931SSreekanth Reddy cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DRIVER; 580864a8d931SSreekanth Reddy cfg_req.page_number = 1; 580964a8d931SSreekanth Reddy cfg_req.page_address = 0; 581064a8d931SSreekanth Reddy 581164a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL, 581264a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) { 581364a8d931SSreekanth Reddy ioc_err(mrioc, "driver page1 header read failed\n"); 581464a8d931SSreekanth Reddy goto out_failed; 581564a8d931SSreekanth Reddy } 581664a8d931SSreekanth Reddy if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { 581764a8d931SSreekanth Reddy ioc_err(mrioc, "driver page1 header read failed with ioc_status(0x%04x)\n", 581864a8d931SSreekanth Reddy ioc_status); 581964a8d931SSreekanth Reddy goto out_failed; 582064a8d931SSreekanth Reddy } 582164a8d931SSreekanth Reddy cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT; 582264a8d931SSreekanth Reddy 582364a8d931SSreekanth Reddy if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr, 582464a8d931SSreekanth Reddy MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, driver_pg1, pg_sz)) { 582564a8d931SSreekanth Reddy ioc_err(mrioc, "driver page1 read failed\n"); 582664a8d931SSreekanth Reddy goto out_failed; 582764a8d931SSreekanth Reddy } 582864a8d931SSreekanth Reddy if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { 582964a8d931SSreekanth Reddy ioc_err(mrioc, "driver page1 read failed with ioc_status(0x%04x)\n", 583064a8d931SSreekanth Reddy ioc_status); 583164a8d931SSreekanth Reddy goto out_failed; 583264a8d931SSreekanth Reddy } 583364a8d931SSreekanth Reddy return 0; 583464a8d931SSreekanth Reddy out_failed: 583564a8d931SSreekanth Reddy return -1; 583664a8d931SSreekanth Reddy } 5837