1824a1566SKashyap Desai // SPDX-License-Identifier: GPL-2.0-or-later 2824a1566SKashyap Desai /* 3824a1566SKashyap Desai * Driver for Broadcom MPI3 Storage Controllers 4824a1566SKashyap Desai * 5824a1566SKashyap Desai * Copyright (C) 2017-2021 Broadcom Inc. 6824a1566SKashyap Desai * (mailto: mpi3mr-linuxdrv.pdl@broadcom.com) 7824a1566SKashyap Desai * 8824a1566SKashyap Desai */ 9824a1566SKashyap Desai 10824a1566SKashyap Desai #include "mpi3mr.h" 11824a1566SKashyap Desai #include <linux/io-64-nonatomic-lo-hi.h> 12824a1566SKashyap Desai 13824a1566SKashyap Desai #if defined(writeq) && defined(CONFIG_64BIT) 14824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) 15824a1566SKashyap Desai { 16824a1566SKashyap Desai writeq(b, addr); 17824a1566SKashyap Desai } 18824a1566SKashyap Desai #else 19824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) 20824a1566SKashyap Desai { 21824a1566SKashyap Desai __u64 data_out = b; 22824a1566SKashyap Desai 23824a1566SKashyap Desai writel((u32)(data_out), addr); 24824a1566SKashyap Desai writel((u32)(data_out >> 32), (addr + 4)); 25824a1566SKashyap Desai } 26824a1566SKashyap Desai #endif 27824a1566SKashyap Desai 28023ab2a9SKashyap Desai static inline bool 29023ab2a9SKashyap Desai mpi3mr_check_req_qfull(struct op_req_qinfo *op_req_q) 30023ab2a9SKashyap Desai { 31023ab2a9SKashyap Desai u16 pi, ci, max_entries; 32023ab2a9SKashyap Desai bool is_qfull = false; 33023ab2a9SKashyap Desai 34023ab2a9SKashyap Desai pi = op_req_q->pi; 35023ab2a9SKashyap Desai ci = READ_ONCE(op_req_q->ci); 36023ab2a9SKashyap Desai max_entries = op_req_q->num_requests; 37023ab2a9SKashyap Desai 38023ab2a9SKashyap Desai if ((ci == (pi + 1)) || ((!ci) && (pi == (max_entries - 1)))) 39023ab2a9SKashyap Desai is_qfull = true; 40023ab2a9SKashyap Desai 41023ab2a9SKashyap Desai return is_qfull; 42023ab2a9SKashyap Desai } 43023ab2a9SKashyap Desai 44824a1566SKashyap Desai static void mpi3mr_sync_irqs(struct mpi3mr_ioc *mrioc) 45824a1566SKashyap Desai { 46824a1566SKashyap Desai u16 i, max_vectors; 47824a1566SKashyap Desai 48824a1566SKashyap Desai max_vectors = mrioc->intr_info_count; 49824a1566SKashyap Desai 50824a1566SKashyap Desai for (i = 0; i < max_vectors; i++) 51824a1566SKashyap Desai synchronize_irq(pci_irq_vector(mrioc->pdev, i)); 52824a1566SKashyap Desai } 53824a1566SKashyap Desai 54824a1566SKashyap Desai void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc) 55824a1566SKashyap Desai { 56824a1566SKashyap Desai mrioc->intr_enabled = 0; 57824a1566SKashyap Desai mpi3mr_sync_irqs(mrioc); 58824a1566SKashyap Desai } 59824a1566SKashyap Desai 60824a1566SKashyap Desai void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc) 61824a1566SKashyap Desai { 62824a1566SKashyap Desai mrioc->intr_enabled = 1; 63824a1566SKashyap Desai } 64824a1566SKashyap Desai 65824a1566SKashyap Desai static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc) 66824a1566SKashyap Desai { 67824a1566SKashyap Desai u16 i; 68824a1566SKashyap Desai 69824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 70824a1566SKashyap Desai 71824a1566SKashyap Desai if (!mrioc->intr_info) 72824a1566SKashyap Desai return; 73824a1566SKashyap Desai 74824a1566SKashyap Desai for (i = 0; i < mrioc->intr_info_count; i++) 75824a1566SKashyap Desai free_irq(pci_irq_vector(mrioc->pdev, i), 76824a1566SKashyap Desai (mrioc->intr_info + i)); 77824a1566SKashyap Desai 78824a1566SKashyap Desai kfree(mrioc->intr_info); 79824a1566SKashyap Desai mrioc->intr_info = NULL; 80824a1566SKashyap Desai mrioc->intr_info_count = 0; 81824a1566SKashyap Desai pci_free_irq_vectors(mrioc->pdev); 82824a1566SKashyap Desai } 83824a1566SKashyap Desai 84824a1566SKashyap Desai void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length, 85824a1566SKashyap Desai dma_addr_t dma_addr) 86824a1566SKashyap Desai { 87824a1566SKashyap Desai struct mpi3_sge_common *sgel = paddr; 88824a1566SKashyap Desai 89824a1566SKashyap Desai sgel->flags = flags; 90824a1566SKashyap Desai sgel->length = cpu_to_le32(length); 91824a1566SKashyap Desai sgel->address = cpu_to_le64(dma_addr); 92824a1566SKashyap Desai } 93824a1566SKashyap Desai 94824a1566SKashyap Desai void mpi3mr_build_zero_len_sge(void *paddr) 95824a1566SKashyap Desai { 96824a1566SKashyap Desai u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 97824a1566SKashyap Desai 98824a1566SKashyap Desai mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1); 99824a1566SKashyap Desai } 100824a1566SKashyap Desai 101824a1566SKashyap Desai void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc, 102824a1566SKashyap Desai dma_addr_t phys_addr) 103824a1566SKashyap Desai { 104824a1566SKashyap Desai if (!phys_addr) 105824a1566SKashyap Desai return NULL; 106824a1566SKashyap Desai 107824a1566SKashyap Desai if ((phys_addr < mrioc->reply_buf_dma) || 108824a1566SKashyap Desai (phys_addr > mrioc->reply_buf_dma_max_address)) 109824a1566SKashyap Desai return NULL; 110824a1566SKashyap Desai 111824a1566SKashyap Desai return mrioc->reply_buf + (phys_addr - mrioc->reply_buf_dma); 112824a1566SKashyap Desai } 113824a1566SKashyap Desai 114824a1566SKashyap Desai void *mpi3mr_get_sensebuf_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 return mrioc->sense_buf + (phys_addr - mrioc->sense_buf_dma); 121824a1566SKashyap Desai } 122824a1566SKashyap Desai 123824a1566SKashyap Desai static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc, 124824a1566SKashyap Desai u64 reply_dma) 125824a1566SKashyap Desai { 126824a1566SKashyap Desai u32 old_idx = 0; 127824a1566SKashyap Desai 128824a1566SKashyap Desai spin_lock(&mrioc->reply_free_queue_lock); 129824a1566SKashyap Desai old_idx = mrioc->reply_free_queue_host_index; 130824a1566SKashyap Desai mrioc->reply_free_queue_host_index = ( 131824a1566SKashyap Desai (mrioc->reply_free_queue_host_index == 132824a1566SKashyap Desai (mrioc->reply_free_qsz - 1)) ? 0 : 133824a1566SKashyap Desai (mrioc->reply_free_queue_host_index + 1)); 134824a1566SKashyap Desai mrioc->reply_free_q[old_idx] = cpu_to_le64(reply_dma); 135824a1566SKashyap Desai writel(mrioc->reply_free_queue_host_index, 136824a1566SKashyap Desai &mrioc->sysif_regs->reply_free_host_index); 137824a1566SKashyap Desai spin_unlock(&mrioc->reply_free_queue_lock); 138824a1566SKashyap Desai } 139824a1566SKashyap Desai 140824a1566SKashyap Desai void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc, 141824a1566SKashyap Desai u64 sense_buf_dma) 142824a1566SKashyap Desai { 143824a1566SKashyap Desai u32 old_idx = 0; 144824a1566SKashyap Desai 145824a1566SKashyap Desai spin_lock(&mrioc->sbq_lock); 146824a1566SKashyap Desai old_idx = mrioc->sbq_host_index; 147824a1566SKashyap Desai mrioc->sbq_host_index = ((mrioc->sbq_host_index == 148824a1566SKashyap Desai (mrioc->sense_buf_q_sz - 1)) ? 0 : 149824a1566SKashyap Desai (mrioc->sbq_host_index + 1)); 150824a1566SKashyap Desai mrioc->sense_buf_q[old_idx] = cpu_to_le64(sense_buf_dma); 151824a1566SKashyap Desai writel(mrioc->sbq_host_index, 152824a1566SKashyap Desai &mrioc->sysif_regs->sense_buffer_free_host_index); 153824a1566SKashyap Desai spin_unlock(&mrioc->sbq_lock); 154824a1566SKashyap Desai } 155824a1566SKashyap Desai 156824a1566SKashyap Desai static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc, 157824a1566SKashyap Desai struct mpi3_default_reply *def_reply) 158824a1566SKashyap Desai { 159824a1566SKashyap Desai struct mpi3_event_notification_reply *event_reply = 160824a1566SKashyap Desai (struct mpi3_event_notification_reply *)def_reply; 161824a1566SKashyap Desai 162824a1566SKashyap Desai mrioc->change_count = le16_to_cpu(event_reply->ioc_change_count); 16313ef29eaSKashyap Desai mpi3mr_os_handle_events(mrioc, event_reply); 164824a1566SKashyap Desai } 165824a1566SKashyap Desai 166824a1566SKashyap Desai static struct mpi3mr_drv_cmd * 167824a1566SKashyap Desai mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag, 168824a1566SKashyap Desai struct mpi3_default_reply *def_reply) 169824a1566SKashyap Desai { 17013ef29eaSKashyap Desai u16 idx; 17113ef29eaSKashyap Desai 172824a1566SKashyap Desai switch (host_tag) { 173824a1566SKashyap Desai case MPI3MR_HOSTTAG_INITCMDS: 174824a1566SKashyap Desai return &mrioc->init_cmds; 175*e844adb1SKashyap Desai case MPI3MR_HOSTTAG_BLK_TMS: 176*e844adb1SKashyap Desai return &mrioc->host_tm_cmds; 177824a1566SKashyap Desai case MPI3MR_HOSTTAG_INVALID: 178824a1566SKashyap Desai if (def_reply && def_reply->function == 179824a1566SKashyap Desai MPI3_FUNCTION_EVENT_NOTIFICATION) 180824a1566SKashyap Desai mpi3mr_handle_events(mrioc, def_reply); 181824a1566SKashyap Desai return NULL; 182824a1566SKashyap Desai default: 183824a1566SKashyap Desai break; 184824a1566SKashyap Desai } 18513ef29eaSKashyap Desai if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN && 18613ef29eaSKashyap Desai host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX) { 18713ef29eaSKashyap Desai idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN; 18813ef29eaSKashyap Desai return &mrioc->dev_rmhs_cmds[idx]; 18913ef29eaSKashyap Desai } 190824a1566SKashyap Desai 191824a1566SKashyap Desai return NULL; 192824a1566SKashyap Desai } 193824a1566SKashyap Desai 194824a1566SKashyap Desai static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, 195824a1566SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma) 196824a1566SKashyap Desai { 197824a1566SKashyap Desai u16 reply_desc_type, host_tag = 0; 198824a1566SKashyap Desai u16 ioc_status = MPI3_IOCSTATUS_SUCCESS; 199824a1566SKashyap Desai u32 ioc_loginfo = 0; 200824a1566SKashyap Desai struct mpi3_status_reply_descriptor *status_desc; 201824a1566SKashyap Desai struct mpi3_address_reply_descriptor *addr_desc; 202824a1566SKashyap Desai struct mpi3_success_reply_descriptor *success_desc; 203824a1566SKashyap Desai struct mpi3_default_reply *def_reply = NULL; 204824a1566SKashyap Desai struct mpi3mr_drv_cmd *cmdptr = NULL; 205824a1566SKashyap Desai struct mpi3_scsi_io_reply *scsi_reply; 206824a1566SKashyap Desai u8 *sense_buf = NULL; 207824a1566SKashyap Desai 208824a1566SKashyap Desai *reply_dma = 0; 209824a1566SKashyap Desai reply_desc_type = le16_to_cpu(reply_desc->reply_flags) & 210824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK; 211824a1566SKashyap Desai switch (reply_desc_type) { 212824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS: 213824a1566SKashyap Desai status_desc = (struct mpi3_status_reply_descriptor *)reply_desc; 214824a1566SKashyap Desai host_tag = le16_to_cpu(status_desc->host_tag); 215824a1566SKashyap Desai ioc_status = le16_to_cpu(status_desc->ioc_status); 216824a1566SKashyap Desai if (ioc_status & 217824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) 218824a1566SKashyap Desai ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info); 219824a1566SKashyap Desai ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; 220824a1566SKashyap Desai break; 221824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY: 222824a1566SKashyap Desai addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc; 223824a1566SKashyap Desai *reply_dma = le64_to_cpu(addr_desc->reply_frame_address); 224824a1566SKashyap Desai def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma); 225824a1566SKashyap Desai if (!def_reply) 226824a1566SKashyap Desai goto out; 227824a1566SKashyap Desai host_tag = le16_to_cpu(def_reply->host_tag); 228824a1566SKashyap Desai ioc_status = le16_to_cpu(def_reply->ioc_status); 229824a1566SKashyap Desai if (ioc_status & 230824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) 231824a1566SKashyap Desai ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info); 232824a1566SKashyap Desai ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; 233824a1566SKashyap Desai if (def_reply->function == MPI3_FUNCTION_SCSI_IO) { 234824a1566SKashyap Desai scsi_reply = (struct mpi3_scsi_io_reply *)def_reply; 235824a1566SKashyap Desai sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc, 236824a1566SKashyap Desai le64_to_cpu(scsi_reply->sense_data_buffer_address)); 237824a1566SKashyap Desai } 238824a1566SKashyap Desai break; 239824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS: 240824a1566SKashyap Desai success_desc = (struct mpi3_success_reply_descriptor *)reply_desc; 241824a1566SKashyap Desai host_tag = le16_to_cpu(success_desc->host_tag); 242824a1566SKashyap Desai break; 243824a1566SKashyap Desai default: 244824a1566SKashyap Desai break; 245824a1566SKashyap Desai } 246824a1566SKashyap Desai 247824a1566SKashyap Desai cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply); 248824a1566SKashyap Desai if (cmdptr) { 249824a1566SKashyap Desai if (cmdptr->state & MPI3MR_CMD_PENDING) { 250824a1566SKashyap Desai cmdptr->state |= MPI3MR_CMD_COMPLETE; 251824a1566SKashyap Desai cmdptr->ioc_loginfo = ioc_loginfo; 252824a1566SKashyap Desai cmdptr->ioc_status = ioc_status; 253824a1566SKashyap Desai cmdptr->state &= ~MPI3MR_CMD_PENDING; 254824a1566SKashyap Desai if (def_reply) { 255824a1566SKashyap Desai cmdptr->state |= MPI3MR_CMD_REPLY_VALID; 256824a1566SKashyap Desai memcpy((u8 *)cmdptr->reply, (u8 *)def_reply, 257824a1566SKashyap Desai mrioc->facts.reply_sz); 258824a1566SKashyap Desai } 259824a1566SKashyap Desai if (cmdptr->is_waiting) { 260824a1566SKashyap Desai complete(&cmdptr->done); 261824a1566SKashyap Desai cmdptr->is_waiting = 0; 262824a1566SKashyap Desai } else if (cmdptr->callback) 263824a1566SKashyap Desai cmdptr->callback(mrioc, cmdptr); 264824a1566SKashyap Desai } 265824a1566SKashyap Desai } 266824a1566SKashyap Desai out: 267824a1566SKashyap Desai if (sense_buf) 268824a1566SKashyap Desai mpi3mr_repost_sense_buf(mrioc, 269824a1566SKashyap Desai le64_to_cpu(scsi_reply->sense_data_buffer_address)); 270824a1566SKashyap Desai } 271824a1566SKashyap Desai 272824a1566SKashyap Desai static int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) 273824a1566SKashyap Desai { 274824a1566SKashyap Desai u32 exp_phase = mrioc->admin_reply_ephase; 275824a1566SKashyap Desai u32 admin_reply_ci = mrioc->admin_reply_ci; 276824a1566SKashyap Desai u32 num_admin_replies = 0; 277824a1566SKashyap Desai u64 reply_dma = 0; 278824a1566SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc; 279824a1566SKashyap Desai 280824a1566SKashyap Desai reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base + 281824a1566SKashyap Desai admin_reply_ci; 282824a1566SKashyap Desai 283824a1566SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 284824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 285824a1566SKashyap Desai return 0; 286824a1566SKashyap Desai 287824a1566SKashyap Desai do { 288824a1566SKashyap Desai mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci); 289824a1566SKashyap Desai mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma); 290824a1566SKashyap Desai if (reply_dma) 291824a1566SKashyap Desai mpi3mr_repost_reply_buf(mrioc, reply_dma); 292824a1566SKashyap Desai num_admin_replies++; 293824a1566SKashyap Desai if (++admin_reply_ci == mrioc->num_admin_replies) { 294824a1566SKashyap Desai admin_reply_ci = 0; 295824a1566SKashyap Desai exp_phase ^= 1; 296824a1566SKashyap Desai } 297824a1566SKashyap Desai reply_desc = 298824a1566SKashyap Desai (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base + 299824a1566SKashyap Desai admin_reply_ci; 300824a1566SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 301824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 302824a1566SKashyap Desai break; 303824a1566SKashyap Desai } while (1); 304824a1566SKashyap Desai 305824a1566SKashyap Desai writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); 306824a1566SKashyap Desai mrioc->admin_reply_ci = admin_reply_ci; 307824a1566SKashyap Desai mrioc->admin_reply_ephase = exp_phase; 308824a1566SKashyap Desai 309824a1566SKashyap Desai return num_admin_replies; 310824a1566SKashyap Desai } 311824a1566SKashyap Desai 312023ab2a9SKashyap Desai /** 313023ab2a9SKashyap Desai * mpi3mr_get_reply_desc - get reply descriptor frame corresponding to 314023ab2a9SKashyap Desai * queue's consumer index from operational reply descriptor queue. 315023ab2a9SKashyap Desai * @op_reply_q: op_reply_qinfo object 316023ab2a9SKashyap Desai * @reply_ci: operational reply descriptor's queue consumer index 317023ab2a9SKashyap Desai * 318023ab2a9SKashyap Desai * Returns reply descriptor frame address 319023ab2a9SKashyap Desai */ 320023ab2a9SKashyap Desai static inline struct mpi3_default_reply_descriptor * 321023ab2a9SKashyap Desai mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci) 322023ab2a9SKashyap Desai { 323023ab2a9SKashyap Desai void *segment_base_addr; 324023ab2a9SKashyap Desai struct segments *segments = op_reply_q->q_segments; 325023ab2a9SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc = NULL; 326023ab2a9SKashyap Desai 327023ab2a9SKashyap Desai segment_base_addr = 328023ab2a9SKashyap Desai segments[reply_ci / op_reply_q->segment_qd].segment; 329023ab2a9SKashyap Desai reply_desc = (struct mpi3_default_reply_descriptor *)segment_base_addr + 330023ab2a9SKashyap Desai (reply_ci % op_reply_q->segment_qd); 331023ab2a9SKashyap Desai return reply_desc; 332023ab2a9SKashyap Desai } 333023ab2a9SKashyap Desai 334023ab2a9SKashyap Desai static int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, 335023ab2a9SKashyap Desai struct mpi3mr_intr_info *intr_info) 336023ab2a9SKashyap Desai { 337023ab2a9SKashyap Desai struct op_reply_qinfo *op_reply_q = intr_info->op_reply_q; 338023ab2a9SKashyap Desai struct op_req_qinfo *op_req_q; 339023ab2a9SKashyap Desai u32 exp_phase; 340023ab2a9SKashyap Desai u32 reply_ci; 341023ab2a9SKashyap Desai u32 num_op_reply = 0; 342023ab2a9SKashyap Desai u64 reply_dma = 0; 343023ab2a9SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc; 344023ab2a9SKashyap Desai u16 req_q_idx = 0, reply_qidx; 345023ab2a9SKashyap Desai 346023ab2a9SKashyap Desai reply_qidx = op_reply_q->qid - 1; 347023ab2a9SKashyap Desai 348023ab2a9SKashyap Desai exp_phase = op_reply_q->ephase; 349023ab2a9SKashyap Desai reply_ci = op_reply_q->ci; 350023ab2a9SKashyap Desai 351023ab2a9SKashyap Desai reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci); 352023ab2a9SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 353023ab2a9SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) { 354023ab2a9SKashyap Desai return 0; 355023ab2a9SKashyap Desai } 356023ab2a9SKashyap Desai 357023ab2a9SKashyap Desai do { 358023ab2a9SKashyap Desai req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1; 359023ab2a9SKashyap Desai op_req_q = &mrioc->req_qinfo[req_q_idx]; 360023ab2a9SKashyap Desai 361023ab2a9SKashyap Desai WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci)); 362023ab2a9SKashyap Desai mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma, 363023ab2a9SKashyap Desai reply_qidx); 364023ab2a9SKashyap Desai if (reply_dma) 365023ab2a9SKashyap Desai mpi3mr_repost_reply_buf(mrioc, reply_dma); 366023ab2a9SKashyap Desai num_op_reply++; 367023ab2a9SKashyap Desai 368023ab2a9SKashyap Desai if (++reply_ci == op_reply_q->num_replies) { 369023ab2a9SKashyap Desai reply_ci = 0; 370023ab2a9SKashyap Desai exp_phase ^= 1; 371023ab2a9SKashyap Desai } 372023ab2a9SKashyap Desai 373023ab2a9SKashyap Desai reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci); 374023ab2a9SKashyap Desai 375023ab2a9SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 376023ab2a9SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 377023ab2a9SKashyap Desai break; 378023ab2a9SKashyap Desai 379023ab2a9SKashyap Desai } while (1); 380023ab2a9SKashyap Desai 381023ab2a9SKashyap Desai writel(reply_ci, 382023ab2a9SKashyap Desai &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index); 383023ab2a9SKashyap Desai op_reply_q->ci = reply_ci; 384023ab2a9SKashyap Desai op_reply_q->ephase = exp_phase; 385023ab2a9SKashyap Desai 386023ab2a9SKashyap Desai return num_op_reply; 387023ab2a9SKashyap Desai } 388023ab2a9SKashyap Desai 389824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata) 390824a1566SKashyap Desai { 391824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = privdata; 392824a1566SKashyap Desai struct mpi3mr_ioc *mrioc; 393824a1566SKashyap Desai u16 midx; 394824a1566SKashyap Desai u32 num_admin_replies = 0; 395824a1566SKashyap Desai 396824a1566SKashyap Desai if (!intr_info) 397824a1566SKashyap Desai return IRQ_NONE; 398824a1566SKashyap Desai 399824a1566SKashyap Desai mrioc = intr_info->mrioc; 400824a1566SKashyap Desai 401824a1566SKashyap Desai if (!mrioc->intr_enabled) 402824a1566SKashyap Desai return IRQ_NONE; 403824a1566SKashyap Desai 404824a1566SKashyap Desai midx = intr_info->msix_index; 405824a1566SKashyap Desai 406824a1566SKashyap Desai if (!midx) 407824a1566SKashyap Desai num_admin_replies = mpi3mr_process_admin_reply_q(mrioc); 408824a1566SKashyap Desai 409824a1566SKashyap Desai if (num_admin_replies) 410824a1566SKashyap Desai return IRQ_HANDLED; 411824a1566SKashyap Desai else 412824a1566SKashyap Desai return IRQ_NONE; 413824a1566SKashyap Desai } 414824a1566SKashyap Desai 415824a1566SKashyap Desai static irqreturn_t mpi3mr_isr(int irq, void *privdata) 416824a1566SKashyap Desai { 417824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = privdata; 418824a1566SKashyap Desai int ret; 419824a1566SKashyap Desai 420824a1566SKashyap Desai if (!intr_info) 421824a1566SKashyap Desai return IRQ_NONE; 422824a1566SKashyap Desai 423824a1566SKashyap Desai /* Call primary ISR routine */ 424824a1566SKashyap Desai ret = mpi3mr_isr_primary(irq, privdata); 425824a1566SKashyap Desai 426824a1566SKashyap Desai return ret; 427824a1566SKashyap Desai } 428824a1566SKashyap Desai 429824a1566SKashyap Desai /** 430824a1566SKashyap Desai * mpi3mr_isr_poll - Reply queue polling routine 431824a1566SKashyap Desai * @irq: IRQ 432824a1566SKashyap Desai * @privdata: Interrupt info 433824a1566SKashyap Desai * 434824a1566SKashyap Desai * poll for pending I/O completions in a loop until pending I/Os 435824a1566SKashyap Desai * present or controller queue depth I/Os are processed. 436824a1566SKashyap Desai * 437824a1566SKashyap Desai * Return: IRQ_NONE or IRQ_HANDLED 438824a1566SKashyap Desai */ 439824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata) 440824a1566SKashyap Desai { 441824a1566SKashyap Desai return IRQ_HANDLED; 442824a1566SKashyap Desai } 443824a1566SKashyap Desai 444824a1566SKashyap Desai /** 445824a1566SKashyap Desai * mpi3mr_request_irq - Request IRQ and register ISR 446824a1566SKashyap Desai * @mrioc: Adapter instance reference 447824a1566SKashyap Desai * @index: IRQ vector index 448824a1566SKashyap Desai * 449824a1566SKashyap Desai * Request threaded ISR with primary ISR and secondary 450824a1566SKashyap Desai * 451824a1566SKashyap Desai * Return: 0 on success and non zero on failures. 452824a1566SKashyap Desai */ 453824a1566SKashyap Desai static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index) 454824a1566SKashyap Desai { 455824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 456824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index; 457824a1566SKashyap Desai int retval = 0; 458824a1566SKashyap Desai 459824a1566SKashyap Desai intr_info->mrioc = mrioc; 460824a1566SKashyap Desai intr_info->msix_index = index; 461824a1566SKashyap Desai intr_info->op_reply_q = NULL; 462824a1566SKashyap Desai 463824a1566SKashyap Desai snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d", 464824a1566SKashyap Desai mrioc->driver_name, mrioc->id, index); 465824a1566SKashyap Desai 466824a1566SKashyap Desai retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr, 467824a1566SKashyap Desai mpi3mr_isr_poll, IRQF_SHARED, intr_info->name, intr_info); 468824a1566SKashyap Desai if (retval) { 469824a1566SKashyap Desai ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n", 470824a1566SKashyap Desai intr_info->name, pci_irq_vector(pdev, index)); 471824a1566SKashyap Desai return retval; 472824a1566SKashyap Desai } 473824a1566SKashyap Desai 474824a1566SKashyap Desai return retval; 475824a1566SKashyap Desai } 476824a1566SKashyap Desai 477824a1566SKashyap Desai /** 478824a1566SKashyap Desai * mpi3mr_setup_isr - Setup ISR for the controller 479824a1566SKashyap Desai * @mrioc: Adapter instance reference 480824a1566SKashyap Desai * @setup_one: Request one IRQ or more 481824a1566SKashyap Desai * 482824a1566SKashyap Desai * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR 483824a1566SKashyap Desai * 484824a1566SKashyap Desai * Return: 0 on success and non zero on failures. 485824a1566SKashyap Desai */ 486824a1566SKashyap Desai static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one) 487824a1566SKashyap Desai { 488824a1566SKashyap Desai unsigned int irq_flags = PCI_IRQ_MSIX; 489824a1566SKashyap Desai u16 max_vectors = 0, i; 490824a1566SKashyap Desai int retval = 0; 491824a1566SKashyap Desai struct irq_affinity desc = { .pre_vectors = 1}; 492824a1566SKashyap Desai 493824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 494824a1566SKashyap Desai 495824a1566SKashyap Desai if (setup_one || reset_devices) 496824a1566SKashyap Desai max_vectors = 1; 497824a1566SKashyap Desai else { 498824a1566SKashyap Desai max_vectors = 499824a1566SKashyap Desai min_t(int, mrioc->cpu_count + 1, mrioc->msix_count); 500824a1566SKashyap Desai 501824a1566SKashyap Desai ioc_info(mrioc, 502824a1566SKashyap Desai "MSI-X vectors supported: %d, no of cores: %d,", 503824a1566SKashyap Desai mrioc->msix_count, mrioc->cpu_count); 504824a1566SKashyap Desai ioc_info(mrioc, 505824a1566SKashyap Desai "MSI-x vectors requested: %d\n", max_vectors); 506824a1566SKashyap Desai } 507824a1566SKashyap Desai 508824a1566SKashyap Desai irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES; 509824a1566SKashyap Desai 510c9566231SKashyap Desai mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0; 511824a1566SKashyap Desai i = pci_alloc_irq_vectors_affinity(mrioc->pdev, 512824a1566SKashyap Desai 1, max_vectors, irq_flags, &desc); 513824a1566SKashyap Desai if (i <= 0) { 514824a1566SKashyap Desai ioc_err(mrioc, "Cannot alloc irq vectors\n"); 515824a1566SKashyap Desai goto out_failed; 516824a1566SKashyap Desai } 517824a1566SKashyap Desai if (i != max_vectors) { 518824a1566SKashyap Desai ioc_info(mrioc, 519824a1566SKashyap Desai "allocated vectors (%d) are less than configured (%d)\n", 520824a1566SKashyap Desai i, max_vectors); 521c9566231SKashyap Desai /* 522c9566231SKashyap Desai * If only one MSI-x is allocated, then MSI-x 0 will be shared 523c9566231SKashyap Desai * between Admin queue and operational queue 524c9566231SKashyap Desai */ 525c9566231SKashyap Desai if (i == 1) 526c9566231SKashyap Desai mrioc->op_reply_q_offset = 0; 527824a1566SKashyap Desai 528824a1566SKashyap Desai max_vectors = i; 529824a1566SKashyap Desai } 530824a1566SKashyap Desai mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info) * max_vectors, 531824a1566SKashyap Desai GFP_KERNEL); 532824a1566SKashyap Desai if (!mrioc->intr_info) { 533824a1566SKashyap Desai retval = -1; 534824a1566SKashyap Desai pci_free_irq_vectors(mrioc->pdev); 535824a1566SKashyap Desai goto out_failed; 536824a1566SKashyap Desai } 537824a1566SKashyap Desai for (i = 0; i < max_vectors; i++) { 538824a1566SKashyap Desai retval = mpi3mr_request_irq(mrioc, i); 539824a1566SKashyap Desai if (retval) { 540824a1566SKashyap Desai mrioc->intr_info_count = i; 541824a1566SKashyap Desai goto out_failed; 542824a1566SKashyap Desai } 543824a1566SKashyap Desai } 544824a1566SKashyap Desai mrioc->intr_info_count = max_vectors; 545824a1566SKashyap Desai mpi3mr_ioc_enable_intr(mrioc); 546824a1566SKashyap Desai return retval; 547824a1566SKashyap Desai out_failed: 548824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 549824a1566SKashyap Desai 550824a1566SKashyap Desai return retval; 551824a1566SKashyap Desai } 552824a1566SKashyap Desai 553824a1566SKashyap Desai static const struct { 554824a1566SKashyap Desai enum mpi3mr_iocstate value; 555824a1566SKashyap Desai char *name; 556824a1566SKashyap Desai } mrioc_states[] = { 557824a1566SKashyap Desai { MRIOC_STATE_READY, "ready" }, 558824a1566SKashyap Desai { MRIOC_STATE_FAULT, "fault" }, 559824a1566SKashyap Desai { MRIOC_STATE_RESET, "reset" }, 560824a1566SKashyap Desai { MRIOC_STATE_BECOMING_READY, "becoming ready" }, 561824a1566SKashyap Desai { MRIOC_STATE_RESET_REQUESTED, "reset requested" }, 562824a1566SKashyap Desai { MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" }, 563824a1566SKashyap Desai }; 564824a1566SKashyap Desai 565824a1566SKashyap Desai static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state) 566824a1566SKashyap Desai { 567824a1566SKashyap Desai int i; 568824a1566SKashyap Desai char *name = NULL; 569824a1566SKashyap Desai 570824a1566SKashyap Desai for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) { 571824a1566SKashyap Desai if (mrioc_states[i].value == mrioc_state) { 572824a1566SKashyap Desai name = mrioc_states[i].name; 573824a1566SKashyap Desai break; 574824a1566SKashyap Desai } 575824a1566SKashyap Desai } 576824a1566SKashyap Desai return name; 577824a1566SKashyap Desai } 578824a1566SKashyap Desai 579824a1566SKashyap Desai /** 580824a1566SKashyap Desai * mpi3mr_print_fault_info - Display fault information 581824a1566SKashyap Desai * @mrioc: Adapter instance reference 582824a1566SKashyap Desai * 583824a1566SKashyap Desai * Display the controller fault information if there is a 584824a1566SKashyap Desai * controller fault. 585824a1566SKashyap Desai * 586824a1566SKashyap Desai * Return: Nothing. 587824a1566SKashyap Desai */ 588824a1566SKashyap Desai static void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc) 589824a1566SKashyap Desai { 590824a1566SKashyap Desai u32 ioc_status, code, code1, code2, code3; 591824a1566SKashyap Desai 592824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 593824a1566SKashyap Desai 594824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { 595824a1566SKashyap Desai code = readl(&mrioc->sysif_regs->fault); 596824a1566SKashyap Desai code1 = readl(&mrioc->sysif_regs->fault_info[0]); 597824a1566SKashyap Desai code2 = readl(&mrioc->sysif_regs->fault_info[1]); 598824a1566SKashyap Desai code3 = readl(&mrioc->sysif_regs->fault_info[2]); 599824a1566SKashyap Desai 600824a1566SKashyap Desai ioc_info(mrioc, 601824a1566SKashyap Desai "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n", 602824a1566SKashyap Desai code, code1, code2, code3); 603824a1566SKashyap Desai } 604824a1566SKashyap Desai } 605824a1566SKashyap Desai 606824a1566SKashyap Desai /** 607824a1566SKashyap Desai * mpi3mr_get_iocstate - Get IOC State 608824a1566SKashyap Desai * @mrioc: Adapter instance reference 609824a1566SKashyap Desai * 610824a1566SKashyap Desai * Return a proper IOC state enum based on the IOC status and 611824a1566SKashyap Desai * IOC configuration and unrcoverable state of the controller. 612824a1566SKashyap Desai * 613824a1566SKashyap Desai * Return: Current IOC state. 614824a1566SKashyap Desai */ 615824a1566SKashyap Desai enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc) 616824a1566SKashyap Desai { 617824a1566SKashyap Desai u32 ioc_status, ioc_config; 618824a1566SKashyap Desai u8 ready, enabled; 619824a1566SKashyap Desai 620824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 621824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 622824a1566SKashyap Desai 623824a1566SKashyap Desai if (mrioc->unrecoverable) 624824a1566SKashyap Desai return MRIOC_STATE_UNRECOVERABLE; 625824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) 626824a1566SKashyap Desai return MRIOC_STATE_FAULT; 627824a1566SKashyap Desai 628824a1566SKashyap Desai ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY); 629824a1566SKashyap Desai enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC); 630824a1566SKashyap Desai 631824a1566SKashyap Desai if (ready && enabled) 632824a1566SKashyap Desai return MRIOC_STATE_READY; 633824a1566SKashyap Desai if ((!ready) && (!enabled)) 634824a1566SKashyap Desai return MRIOC_STATE_RESET; 635824a1566SKashyap Desai if ((!ready) && (enabled)) 636824a1566SKashyap Desai return MRIOC_STATE_BECOMING_READY; 637824a1566SKashyap Desai 638824a1566SKashyap Desai return MRIOC_STATE_RESET_REQUESTED; 639824a1566SKashyap Desai } 640824a1566SKashyap Desai 641824a1566SKashyap Desai /** 642824a1566SKashyap Desai * mpi3mr_clear_reset_history - clear reset history 643824a1566SKashyap Desai * @mrioc: Adapter instance reference 644824a1566SKashyap Desai * 645824a1566SKashyap Desai * Write the reset history bit in IOC status to clear the bit, 646824a1566SKashyap Desai * if it is already set. 647824a1566SKashyap Desai * 648824a1566SKashyap Desai * Return: Nothing. 649824a1566SKashyap Desai */ 650824a1566SKashyap Desai static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc) 651824a1566SKashyap Desai { 652824a1566SKashyap Desai u32 ioc_status; 653824a1566SKashyap Desai 654824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 655824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) 656824a1566SKashyap Desai writel(ioc_status, &mrioc->sysif_regs->ioc_status); 657824a1566SKashyap Desai } 658824a1566SKashyap Desai 659824a1566SKashyap Desai /** 660824a1566SKashyap Desai * mpi3mr_issue_and_process_mur - Message unit Reset handler 661824a1566SKashyap Desai * @mrioc: Adapter instance reference 662824a1566SKashyap Desai * @reset_reason: Reset reason code 663824a1566SKashyap Desai * 664824a1566SKashyap Desai * Issue Message unit Reset to the controller and wait for it to 665824a1566SKashyap Desai * be complete. 666824a1566SKashyap Desai * 667824a1566SKashyap Desai * Return: 0 on success, -1 on failure. 668824a1566SKashyap Desai */ 669824a1566SKashyap Desai static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc, 670824a1566SKashyap Desai u32 reset_reason) 671824a1566SKashyap Desai { 672824a1566SKashyap Desai u32 ioc_config, timeout, ioc_status; 673824a1566SKashyap Desai int retval = -1; 674824a1566SKashyap Desai 675824a1566SKashyap Desai ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n"); 676824a1566SKashyap Desai if (mrioc->unrecoverable) { 677824a1566SKashyap Desai ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n"); 678824a1566SKashyap Desai return retval; 679824a1566SKashyap Desai } 680824a1566SKashyap Desai mpi3mr_clear_reset_history(mrioc); 681824a1566SKashyap Desai writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); 682824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 683824a1566SKashyap Desai ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; 684824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 685824a1566SKashyap Desai 686824a1566SKashyap Desai timeout = mrioc->ready_timeout * 10; 687824a1566SKashyap Desai do { 688824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 689824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) { 690824a1566SKashyap Desai mpi3mr_clear_reset_history(mrioc); 691824a1566SKashyap Desai ioc_config = 692824a1566SKashyap Desai readl(&mrioc->sysif_regs->ioc_configuration); 693824a1566SKashyap Desai if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || 694824a1566SKashyap Desai (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) || 695824a1566SKashyap Desai (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) { 696824a1566SKashyap Desai retval = 0; 697824a1566SKashyap Desai break; 698824a1566SKashyap Desai } 699824a1566SKashyap Desai } 700824a1566SKashyap Desai msleep(100); 701824a1566SKashyap Desai } while (--timeout); 702824a1566SKashyap Desai 703824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 704824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 705824a1566SKashyap Desai 706824a1566SKashyap Desai ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n", 707824a1566SKashyap Desai (!retval) ? "successful" : "failed", ioc_status, ioc_config); 708824a1566SKashyap Desai return retval; 709824a1566SKashyap Desai } 710824a1566SKashyap Desai 711824a1566SKashyap Desai /** 712824a1566SKashyap Desai * mpi3mr_bring_ioc_ready - Bring controller to ready state 713824a1566SKashyap Desai * @mrioc: Adapter instance reference 714824a1566SKashyap Desai * 715824a1566SKashyap Desai * Set Enable IOC bit in IOC configuration register and wait for 716824a1566SKashyap Desai * the controller to become ready. 717824a1566SKashyap Desai * 718824a1566SKashyap Desai * Return: 0 on success, -1 on failure. 719824a1566SKashyap Desai */ 720824a1566SKashyap Desai static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) 721824a1566SKashyap Desai { 722824a1566SKashyap Desai u32 ioc_config, timeout; 723824a1566SKashyap Desai enum mpi3mr_iocstate current_state; 724824a1566SKashyap Desai 725824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 726824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; 727824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 728824a1566SKashyap Desai 729824a1566SKashyap Desai timeout = mrioc->ready_timeout * 10; 730824a1566SKashyap Desai do { 731824a1566SKashyap Desai current_state = mpi3mr_get_iocstate(mrioc); 732824a1566SKashyap Desai if (current_state == MRIOC_STATE_READY) 733824a1566SKashyap Desai return 0; 734824a1566SKashyap Desai msleep(100); 735824a1566SKashyap Desai } while (--timeout); 736824a1566SKashyap Desai 737824a1566SKashyap Desai return -1; 738824a1566SKashyap Desai } 739824a1566SKashyap Desai 740824a1566SKashyap Desai /** 741824a1566SKashyap Desai * mpi3mr_set_diagsave - Set diag save bit for snapdump 742824a1566SKashyap Desai * @mrioc: Adapter reference 743824a1566SKashyap Desai * 744824a1566SKashyap Desai * Set diag save bit in IOC configuration register to enable 745824a1566SKashyap Desai * snapdump. 746824a1566SKashyap Desai * 747824a1566SKashyap Desai * Return: Nothing. 748824a1566SKashyap Desai */ 749824a1566SKashyap Desai static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc) 750824a1566SKashyap Desai { 751824a1566SKashyap Desai u32 ioc_config; 752824a1566SKashyap Desai 753824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 754824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE; 755824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 756824a1566SKashyap Desai } 757824a1566SKashyap Desai 758824a1566SKashyap Desai /** 759824a1566SKashyap Desai * mpi3mr_issue_reset - Issue reset to the controller 760824a1566SKashyap Desai * @mrioc: Adapter reference 761824a1566SKashyap Desai * @reset_type: Reset type 762824a1566SKashyap Desai * @reset_reason: Reset reason code 763824a1566SKashyap Desai * 764824a1566SKashyap Desai * TBD 765824a1566SKashyap Desai * 766824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 767824a1566SKashyap Desai */ 768824a1566SKashyap Desai static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, 769824a1566SKashyap Desai u32 reset_reason) 770824a1566SKashyap Desai { 771824a1566SKashyap Desai return 0; 772824a1566SKashyap Desai } 773824a1566SKashyap Desai 774824a1566SKashyap Desai /** 775824a1566SKashyap Desai * mpi3mr_admin_request_post - Post request to admin queue 776824a1566SKashyap Desai * @mrioc: Adapter reference 777824a1566SKashyap Desai * @admin_req: MPI3 request 778824a1566SKashyap Desai * @admin_req_sz: Request size 779824a1566SKashyap Desai * @ignore_reset: Ignore reset in process 780824a1566SKashyap Desai * 781824a1566SKashyap Desai * Post the MPI3 request into admin request queue and 782824a1566SKashyap Desai * inform the controller, if the queue is full return 783824a1566SKashyap Desai * appropriate error. 784824a1566SKashyap Desai * 785824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 786824a1566SKashyap Desai */ 787824a1566SKashyap Desai int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req, 788824a1566SKashyap Desai u16 admin_req_sz, u8 ignore_reset) 789824a1566SKashyap Desai { 790824a1566SKashyap Desai u16 areq_pi = 0, areq_ci = 0, max_entries = 0; 791824a1566SKashyap Desai int retval = 0; 792824a1566SKashyap Desai unsigned long flags; 793824a1566SKashyap Desai u8 *areq_entry; 794824a1566SKashyap Desai 795824a1566SKashyap Desai if (mrioc->unrecoverable) { 796824a1566SKashyap Desai ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__); 797824a1566SKashyap Desai return -EFAULT; 798824a1566SKashyap Desai } 799824a1566SKashyap Desai 800824a1566SKashyap Desai spin_lock_irqsave(&mrioc->admin_req_lock, flags); 801824a1566SKashyap Desai areq_pi = mrioc->admin_req_pi; 802824a1566SKashyap Desai areq_ci = mrioc->admin_req_ci; 803824a1566SKashyap Desai max_entries = mrioc->num_admin_req; 804824a1566SKashyap Desai if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) && 805824a1566SKashyap Desai (areq_pi == (max_entries - 1)))) { 806824a1566SKashyap Desai ioc_err(mrioc, "AdminReqQ full condition detected\n"); 807824a1566SKashyap Desai retval = -EAGAIN; 808824a1566SKashyap Desai goto out; 809824a1566SKashyap Desai } 810824a1566SKashyap Desai if (!ignore_reset && mrioc->reset_in_progress) { 811824a1566SKashyap Desai ioc_err(mrioc, "AdminReqQ submit reset in progress\n"); 812824a1566SKashyap Desai retval = -EAGAIN; 813824a1566SKashyap Desai goto out; 814824a1566SKashyap Desai } 815824a1566SKashyap Desai areq_entry = (u8 *)mrioc->admin_req_base + 816824a1566SKashyap Desai (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ); 817824a1566SKashyap Desai memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ); 818824a1566SKashyap Desai memcpy(areq_entry, (u8 *)admin_req, admin_req_sz); 819824a1566SKashyap Desai 820824a1566SKashyap Desai if (++areq_pi == max_entries) 821824a1566SKashyap Desai areq_pi = 0; 822824a1566SKashyap Desai mrioc->admin_req_pi = areq_pi; 823824a1566SKashyap Desai 824824a1566SKashyap Desai writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi); 825824a1566SKashyap Desai 826824a1566SKashyap Desai out: 827824a1566SKashyap Desai spin_unlock_irqrestore(&mrioc->admin_req_lock, flags); 828824a1566SKashyap Desai 829824a1566SKashyap Desai return retval; 830824a1566SKashyap Desai } 831824a1566SKashyap Desai 832824a1566SKashyap Desai /** 833c9566231SKashyap Desai * mpi3mr_free_op_req_q_segments - free request memory segments 834c9566231SKashyap Desai * @mrioc: Adapter instance reference 835c9566231SKashyap Desai * @q_idx: operational request queue index 836c9566231SKashyap Desai * 837c9566231SKashyap Desai * Free memory segments allocated for operational request queue 838c9566231SKashyap Desai * 839c9566231SKashyap Desai * Return: Nothing. 840c9566231SKashyap Desai */ 841c9566231SKashyap Desai static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) 842c9566231SKashyap Desai { 843c9566231SKashyap Desai u16 j; 844c9566231SKashyap Desai int size; 845c9566231SKashyap Desai struct segments *segments; 846c9566231SKashyap Desai 847c9566231SKashyap Desai segments = mrioc->req_qinfo[q_idx].q_segments; 848c9566231SKashyap Desai if (!segments) 849c9566231SKashyap Desai return; 850c9566231SKashyap Desai 851c9566231SKashyap Desai if (mrioc->enable_segqueue) { 852c9566231SKashyap Desai size = MPI3MR_OP_REQ_Q_SEG_SIZE; 853c9566231SKashyap Desai if (mrioc->req_qinfo[q_idx].q_segment_list) { 854c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 855c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, 856c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segment_list, 857c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segment_list_dma); 858c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL; 859c9566231SKashyap Desai } 860c9566231SKashyap Desai } else 861c9566231SKashyap Desai size = mrioc->req_qinfo[q_idx].num_requests * 862c9566231SKashyap Desai mrioc->facts.op_req_sz; 863c9566231SKashyap Desai 864c9566231SKashyap Desai for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) { 865c9566231SKashyap Desai if (!segments[j].segment) 866c9566231SKashyap Desai continue; 867c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 868c9566231SKashyap Desai size, segments[j].segment, segments[j].segment_dma); 869c9566231SKashyap Desai segments[j].segment = NULL; 870c9566231SKashyap Desai } 871c9566231SKashyap Desai kfree(mrioc->req_qinfo[q_idx].q_segments); 872c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segments = NULL; 873c9566231SKashyap Desai mrioc->req_qinfo[q_idx].qid = 0; 874c9566231SKashyap Desai } 875c9566231SKashyap Desai 876c9566231SKashyap Desai /** 877c9566231SKashyap Desai * mpi3mr_free_op_reply_q_segments - free reply memory segments 878c9566231SKashyap Desai * @mrioc: Adapter instance reference 879c9566231SKashyap Desai * @q_idx: operational reply queue index 880c9566231SKashyap Desai * 881c9566231SKashyap Desai * Free memory segments allocated for operational reply queue 882c9566231SKashyap Desai * 883c9566231SKashyap Desai * Return: Nothing. 884c9566231SKashyap Desai */ 885c9566231SKashyap Desai static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) 886c9566231SKashyap Desai { 887c9566231SKashyap Desai u16 j; 888c9566231SKashyap Desai int size; 889c9566231SKashyap Desai struct segments *segments; 890c9566231SKashyap Desai 891c9566231SKashyap Desai segments = mrioc->op_reply_qinfo[q_idx].q_segments; 892c9566231SKashyap Desai if (!segments) 893c9566231SKashyap Desai return; 894c9566231SKashyap Desai 895c9566231SKashyap Desai if (mrioc->enable_segqueue) { 896c9566231SKashyap Desai size = MPI3MR_OP_REP_Q_SEG_SIZE; 897c9566231SKashyap Desai if (mrioc->op_reply_qinfo[q_idx].q_segment_list) { 898c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 899c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, 900c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list, 901c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list_dma); 902c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL; 903c9566231SKashyap Desai } 904c9566231SKashyap Desai } else 905c9566231SKashyap Desai size = mrioc->op_reply_qinfo[q_idx].segment_qd * 906c9566231SKashyap Desai mrioc->op_reply_desc_sz; 907c9566231SKashyap Desai 908c9566231SKashyap Desai for (j = 0; j < mrioc->op_reply_qinfo[q_idx].num_segments; j++) { 909c9566231SKashyap Desai if (!segments[j].segment) 910c9566231SKashyap Desai continue; 911c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 912c9566231SKashyap Desai size, segments[j].segment, segments[j].segment_dma); 913c9566231SKashyap Desai segments[j].segment = NULL; 914c9566231SKashyap Desai } 915c9566231SKashyap Desai 916c9566231SKashyap Desai kfree(mrioc->op_reply_qinfo[q_idx].q_segments); 917c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segments = NULL; 918c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].qid = 0; 919c9566231SKashyap Desai } 920c9566231SKashyap Desai 921c9566231SKashyap Desai /** 922c9566231SKashyap Desai * mpi3mr_delete_op_reply_q - delete operational reply queue 923c9566231SKashyap Desai * @mrioc: Adapter instance reference 924c9566231SKashyap Desai * @qidx: operational reply queue index 925c9566231SKashyap Desai * 926c9566231SKashyap Desai * Delete operatinal reply queue by issuing MPI request 927c9566231SKashyap Desai * through admin queue. 928c9566231SKashyap Desai * 929c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 930c9566231SKashyap Desai */ 931c9566231SKashyap Desai static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) 932c9566231SKashyap Desai { 933c9566231SKashyap Desai struct mpi3_delete_reply_queue_request delq_req; 934c9566231SKashyap Desai int retval = 0; 935c9566231SKashyap Desai u16 reply_qid = 0, midx; 936c9566231SKashyap Desai 937c9566231SKashyap Desai reply_qid = mrioc->op_reply_qinfo[qidx].qid; 938c9566231SKashyap Desai 939c9566231SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset); 940c9566231SKashyap Desai 941c9566231SKashyap Desai if (!reply_qid) { 942c9566231SKashyap Desai retval = -1; 943c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: called with invalid ReqQID\n"); 944c9566231SKashyap Desai goto out; 945c9566231SKashyap Desai } 946c9566231SKashyap Desai 947c9566231SKashyap Desai memset(&delq_req, 0, sizeof(delq_req)); 948c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 949c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 950c9566231SKashyap Desai retval = -1; 951c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: Init command is in use\n"); 952c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 953c9566231SKashyap Desai goto out; 954c9566231SKashyap Desai } 955c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 956c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 957c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 958c9566231SKashyap Desai delq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 959c9566231SKashyap Desai delq_req.function = MPI3_FUNCTION_DELETE_REPLY_QUEUE; 960c9566231SKashyap Desai delq_req.queue_id = cpu_to_le16(reply_qid); 961c9566231SKashyap Desai 962c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 963c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &delq_req, sizeof(delq_req), 964c9566231SKashyap Desai 1); 965c9566231SKashyap Desai if (retval) { 966c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: Admin Post failed\n"); 967c9566231SKashyap Desai goto out_unlock; 968c9566231SKashyap Desai } 969c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 970c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 971c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 972c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: command timed out\n"); 973c9566231SKashyap Desai mpi3mr_set_diagsave(mrioc); 974c9566231SKashyap Desai mpi3mr_issue_reset(mrioc, 975c9566231SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 976c9566231SKashyap Desai MPI3MR_RESET_FROM_DELREPQ_TIMEOUT); 977c9566231SKashyap Desai mrioc->unrecoverable = 1; 978c9566231SKashyap Desai 979c9566231SKashyap Desai retval = -1; 980c9566231SKashyap Desai goto out_unlock; 981c9566231SKashyap Desai } 982c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 983c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 984c9566231SKashyap Desai ioc_err(mrioc, 985c9566231SKashyap Desai "Issue DelRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 986c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 987c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 988c9566231SKashyap Desai retval = -1; 989c9566231SKashyap Desai goto out_unlock; 990c9566231SKashyap Desai } 991c9566231SKashyap Desai mrioc->intr_info[midx].op_reply_q = NULL; 992c9566231SKashyap Desai 993c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, qidx); 994c9566231SKashyap Desai out_unlock: 995c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 996c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 997c9566231SKashyap Desai out: 998c9566231SKashyap Desai 999c9566231SKashyap Desai return retval; 1000c9566231SKashyap Desai } 1001c9566231SKashyap Desai 1002c9566231SKashyap Desai /** 1003c9566231SKashyap Desai * mpi3mr_alloc_op_reply_q_segments -Alloc segmented reply pool 1004c9566231SKashyap Desai * @mrioc: Adapter instance reference 1005c9566231SKashyap Desai * @qidx: request queue index 1006c9566231SKashyap Desai * 1007c9566231SKashyap Desai * Allocate segmented memory pools for operational reply 1008c9566231SKashyap Desai * queue. 1009c9566231SKashyap Desai * 1010c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1011c9566231SKashyap Desai */ 1012c9566231SKashyap Desai static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) 1013c9566231SKashyap Desai { 1014c9566231SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 1015c9566231SKashyap Desai int i, size; 1016c9566231SKashyap Desai u64 *q_segment_list_entry = NULL; 1017c9566231SKashyap Desai struct segments *segments; 1018c9566231SKashyap Desai 1019c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1020c9566231SKashyap Desai op_reply_q->segment_qd = 1021c9566231SKashyap Desai MPI3MR_OP_REP_Q_SEG_SIZE / mrioc->op_reply_desc_sz; 1022c9566231SKashyap Desai 1023c9566231SKashyap Desai size = MPI3MR_OP_REP_Q_SEG_SIZE; 1024c9566231SKashyap Desai 1025c9566231SKashyap Desai op_reply_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev, 1026c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, &op_reply_q->q_segment_list_dma, 1027c9566231SKashyap Desai GFP_KERNEL); 1028c9566231SKashyap Desai if (!op_reply_q->q_segment_list) 1029c9566231SKashyap Desai return -ENOMEM; 1030c9566231SKashyap Desai q_segment_list_entry = (u64 *)op_reply_q->q_segment_list; 1031c9566231SKashyap Desai } else { 1032c9566231SKashyap Desai op_reply_q->segment_qd = op_reply_q->num_replies; 1033c9566231SKashyap Desai size = op_reply_q->num_replies * mrioc->op_reply_desc_sz; 1034c9566231SKashyap Desai } 1035c9566231SKashyap Desai 1036c9566231SKashyap Desai op_reply_q->num_segments = DIV_ROUND_UP(op_reply_q->num_replies, 1037c9566231SKashyap Desai op_reply_q->segment_qd); 1038c9566231SKashyap Desai 1039c9566231SKashyap Desai op_reply_q->q_segments = kcalloc(op_reply_q->num_segments, 1040c9566231SKashyap Desai sizeof(struct segments), GFP_KERNEL); 1041c9566231SKashyap Desai if (!op_reply_q->q_segments) 1042c9566231SKashyap Desai return -ENOMEM; 1043c9566231SKashyap Desai 1044c9566231SKashyap Desai segments = op_reply_q->q_segments; 1045c9566231SKashyap Desai for (i = 0; i < op_reply_q->num_segments; i++) { 1046c9566231SKashyap Desai segments[i].segment = 1047c9566231SKashyap Desai dma_alloc_coherent(&mrioc->pdev->dev, 1048c9566231SKashyap Desai size, &segments[i].segment_dma, GFP_KERNEL); 1049c9566231SKashyap Desai if (!segments[i].segment) 1050c9566231SKashyap Desai return -ENOMEM; 1051c9566231SKashyap Desai if (mrioc->enable_segqueue) 1052c9566231SKashyap Desai q_segment_list_entry[i] = 1053c9566231SKashyap Desai (unsigned long)segments[i].segment_dma; 1054c9566231SKashyap Desai } 1055c9566231SKashyap Desai 1056c9566231SKashyap Desai return 0; 1057c9566231SKashyap Desai } 1058c9566231SKashyap Desai 1059c9566231SKashyap Desai /** 1060c9566231SKashyap Desai * mpi3mr_alloc_op_req_q_segments - Alloc segmented req pool. 1061c9566231SKashyap Desai * @mrioc: Adapter instance reference 1062c9566231SKashyap Desai * @qidx: request queue index 1063c9566231SKashyap Desai * 1064c9566231SKashyap Desai * Allocate segmented memory pools for operational request 1065c9566231SKashyap Desai * queue. 1066c9566231SKashyap Desai * 1067c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1068c9566231SKashyap Desai */ 1069c9566231SKashyap Desai static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) 1070c9566231SKashyap Desai { 1071c9566231SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx; 1072c9566231SKashyap Desai int i, size; 1073c9566231SKashyap Desai u64 *q_segment_list_entry = NULL; 1074c9566231SKashyap Desai struct segments *segments; 1075c9566231SKashyap Desai 1076c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1077c9566231SKashyap Desai op_req_q->segment_qd = 1078c9566231SKashyap Desai MPI3MR_OP_REQ_Q_SEG_SIZE / mrioc->facts.op_req_sz; 1079c9566231SKashyap Desai 1080c9566231SKashyap Desai size = MPI3MR_OP_REQ_Q_SEG_SIZE; 1081c9566231SKashyap Desai 1082c9566231SKashyap Desai op_req_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev, 1083c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, &op_req_q->q_segment_list_dma, 1084c9566231SKashyap Desai GFP_KERNEL); 1085c9566231SKashyap Desai if (!op_req_q->q_segment_list) 1086c9566231SKashyap Desai return -ENOMEM; 1087c9566231SKashyap Desai q_segment_list_entry = (u64 *)op_req_q->q_segment_list; 1088c9566231SKashyap Desai 1089c9566231SKashyap Desai } else { 1090c9566231SKashyap Desai op_req_q->segment_qd = op_req_q->num_requests; 1091c9566231SKashyap Desai size = op_req_q->num_requests * mrioc->facts.op_req_sz; 1092c9566231SKashyap Desai } 1093c9566231SKashyap Desai 1094c9566231SKashyap Desai op_req_q->num_segments = DIV_ROUND_UP(op_req_q->num_requests, 1095c9566231SKashyap Desai op_req_q->segment_qd); 1096c9566231SKashyap Desai 1097c9566231SKashyap Desai op_req_q->q_segments = kcalloc(op_req_q->num_segments, 1098c9566231SKashyap Desai sizeof(struct segments), GFP_KERNEL); 1099c9566231SKashyap Desai if (!op_req_q->q_segments) 1100c9566231SKashyap Desai return -ENOMEM; 1101c9566231SKashyap Desai 1102c9566231SKashyap Desai segments = op_req_q->q_segments; 1103c9566231SKashyap Desai for (i = 0; i < op_req_q->num_segments; i++) { 1104c9566231SKashyap Desai segments[i].segment = 1105c9566231SKashyap Desai dma_alloc_coherent(&mrioc->pdev->dev, 1106c9566231SKashyap Desai size, &segments[i].segment_dma, GFP_KERNEL); 1107c9566231SKashyap Desai if (!segments[i].segment) 1108c9566231SKashyap Desai return -ENOMEM; 1109c9566231SKashyap Desai if (mrioc->enable_segqueue) 1110c9566231SKashyap Desai q_segment_list_entry[i] = 1111c9566231SKashyap Desai (unsigned long)segments[i].segment_dma; 1112c9566231SKashyap Desai } 1113c9566231SKashyap Desai 1114c9566231SKashyap Desai return 0; 1115c9566231SKashyap Desai } 1116c9566231SKashyap Desai 1117c9566231SKashyap Desai /** 1118c9566231SKashyap Desai * mpi3mr_create_op_reply_q - create operational reply queue 1119c9566231SKashyap Desai * @mrioc: Adapter instance reference 1120c9566231SKashyap Desai * @qidx: operational reply queue index 1121c9566231SKashyap Desai * 1122c9566231SKashyap Desai * Create operatinal reply queue by issuing MPI request 1123c9566231SKashyap Desai * through admin queue. 1124c9566231SKashyap Desai * 1125c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1126c9566231SKashyap Desai */ 1127c9566231SKashyap Desai static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) 1128c9566231SKashyap Desai { 1129c9566231SKashyap Desai struct mpi3_create_reply_queue_request create_req; 1130c9566231SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 1131c9566231SKashyap Desai int retval = 0; 1132c9566231SKashyap Desai u16 reply_qid = 0, midx; 1133c9566231SKashyap Desai 1134c9566231SKashyap Desai reply_qid = op_reply_q->qid; 1135c9566231SKashyap Desai 1136c9566231SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset); 1137c9566231SKashyap Desai 1138c9566231SKashyap Desai if (reply_qid) { 1139c9566231SKashyap Desai retval = -1; 1140c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: called for duplicate qid %d\n", 1141c9566231SKashyap Desai reply_qid); 1142c9566231SKashyap Desai 1143c9566231SKashyap Desai return retval; 1144c9566231SKashyap Desai } 1145c9566231SKashyap Desai 1146c9566231SKashyap Desai reply_qid = qidx + 1; 1147c9566231SKashyap Desai op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; 1148c9566231SKashyap Desai op_reply_q->ci = 0; 1149c9566231SKashyap Desai op_reply_q->ephase = 1; 1150c9566231SKashyap Desai 1151c9566231SKashyap Desai if (!op_reply_q->q_segments) { 1152c9566231SKashyap Desai retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx); 1153c9566231SKashyap Desai if (retval) { 1154c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, qidx); 1155c9566231SKashyap Desai goto out; 1156c9566231SKashyap Desai } 1157c9566231SKashyap Desai } 1158c9566231SKashyap Desai 1159c9566231SKashyap Desai memset(&create_req, 0, sizeof(create_req)); 1160c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1161c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1162c9566231SKashyap Desai retval = -1; 1163c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: Init command is in use\n"); 1164c9566231SKashyap Desai goto out; 1165c9566231SKashyap Desai } 1166c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1167c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1168c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 1169c9566231SKashyap Desai create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1170c9566231SKashyap Desai create_req.function = MPI3_FUNCTION_CREATE_REPLY_QUEUE; 1171c9566231SKashyap Desai create_req.queue_id = cpu_to_le16(reply_qid); 1172c9566231SKashyap Desai create_req.flags = MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE; 1173c9566231SKashyap Desai create_req.msix_index = cpu_to_le16(mrioc->intr_info[midx].msix_index); 1174c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1175c9566231SKashyap Desai create_req.flags |= 1176c9566231SKashyap Desai MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED; 1177c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1178c9566231SKashyap Desai op_reply_q->q_segment_list_dma); 1179c9566231SKashyap Desai } else 1180c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1181c9566231SKashyap Desai op_reply_q->q_segments[0].segment_dma); 1182c9566231SKashyap Desai 1183c9566231SKashyap Desai create_req.size = cpu_to_le16(op_reply_q->num_replies); 1184c9566231SKashyap Desai 1185c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 1186c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &create_req, 1187c9566231SKashyap Desai sizeof(create_req), 1); 1188c9566231SKashyap Desai if (retval) { 1189c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: Admin Post failed\n"); 1190c9566231SKashyap Desai goto out_unlock; 1191c9566231SKashyap Desai } 1192c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1193c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1194c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1195c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: command timed out\n"); 1196c9566231SKashyap Desai mpi3mr_set_diagsave(mrioc); 1197c9566231SKashyap Desai mpi3mr_issue_reset(mrioc, 1198c9566231SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 1199c9566231SKashyap Desai MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT); 1200c9566231SKashyap Desai mrioc->unrecoverable = 1; 1201c9566231SKashyap Desai retval = -1; 1202c9566231SKashyap Desai goto out_unlock; 1203c9566231SKashyap Desai } 1204c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1205c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1206c9566231SKashyap Desai ioc_err(mrioc, 1207c9566231SKashyap Desai "CreateRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1208c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1209c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 1210c9566231SKashyap Desai retval = -1; 1211c9566231SKashyap Desai goto out_unlock; 1212c9566231SKashyap Desai } 1213c9566231SKashyap Desai op_reply_q->qid = reply_qid; 1214c9566231SKashyap Desai mrioc->intr_info[midx].op_reply_q = op_reply_q; 1215c9566231SKashyap Desai 1216c9566231SKashyap Desai out_unlock: 1217c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 1218c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1219c9566231SKashyap Desai out: 1220c9566231SKashyap Desai 1221c9566231SKashyap Desai return retval; 1222c9566231SKashyap Desai } 1223c9566231SKashyap Desai 1224c9566231SKashyap Desai /** 1225c9566231SKashyap Desai * mpi3mr_create_op_req_q - create operational request queue 1226c9566231SKashyap Desai * @mrioc: Adapter instance reference 1227c9566231SKashyap Desai * @idx: operational request queue index 1228c9566231SKashyap Desai * @reply_qid: Reply queue ID 1229c9566231SKashyap Desai * 1230c9566231SKashyap Desai * Create operatinal request queue by issuing MPI request 1231c9566231SKashyap Desai * through admin queue. 1232c9566231SKashyap Desai * 1233c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1234c9566231SKashyap Desai */ 1235c9566231SKashyap Desai static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx, 1236c9566231SKashyap Desai u16 reply_qid) 1237c9566231SKashyap Desai { 1238c9566231SKashyap Desai struct mpi3_create_request_queue_request create_req; 1239c9566231SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + idx; 1240c9566231SKashyap Desai int retval = 0; 1241c9566231SKashyap Desai u16 req_qid = 0; 1242c9566231SKashyap Desai 1243c9566231SKashyap Desai req_qid = op_req_q->qid; 1244c9566231SKashyap Desai 1245c9566231SKashyap Desai if (req_qid) { 1246c9566231SKashyap Desai retval = -1; 1247c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: called for duplicate qid %d\n", 1248c9566231SKashyap Desai req_qid); 1249c9566231SKashyap Desai 1250c9566231SKashyap Desai return retval; 1251c9566231SKashyap Desai } 1252c9566231SKashyap Desai req_qid = idx + 1; 1253c9566231SKashyap Desai 1254c9566231SKashyap Desai op_req_q->num_requests = MPI3MR_OP_REQ_Q_QD; 1255c9566231SKashyap Desai op_req_q->ci = 0; 1256c9566231SKashyap Desai op_req_q->pi = 0; 1257c9566231SKashyap Desai op_req_q->reply_qid = reply_qid; 1258c9566231SKashyap Desai spin_lock_init(&op_req_q->q_lock); 1259c9566231SKashyap Desai 1260c9566231SKashyap Desai if (!op_req_q->q_segments) { 1261c9566231SKashyap Desai retval = mpi3mr_alloc_op_req_q_segments(mrioc, idx); 1262c9566231SKashyap Desai if (retval) { 1263c9566231SKashyap Desai mpi3mr_free_op_req_q_segments(mrioc, idx); 1264c9566231SKashyap Desai goto out; 1265c9566231SKashyap Desai } 1266c9566231SKashyap Desai } 1267c9566231SKashyap Desai 1268c9566231SKashyap Desai memset(&create_req, 0, sizeof(create_req)); 1269c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1270c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1271c9566231SKashyap Desai retval = -1; 1272c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: Init command is in use\n"); 1273c9566231SKashyap Desai goto out; 1274c9566231SKashyap Desai } 1275c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1276c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1277c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 1278c9566231SKashyap Desai create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1279c9566231SKashyap Desai create_req.function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE; 1280c9566231SKashyap Desai create_req.queue_id = cpu_to_le16(req_qid); 1281c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1282c9566231SKashyap Desai create_req.flags = 1283c9566231SKashyap Desai MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED; 1284c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1285c9566231SKashyap Desai op_req_q->q_segment_list_dma); 1286c9566231SKashyap Desai } else 1287c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1288c9566231SKashyap Desai op_req_q->q_segments[0].segment_dma); 1289c9566231SKashyap Desai create_req.reply_queue_id = cpu_to_le16(reply_qid); 1290c9566231SKashyap Desai create_req.size = cpu_to_le16(op_req_q->num_requests); 1291c9566231SKashyap Desai 1292c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 1293c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &create_req, 1294c9566231SKashyap Desai sizeof(create_req), 1); 1295c9566231SKashyap Desai if (retval) { 1296c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: Admin Post failed\n"); 1297c9566231SKashyap Desai goto out_unlock; 1298c9566231SKashyap Desai } 1299c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1300c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1301c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1302c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: command timed out\n"); 1303c9566231SKashyap Desai mpi3mr_set_diagsave(mrioc); 1304c9566231SKashyap Desai if (mpi3mr_issue_reset(mrioc, 1305c9566231SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 1306c9566231SKashyap Desai MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT)) 1307c9566231SKashyap Desai mrioc->unrecoverable = 1; 1308c9566231SKashyap Desai retval = -1; 1309c9566231SKashyap Desai goto out_unlock; 1310c9566231SKashyap Desai } 1311c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1312c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1313c9566231SKashyap Desai ioc_err(mrioc, 1314c9566231SKashyap Desai "CreateReqQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1315c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1316c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 1317c9566231SKashyap Desai retval = -1; 1318c9566231SKashyap Desai goto out_unlock; 1319c9566231SKashyap Desai } 1320c9566231SKashyap Desai op_req_q->qid = req_qid; 1321c9566231SKashyap Desai 1322c9566231SKashyap Desai out_unlock: 1323c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 1324c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1325c9566231SKashyap Desai out: 1326c9566231SKashyap Desai 1327c9566231SKashyap Desai return retval; 1328c9566231SKashyap Desai } 1329c9566231SKashyap Desai 1330c9566231SKashyap Desai /** 1331c9566231SKashyap Desai * mpi3mr_create_op_queues - create operational queue pairs 1332c9566231SKashyap Desai * @mrioc: Adapter instance reference 1333c9566231SKashyap Desai * 1334c9566231SKashyap Desai * Allocate memory for operational queue meta data and call 1335c9566231SKashyap Desai * create request and reply queue functions. 1336c9566231SKashyap Desai * 1337c9566231SKashyap Desai * Return: 0 on success, non-zero on failures. 1338c9566231SKashyap Desai */ 1339c9566231SKashyap Desai static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc) 1340c9566231SKashyap Desai { 1341c9566231SKashyap Desai int retval = 0; 1342c9566231SKashyap Desai u16 num_queues = 0, i = 0, msix_count_op_q = 1; 1343c9566231SKashyap Desai 1344c9566231SKashyap Desai num_queues = min_t(int, mrioc->facts.max_op_reply_q, 1345c9566231SKashyap Desai mrioc->facts.max_op_req_q); 1346c9566231SKashyap Desai 1347c9566231SKashyap Desai msix_count_op_q = 1348c9566231SKashyap Desai mrioc->intr_info_count - mrioc->op_reply_q_offset; 1349c9566231SKashyap Desai if (!mrioc->num_queues) 1350c9566231SKashyap Desai mrioc->num_queues = min_t(int, num_queues, msix_count_op_q); 1351c9566231SKashyap Desai num_queues = mrioc->num_queues; 1352c9566231SKashyap Desai ioc_info(mrioc, "Trying to create %d Operational Q pairs\n", 1353c9566231SKashyap Desai num_queues); 1354c9566231SKashyap Desai 1355c9566231SKashyap Desai if (!mrioc->req_qinfo) { 1356c9566231SKashyap Desai mrioc->req_qinfo = kcalloc(num_queues, 1357c9566231SKashyap Desai sizeof(struct op_req_qinfo), GFP_KERNEL); 1358c9566231SKashyap Desai if (!mrioc->req_qinfo) { 1359c9566231SKashyap Desai retval = -1; 1360c9566231SKashyap Desai goto out_failed; 1361c9566231SKashyap Desai } 1362c9566231SKashyap Desai 1363c9566231SKashyap Desai mrioc->op_reply_qinfo = kzalloc(sizeof(struct op_reply_qinfo) * 1364c9566231SKashyap Desai num_queues, GFP_KERNEL); 1365c9566231SKashyap Desai if (!mrioc->op_reply_qinfo) { 1366c9566231SKashyap Desai retval = -1; 1367c9566231SKashyap Desai goto out_failed; 1368c9566231SKashyap Desai } 1369c9566231SKashyap Desai } 1370c9566231SKashyap Desai 1371c9566231SKashyap Desai if (mrioc->enable_segqueue) 1372c9566231SKashyap Desai ioc_info(mrioc, 1373c9566231SKashyap Desai "allocating operational queues through segmented queues\n"); 1374c9566231SKashyap Desai 1375c9566231SKashyap Desai for (i = 0; i < num_queues; i++) { 1376c9566231SKashyap Desai if (mpi3mr_create_op_reply_q(mrioc, i)) { 1377c9566231SKashyap Desai ioc_err(mrioc, "Cannot create OP RepQ %d\n", i); 1378c9566231SKashyap Desai break; 1379c9566231SKashyap Desai } 1380c9566231SKashyap Desai if (mpi3mr_create_op_req_q(mrioc, i, 1381c9566231SKashyap Desai mrioc->op_reply_qinfo[i].qid)) { 1382c9566231SKashyap Desai ioc_err(mrioc, "Cannot create OP ReqQ %d\n", i); 1383c9566231SKashyap Desai mpi3mr_delete_op_reply_q(mrioc, i); 1384c9566231SKashyap Desai break; 1385c9566231SKashyap Desai } 1386c9566231SKashyap Desai } 1387c9566231SKashyap Desai 1388c9566231SKashyap Desai if (i == 0) { 1389c9566231SKashyap Desai /* Not even one queue is created successfully*/ 1390c9566231SKashyap Desai retval = -1; 1391c9566231SKashyap Desai goto out_failed; 1392c9566231SKashyap Desai } 1393c9566231SKashyap Desai mrioc->num_op_reply_q = mrioc->num_op_req_q = i; 1394c9566231SKashyap Desai ioc_info(mrioc, "Successfully created %d Operational Q pairs\n", 1395c9566231SKashyap Desai mrioc->num_op_reply_q); 1396c9566231SKashyap Desai 1397c9566231SKashyap Desai return retval; 1398c9566231SKashyap Desai out_failed: 1399c9566231SKashyap Desai kfree(mrioc->req_qinfo); 1400c9566231SKashyap Desai mrioc->req_qinfo = NULL; 1401c9566231SKashyap Desai 1402c9566231SKashyap Desai kfree(mrioc->op_reply_qinfo); 1403c9566231SKashyap Desai mrioc->op_reply_qinfo = NULL; 1404c9566231SKashyap Desai 1405c9566231SKashyap Desai return retval; 1406c9566231SKashyap Desai } 1407c9566231SKashyap Desai 1408c9566231SKashyap Desai /** 1409023ab2a9SKashyap Desai * mpi3mr_op_request_post - Post request to operational queue 1410023ab2a9SKashyap Desai * @mrioc: Adapter reference 1411023ab2a9SKashyap Desai * @op_req_q: Operational request queue info 1412023ab2a9SKashyap Desai * @req: MPI3 request 1413023ab2a9SKashyap Desai * 1414023ab2a9SKashyap Desai * Post the MPI3 request into operational request queue and 1415023ab2a9SKashyap Desai * inform the controller, if the queue is full return 1416023ab2a9SKashyap Desai * appropriate error. 1417023ab2a9SKashyap Desai * 1418023ab2a9SKashyap Desai * Return: 0 on success, non-zero on failure. 1419023ab2a9SKashyap Desai */ 1420023ab2a9SKashyap Desai int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc, 1421023ab2a9SKashyap Desai struct op_req_qinfo *op_req_q, u8 *req) 1422023ab2a9SKashyap Desai { 1423023ab2a9SKashyap Desai u16 pi = 0, max_entries, reply_qidx = 0, midx; 1424023ab2a9SKashyap Desai int retval = 0; 1425023ab2a9SKashyap Desai unsigned long flags; 1426023ab2a9SKashyap Desai u8 *req_entry; 1427023ab2a9SKashyap Desai void *segment_base_addr; 1428023ab2a9SKashyap Desai u16 req_sz = mrioc->facts.op_req_sz; 1429023ab2a9SKashyap Desai struct segments *segments = op_req_q->q_segments; 1430023ab2a9SKashyap Desai 1431023ab2a9SKashyap Desai reply_qidx = op_req_q->reply_qid - 1; 1432023ab2a9SKashyap Desai 1433023ab2a9SKashyap Desai if (mrioc->unrecoverable) 1434023ab2a9SKashyap Desai return -EFAULT; 1435023ab2a9SKashyap Desai 1436023ab2a9SKashyap Desai spin_lock_irqsave(&op_req_q->q_lock, flags); 1437023ab2a9SKashyap Desai pi = op_req_q->pi; 1438023ab2a9SKashyap Desai max_entries = op_req_q->num_requests; 1439023ab2a9SKashyap Desai 1440023ab2a9SKashyap Desai if (mpi3mr_check_req_qfull(op_req_q)) { 1441023ab2a9SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX( 1442023ab2a9SKashyap Desai reply_qidx, mrioc->op_reply_q_offset); 1443023ab2a9SKashyap Desai mpi3mr_process_op_reply_q(mrioc, &mrioc->intr_info[midx]); 1444023ab2a9SKashyap Desai 1445023ab2a9SKashyap Desai if (mpi3mr_check_req_qfull(op_req_q)) { 1446023ab2a9SKashyap Desai retval = -EAGAIN; 1447023ab2a9SKashyap Desai goto out; 1448023ab2a9SKashyap Desai } 1449023ab2a9SKashyap Desai } 1450023ab2a9SKashyap Desai 1451023ab2a9SKashyap Desai if (mrioc->reset_in_progress) { 1452023ab2a9SKashyap Desai ioc_err(mrioc, "OpReqQ submit reset in progress\n"); 1453023ab2a9SKashyap Desai retval = -EAGAIN; 1454023ab2a9SKashyap Desai goto out; 1455023ab2a9SKashyap Desai } 1456023ab2a9SKashyap Desai 1457023ab2a9SKashyap Desai segment_base_addr = segments[pi / op_req_q->segment_qd].segment; 1458023ab2a9SKashyap Desai req_entry = (u8 *)segment_base_addr + 1459023ab2a9SKashyap Desai ((pi % op_req_q->segment_qd) * req_sz); 1460023ab2a9SKashyap Desai 1461023ab2a9SKashyap Desai memset(req_entry, 0, req_sz); 1462023ab2a9SKashyap Desai memcpy(req_entry, req, MPI3MR_ADMIN_REQ_FRAME_SZ); 1463023ab2a9SKashyap Desai 1464023ab2a9SKashyap Desai if (++pi == max_entries) 1465023ab2a9SKashyap Desai pi = 0; 1466023ab2a9SKashyap Desai op_req_q->pi = pi; 1467023ab2a9SKashyap Desai 1468023ab2a9SKashyap Desai writel(op_req_q->pi, 1469023ab2a9SKashyap Desai &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].producer_index); 1470023ab2a9SKashyap Desai 1471023ab2a9SKashyap Desai out: 1472023ab2a9SKashyap Desai spin_unlock_irqrestore(&op_req_q->q_lock, flags); 1473023ab2a9SKashyap Desai return retval; 1474023ab2a9SKashyap Desai } 1475023ab2a9SKashyap Desai 1476023ab2a9SKashyap Desai /** 147754dfcffbSKashyap Desai * mpi3mr_sync_timestamp - Issue time stamp sync request 147854dfcffbSKashyap Desai * @mrioc: Adapter reference 147954dfcffbSKashyap Desai * 148054dfcffbSKashyap Desai * Issue IO unit control MPI request to synchornize firmware 148154dfcffbSKashyap Desai * timestamp with host time. 148254dfcffbSKashyap Desai * 148354dfcffbSKashyap Desai * Return: 0 on success, non-zero on failure. 148454dfcffbSKashyap Desai */ 148554dfcffbSKashyap Desai static int mpi3mr_sync_timestamp(struct mpi3mr_ioc *mrioc) 148654dfcffbSKashyap Desai { 148754dfcffbSKashyap Desai ktime_t current_time; 148854dfcffbSKashyap Desai struct mpi3_iounit_control_request iou_ctrl; 148954dfcffbSKashyap Desai int retval = 0; 149054dfcffbSKashyap Desai 149154dfcffbSKashyap Desai memset(&iou_ctrl, 0, sizeof(iou_ctrl)); 149254dfcffbSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 149354dfcffbSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 149454dfcffbSKashyap Desai retval = -1; 149554dfcffbSKashyap Desai ioc_err(mrioc, "Issue IOUCTL time_stamp: command is in use\n"); 149654dfcffbSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 149754dfcffbSKashyap Desai goto out; 149854dfcffbSKashyap Desai } 149954dfcffbSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 150054dfcffbSKashyap Desai mrioc->init_cmds.is_waiting = 1; 150154dfcffbSKashyap Desai mrioc->init_cmds.callback = NULL; 150254dfcffbSKashyap Desai iou_ctrl.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 150354dfcffbSKashyap Desai iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL; 150454dfcffbSKashyap Desai iou_ctrl.operation = MPI3_CTRL_OP_UPDATE_TIMESTAMP; 150554dfcffbSKashyap Desai current_time = ktime_get_real(); 150654dfcffbSKashyap Desai iou_ctrl.param64[0] = cpu_to_le64(ktime_to_ms(current_time)); 150754dfcffbSKashyap Desai 150854dfcffbSKashyap Desai init_completion(&mrioc->init_cmds.done); 150954dfcffbSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl, 151054dfcffbSKashyap Desai sizeof(iou_ctrl), 0); 151154dfcffbSKashyap Desai if (retval) { 151254dfcffbSKashyap Desai ioc_err(mrioc, "Issue IOUCTL time_stamp: Admin Post failed\n"); 151354dfcffbSKashyap Desai goto out_unlock; 151454dfcffbSKashyap Desai } 151554dfcffbSKashyap Desai 151654dfcffbSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 151754dfcffbSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 151854dfcffbSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 151954dfcffbSKashyap Desai ioc_err(mrioc, "Issue IOUCTL time_stamp: command timed out\n"); 152054dfcffbSKashyap Desai mrioc->init_cmds.is_waiting = 0; 152154dfcffbSKashyap Desai mpi3mr_soft_reset_handler(mrioc, 152254dfcffbSKashyap Desai MPI3MR_RESET_FROM_TSU_TIMEOUT, 1); 152354dfcffbSKashyap Desai retval = -1; 152454dfcffbSKashyap Desai goto out_unlock; 152554dfcffbSKashyap Desai } 152654dfcffbSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 152754dfcffbSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 152854dfcffbSKashyap Desai ioc_err(mrioc, 152954dfcffbSKashyap Desai "Issue IOUCTL time_stamp: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 153054dfcffbSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 153154dfcffbSKashyap Desai mrioc->init_cmds.ioc_loginfo); 153254dfcffbSKashyap Desai retval = -1; 153354dfcffbSKashyap Desai goto out_unlock; 153454dfcffbSKashyap Desai } 153554dfcffbSKashyap Desai 153654dfcffbSKashyap Desai out_unlock: 153754dfcffbSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 153854dfcffbSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 153954dfcffbSKashyap Desai 154054dfcffbSKashyap Desai out: 154154dfcffbSKashyap Desai return retval; 154254dfcffbSKashyap Desai } 154354dfcffbSKashyap Desai 154454dfcffbSKashyap Desai /** 1545672ae26cSKashyap Desai * mpi3mr_watchdog_work - watchdog thread to monitor faults 1546672ae26cSKashyap Desai * @work: work struct 1547672ae26cSKashyap Desai * 1548672ae26cSKashyap Desai * Watch dog work periodically executed (1 second interval) to 1549672ae26cSKashyap Desai * monitor firmware fault and to issue periodic timer sync to 1550672ae26cSKashyap Desai * the firmware. 1551672ae26cSKashyap Desai * 1552672ae26cSKashyap Desai * Return: Nothing. 1553672ae26cSKashyap Desai */ 1554672ae26cSKashyap Desai static void mpi3mr_watchdog_work(struct work_struct *work) 1555672ae26cSKashyap Desai { 1556672ae26cSKashyap Desai struct mpi3mr_ioc *mrioc = 1557672ae26cSKashyap Desai container_of(work, struct mpi3mr_ioc, watchdog_work.work); 1558672ae26cSKashyap Desai unsigned long flags; 1559672ae26cSKashyap Desai enum mpi3mr_iocstate ioc_state; 1560672ae26cSKashyap Desai u32 fault, host_diagnostic; 1561672ae26cSKashyap Desai 156254dfcffbSKashyap Desai if (mrioc->ts_update_counter++ >= MPI3MR_TSUPDATE_INTERVAL) { 156354dfcffbSKashyap Desai mrioc->ts_update_counter = 0; 156454dfcffbSKashyap Desai mpi3mr_sync_timestamp(mrioc); 156554dfcffbSKashyap Desai } 156654dfcffbSKashyap Desai 1567672ae26cSKashyap Desai /*Check for fault state every one second and issue Soft reset*/ 1568672ae26cSKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 1569672ae26cSKashyap Desai if (ioc_state == MRIOC_STATE_FAULT) { 1570672ae26cSKashyap Desai fault = readl(&mrioc->sysif_regs->fault) & 1571672ae26cSKashyap Desai MPI3_SYSIF_FAULT_CODE_MASK; 1572672ae26cSKashyap Desai host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); 1573672ae26cSKashyap Desai if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) { 1574672ae26cSKashyap Desai if (!mrioc->diagsave_timeout) { 1575672ae26cSKashyap Desai mpi3mr_print_fault_info(mrioc); 1576672ae26cSKashyap Desai ioc_warn(mrioc, "Diag save in progress\n"); 1577672ae26cSKashyap Desai } 1578672ae26cSKashyap Desai if ((mrioc->diagsave_timeout++) <= 1579672ae26cSKashyap Desai MPI3_SYSIF_DIAG_SAVE_TIMEOUT) 1580672ae26cSKashyap Desai goto schedule_work; 1581672ae26cSKashyap Desai } else 1582672ae26cSKashyap Desai mpi3mr_print_fault_info(mrioc); 1583672ae26cSKashyap Desai mrioc->diagsave_timeout = 0; 1584672ae26cSKashyap Desai 1585672ae26cSKashyap Desai if (fault == MPI3_SYSIF_FAULT_CODE_FACTORY_RESET) { 1586672ae26cSKashyap Desai ioc_info(mrioc, 1587672ae26cSKashyap Desai "Factory Reset fault occurred marking controller as unrecoverable" 1588672ae26cSKashyap Desai ); 1589672ae26cSKashyap Desai mrioc->unrecoverable = 1; 1590672ae26cSKashyap Desai goto out; 1591672ae26cSKashyap Desai } 1592672ae26cSKashyap Desai 1593672ae26cSKashyap Desai if ((fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) || 1594672ae26cSKashyap Desai (fault == MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS) || 1595672ae26cSKashyap Desai (mrioc->reset_in_progress)) 1596672ae26cSKashyap Desai goto out; 1597672ae26cSKashyap Desai if (fault == MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET) 1598672ae26cSKashyap Desai mpi3mr_soft_reset_handler(mrioc, 1599672ae26cSKashyap Desai MPI3MR_RESET_FROM_CIACTIV_FAULT, 0); 1600672ae26cSKashyap Desai else 1601672ae26cSKashyap Desai mpi3mr_soft_reset_handler(mrioc, 1602672ae26cSKashyap Desai MPI3MR_RESET_FROM_FAULT_WATCH, 0); 1603672ae26cSKashyap Desai } 1604672ae26cSKashyap Desai 1605672ae26cSKashyap Desai schedule_work: 1606672ae26cSKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 1607672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 1608672ae26cSKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 1609672ae26cSKashyap Desai &mrioc->watchdog_work, 1610672ae26cSKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 1611672ae26cSKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 1612672ae26cSKashyap Desai out: 1613672ae26cSKashyap Desai return; 1614672ae26cSKashyap Desai } 1615672ae26cSKashyap Desai 1616672ae26cSKashyap Desai /** 1617672ae26cSKashyap Desai * mpi3mr_start_watchdog - Start watchdog 1618672ae26cSKashyap Desai * @mrioc: Adapter instance reference 1619672ae26cSKashyap Desai * 1620672ae26cSKashyap Desai * Create and start the watchdog thread to monitor controller 1621672ae26cSKashyap Desai * faults. 1622672ae26cSKashyap Desai * 1623672ae26cSKashyap Desai * Return: Nothing. 1624672ae26cSKashyap Desai */ 1625672ae26cSKashyap Desai void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc) 1626672ae26cSKashyap Desai { 1627672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 1628672ae26cSKashyap Desai return; 1629672ae26cSKashyap Desai 1630672ae26cSKashyap Desai INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work); 1631672ae26cSKashyap Desai snprintf(mrioc->watchdog_work_q_name, 1632672ae26cSKashyap Desai sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name, 1633672ae26cSKashyap Desai mrioc->id); 1634672ae26cSKashyap Desai mrioc->watchdog_work_q = 1635672ae26cSKashyap Desai create_singlethread_workqueue(mrioc->watchdog_work_q_name); 1636672ae26cSKashyap Desai if (!mrioc->watchdog_work_q) { 1637672ae26cSKashyap Desai ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__); 1638672ae26cSKashyap Desai return; 1639672ae26cSKashyap Desai } 1640672ae26cSKashyap Desai 1641672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 1642672ae26cSKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 1643672ae26cSKashyap Desai &mrioc->watchdog_work, 1644672ae26cSKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 1645672ae26cSKashyap Desai } 1646672ae26cSKashyap Desai 1647672ae26cSKashyap Desai /** 1648672ae26cSKashyap Desai * mpi3mr_stop_watchdog - Stop watchdog 1649672ae26cSKashyap Desai * @mrioc: Adapter instance reference 1650672ae26cSKashyap Desai * 1651672ae26cSKashyap Desai * Stop the watchdog thread created to monitor controller 1652672ae26cSKashyap Desai * faults. 1653672ae26cSKashyap Desai * 1654672ae26cSKashyap Desai * Return: Nothing. 1655672ae26cSKashyap Desai */ 1656672ae26cSKashyap Desai void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc) 1657672ae26cSKashyap Desai { 1658672ae26cSKashyap Desai unsigned long flags; 1659672ae26cSKashyap Desai struct workqueue_struct *wq; 1660672ae26cSKashyap Desai 1661672ae26cSKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 1662672ae26cSKashyap Desai wq = mrioc->watchdog_work_q; 1663672ae26cSKashyap Desai mrioc->watchdog_work_q = NULL; 1664672ae26cSKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 1665672ae26cSKashyap Desai if (wq) { 1666672ae26cSKashyap Desai if (!cancel_delayed_work_sync(&mrioc->watchdog_work)) 1667672ae26cSKashyap Desai flush_workqueue(wq); 1668672ae26cSKashyap Desai destroy_workqueue(wq); 1669672ae26cSKashyap Desai } 1670672ae26cSKashyap Desai } 1671672ae26cSKashyap Desai 1672672ae26cSKashyap Desai /** 1673fb9b0457SKashyap Desai * mpi3mr_kill_ioc - Kill the controller 1674fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 1675fb9b0457SKashyap Desai * @reason: reason for the failure. 1676fb9b0457SKashyap Desai * 1677fb9b0457SKashyap Desai * If fault debug is enabled, display the fault info else issue 1678fb9b0457SKashyap Desai * diag fault and freeze the system for controller debug 1679fb9b0457SKashyap Desai * purpose. 1680fb9b0457SKashyap Desai * 1681fb9b0457SKashyap Desai * Return: Nothing. 1682fb9b0457SKashyap Desai */ 1683fb9b0457SKashyap Desai static void mpi3mr_kill_ioc(struct mpi3mr_ioc *mrioc, u32 reason) 1684fb9b0457SKashyap Desai { 1685fb9b0457SKashyap Desai enum mpi3mr_iocstate ioc_state; 1686fb9b0457SKashyap Desai 1687fb9b0457SKashyap Desai if (!mrioc->fault_dbg) 1688fb9b0457SKashyap Desai return; 1689fb9b0457SKashyap Desai 1690fb9b0457SKashyap Desai dump_stack(); 1691fb9b0457SKashyap Desai 1692fb9b0457SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 1693fb9b0457SKashyap Desai if (ioc_state == MRIOC_STATE_FAULT) 1694fb9b0457SKashyap Desai mpi3mr_print_fault_info(mrioc); 1695fb9b0457SKashyap Desai else { 1696fb9b0457SKashyap Desai ioc_err(mrioc, "Firmware is halted due to the reason %d\n", 1697fb9b0457SKashyap Desai reason); 1698fb9b0457SKashyap Desai mpi3mr_diagfault_reset_handler(mrioc, reason); 1699fb9b0457SKashyap Desai } 1700fb9b0457SKashyap Desai if (mrioc->fault_dbg == 2) 1701fb9b0457SKashyap Desai for (;;) 1702fb9b0457SKashyap Desai ; 1703fb9b0457SKashyap Desai else 1704fb9b0457SKashyap Desai panic("panic in %s\n", __func__); 1705fb9b0457SKashyap Desai } 1706fb9b0457SKashyap Desai 1707fb9b0457SKashyap Desai /** 1708824a1566SKashyap Desai * mpi3mr_setup_admin_qpair - Setup admin queue pair 1709824a1566SKashyap Desai * @mrioc: Adapter instance reference 1710824a1566SKashyap Desai * 1711824a1566SKashyap Desai * Allocate memory for admin queue pair if required and register 1712824a1566SKashyap Desai * the admin queue with the controller. 1713824a1566SKashyap Desai * 1714824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 1715824a1566SKashyap Desai */ 1716824a1566SKashyap Desai static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc) 1717824a1566SKashyap Desai { 1718824a1566SKashyap Desai int retval = 0; 1719824a1566SKashyap Desai u32 num_admin_entries = 0; 1720824a1566SKashyap Desai 1721824a1566SKashyap Desai mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE; 1722824a1566SKashyap Desai mrioc->num_admin_req = mrioc->admin_req_q_sz / 1723824a1566SKashyap Desai MPI3MR_ADMIN_REQ_FRAME_SZ; 1724824a1566SKashyap Desai mrioc->admin_req_ci = mrioc->admin_req_pi = 0; 1725824a1566SKashyap Desai mrioc->admin_req_base = NULL; 1726824a1566SKashyap Desai 1727824a1566SKashyap Desai mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE; 1728824a1566SKashyap Desai mrioc->num_admin_replies = mrioc->admin_reply_q_sz / 1729824a1566SKashyap Desai MPI3MR_ADMIN_REPLY_FRAME_SZ; 1730824a1566SKashyap Desai mrioc->admin_reply_ci = 0; 1731824a1566SKashyap Desai mrioc->admin_reply_ephase = 1; 1732824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 1733824a1566SKashyap Desai 1734824a1566SKashyap Desai if (!mrioc->admin_req_base) { 1735824a1566SKashyap Desai mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev, 1736824a1566SKashyap Desai mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL); 1737824a1566SKashyap Desai 1738824a1566SKashyap Desai if (!mrioc->admin_req_base) { 1739824a1566SKashyap Desai retval = -1; 1740824a1566SKashyap Desai goto out_failed; 1741824a1566SKashyap Desai } 1742824a1566SKashyap Desai 1743824a1566SKashyap Desai mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev, 1744824a1566SKashyap Desai mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma, 1745824a1566SKashyap Desai GFP_KERNEL); 1746824a1566SKashyap Desai 1747824a1566SKashyap Desai if (!mrioc->admin_reply_base) { 1748824a1566SKashyap Desai retval = -1; 1749824a1566SKashyap Desai goto out_failed; 1750824a1566SKashyap Desai } 1751824a1566SKashyap Desai } 1752824a1566SKashyap Desai 1753824a1566SKashyap Desai num_admin_entries = (mrioc->num_admin_replies << 16) | 1754824a1566SKashyap Desai (mrioc->num_admin_req); 1755824a1566SKashyap Desai writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries); 1756824a1566SKashyap Desai mpi3mr_writeq(mrioc->admin_req_dma, 1757824a1566SKashyap Desai &mrioc->sysif_regs->admin_request_queue_address); 1758824a1566SKashyap Desai mpi3mr_writeq(mrioc->admin_reply_dma, 1759824a1566SKashyap Desai &mrioc->sysif_regs->admin_reply_queue_address); 1760824a1566SKashyap Desai writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi); 1761824a1566SKashyap Desai writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); 1762824a1566SKashyap Desai return retval; 1763824a1566SKashyap Desai 1764824a1566SKashyap Desai out_failed: 1765824a1566SKashyap Desai 1766824a1566SKashyap Desai if (mrioc->admin_reply_base) { 1767824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz, 1768824a1566SKashyap Desai mrioc->admin_reply_base, mrioc->admin_reply_dma); 1769824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 1770824a1566SKashyap Desai } 1771824a1566SKashyap Desai if (mrioc->admin_req_base) { 1772824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz, 1773824a1566SKashyap Desai mrioc->admin_req_base, mrioc->admin_req_dma); 1774824a1566SKashyap Desai mrioc->admin_req_base = NULL; 1775824a1566SKashyap Desai } 1776824a1566SKashyap Desai return retval; 1777824a1566SKashyap Desai } 1778824a1566SKashyap Desai 1779824a1566SKashyap Desai /** 1780824a1566SKashyap Desai * mpi3mr_issue_iocfacts - Send IOC Facts 1781824a1566SKashyap Desai * @mrioc: Adapter instance reference 1782824a1566SKashyap Desai * @facts_data: Cached IOC facts data 1783824a1566SKashyap Desai * 1784824a1566SKashyap Desai * Issue IOC Facts MPI request through admin queue and wait for 1785824a1566SKashyap Desai * the completion of it or time out. 1786824a1566SKashyap Desai * 1787824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 1788824a1566SKashyap Desai */ 1789824a1566SKashyap Desai static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc, 1790824a1566SKashyap Desai struct mpi3_ioc_facts_data *facts_data) 1791824a1566SKashyap Desai { 1792824a1566SKashyap Desai struct mpi3_ioc_facts_request iocfacts_req; 1793824a1566SKashyap Desai void *data = NULL; 1794824a1566SKashyap Desai dma_addr_t data_dma; 1795824a1566SKashyap Desai u32 data_len = sizeof(*facts_data); 1796824a1566SKashyap Desai int retval = 0; 1797824a1566SKashyap Desai u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 1798824a1566SKashyap Desai 1799824a1566SKashyap Desai data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, 1800824a1566SKashyap Desai GFP_KERNEL); 1801824a1566SKashyap Desai 1802824a1566SKashyap Desai if (!data) { 1803824a1566SKashyap Desai retval = -1; 1804824a1566SKashyap Desai goto out; 1805824a1566SKashyap Desai } 1806824a1566SKashyap Desai 1807824a1566SKashyap Desai memset(&iocfacts_req, 0, sizeof(iocfacts_req)); 1808824a1566SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1809824a1566SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1810824a1566SKashyap Desai retval = -1; 1811824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n"); 1812824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1813824a1566SKashyap Desai goto out; 1814824a1566SKashyap Desai } 1815824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1816824a1566SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1817824a1566SKashyap Desai mrioc->init_cmds.callback = NULL; 1818824a1566SKashyap Desai iocfacts_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1819824a1566SKashyap Desai iocfacts_req.function = MPI3_FUNCTION_IOC_FACTS; 1820824a1566SKashyap Desai 1821824a1566SKashyap Desai mpi3mr_add_sg_single(&iocfacts_req.sgl, sgl_flags, data_len, 1822824a1566SKashyap Desai data_dma); 1823824a1566SKashyap Desai 1824824a1566SKashyap Desai init_completion(&mrioc->init_cmds.done); 1825824a1566SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req, 1826824a1566SKashyap Desai sizeof(iocfacts_req), 1); 1827824a1566SKashyap Desai if (retval) { 1828824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n"); 1829824a1566SKashyap Desai goto out_unlock; 1830824a1566SKashyap Desai } 1831824a1566SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1832824a1566SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1833824a1566SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1834824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCFacts: command timed out\n"); 1835824a1566SKashyap Desai mpi3mr_set_diagsave(mrioc); 1836824a1566SKashyap Desai mpi3mr_issue_reset(mrioc, 1837824a1566SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 1838824a1566SKashyap Desai MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT); 1839824a1566SKashyap Desai mrioc->unrecoverable = 1; 1840824a1566SKashyap Desai retval = -1; 1841824a1566SKashyap Desai goto out_unlock; 1842824a1566SKashyap Desai } 1843824a1566SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1844824a1566SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1845824a1566SKashyap Desai ioc_err(mrioc, 1846824a1566SKashyap Desai "Issue IOCFacts: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1847824a1566SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1848824a1566SKashyap Desai mrioc->init_cmds.ioc_loginfo); 1849824a1566SKashyap Desai retval = -1; 1850824a1566SKashyap Desai goto out_unlock; 1851824a1566SKashyap Desai } 1852824a1566SKashyap Desai memcpy(facts_data, (u8 *)data, data_len); 1853824a1566SKashyap Desai out_unlock: 1854824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 1855824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1856824a1566SKashyap Desai 1857824a1566SKashyap Desai out: 1858824a1566SKashyap Desai if (data) 1859824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma); 1860824a1566SKashyap Desai 1861824a1566SKashyap Desai return retval; 1862824a1566SKashyap Desai } 1863824a1566SKashyap Desai 1864824a1566SKashyap Desai /** 1865824a1566SKashyap Desai * mpi3mr_check_reset_dma_mask - Process IOC facts data 1866824a1566SKashyap Desai * @mrioc: Adapter instance reference 1867824a1566SKashyap Desai * 1868824a1566SKashyap Desai * Check whether the new DMA mask requested through IOCFacts by 1869824a1566SKashyap Desai * firmware needs to be set, if so set it . 1870824a1566SKashyap Desai * 1871824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 1872824a1566SKashyap Desai */ 1873824a1566SKashyap Desai static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc) 1874824a1566SKashyap Desai { 1875824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 1876824a1566SKashyap Desai int r; 1877824a1566SKashyap Desai u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask); 1878824a1566SKashyap Desai 1879824a1566SKashyap Desai if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask)) 1880824a1566SKashyap Desai return 0; 1881824a1566SKashyap Desai 1882824a1566SKashyap Desai ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n", 1883824a1566SKashyap Desai mrioc->dma_mask, facts_dma_mask); 1884824a1566SKashyap Desai 1885824a1566SKashyap Desai r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask); 1886824a1566SKashyap Desai if (r) { 1887824a1566SKashyap Desai ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n", 1888824a1566SKashyap Desai facts_dma_mask, r); 1889824a1566SKashyap Desai return r; 1890824a1566SKashyap Desai } 1891824a1566SKashyap Desai mrioc->dma_mask = facts_dma_mask; 1892824a1566SKashyap Desai return r; 1893824a1566SKashyap Desai } 1894824a1566SKashyap Desai 1895824a1566SKashyap Desai /** 1896824a1566SKashyap Desai * mpi3mr_process_factsdata - Process IOC facts data 1897824a1566SKashyap Desai * @mrioc: Adapter instance reference 1898824a1566SKashyap Desai * @facts_data: Cached IOC facts data 1899824a1566SKashyap Desai * 1900824a1566SKashyap Desai * Convert IOC facts data into cpu endianness and cache it in 1901824a1566SKashyap Desai * the driver . 1902824a1566SKashyap Desai * 1903824a1566SKashyap Desai * Return: Nothing. 1904824a1566SKashyap Desai */ 1905824a1566SKashyap Desai static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, 1906824a1566SKashyap Desai struct mpi3_ioc_facts_data *facts_data) 1907824a1566SKashyap Desai { 1908824a1566SKashyap Desai u32 ioc_config, req_sz, facts_flags; 1909824a1566SKashyap Desai 1910824a1566SKashyap Desai if ((le16_to_cpu(facts_data->ioc_facts_data_length)) != 1911824a1566SKashyap Desai (sizeof(*facts_data) / 4)) { 1912824a1566SKashyap Desai ioc_warn(mrioc, 1913824a1566SKashyap Desai "IOCFactsdata length mismatch driver_sz(%zu) firmware_sz(%d)\n", 1914824a1566SKashyap Desai sizeof(*facts_data), 1915824a1566SKashyap Desai le16_to_cpu(facts_data->ioc_facts_data_length) * 4); 1916824a1566SKashyap Desai } 1917824a1566SKashyap Desai 1918824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1919824a1566SKashyap Desai req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >> 1920824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT); 1921824a1566SKashyap Desai if (le16_to_cpu(facts_data->ioc_request_frame_size) != (req_sz / 4)) { 1922824a1566SKashyap Desai ioc_err(mrioc, 1923824a1566SKashyap Desai "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n", 1924824a1566SKashyap Desai req_sz / 4, le16_to_cpu(facts_data->ioc_request_frame_size)); 1925824a1566SKashyap Desai } 1926824a1566SKashyap Desai 1927824a1566SKashyap Desai memset(&mrioc->facts, 0, sizeof(mrioc->facts)); 1928824a1566SKashyap Desai 1929824a1566SKashyap Desai facts_flags = le32_to_cpu(facts_data->flags); 1930824a1566SKashyap Desai mrioc->facts.op_req_sz = req_sz; 1931824a1566SKashyap Desai mrioc->op_reply_desc_sz = 1 << ((ioc_config & 1932824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >> 1933824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT); 1934824a1566SKashyap Desai 1935824a1566SKashyap Desai mrioc->facts.ioc_num = facts_data->ioc_number; 1936824a1566SKashyap Desai mrioc->facts.who_init = facts_data->who_init; 1937824a1566SKashyap Desai mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->max_msix_vectors); 1938824a1566SKashyap Desai mrioc->facts.personality = (facts_flags & 1939824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK); 1940824a1566SKashyap Desai mrioc->facts.dma_mask = (facts_flags & 1941824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >> 1942824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT; 1943824a1566SKashyap Desai mrioc->facts.protocol_flags = facts_data->protocol_flags; 1944824a1566SKashyap Desai mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word); 1945824a1566SKashyap Desai mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_request); 1946824a1566SKashyap Desai mrioc->facts.product_id = le16_to_cpu(facts_data->product_id); 1947824a1566SKashyap Desai mrioc->facts.reply_sz = le16_to_cpu(facts_data->reply_frame_size) * 4; 1948824a1566SKashyap Desai mrioc->facts.exceptions = le16_to_cpu(facts_data->ioc_exceptions); 1949824a1566SKashyap Desai mrioc->facts.max_perids = le16_to_cpu(facts_data->max_persistent_id); 1950824a1566SKashyap Desai mrioc->facts.max_pds = le16_to_cpu(facts_data->max_pds); 1951824a1566SKashyap Desai mrioc->facts.max_vds = le16_to_cpu(facts_data->max_vds); 1952824a1566SKashyap Desai mrioc->facts.max_hpds = le16_to_cpu(facts_data->max_host_pds); 1953824a1566SKashyap Desai mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_advanced_host_pds); 1954824a1566SKashyap Desai mrioc->facts.max_raidpds = le16_to_cpu(facts_data->max_raid_pds); 1955824a1566SKashyap Desai mrioc->facts.max_nvme = le16_to_cpu(facts_data->max_nvme); 1956824a1566SKashyap Desai mrioc->facts.max_pcie_switches = 1957824a1566SKashyap Desai le16_to_cpu(facts_data->max_pc_ie_switches); 1958824a1566SKashyap Desai mrioc->facts.max_sasexpanders = 1959824a1566SKashyap Desai le16_to_cpu(facts_data->max_sas_expanders); 1960824a1566SKashyap Desai mrioc->facts.max_sasinitiators = 1961824a1566SKashyap Desai le16_to_cpu(facts_data->max_sas_initiators); 1962824a1566SKashyap Desai mrioc->facts.max_enclosures = le16_to_cpu(facts_data->max_enclosures); 1963824a1566SKashyap Desai mrioc->facts.min_devhandle = le16_to_cpu(facts_data->min_dev_handle); 1964824a1566SKashyap Desai mrioc->facts.max_devhandle = le16_to_cpu(facts_data->max_dev_handle); 1965824a1566SKashyap Desai mrioc->facts.max_op_req_q = 1966824a1566SKashyap Desai le16_to_cpu(facts_data->max_operational_request_queues); 1967824a1566SKashyap Desai mrioc->facts.max_op_reply_q = 1968824a1566SKashyap Desai le16_to_cpu(facts_data->max_operational_reply_queues); 1969824a1566SKashyap Desai mrioc->facts.ioc_capabilities = 1970824a1566SKashyap Desai le32_to_cpu(facts_data->ioc_capabilities); 1971824a1566SKashyap Desai mrioc->facts.fw_ver.build_num = 1972824a1566SKashyap Desai le16_to_cpu(facts_data->fw_version.build_num); 1973824a1566SKashyap Desai mrioc->facts.fw_ver.cust_id = 1974824a1566SKashyap Desai le16_to_cpu(facts_data->fw_version.customer_id); 1975824a1566SKashyap Desai mrioc->facts.fw_ver.ph_minor = facts_data->fw_version.phase_minor; 1976824a1566SKashyap Desai mrioc->facts.fw_ver.ph_major = facts_data->fw_version.phase_major; 1977824a1566SKashyap Desai mrioc->facts.fw_ver.gen_minor = facts_data->fw_version.gen_minor; 1978824a1566SKashyap Desai mrioc->facts.fw_ver.gen_major = facts_data->fw_version.gen_major; 1979824a1566SKashyap Desai mrioc->msix_count = min_t(int, mrioc->msix_count, 1980824a1566SKashyap Desai mrioc->facts.max_msix_vectors); 1981824a1566SKashyap Desai mrioc->facts.sge_mod_mask = facts_data->sge_modifier_mask; 1982824a1566SKashyap Desai mrioc->facts.sge_mod_value = facts_data->sge_modifier_value; 1983824a1566SKashyap Desai mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift; 1984824a1566SKashyap Desai mrioc->facts.shutdown_timeout = 1985824a1566SKashyap Desai le16_to_cpu(facts_data->shutdown_timeout); 1986824a1566SKashyap Desai 1987824a1566SKashyap Desai ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),", 1988824a1566SKashyap Desai mrioc->facts.ioc_num, mrioc->facts.max_op_req_q, 1989824a1566SKashyap Desai mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle); 1990824a1566SKashyap Desai ioc_info(mrioc, 1991824a1566SKashyap Desai "maxreqs(%d), mindh(%d) maxPDs(%d) maxvectors(%d) maxperids(%d)\n", 1992824a1566SKashyap Desai mrioc->facts.max_reqs, mrioc->facts.min_devhandle, 1993824a1566SKashyap Desai mrioc->facts.max_pds, mrioc->facts.max_msix_vectors, 1994824a1566SKashyap Desai mrioc->facts.max_perids); 1995824a1566SKashyap Desai ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ", 1996824a1566SKashyap Desai mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value, 1997824a1566SKashyap Desai mrioc->facts.sge_mod_shift); 1998824a1566SKashyap Desai ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x\n", 1999824a1566SKashyap Desai mrioc->facts.dma_mask, (facts_flags & 2000824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK)); 2001824a1566SKashyap Desai 2002824a1566SKashyap Desai mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD; 2003824a1566SKashyap Desai 2004824a1566SKashyap Desai if (reset_devices) 2005824a1566SKashyap Desai mrioc->max_host_ios = min_t(int, mrioc->max_host_ios, 2006824a1566SKashyap Desai MPI3MR_HOST_IOS_KDUMP); 2007824a1566SKashyap Desai } 2008824a1566SKashyap Desai 2009824a1566SKashyap Desai /** 2010824a1566SKashyap Desai * mpi3mr_alloc_reply_sense_bufs - Send IOC Init 2011824a1566SKashyap Desai * @mrioc: Adapter instance reference 2012824a1566SKashyap Desai * 2013824a1566SKashyap Desai * Allocate and initialize the reply free buffers, sense 2014824a1566SKashyap Desai * buffers, reply free queue and sense buffer queue. 2015824a1566SKashyap Desai * 2016824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2017824a1566SKashyap Desai */ 2018824a1566SKashyap Desai static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) 2019824a1566SKashyap Desai { 2020824a1566SKashyap Desai int retval = 0; 2021824a1566SKashyap Desai u32 sz, i; 2022824a1566SKashyap Desai dma_addr_t phy_addr; 2023824a1566SKashyap Desai 2024824a1566SKashyap Desai if (mrioc->init_cmds.reply) 2025824a1566SKashyap Desai goto post_reply_sbuf; 2026824a1566SKashyap Desai 2027824a1566SKashyap Desai mrioc->init_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL); 2028824a1566SKashyap Desai if (!mrioc->init_cmds.reply) 2029824a1566SKashyap Desai goto out_failed; 2030824a1566SKashyap Desai 203113ef29eaSKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 203213ef29eaSKashyap Desai mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->facts.reply_sz, 203313ef29eaSKashyap Desai GFP_KERNEL); 203413ef29eaSKashyap Desai if (!mrioc->dev_rmhs_cmds[i].reply) 203513ef29eaSKashyap Desai goto out_failed; 203613ef29eaSKashyap Desai } 203713ef29eaSKashyap Desai 2038*e844adb1SKashyap Desai mrioc->host_tm_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL); 2039*e844adb1SKashyap Desai if (!mrioc->host_tm_cmds.reply) 2040*e844adb1SKashyap Desai goto out_failed; 2041*e844adb1SKashyap Desai 2042*e844adb1SKashyap Desai mrioc->dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8; 2043*e844adb1SKashyap Desai if (mrioc->facts.max_devhandle % 8) 2044*e844adb1SKashyap Desai mrioc->dev_handle_bitmap_sz++; 2045*e844adb1SKashyap Desai mrioc->removepend_bitmap = kzalloc(mrioc->dev_handle_bitmap_sz, 2046*e844adb1SKashyap Desai GFP_KERNEL); 2047*e844adb1SKashyap Desai if (!mrioc->removepend_bitmap) 2048*e844adb1SKashyap Desai goto out_failed; 2049*e844adb1SKashyap Desai 2050*e844adb1SKashyap Desai mrioc->devrem_bitmap_sz = MPI3MR_NUM_DEVRMCMD / 8; 2051*e844adb1SKashyap Desai if (MPI3MR_NUM_DEVRMCMD % 8) 2052*e844adb1SKashyap Desai mrioc->devrem_bitmap_sz++; 2053*e844adb1SKashyap Desai mrioc->devrem_bitmap = kzalloc(mrioc->devrem_bitmap_sz, 2054*e844adb1SKashyap Desai GFP_KERNEL); 2055*e844adb1SKashyap Desai if (!mrioc->devrem_bitmap) 2056*e844adb1SKashyap Desai goto out_failed; 2057*e844adb1SKashyap Desai 2058824a1566SKashyap Desai mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES; 2059824a1566SKashyap Desai mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1; 2060824a1566SKashyap Desai mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR; 2061824a1566SKashyap Desai mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1; 2062824a1566SKashyap Desai 2063824a1566SKashyap Desai /* reply buffer pool, 16 byte align */ 2064824a1566SKashyap Desai sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz; 2065824a1566SKashyap Desai mrioc->reply_buf_pool = dma_pool_create("reply_buf pool", 2066824a1566SKashyap Desai &mrioc->pdev->dev, sz, 16, 0); 2067824a1566SKashyap Desai if (!mrioc->reply_buf_pool) { 2068824a1566SKashyap Desai ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n"); 2069824a1566SKashyap Desai goto out_failed; 2070824a1566SKashyap Desai } 2071824a1566SKashyap Desai 2072824a1566SKashyap Desai mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL, 2073824a1566SKashyap Desai &mrioc->reply_buf_dma); 2074824a1566SKashyap Desai if (!mrioc->reply_buf) 2075824a1566SKashyap Desai goto out_failed; 2076824a1566SKashyap Desai 2077824a1566SKashyap Desai mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz; 2078824a1566SKashyap Desai 2079824a1566SKashyap Desai /* reply free queue, 8 byte align */ 2080824a1566SKashyap Desai sz = mrioc->reply_free_qsz * 8; 2081824a1566SKashyap Desai mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool", 2082824a1566SKashyap Desai &mrioc->pdev->dev, sz, 8, 0); 2083824a1566SKashyap Desai if (!mrioc->reply_free_q_pool) { 2084824a1566SKashyap Desai ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n"); 2085824a1566SKashyap Desai goto out_failed; 2086824a1566SKashyap Desai } 2087824a1566SKashyap Desai mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool, 2088824a1566SKashyap Desai GFP_KERNEL, &mrioc->reply_free_q_dma); 2089824a1566SKashyap Desai if (!mrioc->reply_free_q) 2090824a1566SKashyap Desai goto out_failed; 2091824a1566SKashyap Desai 2092824a1566SKashyap Desai /* sense buffer pool, 4 byte align */ 2093824a1566SKashyap Desai sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ; 2094824a1566SKashyap Desai mrioc->sense_buf_pool = dma_pool_create("sense_buf pool", 2095824a1566SKashyap Desai &mrioc->pdev->dev, sz, 4, 0); 2096824a1566SKashyap Desai if (!mrioc->sense_buf_pool) { 2097824a1566SKashyap Desai ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n"); 2098824a1566SKashyap Desai goto out_failed; 2099824a1566SKashyap Desai } 2100824a1566SKashyap Desai mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL, 2101824a1566SKashyap Desai &mrioc->sense_buf_dma); 2102824a1566SKashyap Desai if (!mrioc->sense_buf) 2103824a1566SKashyap Desai goto out_failed; 2104824a1566SKashyap Desai 2105824a1566SKashyap Desai /* sense buffer queue, 8 byte align */ 2106824a1566SKashyap Desai sz = mrioc->sense_buf_q_sz * 8; 2107824a1566SKashyap Desai mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool", 2108824a1566SKashyap Desai &mrioc->pdev->dev, sz, 8, 0); 2109824a1566SKashyap Desai if (!mrioc->sense_buf_q_pool) { 2110824a1566SKashyap Desai ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n"); 2111824a1566SKashyap Desai goto out_failed; 2112824a1566SKashyap Desai } 2113824a1566SKashyap Desai mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool, 2114824a1566SKashyap Desai GFP_KERNEL, &mrioc->sense_buf_q_dma); 2115824a1566SKashyap Desai if (!mrioc->sense_buf_q) 2116824a1566SKashyap Desai goto out_failed; 2117824a1566SKashyap Desai 2118824a1566SKashyap Desai post_reply_sbuf: 2119824a1566SKashyap Desai sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz; 2120824a1566SKashyap Desai ioc_info(mrioc, 2121824a1566SKashyap Desai "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n", 2122824a1566SKashyap Desai mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->facts.reply_sz, 2123824a1566SKashyap Desai (sz / 1024), (unsigned long long)mrioc->reply_buf_dma); 2124824a1566SKashyap Desai sz = mrioc->reply_free_qsz * 8; 2125824a1566SKashyap Desai ioc_info(mrioc, 2126824a1566SKashyap Desai "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n", 2127824a1566SKashyap Desai mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024), 2128824a1566SKashyap Desai (unsigned long long)mrioc->reply_free_q_dma); 2129824a1566SKashyap Desai sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ; 2130824a1566SKashyap Desai ioc_info(mrioc, 2131824a1566SKashyap Desai "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n", 2132824a1566SKashyap Desai mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSEBUF_SZ, 2133824a1566SKashyap Desai (sz / 1024), (unsigned long long)mrioc->sense_buf_dma); 2134824a1566SKashyap Desai sz = mrioc->sense_buf_q_sz * 8; 2135824a1566SKashyap Desai ioc_info(mrioc, 2136824a1566SKashyap Desai "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n", 2137824a1566SKashyap Desai mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024), 2138824a1566SKashyap Desai (unsigned long long)mrioc->sense_buf_q_dma); 2139824a1566SKashyap Desai 2140824a1566SKashyap Desai /* initialize Reply buffer Queue */ 2141824a1566SKashyap Desai for (i = 0, phy_addr = mrioc->reply_buf_dma; 2142824a1566SKashyap Desai i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->facts.reply_sz) 2143824a1566SKashyap Desai mrioc->reply_free_q[i] = cpu_to_le64(phy_addr); 2144824a1566SKashyap Desai mrioc->reply_free_q[i] = cpu_to_le64(0); 2145824a1566SKashyap Desai 2146824a1566SKashyap Desai /* initialize Sense Buffer Queue */ 2147824a1566SKashyap Desai for (i = 0, phy_addr = mrioc->sense_buf_dma; 2148824a1566SKashyap Desai i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSEBUF_SZ) 2149824a1566SKashyap Desai mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr); 2150824a1566SKashyap Desai mrioc->sense_buf_q[i] = cpu_to_le64(0); 2151824a1566SKashyap Desai return retval; 2152824a1566SKashyap Desai 2153824a1566SKashyap Desai out_failed: 2154824a1566SKashyap Desai retval = -1; 2155824a1566SKashyap Desai return retval; 2156824a1566SKashyap Desai } 2157824a1566SKashyap Desai 2158824a1566SKashyap Desai /** 2159824a1566SKashyap Desai * mpi3mr_issue_iocinit - Send IOC Init 2160824a1566SKashyap Desai * @mrioc: Adapter instance reference 2161824a1566SKashyap Desai * 2162824a1566SKashyap Desai * Issue IOC Init MPI request through admin queue and wait for 2163824a1566SKashyap Desai * the completion of it or time out. 2164824a1566SKashyap Desai * 2165824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2166824a1566SKashyap Desai */ 2167824a1566SKashyap Desai static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc) 2168824a1566SKashyap Desai { 2169824a1566SKashyap Desai struct mpi3_ioc_init_request iocinit_req; 2170824a1566SKashyap Desai struct mpi3_driver_info_layout *drv_info; 2171824a1566SKashyap Desai dma_addr_t data_dma; 2172824a1566SKashyap Desai u32 data_len = sizeof(*drv_info); 2173824a1566SKashyap Desai int retval = 0; 2174824a1566SKashyap Desai ktime_t current_time; 2175824a1566SKashyap Desai 2176824a1566SKashyap Desai drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, 2177824a1566SKashyap Desai GFP_KERNEL); 2178824a1566SKashyap Desai if (!drv_info) { 2179824a1566SKashyap Desai retval = -1; 2180824a1566SKashyap Desai goto out; 2181824a1566SKashyap Desai } 2182824a1566SKashyap Desai drv_info->information_length = cpu_to_le32(data_len); 2183824a1566SKashyap Desai strncpy(drv_info->driver_signature, "Broadcom", sizeof(drv_info->driver_signature)); 2184824a1566SKashyap Desai strncpy(drv_info->os_name, utsname()->sysname, sizeof(drv_info->os_name)); 2185824a1566SKashyap Desai drv_info->os_name[sizeof(drv_info->os_name) - 1] = 0; 2186824a1566SKashyap Desai strncpy(drv_info->os_version, utsname()->release, sizeof(drv_info->os_version)); 2187824a1566SKashyap Desai drv_info->os_version[sizeof(drv_info->os_version) - 1] = 0; 2188824a1566SKashyap Desai strncpy(drv_info->driver_name, MPI3MR_DRIVER_NAME, sizeof(drv_info->driver_name)); 2189824a1566SKashyap Desai strncpy(drv_info->driver_version, MPI3MR_DRIVER_VERSION, sizeof(drv_info->driver_version)); 2190824a1566SKashyap Desai strncpy(drv_info->driver_release_date, MPI3MR_DRIVER_RELDATE, sizeof(drv_info->driver_release_date)); 2191824a1566SKashyap Desai drv_info->driver_capabilities = 0; 2192824a1566SKashyap Desai memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info, 2193824a1566SKashyap Desai sizeof(mrioc->driver_info)); 2194824a1566SKashyap Desai 2195824a1566SKashyap Desai memset(&iocinit_req, 0, sizeof(iocinit_req)); 2196824a1566SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 2197824a1566SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 2198824a1566SKashyap Desai retval = -1; 2199824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCInit: Init command is in use\n"); 2200824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2201824a1566SKashyap Desai goto out; 2202824a1566SKashyap Desai } 2203824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 2204824a1566SKashyap Desai mrioc->init_cmds.is_waiting = 1; 2205824a1566SKashyap Desai mrioc->init_cmds.callback = NULL; 2206824a1566SKashyap Desai iocinit_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 2207824a1566SKashyap Desai iocinit_req.function = MPI3_FUNCTION_IOC_INIT; 2208824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.dev = MPI3_VERSION_DEV; 2209824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.unit = MPI3_VERSION_UNIT; 2210824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.major = MPI3_VERSION_MAJOR; 2211824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.minor = MPI3_VERSION_MINOR; 2212824a1566SKashyap Desai iocinit_req.who_init = MPI3_WHOINIT_HOST_DRIVER; 2213824a1566SKashyap Desai iocinit_req.reply_free_queue_depth = cpu_to_le16(mrioc->reply_free_qsz); 2214824a1566SKashyap Desai iocinit_req.reply_free_queue_address = 2215824a1566SKashyap Desai cpu_to_le64(mrioc->reply_free_q_dma); 2216824a1566SKashyap Desai iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSEBUF_SZ); 2217824a1566SKashyap Desai iocinit_req.sense_buffer_free_queue_depth = 2218824a1566SKashyap Desai cpu_to_le16(mrioc->sense_buf_q_sz); 2219824a1566SKashyap Desai iocinit_req.sense_buffer_free_queue_address = 2220824a1566SKashyap Desai cpu_to_le64(mrioc->sense_buf_q_dma); 2221824a1566SKashyap Desai iocinit_req.driver_information_address = cpu_to_le64(data_dma); 2222824a1566SKashyap Desai 2223824a1566SKashyap Desai current_time = ktime_get_real(); 2224824a1566SKashyap Desai iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time)); 2225824a1566SKashyap Desai 2226824a1566SKashyap Desai init_completion(&mrioc->init_cmds.done); 2227824a1566SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iocinit_req, 2228824a1566SKashyap Desai sizeof(iocinit_req), 1); 2229824a1566SKashyap Desai if (retval) { 2230824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n"); 2231824a1566SKashyap Desai goto out_unlock; 2232824a1566SKashyap Desai } 2233824a1566SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 2234824a1566SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 2235824a1566SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 2236824a1566SKashyap Desai mpi3mr_set_diagsave(mrioc); 2237824a1566SKashyap Desai mpi3mr_issue_reset(mrioc, 2238824a1566SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 2239824a1566SKashyap Desai MPI3MR_RESET_FROM_IOCINIT_TIMEOUT); 2240824a1566SKashyap Desai mrioc->unrecoverable = 1; 2241824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCInit: command timed out\n"); 2242824a1566SKashyap Desai retval = -1; 2243824a1566SKashyap Desai goto out_unlock; 2244824a1566SKashyap Desai } 2245824a1566SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 2246824a1566SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 2247824a1566SKashyap Desai ioc_err(mrioc, 2248824a1566SKashyap Desai "Issue IOCInit: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 2249824a1566SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 2250824a1566SKashyap Desai mrioc->init_cmds.ioc_loginfo); 2251824a1566SKashyap Desai retval = -1; 2252824a1566SKashyap Desai goto out_unlock; 2253824a1566SKashyap Desai } 2254824a1566SKashyap Desai 2255824a1566SKashyap Desai out_unlock: 2256824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 2257824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2258824a1566SKashyap Desai 2259824a1566SKashyap Desai out: 2260824a1566SKashyap Desai if (drv_info) 2261824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info, 2262824a1566SKashyap Desai data_dma); 2263824a1566SKashyap Desai 2264824a1566SKashyap Desai return retval; 2265824a1566SKashyap Desai } 2266824a1566SKashyap Desai 2267824a1566SKashyap Desai /** 226813ef29eaSKashyap Desai * mpi3mr_unmask_events - Unmask events in event mask bitmap 226913ef29eaSKashyap Desai * @mrioc: Adapter instance reference 227013ef29eaSKashyap Desai * @event: MPI event ID 227113ef29eaSKashyap Desai * 227213ef29eaSKashyap Desai * Un mask the specific event by resetting the event_mask 227313ef29eaSKashyap Desai * bitmap. 227413ef29eaSKashyap Desai * 227513ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 227613ef29eaSKashyap Desai */ 227713ef29eaSKashyap Desai static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event) 227813ef29eaSKashyap Desai { 227913ef29eaSKashyap Desai u32 desired_event; 228013ef29eaSKashyap Desai u8 word; 228113ef29eaSKashyap Desai 228213ef29eaSKashyap Desai if (event >= 128) 228313ef29eaSKashyap Desai return; 228413ef29eaSKashyap Desai 228513ef29eaSKashyap Desai desired_event = (1 << (event % 32)); 228613ef29eaSKashyap Desai word = event / 32; 228713ef29eaSKashyap Desai 228813ef29eaSKashyap Desai mrioc->event_masks[word] &= ~desired_event; 228913ef29eaSKashyap Desai } 229013ef29eaSKashyap Desai 229113ef29eaSKashyap Desai /** 229213ef29eaSKashyap Desai * mpi3mr_issue_event_notification - Send event notification 229313ef29eaSKashyap Desai * @mrioc: Adapter instance reference 229413ef29eaSKashyap Desai * 229513ef29eaSKashyap Desai * Issue event notification MPI request through admin queue and 229613ef29eaSKashyap Desai * wait for the completion of it or time out. 229713ef29eaSKashyap Desai * 229813ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 229913ef29eaSKashyap Desai */ 230013ef29eaSKashyap Desai static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc) 230113ef29eaSKashyap Desai { 230213ef29eaSKashyap Desai struct mpi3_event_notification_request evtnotify_req; 230313ef29eaSKashyap Desai int retval = 0; 230413ef29eaSKashyap Desai u8 i; 230513ef29eaSKashyap Desai 230613ef29eaSKashyap Desai memset(&evtnotify_req, 0, sizeof(evtnotify_req)); 230713ef29eaSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 230813ef29eaSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 230913ef29eaSKashyap Desai retval = -1; 231013ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: Init command is in use\n"); 231113ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 231213ef29eaSKashyap Desai goto out; 231313ef29eaSKashyap Desai } 231413ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 231513ef29eaSKashyap Desai mrioc->init_cmds.is_waiting = 1; 231613ef29eaSKashyap Desai mrioc->init_cmds.callback = NULL; 231713ef29eaSKashyap Desai evtnotify_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 231813ef29eaSKashyap Desai evtnotify_req.function = MPI3_FUNCTION_EVENT_NOTIFICATION; 231913ef29eaSKashyap Desai for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 232013ef29eaSKashyap Desai evtnotify_req.event_masks[i] = 232113ef29eaSKashyap Desai cpu_to_le32(mrioc->event_masks[i]); 232213ef29eaSKashyap Desai init_completion(&mrioc->init_cmds.done); 232313ef29eaSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &evtnotify_req, 232413ef29eaSKashyap Desai sizeof(evtnotify_req), 1); 232513ef29eaSKashyap Desai if (retval) { 232613ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: Admin Post failed\n"); 232713ef29eaSKashyap Desai goto out_unlock; 232813ef29eaSKashyap Desai } 232913ef29eaSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 233013ef29eaSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 233113ef29eaSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 233213ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: command timed out\n"); 233313ef29eaSKashyap Desai mpi3mr_set_diagsave(mrioc); 233413ef29eaSKashyap Desai mpi3mr_issue_reset(mrioc, 233513ef29eaSKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 233613ef29eaSKashyap Desai MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT); 233713ef29eaSKashyap Desai mrioc->unrecoverable = 1; 233813ef29eaSKashyap Desai retval = -1; 233913ef29eaSKashyap Desai goto out_unlock; 234013ef29eaSKashyap Desai } 234113ef29eaSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 234213ef29eaSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 234313ef29eaSKashyap Desai ioc_err(mrioc, 234413ef29eaSKashyap Desai "Issue EvtNotify: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 234513ef29eaSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 234613ef29eaSKashyap Desai mrioc->init_cmds.ioc_loginfo); 234713ef29eaSKashyap Desai retval = -1; 234813ef29eaSKashyap Desai goto out_unlock; 234913ef29eaSKashyap Desai } 235013ef29eaSKashyap Desai 235113ef29eaSKashyap Desai out_unlock: 235213ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 235313ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 235413ef29eaSKashyap Desai out: 235513ef29eaSKashyap Desai return retval; 235613ef29eaSKashyap Desai } 235713ef29eaSKashyap Desai 235813ef29eaSKashyap Desai /** 235913ef29eaSKashyap Desai * mpi3mr_send_event_ack - Send event acknowledgment 236013ef29eaSKashyap Desai * @mrioc: Adapter instance reference 236113ef29eaSKashyap Desai * @event: MPI3 event ID 236213ef29eaSKashyap Desai * @event_ctx: Event context 236313ef29eaSKashyap Desai * 236413ef29eaSKashyap Desai * Send event acknowledgment through admin queue and wait for 236513ef29eaSKashyap Desai * it to complete. 236613ef29eaSKashyap Desai * 236713ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 236813ef29eaSKashyap Desai */ 236913ef29eaSKashyap Desai int mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, 237013ef29eaSKashyap Desai u32 event_ctx) 237113ef29eaSKashyap Desai { 237213ef29eaSKashyap Desai struct mpi3_event_ack_request evtack_req; 237313ef29eaSKashyap Desai int retval = 0; 237413ef29eaSKashyap Desai 237513ef29eaSKashyap Desai memset(&evtack_req, 0, sizeof(evtack_req)); 237613ef29eaSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 237713ef29eaSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 237813ef29eaSKashyap Desai retval = -1; 237913ef29eaSKashyap Desai ioc_err(mrioc, "Send EvtAck: Init command is in use\n"); 238013ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 238113ef29eaSKashyap Desai goto out; 238213ef29eaSKashyap Desai } 238313ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 238413ef29eaSKashyap Desai mrioc->init_cmds.is_waiting = 1; 238513ef29eaSKashyap Desai mrioc->init_cmds.callback = NULL; 238613ef29eaSKashyap Desai evtack_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 238713ef29eaSKashyap Desai evtack_req.function = MPI3_FUNCTION_EVENT_ACK; 238813ef29eaSKashyap Desai evtack_req.event = event; 238913ef29eaSKashyap Desai evtack_req.event_context = cpu_to_le32(event_ctx); 239013ef29eaSKashyap Desai 239113ef29eaSKashyap Desai init_completion(&mrioc->init_cmds.done); 239213ef29eaSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &evtack_req, 239313ef29eaSKashyap Desai sizeof(evtack_req), 1); 239413ef29eaSKashyap Desai if (retval) { 239513ef29eaSKashyap Desai ioc_err(mrioc, "Send EvtAck: Admin Post failed\n"); 239613ef29eaSKashyap Desai goto out_unlock; 239713ef29eaSKashyap Desai } 239813ef29eaSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 239913ef29eaSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 240013ef29eaSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 240113ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: command timed out\n"); 240213ef29eaSKashyap Desai mpi3mr_soft_reset_handler(mrioc, 240313ef29eaSKashyap Desai MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1); 240413ef29eaSKashyap Desai retval = -1; 240513ef29eaSKashyap Desai goto out_unlock; 240613ef29eaSKashyap Desai } 240713ef29eaSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 240813ef29eaSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 240913ef29eaSKashyap Desai ioc_err(mrioc, 241013ef29eaSKashyap Desai "Send EvtAck: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 241113ef29eaSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 241213ef29eaSKashyap Desai mrioc->init_cmds.ioc_loginfo); 241313ef29eaSKashyap Desai retval = -1; 241413ef29eaSKashyap Desai goto out_unlock; 241513ef29eaSKashyap Desai } 241613ef29eaSKashyap Desai 241713ef29eaSKashyap Desai out_unlock: 241813ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 241913ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 242013ef29eaSKashyap Desai out: 242113ef29eaSKashyap Desai return retval; 242213ef29eaSKashyap Desai } 242313ef29eaSKashyap Desai 242413ef29eaSKashyap Desai /** 2425824a1566SKashyap Desai * mpi3mr_alloc_chain_bufs - Allocate chain buffers 2426824a1566SKashyap Desai * @mrioc: Adapter instance reference 2427824a1566SKashyap Desai * 2428824a1566SKashyap Desai * Allocate chain buffers and set a bitmap to indicate free 2429824a1566SKashyap Desai * chain buffers. Chain buffers are used to pass the SGE 2430824a1566SKashyap Desai * information along with MPI3 SCSI IO requests for host I/O. 2431824a1566SKashyap Desai * 2432824a1566SKashyap Desai * Return: 0 on success, non-zero on failure 2433824a1566SKashyap Desai */ 2434824a1566SKashyap Desai static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc) 2435824a1566SKashyap Desai { 2436824a1566SKashyap Desai int retval = 0; 2437824a1566SKashyap Desai u32 sz, i; 2438824a1566SKashyap Desai u16 num_chains; 2439824a1566SKashyap Desai 2440824a1566SKashyap Desai num_chains = mrioc->max_host_ios / MPI3MR_CHAINBUF_FACTOR; 2441824a1566SKashyap Desai 2442824a1566SKashyap Desai mrioc->chain_buf_count = num_chains; 2443824a1566SKashyap Desai sz = sizeof(struct chain_element) * num_chains; 2444824a1566SKashyap Desai mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL); 2445824a1566SKashyap Desai if (!mrioc->chain_sgl_list) 2446824a1566SKashyap Desai goto out_failed; 2447824a1566SKashyap Desai 2448824a1566SKashyap Desai sz = MPI3MR_PAGE_SIZE_4K; 2449824a1566SKashyap Desai mrioc->chain_buf_pool = dma_pool_create("chain_buf pool", 2450824a1566SKashyap Desai &mrioc->pdev->dev, sz, 16, 0); 2451824a1566SKashyap Desai if (!mrioc->chain_buf_pool) { 2452824a1566SKashyap Desai ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n"); 2453824a1566SKashyap Desai goto out_failed; 2454824a1566SKashyap Desai } 2455824a1566SKashyap Desai 2456824a1566SKashyap Desai for (i = 0; i < num_chains; i++) { 2457824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr = 2458824a1566SKashyap Desai dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL, 2459824a1566SKashyap Desai &mrioc->chain_sgl_list[i].dma_addr); 2460824a1566SKashyap Desai 2461824a1566SKashyap Desai if (!mrioc->chain_sgl_list[i].addr) 2462824a1566SKashyap Desai goto out_failed; 2463824a1566SKashyap Desai } 2464824a1566SKashyap Desai mrioc->chain_bitmap_sz = num_chains / 8; 2465824a1566SKashyap Desai if (num_chains % 8) 2466824a1566SKashyap Desai mrioc->chain_bitmap_sz++; 2467824a1566SKashyap Desai mrioc->chain_bitmap = kzalloc(mrioc->chain_bitmap_sz, GFP_KERNEL); 2468824a1566SKashyap Desai if (!mrioc->chain_bitmap) 2469824a1566SKashyap Desai goto out_failed; 2470824a1566SKashyap Desai return retval; 2471824a1566SKashyap Desai out_failed: 2472824a1566SKashyap Desai retval = -1; 2473824a1566SKashyap Desai return retval; 2474824a1566SKashyap Desai } 2475824a1566SKashyap Desai 2476824a1566SKashyap Desai /** 2477023ab2a9SKashyap Desai * mpi3mr_port_enable_complete - Mark port enable complete 2478023ab2a9SKashyap Desai * @mrioc: Adapter instance reference 2479023ab2a9SKashyap Desai * @drv_cmd: Internal command tracker 2480023ab2a9SKashyap Desai * 2481023ab2a9SKashyap Desai * Call back for asynchronous port enable request sets the 2482023ab2a9SKashyap Desai * driver command to indicate port enable request is complete. 2483023ab2a9SKashyap Desai * 2484023ab2a9SKashyap Desai * Return: Nothing 2485023ab2a9SKashyap Desai */ 2486023ab2a9SKashyap Desai static void mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc, 2487023ab2a9SKashyap Desai struct mpi3mr_drv_cmd *drv_cmd) 2488023ab2a9SKashyap Desai { 2489023ab2a9SKashyap Desai drv_cmd->state = MPI3MR_CMD_NOTUSED; 2490023ab2a9SKashyap Desai drv_cmd->callback = NULL; 2491023ab2a9SKashyap Desai mrioc->scan_failed = drv_cmd->ioc_status; 2492023ab2a9SKashyap Desai mrioc->scan_started = 0; 2493023ab2a9SKashyap Desai } 2494023ab2a9SKashyap Desai 2495023ab2a9SKashyap Desai /** 2496023ab2a9SKashyap Desai * mpi3mr_issue_port_enable - Issue Port Enable 2497023ab2a9SKashyap Desai * @mrioc: Adapter instance reference 2498023ab2a9SKashyap Desai * @async: Flag to wait for completion or not 2499023ab2a9SKashyap Desai * 2500023ab2a9SKashyap Desai * Issue Port Enable MPI request through admin queue and if the 2501023ab2a9SKashyap Desai * async flag is not set wait for the completion of the port 2502023ab2a9SKashyap Desai * enable or time out. 2503023ab2a9SKashyap Desai * 2504023ab2a9SKashyap Desai * Return: 0 on success, non-zero on failures. 2505023ab2a9SKashyap Desai */ 2506023ab2a9SKashyap Desai int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async) 2507023ab2a9SKashyap Desai { 2508023ab2a9SKashyap Desai struct mpi3_port_enable_request pe_req; 2509023ab2a9SKashyap Desai int retval = 0; 2510023ab2a9SKashyap Desai u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT; 2511023ab2a9SKashyap Desai 2512023ab2a9SKashyap Desai memset(&pe_req, 0, sizeof(pe_req)); 2513023ab2a9SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 2514023ab2a9SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 2515023ab2a9SKashyap Desai retval = -1; 2516023ab2a9SKashyap Desai ioc_err(mrioc, "Issue PortEnable: Init command is in use\n"); 2517023ab2a9SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2518023ab2a9SKashyap Desai goto out; 2519023ab2a9SKashyap Desai } 2520023ab2a9SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 2521023ab2a9SKashyap Desai if (async) { 2522023ab2a9SKashyap Desai mrioc->init_cmds.is_waiting = 0; 2523023ab2a9SKashyap Desai mrioc->init_cmds.callback = mpi3mr_port_enable_complete; 2524023ab2a9SKashyap Desai } else { 2525023ab2a9SKashyap Desai mrioc->init_cmds.is_waiting = 1; 2526023ab2a9SKashyap Desai mrioc->init_cmds.callback = NULL; 2527023ab2a9SKashyap Desai init_completion(&mrioc->init_cmds.done); 2528023ab2a9SKashyap Desai } 2529023ab2a9SKashyap Desai pe_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 2530023ab2a9SKashyap Desai pe_req.function = MPI3_FUNCTION_PORT_ENABLE; 2531023ab2a9SKashyap Desai 2532023ab2a9SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &pe_req, sizeof(pe_req), 1); 2533023ab2a9SKashyap Desai if (retval) { 2534023ab2a9SKashyap Desai ioc_err(mrioc, "Issue PortEnable: Admin Post failed\n"); 2535023ab2a9SKashyap Desai goto out_unlock; 2536023ab2a9SKashyap Desai } 2537023ab2a9SKashyap Desai if (!async) { 2538023ab2a9SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 2539023ab2a9SKashyap Desai (pe_timeout * HZ)); 2540023ab2a9SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 2541023ab2a9SKashyap Desai ioc_err(mrioc, "Issue PortEnable: command timed out\n"); 2542023ab2a9SKashyap Desai retval = -1; 2543023ab2a9SKashyap Desai mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR; 2544023ab2a9SKashyap Desai mpi3mr_set_diagsave(mrioc); 2545023ab2a9SKashyap Desai mpi3mr_issue_reset(mrioc, 2546023ab2a9SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 2547023ab2a9SKashyap Desai MPI3MR_RESET_FROM_PE_TIMEOUT); 2548023ab2a9SKashyap Desai mrioc->unrecoverable = 1; 2549023ab2a9SKashyap Desai goto out_unlock; 2550023ab2a9SKashyap Desai } 2551023ab2a9SKashyap Desai mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds); 2552023ab2a9SKashyap Desai } 2553023ab2a9SKashyap Desai out_unlock: 2554023ab2a9SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2555023ab2a9SKashyap Desai out: 2556023ab2a9SKashyap Desai return retval; 2557023ab2a9SKashyap Desai } 2558023ab2a9SKashyap Desai 2559ff9561e9SKashyap Desai /* Protocol type to name mapper structure*/ 2560ff9561e9SKashyap Desai static const struct { 2561ff9561e9SKashyap Desai u8 protocol; 2562ff9561e9SKashyap Desai char *name; 2563ff9561e9SKashyap Desai } mpi3mr_protocols[] = { 2564ff9561e9SKashyap Desai { MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR, "Initiator" }, 2565ff9561e9SKashyap Desai { MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET, "Target" }, 2566ff9561e9SKashyap Desai { MPI3_IOCFACTS_PROTOCOL_NVME, "NVMe attachment" }, 2567ff9561e9SKashyap Desai }; 2568ff9561e9SKashyap Desai 2569ff9561e9SKashyap Desai /* Capability to name mapper structure*/ 2570ff9561e9SKashyap Desai static const struct { 2571ff9561e9SKashyap Desai u32 capability; 2572ff9561e9SKashyap Desai char *name; 2573ff9561e9SKashyap Desai } mpi3mr_capabilities[] = { 2574ff9561e9SKashyap Desai { MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE, "RAID" }, 2575ff9561e9SKashyap Desai }; 2576ff9561e9SKashyap Desai 2577ff9561e9SKashyap Desai /** 2578ff9561e9SKashyap Desai * mpi3mr_print_ioc_info - Display controller information 2579ff9561e9SKashyap Desai * @mrioc: Adapter instance reference 2580ff9561e9SKashyap Desai * 2581ff9561e9SKashyap Desai * Display controller personalit, capability, supported 2582ff9561e9SKashyap Desai * protocols etc. 2583ff9561e9SKashyap Desai * 2584ff9561e9SKashyap Desai * Return: Nothing 2585ff9561e9SKashyap Desai */ 2586ff9561e9SKashyap Desai static void 2587ff9561e9SKashyap Desai mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc) 2588ff9561e9SKashyap Desai { 2589ff9561e9SKashyap Desai int i = 0, bytes_wrote = 0; 2590ff9561e9SKashyap Desai char personality[16]; 2591ff9561e9SKashyap Desai char protocol[50] = {0}; 2592ff9561e9SKashyap Desai char capabilities[100] = {0}; 2593ff9561e9SKashyap Desai bool is_string_nonempty = false; 2594ff9561e9SKashyap Desai struct mpi3mr_compimg_ver *fwver = &mrioc->facts.fw_ver; 2595ff9561e9SKashyap Desai 2596ff9561e9SKashyap Desai switch (mrioc->facts.personality) { 2597ff9561e9SKashyap Desai case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA: 2598ff9561e9SKashyap Desai strncpy(personality, "Enhanced HBA", sizeof(personality)); 2599ff9561e9SKashyap Desai break; 2600ff9561e9SKashyap Desai case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR: 2601ff9561e9SKashyap Desai strncpy(personality, "RAID", sizeof(personality)); 2602ff9561e9SKashyap Desai break; 2603ff9561e9SKashyap Desai default: 2604ff9561e9SKashyap Desai strncpy(personality, "Unknown", sizeof(personality)); 2605ff9561e9SKashyap Desai break; 2606ff9561e9SKashyap Desai } 2607ff9561e9SKashyap Desai 2608ff9561e9SKashyap Desai ioc_info(mrioc, "Running in %s Personality", personality); 2609ff9561e9SKashyap Desai 2610ff9561e9SKashyap Desai ioc_info(mrioc, "FW version(%d.%d.%d.%d.%d.%d)\n", 2611ff9561e9SKashyap Desai fwver->gen_major, fwver->gen_minor, fwver->ph_major, 2612ff9561e9SKashyap Desai fwver->ph_minor, fwver->cust_id, fwver->build_num); 2613ff9561e9SKashyap Desai 2614ff9561e9SKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_protocols); i++) { 2615ff9561e9SKashyap Desai if (mrioc->facts.protocol_flags & 2616ff9561e9SKashyap Desai mpi3mr_protocols[i].protocol) { 2617ff9561e9SKashyap Desai if (is_string_nonempty && 2618ff9561e9SKashyap Desai (bytes_wrote < sizeof(protocol))) 2619ff9561e9SKashyap Desai bytes_wrote += snprintf(protocol + bytes_wrote, 2620ff9561e9SKashyap Desai (sizeof(protocol) - bytes_wrote), ","); 2621ff9561e9SKashyap Desai 2622ff9561e9SKashyap Desai if (bytes_wrote < sizeof(protocol)) 2623ff9561e9SKashyap Desai bytes_wrote += snprintf(protocol + bytes_wrote, 2624ff9561e9SKashyap Desai (sizeof(protocol) - bytes_wrote), "%s", 2625ff9561e9SKashyap Desai mpi3mr_protocols[i].name); 2626ff9561e9SKashyap Desai is_string_nonempty = true; 2627ff9561e9SKashyap Desai } 2628ff9561e9SKashyap Desai } 2629ff9561e9SKashyap Desai 2630ff9561e9SKashyap Desai bytes_wrote = 0; 2631ff9561e9SKashyap Desai is_string_nonempty = false; 2632ff9561e9SKashyap Desai for (i = 0; i < ARRAY_SIZE(mpi3mr_capabilities); i++) { 2633ff9561e9SKashyap Desai if (mrioc->facts.protocol_flags & 2634ff9561e9SKashyap Desai mpi3mr_capabilities[i].capability) { 2635ff9561e9SKashyap Desai if (is_string_nonempty && 2636ff9561e9SKashyap Desai (bytes_wrote < sizeof(capabilities))) 2637ff9561e9SKashyap Desai bytes_wrote += snprintf(capabilities + bytes_wrote, 2638ff9561e9SKashyap Desai (sizeof(capabilities) - bytes_wrote), ","); 2639ff9561e9SKashyap Desai 2640ff9561e9SKashyap Desai if (bytes_wrote < sizeof(capabilities)) 2641ff9561e9SKashyap Desai bytes_wrote += snprintf(capabilities + bytes_wrote, 2642ff9561e9SKashyap Desai (sizeof(capabilities) - bytes_wrote), "%s", 2643ff9561e9SKashyap Desai mpi3mr_capabilities[i].name); 2644ff9561e9SKashyap Desai is_string_nonempty = true; 2645ff9561e9SKashyap Desai } 2646ff9561e9SKashyap Desai } 2647ff9561e9SKashyap Desai 2648ff9561e9SKashyap Desai ioc_info(mrioc, "Protocol=(%s), Capabilities=(%s)\n", 2649ff9561e9SKashyap Desai protocol, capabilities); 2650ff9561e9SKashyap Desai } 2651ff9561e9SKashyap Desai 2652023ab2a9SKashyap Desai /** 2653824a1566SKashyap Desai * mpi3mr_cleanup_resources - Free PCI resources 2654824a1566SKashyap Desai * @mrioc: Adapter instance reference 2655824a1566SKashyap Desai * 2656824a1566SKashyap Desai * Unmap PCI device memory and disable PCI device. 2657824a1566SKashyap Desai * 2658824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 2659824a1566SKashyap Desai */ 2660824a1566SKashyap Desai void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc) 2661824a1566SKashyap Desai { 2662824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 2663824a1566SKashyap Desai 2664824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 2665824a1566SKashyap Desai 2666824a1566SKashyap Desai if (mrioc->sysif_regs) { 2667824a1566SKashyap Desai iounmap((void __iomem *)mrioc->sysif_regs); 2668824a1566SKashyap Desai mrioc->sysif_regs = NULL; 2669824a1566SKashyap Desai } 2670824a1566SKashyap Desai 2671824a1566SKashyap Desai if (pci_is_enabled(pdev)) { 2672824a1566SKashyap Desai if (mrioc->bars) 2673824a1566SKashyap Desai pci_release_selected_regions(pdev, mrioc->bars); 2674824a1566SKashyap Desai pci_disable_device(pdev); 2675824a1566SKashyap Desai } 2676824a1566SKashyap Desai } 2677824a1566SKashyap Desai 2678824a1566SKashyap Desai /** 2679824a1566SKashyap Desai * mpi3mr_setup_resources - Enable PCI resources 2680824a1566SKashyap Desai * @mrioc: Adapter instance reference 2681824a1566SKashyap Desai * 2682824a1566SKashyap Desai * Enable PCI device memory, MSI-x registers and set DMA mask. 2683824a1566SKashyap Desai * 2684824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 2685824a1566SKashyap Desai */ 2686824a1566SKashyap Desai int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc) 2687824a1566SKashyap Desai { 2688824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 2689824a1566SKashyap Desai u32 memap_sz = 0; 2690824a1566SKashyap Desai int i, retval = 0, capb = 0; 2691824a1566SKashyap Desai u16 message_control; 2692824a1566SKashyap Desai u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask : 2693824a1566SKashyap Desai (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) && 2694824a1566SKashyap Desai (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32)); 2695824a1566SKashyap Desai 2696824a1566SKashyap Desai if (pci_enable_device_mem(pdev)) { 2697824a1566SKashyap Desai ioc_err(mrioc, "pci_enable_device_mem: failed\n"); 2698824a1566SKashyap Desai retval = -ENODEV; 2699824a1566SKashyap Desai goto out_failed; 2700824a1566SKashyap Desai } 2701824a1566SKashyap Desai 2702824a1566SKashyap Desai capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX); 2703824a1566SKashyap Desai if (!capb) { 2704824a1566SKashyap Desai ioc_err(mrioc, "Unable to find MSI-X Capabilities\n"); 2705824a1566SKashyap Desai retval = -ENODEV; 2706824a1566SKashyap Desai goto out_failed; 2707824a1566SKashyap Desai } 2708824a1566SKashyap Desai mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); 2709824a1566SKashyap Desai 2710824a1566SKashyap Desai if (pci_request_selected_regions(pdev, mrioc->bars, 2711824a1566SKashyap Desai mrioc->driver_name)) { 2712824a1566SKashyap Desai ioc_err(mrioc, "pci_request_selected_regions: failed\n"); 2713824a1566SKashyap Desai retval = -ENODEV; 2714824a1566SKashyap Desai goto out_failed; 2715824a1566SKashyap Desai } 2716824a1566SKashyap Desai 2717824a1566SKashyap Desai for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) { 2718824a1566SKashyap Desai if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { 2719824a1566SKashyap Desai mrioc->sysif_regs_phys = pci_resource_start(pdev, i); 2720824a1566SKashyap Desai memap_sz = pci_resource_len(pdev, i); 2721824a1566SKashyap Desai mrioc->sysif_regs = 2722824a1566SKashyap Desai ioremap(mrioc->sysif_regs_phys, memap_sz); 2723824a1566SKashyap Desai break; 2724824a1566SKashyap Desai } 2725824a1566SKashyap Desai } 2726824a1566SKashyap Desai 2727824a1566SKashyap Desai pci_set_master(pdev); 2728824a1566SKashyap Desai 2729824a1566SKashyap Desai retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask); 2730824a1566SKashyap Desai if (retval) { 2731824a1566SKashyap Desai if (dma_mask != DMA_BIT_MASK(32)) { 2732824a1566SKashyap Desai ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n"); 2733824a1566SKashyap Desai dma_mask = DMA_BIT_MASK(32); 2734824a1566SKashyap Desai retval = dma_set_mask_and_coherent(&pdev->dev, 2735824a1566SKashyap Desai dma_mask); 2736824a1566SKashyap Desai } 2737824a1566SKashyap Desai if (retval) { 2738824a1566SKashyap Desai mrioc->dma_mask = 0; 2739824a1566SKashyap Desai ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n"); 2740824a1566SKashyap Desai goto out_failed; 2741824a1566SKashyap Desai } 2742824a1566SKashyap Desai } 2743824a1566SKashyap Desai mrioc->dma_mask = dma_mask; 2744824a1566SKashyap Desai 2745824a1566SKashyap Desai if (!mrioc->sysif_regs) { 2746824a1566SKashyap Desai ioc_err(mrioc, 2747824a1566SKashyap Desai "Unable to map adapter memory or resource not found\n"); 2748824a1566SKashyap Desai retval = -EINVAL; 2749824a1566SKashyap Desai goto out_failed; 2750824a1566SKashyap Desai } 2751824a1566SKashyap Desai 2752824a1566SKashyap Desai pci_read_config_word(pdev, capb + 2, &message_control); 2753824a1566SKashyap Desai mrioc->msix_count = (message_control & 0x3FF) + 1; 2754824a1566SKashyap Desai 2755824a1566SKashyap Desai pci_save_state(pdev); 2756824a1566SKashyap Desai 2757824a1566SKashyap Desai pci_set_drvdata(pdev, mrioc->shost); 2758824a1566SKashyap Desai 2759824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 2760824a1566SKashyap Desai 2761824a1566SKashyap Desai ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n", 2762824a1566SKashyap Desai (unsigned long long)mrioc->sysif_regs_phys, 2763824a1566SKashyap Desai mrioc->sysif_regs, memap_sz); 2764824a1566SKashyap Desai ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n", 2765824a1566SKashyap Desai mrioc->msix_count); 2766824a1566SKashyap Desai return retval; 2767824a1566SKashyap Desai 2768824a1566SKashyap Desai out_failed: 2769824a1566SKashyap Desai mpi3mr_cleanup_resources(mrioc); 2770824a1566SKashyap Desai return retval; 2771824a1566SKashyap Desai } 2772824a1566SKashyap Desai 2773824a1566SKashyap Desai /** 2774824a1566SKashyap Desai * mpi3mr_init_ioc - Initialize the controller 2775824a1566SKashyap Desai * @mrioc: Adapter instance reference 2776fb9b0457SKashyap Desai * @re_init: Flag to indicate is this fresh init or re-init 2777824a1566SKashyap Desai * 2778824a1566SKashyap Desai * This the controller initialization routine, executed either 2779824a1566SKashyap Desai * after soft reset or from pci probe callback. 2780824a1566SKashyap Desai * Setup the required resources, memory map the controller 2781824a1566SKashyap Desai * registers, create admin and operational reply queue pairs, 2782824a1566SKashyap Desai * allocate required memory for reply pool, sense buffer pool, 2783824a1566SKashyap Desai * issue IOC init request to the firmware, unmask the events and 2784824a1566SKashyap Desai * issue port enable to discover SAS/SATA/NVMe devies and RAID 2785824a1566SKashyap Desai * volumes. 2786824a1566SKashyap Desai * 2787824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 2788824a1566SKashyap Desai */ 2789fb9b0457SKashyap Desai int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 re_init) 2790824a1566SKashyap Desai { 2791824a1566SKashyap Desai int retval = 0; 2792824a1566SKashyap Desai enum mpi3mr_iocstate ioc_state; 2793824a1566SKashyap Desai u64 base_info; 2794824a1566SKashyap Desai u32 timeout; 279513ef29eaSKashyap Desai u32 ioc_status, ioc_config, i; 2796824a1566SKashyap Desai struct mpi3_ioc_facts_data facts_data; 2797824a1566SKashyap Desai 2798824a1566SKashyap Desai mrioc->change_count = 0; 2799fb9b0457SKashyap Desai if (!re_init) { 2800824a1566SKashyap Desai mrioc->cpu_count = num_online_cpus(); 2801824a1566SKashyap Desai retval = mpi3mr_setup_resources(mrioc); 2802824a1566SKashyap Desai if (retval) { 2803824a1566SKashyap Desai ioc_err(mrioc, "Failed to setup resources:error %d\n", 2804824a1566SKashyap Desai retval); 2805824a1566SKashyap Desai goto out_nocleanup; 2806824a1566SKashyap Desai } 2807fb9b0457SKashyap Desai } 2808fb9b0457SKashyap Desai 2809824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 2810824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 2811824a1566SKashyap Desai 2812824a1566SKashyap Desai ioc_info(mrioc, "SOD status %x configuration %x\n", 2813824a1566SKashyap Desai ioc_status, ioc_config); 2814824a1566SKashyap Desai 2815824a1566SKashyap Desai base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information); 2816824a1566SKashyap Desai ioc_info(mrioc, "SOD base_info %llx\n", base_info); 2817824a1566SKashyap Desai 2818824a1566SKashyap Desai /*The timeout value is in 2sec unit, changing it to seconds*/ 2819824a1566SKashyap Desai mrioc->ready_timeout = 2820824a1566SKashyap Desai ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >> 2821824a1566SKashyap Desai MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2; 2822824a1566SKashyap Desai 2823824a1566SKashyap Desai ioc_info(mrioc, "IOC ready timeout %d\n", mrioc->ready_timeout); 2824824a1566SKashyap Desai 2825824a1566SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 2826824a1566SKashyap Desai ioc_info(mrioc, "IOC in %s state during detection\n", 2827824a1566SKashyap Desai mpi3mr_iocstate_name(ioc_state)); 2828824a1566SKashyap Desai 2829824a1566SKashyap Desai if (ioc_state == MRIOC_STATE_BECOMING_READY || 2830824a1566SKashyap Desai ioc_state == MRIOC_STATE_RESET_REQUESTED) { 2831824a1566SKashyap Desai timeout = mrioc->ready_timeout * 10; 2832824a1566SKashyap Desai do { 2833824a1566SKashyap Desai msleep(100); 2834824a1566SKashyap Desai } while (--timeout); 2835824a1566SKashyap Desai 2836824a1566SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 2837824a1566SKashyap Desai ioc_info(mrioc, 2838824a1566SKashyap Desai "IOC in %s state after waiting for reset time\n", 2839824a1566SKashyap Desai mpi3mr_iocstate_name(ioc_state)); 2840824a1566SKashyap Desai } 2841824a1566SKashyap Desai 2842824a1566SKashyap Desai if (ioc_state == MRIOC_STATE_READY) { 2843824a1566SKashyap Desai retval = mpi3mr_issue_and_process_mur(mrioc, 2844824a1566SKashyap Desai MPI3MR_RESET_FROM_BRINGUP); 2845824a1566SKashyap Desai if (retval) { 2846824a1566SKashyap Desai ioc_err(mrioc, "Failed to MU reset IOC error %d\n", 2847824a1566SKashyap Desai retval); 2848824a1566SKashyap Desai } 2849824a1566SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 2850824a1566SKashyap Desai } 2851824a1566SKashyap Desai if (ioc_state != MRIOC_STATE_RESET) { 2852824a1566SKashyap Desai mpi3mr_print_fault_info(mrioc); 2853824a1566SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 2854824a1566SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, 2855824a1566SKashyap Desai MPI3MR_RESET_FROM_BRINGUP); 2856824a1566SKashyap Desai if (retval) { 2857824a1566SKashyap Desai ioc_err(mrioc, 2858824a1566SKashyap Desai "%s :Failed to soft reset IOC error %d\n", 2859824a1566SKashyap Desai __func__, retval); 2860824a1566SKashyap Desai goto out_failed; 2861824a1566SKashyap Desai } 2862824a1566SKashyap Desai } 2863824a1566SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 2864824a1566SKashyap Desai if (ioc_state != MRIOC_STATE_RESET) { 2865824a1566SKashyap Desai ioc_err(mrioc, "Cannot bring IOC to reset state\n"); 2866824a1566SKashyap Desai goto out_failed; 2867824a1566SKashyap Desai } 2868824a1566SKashyap Desai 2869824a1566SKashyap Desai retval = mpi3mr_setup_admin_qpair(mrioc); 2870824a1566SKashyap Desai if (retval) { 2871824a1566SKashyap Desai ioc_err(mrioc, "Failed to setup admin Qs: error %d\n", 2872824a1566SKashyap Desai retval); 2873824a1566SKashyap Desai goto out_failed; 2874824a1566SKashyap Desai } 2875824a1566SKashyap Desai 2876824a1566SKashyap Desai retval = mpi3mr_bring_ioc_ready(mrioc); 2877824a1566SKashyap Desai if (retval) { 2878824a1566SKashyap Desai ioc_err(mrioc, "Failed to bring ioc ready: error %d\n", 2879824a1566SKashyap Desai retval); 2880824a1566SKashyap Desai goto out_failed; 2881824a1566SKashyap Desai } 2882824a1566SKashyap Desai 2883fb9b0457SKashyap Desai if (!re_init) { 2884824a1566SKashyap Desai retval = mpi3mr_setup_isr(mrioc, 1); 2885824a1566SKashyap Desai if (retval) { 2886824a1566SKashyap Desai ioc_err(mrioc, "Failed to setup ISR error %d\n", 2887824a1566SKashyap Desai retval); 2888824a1566SKashyap Desai goto out_failed; 2889824a1566SKashyap Desai } 2890fb9b0457SKashyap Desai } else 2891fb9b0457SKashyap Desai mpi3mr_ioc_enable_intr(mrioc); 2892824a1566SKashyap Desai 2893824a1566SKashyap Desai retval = mpi3mr_issue_iocfacts(mrioc, &facts_data); 2894824a1566SKashyap Desai if (retval) { 2895824a1566SKashyap Desai ioc_err(mrioc, "Failed to Issue IOC Facts %d\n", 2896824a1566SKashyap Desai retval); 2897824a1566SKashyap Desai goto out_failed; 2898824a1566SKashyap Desai } 2899824a1566SKashyap Desai 2900824a1566SKashyap Desai mpi3mr_process_factsdata(mrioc, &facts_data); 2901fb9b0457SKashyap Desai if (!re_init) { 2902824a1566SKashyap Desai retval = mpi3mr_check_reset_dma_mask(mrioc); 2903824a1566SKashyap Desai if (retval) { 2904824a1566SKashyap Desai ioc_err(mrioc, "Resetting dma mask failed %d\n", 2905824a1566SKashyap Desai retval); 2906824a1566SKashyap Desai goto out_failed; 2907824a1566SKashyap Desai } 2908fb9b0457SKashyap Desai } 2909824a1566SKashyap Desai 2910ff9561e9SKashyap Desai mpi3mr_print_ioc_info(mrioc); 2911ff9561e9SKashyap Desai 2912824a1566SKashyap Desai retval = mpi3mr_alloc_reply_sense_bufs(mrioc); 2913824a1566SKashyap Desai if (retval) { 2914824a1566SKashyap Desai ioc_err(mrioc, 2915824a1566SKashyap Desai "%s :Failed to allocated reply sense buffers %d\n", 2916824a1566SKashyap Desai __func__, retval); 2917824a1566SKashyap Desai goto out_failed; 2918824a1566SKashyap Desai } 2919824a1566SKashyap Desai 2920fb9b0457SKashyap Desai if (!re_init) { 2921824a1566SKashyap Desai retval = mpi3mr_alloc_chain_bufs(mrioc); 2922824a1566SKashyap Desai if (retval) { 2923824a1566SKashyap Desai ioc_err(mrioc, "Failed to allocated chain buffers %d\n", 2924824a1566SKashyap Desai retval); 2925824a1566SKashyap Desai goto out_failed; 2926824a1566SKashyap Desai } 2927fb9b0457SKashyap Desai } 2928824a1566SKashyap Desai 2929824a1566SKashyap Desai retval = mpi3mr_issue_iocinit(mrioc); 2930824a1566SKashyap Desai if (retval) { 2931824a1566SKashyap Desai ioc_err(mrioc, "Failed to Issue IOC Init %d\n", 2932824a1566SKashyap Desai retval); 2933824a1566SKashyap Desai goto out_failed; 2934824a1566SKashyap Desai } 2935824a1566SKashyap Desai mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs; 2936824a1566SKashyap Desai writel(mrioc->reply_free_queue_host_index, 2937824a1566SKashyap Desai &mrioc->sysif_regs->reply_free_host_index); 2938824a1566SKashyap Desai 2939824a1566SKashyap Desai mrioc->sbq_host_index = mrioc->num_sense_bufs; 2940824a1566SKashyap Desai writel(mrioc->sbq_host_index, 2941824a1566SKashyap Desai &mrioc->sysif_regs->sense_buffer_free_host_index); 2942824a1566SKashyap Desai 2943fb9b0457SKashyap Desai if (!re_init) { 2944824a1566SKashyap Desai retval = mpi3mr_setup_isr(mrioc, 0); 2945824a1566SKashyap Desai if (retval) { 2946824a1566SKashyap Desai ioc_err(mrioc, "Failed to re-setup ISR, error %d\n", 2947824a1566SKashyap Desai retval); 2948824a1566SKashyap Desai goto out_failed; 2949824a1566SKashyap Desai } 2950fb9b0457SKashyap Desai } 2951824a1566SKashyap Desai 2952c9566231SKashyap Desai retval = mpi3mr_create_op_queues(mrioc); 2953c9566231SKashyap Desai if (retval) { 2954c9566231SKashyap Desai ioc_err(mrioc, "Failed to create OpQueues error %d\n", 2955c9566231SKashyap Desai retval); 2956c9566231SKashyap Desai goto out_failed; 2957c9566231SKashyap Desai } 2958c9566231SKashyap Desai 2959fb9b0457SKashyap Desai if (re_init && 2960fb9b0457SKashyap Desai (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q)) { 2961fb9b0457SKashyap Desai ioc_err(mrioc, 2962fb9b0457SKashyap Desai "Cannot create minimum number of OpQueues expected:%d created:%d\n", 2963fb9b0457SKashyap Desai mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q); 2964fb9b0457SKashyap Desai goto out_failed; 2965fb9b0457SKashyap Desai } 2966fb9b0457SKashyap Desai 296713ef29eaSKashyap Desai for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 296813ef29eaSKashyap Desai mrioc->event_masks[i] = -1; 296913ef29eaSKashyap Desai 297013ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED); 297113ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED); 297213ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE); 297313ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE); 297413ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST); 297513ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY); 297613ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR); 2977e36710dcSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE); 29788e653455SKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST); 29798e653455SKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION); 2980e36710dcSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT); 2981e36710dcSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE); 298213ef29eaSKashyap Desai 298313ef29eaSKashyap Desai retval = mpi3mr_issue_event_notification(mrioc); 298413ef29eaSKashyap Desai if (retval) { 298513ef29eaSKashyap Desai ioc_err(mrioc, "Failed to issue event notification %d\n", 298613ef29eaSKashyap Desai retval); 298713ef29eaSKashyap Desai goto out_failed; 298813ef29eaSKashyap Desai } 298913ef29eaSKashyap Desai 2990fb9b0457SKashyap Desai if (re_init) { 2991fb9b0457SKashyap Desai ioc_info(mrioc, "Issuing Port Enable\n"); 2992fb9b0457SKashyap Desai retval = mpi3mr_issue_port_enable(mrioc, 0); 2993fb9b0457SKashyap Desai if (retval) { 2994fb9b0457SKashyap Desai ioc_err(mrioc, "Failed to issue port enable %d\n", 2995fb9b0457SKashyap Desai retval); 2996fb9b0457SKashyap Desai goto out_failed; 2997fb9b0457SKashyap Desai } 2998fb9b0457SKashyap Desai } 2999824a1566SKashyap Desai return retval; 3000824a1566SKashyap Desai 3001824a1566SKashyap Desai out_failed: 3002fb9b0457SKashyap Desai mpi3mr_cleanup_ioc(mrioc, re_init); 3003824a1566SKashyap Desai out_nocleanup: 3004824a1566SKashyap Desai return retval; 3005824a1566SKashyap Desai } 3006824a1566SKashyap Desai 3007824a1566SKashyap Desai /** 3008fb9b0457SKashyap Desai * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's 3009fb9b0457SKashyap Desai * segments 3010fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3011fb9b0457SKashyap Desai * @qidx: Operational reply queue index 3012fb9b0457SKashyap Desai * 3013fb9b0457SKashyap Desai * Return: Nothing. 3014fb9b0457SKashyap Desai */ 3015fb9b0457SKashyap Desai static void mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx) 3016fb9b0457SKashyap Desai { 3017fb9b0457SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 3018fb9b0457SKashyap Desai struct segments *segments; 3019fb9b0457SKashyap Desai int i, size; 3020fb9b0457SKashyap Desai 3021fb9b0457SKashyap Desai if (!op_reply_q->q_segments) 3022fb9b0457SKashyap Desai return; 3023fb9b0457SKashyap Desai 3024fb9b0457SKashyap Desai size = op_reply_q->segment_qd * mrioc->op_reply_desc_sz; 3025fb9b0457SKashyap Desai segments = op_reply_q->q_segments; 3026fb9b0457SKashyap Desai for (i = 0; i < op_reply_q->num_segments; i++) 3027fb9b0457SKashyap Desai memset(segments[i].segment, 0, size); 3028fb9b0457SKashyap Desai } 3029fb9b0457SKashyap Desai 3030fb9b0457SKashyap Desai /** 3031fb9b0457SKashyap Desai * mpi3mr_memset_op_req_q_buffers - memset the operational request queue's 3032fb9b0457SKashyap Desai * segments 3033fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3034fb9b0457SKashyap Desai * @qidx: Operational request queue index 3035fb9b0457SKashyap Desai * 3036fb9b0457SKashyap Desai * Return: Nothing. 3037fb9b0457SKashyap Desai */ 3038fb9b0457SKashyap Desai static void mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx) 3039fb9b0457SKashyap Desai { 3040fb9b0457SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx; 3041fb9b0457SKashyap Desai struct segments *segments; 3042fb9b0457SKashyap Desai int i, size; 3043fb9b0457SKashyap Desai 3044fb9b0457SKashyap Desai if (!op_req_q->q_segments) 3045fb9b0457SKashyap Desai return; 3046fb9b0457SKashyap Desai 3047fb9b0457SKashyap Desai size = op_req_q->segment_qd * mrioc->facts.op_req_sz; 3048fb9b0457SKashyap Desai segments = op_req_q->q_segments; 3049fb9b0457SKashyap Desai for (i = 0; i < op_req_q->num_segments; i++) 3050fb9b0457SKashyap Desai memset(segments[i].segment, 0, size); 3051fb9b0457SKashyap Desai } 3052fb9b0457SKashyap Desai 3053fb9b0457SKashyap Desai /** 3054fb9b0457SKashyap Desai * mpi3mr_memset_buffers - memset memory for a controller 3055fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3056fb9b0457SKashyap Desai * 3057fb9b0457SKashyap Desai * clear all the memory allocated for a controller, typically 3058fb9b0457SKashyap Desai * called post reset to reuse the memory allocated during the 3059fb9b0457SKashyap Desai * controller init. 3060fb9b0457SKashyap Desai * 3061fb9b0457SKashyap Desai * Return: Nothing. 3062fb9b0457SKashyap Desai */ 3063fb9b0457SKashyap Desai static void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) 3064fb9b0457SKashyap Desai { 3065fb9b0457SKashyap Desai u16 i; 3066fb9b0457SKashyap Desai 3067fb9b0457SKashyap Desai memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz); 3068fb9b0457SKashyap Desai memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz); 3069fb9b0457SKashyap Desai 3070fb9b0457SKashyap Desai memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply)); 3071*e844adb1SKashyap Desai memset(mrioc->host_tm_cmds.reply, 0, 3072*e844adb1SKashyap Desai sizeof(*mrioc->host_tm_cmds.reply)); 3073fb9b0457SKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) 3074fb9b0457SKashyap Desai memset(mrioc->dev_rmhs_cmds[i].reply, 0, 3075fb9b0457SKashyap Desai sizeof(*mrioc->dev_rmhs_cmds[i].reply)); 3076fb9b0457SKashyap Desai memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); 3077fb9b0457SKashyap Desai memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); 3078fb9b0457SKashyap Desai 3079fb9b0457SKashyap Desai for (i = 0; i < mrioc->num_queues; i++) { 3080fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].qid = 0; 3081fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].ci = 0; 3082fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].num_replies = 0; 3083fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].ephase = 0; 3084fb9b0457SKashyap Desai mpi3mr_memset_op_reply_q_buffers(mrioc, i); 3085fb9b0457SKashyap Desai 3086fb9b0457SKashyap Desai mrioc->req_qinfo[i].ci = 0; 3087fb9b0457SKashyap Desai mrioc->req_qinfo[i].pi = 0; 3088fb9b0457SKashyap Desai mrioc->req_qinfo[i].num_requests = 0; 3089fb9b0457SKashyap Desai mrioc->req_qinfo[i].qid = 0; 3090fb9b0457SKashyap Desai mrioc->req_qinfo[i].reply_qid = 0; 3091fb9b0457SKashyap Desai spin_lock_init(&mrioc->req_qinfo[i].q_lock); 3092fb9b0457SKashyap Desai mpi3mr_memset_op_req_q_buffers(mrioc, i); 3093fb9b0457SKashyap Desai } 3094fb9b0457SKashyap Desai } 3095fb9b0457SKashyap Desai 3096fb9b0457SKashyap Desai /** 3097824a1566SKashyap Desai * mpi3mr_free_mem - Free memory allocated for a controller 3098824a1566SKashyap Desai * @mrioc: Adapter instance reference 3099824a1566SKashyap Desai * 3100824a1566SKashyap Desai * Free all the memory allocated for a controller. 3101824a1566SKashyap Desai * 3102824a1566SKashyap Desai * Return: Nothing. 3103824a1566SKashyap Desai */ 3104824a1566SKashyap Desai static void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) 3105824a1566SKashyap Desai { 3106824a1566SKashyap Desai u16 i; 3107824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info; 3108824a1566SKashyap Desai 3109824a1566SKashyap Desai if (mrioc->sense_buf_pool) { 3110824a1566SKashyap Desai if (mrioc->sense_buf) 3111824a1566SKashyap Desai dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf, 3112824a1566SKashyap Desai mrioc->sense_buf_dma); 3113824a1566SKashyap Desai dma_pool_destroy(mrioc->sense_buf_pool); 3114824a1566SKashyap Desai mrioc->sense_buf = NULL; 3115824a1566SKashyap Desai mrioc->sense_buf_pool = NULL; 3116824a1566SKashyap Desai } 3117824a1566SKashyap Desai if (mrioc->sense_buf_q_pool) { 3118824a1566SKashyap Desai if (mrioc->sense_buf_q) 3119824a1566SKashyap Desai dma_pool_free(mrioc->sense_buf_q_pool, 3120824a1566SKashyap Desai mrioc->sense_buf_q, mrioc->sense_buf_q_dma); 3121824a1566SKashyap Desai dma_pool_destroy(mrioc->sense_buf_q_pool); 3122824a1566SKashyap Desai mrioc->sense_buf_q = NULL; 3123824a1566SKashyap Desai mrioc->sense_buf_q_pool = NULL; 3124824a1566SKashyap Desai } 3125824a1566SKashyap Desai 3126824a1566SKashyap Desai if (mrioc->reply_buf_pool) { 3127824a1566SKashyap Desai if (mrioc->reply_buf) 3128824a1566SKashyap Desai dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf, 3129824a1566SKashyap Desai mrioc->reply_buf_dma); 3130824a1566SKashyap Desai dma_pool_destroy(mrioc->reply_buf_pool); 3131824a1566SKashyap Desai mrioc->reply_buf = NULL; 3132824a1566SKashyap Desai mrioc->reply_buf_pool = NULL; 3133824a1566SKashyap Desai } 3134824a1566SKashyap Desai if (mrioc->reply_free_q_pool) { 3135824a1566SKashyap Desai if (mrioc->reply_free_q) 3136824a1566SKashyap Desai dma_pool_free(mrioc->reply_free_q_pool, 3137824a1566SKashyap Desai mrioc->reply_free_q, mrioc->reply_free_q_dma); 3138824a1566SKashyap Desai dma_pool_destroy(mrioc->reply_free_q_pool); 3139824a1566SKashyap Desai mrioc->reply_free_q = NULL; 3140824a1566SKashyap Desai mrioc->reply_free_q_pool = NULL; 3141824a1566SKashyap Desai } 3142824a1566SKashyap Desai 3143c9566231SKashyap Desai for (i = 0; i < mrioc->num_op_req_q; i++) 3144c9566231SKashyap Desai mpi3mr_free_op_req_q_segments(mrioc, i); 3145c9566231SKashyap Desai 3146c9566231SKashyap Desai for (i = 0; i < mrioc->num_op_reply_q; i++) 3147c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, i); 3148c9566231SKashyap Desai 3149824a1566SKashyap Desai for (i = 0; i < mrioc->intr_info_count; i++) { 3150824a1566SKashyap Desai intr_info = mrioc->intr_info + i; 3151824a1566SKashyap Desai if (intr_info) 3152824a1566SKashyap Desai intr_info->op_reply_q = NULL; 3153824a1566SKashyap Desai } 3154824a1566SKashyap Desai 3155824a1566SKashyap Desai kfree(mrioc->req_qinfo); 3156824a1566SKashyap Desai mrioc->req_qinfo = NULL; 3157824a1566SKashyap Desai mrioc->num_op_req_q = 0; 3158824a1566SKashyap Desai 3159824a1566SKashyap Desai kfree(mrioc->op_reply_qinfo); 3160824a1566SKashyap Desai mrioc->op_reply_qinfo = NULL; 3161824a1566SKashyap Desai mrioc->num_op_reply_q = 0; 3162824a1566SKashyap Desai 3163824a1566SKashyap Desai kfree(mrioc->init_cmds.reply); 3164824a1566SKashyap Desai mrioc->init_cmds.reply = NULL; 3165824a1566SKashyap Desai 3166*e844adb1SKashyap Desai kfree(mrioc->host_tm_cmds.reply); 3167*e844adb1SKashyap Desai mrioc->host_tm_cmds.reply = NULL; 3168*e844adb1SKashyap Desai 3169*e844adb1SKashyap Desai kfree(mrioc->removepend_bitmap); 3170*e844adb1SKashyap Desai mrioc->removepend_bitmap = NULL; 3171*e844adb1SKashyap Desai 3172*e844adb1SKashyap Desai kfree(mrioc->devrem_bitmap); 3173*e844adb1SKashyap Desai mrioc->devrem_bitmap = NULL; 3174*e844adb1SKashyap Desai 3175824a1566SKashyap Desai kfree(mrioc->chain_bitmap); 3176824a1566SKashyap Desai mrioc->chain_bitmap = NULL; 3177824a1566SKashyap Desai 317813ef29eaSKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 317913ef29eaSKashyap Desai kfree(mrioc->dev_rmhs_cmds[i].reply); 318013ef29eaSKashyap Desai mrioc->dev_rmhs_cmds[i].reply = NULL; 318113ef29eaSKashyap Desai } 318213ef29eaSKashyap Desai 3183824a1566SKashyap Desai if (mrioc->chain_buf_pool) { 3184824a1566SKashyap Desai for (i = 0; i < mrioc->chain_buf_count; i++) { 3185824a1566SKashyap Desai if (mrioc->chain_sgl_list[i].addr) { 3186824a1566SKashyap Desai dma_pool_free(mrioc->chain_buf_pool, 3187824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr, 3188824a1566SKashyap Desai mrioc->chain_sgl_list[i].dma_addr); 3189824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr = NULL; 3190824a1566SKashyap Desai } 3191824a1566SKashyap Desai } 3192824a1566SKashyap Desai dma_pool_destroy(mrioc->chain_buf_pool); 3193824a1566SKashyap Desai mrioc->chain_buf_pool = NULL; 3194824a1566SKashyap Desai } 3195824a1566SKashyap Desai 3196824a1566SKashyap Desai kfree(mrioc->chain_sgl_list); 3197824a1566SKashyap Desai mrioc->chain_sgl_list = NULL; 3198824a1566SKashyap Desai 3199824a1566SKashyap Desai if (mrioc->admin_reply_base) { 3200824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz, 3201824a1566SKashyap Desai mrioc->admin_reply_base, mrioc->admin_reply_dma); 3202824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 3203824a1566SKashyap Desai } 3204824a1566SKashyap Desai if (mrioc->admin_req_base) { 3205824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz, 3206824a1566SKashyap Desai mrioc->admin_req_base, mrioc->admin_req_dma); 3207824a1566SKashyap Desai mrioc->admin_req_base = NULL; 3208824a1566SKashyap Desai } 3209824a1566SKashyap Desai } 3210824a1566SKashyap Desai 3211824a1566SKashyap Desai /** 3212824a1566SKashyap Desai * mpi3mr_issue_ioc_shutdown - shutdown controller 3213824a1566SKashyap Desai * @mrioc: Adapter instance reference 3214824a1566SKashyap Desai * 3215824a1566SKashyap Desai * Send shutodwn notification to the controller and wait for the 3216824a1566SKashyap Desai * shutdown_timeout for it to be completed. 3217824a1566SKashyap Desai * 3218824a1566SKashyap Desai * Return: Nothing. 3219824a1566SKashyap Desai */ 3220824a1566SKashyap Desai static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc) 3221824a1566SKashyap Desai { 3222824a1566SKashyap Desai u32 ioc_config, ioc_status; 3223824a1566SKashyap Desai u8 retval = 1; 3224824a1566SKashyap Desai u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10; 3225824a1566SKashyap Desai 3226824a1566SKashyap Desai ioc_info(mrioc, "Issuing shutdown Notification\n"); 3227824a1566SKashyap Desai if (mrioc->unrecoverable) { 3228824a1566SKashyap Desai ioc_warn(mrioc, 3229824a1566SKashyap Desai "IOC is unrecoverable shutdown is not issued\n"); 3230824a1566SKashyap Desai return; 3231824a1566SKashyap Desai } 3232824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 3233824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 3234824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) { 3235824a1566SKashyap Desai ioc_info(mrioc, "shutdown already in progress\n"); 3236824a1566SKashyap Desai return; 3237824a1566SKashyap Desai } 3238824a1566SKashyap Desai 3239824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 3240824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL; 3241824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN; 3242824a1566SKashyap Desai 3243824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 3244824a1566SKashyap Desai 3245824a1566SKashyap Desai if (mrioc->facts.shutdown_timeout) 3246824a1566SKashyap Desai timeout = mrioc->facts.shutdown_timeout * 10; 3247824a1566SKashyap Desai 3248824a1566SKashyap Desai do { 3249824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 3250824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 3251824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) { 3252824a1566SKashyap Desai retval = 0; 3253824a1566SKashyap Desai break; 3254824a1566SKashyap Desai } 3255824a1566SKashyap Desai msleep(100); 3256824a1566SKashyap Desai } while (--timeout); 3257824a1566SKashyap Desai 3258824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 3259824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 3260824a1566SKashyap Desai 3261824a1566SKashyap Desai if (retval) { 3262824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 3263824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) 3264824a1566SKashyap Desai ioc_warn(mrioc, 3265824a1566SKashyap Desai "shutdown still in progress after timeout\n"); 3266824a1566SKashyap Desai } 3267824a1566SKashyap Desai 3268824a1566SKashyap Desai ioc_info(mrioc, 3269824a1566SKashyap Desai "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n", 3270824a1566SKashyap Desai (!retval) ? "successful" : "failed", ioc_status, 3271824a1566SKashyap Desai ioc_config); 3272824a1566SKashyap Desai } 3273824a1566SKashyap Desai 3274824a1566SKashyap Desai /** 3275824a1566SKashyap Desai * mpi3mr_cleanup_ioc - Cleanup controller 3276824a1566SKashyap Desai * @mrioc: Adapter instance reference 3277fb9b0457SKashyap Desai * @re_init: Cleanup due to a reinit or not 3278824a1566SKashyap Desai * 3279824a1566SKashyap Desai * controller cleanup handler, Message unit reset or soft reset 3280824a1566SKashyap Desai * and shutdown notification is issued to the controller and the 3281824a1566SKashyap Desai * associated memory resources are freed. 3282824a1566SKashyap Desai * 3283824a1566SKashyap Desai * Return: Nothing. 3284824a1566SKashyap Desai */ 3285fb9b0457SKashyap Desai void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc, u8 re_init) 3286824a1566SKashyap Desai { 3287824a1566SKashyap Desai enum mpi3mr_iocstate ioc_state; 3288824a1566SKashyap Desai 3289fb9b0457SKashyap Desai if (!re_init) 3290672ae26cSKashyap Desai mpi3mr_stop_watchdog(mrioc); 3291672ae26cSKashyap Desai 3292824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 3293824a1566SKashyap Desai 3294824a1566SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 3295824a1566SKashyap Desai 3296824a1566SKashyap Desai if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) && 3297824a1566SKashyap Desai (ioc_state == MRIOC_STATE_READY)) { 3298824a1566SKashyap Desai if (mpi3mr_issue_and_process_mur(mrioc, 3299824a1566SKashyap Desai MPI3MR_RESET_FROM_CTLR_CLEANUP)) 3300824a1566SKashyap Desai mpi3mr_issue_reset(mrioc, 3301824a1566SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, 3302824a1566SKashyap Desai MPI3MR_RESET_FROM_MUR_FAILURE); 3303824a1566SKashyap Desai 3304fb9b0457SKashyap Desai if (!re_init) 3305824a1566SKashyap Desai mpi3mr_issue_ioc_shutdown(mrioc); 3306824a1566SKashyap Desai } 3307824a1566SKashyap Desai 3308fb9b0457SKashyap Desai if (!re_init) { 3309824a1566SKashyap Desai mpi3mr_free_mem(mrioc); 3310824a1566SKashyap Desai mpi3mr_cleanup_resources(mrioc); 3311824a1566SKashyap Desai } 3312fb9b0457SKashyap Desai } 3313fb9b0457SKashyap Desai 3314fb9b0457SKashyap Desai /** 3315fb9b0457SKashyap Desai * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command 3316fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3317fb9b0457SKashyap Desai * @cmdptr: Internal command tracker 3318fb9b0457SKashyap Desai * 3319fb9b0457SKashyap Desai * Complete an internal driver commands with state indicating it 3320fb9b0457SKashyap Desai * is completed due to reset. 3321fb9b0457SKashyap Desai * 3322fb9b0457SKashyap Desai * Return: Nothing. 3323fb9b0457SKashyap Desai */ 3324fb9b0457SKashyap Desai static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc *mrioc, 3325fb9b0457SKashyap Desai struct mpi3mr_drv_cmd *cmdptr) 3326fb9b0457SKashyap Desai { 3327fb9b0457SKashyap Desai if (cmdptr->state & MPI3MR_CMD_PENDING) { 3328fb9b0457SKashyap Desai cmdptr->state |= MPI3MR_CMD_RESET; 3329fb9b0457SKashyap Desai cmdptr->state &= ~MPI3MR_CMD_PENDING; 3330fb9b0457SKashyap Desai if (cmdptr->is_waiting) { 3331fb9b0457SKashyap Desai complete(&cmdptr->done); 3332fb9b0457SKashyap Desai cmdptr->is_waiting = 0; 3333fb9b0457SKashyap Desai } else if (cmdptr->callback) 3334fb9b0457SKashyap Desai cmdptr->callback(mrioc, cmdptr); 3335fb9b0457SKashyap Desai } 3336fb9b0457SKashyap Desai } 3337fb9b0457SKashyap Desai 3338fb9b0457SKashyap Desai /** 3339fb9b0457SKashyap Desai * mpi3mr_flush_drv_cmds - Flush internaldriver commands 3340fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3341fb9b0457SKashyap Desai * 3342fb9b0457SKashyap Desai * Flush all internal driver commands post reset 3343fb9b0457SKashyap Desai * 3344fb9b0457SKashyap Desai * Return: Nothing. 3345fb9b0457SKashyap Desai */ 3346fb9b0457SKashyap Desai static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc) 3347fb9b0457SKashyap Desai { 3348fb9b0457SKashyap Desai struct mpi3mr_drv_cmd *cmdptr; 3349fb9b0457SKashyap Desai u8 i; 3350fb9b0457SKashyap Desai 3351fb9b0457SKashyap Desai cmdptr = &mrioc->init_cmds; 3352fb9b0457SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 3353*e844adb1SKashyap Desai cmdptr = &mrioc->host_tm_cmds; 3354*e844adb1SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 3355fb9b0457SKashyap Desai 3356fb9b0457SKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 3357fb9b0457SKashyap Desai cmdptr = &mrioc->dev_rmhs_cmds[i]; 3358fb9b0457SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 3359fb9b0457SKashyap Desai } 3360fb9b0457SKashyap Desai } 3361fb9b0457SKashyap Desai 3362fb9b0457SKashyap Desai /** 3363fb9b0457SKashyap Desai * mpi3mr_diagfault_reset_handler - Diag fault reset handler 3364fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3365fb9b0457SKashyap Desai * @reset_reason: Reset reason code 3366fb9b0457SKashyap Desai * 3367fb9b0457SKashyap Desai * This is an handler for issuing diag fault reset from the 3368fb9b0457SKashyap Desai * applications through IOCTL path to stop the execution of the 3369fb9b0457SKashyap Desai * controller 3370fb9b0457SKashyap Desai * 3371fb9b0457SKashyap Desai * Return: 0 on success, non-zero on failure. 3372fb9b0457SKashyap Desai */ 3373fb9b0457SKashyap Desai int mpi3mr_diagfault_reset_handler(struct mpi3mr_ioc *mrioc, 3374fb9b0457SKashyap Desai u32 reset_reason) 3375fb9b0457SKashyap Desai { 3376fb9b0457SKashyap Desai int retval = 0; 3377fb9b0457SKashyap Desai 3378fb9b0457SKashyap Desai mrioc->reset_in_progress = 1; 3379fb9b0457SKashyap Desai 3380fb9b0457SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 3381fb9b0457SKashyap Desai 3382fb9b0457SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 3383fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); 3384fb9b0457SKashyap Desai 3385fb9b0457SKashyap Desai if (retval) { 3386fb9b0457SKashyap Desai ioc_err(mrioc, "The diag fault reset failed: reason %d\n", 3387fb9b0457SKashyap Desai reset_reason); 3388fb9b0457SKashyap Desai mpi3mr_ioc_enable_intr(mrioc); 3389fb9b0457SKashyap Desai } 3390fb9b0457SKashyap Desai ioc_info(mrioc, "%s\n", ((retval == 0) ? "SUCCESS" : "FAILED")); 3391fb9b0457SKashyap Desai mrioc->reset_in_progress = 0; 3392fb9b0457SKashyap Desai return retval; 3393fb9b0457SKashyap Desai } 3394824a1566SKashyap Desai 3395824a1566SKashyap Desai /** 3396824a1566SKashyap Desai * mpi3mr_soft_reset_handler - Reset the controller 3397824a1566SKashyap Desai * @mrioc: Adapter instance reference 3398824a1566SKashyap Desai * @reset_reason: Reset reason code 3399824a1566SKashyap Desai * @snapdump: Flag to generate snapdump in firmware or not 3400824a1566SKashyap Desai * 3401fb9b0457SKashyap Desai * This is an handler for recovering controller by issuing soft 3402fb9b0457SKashyap Desai * reset are diag fault reset. This is a blocking function and 3403fb9b0457SKashyap Desai * when one reset is executed if any other resets they will be 3404fb9b0457SKashyap Desai * blocked. All IOCTLs/IO will be blocked during the reset. If 3405fb9b0457SKashyap Desai * controller reset is successful then the controller will be 3406fb9b0457SKashyap Desai * reinitalized, otherwise the controller will be marked as not 3407fb9b0457SKashyap Desai * recoverable 3408fb9b0457SKashyap Desai * 3409fb9b0457SKashyap Desai * In snapdump bit is set, the controller is issued with diag 3410fb9b0457SKashyap Desai * fault reset so that the firmware can create a snap dump and 3411fb9b0457SKashyap Desai * post that the firmware will result in F000 fault and the 3412fb9b0457SKashyap Desai * driver will issue soft reset to recover from that. 3413824a1566SKashyap Desai * 3414824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 3415824a1566SKashyap Desai */ 3416824a1566SKashyap Desai int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, 3417824a1566SKashyap Desai u32 reset_reason, u8 snapdump) 3418824a1566SKashyap Desai { 3419fb9b0457SKashyap Desai int retval = 0, i; 3420fb9b0457SKashyap Desai unsigned long flags; 3421fb9b0457SKashyap Desai u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; 3422fb9b0457SKashyap Desai 3423fb9b0457SKashyap Desai if (mrioc->fault_dbg) { 3424fb9b0457SKashyap Desai if (snapdump) 3425fb9b0457SKashyap Desai mpi3mr_set_diagsave(mrioc); 3426fb9b0457SKashyap Desai mpi3mr_kill_ioc(mrioc, reset_reason); 3427fb9b0457SKashyap Desai } 3428fb9b0457SKashyap Desai 3429fb9b0457SKashyap Desai /* 3430fb9b0457SKashyap Desai * Block new resets until the currently executing one is finished and 3431fb9b0457SKashyap Desai * return the status of the existing reset for all blocked resets 3432fb9b0457SKashyap Desai */ 3433fb9b0457SKashyap Desai if (!mutex_trylock(&mrioc->reset_mutex)) { 3434fb9b0457SKashyap Desai ioc_info(mrioc, "Another reset in progress\n"); 3435fb9b0457SKashyap Desai return -1; 3436fb9b0457SKashyap Desai } 3437fb9b0457SKashyap Desai mrioc->reset_in_progress = 1; 3438fb9b0457SKashyap Desai 3439fb9b0457SKashyap Desai if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) && 3440fb9b0457SKashyap Desai (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) { 3441fb9b0457SKashyap Desai for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 3442fb9b0457SKashyap Desai mrioc->event_masks[i] = -1; 3443fb9b0457SKashyap Desai 3444fb9b0457SKashyap Desai retval = mpi3mr_issue_event_notification(mrioc); 3445fb9b0457SKashyap Desai 3446fb9b0457SKashyap Desai if (retval) { 3447fb9b0457SKashyap Desai ioc_err(mrioc, 3448fb9b0457SKashyap Desai "Failed to turn off events prior to reset %d\n", 3449fb9b0457SKashyap Desai retval); 3450fb9b0457SKashyap Desai } 3451fb9b0457SKashyap Desai } 3452fb9b0457SKashyap Desai 3453fb9b0457SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 3454fb9b0457SKashyap Desai 3455fb9b0457SKashyap Desai if (snapdump) { 3456fb9b0457SKashyap Desai mpi3mr_set_diagsave(mrioc); 3457fb9b0457SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 3458fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); 3459fb9b0457SKashyap Desai if (!retval) { 3460fb9b0457SKashyap Desai do { 3461fb9b0457SKashyap Desai host_diagnostic = 3462fb9b0457SKashyap Desai readl(&mrioc->sysif_regs->host_diagnostic); 3463fb9b0457SKashyap Desai if (!(host_diagnostic & 3464fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS)) 3465fb9b0457SKashyap Desai break; 3466fb9b0457SKashyap Desai msleep(100); 3467fb9b0457SKashyap Desai } while (--timeout); 3468fb9b0457SKashyap Desai } 3469fb9b0457SKashyap Desai } 3470fb9b0457SKashyap Desai 3471fb9b0457SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 3472fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason); 3473fb9b0457SKashyap Desai if (retval) { 3474fb9b0457SKashyap Desai ioc_err(mrioc, "Failed to issue soft reset to the ioc\n"); 3475fb9b0457SKashyap Desai goto out; 3476fb9b0457SKashyap Desai } 3477fb9b0457SKashyap Desai 3478fb9b0457SKashyap Desai mpi3mr_flush_delayed_rmhs_list(mrioc); 3479fb9b0457SKashyap Desai mpi3mr_flush_drv_cmds(mrioc); 3480fb9b0457SKashyap Desai memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); 3481fb9b0457SKashyap Desai memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); 3482fb9b0457SKashyap Desai mpi3mr_cleanup_fwevt_list(mrioc); 3483fb9b0457SKashyap Desai mpi3mr_flush_host_io(mrioc); 3484fb9b0457SKashyap Desai mpi3mr_invalidate_devhandles(mrioc); 3485fb9b0457SKashyap Desai mpi3mr_memset_buffers(mrioc); 3486fb9b0457SKashyap Desai retval = mpi3mr_init_ioc(mrioc, 1); 3487fb9b0457SKashyap Desai if (retval) { 3488fb9b0457SKashyap Desai pr_err(IOCNAME "reinit after soft reset failed: reason %d\n", 3489fb9b0457SKashyap Desai mrioc->name, reset_reason); 3490fb9b0457SKashyap Desai goto out; 3491fb9b0457SKashyap Desai } 3492fb9b0457SKashyap Desai ssleep(10); 3493fb9b0457SKashyap Desai 3494fb9b0457SKashyap Desai out: 3495fb9b0457SKashyap Desai if (!retval) { 3496fb9b0457SKashyap Desai mrioc->reset_in_progress = 0; 3497fb9b0457SKashyap Desai scsi_unblock_requests(mrioc->shost); 3498fb9b0457SKashyap Desai mpi3mr_rfresh_tgtdevs(mrioc); 349954dfcffbSKashyap Desai mrioc->ts_update_counter = 0; 3500fb9b0457SKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 3501fb9b0457SKashyap Desai if (mrioc->watchdog_work_q) 3502fb9b0457SKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 3503fb9b0457SKashyap Desai &mrioc->watchdog_work, 3504fb9b0457SKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 3505fb9b0457SKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 3506fb9b0457SKashyap Desai } else { 3507fb9b0457SKashyap Desai mpi3mr_issue_reset(mrioc, 3508fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); 3509fb9b0457SKashyap Desai mrioc->unrecoverable = 1; 3510fb9b0457SKashyap Desai mrioc->reset_in_progress = 0; 3511fb9b0457SKashyap Desai retval = -1; 3512fb9b0457SKashyap Desai } 3513fb9b0457SKashyap Desai 3514fb9b0457SKashyap Desai mutex_unlock(&mrioc->reset_mutex); 3515fb9b0457SKashyap Desai ioc_info(mrioc, "%s\n", ((retval == 0) ? "SUCCESS" : "FAILED")); 3516fb9b0457SKashyap Desai return retval; 3517824a1566SKashyap Desai } 3518