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; 175824a1566SKashyap Desai case MPI3MR_HOSTTAG_INVALID: 176824a1566SKashyap Desai if (def_reply && def_reply->function == 177824a1566SKashyap Desai MPI3_FUNCTION_EVENT_NOTIFICATION) 178824a1566SKashyap Desai mpi3mr_handle_events(mrioc, def_reply); 179824a1566SKashyap Desai return NULL; 180824a1566SKashyap Desai default: 181824a1566SKashyap Desai break; 182824a1566SKashyap Desai } 18313ef29eaSKashyap Desai if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN && 18413ef29eaSKashyap Desai host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX) { 18513ef29eaSKashyap Desai idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN; 18613ef29eaSKashyap Desai return &mrioc->dev_rmhs_cmds[idx]; 18713ef29eaSKashyap Desai } 188824a1566SKashyap Desai 189824a1566SKashyap Desai return NULL; 190824a1566SKashyap Desai } 191824a1566SKashyap Desai 192824a1566SKashyap Desai static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, 193824a1566SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma) 194824a1566SKashyap Desai { 195824a1566SKashyap Desai u16 reply_desc_type, host_tag = 0; 196824a1566SKashyap Desai u16 ioc_status = MPI3_IOCSTATUS_SUCCESS; 197824a1566SKashyap Desai u32 ioc_loginfo = 0; 198824a1566SKashyap Desai struct mpi3_status_reply_descriptor *status_desc; 199824a1566SKashyap Desai struct mpi3_address_reply_descriptor *addr_desc; 200824a1566SKashyap Desai struct mpi3_success_reply_descriptor *success_desc; 201824a1566SKashyap Desai struct mpi3_default_reply *def_reply = NULL; 202824a1566SKashyap Desai struct mpi3mr_drv_cmd *cmdptr = NULL; 203824a1566SKashyap Desai struct mpi3_scsi_io_reply *scsi_reply; 204824a1566SKashyap Desai u8 *sense_buf = NULL; 205824a1566SKashyap Desai 206824a1566SKashyap Desai *reply_dma = 0; 207824a1566SKashyap Desai reply_desc_type = le16_to_cpu(reply_desc->reply_flags) & 208824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK; 209824a1566SKashyap Desai switch (reply_desc_type) { 210824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS: 211824a1566SKashyap Desai status_desc = (struct mpi3_status_reply_descriptor *)reply_desc; 212824a1566SKashyap Desai host_tag = le16_to_cpu(status_desc->host_tag); 213824a1566SKashyap Desai ioc_status = le16_to_cpu(status_desc->ioc_status); 214824a1566SKashyap Desai if (ioc_status & 215824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) 216824a1566SKashyap Desai ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info); 217824a1566SKashyap Desai ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; 218824a1566SKashyap Desai break; 219824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY: 220824a1566SKashyap Desai addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc; 221824a1566SKashyap Desai *reply_dma = le64_to_cpu(addr_desc->reply_frame_address); 222824a1566SKashyap Desai def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma); 223824a1566SKashyap Desai if (!def_reply) 224824a1566SKashyap Desai goto out; 225824a1566SKashyap Desai host_tag = le16_to_cpu(def_reply->host_tag); 226824a1566SKashyap Desai ioc_status = le16_to_cpu(def_reply->ioc_status); 227824a1566SKashyap Desai if (ioc_status & 228824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) 229824a1566SKashyap Desai ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info); 230824a1566SKashyap Desai ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; 231824a1566SKashyap Desai if (def_reply->function == MPI3_FUNCTION_SCSI_IO) { 232824a1566SKashyap Desai scsi_reply = (struct mpi3_scsi_io_reply *)def_reply; 233824a1566SKashyap Desai sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc, 234824a1566SKashyap Desai le64_to_cpu(scsi_reply->sense_data_buffer_address)); 235824a1566SKashyap Desai } 236824a1566SKashyap Desai break; 237824a1566SKashyap Desai case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS: 238824a1566SKashyap Desai success_desc = (struct mpi3_success_reply_descriptor *)reply_desc; 239824a1566SKashyap Desai host_tag = le16_to_cpu(success_desc->host_tag); 240824a1566SKashyap Desai break; 241824a1566SKashyap Desai default: 242824a1566SKashyap Desai break; 243824a1566SKashyap Desai } 244824a1566SKashyap Desai 245824a1566SKashyap Desai cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply); 246824a1566SKashyap Desai if (cmdptr) { 247824a1566SKashyap Desai if (cmdptr->state & MPI3MR_CMD_PENDING) { 248824a1566SKashyap Desai cmdptr->state |= MPI3MR_CMD_COMPLETE; 249824a1566SKashyap Desai cmdptr->ioc_loginfo = ioc_loginfo; 250824a1566SKashyap Desai cmdptr->ioc_status = ioc_status; 251824a1566SKashyap Desai cmdptr->state &= ~MPI3MR_CMD_PENDING; 252824a1566SKashyap Desai if (def_reply) { 253824a1566SKashyap Desai cmdptr->state |= MPI3MR_CMD_REPLY_VALID; 254824a1566SKashyap Desai memcpy((u8 *)cmdptr->reply, (u8 *)def_reply, 255824a1566SKashyap Desai mrioc->facts.reply_sz); 256824a1566SKashyap Desai } 257824a1566SKashyap Desai if (cmdptr->is_waiting) { 258824a1566SKashyap Desai complete(&cmdptr->done); 259824a1566SKashyap Desai cmdptr->is_waiting = 0; 260824a1566SKashyap Desai } else if (cmdptr->callback) 261824a1566SKashyap Desai cmdptr->callback(mrioc, cmdptr); 262824a1566SKashyap Desai } 263824a1566SKashyap Desai } 264824a1566SKashyap Desai out: 265824a1566SKashyap Desai if (sense_buf) 266824a1566SKashyap Desai mpi3mr_repost_sense_buf(mrioc, 267824a1566SKashyap Desai le64_to_cpu(scsi_reply->sense_data_buffer_address)); 268824a1566SKashyap Desai } 269824a1566SKashyap Desai 270824a1566SKashyap Desai static int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) 271824a1566SKashyap Desai { 272824a1566SKashyap Desai u32 exp_phase = mrioc->admin_reply_ephase; 273824a1566SKashyap Desai u32 admin_reply_ci = mrioc->admin_reply_ci; 274824a1566SKashyap Desai u32 num_admin_replies = 0; 275824a1566SKashyap Desai u64 reply_dma = 0; 276824a1566SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc; 277824a1566SKashyap Desai 278824a1566SKashyap Desai reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base + 279824a1566SKashyap Desai admin_reply_ci; 280824a1566SKashyap Desai 281824a1566SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 282824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 283824a1566SKashyap Desai return 0; 284824a1566SKashyap Desai 285824a1566SKashyap Desai do { 286824a1566SKashyap Desai mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci); 287824a1566SKashyap Desai mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma); 288824a1566SKashyap Desai if (reply_dma) 289824a1566SKashyap Desai mpi3mr_repost_reply_buf(mrioc, reply_dma); 290824a1566SKashyap Desai num_admin_replies++; 291824a1566SKashyap Desai if (++admin_reply_ci == mrioc->num_admin_replies) { 292824a1566SKashyap Desai admin_reply_ci = 0; 293824a1566SKashyap Desai exp_phase ^= 1; 294824a1566SKashyap Desai } 295824a1566SKashyap Desai reply_desc = 296824a1566SKashyap Desai (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base + 297824a1566SKashyap Desai admin_reply_ci; 298824a1566SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 299824a1566SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 300824a1566SKashyap Desai break; 301824a1566SKashyap Desai } while (1); 302824a1566SKashyap Desai 303824a1566SKashyap Desai writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); 304824a1566SKashyap Desai mrioc->admin_reply_ci = admin_reply_ci; 305824a1566SKashyap Desai mrioc->admin_reply_ephase = exp_phase; 306824a1566SKashyap Desai 307824a1566SKashyap Desai return num_admin_replies; 308824a1566SKashyap Desai } 309824a1566SKashyap Desai 310023ab2a9SKashyap Desai /** 311023ab2a9SKashyap Desai * mpi3mr_get_reply_desc - get reply descriptor frame corresponding to 312023ab2a9SKashyap Desai * queue's consumer index from operational reply descriptor queue. 313023ab2a9SKashyap Desai * @op_reply_q: op_reply_qinfo object 314023ab2a9SKashyap Desai * @reply_ci: operational reply descriptor's queue consumer index 315023ab2a9SKashyap Desai * 316023ab2a9SKashyap Desai * Returns reply descriptor frame address 317023ab2a9SKashyap Desai */ 318023ab2a9SKashyap Desai static inline struct mpi3_default_reply_descriptor * 319023ab2a9SKashyap Desai mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci) 320023ab2a9SKashyap Desai { 321023ab2a9SKashyap Desai void *segment_base_addr; 322023ab2a9SKashyap Desai struct segments *segments = op_reply_q->q_segments; 323023ab2a9SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc = NULL; 324023ab2a9SKashyap Desai 325023ab2a9SKashyap Desai segment_base_addr = 326023ab2a9SKashyap Desai segments[reply_ci / op_reply_q->segment_qd].segment; 327023ab2a9SKashyap Desai reply_desc = (struct mpi3_default_reply_descriptor *)segment_base_addr + 328023ab2a9SKashyap Desai (reply_ci % op_reply_q->segment_qd); 329023ab2a9SKashyap Desai return reply_desc; 330023ab2a9SKashyap Desai } 331023ab2a9SKashyap Desai 332023ab2a9SKashyap Desai static int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, 333023ab2a9SKashyap Desai struct mpi3mr_intr_info *intr_info) 334023ab2a9SKashyap Desai { 335023ab2a9SKashyap Desai struct op_reply_qinfo *op_reply_q = intr_info->op_reply_q; 336023ab2a9SKashyap Desai struct op_req_qinfo *op_req_q; 337023ab2a9SKashyap Desai u32 exp_phase; 338023ab2a9SKashyap Desai u32 reply_ci; 339023ab2a9SKashyap Desai u32 num_op_reply = 0; 340023ab2a9SKashyap Desai u64 reply_dma = 0; 341023ab2a9SKashyap Desai struct mpi3_default_reply_descriptor *reply_desc; 342023ab2a9SKashyap Desai u16 req_q_idx = 0, reply_qidx; 343023ab2a9SKashyap Desai 344023ab2a9SKashyap Desai reply_qidx = op_reply_q->qid - 1; 345023ab2a9SKashyap Desai 346023ab2a9SKashyap Desai exp_phase = op_reply_q->ephase; 347023ab2a9SKashyap Desai reply_ci = op_reply_q->ci; 348023ab2a9SKashyap Desai 349023ab2a9SKashyap Desai reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci); 350023ab2a9SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 351023ab2a9SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) { 352023ab2a9SKashyap Desai return 0; 353023ab2a9SKashyap Desai } 354023ab2a9SKashyap Desai 355023ab2a9SKashyap Desai do { 356023ab2a9SKashyap Desai req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1; 357023ab2a9SKashyap Desai op_req_q = &mrioc->req_qinfo[req_q_idx]; 358023ab2a9SKashyap Desai 359023ab2a9SKashyap Desai WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci)); 360023ab2a9SKashyap Desai mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma, 361023ab2a9SKashyap Desai reply_qidx); 362023ab2a9SKashyap Desai if (reply_dma) 363023ab2a9SKashyap Desai mpi3mr_repost_reply_buf(mrioc, reply_dma); 364023ab2a9SKashyap Desai num_op_reply++; 365023ab2a9SKashyap Desai 366023ab2a9SKashyap Desai if (++reply_ci == op_reply_q->num_replies) { 367023ab2a9SKashyap Desai reply_ci = 0; 368023ab2a9SKashyap Desai exp_phase ^= 1; 369023ab2a9SKashyap Desai } 370023ab2a9SKashyap Desai 371023ab2a9SKashyap Desai reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci); 372023ab2a9SKashyap Desai 373023ab2a9SKashyap Desai if ((le16_to_cpu(reply_desc->reply_flags) & 374023ab2a9SKashyap Desai MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) 375023ab2a9SKashyap Desai break; 376023ab2a9SKashyap Desai 377023ab2a9SKashyap Desai } while (1); 378023ab2a9SKashyap Desai 379023ab2a9SKashyap Desai writel(reply_ci, 380023ab2a9SKashyap Desai &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index); 381023ab2a9SKashyap Desai op_reply_q->ci = reply_ci; 382023ab2a9SKashyap Desai op_reply_q->ephase = exp_phase; 383023ab2a9SKashyap Desai 384023ab2a9SKashyap Desai return num_op_reply; 385023ab2a9SKashyap Desai } 386023ab2a9SKashyap Desai 387824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata) 388824a1566SKashyap Desai { 389824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = privdata; 390824a1566SKashyap Desai struct mpi3mr_ioc *mrioc; 391824a1566SKashyap Desai u16 midx; 392824a1566SKashyap Desai u32 num_admin_replies = 0; 393824a1566SKashyap Desai 394824a1566SKashyap Desai if (!intr_info) 395824a1566SKashyap Desai return IRQ_NONE; 396824a1566SKashyap Desai 397824a1566SKashyap Desai mrioc = intr_info->mrioc; 398824a1566SKashyap Desai 399824a1566SKashyap Desai if (!mrioc->intr_enabled) 400824a1566SKashyap Desai return IRQ_NONE; 401824a1566SKashyap Desai 402824a1566SKashyap Desai midx = intr_info->msix_index; 403824a1566SKashyap Desai 404824a1566SKashyap Desai if (!midx) 405824a1566SKashyap Desai num_admin_replies = mpi3mr_process_admin_reply_q(mrioc); 406824a1566SKashyap Desai 407824a1566SKashyap Desai if (num_admin_replies) 408824a1566SKashyap Desai return IRQ_HANDLED; 409824a1566SKashyap Desai else 410824a1566SKashyap Desai return IRQ_NONE; 411824a1566SKashyap Desai } 412824a1566SKashyap Desai 413824a1566SKashyap Desai static irqreturn_t mpi3mr_isr(int irq, void *privdata) 414824a1566SKashyap Desai { 415824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = privdata; 416824a1566SKashyap Desai int ret; 417824a1566SKashyap Desai 418824a1566SKashyap Desai if (!intr_info) 419824a1566SKashyap Desai return IRQ_NONE; 420824a1566SKashyap Desai 421824a1566SKashyap Desai /* Call primary ISR routine */ 422824a1566SKashyap Desai ret = mpi3mr_isr_primary(irq, privdata); 423824a1566SKashyap Desai 424824a1566SKashyap Desai return ret; 425824a1566SKashyap Desai } 426824a1566SKashyap Desai 427824a1566SKashyap Desai /** 428824a1566SKashyap Desai * mpi3mr_isr_poll - Reply queue polling routine 429824a1566SKashyap Desai * @irq: IRQ 430824a1566SKashyap Desai * @privdata: Interrupt info 431824a1566SKashyap Desai * 432824a1566SKashyap Desai * poll for pending I/O completions in a loop until pending I/Os 433824a1566SKashyap Desai * present or controller queue depth I/Os are processed. 434824a1566SKashyap Desai * 435824a1566SKashyap Desai * Return: IRQ_NONE or IRQ_HANDLED 436824a1566SKashyap Desai */ 437824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata) 438824a1566SKashyap Desai { 439824a1566SKashyap Desai return IRQ_HANDLED; 440824a1566SKashyap Desai } 441824a1566SKashyap Desai 442824a1566SKashyap Desai /** 443824a1566SKashyap Desai * mpi3mr_request_irq - Request IRQ and register ISR 444824a1566SKashyap Desai * @mrioc: Adapter instance reference 445824a1566SKashyap Desai * @index: IRQ vector index 446824a1566SKashyap Desai * 447824a1566SKashyap Desai * Request threaded ISR with primary ISR and secondary 448824a1566SKashyap Desai * 449824a1566SKashyap Desai * Return: 0 on success and non zero on failures. 450824a1566SKashyap Desai */ 451824a1566SKashyap Desai static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index) 452824a1566SKashyap Desai { 453824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 454824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index; 455824a1566SKashyap Desai int retval = 0; 456824a1566SKashyap Desai 457824a1566SKashyap Desai intr_info->mrioc = mrioc; 458824a1566SKashyap Desai intr_info->msix_index = index; 459824a1566SKashyap Desai intr_info->op_reply_q = NULL; 460824a1566SKashyap Desai 461824a1566SKashyap Desai snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d", 462824a1566SKashyap Desai mrioc->driver_name, mrioc->id, index); 463824a1566SKashyap Desai 464824a1566SKashyap Desai retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr, 465824a1566SKashyap Desai mpi3mr_isr_poll, IRQF_SHARED, intr_info->name, intr_info); 466824a1566SKashyap Desai if (retval) { 467824a1566SKashyap Desai ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n", 468824a1566SKashyap Desai intr_info->name, pci_irq_vector(pdev, index)); 469824a1566SKashyap Desai return retval; 470824a1566SKashyap Desai } 471824a1566SKashyap Desai 472824a1566SKashyap Desai return retval; 473824a1566SKashyap Desai } 474824a1566SKashyap Desai 475824a1566SKashyap Desai /** 476824a1566SKashyap Desai * mpi3mr_setup_isr - Setup ISR for the controller 477824a1566SKashyap Desai * @mrioc: Adapter instance reference 478824a1566SKashyap Desai * @setup_one: Request one IRQ or more 479824a1566SKashyap Desai * 480824a1566SKashyap Desai * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR 481824a1566SKashyap Desai * 482824a1566SKashyap Desai * Return: 0 on success and non zero on failures. 483824a1566SKashyap Desai */ 484824a1566SKashyap Desai static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one) 485824a1566SKashyap Desai { 486824a1566SKashyap Desai unsigned int irq_flags = PCI_IRQ_MSIX; 487824a1566SKashyap Desai u16 max_vectors = 0, i; 488824a1566SKashyap Desai int retval = 0; 489824a1566SKashyap Desai struct irq_affinity desc = { .pre_vectors = 1}; 490824a1566SKashyap Desai 491824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 492824a1566SKashyap Desai 493824a1566SKashyap Desai if (setup_one || reset_devices) 494824a1566SKashyap Desai max_vectors = 1; 495824a1566SKashyap Desai else { 496824a1566SKashyap Desai max_vectors = 497824a1566SKashyap Desai min_t(int, mrioc->cpu_count + 1, mrioc->msix_count); 498824a1566SKashyap Desai 499824a1566SKashyap Desai ioc_info(mrioc, 500824a1566SKashyap Desai "MSI-X vectors supported: %d, no of cores: %d,", 501824a1566SKashyap Desai mrioc->msix_count, mrioc->cpu_count); 502824a1566SKashyap Desai ioc_info(mrioc, 503824a1566SKashyap Desai "MSI-x vectors requested: %d\n", max_vectors); 504824a1566SKashyap Desai } 505824a1566SKashyap Desai 506824a1566SKashyap Desai irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES; 507824a1566SKashyap Desai 508c9566231SKashyap Desai mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0; 509824a1566SKashyap Desai i = pci_alloc_irq_vectors_affinity(mrioc->pdev, 510824a1566SKashyap Desai 1, max_vectors, irq_flags, &desc); 511824a1566SKashyap Desai if (i <= 0) { 512824a1566SKashyap Desai ioc_err(mrioc, "Cannot alloc irq vectors\n"); 513824a1566SKashyap Desai goto out_failed; 514824a1566SKashyap Desai } 515824a1566SKashyap Desai if (i != max_vectors) { 516824a1566SKashyap Desai ioc_info(mrioc, 517824a1566SKashyap Desai "allocated vectors (%d) are less than configured (%d)\n", 518824a1566SKashyap Desai i, max_vectors); 519c9566231SKashyap Desai /* 520c9566231SKashyap Desai * If only one MSI-x is allocated, then MSI-x 0 will be shared 521c9566231SKashyap Desai * between Admin queue and operational queue 522c9566231SKashyap Desai */ 523c9566231SKashyap Desai if (i == 1) 524c9566231SKashyap Desai mrioc->op_reply_q_offset = 0; 525824a1566SKashyap Desai 526824a1566SKashyap Desai max_vectors = i; 527824a1566SKashyap Desai } 528824a1566SKashyap Desai mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info) * max_vectors, 529824a1566SKashyap Desai GFP_KERNEL); 530824a1566SKashyap Desai if (!mrioc->intr_info) { 531824a1566SKashyap Desai retval = -1; 532824a1566SKashyap Desai pci_free_irq_vectors(mrioc->pdev); 533824a1566SKashyap Desai goto out_failed; 534824a1566SKashyap Desai } 535824a1566SKashyap Desai for (i = 0; i < max_vectors; i++) { 536824a1566SKashyap Desai retval = mpi3mr_request_irq(mrioc, i); 537824a1566SKashyap Desai if (retval) { 538824a1566SKashyap Desai mrioc->intr_info_count = i; 539824a1566SKashyap Desai goto out_failed; 540824a1566SKashyap Desai } 541824a1566SKashyap Desai } 542824a1566SKashyap Desai mrioc->intr_info_count = max_vectors; 543824a1566SKashyap Desai mpi3mr_ioc_enable_intr(mrioc); 544824a1566SKashyap Desai return retval; 545824a1566SKashyap Desai out_failed: 546824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 547824a1566SKashyap Desai 548824a1566SKashyap Desai return retval; 549824a1566SKashyap Desai } 550824a1566SKashyap Desai 551824a1566SKashyap Desai static const struct { 552824a1566SKashyap Desai enum mpi3mr_iocstate value; 553824a1566SKashyap Desai char *name; 554824a1566SKashyap Desai } mrioc_states[] = { 555824a1566SKashyap Desai { MRIOC_STATE_READY, "ready" }, 556824a1566SKashyap Desai { MRIOC_STATE_FAULT, "fault" }, 557824a1566SKashyap Desai { MRIOC_STATE_RESET, "reset" }, 558824a1566SKashyap Desai { MRIOC_STATE_BECOMING_READY, "becoming ready" }, 559824a1566SKashyap Desai { MRIOC_STATE_RESET_REQUESTED, "reset requested" }, 560824a1566SKashyap Desai { MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" }, 561824a1566SKashyap Desai }; 562824a1566SKashyap Desai 563824a1566SKashyap Desai static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state) 564824a1566SKashyap Desai { 565824a1566SKashyap Desai int i; 566824a1566SKashyap Desai char *name = NULL; 567824a1566SKashyap Desai 568824a1566SKashyap Desai for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) { 569824a1566SKashyap Desai if (mrioc_states[i].value == mrioc_state) { 570824a1566SKashyap Desai name = mrioc_states[i].name; 571824a1566SKashyap Desai break; 572824a1566SKashyap Desai } 573824a1566SKashyap Desai } 574824a1566SKashyap Desai return name; 575824a1566SKashyap Desai } 576824a1566SKashyap Desai 577824a1566SKashyap Desai /** 578824a1566SKashyap Desai * mpi3mr_print_fault_info - Display fault information 579824a1566SKashyap Desai * @mrioc: Adapter instance reference 580824a1566SKashyap Desai * 581824a1566SKashyap Desai * Display the controller fault information if there is a 582824a1566SKashyap Desai * controller fault. 583824a1566SKashyap Desai * 584824a1566SKashyap Desai * Return: Nothing. 585824a1566SKashyap Desai */ 586824a1566SKashyap Desai static void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc) 587824a1566SKashyap Desai { 588824a1566SKashyap Desai u32 ioc_status, code, code1, code2, code3; 589824a1566SKashyap Desai 590824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 591824a1566SKashyap Desai 592824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { 593824a1566SKashyap Desai code = readl(&mrioc->sysif_regs->fault); 594824a1566SKashyap Desai code1 = readl(&mrioc->sysif_regs->fault_info[0]); 595824a1566SKashyap Desai code2 = readl(&mrioc->sysif_regs->fault_info[1]); 596824a1566SKashyap Desai code3 = readl(&mrioc->sysif_regs->fault_info[2]); 597824a1566SKashyap Desai 598824a1566SKashyap Desai ioc_info(mrioc, 599824a1566SKashyap Desai "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n", 600824a1566SKashyap Desai code, code1, code2, code3); 601824a1566SKashyap Desai } 602824a1566SKashyap Desai } 603824a1566SKashyap Desai 604824a1566SKashyap Desai /** 605824a1566SKashyap Desai * mpi3mr_get_iocstate - Get IOC State 606824a1566SKashyap Desai * @mrioc: Adapter instance reference 607824a1566SKashyap Desai * 608824a1566SKashyap Desai * Return a proper IOC state enum based on the IOC status and 609824a1566SKashyap Desai * IOC configuration and unrcoverable state of the controller. 610824a1566SKashyap Desai * 611824a1566SKashyap Desai * Return: Current IOC state. 612824a1566SKashyap Desai */ 613824a1566SKashyap Desai enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc) 614824a1566SKashyap Desai { 615824a1566SKashyap Desai u32 ioc_status, ioc_config; 616824a1566SKashyap Desai u8 ready, enabled; 617824a1566SKashyap Desai 618824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 619824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 620824a1566SKashyap Desai 621824a1566SKashyap Desai if (mrioc->unrecoverable) 622824a1566SKashyap Desai return MRIOC_STATE_UNRECOVERABLE; 623824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) 624824a1566SKashyap Desai return MRIOC_STATE_FAULT; 625824a1566SKashyap Desai 626824a1566SKashyap Desai ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY); 627824a1566SKashyap Desai enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC); 628824a1566SKashyap Desai 629824a1566SKashyap Desai if (ready && enabled) 630824a1566SKashyap Desai return MRIOC_STATE_READY; 631824a1566SKashyap Desai if ((!ready) && (!enabled)) 632824a1566SKashyap Desai return MRIOC_STATE_RESET; 633824a1566SKashyap Desai if ((!ready) && (enabled)) 634824a1566SKashyap Desai return MRIOC_STATE_BECOMING_READY; 635824a1566SKashyap Desai 636824a1566SKashyap Desai return MRIOC_STATE_RESET_REQUESTED; 637824a1566SKashyap Desai } 638824a1566SKashyap Desai 639824a1566SKashyap Desai /** 640824a1566SKashyap Desai * mpi3mr_clear_reset_history - clear reset history 641824a1566SKashyap Desai * @mrioc: Adapter instance reference 642824a1566SKashyap Desai * 643824a1566SKashyap Desai * Write the reset history bit in IOC status to clear the bit, 644824a1566SKashyap Desai * if it is already set. 645824a1566SKashyap Desai * 646824a1566SKashyap Desai * Return: Nothing. 647824a1566SKashyap Desai */ 648824a1566SKashyap Desai static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc) 649824a1566SKashyap Desai { 650824a1566SKashyap Desai u32 ioc_status; 651824a1566SKashyap Desai 652824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 653824a1566SKashyap Desai if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) 654824a1566SKashyap Desai writel(ioc_status, &mrioc->sysif_regs->ioc_status); 655824a1566SKashyap Desai } 656824a1566SKashyap Desai 657824a1566SKashyap Desai /** 658824a1566SKashyap Desai * mpi3mr_issue_and_process_mur - Message unit Reset handler 659824a1566SKashyap Desai * @mrioc: Adapter instance reference 660824a1566SKashyap Desai * @reset_reason: Reset reason code 661824a1566SKashyap Desai * 662824a1566SKashyap Desai * Issue Message unit Reset to the controller and wait for it to 663824a1566SKashyap Desai * be complete. 664824a1566SKashyap Desai * 665824a1566SKashyap Desai * Return: 0 on success, -1 on failure. 666824a1566SKashyap Desai */ 667824a1566SKashyap Desai static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc, 668824a1566SKashyap Desai u32 reset_reason) 669824a1566SKashyap Desai { 670824a1566SKashyap Desai u32 ioc_config, timeout, ioc_status; 671824a1566SKashyap Desai int retval = -1; 672824a1566SKashyap Desai 673824a1566SKashyap Desai ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n"); 674824a1566SKashyap Desai if (mrioc->unrecoverable) { 675824a1566SKashyap Desai ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n"); 676824a1566SKashyap Desai return retval; 677824a1566SKashyap Desai } 678824a1566SKashyap Desai mpi3mr_clear_reset_history(mrioc); 679824a1566SKashyap Desai writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); 680824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 681824a1566SKashyap Desai ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; 682824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 683824a1566SKashyap Desai 684824a1566SKashyap Desai timeout = mrioc->ready_timeout * 10; 685824a1566SKashyap Desai do { 686824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 687824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) { 688824a1566SKashyap Desai mpi3mr_clear_reset_history(mrioc); 689824a1566SKashyap Desai ioc_config = 690824a1566SKashyap Desai readl(&mrioc->sysif_regs->ioc_configuration); 691824a1566SKashyap Desai if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || 692824a1566SKashyap Desai (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) || 693824a1566SKashyap Desai (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) { 694824a1566SKashyap Desai retval = 0; 695824a1566SKashyap Desai break; 696824a1566SKashyap Desai } 697824a1566SKashyap Desai } 698824a1566SKashyap Desai msleep(100); 699824a1566SKashyap Desai } while (--timeout); 700824a1566SKashyap Desai 701824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 702824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 703824a1566SKashyap Desai 704824a1566SKashyap Desai ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n", 705824a1566SKashyap Desai (!retval) ? "successful" : "failed", ioc_status, ioc_config); 706824a1566SKashyap Desai return retval; 707824a1566SKashyap Desai } 708824a1566SKashyap Desai 709824a1566SKashyap Desai /** 710824a1566SKashyap Desai * mpi3mr_bring_ioc_ready - Bring controller to ready state 711824a1566SKashyap Desai * @mrioc: Adapter instance reference 712824a1566SKashyap Desai * 713824a1566SKashyap Desai * Set Enable IOC bit in IOC configuration register and wait for 714824a1566SKashyap Desai * the controller to become ready. 715824a1566SKashyap Desai * 716824a1566SKashyap Desai * Return: 0 on success, -1 on failure. 717824a1566SKashyap Desai */ 718824a1566SKashyap Desai static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) 719824a1566SKashyap Desai { 720824a1566SKashyap Desai u32 ioc_config, timeout; 721824a1566SKashyap Desai enum mpi3mr_iocstate current_state; 722824a1566SKashyap Desai 723824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 724824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; 725824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 726824a1566SKashyap Desai 727824a1566SKashyap Desai timeout = mrioc->ready_timeout * 10; 728824a1566SKashyap Desai do { 729824a1566SKashyap Desai current_state = mpi3mr_get_iocstate(mrioc); 730824a1566SKashyap Desai if (current_state == MRIOC_STATE_READY) 731824a1566SKashyap Desai return 0; 732824a1566SKashyap Desai msleep(100); 733824a1566SKashyap Desai } while (--timeout); 734824a1566SKashyap Desai 735824a1566SKashyap Desai return -1; 736824a1566SKashyap Desai } 737824a1566SKashyap Desai 738824a1566SKashyap Desai /** 739824a1566SKashyap Desai * mpi3mr_set_diagsave - Set diag save bit for snapdump 740824a1566SKashyap Desai * @mrioc: Adapter reference 741824a1566SKashyap Desai * 742824a1566SKashyap Desai * Set diag save bit in IOC configuration register to enable 743824a1566SKashyap Desai * snapdump. 744824a1566SKashyap Desai * 745824a1566SKashyap Desai * Return: Nothing. 746824a1566SKashyap Desai */ 747824a1566SKashyap Desai static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc) 748824a1566SKashyap Desai { 749824a1566SKashyap Desai u32 ioc_config; 750824a1566SKashyap Desai 751824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 752824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE; 753824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 754824a1566SKashyap Desai } 755824a1566SKashyap Desai 756824a1566SKashyap Desai /** 757824a1566SKashyap Desai * mpi3mr_issue_reset - Issue reset to the controller 758824a1566SKashyap Desai * @mrioc: Adapter reference 759824a1566SKashyap Desai * @reset_type: Reset type 760824a1566SKashyap Desai * @reset_reason: Reset reason code 761824a1566SKashyap Desai * 762824a1566SKashyap Desai * TBD 763824a1566SKashyap Desai * 764824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 765824a1566SKashyap Desai */ 766824a1566SKashyap Desai static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, 767824a1566SKashyap Desai u32 reset_reason) 768824a1566SKashyap Desai { 769824a1566SKashyap Desai return 0; 770824a1566SKashyap Desai } 771824a1566SKashyap Desai 772824a1566SKashyap Desai /** 773824a1566SKashyap Desai * mpi3mr_admin_request_post - Post request to admin queue 774824a1566SKashyap Desai * @mrioc: Adapter reference 775824a1566SKashyap Desai * @admin_req: MPI3 request 776824a1566SKashyap Desai * @admin_req_sz: Request size 777824a1566SKashyap Desai * @ignore_reset: Ignore reset in process 778824a1566SKashyap Desai * 779824a1566SKashyap Desai * Post the MPI3 request into admin request queue and 780824a1566SKashyap Desai * inform the controller, if the queue is full return 781824a1566SKashyap Desai * appropriate error. 782824a1566SKashyap Desai * 783824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 784824a1566SKashyap Desai */ 785824a1566SKashyap Desai int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req, 786824a1566SKashyap Desai u16 admin_req_sz, u8 ignore_reset) 787824a1566SKashyap Desai { 788824a1566SKashyap Desai u16 areq_pi = 0, areq_ci = 0, max_entries = 0; 789824a1566SKashyap Desai int retval = 0; 790824a1566SKashyap Desai unsigned long flags; 791824a1566SKashyap Desai u8 *areq_entry; 792824a1566SKashyap Desai 793824a1566SKashyap Desai if (mrioc->unrecoverable) { 794824a1566SKashyap Desai ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__); 795824a1566SKashyap Desai return -EFAULT; 796824a1566SKashyap Desai } 797824a1566SKashyap Desai 798824a1566SKashyap Desai spin_lock_irqsave(&mrioc->admin_req_lock, flags); 799824a1566SKashyap Desai areq_pi = mrioc->admin_req_pi; 800824a1566SKashyap Desai areq_ci = mrioc->admin_req_ci; 801824a1566SKashyap Desai max_entries = mrioc->num_admin_req; 802824a1566SKashyap Desai if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) && 803824a1566SKashyap Desai (areq_pi == (max_entries - 1)))) { 804824a1566SKashyap Desai ioc_err(mrioc, "AdminReqQ full condition detected\n"); 805824a1566SKashyap Desai retval = -EAGAIN; 806824a1566SKashyap Desai goto out; 807824a1566SKashyap Desai } 808824a1566SKashyap Desai if (!ignore_reset && mrioc->reset_in_progress) { 809824a1566SKashyap Desai ioc_err(mrioc, "AdminReqQ submit reset in progress\n"); 810824a1566SKashyap Desai retval = -EAGAIN; 811824a1566SKashyap Desai goto out; 812824a1566SKashyap Desai } 813824a1566SKashyap Desai areq_entry = (u8 *)mrioc->admin_req_base + 814824a1566SKashyap Desai (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ); 815824a1566SKashyap Desai memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ); 816824a1566SKashyap Desai memcpy(areq_entry, (u8 *)admin_req, admin_req_sz); 817824a1566SKashyap Desai 818824a1566SKashyap Desai if (++areq_pi == max_entries) 819824a1566SKashyap Desai areq_pi = 0; 820824a1566SKashyap Desai mrioc->admin_req_pi = areq_pi; 821824a1566SKashyap Desai 822824a1566SKashyap Desai writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi); 823824a1566SKashyap Desai 824824a1566SKashyap Desai out: 825824a1566SKashyap Desai spin_unlock_irqrestore(&mrioc->admin_req_lock, flags); 826824a1566SKashyap Desai 827824a1566SKashyap Desai return retval; 828824a1566SKashyap Desai } 829824a1566SKashyap Desai 830824a1566SKashyap Desai /** 831c9566231SKashyap Desai * mpi3mr_free_op_req_q_segments - free request memory segments 832c9566231SKashyap Desai * @mrioc: Adapter instance reference 833c9566231SKashyap Desai * @q_idx: operational request queue index 834c9566231SKashyap Desai * 835c9566231SKashyap Desai * Free memory segments allocated for operational request queue 836c9566231SKashyap Desai * 837c9566231SKashyap Desai * Return: Nothing. 838c9566231SKashyap Desai */ 839c9566231SKashyap Desai static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) 840c9566231SKashyap Desai { 841c9566231SKashyap Desai u16 j; 842c9566231SKashyap Desai int size; 843c9566231SKashyap Desai struct segments *segments; 844c9566231SKashyap Desai 845c9566231SKashyap Desai segments = mrioc->req_qinfo[q_idx].q_segments; 846c9566231SKashyap Desai if (!segments) 847c9566231SKashyap Desai return; 848c9566231SKashyap Desai 849c9566231SKashyap Desai if (mrioc->enable_segqueue) { 850c9566231SKashyap Desai size = MPI3MR_OP_REQ_Q_SEG_SIZE; 851c9566231SKashyap Desai if (mrioc->req_qinfo[q_idx].q_segment_list) { 852c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 853c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, 854c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segment_list, 855c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segment_list_dma); 856c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL; 857c9566231SKashyap Desai } 858c9566231SKashyap Desai } else 859c9566231SKashyap Desai size = mrioc->req_qinfo[q_idx].num_requests * 860c9566231SKashyap Desai mrioc->facts.op_req_sz; 861c9566231SKashyap Desai 862c9566231SKashyap Desai for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) { 863c9566231SKashyap Desai if (!segments[j].segment) 864c9566231SKashyap Desai continue; 865c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 866c9566231SKashyap Desai size, segments[j].segment, segments[j].segment_dma); 867c9566231SKashyap Desai segments[j].segment = NULL; 868c9566231SKashyap Desai } 869c9566231SKashyap Desai kfree(mrioc->req_qinfo[q_idx].q_segments); 870c9566231SKashyap Desai mrioc->req_qinfo[q_idx].q_segments = NULL; 871c9566231SKashyap Desai mrioc->req_qinfo[q_idx].qid = 0; 872c9566231SKashyap Desai } 873c9566231SKashyap Desai 874c9566231SKashyap Desai /** 875c9566231SKashyap Desai * mpi3mr_free_op_reply_q_segments - free reply memory segments 876c9566231SKashyap Desai * @mrioc: Adapter instance reference 877c9566231SKashyap Desai * @q_idx: operational reply queue index 878c9566231SKashyap Desai * 879c9566231SKashyap Desai * Free memory segments allocated for operational reply queue 880c9566231SKashyap Desai * 881c9566231SKashyap Desai * Return: Nothing. 882c9566231SKashyap Desai */ 883c9566231SKashyap Desai static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) 884c9566231SKashyap Desai { 885c9566231SKashyap Desai u16 j; 886c9566231SKashyap Desai int size; 887c9566231SKashyap Desai struct segments *segments; 888c9566231SKashyap Desai 889c9566231SKashyap Desai segments = mrioc->op_reply_qinfo[q_idx].q_segments; 890c9566231SKashyap Desai if (!segments) 891c9566231SKashyap Desai return; 892c9566231SKashyap Desai 893c9566231SKashyap Desai if (mrioc->enable_segqueue) { 894c9566231SKashyap Desai size = MPI3MR_OP_REP_Q_SEG_SIZE; 895c9566231SKashyap Desai if (mrioc->op_reply_qinfo[q_idx].q_segment_list) { 896c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 897c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, 898c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list, 899c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list_dma); 900c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL; 901c9566231SKashyap Desai } 902c9566231SKashyap Desai } else 903c9566231SKashyap Desai size = mrioc->op_reply_qinfo[q_idx].segment_qd * 904c9566231SKashyap Desai mrioc->op_reply_desc_sz; 905c9566231SKashyap Desai 906c9566231SKashyap Desai for (j = 0; j < mrioc->op_reply_qinfo[q_idx].num_segments; j++) { 907c9566231SKashyap Desai if (!segments[j].segment) 908c9566231SKashyap Desai continue; 909c9566231SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, 910c9566231SKashyap Desai size, segments[j].segment, segments[j].segment_dma); 911c9566231SKashyap Desai segments[j].segment = NULL; 912c9566231SKashyap Desai } 913c9566231SKashyap Desai 914c9566231SKashyap Desai kfree(mrioc->op_reply_qinfo[q_idx].q_segments); 915c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].q_segments = NULL; 916c9566231SKashyap Desai mrioc->op_reply_qinfo[q_idx].qid = 0; 917c9566231SKashyap Desai } 918c9566231SKashyap Desai 919c9566231SKashyap Desai /** 920c9566231SKashyap Desai * mpi3mr_delete_op_reply_q - delete operational reply queue 921c9566231SKashyap Desai * @mrioc: Adapter instance reference 922c9566231SKashyap Desai * @qidx: operational reply queue index 923c9566231SKashyap Desai * 924c9566231SKashyap Desai * Delete operatinal reply queue by issuing MPI request 925c9566231SKashyap Desai * through admin queue. 926c9566231SKashyap Desai * 927c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 928c9566231SKashyap Desai */ 929c9566231SKashyap Desai static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) 930c9566231SKashyap Desai { 931c9566231SKashyap Desai struct mpi3_delete_reply_queue_request delq_req; 932c9566231SKashyap Desai int retval = 0; 933c9566231SKashyap Desai u16 reply_qid = 0, midx; 934c9566231SKashyap Desai 935c9566231SKashyap Desai reply_qid = mrioc->op_reply_qinfo[qidx].qid; 936c9566231SKashyap Desai 937c9566231SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset); 938c9566231SKashyap Desai 939c9566231SKashyap Desai if (!reply_qid) { 940c9566231SKashyap Desai retval = -1; 941c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: called with invalid ReqQID\n"); 942c9566231SKashyap Desai goto out; 943c9566231SKashyap Desai } 944c9566231SKashyap Desai 945c9566231SKashyap Desai memset(&delq_req, 0, sizeof(delq_req)); 946c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 947c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 948c9566231SKashyap Desai retval = -1; 949c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: Init command is in use\n"); 950c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 951c9566231SKashyap Desai goto out; 952c9566231SKashyap Desai } 953c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 954c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 955c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 956c9566231SKashyap Desai delq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 957c9566231SKashyap Desai delq_req.function = MPI3_FUNCTION_DELETE_REPLY_QUEUE; 958c9566231SKashyap Desai delq_req.queue_id = cpu_to_le16(reply_qid); 959c9566231SKashyap Desai 960c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 961c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &delq_req, sizeof(delq_req), 962c9566231SKashyap Desai 1); 963c9566231SKashyap Desai if (retval) { 964c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: Admin Post failed\n"); 965c9566231SKashyap Desai goto out_unlock; 966c9566231SKashyap Desai } 967c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 968c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 969c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 970c9566231SKashyap Desai ioc_err(mrioc, "Issue DelRepQ: command timed out\n"); 971c9566231SKashyap Desai mpi3mr_set_diagsave(mrioc); 972c9566231SKashyap Desai mpi3mr_issue_reset(mrioc, 973c9566231SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 974c9566231SKashyap Desai MPI3MR_RESET_FROM_DELREPQ_TIMEOUT); 975c9566231SKashyap Desai mrioc->unrecoverable = 1; 976c9566231SKashyap Desai 977c9566231SKashyap Desai retval = -1; 978c9566231SKashyap Desai goto out_unlock; 979c9566231SKashyap Desai } 980c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 981c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 982c9566231SKashyap Desai ioc_err(mrioc, 983c9566231SKashyap Desai "Issue DelRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 984c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 985c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 986c9566231SKashyap Desai retval = -1; 987c9566231SKashyap Desai goto out_unlock; 988c9566231SKashyap Desai } 989c9566231SKashyap Desai mrioc->intr_info[midx].op_reply_q = NULL; 990c9566231SKashyap Desai 991c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, qidx); 992c9566231SKashyap Desai out_unlock: 993c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 994c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 995c9566231SKashyap Desai out: 996c9566231SKashyap Desai 997c9566231SKashyap Desai return retval; 998c9566231SKashyap Desai } 999c9566231SKashyap Desai 1000c9566231SKashyap Desai /** 1001c9566231SKashyap Desai * mpi3mr_alloc_op_reply_q_segments -Alloc segmented reply pool 1002c9566231SKashyap Desai * @mrioc: Adapter instance reference 1003c9566231SKashyap Desai * @qidx: request queue index 1004c9566231SKashyap Desai * 1005c9566231SKashyap Desai * Allocate segmented memory pools for operational reply 1006c9566231SKashyap Desai * queue. 1007c9566231SKashyap Desai * 1008c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1009c9566231SKashyap Desai */ 1010c9566231SKashyap Desai static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) 1011c9566231SKashyap Desai { 1012c9566231SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 1013c9566231SKashyap Desai int i, size; 1014c9566231SKashyap Desai u64 *q_segment_list_entry = NULL; 1015c9566231SKashyap Desai struct segments *segments; 1016c9566231SKashyap Desai 1017c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1018c9566231SKashyap Desai op_reply_q->segment_qd = 1019c9566231SKashyap Desai MPI3MR_OP_REP_Q_SEG_SIZE / mrioc->op_reply_desc_sz; 1020c9566231SKashyap Desai 1021c9566231SKashyap Desai size = MPI3MR_OP_REP_Q_SEG_SIZE; 1022c9566231SKashyap Desai 1023c9566231SKashyap Desai op_reply_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev, 1024c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, &op_reply_q->q_segment_list_dma, 1025c9566231SKashyap Desai GFP_KERNEL); 1026c9566231SKashyap Desai if (!op_reply_q->q_segment_list) 1027c9566231SKashyap Desai return -ENOMEM; 1028c9566231SKashyap Desai q_segment_list_entry = (u64 *)op_reply_q->q_segment_list; 1029c9566231SKashyap Desai } else { 1030c9566231SKashyap Desai op_reply_q->segment_qd = op_reply_q->num_replies; 1031c9566231SKashyap Desai size = op_reply_q->num_replies * mrioc->op_reply_desc_sz; 1032c9566231SKashyap Desai } 1033c9566231SKashyap Desai 1034c9566231SKashyap Desai op_reply_q->num_segments = DIV_ROUND_UP(op_reply_q->num_replies, 1035c9566231SKashyap Desai op_reply_q->segment_qd); 1036c9566231SKashyap Desai 1037c9566231SKashyap Desai op_reply_q->q_segments = kcalloc(op_reply_q->num_segments, 1038c9566231SKashyap Desai sizeof(struct segments), GFP_KERNEL); 1039c9566231SKashyap Desai if (!op_reply_q->q_segments) 1040c9566231SKashyap Desai return -ENOMEM; 1041c9566231SKashyap Desai 1042c9566231SKashyap Desai segments = op_reply_q->q_segments; 1043c9566231SKashyap Desai for (i = 0; i < op_reply_q->num_segments; i++) { 1044c9566231SKashyap Desai segments[i].segment = 1045c9566231SKashyap Desai dma_alloc_coherent(&mrioc->pdev->dev, 1046c9566231SKashyap Desai size, &segments[i].segment_dma, GFP_KERNEL); 1047c9566231SKashyap Desai if (!segments[i].segment) 1048c9566231SKashyap Desai return -ENOMEM; 1049c9566231SKashyap Desai if (mrioc->enable_segqueue) 1050c9566231SKashyap Desai q_segment_list_entry[i] = 1051c9566231SKashyap Desai (unsigned long)segments[i].segment_dma; 1052c9566231SKashyap Desai } 1053c9566231SKashyap Desai 1054c9566231SKashyap Desai return 0; 1055c9566231SKashyap Desai } 1056c9566231SKashyap Desai 1057c9566231SKashyap Desai /** 1058c9566231SKashyap Desai * mpi3mr_alloc_op_req_q_segments - Alloc segmented req pool. 1059c9566231SKashyap Desai * @mrioc: Adapter instance reference 1060c9566231SKashyap Desai * @qidx: request queue index 1061c9566231SKashyap Desai * 1062c9566231SKashyap Desai * Allocate segmented memory pools for operational request 1063c9566231SKashyap Desai * queue. 1064c9566231SKashyap Desai * 1065c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1066c9566231SKashyap Desai */ 1067c9566231SKashyap Desai static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) 1068c9566231SKashyap Desai { 1069c9566231SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx; 1070c9566231SKashyap Desai int i, size; 1071c9566231SKashyap Desai u64 *q_segment_list_entry = NULL; 1072c9566231SKashyap Desai struct segments *segments; 1073c9566231SKashyap Desai 1074c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1075c9566231SKashyap Desai op_req_q->segment_qd = 1076c9566231SKashyap Desai MPI3MR_OP_REQ_Q_SEG_SIZE / mrioc->facts.op_req_sz; 1077c9566231SKashyap Desai 1078c9566231SKashyap Desai size = MPI3MR_OP_REQ_Q_SEG_SIZE; 1079c9566231SKashyap Desai 1080c9566231SKashyap Desai op_req_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev, 1081c9566231SKashyap Desai MPI3MR_MAX_SEG_LIST_SIZE, &op_req_q->q_segment_list_dma, 1082c9566231SKashyap Desai GFP_KERNEL); 1083c9566231SKashyap Desai if (!op_req_q->q_segment_list) 1084c9566231SKashyap Desai return -ENOMEM; 1085c9566231SKashyap Desai q_segment_list_entry = (u64 *)op_req_q->q_segment_list; 1086c9566231SKashyap Desai 1087c9566231SKashyap Desai } else { 1088c9566231SKashyap Desai op_req_q->segment_qd = op_req_q->num_requests; 1089c9566231SKashyap Desai size = op_req_q->num_requests * mrioc->facts.op_req_sz; 1090c9566231SKashyap Desai } 1091c9566231SKashyap Desai 1092c9566231SKashyap Desai op_req_q->num_segments = DIV_ROUND_UP(op_req_q->num_requests, 1093c9566231SKashyap Desai op_req_q->segment_qd); 1094c9566231SKashyap Desai 1095c9566231SKashyap Desai op_req_q->q_segments = kcalloc(op_req_q->num_segments, 1096c9566231SKashyap Desai sizeof(struct segments), GFP_KERNEL); 1097c9566231SKashyap Desai if (!op_req_q->q_segments) 1098c9566231SKashyap Desai return -ENOMEM; 1099c9566231SKashyap Desai 1100c9566231SKashyap Desai segments = op_req_q->q_segments; 1101c9566231SKashyap Desai for (i = 0; i < op_req_q->num_segments; i++) { 1102c9566231SKashyap Desai segments[i].segment = 1103c9566231SKashyap Desai dma_alloc_coherent(&mrioc->pdev->dev, 1104c9566231SKashyap Desai size, &segments[i].segment_dma, GFP_KERNEL); 1105c9566231SKashyap Desai if (!segments[i].segment) 1106c9566231SKashyap Desai return -ENOMEM; 1107c9566231SKashyap Desai if (mrioc->enable_segqueue) 1108c9566231SKashyap Desai q_segment_list_entry[i] = 1109c9566231SKashyap Desai (unsigned long)segments[i].segment_dma; 1110c9566231SKashyap Desai } 1111c9566231SKashyap Desai 1112c9566231SKashyap Desai return 0; 1113c9566231SKashyap Desai } 1114c9566231SKashyap Desai 1115c9566231SKashyap Desai /** 1116c9566231SKashyap Desai * mpi3mr_create_op_reply_q - create operational reply queue 1117c9566231SKashyap Desai * @mrioc: Adapter instance reference 1118c9566231SKashyap Desai * @qidx: operational reply queue index 1119c9566231SKashyap Desai * 1120c9566231SKashyap Desai * Create operatinal reply queue by issuing MPI request 1121c9566231SKashyap Desai * through admin queue. 1122c9566231SKashyap Desai * 1123c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1124c9566231SKashyap Desai */ 1125c9566231SKashyap Desai static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) 1126c9566231SKashyap Desai { 1127c9566231SKashyap Desai struct mpi3_create_reply_queue_request create_req; 1128c9566231SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 1129c9566231SKashyap Desai int retval = 0; 1130c9566231SKashyap Desai u16 reply_qid = 0, midx; 1131c9566231SKashyap Desai 1132c9566231SKashyap Desai reply_qid = op_reply_q->qid; 1133c9566231SKashyap Desai 1134c9566231SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset); 1135c9566231SKashyap Desai 1136c9566231SKashyap Desai if (reply_qid) { 1137c9566231SKashyap Desai retval = -1; 1138c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: called for duplicate qid %d\n", 1139c9566231SKashyap Desai reply_qid); 1140c9566231SKashyap Desai 1141c9566231SKashyap Desai return retval; 1142c9566231SKashyap Desai } 1143c9566231SKashyap Desai 1144c9566231SKashyap Desai reply_qid = qidx + 1; 1145c9566231SKashyap Desai op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; 1146c9566231SKashyap Desai op_reply_q->ci = 0; 1147c9566231SKashyap Desai op_reply_q->ephase = 1; 1148c9566231SKashyap Desai 1149c9566231SKashyap Desai if (!op_reply_q->q_segments) { 1150c9566231SKashyap Desai retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx); 1151c9566231SKashyap Desai if (retval) { 1152c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, qidx); 1153c9566231SKashyap Desai goto out; 1154c9566231SKashyap Desai } 1155c9566231SKashyap Desai } 1156c9566231SKashyap Desai 1157c9566231SKashyap Desai memset(&create_req, 0, sizeof(create_req)); 1158c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1159c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1160c9566231SKashyap Desai retval = -1; 1161c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: Init command is in use\n"); 1162c9566231SKashyap Desai goto out; 1163c9566231SKashyap Desai } 1164c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1165c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1166c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 1167c9566231SKashyap Desai create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1168c9566231SKashyap Desai create_req.function = MPI3_FUNCTION_CREATE_REPLY_QUEUE; 1169c9566231SKashyap Desai create_req.queue_id = cpu_to_le16(reply_qid); 1170c9566231SKashyap Desai create_req.flags = MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE; 1171c9566231SKashyap Desai create_req.msix_index = cpu_to_le16(mrioc->intr_info[midx].msix_index); 1172c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1173c9566231SKashyap Desai create_req.flags |= 1174c9566231SKashyap Desai MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED; 1175c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1176c9566231SKashyap Desai op_reply_q->q_segment_list_dma); 1177c9566231SKashyap Desai } else 1178c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1179c9566231SKashyap Desai op_reply_q->q_segments[0].segment_dma); 1180c9566231SKashyap Desai 1181c9566231SKashyap Desai create_req.size = cpu_to_le16(op_reply_q->num_replies); 1182c9566231SKashyap Desai 1183c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 1184c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &create_req, 1185c9566231SKashyap Desai sizeof(create_req), 1); 1186c9566231SKashyap Desai if (retval) { 1187c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: Admin Post failed\n"); 1188c9566231SKashyap Desai goto out_unlock; 1189c9566231SKashyap Desai } 1190c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1191c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1192c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1193c9566231SKashyap Desai ioc_err(mrioc, "CreateRepQ: command timed out\n"); 1194c9566231SKashyap Desai mpi3mr_set_diagsave(mrioc); 1195c9566231SKashyap Desai mpi3mr_issue_reset(mrioc, 1196c9566231SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 1197c9566231SKashyap Desai MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT); 1198c9566231SKashyap Desai mrioc->unrecoverable = 1; 1199c9566231SKashyap Desai retval = -1; 1200c9566231SKashyap Desai goto out_unlock; 1201c9566231SKashyap Desai } 1202c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1203c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1204c9566231SKashyap Desai ioc_err(mrioc, 1205c9566231SKashyap Desai "CreateRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1206c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1207c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 1208c9566231SKashyap Desai retval = -1; 1209c9566231SKashyap Desai goto out_unlock; 1210c9566231SKashyap Desai } 1211c9566231SKashyap Desai op_reply_q->qid = reply_qid; 1212c9566231SKashyap Desai mrioc->intr_info[midx].op_reply_q = op_reply_q; 1213c9566231SKashyap Desai 1214c9566231SKashyap Desai out_unlock: 1215c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 1216c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1217c9566231SKashyap Desai out: 1218c9566231SKashyap Desai 1219c9566231SKashyap Desai return retval; 1220c9566231SKashyap Desai } 1221c9566231SKashyap Desai 1222c9566231SKashyap Desai /** 1223c9566231SKashyap Desai * mpi3mr_create_op_req_q - create operational request queue 1224c9566231SKashyap Desai * @mrioc: Adapter instance reference 1225c9566231SKashyap Desai * @idx: operational request queue index 1226c9566231SKashyap Desai * @reply_qid: Reply queue ID 1227c9566231SKashyap Desai * 1228c9566231SKashyap Desai * Create operatinal request queue by issuing MPI request 1229c9566231SKashyap Desai * through admin queue. 1230c9566231SKashyap Desai * 1231c9566231SKashyap Desai * Return: 0 on success, non-zero on failure. 1232c9566231SKashyap Desai */ 1233c9566231SKashyap Desai static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx, 1234c9566231SKashyap Desai u16 reply_qid) 1235c9566231SKashyap Desai { 1236c9566231SKashyap Desai struct mpi3_create_request_queue_request create_req; 1237c9566231SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + idx; 1238c9566231SKashyap Desai int retval = 0; 1239c9566231SKashyap Desai u16 req_qid = 0; 1240c9566231SKashyap Desai 1241c9566231SKashyap Desai req_qid = op_req_q->qid; 1242c9566231SKashyap Desai 1243c9566231SKashyap Desai if (req_qid) { 1244c9566231SKashyap Desai retval = -1; 1245c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: called for duplicate qid %d\n", 1246c9566231SKashyap Desai req_qid); 1247c9566231SKashyap Desai 1248c9566231SKashyap Desai return retval; 1249c9566231SKashyap Desai } 1250c9566231SKashyap Desai req_qid = idx + 1; 1251c9566231SKashyap Desai 1252c9566231SKashyap Desai op_req_q->num_requests = MPI3MR_OP_REQ_Q_QD; 1253c9566231SKashyap Desai op_req_q->ci = 0; 1254c9566231SKashyap Desai op_req_q->pi = 0; 1255c9566231SKashyap Desai op_req_q->reply_qid = reply_qid; 1256c9566231SKashyap Desai spin_lock_init(&op_req_q->q_lock); 1257c9566231SKashyap Desai 1258c9566231SKashyap Desai if (!op_req_q->q_segments) { 1259c9566231SKashyap Desai retval = mpi3mr_alloc_op_req_q_segments(mrioc, idx); 1260c9566231SKashyap Desai if (retval) { 1261c9566231SKashyap Desai mpi3mr_free_op_req_q_segments(mrioc, idx); 1262c9566231SKashyap Desai goto out; 1263c9566231SKashyap Desai } 1264c9566231SKashyap Desai } 1265c9566231SKashyap Desai 1266c9566231SKashyap Desai memset(&create_req, 0, sizeof(create_req)); 1267c9566231SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1268c9566231SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1269c9566231SKashyap Desai retval = -1; 1270c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: Init command is in use\n"); 1271c9566231SKashyap Desai goto out; 1272c9566231SKashyap Desai } 1273c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1274c9566231SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1275c9566231SKashyap Desai mrioc->init_cmds.callback = NULL; 1276c9566231SKashyap Desai create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1277c9566231SKashyap Desai create_req.function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE; 1278c9566231SKashyap Desai create_req.queue_id = cpu_to_le16(req_qid); 1279c9566231SKashyap Desai if (mrioc->enable_segqueue) { 1280c9566231SKashyap Desai create_req.flags = 1281c9566231SKashyap Desai MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED; 1282c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1283c9566231SKashyap Desai op_req_q->q_segment_list_dma); 1284c9566231SKashyap Desai } else 1285c9566231SKashyap Desai create_req.base_address = cpu_to_le64( 1286c9566231SKashyap Desai op_req_q->q_segments[0].segment_dma); 1287c9566231SKashyap Desai create_req.reply_queue_id = cpu_to_le16(reply_qid); 1288c9566231SKashyap Desai create_req.size = cpu_to_le16(op_req_q->num_requests); 1289c9566231SKashyap Desai 1290c9566231SKashyap Desai init_completion(&mrioc->init_cmds.done); 1291c9566231SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &create_req, 1292c9566231SKashyap Desai sizeof(create_req), 1); 1293c9566231SKashyap Desai if (retval) { 1294c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: Admin Post failed\n"); 1295c9566231SKashyap Desai goto out_unlock; 1296c9566231SKashyap Desai } 1297c9566231SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1298c9566231SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1299c9566231SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1300c9566231SKashyap Desai ioc_err(mrioc, "CreateReqQ: command timed out\n"); 1301c9566231SKashyap Desai mpi3mr_set_diagsave(mrioc); 1302c9566231SKashyap Desai if (mpi3mr_issue_reset(mrioc, 1303c9566231SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 1304c9566231SKashyap Desai MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT)) 1305c9566231SKashyap Desai mrioc->unrecoverable = 1; 1306c9566231SKashyap Desai retval = -1; 1307c9566231SKashyap Desai goto out_unlock; 1308c9566231SKashyap Desai } 1309c9566231SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1310c9566231SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1311c9566231SKashyap Desai ioc_err(mrioc, 1312c9566231SKashyap Desai "CreateReqQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1313c9566231SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1314c9566231SKashyap Desai mrioc->init_cmds.ioc_loginfo); 1315c9566231SKashyap Desai retval = -1; 1316c9566231SKashyap Desai goto out_unlock; 1317c9566231SKashyap Desai } 1318c9566231SKashyap Desai op_req_q->qid = req_qid; 1319c9566231SKashyap Desai 1320c9566231SKashyap Desai out_unlock: 1321c9566231SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 1322c9566231SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1323c9566231SKashyap Desai out: 1324c9566231SKashyap Desai 1325c9566231SKashyap Desai return retval; 1326c9566231SKashyap Desai } 1327c9566231SKashyap Desai 1328c9566231SKashyap Desai /** 1329c9566231SKashyap Desai * mpi3mr_create_op_queues - create operational queue pairs 1330c9566231SKashyap Desai * @mrioc: Adapter instance reference 1331c9566231SKashyap Desai * 1332c9566231SKashyap Desai * Allocate memory for operational queue meta data and call 1333c9566231SKashyap Desai * create request and reply queue functions. 1334c9566231SKashyap Desai * 1335c9566231SKashyap Desai * Return: 0 on success, non-zero on failures. 1336c9566231SKashyap Desai */ 1337c9566231SKashyap Desai static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc) 1338c9566231SKashyap Desai { 1339c9566231SKashyap Desai int retval = 0; 1340c9566231SKashyap Desai u16 num_queues = 0, i = 0, msix_count_op_q = 1; 1341c9566231SKashyap Desai 1342c9566231SKashyap Desai num_queues = min_t(int, mrioc->facts.max_op_reply_q, 1343c9566231SKashyap Desai mrioc->facts.max_op_req_q); 1344c9566231SKashyap Desai 1345c9566231SKashyap Desai msix_count_op_q = 1346c9566231SKashyap Desai mrioc->intr_info_count - mrioc->op_reply_q_offset; 1347c9566231SKashyap Desai if (!mrioc->num_queues) 1348c9566231SKashyap Desai mrioc->num_queues = min_t(int, num_queues, msix_count_op_q); 1349c9566231SKashyap Desai num_queues = mrioc->num_queues; 1350c9566231SKashyap Desai ioc_info(mrioc, "Trying to create %d Operational Q pairs\n", 1351c9566231SKashyap Desai num_queues); 1352c9566231SKashyap Desai 1353c9566231SKashyap Desai if (!mrioc->req_qinfo) { 1354c9566231SKashyap Desai mrioc->req_qinfo = kcalloc(num_queues, 1355c9566231SKashyap Desai sizeof(struct op_req_qinfo), GFP_KERNEL); 1356c9566231SKashyap Desai if (!mrioc->req_qinfo) { 1357c9566231SKashyap Desai retval = -1; 1358c9566231SKashyap Desai goto out_failed; 1359c9566231SKashyap Desai } 1360c9566231SKashyap Desai 1361c9566231SKashyap Desai mrioc->op_reply_qinfo = kzalloc(sizeof(struct op_reply_qinfo) * 1362c9566231SKashyap Desai num_queues, GFP_KERNEL); 1363c9566231SKashyap Desai if (!mrioc->op_reply_qinfo) { 1364c9566231SKashyap Desai retval = -1; 1365c9566231SKashyap Desai goto out_failed; 1366c9566231SKashyap Desai } 1367c9566231SKashyap Desai } 1368c9566231SKashyap Desai 1369c9566231SKashyap Desai if (mrioc->enable_segqueue) 1370c9566231SKashyap Desai ioc_info(mrioc, 1371c9566231SKashyap Desai "allocating operational queues through segmented queues\n"); 1372c9566231SKashyap Desai 1373c9566231SKashyap Desai for (i = 0; i < num_queues; i++) { 1374c9566231SKashyap Desai if (mpi3mr_create_op_reply_q(mrioc, i)) { 1375c9566231SKashyap Desai ioc_err(mrioc, "Cannot create OP RepQ %d\n", i); 1376c9566231SKashyap Desai break; 1377c9566231SKashyap Desai } 1378c9566231SKashyap Desai if (mpi3mr_create_op_req_q(mrioc, i, 1379c9566231SKashyap Desai mrioc->op_reply_qinfo[i].qid)) { 1380c9566231SKashyap Desai ioc_err(mrioc, "Cannot create OP ReqQ %d\n", i); 1381c9566231SKashyap Desai mpi3mr_delete_op_reply_q(mrioc, i); 1382c9566231SKashyap Desai break; 1383c9566231SKashyap Desai } 1384c9566231SKashyap Desai } 1385c9566231SKashyap Desai 1386c9566231SKashyap Desai if (i == 0) { 1387c9566231SKashyap Desai /* Not even one queue is created successfully*/ 1388c9566231SKashyap Desai retval = -1; 1389c9566231SKashyap Desai goto out_failed; 1390c9566231SKashyap Desai } 1391c9566231SKashyap Desai mrioc->num_op_reply_q = mrioc->num_op_req_q = i; 1392c9566231SKashyap Desai ioc_info(mrioc, "Successfully created %d Operational Q pairs\n", 1393c9566231SKashyap Desai mrioc->num_op_reply_q); 1394c9566231SKashyap Desai 1395c9566231SKashyap Desai return retval; 1396c9566231SKashyap Desai out_failed: 1397c9566231SKashyap Desai kfree(mrioc->req_qinfo); 1398c9566231SKashyap Desai mrioc->req_qinfo = NULL; 1399c9566231SKashyap Desai 1400c9566231SKashyap Desai kfree(mrioc->op_reply_qinfo); 1401c9566231SKashyap Desai mrioc->op_reply_qinfo = NULL; 1402c9566231SKashyap Desai 1403c9566231SKashyap Desai return retval; 1404c9566231SKashyap Desai } 1405c9566231SKashyap Desai 1406c9566231SKashyap Desai /** 1407023ab2a9SKashyap Desai * mpi3mr_op_request_post - Post request to operational queue 1408023ab2a9SKashyap Desai * @mrioc: Adapter reference 1409023ab2a9SKashyap Desai * @op_req_q: Operational request queue info 1410023ab2a9SKashyap Desai * @req: MPI3 request 1411023ab2a9SKashyap Desai * 1412023ab2a9SKashyap Desai * Post the MPI3 request into operational request queue and 1413023ab2a9SKashyap Desai * inform the controller, if the queue is full return 1414023ab2a9SKashyap Desai * appropriate error. 1415023ab2a9SKashyap Desai * 1416023ab2a9SKashyap Desai * Return: 0 on success, non-zero on failure. 1417023ab2a9SKashyap Desai */ 1418023ab2a9SKashyap Desai int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc, 1419023ab2a9SKashyap Desai struct op_req_qinfo *op_req_q, u8 *req) 1420023ab2a9SKashyap Desai { 1421023ab2a9SKashyap Desai u16 pi = 0, max_entries, reply_qidx = 0, midx; 1422023ab2a9SKashyap Desai int retval = 0; 1423023ab2a9SKashyap Desai unsigned long flags; 1424023ab2a9SKashyap Desai u8 *req_entry; 1425023ab2a9SKashyap Desai void *segment_base_addr; 1426023ab2a9SKashyap Desai u16 req_sz = mrioc->facts.op_req_sz; 1427023ab2a9SKashyap Desai struct segments *segments = op_req_q->q_segments; 1428023ab2a9SKashyap Desai 1429023ab2a9SKashyap Desai reply_qidx = op_req_q->reply_qid - 1; 1430023ab2a9SKashyap Desai 1431023ab2a9SKashyap Desai if (mrioc->unrecoverable) 1432023ab2a9SKashyap Desai return -EFAULT; 1433023ab2a9SKashyap Desai 1434023ab2a9SKashyap Desai spin_lock_irqsave(&op_req_q->q_lock, flags); 1435023ab2a9SKashyap Desai pi = op_req_q->pi; 1436023ab2a9SKashyap Desai max_entries = op_req_q->num_requests; 1437023ab2a9SKashyap Desai 1438023ab2a9SKashyap Desai if (mpi3mr_check_req_qfull(op_req_q)) { 1439023ab2a9SKashyap Desai midx = REPLY_QUEUE_IDX_TO_MSIX_IDX( 1440023ab2a9SKashyap Desai reply_qidx, mrioc->op_reply_q_offset); 1441023ab2a9SKashyap Desai mpi3mr_process_op_reply_q(mrioc, &mrioc->intr_info[midx]); 1442023ab2a9SKashyap Desai 1443023ab2a9SKashyap Desai if (mpi3mr_check_req_qfull(op_req_q)) { 1444023ab2a9SKashyap Desai retval = -EAGAIN; 1445023ab2a9SKashyap Desai goto out; 1446023ab2a9SKashyap Desai } 1447023ab2a9SKashyap Desai } 1448023ab2a9SKashyap Desai 1449023ab2a9SKashyap Desai if (mrioc->reset_in_progress) { 1450023ab2a9SKashyap Desai ioc_err(mrioc, "OpReqQ submit reset in progress\n"); 1451023ab2a9SKashyap Desai retval = -EAGAIN; 1452023ab2a9SKashyap Desai goto out; 1453023ab2a9SKashyap Desai } 1454023ab2a9SKashyap Desai 1455023ab2a9SKashyap Desai segment_base_addr = segments[pi / op_req_q->segment_qd].segment; 1456023ab2a9SKashyap Desai req_entry = (u8 *)segment_base_addr + 1457023ab2a9SKashyap Desai ((pi % op_req_q->segment_qd) * req_sz); 1458023ab2a9SKashyap Desai 1459023ab2a9SKashyap Desai memset(req_entry, 0, req_sz); 1460023ab2a9SKashyap Desai memcpy(req_entry, req, MPI3MR_ADMIN_REQ_FRAME_SZ); 1461023ab2a9SKashyap Desai 1462023ab2a9SKashyap Desai if (++pi == max_entries) 1463023ab2a9SKashyap Desai pi = 0; 1464023ab2a9SKashyap Desai op_req_q->pi = pi; 1465023ab2a9SKashyap Desai 1466023ab2a9SKashyap Desai writel(op_req_q->pi, 1467023ab2a9SKashyap Desai &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].producer_index); 1468023ab2a9SKashyap Desai 1469023ab2a9SKashyap Desai out: 1470023ab2a9SKashyap Desai spin_unlock_irqrestore(&op_req_q->q_lock, flags); 1471023ab2a9SKashyap Desai return retval; 1472023ab2a9SKashyap Desai } 1473023ab2a9SKashyap Desai 1474023ab2a9SKashyap Desai /** 1475672ae26cSKashyap Desai * mpi3mr_watchdog_work - watchdog thread to monitor faults 1476672ae26cSKashyap Desai * @work: work struct 1477672ae26cSKashyap Desai * 1478672ae26cSKashyap Desai * Watch dog work periodically executed (1 second interval) to 1479672ae26cSKashyap Desai * monitor firmware fault and to issue periodic timer sync to 1480672ae26cSKashyap Desai * the firmware. 1481672ae26cSKashyap Desai * 1482672ae26cSKashyap Desai * Return: Nothing. 1483672ae26cSKashyap Desai */ 1484672ae26cSKashyap Desai static void mpi3mr_watchdog_work(struct work_struct *work) 1485672ae26cSKashyap Desai { 1486672ae26cSKashyap Desai struct mpi3mr_ioc *mrioc = 1487672ae26cSKashyap Desai container_of(work, struct mpi3mr_ioc, watchdog_work.work); 1488672ae26cSKashyap Desai unsigned long flags; 1489672ae26cSKashyap Desai enum mpi3mr_iocstate ioc_state; 1490672ae26cSKashyap Desai u32 fault, host_diagnostic; 1491672ae26cSKashyap Desai 1492672ae26cSKashyap Desai /*Check for fault state every one second and issue Soft reset*/ 1493672ae26cSKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 1494672ae26cSKashyap Desai if (ioc_state == MRIOC_STATE_FAULT) { 1495672ae26cSKashyap Desai fault = readl(&mrioc->sysif_regs->fault) & 1496672ae26cSKashyap Desai MPI3_SYSIF_FAULT_CODE_MASK; 1497672ae26cSKashyap Desai host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); 1498672ae26cSKashyap Desai if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) { 1499672ae26cSKashyap Desai if (!mrioc->diagsave_timeout) { 1500672ae26cSKashyap Desai mpi3mr_print_fault_info(mrioc); 1501672ae26cSKashyap Desai ioc_warn(mrioc, "Diag save in progress\n"); 1502672ae26cSKashyap Desai } 1503672ae26cSKashyap Desai if ((mrioc->diagsave_timeout++) <= 1504672ae26cSKashyap Desai MPI3_SYSIF_DIAG_SAVE_TIMEOUT) 1505672ae26cSKashyap Desai goto schedule_work; 1506672ae26cSKashyap Desai } else 1507672ae26cSKashyap Desai mpi3mr_print_fault_info(mrioc); 1508672ae26cSKashyap Desai mrioc->diagsave_timeout = 0; 1509672ae26cSKashyap Desai 1510672ae26cSKashyap Desai if (fault == MPI3_SYSIF_FAULT_CODE_FACTORY_RESET) { 1511672ae26cSKashyap Desai ioc_info(mrioc, 1512672ae26cSKashyap Desai "Factory Reset fault occurred marking controller as unrecoverable" 1513672ae26cSKashyap Desai ); 1514672ae26cSKashyap Desai mrioc->unrecoverable = 1; 1515672ae26cSKashyap Desai goto out; 1516672ae26cSKashyap Desai } 1517672ae26cSKashyap Desai 1518672ae26cSKashyap Desai if ((fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) || 1519672ae26cSKashyap Desai (fault == MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS) || 1520672ae26cSKashyap Desai (mrioc->reset_in_progress)) 1521672ae26cSKashyap Desai goto out; 1522672ae26cSKashyap Desai if (fault == MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET) 1523672ae26cSKashyap Desai mpi3mr_soft_reset_handler(mrioc, 1524672ae26cSKashyap Desai MPI3MR_RESET_FROM_CIACTIV_FAULT, 0); 1525672ae26cSKashyap Desai else 1526672ae26cSKashyap Desai mpi3mr_soft_reset_handler(mrioc, 1527672ae26cSKashyap Desai MPI3MR_RESET_FROM_FAULT_WATCH, 0); 1528672ae26cSKashyap Desai } 1529672ae26cSKashyap Desai 1530672ae26cSKashyap Desai schedule_work: 1531672ae26cSKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 1532672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 1533672ae26cSKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 1534672ae26cSKashyap Desai &mrioc->watchdog_work, 1535672ae26cSKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 1536672ae26cSKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 1537672ae26cSKashyap Desai out: 1538672ae26cSKashyap Desai return; 1539672ae26cSKashyap Desai } 1540672ae26cSKashyap Desai 1541672ae26cSKashyap Desai /** 1542672ae26cSKashyap Desai * mpi3mr_start_watchdog - Start watchdog 1543672ae26cSKashyap Desai * @mrioc: Adapter instance reference 1544672ae26cSKashyap Desai * 1545672ae26cSKashyap Desai * Create and start the watchdog thread to monitor controller 1546672ae26cSKashyap Desai * faults. 1547672ae26cSKashyap Desai * 1548672ae26cSKashyap Desai * Return: Nothing. 1549672ae26cSKashyap Desai */ 1550672ae26cSKashyap Desai void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc) 1551672ae26cSKashyap Desai { 1552672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 1553672ae26cSKashyap Desai return; 1554672ae26cSKashyap Desai 1555672ae26cSKashyap Desai INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work); 1556672ae26cSKashyap Desai snprintf(mrioc->watchdog_work_q_name, 1557672ae26cSKashyap Desai sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name, 1558672ae26cSKashyap Desai mrioc->id); 1559672ae26cSKashyap Desai mrioc->watchdog_work_q = 1560672ae26cSKashyap Desai create_singlethread_workqueue(mrioc->watchdog_work_q_name); 1561672ae26cSKashyap Desai if (!mrioc->watchdog_work_q) { 1562672ae26cSKashyap Desai ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__); 1563672ae26cSKashyap Desai return; 1564672ae26cSKashyap Desai } 1565672ae26cSKashyap Desai 1566672ae26cSKashyap Desai if (mrioc->watchdog_work_q) 1567672ae26cSKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 1568672ae26cSKashyap Desai &mrioc->watchdog_work, 1569672ae26cSKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 1570672ae26cSKashyap Desai } 1571672ae26cSKashyap Desai 1572672ae26cSKashyap Desai /** 1573672ae26cSKashyap Desai * mpi3mr_stop_watchdog - Stop watchdog 1574672ae26cSKashyap Desai * @mrioc: Adapter instance reference 1575672ae26cSKashyap Desai * 1576672ae26cSKashyap Desai * Stop the watchdog thread created to monitor controller 1577672ae26cSKashyap Desai * faults. 1578672ae26cSKashyap Desai * 1579672ae26cSKashyap Desai * Return: Nothing. 1580672ae26cSKashyap Desai */ 1581672ae26cSKashyap Desai void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc) 1582672ae26cSKashyap Desai { 1583672ae26cSKashyap Desai unsigned long flags; 1584672ae26cSKashyap Desai struct workqueue_struct *wq; 1585672ae26cSKashyap Desai 1586672ae26cSKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 1587672ae26cSKashyap Desai wq = mrioc->watchdog_work_q; 1588672ae26cSKashyap Desai mrioc->watchdog_work_q = NULL; 1589672ae26cSKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 1590672ae26cSKashyap Desai if (wq) { 1591672ae26cSKashyap Desai if (!cancel_delayed_work_sync(&mrioc->watchdog_work)) 1592672ae26cSKashyap Desai flush_workqueue(wq); 1593672ae26cSKashyap Desai destroy_workqueue(wq); 1594672ae26cSKashyap Desai } 1595672ae26cSKashyap Desai } 1596672ae26cSKashyap Desai 1597672ae26cSKashyap Desai /** 1598*fb9b0457SKashyap Desai * mpi3mr_kill_ioc - Kill the controller 1599*fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 1600*fb9b0457SKashyap Desai * @reason: reason for the failure. 1601*fb9b0457SKashyap Desai * 1602*fb9b0457SKashyap Desai * If fault debug is enabled, display the fault info else issue 1603*fb9b0457SKashyap Desai * diag fault and freeze the system for controller debug 1604*fb9b0457SKashyap Desai * purpose. 1605*fb9b0457SKashyap Desai * 1606*fb9b0457SKashyap Desai * Return: Nothing. 1607*fb9b0457SKashyap Desai */ 1608*fb9b0457SKashyap Desai static void mpi3mr_kill_ioc(struct mpi3mr_ioc *mrioc, u32 reason) 1609*fb9b0457SKashyap Desai { 1610*fb9b0457SKashyap Desai enum mpi3mr_iocstate ioc_state; 1611*fb9b0457SKashyap Desai 1612*fb9b0457SKashyap Desai if (!mrioc->fault_dbg) 1613*fb9b0457SKashyap Desai return; 1614*fb9b0457SKashyap Desai 1615*fb9b0457SKashyap Desai dump_stack(); 1616*fb9b0457SKashyap Desai 1617*fb9b0457SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 1618*fb9b0457SKashyap Desai if (ioc_state == MRIOC_STATE_FAULT) 1619*fb9b0457SKashyap Desai mpi3mr_print_fault_info(mrioc); 1620*fb9b0457SKashyap Desai else { 1621*fb9b0457SKashyap Desai ioc_err(mrioc, "Firmware is halted due to the reason %d\n", 1622*fb9b0457SKashyap Desai reason); 1623*fb9b0457SKashyap Desai mpi3mr_diagfault_reset_handler(mrioc, reason); 1624*fb9b0457SKashyap Desai } 1625*fb9b0457SKashyap Desai if (mrioc->fault_dbg == 2) 1626*fb9b0457SKashyap Desai for (;;) 1627*fb9b0457SKashyap Desai ; 1628*fb9b0457SKashyap Desai else 1629*fb9b0457SKashyap Desai panic("panic in %s\n", __func__); 1630*fb9b0457SKashyap Desai } 1631*fb9b0457SKashyap Desai 1632*fb9b0457SKashyap Desai /** 1633824a1566SKashyap Desai * mpi3mr_setup_admin_qpair - Setup admin queue pair 1634824a1566SKashyap Desai * @mrioc: Adapter instance reference 1635824a1566SKashyap Desai * 1636824a1566SKashyap Desai * Allocate memory for admin queue pair if required and register 1637824a1566SKashyap Desai * the admin queue with the controller. 1638824a1566SKashyap Desai * 1639824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 1640824a1566SKashyap Desai */ 1641824a1566SKashyap Desai static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc) 1642824a1566SKashyap Desai { 1643824a1566SKashyap Desai int retval = 0; 1644824a1566SKashyap Desai u32 num_admin_entries = 0; 1645824a1566SKashyap Desai 1646824a1566SKashyap Desai mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE; 1647824a1566SKashyap Desai mrioc->num_admin_req = mrioc->admin_req_q_sz / 1648824a1566SKashyap Desai MPI3MR_ADMIN_REQ_FRAME_SZ; 1649824a1566SKashyap Desai mrioc->admin_req_ci = mrioc->admin_req_pi = 0; 1650824a1566SKashyap Desai mrioc->admin_req_base = NULL; 1651824a1566SKashyap Desai 1652824a1566SKashyap Desai mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE; 1653824a1566SKashyap Desai mrioc->num_admin_replies = mrioc->admin_reply_q_sz / 1654824a1566SKashyap Desai MPI3MR_ADMIN_REPLY_FRAME_SZ; 1655824a1566SKashyap Desai mrioc->admin_reply_ci = 0; 1656824a1566SKashyap Desai mrioc->admin_reply_ephase = 1; 1657824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 1658824a1566SKashyap Desai 1659824a1566SKashyap Desai if (!mrioc->admin_req_base) { 1660824a1566SKashyap Desai mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev, 1661824a1566SKashyap Desai mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL); 1662824a1566SKashyap Desai 1663824a1566SKashyap Desai if (!mrioc->admin_req_base) { 1664824a1566SKashyap Desai retval = -1; 1665824a1566SKashyap Desai goto out_failed; 1666824a1566SKashyap Desai } 1667824a1566SKashyap Desai 1668824a1566SKashyap Desai mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev, 1669824a1566SKashyap Desai mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma, 1670824a1566SKashyap Desai GFP_KERNEL); 1671824a1566SKashyap Desai 1672824a1566SKashyap Desai if (!mrioc->admin_reply_base) { 1673824a1566SKashyap Desai retval = -1; 1674824a1566SKashyap Desai goto out_failed; 1675824a1566SKashyap Desai } 1676824a1566SKashyap Desai } 1677824a1566SKashyap Desai 1678824a1566SKashyap Desai num_admin_entries = (mrioc->num_admin_replies << 16) | 1679824a1566SKashyap Desai (mrioc->num_admin_req); 1680824a1566SKashyap Desai writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries); 1681824a1566SKashyap Desai mpi3mr_writeq(mrioc->admin_req_dma, 1682824a1566SKashyap Desai &mrioc->sysif_regs->admin_request_queue_address); 1683824a1566SKashyap Desai mpi3mr_writeq(mrioc->admin_reply_dma, 1684824a1566SKashyap Desai &mrioc->sysif_regs->admin_reply_queue_address); 1685824a1566SKashyap Desai writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi); 1686824a1566SKashyap Desai writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); 1687824a1566SKashyap Desai return retval; 1688824a1566SKashyap Desai 1689824a1566SKashyap Desai out_failed: 1690824a1566SKashyap Desai 1691824a1566SKashyap Desai if (mrioc->admin_reply_base) { 1692824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz, 1693824a1566SKashyap Desai mrioc->admin_reply_base, mrioc->admin_reply_dma); 1694824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 1695824a1566SKashyap Desai } 1696824a1566SKashyap Desai if (mrioc->admin_req_base) { 1697824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz, 1698824a1566SKashyap Desai mrioc->admin_req_base, mrioc->admin_req_dma); 1699824a1566SKashyap Desai mrioc->admin_req_base = NULL; 1700824a1566SKashyap Desai } 1701824a1566SKashyap Desai return retval; 1702824a1566SKashyap Desai } 1703824a1566SKashyap Desai 1704824a1566SKashyap Desai /** 1705824a1566SKashyap Desai * mpi3mr_issue_iocfacts - Send IOC Facts 1706824a1566SKashyap Desai * @mrioc: Adapter instance reference 1707824a1566SKashyap Desai * @facts_data: Cached IOC facts data 1708824a1566SKashyap Desai * 1709824a1566SKashyap Desai * Issue IOC Facts MPI request through admin queue and wait for 1710824a1566SKashyap Desai * the completion of it or time out. 1711824a1566SKashyap Desai * 1712824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 1713824a1566SKashyap Desai */ 1714824a1566SKashyap Desai static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc, 1715824a1566SKashyap Desai struct mpi3_ioc_facts_data *facts_data) 1716824a1566SKashyap Desai { 1717824a1566SKashyap Desai struct mpi3_ioc_facts_request iocfacts_req; 1718824a1566SKashyap Desai void *data = NULL; 1719824a1566SKashyap Desai dma_addr_t data_dma; 1720824a1566SKashyap Desai u32 data_len = sizeof(*facts_data); 1721824a1566SKashyap Desai int retval = 0; 1722824a1566SKashyap Desai u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 1723824a1566SKashyap Desai 1724824a1566SKashyap Desai data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, 1725824a1566SKashyap Desai GFP_KERNEL); 1726824a1566SKashyap Desai 1727824a1566SKashyap Desai if (!data) { 1728824a1566SKashyap Desai retval = -1; 1729824a1566SKashyap Desai goto out; 1730824a1566SKashyap Desai } 1731824a1566SKashyap Desai 1732824a1566SKashyap Desai memset(&iocfacts_req, 0, sizeof(iocfacts_req)); 1733824a1566SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 1734824a1566SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 1735824a1566SKashyap Desai retval = -1; 1736824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n"); 1737824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1738824a1566SKashyap Desai goto out; 1739824a1566SKashyap Desai } 1740824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 1741824a1566SKashyap Desai mrioc->init_cmds.is_waiting = 1; 1742824a1566SKashyap Desai mrioc->init_cmds.callback = NULL; 1743824a1566SKashyap Desai iocfacts_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 1744824a1566SKashyap Desai iocfacts_req.function = MPI3_FUNCTION_IOC_FACTS; 1745824a1566SKashyap Desai 1746824a1566SKashyap Desai mpi3mr_add_sg_single(&iocfacts_req.sgl, sgl_flags, data_len, 1747824a1566SKashyap Desai data_dma); 1748824a1566SKashyap Desai 1749824a1566SKashyap Desai init_completion(&mrioc->init_cmds.done); 1750824a1566SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req, 1751824a1566SKashyap Desai sizeof(iocfacts_req), 1); 1752824a1566SKashyap Desai if (retval) { 1753824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n"); 1754824a1566SKashyap Desai goto out_unlock; 1755824a1566SKashyap Desai } 1756824a1566SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 1757824a1566SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 1758824a1566SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 1759824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCFacts: command timed out\n"); 1760824a1566SKashyap Desai mpi3mr_set_diagsave(mrioc); 1761824a1566SKashyap Desai mpi3mr_issue_reset(mrioc, 1762824a1566SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 1763824a1566SKashyap Desai MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT); 1764824a1566SKashyap Desai mrioc->unrecoverable = 1; 1765824a1566SKashyap Desai retval = -1; 1766824a1566SKashyap Desai goto out_unlock; 1767824a1566SKashyap Desai } 1768824a1566SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1769824a1566SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 1770824a1566SKashyap Desai ioc_err(mrioc, 1771824a1566SKashyap Desai "Issue IOCFacts: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 1772824a1566SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1773824a1566SKashyap Desai mrioc->init_cmds.ioc_loginfo); 1774824a1566SKashyap Desai retval = -1; 1775824a1566SKashyap Desai goto out_unlock; 1776824a1566SKashyap Desai } 1777824a1566SKashyap Desai memcpy(facts_data, (u8 *)data, data_len); 1778824a1566SKashyap Desai out_unlock: 1779824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 1780824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 1781824a1566SKashyap Desai 1782824a1566SKashyap Desai out: 1783824a1566SKashyap Desai if (data) 1784824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma); 1785824a1566SKashyap Desai 1786824a1566SKashyap Desai return retval; 1787824a1566SKashyap Desai } 1788824a1566SKashyap Desai 1789824a1566SKashyap Desai /** 1790824a1566SKashyap Desai * mpi3mr_check_reset_dma_mask - Process IOC facts data 1791824a1566SKashyap Desai * @mrioc: Adapter instance reference 1792824a1566SKashyap Desai * 1793824a1566SKashyap Desai * Check whether the new DMA mask requested through IOCFacts by 1794824a1566SKashyap Desai * firmware needs to be set, if so set it . 1795824a1566SKashyap Desai * 1796824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 1797824a1566SKashyap Desai */ 1798824a1566SKashyap Desai static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc) 1799824a1566SKashyap Desai { 1800824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 1801824a1566SKashyap Desai int r; 1802824a1566SKashyap Desai u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask); 1803824a1566SKashyap Desai 1804824a1566SKashyap Desai if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask)) 1805824a1566SKashyap Desai return 0; 1806824a1566SKashyap Desai 1807824a1566SKashyap Desai ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n", 1808824a1566SKashyap Desai mrioc->dma_mask, facts_dma_mask); 1809824a1566SKashyap Desai 1810824a1566SKashyap Desai r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask); 1811824a1566SKashyap Desai if (r) { 1812824a1566SKashyap Desai ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n", 1813824a1566SKashyap Desai facts_dma_mask, r); 1814824a1566SKashyap Desai return r; 1815824a1566SKashyap Desai } 1816824a1566SKashyap Desai mrioc->dma_mask = facts_dma_mask; 1817824a1566SKashyap Desai return r; 1818824a1566SKashyap Desai } 1819824a1566SKashyap Desai 1820824a1566SKashyap Desai /** 1821824a1566SKashyap Desai * mpi3mr_process_factsdata - Process IOC facts data 1822824a1566SKashyap Desai * @mrioc: Adapter instance reference 1823824a1566SKashyap Desai * @facts_data: Cached IOC facts data 1824824a1566SKashyap Desai * 1825824a1566SKashyap Desai * Convert IOC facts data into cpu endianness and cache it in 1826824a1566SKashyap Desai * the driver . 1827824a1566SKashyap Desai * 1828824a1566SKashyap Desai * Return: Nothing. 1829824a1566SKashyap Desai */ 1830824a1566SKashyap Desai static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, 1831824a1566SKashyap Desai struct mpi3_ioc_facts_data *facts_data) 1832824a1566SKashyap Desai { 1833824a1566SKashyap Desai u32 ioc_config, req_sz, facts_flags; 1834824a1566SKashyap Desai 1835824a1566SKashyap Desai if ((le16_to_cpu(facts_data->ioc_facts_data_length)) != 1836824a1566SKashyap Desai (sizeof(*facts_data) / 4)) { 1837824a1566SKashyap Desai ioc_warn(mrioc, 1838824a1566SKashyap Desai "IOCFactsdata length mismatch driver_sz(%zu) firmware_sz(%d)\n", 1839824a1566SKashyap Desai sizeof(*facts_data), 1840824a1566SKashyap Desai le16_to_cpu(facts_data->ioc_facts_data_length) * 4); 1841824a1566SKashyap Desai } 1842824a1566SKashyap Desai 1843824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 1844824a1566SKashyap Desai req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >> 1845824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT); 1846824a1566SKashyap Desai if (le16_to_cpu(facts_data->ioc_request_frame_size) != (req_sz / 4)) { 1847824a1566SKashyap Desai ioc_err(mrioc, 1848824a1566SKashyap Desai "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n", 1849824a1566SKashyap Desai req_sz / 4, le16_to_cpu(facts_data->ioc_request_frame_size)); 1850824a1566SKashyap Desai } 1851824a1566SKashyap Desai 1852824a1566SKashyap Desai memset(&mrioc->facts, 0, sizeof(mrioc->facts)); 1853824a1566SKashyap Desai 1854824a1566SKashyap Desai facts_flags = le32_to_cpu(facts_data->flags); 1855824a1566SKashyap Desai mrioc->facts.op_req_sz = req_sz; 1856824a1566SKashyap Desai mrioc->op_reply_desc_sz = 1 << ((ioc_config & 1857824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >> 1858824a1566SKashyap Desai MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT); 1859824a1566SKashyap Desai 1860824a1566SKashyap Desai mrioc->facts.ioc_num = facts_data->ioc_number; 1861824a1566SKashyap Desai mrioc->facts.who_init = facts_data->who_init; 1862824a1566SKashyap Desai mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->max_msix_vectors); 1863824a1566SKashyap Desai mrioc->facts.personality = (facts_flags & 1864824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK); 1865824a1566SKashyap Desai mrioc->facts.dma_mask = (facts_flags & 1866824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >> 1867824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT; 1868824a1566SKashyap Desai mrioc->facts.protocol_flags = facts_data->protocol_flags; 1869824a1566SKashyap Desai mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word); 1870824a1566SKashyap Desai mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_request); 1871824a1566SKashyap Desai mrioc->facts.product_id = le16_to_cpu(facts_data->product_id); 1872824a1566SKashyap Desai mrioc->facts.reply_sz = le16_to_cpu(facts_data->reply_frame_size) * 4; 1873824a1566SKashyap Desai mrioc->facts.exceptions = le16_to_cpu(facts_data->ioc_exceptions); 1874824a1566SKashyap Desai mrioc->facts.max_perids = le16_to_cpu(facts_data->max_persistent_id); 1875824a1566SKashyap Desai mrioc->facts.max_pds = le16_to_cpu(facts_data->max_pds); 1876824a1566SKashyap Desai mrioc->facts.max_vds = le16_to_cpu(facts_data->max_vds); 1877824a1566SKashyap Desai mrioc->facts.max_hpds = le16_to_cpu(facts_data->max_host_pds); 1878824a1566SKashyap Desai mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_advanced_host_pds); 1879824a1566SKashyap Desai mrioc->facts.max_raidpds = le16_to_cpu(facts_data->max_raid_pds); 1880824a1566SKashyap Desai mrioc->facts.max_nvme = le16_to_cpu(facts_data->max_nvme); 1881824a1566SKashyap Desai mrioc->facts.max_pcie_switches = 1882824a1566SKashyap Desai le16_to_cpu(facts_data->max_pc_ie_switches); 1883824a1566SKashyap Desai mrioc->facts.max_sasexpanders = 1884824a1566SKashyap Desai le16_to_cpu(facts_data->max_sas_expanders); 1885824a1566SKashyap Desai mrioc->facts.max_sasinitiators = 1886824a1566SKashyap Desai le16_to_cpu(facts_data->max_sas_initiators); 1887824a1566SKashyap Desai mrioc->facts.max_enclosures = le16_to_cpu(facts_data->max_enclosures); 1888824a1566SKashyap Desai mrioc->facts.min_devhandle = le16_to_cpu(facts_data->min_dev_handle); 1889824a1566SKashyap Desai mrioc->facts.max_devhandle = le16_to_cpu(facts_data->max_dev_handle); 1890824a1566SKashyap Desai mrioc->facts.max_op_req_q = 1891824a1566SKashyap Desai le16_to_cpu(facts_data->max_operational_request_queues); 1892824a1566SKashyap Desai mrioc->facts.max_op_reply_q = 1893824a1566SKashyap Desai le16_to_cpu(facts_data->max_operational_reply_queues); 1894824a1566SKashyap Desai mrioc->facts.ioc_capabilities = 1895824a1566SKashyap Desai le32_to_cpu(facts_data->ioc_capabilities); 1896824a1566SKashyap Desai mrioc->facts.fw_ver.build_num = 1897824a1566SKashyap Desai le16_to_cpu(facts_data->fw_version.build_num); 1898824a1566SKashyap Desai mrioc->facts.fw_ver.cust_id = 1899824a1566SKashyap Desai le16_to_cpu(facts_data->fw_version.customer_id); 1900824a1566SKashyap Desai mrioc->facts.fw_ver.ph_minor = facts_data->fw_version.phase_minor; 1901824a1566SKashyap Desai mrioc->facts.fw_ver.ph_major = facts_data->fw_version.phase_major; 1902824a1566SKashyap Desai mrioc->facts.fw_ver.gen_minor = facts_data->fw_version.gen_minor; 1903824a1566SKashyap Desai mrioc->facts.fw_ver.gen_major = facts_data->fw_version.gen_major; 1904824a1566SKashyap Desai mrioc->msix_count = min_t(int, mrioc->msix_count, 1905824a1566SKashyap Desai mrioc->facts.max_msix_vectors); 1906824a1566SKashyap Desai mrioc->facts.sge_mod_mask = facts_data->sge_modifier_mask; 1907824a1566SKashyap Desai mrioc->facts.sge_mod_value = facts_data->sge_modifier_value; 1908824a1566SKashyap Desai mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift; 1909824a1566SKashyap Desai mrioc->facts.shutdown_timeout = 1910824a1566SKashyap Desai le16_to_cpu(facts_data->shutdown_timeout); 1911824a1566SKashyap Desai 1912824a1566SKashyap Desai ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),", 1913824a1566SKashyap Desai mrioc->facts.ioc_num, mrioc->facts.max_op_req_q, 1914824a1566SKashyap Desai mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle); 1915824a1566SKashyap Desai ioc_info(mrioc, 1916824a1566SKashyap Desai "maxreqs(%d), mindh(%d) maxPDs(%d) maxvectors(%d) maxperids(%d)\n", 1917824a1566SKashyap Desai mrioc->facts.max_reqs, mrioc->facts.min_devhandle, 1918824a1566SKashyap Desai mrioc->facts.max_pds, mrioc->facts.max_msix_vectors, 1919824a1566SKashyap Desai mrioc->facts.max_perids); 1920824a1566SKashyap Desai ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ", 1921824a1566SKashyap Desai mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value, 1922824a1566SKashyap Desai mrioc->facts.sge_mod_shift); 1923824a1566SKashyap Desai ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x\n", 1924824a1566SKashyap Desai mrioc->facts.dma_mask, (facts_flags & 1925824a1566SKashyap Desai MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK)); 1926824a1566SKashyap Desai 1927824a1566SKashyap Desai mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD; 1928824a1566SKashyap Desai 1929824a1566SKashyap Desai if (reset_devices) 1930824a1566SKashyap Desai mrioc->max_host_ios = min_t(int, mrioc->max_host_ios, 1931824a1566SKashyap Desai MPI3MR_HOST_IOS_KDUMP); 1932824a1566SKashyap Desai } 1933824a1566SKashyap Desai 1934824a1566SKashyap Desai /** 1935824a1566SKashyap Desai * mpi3mr_alloc_reply_sense_bufs - Send IOC Init 1936824a1566SKashyap Desai * @mrioc: Adapter instance reference 1937824a1566SKashyap Desai * 1938824a1566SKashyap Desai * Allocate and initialize the reply free buffers, sense 1939824a1566SKashyap Desai * buffers, reply free queue and sense buffer queue. 1940824a1566SKashyap Desai * 1941824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 1942824a1566SKashyap Desai */ 1943824a1566SKashyap Desai static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) 1944824a1566SKashyap Desai { 1945824a1566SKashyap Desai int retval = 0; 1946824a1566SKashyap Desai u32 sz, i; 1947824a1566SKashyap Desai dma_addr_t phy_addr; 1948824a1566SKashyap Desai 1949824a1566SKashyap Desai if (mrioc->init_cmds.reply) 1950824a1566SKashyap Desai goto post_reply_sbuf; 1951824a1566SKashyap Desai 1952824a1566SKashyap Desai mrioc->init_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL); 1953824a1566SKashyap Desai if (!mrioc->init_cmds.reply) 1954824a1566SKashyap Desai goto out_failed; 1955824a1566SKashyap Desai 195613ef29eaSKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 195713ef29eaSKashyap Desai mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->facts.reply_sz, 195813ef29eaSKashyap Desai GFP_KERNEL); 195913ef29eaSKashyap Desai if (!mrioc->dev_rmhs_cmds[i].reply) 196013ef29eaSKashyap Desai goto out_failed; 196113ef29eaSKashyap Desai } 196213ef29eaSKashyap Desai 1963824a1566SKashyap Desai mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES; 1964824a1566SKashyap Desai mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1; 1965824a1566SKashyap Desai mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR; 1966824a1566SKashyap Desai mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1; 1967824a1566SKashyap Desai 1968824a1566SKashyap Desai /* reply buffer pool, 16 byte align */ 1969824a1566SKashyap Desai sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz; 1970824a1566SKashyap Desai mrioc->reply_buf_pool = dma_pool_create("reply_buf pool", 1971824a1566SKashyap Desai &mrioc->pdev->dev, sz, 16, 0); 1972824a1566SKashyap Desai if (!mrioc->reply_buf_pool) { 1973824a1566SKashyap Desai ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n"); 1974824a1566SKashyap Desai goto out_failed; 1975824a1566SKashyap Desai } 1976824a1566SKashyap Desai 1977824a1566SKashyap Desai mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL, 1978824a1566SKashyap Desai &mrioc->reply_buf_dma); 1979824a1566SKashyap Desai if (!mrioc->reply_buf) 1980824a1566SKashyap Desai goto out_failed; 1981824a1566SKashyap Desai 1982824a1566SKashyap Desai mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz; 1983824a1566SKashyap Desai 1984824a1566SKashyap Desai /* reply free queue, 8 byte align */ 1985824a1566SKashyap Desai sz = mrioc->reply_free_qsz * 8; 1986824a1566SKashyap Desai mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool", 1987824a1566SKashyap Desai &mrioc->pdev->dev, sz, 8, 0); 1988824a1566SKashyap Desai if (!mrioc->reply_free_q_pool) { 1989824a1566SKashyap Desai ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n"); 1990824a1566SKashyap Desai goto out_failed; 1991824a1566SKashyap Desai } 1992824a1566SKashyap Desai mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool, 1993824a1566SKashyap Desai GFP_KERNEL, &mrioc->reply_free_q_dma); 1994824a1566SKashyap Desai if (!mrioc->reply_free_q) 1995824a1566SKashyap Desai goto out_failed; 1996824a1566SKashyap Desai 1997824a1566SKashyap Desai /* sense buffer pool, 4 byte align */ 1998824a1566SKashyap Desai sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ; 1999824a1566SKashyap Desai mrioc->sense_buf_pool = dma_pool_create("sense_buf pool", 2000824a1566SKashyap Desai &mrioc->pdev->dev, sz, 4, 0); 2001824a1566SKashyap Desai if (!mrioc->sense_buf_pool) { 2002824a1566SKashyap Desai ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n"); 2003824a1566SKashyap Desai goto out_failed; 2004824a1566SKashyap Desai } 2005824a1566SKashyap Desai mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL, 2006824a1566SKashyap Desai &mrioc->sense_buf_dma); 2007824a1566SKashyap Desai if (!mrioc->sense_buf) 2008824a1566SKashyap Desai goto out_failed; 2009824a1566SKashyap Desai 2010824a1566SKashyap Desai /* sense buffer queue, 8 byte align */ 2011824a1566SKashyap Desai sz = mrioc->sense_buf_q_sz * 8; 2012824a1566SKashyap Desai mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool", 2013824a1566SKashyap Desai &mrioc->pdev->dev, sz, 8, 0); 2014824a1566SKashyap Desai if (!mrioc->sense_buf_q_pool) { 2015824a1566SKashyap Desai ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n"); 2016824a1566SKashyap Desai goto out_failed; 2017824a1566SKashyap Desai } 2018824a1566SKashyap Desai mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool, 2019824a1566SKashyap Desai GFP_KERNEL, &mrioc->sense_buf_q_dma); 2020824a1566SKashyap Desai if (!mrioc->sense_buf_q) 2021824a1566SKashyap Desai goto out_failed; 2022824a1566SKashyap Desai 2023824a1566SKashyap Desai post_reply_sbuf: 2024824a1566SKashyap Desai sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz; 2025824a1566SKashyap Desai ioc_info(mrioc, 2026824a1566SKashyap Desai "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n", 2027824a1566SKashyap Desai mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->facts.reply_sz, 2028824a1566SKashyap Desai (sz / 1024), (unsigned long long)mrioc->reply_buf_dma); 2029824a1566SKashyap Desai sz = mrioc->reply_free_qsz * 8; 2030824a1566SKashyap Desai ioc_info(mrioc, 2031824a1566SKashyap Desai "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n", 2032824a1566SKashyap Desai mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024), 2033824a1566SKashyap Desai (unsigned long long)mrioc->reply_free_q_dma); 2034824a1566SKashyap Desai sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ; 2035824a1566SKashyap Desai ioc_info(mrioc, 2036824a1566SKashyap Desai "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n", 2037824a1566SKashyap Desai mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSEBUF_SZ, 2038824a1566SKashyap Desai (sz / 1024), (unsigned long long)mrioc->sense_buf_dma); 2039824a1566SKashyap Desai sz = mrioc->sense_buf_q_sz * 8; 2040824a1566SKashyap Desai ioc_info(mrioc, 2041824a1566SKashyap Desai "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n", 2042824a1566SKashyap Desai mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024), 2043824a1566SKashyap Desai (unsigned long long)mrioc->sense_buf_q_dma); 2044824a1566SKashyap Desai 2045824a1566SKashyap Desai /* initialize Reply buffer Queue */ 2046824a1566SKashyap Desai for (i = 0, phy_addr = mrioc->reply_buf_dma; 2047824a1566SKashyap Desai i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->facts.reply_sz) 2048824a1566SKashyap Desai mrioc->reply_free_q[i] = cpu_to_le64(phy_addr); 2049824a1566SKashyap Desai mrioc->reply_free_q[i] = cpu_to_le64(0); 2050824a1566SKashyap Desai 2051824a1566SKashyap Desai /* initialize Sense Buffer Queue */ 2052824a1566SKashyap Desai for (i = 0, phy_addr = mrioc->sense_buf_dma; 2053824a1566SKashyap Desai i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSEBUF_SZ) 2054824a1566SKashyap Desai mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr); 2055824a1566SKashyap Desai mrioc->sense_buf_q[i] = cpu_to_le64(0); 2056824a1566SKashyap Desai return retval; 2057824a1566SKashyap Desai 2058824a1566SKashyap Desai out_failed: 2059824a1566SKashyap Desai retval = -1; 2060824a1566SKashyap Desai return retval; 2061824a1566SKashyap Desai } 2062824a1566SKashyap Desai 2063824a1566SKashyap Desai /** 2064824a1566SKashyap Desai * mpi3mr_issue_iocinit - Send IOC Init 2065824a1566SKashyap Desai * @mrioc: Adapter instance reference 2066824a1566SKashyap Desai * 2067824a1566SKashyap Desai * Issue IOC Init MPI request through admin queue and wait for 2068824a1566SKashyap Desai * the completion of it or time out. 2069824a1566SKashyap Desai * 2070824a1566SKashyap Desai * Return: 0 on success, non-zero on failures. 2071824a1566SKashyap Desai */ 2072824a1566SKashyap Desai static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc) 2073824a1566SKashyap Desai { 2074824a1566SKashyap Desai struct mpi3_ioc_init_request iocinit_req; 2075824a1566SKashyap Desai struct mpi3_driver_info_layout *drv_info; 2076824a1566SKashyap Desai dma_addr_t data_dma; 2077824a1566SKashyap Desai u32 data_len = sizeof(*drv_info); 2078824a1566SKashyap Desai int retval = 0; 2079824a1566SKashyap Desai ktime_t current_time; 2080824a1566SKashyap Desai 2081824a1566SKashyap Desai drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, 2082824a1566SKashyap Desai GFP_KERNEL); 2083824a1566SKashyap Desai if (!drv_info) { 2084824a1566SKashyap Desai retval = -1; 2085824a1566SKashyap Desai goto out; 2086824a1566SKashyap Desai } 2087824a1566SKashyap Desai drv_info->information_length = cpu_to_le32(data_len); 2088824a1566SKashyap Desai strncpy(drv_info->driver_signature, "Broadcom", sizeof(drv_info->driver_signature)); 2089824a1566SKashyap Desai strncpy(drv_info->os_name, utsname()->sysname, sizeof(drv_info->os_name)); 2090824a1566SKashyap Desai drv_info->os_name[sizeof(drv_info->os_name) - 1] = 0; 2091824a1566SKashyap Desai strncpy(drv_info->os_version, utsname()->release, sizeof(drv_info->os_version)); 2092824a1566SKashyap Desai drv_info->os_version[sizeof(drv_info->os_version) - 1] = 0; 2093824a1566SKashyap Desai strncpy(drv_info->driver_name, MPI3MR_DRIVER_NAME, sizeof(drv_info->driver_name)); 2094824a1566SKashyap Desai strncpy(drv_info->driver_version, MPI3MR_DRIVER_VERSION, sizeof(drv_info->driver_version)); 2095824a1566SKashyap Desai strncpy(drv_info->driver_release_date, MPI3MR_DRIVER_RELDATE, sizeof(drv_info->driver_release_date)); 2096824a1566SKashyap Desai drv_info->driver_capabilities = 0; 2097824a1566SKashyap Desai memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info, 2098824a1566SKashyap Desai sizeof(mrioc->driver_info)); 2099824a1566SKashyap Desai 2100824a1566SKashyap Desai memset(&iocinit_req, 0, sizeof(iocinit_req)); 2101824a1566SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 2102824a1566SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 2103824a1566SKashyap Desai retval = -1; 2104824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCInit: Init command is in use\n"); 2105824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2106824a1566SKashyap Desai goto out; 2107824a1566SKashyap Desai } 2108824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 2109824a1566SKashyap Desai mrioc->init_cmds.is_waiting = 1; 2110824a1566SKashyap Desai mrioc->init_cmds.callback = NULL; 2111824a1566SKashyap Desai iocinit_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 2112824a1566SKashyap Desai iocinit_req.function = MPI3_FUNCTION_IOC_INIT; 2113824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.dev = MPI3_VERSION_DEV; 2114824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.unit = MPI3_VERSION_UNIT; 2115824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.major = MPI3_VERSION_MAJOR; 2116824a1566SKashyap Desai iocinit_req.mpi_version.mpi3_version.minor = MPI3_VERSION_MINOR; 2117824a1566SKashyap Desai iocinit_req.who_init = MPI3_WHOINIT_HOST_DRIVER; 2118824a1566SKashyap Desai iocinit_req.reply_free_queue_depth = cpu_to_le16(mrioc->reply_free_qsz); 2119824a1566SKashyap Desai iocinit_req.reply_free_queue_address = 2120824a1566SKashyap Desai cpu_to_le64(mrioc->reply_free_q_dma); 2121824a1566SKashyap Desai iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSEBUF_SZ); 2122824a1566SKashyap Desai iocinit_req.sense_buffer_free_queue_depth = 2123824a1566SKashyap Desai cpu_to_le16(mrioc->sense_buf_q_sz); 2124824a1566SKashyap Desai iocinit_req.sense_buffer_free_queue_address = 2125824a1566SKashyap Desai cpu_to_le64(mrioc->sense_buf_q_dma); 2126824a1566SKashyap Desai iocinit_req.driver_information_address = cpu_to_le64(data_dma); 2127824a1566SKashyap Desai 2128824a1566SKashyap Desai current_time = ktime_get_real(); 2129824a1566SKashyap Desai iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time)); 2130824a1566SKashyap Desai 2131824a1566SKashyap Desai init_completion(&mrioc->init_cmds.done); 2132824a1566SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &iocinit_req, 2133824a1566SKashyap Desai sizeof(iocinit_req), 1); 2134824a1566SKashyap Desai if (retval) { 2135824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n"); 2136824a1566SKashyap Desai goto out_unlock; 2137824a1566SKashyap Desai } 2138824a1566SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 2139824a1566SKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 2140824a1566SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 2141824a1566SKashyap Desai mpi3mr_set_diagsave(mrioc); 2142824a1566SKashyap Desai mpi3mr_issue_reset(mrioc, 2143824a1566SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 2144824a1566SKashyap Desai MPI3MR_RESET_FROM_IOCINIT_TIMEOUT); 2145824a1566SKashyap Desai mrioc->unrecoverable = 1; 2146824a1566SKashyap Desai ioc_err(mrioc, "Issue IOCInit: command timed out\n"); 2147824a1566SKashyap Desai retval = -1; 2148824a1566SKashyap Desai goto out_unlock; 2149824a1566SKashyap Desai } 2150824a1566SKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 2151824a1566SKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 2152824a1566SKashyap Desai ioc_err(mrioc, 2153824a1566SKashyap Desai "Issue IOCInit: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 2154824a1566SKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 2155824a1566SKashyap Desai mrioc->init_cmds.ioc_loginfo); 2156824a1566SKashyap Desai retval = -1; 2157824a1566SKashyap Desai goto out_unlock; 2158824a1566SKashyap Desai } 2159824a1566SKashyap Desai 2160824a1566SKashyap Desai out_unlock: 2161824a1566SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 2162824a1566SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2163824a1566SKashyap Desai 2164824a1566SKashyap Desai out: 2165824a1566SKashyap Desai if (drv_info) 2166824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info, 2167824a1566SKashyap Desai data_dma); 2168824a1566SKashyap Desai 2169824a1566SKashyap Desai return retval; 2170824a1566SKashyap Desai } 2171824a1566SKashyap Desai 2172824a1566SKashyap Desai /** 217313ef29eaSKashyap Desai * mpi3mr_unmask_events - Unmask events in event mask bitmap 217413ef29eaSKashyap Desai * @mrioc: Adapter instance reference 217513ef29eaSKashyap Desai * @event: MPI event ID 217613ef29eaSKashyap Desai * 217713ef29eaSKashyap Desai * Un mask the specific event by resetting the event_mask 217813ef29eaSKashyap Desai * bitmap. 217913ef29eaSKashyap Desai * 218013ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 218113ef29eaSKashyap Desai */ 218213ef29eaSKashyap Desai static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event) 218313ef29eaSKashyap Desai { 218413ef29eaSKashyap Desai u32 desired_event; 218513ef29eaSKashyap Desai u8 word; 218613ef29eaSKashyap Desai 218713ef29eaSKashyap Desai if (event >= 128) 218813ef29eaSKashyap Desai return; 218913ef29eaSKashyap Desai 219013ef29eaSKashyap Desai desired_event = (1 << (event % 32)); 219113ef29eaSKashyap Desai word = event / 32; 219213ef29eaSKashyap Desai 219313ef29eaSKashyap Desai mrioc->event_masks[word] &= ~desired_event; 219413ef29eaSKashyap Desai } 219513ef29eaSKashyap Desai 219613ef29eaSKashyap Desai /** 219713ef29eaSKashyap Desai * mpi3mr_issue_event_notification - Send event notification 219813ef29eaSKashyap Desai * @mrioc: Adapter instance reference 219913ef29eaSKashyap Desai * 220013ef29eaSKashyap Desai * Issue event notification MPI request through admin queue and 220113ef29eaSKashyap Desai * wait for the completion of it or time out. 220213ef29eaSKashyap Desai * 220313ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 220413ef29eaSKashyap Desai */ 220513ef29eaSKashyap Desai static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc) 220613ef29eaSKashyap Desai { 220713ef29eaSKashyap Desai struct mpi3_event_notification_request evtnotify_req; 220813ef29eaSKashyap Desai int retval = 0; 220913ef29eaSKashyap Desai u8 i; 221013ef29eaSKashyap Desai 221113ef29eaSKashyap Desai memset(&evtnotify_req, 0, sizeof(evtnotify_req)); 221213ef29eaSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 221313ef29eaSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 221413ef29eaSKashyap Desai retval = -1; 221513ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: Init command is in use\n"); 221613ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 221713ef29eaSKashyap Desai goto out; 221813ef29eaSKashyap Desai } 221913ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 222013ef29eaSKashyap Desai mrioc->init_cmds.is_waiting = 1; 222113ef29eaSKashyap Desai mrioc->init_cmds.callback = NULL; 222213ef29eaSKashyap Desai evtnotify_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 222313ef29eaSKashyap Desai evtnotify_req.function = MPI3_FUNCTION_EVENT_NOTIFICATION; 222413ef29eaSKashyap Desai for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 222513ef29eaSKashyap Desai evtnotify_req.event_masks[i] = 222613ef29eaSKashyap Desai cpu_to_le32(mrioc->event_masks[i]); 222713ef29eaSKashyap Desai init_completion(&mrioc->init_cmds.done); 222813ef29eaSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &evtnotify_req, 222913ef29eaSKashyap Desai sizeof(evtnotify_req), 1); 223013ef29eaSKashyap Desai if (retval) { 223113ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: Admin Post failed\n"); 223213ef29eaSKashyap Desai goto out_unlock; 223313ef29eaSKashyap Desai } 223413ef29eaSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 223513ef29eaSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 223613ef29eaSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 223713ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: command timed out\n"); 223813ef29eaSKashyap Desai mpi3mr_set_diagsave(mrioc); 223913ef29eaSKashyap Desai mpi3mr_issue_reset(mrioc, 224013ef29eaSKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 224113ef29eaSKashyap Desai MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT); 224213ef29eaSKashyap Desai mrioc->unrecoverable = 1; 224313ef29eaSKashyap Desai retval = -1; 224413ef29eaSKashyap Desai goto out_unlock; 224513ef29eaSKashyap Desai } 224613ef29eaSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 224713ef29eaSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 224813ef29eaSKashyap Desai ioc_err(mrioc, 224913ef29eaSKashyap Desai "Issue EvtNotify: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 225013ef29eaSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 225113ef29eaSKashyap Desai mrioc->init_cmds.ioc_loginfo); 225213ef29eaSKashyap Desai retval = -1; 225313ef29eaSKashyap Desai goto out_unlock; 225413ef29eaSKashyap Desai } 225513ef29eaSKashyap Desai 225613ef29eaSKashyap Desai out_unlock: 225713ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 225813ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 225913ef29eaSKashyap Desai out: 226013ef29eaSKashyap Desai return retval; 226113ef29eaSKashyap Desai } 226213ef29eaSKashyap Desai 226313ef29eaSKashyap Desai /** 226413ef29eaSKashyap Desai * mpi3mr_send_event_ack - Send event acknowledgment 226513ef29eaSKashyap Desai * @mrioc: Adapter instance reference 226613ef29eaSKashyap Desai * @event: MPI3 event ID 226713ef29eaSKashyap Desai * @event_ctx: Event context 226813ef29eaSKashyap Desai * 226913ef29eaSKashyap Desai * Send event acknowledgment through admin queue and wait for 227013ef29eaSKashyap Desai * it to complete. 227113ef29eaSKashyap Desai * 227213ef29eaSKashyap Desai * Return: 0 on success, non-zero on failures. 227313ef29eaSKashyap Desai */ 227413ef29eaSKashyap Desai int mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, 227513ef29eaSKashyap Desai u32 event_ctx) 227613ef29eaSKashyap Desai { 227713ef29eaSKashyap Desai struct mpi3_event_ack_request evtack_req; 227813ef29eaSKashyap Desai int retval = 0; 227913ef29eaSKashyap Desai 228013ef29eaSKashyap Desai memset(&evtack_req, 0, sizeof(evtack_req)); 228113ef29eaSKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 228213ef29eaSKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 228313ef29eaSKashyap Desai retval = -1; 228413ef29eaSKashyap Desai ioc_err(mrioc, "Send EvtAck: Init command is in use\n"); 228513ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 228613ef29eaSKashyap Desai goto out; 228713ef29eaSKashyap Desai } 228813ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 228913ef29eaSKashyap Desai mrioc->init_cmds.is_waiting = 1; 229013ef29eaSKashyap Desai mrioc->init_cmds.callback = NULL; 229113ef29eaSKashyap Desai evtack_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 229213ef29eaSKashyap Desai evtack_req.function = MPI3_FUNCTION_EVENT_ACK; 229313ef29eaSKashyap Desai evtack_req.event = event; 229413ef29eaSKashyap Desai evtack_req.event_context = cpu_to_le32(event_ctx); 229513ef29eaSKashyap Desai 229613ef29eaSKashyap Desai init_completion(&mrioc->init_cmds.done); 229713ef29eaSKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &evtack_req, 229813ef29eaSKashyap Desai sizeof(evtack_req), 1); 229913ef29eaSKashyap Desai if (retval) { 230013ef29eaSKashyap Desai ioc_err(mrioc, "Send EvtAck: Admin Post failed\n"); 230113ef29eaSKashyap Desai goto out_unlock; 230213ef29eaSKashyap Desai } 230313ef29eaSKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 230413ef29eaSKashyap Desai (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 230513ef29eaSKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 230613ef29eaSKashyap Desai ioc_err(mrioc, "Issue EvtNotify: command timed out\n"); 230713ef29eaSKashyap Desai mpi3mr_soft_reset_handler(mrioc, 230813ef29eaSKashyap Desai MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1); 230913ef29eaSKashyap Desai retval = -1; 231013ef29eaSKashyap Desai goto out_unlock; 231113ef29eaSKashyap Desai } 231213ef29eaSKashyap Desai if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 231313ef29eaSKashyap Desai != MPI3_IOCSTATUS_SUCCESS) { 231413ef29eaSKashyap Desai ioc_err(mrioc, 231513ef29eaSKashyap Desai "Send EvtAck: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", 231613ef29eaSKashyap Desai (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 231713ef29eaSKashyap Desai mrioc->init_cmds.ioc_loginfo); 231813ef29eaSKashyap Desai retval = -1; 231913ef29eaSKashyap Desai goto out_unlock; 232013ef29eaSKashyap Desai } 232113ef29eaSKashyap Desai 232213ef29eaSKashyap Desai out_unlock: 232313ef29eaSKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 232413ef29eaSKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 232513ef29eaSKashyap Desai out: 232613ef29eaSKashyap Desai return retval; 232713ef29eaSKashyap Desai } 232813ef29eaSKashyap Desai 232913ef29eaSKashyap Desai /** 2330824a1566SKashyap Desai * mpi3mr_alloc_chain_bufs - Allocate chain buffers 2331824a1566SKashyap Desai * @mrioc: Adapter instance reference 2332824a1566SKashyap Desai * 2333824a1566SKashyap Desai * Allocate chain buffers and set a bitmap to indicate free 2334824a1566SKashyap Desai * chain buffers. Chain buffers are used to pass the SGE 2335824a1566SKashyap Desai * information along with MPI3 SCSI IO requests for host I/O. 2336824a1566SKashyap Desai * 2337824a1566SKashyap Desai * Return: 0 on success, non-zero on failure 2338824a1566SKashyap Desai */ 2339824a1566SKashyap Desai static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc) 2340824a1566SKashyap Desai { 2341824a1566SKashyap Desai int retval = 0; 2342824a1566SKashyap Desai u32 sz, i; 2343824a1566SKashyap Desai u16 num_chains; 2344824a1566SKashyap Desai 2345824a1566SKashyap Desai num_chains = mrioc->max_host_ios / MPI3MR_CHAINBUF_FACTOR; 2346824a1566SKashyap Desai 2347824a1566SKashyap Desai mrioc->chain_buf_count = num_chains; 2348824a1566SKashyap Desai sz = sizeof(struct chain_element) * num_chains; 2349824a1566SKashyap Desai mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL); 2350824a1566SKashyap Desai if (!mrioc->chain_sgl_list) 2351824a1566SKashyap Desai goto out_failed; 2352824a1566SKashyap Desai 2353824a1566SKashyap Desai sz = MPI3MR_PAGE_SIZE_4K; 2354824a1566SKashyap Desai mrioc->chain_buf_pool = dma_pool_create("chain_buf pool", 2355824a1566SKashyap Desai &mrioc->pdev->dev, sz, 16, 0); 2356824a1566SKashyap Desai if (!mrioc->chain_buf_pool) { 2357824a1566SKashyap Desai ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n"); 2358824a1566SKashyap Desai goto out_failed; 2359824a1566SKashyap Desai } 2360824a1566SKashyap Desai 2361824a1566SKashyap Desai for (i = 0; i < num_chains; i++) { 2362824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr = 2363824a1566SKashyap Desai dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL, 2364824a1566SKashyap Desai &mrioc->chain_sgl_list[i].dma_addr); 2365824a1566SKashyap Desai 2366824a1566SKashyap Desai if (!mrioc->chain_sgl_list[i].addr) 2367824a1566SKashyap Desai goto out_failed; 2368824a1566SKashyap Desai } 2369824a1566SKashyap Desai mrioc->chain_bitmap_sz = num_chains / 8; 2370824a1566SKashyap Desai if (num_chains % 8) 2371824a1566SKashyap Desai mrioc->chain_bitmap_sz++; 2372824a1566SKashyap Desai mrioc->chain_bitmap = kzalloc(mrioc->chain_bitmap_sz, GFP_KERNEL); 2373824a1566SKashyap Desai if (!mrioc->chain_bitmap) 2374824a1566SKashyap Desai goto out_failed; 2375824a1566SKashyap Desai return retval; 2376824a1566SKashyap Desai out_failed: 2377824a1566SKashyap Desai retval = -1; 2378824a1566SKashyap Desai return retval; 2379824a1566SKashyap Desai } 2380824a1566SKashyap Desai 2381824a1566SKashyap Desai /** 2382023ab2a9SKashyap Desai * mpi3mr_port_enable_complete - Mark port enable complete 2383023ab2a9SKashyap Desai * @mrioc: Adapter instance reference 2384023ab2a9SKashyap Desai * @drv_cmd: Internal command tracker 2385023ab2a9SKashyap Desai * 2386023ab2a9SKashyap Desai * Call back for asynchronous port enable request sets the 2387023ab2a9SKashyap Desai * driver command to indicate port enable request is complete. 2388023ab2a9SKashyap Desai * 2389023ab2a9SKashyap Desai * Return: Nothing 2390023ab2a9SKashyap Desai */ 2391023ab2a9SKashyap Desai static void mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc, 2392023ab2a9SKashyap Desai struct mpi3mr_drv_cmd *drv_cmd) 2393023ab2a9SKashyap Desai { 2394023ab2a9SKashyap Desai drv_cmd->state = MPI3MR_CMD_NOTUSED; 2395023ab2a9SKashyap Desai drv_cmd->callback = NULL; 2396023ab2a9SKashyap Desai mrioc->scan_failed = drv_cmd->ioc_status; 2397023ab2a9SKashyap Desai mrioc->scan_started = 0; 2398023ab2a9SKashyap Desai } 2399023ab2a9SKashyap Desai 2400023ab2a9SKashyap Desai /** 2401023ab2a9SKashyap Desai * mpi3mr_issue_port_enable - Issue Port Enable 2402023ab2a9SKashyap Desai * @mrioc: Adapter instance reference 2403023ab2a9SKashyap Desai * @async: Flag to wait for completion or not 2404023ab2a9SKashyap Desai * 2405023ab2a9SKashyap Desai * Issue Port Enable MPI request through admin queue and if the 2406023ab2a9SKashyap Desai * async flag is not set wait for the completion of the port 2407023ab2a9SKashyap Desai * enable or time out. 2408023ab2a9SKashyap Desai * 2409023ab2a9SKashyap Desai * Return: 0 on success, non-zero on failures. 2410023ab2a9SKashyap Desai */ 2411023ab2a9SKashyap Desai int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async) 2412023ab2a9SKashyap Desai { 2413023ab2a9SKashyap Desai struct mpi3_port_enable_request pe_req; 2414023ab2a9SKashyap Desai int retval = 0; 2415023ab2a9SKashyap Desai u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT; 2416023ab2a9SKashyap Desai 2417023ab2a9SKashyap Desai memset(&pe_req, 0, sizeof(pe_req)); 2418023ab2a9SKashyap Desai mutex_lock(&mrioc->init_cmds.mutex); 2419023ab2a9SKashyap Desai if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 2420023ab2a9SKashyap Desai retval = -1; 2421023ab2a9SKashyap Desai ioc_err(mrioc, "Issue PortEnable: Init command is in use\n"); 2422023ab2a9SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2423023ab2a9SKashyap Desai goto out; 2424023ab2a9SKashyap Desai } 2425023ab2a9SKashyap Desai mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 2426023ab2a9SKashyap Desai if (async) { 2427023ab2a9SKashyap Desai mrioc->init_cmds.is_waiting = 0; 2428023ab2a9SKashyap Desai mrioc->init_cmds.callback = mpi3mr_port_enable_complete; 2429023ab2a9SKashyap Desai } else { 2430023ab2a9SKashyap Desai mrioc->init_cmds.is_waiting = 1; 2431023ab2a9SKashyap Desai mrioc->init_cmds.callback = NULL; 2432023ab2a9SKashyap Desai init_completion(&mrioc->init_cmds.done); 2433023ab2a9SKashyap Desai } 2434023ab2a9SKashyap Desai pe_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 2435023ab2a9SKashyap Desai pe_req.function = MPI3_FUNCTION_PORT_ENABLE; 2436023ab2a9SKashyap Desai 2437023ab2a9SKashyap Desai retval = mpi3mr_admin_request_post(mrioc, &pe_req, sizeof(pe_req), 1); 2438023ab2a9SKashyap Desai if (retval) { 2439023ab2a9SKashyap Desai ioc_err(mrioc, "Issue PortEnable: Admin Post failed\n"); 2440023ab2a9SKashyap Desai goto out_unlock; 2441023ab2a9SKashyap Desai } 2442023ab2a9SKashyap Desai if (!async) { 2443023ab2a9SKashyap Desai wait_for_completion_timeout(&mrioc->init_cmds.done, 2444023ab2a9SKashyap Desai (pe_timeout * HZ)); 2445023ab2a9SKashyap Desai if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 2446023ab2a9SKashyap Desai ioc_err(mrioc, "Issue PortEnable: command timed out\n"); 2447023ab2a9SKashyap Desai retval = -1; 2448023ab2a9SKashyap Desai mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR; 2449023ab2a9SKashyap Desai mpi3mr_set_diagsave(mrioc); 2450023ab2a9SKashyap Desai mpi3mr_issue_reset(mrioc, 2451023ab2a9SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, 2452023ab2a9SKashyap Desai MPI3MR_RESET_FROM_PE_TIMEOUT); 2453023ab2a9SKashyap Desai mrioc->unrecoverable = 1; 2454023ab2a9SKashyap Desai goto out_unlock; 2455023ab2a9SKashyap Desai } 2456023ab2a9SKashyap Desai mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds); 2457023ab2a9SKashyap Desai } 2458023ab2a9SKashyap Desai out_unlock: 2459023ab2a9SKashyap Desai mutex_unlock(&mrioc->init_cmds.mutex); 2460023ab2a9SKashyap Desai out: 2461023ab2a9SKashyap Desai return retval; 2462023ab2a9SKashyap Desai } 2463023ab2a9SKashyap Desai 2464023ab2a9SKashyap Desai /** 2465824a1566SKashyap Desai * mpi3mr_cleanup_resources - Free PCI resources 2466824a1566SKashyap Desai * @mrioc: Adapter instance reference 2467824a1566SKashyap Desai * 2468824a1566SKashyap Desai * Unmap PCI device memory and disable PCI device. 2469824a1566SKashyap Desai * 2470824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 2471824a1566SKashyap Desai */ 2472824a1566SKashyap Desai void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc) 2473824a1566SKashyap Desai { 2474824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 2475824a1566SKashyap Desai 2476824a1566SKashyap Desai mpi3mr_cleanup_isr(mrioc); 2477824a1566SKashyap Desai 2478824a1566SKashyap Desai if (mrioc->sysif_regs) { 2479824a1566SKashyap Desai iounmap((void __iomem *)mrioc->sysif_regs); 2480824a1566SKashyap Desai mrioc->sysif_regs = NULL; 2481824a1566SKashyap Desai } 2482824a1566SKashyap Desai 2483824a1566SKashyap Desai if (pci_is_enabled(pdev)) { 2484824a1566SKashyap Desai if (mrioc->bars) 2485824a1566SKashyap Desai pci_release_selected_regions(pdev, mrioc->bars); 2486824a1566SKashyap Desai pci_disable_device(pdev); 2487824a1566SKashyap Desai } 2488824a1566SKashyap Desai } 2489824a1566SKashyap Desai 2490824a1566SKashyap Desai /** 2491824a1566SKashyap Desai * mpi3mr_setup_resources - Enable PCI resources 2492824a1566SKashyap Desai * @mrioc: Adapter instance reference 2493824a1566SKashyap Desai * 2494824a1566SKashyap Desai * Enable PCI device memory, MSI-x registers and set DMA mask. 2495824a1566SKashyap Desai * 2496824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 2497824a1566SKashyap Desai */ 2498824a1566SKashyap Desai int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc) 2499824a1566SKashyap Desai { 2500824a1566SKashyap Desai struct pci_dev *pdev = mrioc->pdev; 2501824a1566SKashyap Desai u32 memap_sz = 0; 2502824a1566SKashyap Desai int i, retval = 0, capb = 0; 2503824a1566SKashyap Desai u16 message_control; 2504824a1566SKashyap Desai u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask : 2505824a1566SKashyap Desai (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) && 2506824a1566SKashyap Desai (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32)); 2507824a1566SKashyap Desai 2508824a1566SKashyap Desai if (pci_enable_device_mem(pdev)) { 2509824a1566SKashyap Desai ioc_err(mrioc, "pci_enable_device_mem: failed\n"); 2510824a1566SKashyap Desai retval = -ENODEV; 2511824a1566SKashyap Desai goto out_failed; 2512824a1566SKashyap Desai } 2513824a1566SKashyap Desai 2514824a1566SKashyap Desai capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX); 2515824a1566SKashyap Desai if (!capb) { 2516824a1566SKashyap Desai ioc_err(mrioc, "Unable to find MSI-X Capabilities\n"); 2517824a1566SKashyap Desai retval = -ENODEV; 2518824a1566SKashyap Desai goto out_failed; 2519824a1566SKashyap Desai } 2520824a1566SKashyap Desai mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); 2521824a1566SKashyap Desai 2522824a1566SKashyap Desai if (pci_request_selected_regions(pdev, mrioc->bars, 2523824a1566SKashyap Desai mrioc->driver_name)) { 2524824a1566SKashyap Desai ioc_err(mrioc, "pci_request_selected_regions: failed\n"); 2525824a1566SKashyap Desai retval = -ENODEV; 2526824a1566SKashyap Desai goto out_failed; 2527824a1566SKashyap Desai } 2528824a1566SKashyap Desai 2529824a1566SKashyap Desai for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) { 2530824a1566SKashyap Desai if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { 2531824a1566SKashyap Desai mrioc->sysif_regs_phys = pci_resource_start(pdev, i); 2532824a1566SKashyap Desai memap_sz = pci_resource_len(pdev, i); 2533824a1566SKashyap Desai mrioc->sysif_regs = 2534824a1566SKashyap Desai ioremap(mrioc->sysif_regs_phys, memap_sz); 2535824a1566SKashyap Desai break; 2536824a1566SKashyap Desai } 2537824a1566SKashyap Desai } 2538824a1566SKashyap Desai 2539824a1566SKashyap Desai pci_set_master(pdev); 2540824a1566SKashyap Desai 2541824a1566SKashyap Desai retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask); 2542824a1566SKashyap Desai if (retval) { 2543824a1566SKashyap Desai if (dma_mask != DMA_BIT_MASK(32)) { 2544824a1566SKashyap Desai ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n"); 2545824a1566SKashyap Desai dma_mask = DMA_BIT_MASK(32); 2546824a1566SKashyap Desai retval = dma_set_mask_and_coherent(&pdev->dev, 2547824a1566SKashyap Desai dma_mask); 2548824a1566SKashyap Desai } 2549824a1566SKashyap Desai if (retval) { 2550824a1566SKashyap Desai mrioc->dma_mask = 0; 2551824a1566SKashyap Desai ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n"); 2552824a1566SKashyap Desai goto out_failed; 2553824a1566SKashyap Desai } 2554824a1566SKashyap Desai } 2555824a1566SKashyap Desai mrioc->dma_mask = dma_mask; 2556824a1566SKashyap Desai 2557824a1566SKashyap Desai if (!mrioc->sysif_regs) { 2558824a1566SKashyap Desai ioc_err(mrioc, 2559824a1566SKashyap Desai "Unable to map adapter memory or resource not found\n"); 2560824a1566SKashyap Desai retval = -EINVAL; 2561824a1566SKashyap Desai goto out_failed; 2562824a1566SKashyap Desai } 2563824a1566SKashyap Desai 2564824a1566SKashyap Desai pci_read_config_word(pdev, capb + 2, &message_control); 2565824a1566SKashyap Desai mrioc->msix_count = (message_control & 0x3FF) + 1; 2566824a1566SKashyap Desai 2567824a1566SKashyap Desai pci_save_state(pdev); 2568824a1566SKashyap Desai 2569824a1566SKashyap Desai pci_set_drvdata(pdev, mrioc->shost); 2570824a1566SKashyap Desai 2571824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 2572824a1566SKashyap Desai 2573824a1566SKashyap Desai ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n", 2574824a1566SKashyap Desai (unsigned long long)mrioc->sysif_regs_phys, 2575824a1566SKashyap Desai mrioc->sysif_regs, memap_sz); 2576824a1566SKashyap Desai ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n", 2577824a1566SKashyap Desai mrioc->msix_count); 2578824a1566SKashyap Desai return retval; 2579824a1566SKashyap Desai 2580824a1566SKashyap Desai out_failed: 2581824a1566SKashyap Desai mpi3mr_cleanup_resources(mrioc); 2582824a1566SKashyap Desai return retval; 2583824a1566SKashyap Desai } 2584824a1566SKashyap Desai 2585824a1566SKashyap Desai /** 2586824a1566SKashyap Desai * mpi3mr_init_ioc - Initialize the controller 2587824a1566SKashyap Desai * @mrioc: Adapter instance reference 2588*fb9b0457SKashyap Desai * @re_init: Flag to indicate is this fresh init or re-init 2589824a1566SKashyap Desai * 2590824a1566SKashyap Desai * This the controller initialization routine, executed either 2591824a1566SKashyap Desai * after soft reset or from pci probe callback. 2592824a1566SKashyap Desai * Setup the required resources, memory map the controller 2593824a1566SKashyap Desai * registers, create admin and operational reply queue pairs, 2594824a1566SKashyap Desai * allocate required memory for reply pool, sense buffer pool, 2595824a1566SKashyap Desai * issue IOC init request to the firmware, unmask the events and 2596824a1566SKashyap Desai * issue port enable to discover SAS/SATA/NVMe devies and RAID 2597824a1566SKashyap Desai * volumes. 2598824a1566SKashyap Desai * 2599824a1566SKashyap Desai * Return: 0 on success and non-zero on failure. 2600824a1566SKashyap Desai */ 2601*fb9b0457SKashyap Desai int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 re_init) 2602824a1566SKashyap Desai { 2603824a1566SKashyap Desai int retval = 0; 2604824a1566SKashyap Desai enum mpi3mr_iocstate ioc_state; 2605824a1566SKashyap Desai u64 base_info; 2606824a1566SKashyap Desai u32 timeout; 260713ef29eaSKashyap Desai u32 ioc_status, ioc_config, i; 2608824a1566SKashyap Desai struct mpi3_ioc_facts_data facts_data; 2609824a1566SKashyap Desai 2610824a1566SKashyap Desai mrioc->change_count = 0; 2611*fb9b0457SKashyap Desai if (!re_init) { 2612824a1566SKashyap Desai mrioc->cpu_count = num_online_cpus(); 2613824a1566SKashyap Desai retval = mpi3mr_setup_resources(mrioc); 2614824a1566SKashyap Desai if (retval) { 2615824a1566SKashyap Desai ioc_err(mrioc, "Failed to setup resources:error %d\n", 2616824a1566SKashyap Desai retval); 2617824a1566SKashyap Desai goto out_nocleanup; 2618824a1566SKashyap Desai } 2619*fb9b0457SKashyap Desai } 2620*fb9b0457SKashyap Desai 2621824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 2622824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 2623824a1566SKashyap Desai 2624824a1566SKashyap Desai ioc_info(mrioc, "SOD status %x configuration %x\n", 2625824a1566SKashyap Desai ioc_status, ioc_config); 2626824a1566SKashyap Desai 2627824a1566SKashyap Desai base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information); 2628824a1566SKashyap Desai ioc_info(mrioc, "SOD base_info %llx\n", base_info); 2629824a1566SKashyap Desai 2630824a1566SKashyap Desai /*The timeout value is in 2sec unit, changing it to seconds*/ 2631824a1566SKashyap Desai mrioc->ready_timeout = 2632824a1566SKashyap Desai ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >> 2633824a1566SKashyap Desai MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2; 2634824a1566SKashyap Desai 2635824a1566SKashyap Desai ioc_info(mrioc, "IOC ready timeout %d\n", mrioc->ready_timeout); 2636824a1566SKashyap Desai 2637824a1566SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 2638824a1566SKashyap Desai ioc_info(mrioc, "IOC in %s state during detection\n", 2639824a1566SKashyap Desai mpi3mr_iocstate_name(ioc_state)); 2640824a1566SKashyap Desai 2641824a1566SKashyap Desai if (ioc_state == MRIOC_STATE_BECOMING_READY || 2642824a1566SKashyap Desai ioc_state == MRIOC_STATE_RESET_REQUESTED) { 2643824a1566SKashyap Desai timeout = mrioc->ready_timeout * 10; 2644824a1566SKashyap Desai do { 2645824a1566SKashyap Desai msleep(100); 2646824a1566SKashyap Desai } while (--timeout); 2647824a1566SKashyap Desai 2648824a1566SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 2649824a1566SKashyap Desai ioc_info(mrioc, 2650824a1566SKashyap Desai "IOC in %s state after waiting for reset time\n", 2651824a1566SKashyap Desai mpi3mr_iocstate_name(ioc_state)); 2652824a1566SKashyap Desai } 2653824a1566SKashyap Desai 2654824a1566SKashyap Desai if (ioc_state == MRIOC_STATE_READY) { 2655824a1566SKashyap Desai retval = mpi3mr_issue_and_process_mur(mrioc, 2656824a1566SKashyap Desai MPI3MR_RESET_FROM_BRINGUP); 2657824a1566SKashyap Desai if (retval) { 2658824a1566SKashyap Desai ioc_err(mrioc, "Failed to MU reset IOC error %d\n", 2659824a1566SKashyap Desai retval); 2660824a1566SKashyap Desai } 2661824a1566SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 2662824a1566SKashyap Desai } 2663824a1566SKashyap Desai if (ioc_state != MRIOC_STATE_RESET) { 2664824a1566SKashyap Desai mpi3mr_print_fault_info(mrioc); 2665824a1566SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 2666824a1566SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, 2667824a1566SKashyap Desai MPI3MR_RESET_FROM_BRINGUP); 2668824a1566SKashyap Desai if (retval) { 2669824a1566SKashyap Desai ioc_err(mrioc, 2670824a1566SKashyap Desai "%s :Failed to soft reset IOC error %d\n", 2671824a1566SKashyap Desai __func__, retval); 2672824a1566SKashyap Desai goto out_failed; 2673824a1566SKashyap Desai } 2674824a1566SKashyap Desai } 2675824a1566SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 2676824a1566SKashyap Desai if (ioc_state != MRIOC_STATE_RESET) { 2677824a1566SKashyap Desai ioc_err(mrioc, "Cannot bring IOC to reset state\n"); 2678824a1566SKashyap Desai goto out_failed; 2679824a1566SKashyap Desai } 2680824a1566SKashyap Desai 2681824a1566SKashyap Desai retval = mpi3mr_setup_admin_qpair(mrioc); 2682824a1566SKashyap Desai if (retval) { 2683824a1566SKashyap Desai ioc_err(mrioc, "Failed to setup admin Qs: error %d\n", 2684824a1566SKashyap Desai retval); 2685824a1566SKashyap Desai goto out_failed; 2686824a1566SKashyap Desai } 2687824a1566SKashyap Desai 2688824a1566SKashyap Desai retval = mpi3mr_bring_ioc_ready(mrioc); 2689824a1566SKashyap Desai if (retval) { 2690824a1566SKashyap Desai ioc_err(mrioc, "Failed to bring ioc ready: error %d\n", 2691824a1566SKashyap Desai retval); 2692824a1566SKashyap Desai goto out_failed; 2693824a1566SKashyap Desai } 2694824a1566SKashyap Desai 2695*fb9b0457SKashyap Desai if (!re_init) { 2696824a1566SKashyap Desai retval = mpi3mr_setup_isr(mrioc, 1); 2697824a1566SKashyap Desai if (retval) { 2698824a1566SKashyap Desai ioc_err(mrioc, "Failed to setup ISR error %d\n", 2699824a1566SKashyap Desai retval); 2700824a1566SKashyap Desai goto out_failed; 2701824a1566SKashyap Desai } 2702*fb9b0457SKashyap Desai } else 2703*fb9b0457SKashyap Desai mpi3mr_ioc_enable_intr(mrioc); 2704824a1566SKashyap Desai 2705824a1566SKashyap Desai retval = mpi3mr_issue_iocfacts(mrioc, &facts_data); 2706824a1566SKashyap Desai if (retval) { 2707824a1566SKashyap Desai ioc_err(mrioc, "Failed to Issue IOC Facts %d\n", 2708824a1566SKashyap Desai retval); 2709824a1566SKashyap Desai goto out_failed; 2710824a1566SKashyap Desai } 2711824a1566SKashyap Desai 2712824a1566SKashyap Desai mpi3mr_process_factsdata(mrioc, &facts_data); 2713*fb9b0457SKashyap Desai if (!re_init) { 2714824a1566SKashyap Desai retval = mpi3mr_check_reset_dma_mask(mrioc); 2715824a1566SKashyap Desai if (retval) { 2716824a1566SKashyap Desai ioc_err(mrioc, "Resetting dma mask failed %d\n", 2717824a1566SKashyap Desai retval); 2718824a1566SKashyap Desai goto out_failed; 2719824a1566SKashyap Desai } 2720*fb9b0457SKashyap Desai } 2721824a1566SKashyap Desai 2722824a1566SKashyap Desai retval = mpi3mr_alloc_reply_sense_bufs(mrioc); 2723824a1566SKashyap Desai if (retval) { 2724824a1566SKashyap Desai ioc_err(mrioc, 2725824a1566SKashyap Desai "%s :Failed to allocated reply sense buffers %d\n", 2726824a1566SKashyap Desai __func__, retval); 2727824a1566SKashyap Desai goto out_failed; 2728824a1566SKashyap Desai } 2729824a1566SKashyap Desai 2730*fb9b0457SKashyap Desai if (!re_init) { 2731824a1566SKashyap Desai retval = mpi3mr_alloc_chain_bufs(mrioc); 2732824a1566SKashyap Desai if (retval) { 2733824a1566SKashyap Desai ioc_err(mrioc, "Failed to allocated chain buffers %d\n", 2734824a1566SKashyap Desai retval); 2735824a1566SKashyap Desai goto out_failed; 2736824a1566SKashyap Desai } 2737*fb9b0457SKashyap Desai } 2738824a1566SKashyap Desai 2739824a1566SKashyap Desai retval = mpi3mr_issue_iocinit(mrioc); 2740824a1566SKashyap Desai if (retval) { 2741824a1566SKashyap Desai ioc_err(mrioc, "Failed to Issue IOC Init %d\n", 2742824a1566SKashyap Desai retval); 2743824a1566SKashyap Desai goto out_failed; 2744824a1566SKashyap Desai } 2745824a1566SKashyap Desai mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs; 2746824a1566SKashyap Desai writel(mrioc->reply_free_queue_host_index, 2747824a1566SKashyap Desai &mrioc->sysif_regs->reply_free_host_index); 2748824a1566SKashyap Desai 2749824a1566SKashyap Desai mrioc->sbq_host_index = mrioc->num_sense_bufs; 2750824a1566SKashyap Desai writel(mrioc->sbq_host_index, 2751824a1566SKashyap Desai &mrioc->sysif_regs->sense_buffer_free_host_index); 2752824a1566SKashyap Desai 2753*fb9b0457SKashyap Desai if (!re_init) { 2754824a1566SKashyap Desai retval = mpi3mr_setup_isr(mrioc, 0); 2755824a1566SKashyap Desai if (retval) { 2756824a1566SKashyap Desai ioc_err(mrioc, "Failed to re-setup ISR, error %d\n", 2757824a1566SKashyap Desai retval); 2758824a1566SKashyap Desai goto out_failed; 2759824a1566SKashyap Desai } 2760*fb9b0457SKashyap Desai } 2761824a1566SKashyap Desai 2762c9566231SKashyap Desai retval = mpi3mr_create_op_queues(mrioc); 2763c9566231SKashyap Desai if (retval) { 2764c9566231SKashyap Desai ioc_err(mrioc, "Failed to create OpQueues error %d\n", 2765c9566231SKashyap Desai retval); 2766c9566231SKashyap Desai goto out_failed; 2767c9566231SKashyap Desai } 2768c9566231SKashyap Desai 2769*fb9b0457SKashyap Desai if (re_init && 2770*fb9b0457SKashyap Desai (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q)) { 2771*fb9b0457SKashyap Desai ioc_err(mrioc, 2772*fb9b0457SKashyap Desai "Cannot create minimum number of OpQueues expected:%d created:%d\n", 2773*fb9b0457SKashyap Desai mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q); 2774*fb9b0457SKashyap Desai goto out_failed; 2775*fb9b0457SKashyap Desai } 2776*fb9b0457SKashyap Desai 277713ef29eaSKashyap Desai for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 277813ef29eaSKashyap Desai mrioc->event_masks[i] = -1; 277913ef29eaSKashyap Desai 278013ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED); 278113ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED); 278213ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE); 278313ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE); 278413ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST); 278513ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY); 278613ef29eaSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR); 2787e36710dcSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE); 27888e653455SKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST); 27898e653455SKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION); 2790e36710dcSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT); 2791e36710dcSKashyap Desai mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE); 279213ef29eaSKashyap Desai 279313ef29eaSKashyap Desai retval = mpi3mr_issue_event_notification(mrioc); 279413ef29eaSKashyap Desai if (retval) { 279513ef29eaSKashyap Desai ioc_err(mrioc, "Failed to issue event notification %d\n", 279613ef29eaSKashyap Desai retval); 279713ef29eaSKashyap Desai goto out_failed; 279813ef29eaSKashyap Desai } 279913ef29eaSKashyap Desai 2800*fb9b0457SKashyap Desai if (re_init) { 2801*fb9b0457SKashyap Desai ioc_info(mrioc, "Issuing Port Enable\n"); 2802*fb9b0457SKashyap Desai retval = mpi3mr_issue_port_enable(mrioc, 0); 2803*fb9b0457SKashyap Desai if (retval) { 2804*fb9b0457SKashyap Desai ioc_err(mrioc, "Failed to issue port enable %d\n", 2805*fb9b0457SKashyap Desai retval); 2806*fb9b0457SKashyap Desai goto out_failed; 2807*fb9b0457SKashyap Desai } 2808*fb9b0457SKashyap Desai } 2809824a1566SKashyap Desai return retval; 2810824a1566SKashyap Desai 2811824a1566SKashyap Desai out_failed: 2812*fb9b0457SKashyap Desai mpi3mr_cleanup_ioc(mrioc, re_init); 2813824a1566SKashyap Desai out_nocleanup: 2814824a1566SKashyap Desai return retval; 2815824a1566SKashyap Desai } 2816824a1566SKashyap Desai 2817824a1566SKashyap Desai /** 2818*fb9b0457SKashyap Desai * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's 2819*fb9b0457SKashyap Desai * segments 2820*fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 2821*fb9b0457SKashyap Desai * @qidx: Operational reply queue index 2822*fb9b0457SKashyap Desai * 2823*fb9b0457SKashyap Desai * Return: Nothing. 2824*fb9b0457SKashyap Desai */ 2825*fb9b0457SKashyap Desai static void mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx) 2826*fb9b0457SKashyap Desai { 2827*fb9b0457SKashyap Desai struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; 2828*fb9b0457SKashyap Desai struct segments *segments; 2829*fb9b0457SKashyap Desai int i, size; 2830*fb9b0457SKashyap Desai 2831*fb9b0457SKashyap Desai if (!op_reply_q->q_segments) 2832*fb9b0457SKashyap Desai return; 2833*fb9b0457SKashyap Desai 2834*fb9b0457SKashyap Desai size = op_reply_q->segment_qd * mrioc->op_reply_desc_sz; 2835*fb9b0457SKashyap Desai segments = op_reply_q->q_segments; 2836*fb9b0457SKashyap Desai for (i = 0; i < op_reply_q->num_segments; i++) 2837*fb9b0457SKashyap Desai memset(segments[i].segment, 0, size); 2838*fb9b0457SKashyap Desai } 2839*fb9b0457SKashyap Desai 2840*fb9b0457SKashyap Desai /** 2841*fb9b0457SKashyap Desai * mpi3mr_memset_op_req_q_buffers - memset the operational request queue's 2842*fb9b0457SKashyap Desai * segments 2843*fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 2844*fb9b0457SKashyap Desai * @qidx: Operational request queue index 2845*fb9b0457SKashyap Desai * 2846*fb9b0457SKashyap Desai * Return: Nothing. 2847*fb9b0457SKashyap Desai */ 2848*fb9b0457SKashyap Desai static void mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx) 2849*fb9b0457SKashyap Desai { 2850*fb9b0457SKashyap Desai struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx; 2851*fb9b0457SKashyap Desai struct segments *segments; 2852*fb9b0457SKashyap Desai int i, size; 2853*fb9b0457SKashyap Desai 2854*fb9b0457SKashyap Desai if (!op_req_q->q_segments) 2855*fb9b0457SKashyap Desai return; 2856*fb9b0457SKashyap Desai 2857*fb9b0457SKashyap Desai size = op_req_q->segment_qd * mrioc->facts.op_req_sz; 2858*fb9b0457SKashyap Desai segments = op_req_q->q_segments; 2859*fb9b0457SKashyap Desai for (i = 0; i < op_req_q->num_segments; i++) 2860*fb9b0457SKashyap Desai memset(segments[i].segment, 0, size); 2861*fb9b0457SKashyap Desai } 2862*fb9b0457SKashyap Desai 2863*fb9b0457SKashyap Desai /** 2864*fb9b0457SKashyap Desai * mpi3mr_memset_buffers - memset memory for a controller 2865*fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 2866*fb9b0457SKashyap Desai * 2867*fb9b0457SKashyap Desai * clear all the memory allocated for a controller, typically 2868*fb9b0457SKashyap Desai * called post reset to reuse the memory allocated during the 2869*fb9b0457SKashyap Desai * controller init. 2870*fb9b0457SKashyap Desai * 2871*fb9b0457SKashyap Desai * Return: Nothing. 2872*fb9b0457SKashyap Desai */ 2873*fb9b0457SKashyap Desai static void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) 2874*fb9b0457SKashyap Desai { 2875*fb9b0457SKashyap Desai u16 i; 2876*fb9b0457SKashyap Desai 2877*fb9b0457SKashyap Desai memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz); 2878*fb9b0457SKashyap Desai memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz); 2879*fb9b0457SKashyap Desai 2880*fb9b0457SKashyap Desai memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply)); 2881*fb9b0457SKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) 2882*fb9b0457SKashyap Desai memset(mrioc->dev_rmhs_cmds[i].reply, 0, 2883*fb9b0457SKashyap Desai sizeof(*mrioc->dev_rmhs_cmds[i].reply)); 2884*fb9b0457SKashyap Desai memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); 2885*fb9b0457SKashyap Desai memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); 2886*fb9b0457SKashyap Desai 2887*fb9b0457SKashyap Desai for (i = 0; i < mrioc->num_queues; i++) { 2888*fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].qid = 0; 2889*fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].ci = 0; 2890*fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].num_replies = 0; 2891*fb9b0457SKashyap Desai mrioc->op_reply_qinfo[i].ephase = 0; 2892*fb9b0457SKashyap Desai mpi3mr_memset_op_reply_q_buffers(mrioc, i); 2893*fb9b0457SKashyap Desai 2894*fb9b0457SKashyap Desai mrioc->req_qinfo[i].ci = 0; 2895*fb9b0457SKashyap Desai mrioc->req_qinfo[i].pi = 0; 2896*fb9b0457SKashyap Desai mrioc->req_qinfo[i].num_requests = 0; 2897*fb9b0457SKashyap Desai mrioc->req_qinfo[i].qid = 0; 2898*fb9b0457SKashyap Desai mrioc->req_qinfo[i].reply_qid = 0; 2899*fb9b0457SKashyap Desai spin_lock_init(&mrioc->req_qinfo[i].q_lock); 2900*fb9b0457SKashyap Desai mpi3mr_memset_op_req_q_buffers(mrioc, i); 2901*fb9b0457SKashyap Desai } 2902*fb9b0457SKashyap Desai } 2903*fb9b0457SKashyap Desai 2904*fb9b0457SKashyap Desai /** 2905824a1566SKashyap Desai * mpi3mr_free_mem - Free memory allocated for a controller 2906824a1566SKashyap Desai * @mrioc: Adapter instance reference 2907824a1566SKashyap Desai * 2908824a1566SKashyap Desai * Free all the memory allocated for a controller. 2909824a1566SKashyap Desai * 2910824a1566SKashyap Desai * Return: Nothing. 2911824a1566SKashyap Desai */ 2912824a1566SKashyap Desai static void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) 2913824a1566SKashyap Desai { 2914824a1566SKashyap Desai u16 i; 2915824a1566SKashyap Desai struct mpi3mr_intr_info *intr_info; 2916824a1566SKashyap Desai 2917824a1566SKashyap Desai if (mrioc->sense_buf_pool) { 2918824a1566SKashyap Desai if (mrioc->sense_buf) 2919824a1566SKashyap Desai dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf, 2920824a1566SKashyap Desai mrioc->sense_buf_dma); 2921824a1566SKashyap Desai dma_pool_destroy(mrioc->sense_buf_pool); 2922824a1566SKashyap Desai mrioc->sense_buf = NULL; 2923824a1566SKashyap Desai mrioc->sense_buf_pool = NULL; 2924824a1566SKashyap Desai } 2925824a1566SKashyap Desai if (mrioc->sense_buf_q_pool) { 2926824a1566SKashyap Desai if (mrioc->sense_buf_q) 2927824a1566SKashyap Desai dma_pool_free(mrioc->sense_buf_q_pool, 2928824a1566SKashyap Desai mrioc->sense_buf_q, mrioc->sense_buf_q_dma); 2929824a1566SKashyap Desai dma_pool_destroy(mrioc->sense_buf_q_pool); 2930824a1566SKashyap Desai mrioc->sense_buf_q = NULL; 2931824a1566SKashyap Desai mrioc->sense_buf_q_pool = NULL; 2932824a1566SKashyap Desai } 2933824a1566SKashyap Desai 2934824a1566SKashyap Desai if (mrioc->reply_buf_pool) { 2935824a1566SKashyap Desai if (mrioc->reply_buf) 2936824a1566SKashyap Desai dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf, 2937824a1566SKashyap Desai mrioc->reply_buf_dma); 2938824a1566SKashyap Desai dma_pool_destroy(mrioc->reply_buf_pool); 2939824a1566SKashyap Desai mrioc->reply_buf = NULL; 2940824a1566SKashyap Desai mrioc->reply_buf_pool = NULL; 2941824a1566SKashyap Desai } 2942824a1566SKashyap Desai if (mrioc->reply_free_q_pool) { 2943824a1566SKashyap Desai if (mrioc->reply_free_q) 2944824a1566SKashyap Desai dma_pool_free(mrioc->reply_free_q_pool, 2945824a1566SKashyap Desai mrioc->reply_free_q, mrioc->reply_free_q_dma); 2946824a1566SKashyap Desai dma_pool_destroy(mrioc->reply_free_q_pool); 2947824a1566SKashyap Desai mrioc->reply_free_q = NULL; 2948824a1566SKashyap Desai mrioc->reply_free_q_pool = NULL; 2949824a1566SKashyap Desai } 2950824a1566SKashyap Desai 2951c9566231SKashyap Desai for (i = 0; i < mrioc->num_op_req_q; i++) 2952c9566231SKashyap Desai mpi3mr_free_op_req_q_segments(mrioc, i); 2953c9566231SKashyap Desai 2954c9566231SKashyap Desai for (i = 0; i < mrioc->num_op_reply_q; i++) 2955c9566231SKashyap Desai mpi3mr_free_op_reply_q_segments(mrioc, i); 2956c9566231SKashyap Desai 2957824a1566SKashyap Desai for (i = 0; i < mrioc->intr_info_count; i++) { 2958824a1566SKashyap Desai intr_info = mrioc->intr_info + i; 2959824a1566SKashyap Desai if (intr_info) 2960824a1566SKashyap Desai intr_info->op_reply_q = NULL; 2961824a1566SKashyap Desai } 2962824a1566SKashyap Desai 2963824a1566SKashyap Desai kfree(mrioc->req_qinfo); 2964824a1566SKashyap Desai mrioc->req_qinfo = NULL; 2965824a1566SKashyap Desai mrioc->num_op_req_q = 0; 2966824a1566SKashyap Desai 2967824a1566SKashyap Desai kfree(mrioc->op_reply_qinfo); 2968824a1566SKashyap Desai mrioc->op_reply_qinfo = NULL; 2969824a1566SKashyap Desai mrioc->num_op_reply_q = 0; 2970824a1566SKashyap Desai 2971824a1566SKashyap Desai kfree(mrioc->init_cmds.reply); 2972824a1566SKashyap Desai mrioc->init_cmds.reply = NULL; 2973824a1566SKashyap Desai 2974824a1566SKashyap Desai kfree(mrioc->chain_bitmap); 2975824a1566SKashyap Desai mrioc->chain_bitmap = NULL; 2976824a1566SKashyap Desai 297713ef29eaSKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 297813ef29eaSKashyap Desai kfree(mrioc->dev_rmhs_cmds[i].reply); 297913ef29eaSKashyap Desai mrioc->dev_rmhs_cmds[i].reply = NULL; 298013ef29eaSKashyap Desai } 298113ef29eaSKashyap Desai 2982824a1566SKashyap Desai if (mrioc->chain_buf_pool) { 2983824a1566SKashyap Desai for (i = 0; i < mrioc->chain_buf_count; i++) { 2984824a1566SKashyap Desai if (mrioc->chain_sgl_list[i].addr) { 2985824a1566SKashyap Desai dma_pool_free(mrioc->chain_buf_pool, 2986824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr, 2987824a1566SKashyap Desai mrioc->chain_sgl_list[i].dma_addr); 2988824a1566SKashyap Desai mrioc->chain_sgl_list[i].addr = NULL; 2989824a1566SKashyap Desai } 2990824a1566SKashyap Desai } 2991824a1566SKashyap Desai dma_pool_destroy(mrioc->chain_buf_pool); 2992824a1566SKashyap Desai mrioc->chain_buf_pool = NULL; 2993824a1566SKashyap Desai } 2994824a1566SKashyap Desai 2995824a1566SKashyap Desai kfree(mrioc->chain_sgl_list); 2996824a1566SKashyap Desai mrioc->chain_sgl_list = NULL; 2997824a1566SKashyap Desai 2998824a1566SKashyap Desai if (mrioc->admin_reply_base) { 2999824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz, 3000824a1566SKashyap Desai mrioc->admin_reply_base, mrioc->admin_reply_dma); 3001824a1566SKashyap Desai mrioc->admin_reply_base = NULL; 3002824a1566SKashyap Desai } 3003824a1566SKashyap Desai if (mrioc->admin_req_base) { 3004824a1566SKashyap Desai dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz, 3005824a1566SKashyap Desai mrioc->admin_req_base, mrioc->admin_req_dma); 3006824a1566SKashyap Desai mrioc->admin_req_base = NULL; 3007824a1566SKashyap Desai } 3008824a1566SKashyap Desai } 3009824a1566SKashyap Desai 3010824a1566SKashyap Desai /** 3011824a1566SKashyap Desai * mpi3mr_issue_ioc_shutdown - shutdown controller 3012824a1566SKashyap Desai * @mrioc: Adapter instance reference 3013824a1566SKashyap Desai * 3014824a1566SKashyap Desai * Send shutodwn notification to the controller and wait for the 3015824a1566SKashyap Desai * shutdown_timeout for it to be completed. 3016824a1566SKashyap Desai * 3017824a1566SKashyap Desai * Return: Nothing. 3018824a1566SKashyap Desai */ 3019824a1566SKashyap Desai static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc) 3020824a1566SKashyap Desai { 3021824a1566SKashyap Desai u32 ioc_config, ioc_status; 3022824a1566SKashyap Desai u8 retval = 1; 3023824a1566SKashyap Desai u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10; 3024824a1566SKashyap Desai 3025824a1566SKashyap Desai ioc_info(mrioc, "Issuing shutdown Notification\n"); 3026824a1566SKashyap Desai if (mrioc->unrecoverable) { 3027824a1566SKashyap Desai ioc_warn(mrioc, 3028824a1566SKashyap Desai "IOC is unrecoverable shutdown is not issued\n"); 3029824a1566SKashyap Desai return; 3030824a1566SKashyap Desai } 3031824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 3032824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 3033824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) { 3034824a1566SKashyap Desai ioc_info(mrioc, "shutdown already in progress\n"); 3035824a1566SKashyap Desai return; 3036824a1566SKashyap Desai } 3037824a1566SKashyap Desai 3038824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 3039824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL; 3040824a1566SKashyap Desai ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN; 3041824a1566SKashyap Desai 3042824a1566SKashyap Desai writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); 3043824a1566SKashyap Desai 3044824a1566SKashyap Desai if (mrioc->facts.shutdown_timeout) 3045824a1566SKashyap Desai timeout = mrioc->facts.shutdown_timeout * 10; 3046824a1566SKashyap Desai 3047824a1566SKashyap Desai do { 3048824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 3049824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 3050824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) { 3051824a1566SKashyap Desai retval = 0; 3052824a1566SKashyap Desai break; 3053824a1566SKashyap Desai } 3054824a1566SKashyap Desai msleep(100); 3055824a1566SKashyap Desai } while (--timeout); 3056824a1566SKashyap Desai 3057824a1566SKashyap Desai ioc_status = readl(&mrioc->sysif_regs->ioc_status); 3058824a1566SKashyap Desai ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); 3059824a1566SKashyap Desai 3060824a1566SKashyap Desai if (retval) { 3061824a1566SKashyap Desai if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) 3062824a1566SKashyap Desai == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) 3063824a1566SKashyap Desai ioc_warn(mrioc, 3064824a1566SKashyap Desai "shutdown still in progress after timeout\n"); 3065824a1566SKashyap Desai } 3066824a1566SKashyap Desai 3067824a1566SKashyap Desai ioc_info(mrioc, 3068824a1566SKashyap Desai "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n", 3069824a1566SKashyap Desai (!retval) ? "successful" : "failed", ioc_status, 3070824a1566SKashyap Desai ioc_config); 3071824a1566SKashyap Desai } 3072824a1566SKashyap Desai 3073824a1566SKashyap Desai /** 3074824a1566SKashyap Desai * mpi3mr_cleanup_ioc - Cleanup controller 3075824a1566SKashyap Desai * @mrioc: Adapter instance reference 3076*fb9b0457SKashyap Desai * @re_init: Cleanup due to a reinit or not 3077824a1566SKashyap Desai * 3078824a1566SKashyap Desai * controller cleanup handler, Message unit reset or soft reset 3079824a1566SKashyap Desai * and shutdown notification is issued to the controller and the 3080824a1566SKashyap Desai * associated memory resources are freed. 3081824a1566SKashyap Desai * 3082824a1566SKashyap Desai * Return: Nothing. 3083824a1566SKashyap Desai */ 3084*fb9b0457SKashyap Desai void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc, u8 re_init) 3085824a1566SKashyap Desai { 3086824a1566SKashyap Desai enum mpi3mr_iocstate ioc_state; 3087824a1566SKashyap Desai 3088*fb9b0457SKashyap Desai if (!re_init) 3089672ae26cSKashyap Desai mpi3mr_stop_watchdog(mrioc); 3090672ae26cSKashyap Desai 3091824a1566SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 3092824a1566SKashyap Desai 3093824a1566SKashyap Desai ioc_state = mpi3mr_get_iocstate(mrioc); 3094824a1566SKashyap Desai 3095824a1566SKashyap Desai if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) && 3096824a1566SKashyap Desai (ioc_state == MRIOC_STATE_READY)) { 3097824a1566SKashyap Desai if (mpi3mr_issue_and_process_mur(mrioc, 3098824a1566SKashyap Desai MPI3MR_RESET_FROM_CTLR_CLEANUP)) 3099824a1566SKashyap Desai mpi3mr_issue_reset(mrioc, 3100824a1566SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, 3101824a1566SKashyap Desai MPI3MR_RESET_FROM_MUR_FAILURE); 3102824a1566SKashyap Desai 3103*fb9b0457SKashyap Desai if (!re_init) 3104824a1566SKashyap Desai mpi3mr_issue_ioc_shutdown(mrioc); 3105824a1566SKashyap Desai } 3106824a1566SKashyap Desai 3107*fb9b0457SKashyap Desai if (!re_init) { 3108824a1566SKashyap Desai mpi3mr_free_mem(mrioc); 3109824a1566SKashyap Desai mpi3mr_cleanup_resources(mrioc); 3110824a1566SKashyap Desai } 3111*fb9b0457SKashyap Desai } 3112*fb9b0457SKashyap Desai 3113*fb9b0457SKashyap Desai /** 3114*fb9b0457SKashyap Desai * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command 3115*fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3116*fb9b0457SKashyap Desai * @cmdptr: Internal command tracker 3117*fb9b0457SKashyap Desai * 3118*fb9b0457SKashyap Desai * Complete an internal driver commands with state indicating it 3119*fb9b0457SKashyap Desai * is completed due to reset. 3120*fb9b0457SKashyap Desai * 3121*fb9b0457SKashyap Desai * Return: Nothing. 3122*fb9b0457SKashyap Desai */ 3123*fb9b0457SKashyap Desai static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc *mrioc, 3124*fb9b0457SKashyap Desai struct mpi3mr_drv_cmd *cmdptr) 3125*fb9b0457SKashyap Desai { 3126*fb9b0457SKashyap Desai if (cmdptr->state & MPI3MR_CMD_PENDING) { 3127*fb9b0457SKashyap Desai cmdptr->state |= MPI3MR_CMD_RESET; 3128*fb9b0457SKashyap Desai cmdptr->state &= ~MPI3MR_CMD_PENDING; 3129*fb9b0457SKashyap Desai if (cmdptr->is_waiting) { 3130*fb9b0457SKashyap Desai complete(&cmdptr->done); 3131*fb9b0457SKashyap Desai cmdptr->is_waiting = 0; 3132*fb9b0457SKashyap Desai } else if (cmdptr->callback) 3133*fb9b0457SKashyap Desai cmdptr->callback(mrioc, cmdptr); 3134*fb9b0457SKashyap Desai } 3135*fb9b0457SKashyap Desai } 3136*fb9b0457SKashyap Desai 3137*fb9b0457SKashyap Desai /** 3138*fb9b0457SKashyap Desai * mpi3mr_flush_drv_cmds - Flush internaldriver commands 3139*fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3140*fb9b0457SKashyap Desai * 3141*fb9b0457SKashyap Desai * Flush all internal driver commands post reset 3142*fb9b0457SKashyap Desai * 3143*fb9b0457SKashyap Desai * Return: Nothing. 3144*fb9b0457SKashyap Desai */ 3145*fb9b0457SKashyap Desai static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc) 3146*fb9b0457SKashyap Desai { 3147*fb9b0457SKashyap Desai struct mpi3mr_drv_cmd *cmdptr; 3148*fb9b0457SKashyap Desai u8 i; 3149*fb9b0457SKashyap Desai 3150*fb9b0457SKashyap Desai cmdptr = &mrioc->init_cmds; 3151*fb9b0457SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 3152*fb9b0457SKashyap Desai 3153*fb9b0457SKashyap Desai for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { 3154*fb9b0457SKashyap Desai cmdptr = &mrioc->dev_rmhs_cmds[i]; 3155*fb9b0457SKashyap Desai mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); 3156*fb9b0457SKashyap Desai } 3157*fb9b0457SKashyap Desai } 3158*fb9b0457SKashyap Desai 3159*fb9b0457SKashyap Desai /** 3160*fb9b0457SKashyap Desai * mpi3mr_diagfault_reset_handler - Diag fault reset handler 3161*fb9b0457SKashyap Desai * @mrioc: Adapter instance reference 3162*fb9b0457SKashyap Desai * @reset_reason: Reset reason code 3163*fb9b0457SKashyap Desai * 3164*fb9b0457SKashyap Desai * This is an handler for issuing diag fault reset from the 3165*fb9b0457SKashyap Desai * applications through IOCTL path to stop the execution of the 3166*fb9b0457SKashyap Desai * controller 3167*fb9b0457SKashyap Desai * 3168*fb9b0457SKashyap Desai * Return: 0 on success, non-zero on failure. 3169*fb9b0457SKashyap Desai */ 3170*fb9b0457SKashyap Desai int mpi3mr_diagfault_reset_handler(struct mpi3mr_ioc *mrioc, 3171*fb9b0457SKashyap Desai u32 reset_reason) 3172*fb9b0457SKashyap Desai { 3173*fb9b0457SKashyap Desai int retval = 0; 3174*fb9b0457SKashyap Desai 3175*fb9b0457SKashyap Desai mrioc->reset_in_progress = 1; 3176*fb9b0457SKashyap Desai 3177*fb9b0457SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 3178*fb9b0457SKashyap Desai 3179*fb9b0457SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 3180*fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); 3181*fb9b0457SKashyap Desai 3182*fb9b0457SKashyap Desai if (retval) { 3183*fb9b0457SKashyap Desai ioc_err(mrioc, "The diag fault reset failed: reason %d\n", 3184*fb9b0457SKashyap Desai reset_reason); 3185*fb9b0457SKashyap Desai mpi3mr_ioc_enable_intr(mrioc); 3186*fb9b0457SKashyap Desai } 3187*fb9b0457SKashyap Desai ioc_info(mrioc, "%s\n", ((retval == 0) ? "SUCCESS" : "FAILED")); 3188*fb9b0457SKashyap Desai mrioc->reset_in_progress = 0; 3189*fb9b0457SKashyap Desai return retval; 3190*fb9b0457SKashyap Desai } 3191824a1566SKashyap Desai 3192824a1566SKashyap Desai /** 3193824a1566SKashyap Desai * mpi3mr_soft_reset_handler - Reset the controller 3194824a1566SKashyap Desai * @mrioc: Adapter instance reference 3195824a1566SKashyap Desai * @reset_reason: Reset reason code 3196824a1566SKashyap Desai * @snapdump: Flag to generate snapdump in firmware or not 3197824a1566SKashyap Desai * 3198*fb9b0457SKashyap Desai * This is an handler for recovering controller by issuing soft 3199*fb9b0457SKashyap Desai * reset are diag fault reset. This is a blocking function and 3200*fb9b0457SKashyap Desai * when one reset is executed if any other resets they will be 3201*fb9b0457SKashyap Desai * blocked. All IOCTLs/IO will be blocked during the reset. If 3202*fb9b0457SKashyap Desai * controller reset is successful then the controller will be 3203*fb9b0457SKashyap Desai * reinitalized, otherwise the controller will be marked as not 3204*fb9b0457SKashyap Desai * recoverable 3205*fb9b0457SKashyap Desai * 3206*fb9b0457SKashyap Desai * In snapdump bit is set, the controller is issued with diag 3207*fb9b0457SKashyap Desai * fault reset so that the firmware can create a snap dump and 3208*fb9b0457SKashyap Desai * post that the firmware will result in F000 fault and the 3209*fb9b0457SKashyap Desai * driver will issue soft reset to recover from that. 3210824a1566SKashyap Desai * 3211824a1566SKashyap Desai * Return: 0 on success, non-zero on failure. 3212824a1566SKashyap Desai */ 3213824a1566SKashyap Desai int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, 3214824a1566SKashyap Desai u32 reset_reason, u8 snapdump) 3215824a1566SKashyap Desai { 3216*fb9b0457SKashyap Desai int retval = 0, i; 3217*fb9b0457SKashyap Desai unsigned long flags; 3218*fb9b0457SKashyap Desai u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; 3219*fb9b0457SKashyap Desai 3220*fb9b0457SKashyap Desai if (mrioc->fault_dbg) { 3221*fb9b0457SKashyap Desai if (snapdump) 3222*fb9b0457SKashyap Desai mpi3mr_set_diagsave(mrioc); 3223*fb9b0457SKashyap Desai mpi3mr_kill_ioc(mrioc, reset_reason); 3224*fb9b0457SKashyap Desai } 3225*fb9b0457SKashyap Desai 3226*fb9b0457SKashyap Desai /* 3227*fb9b0457SKashyap Desai * Block new resets until the currently executing one is finished and 3228*fb9b0457SKashyap Desai * return the status of the existing reset for all blocked resets 3229*fb9b0457SKashyap Desai */ 3230*fb9b0457SKashyap Desai if (!mutex_trylock(&mrioc->reset_mutex)) { 3231*fb9b0457SKashyap Desai ioc_info(mrioc, "Another reset in progress\n"); 3232*fb9b0457SKashyap Desai return -1; 3233*fb9b0457SKashyap Desai } 3234*fb9b0457SKashyap Desai mrioc->reset_in_progress = 1; 3235*fb9b0457SKashyap Desai 3236*fb9b0457SKashyap Desai if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) && 3237*fb9b0457SKashyap Desai (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) { 3238*fb9b0457SKashyap Desai for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 3239*fb9b0457SKashyap Desai mrioc->event_masks[i] = -1; 3240*fb9b0457SKashyap Desai 3241*fb9b0457SKashyap Desai retval = mpi3mr_issue_event_notification(mrioc); 3242*fb9b0457SKashyap Desai 3243*fb9b0457SKashyap Desai if (retval) { 3244*fb9b0457SKashyap Desai ioc_err(mrioc, 3245*fb9b0457SKashyap Desai "Failed to turn off events prior to reset %d\n", 3246*fb9b0457SKashyap Desai retval); 3247*fb9b0457SKashyap Desai } 3248*fb9b0457SKashyap Desai } 3249*fb9b0457SKashyap Desai 3250*fb9b0457SKashyap Desai mpi3mr_ioc_disable_intr(mrioc); 3251*fb9b0457SKashyap Desai 3252*fb9b0457SKashyap Desai if (snapdump) { 3253*fb9b0457SKashyap Desai mpi3mr_set_diagsave(mrioc); 3254*fb9b0457SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 3255*fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); 3256*fb9b0457SKashyap Desai if (!retval) { 3257*fb9b0457SKashyap Desai do { 3258*fb9b0457SKashyap Desai host_diagnostic = 3259*fb9b0457SKashyap Desai readl(&mrioc->sysif_regs->host_diagnostic); 3260*fb9b0457SKashyap Desai if (!(host_diagnostic & 3261*fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS)) 3262*fb9b0457SKashyap Desai break; 3263*fb9b0457SKashyap Desai msleep(100); 3264*fb9b0457SKashyap Desai } while (--timeout); 3265*fb9b0457SKashyap Desai } 3266*fb9b0457SKashyap Desai } 3267*fb9b0457SKashyap Desai 3268*fb9b0457SKashyap Desai retval = mpi3mr_issue_reset(mrioc, 3269*fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason); 3270*fb9b0457SKashyap Desai if (retval) { 3271*fb9b0457SKashyap Desai ioc_err(mrioc, "Failed to issue soft reset to the ioc\n"); 3272*fb9b0457SKashyap Desai goto out; 3273*fb9b0457SKashyap Desai } 3274*fb9b0457SKashyap Desai 3275*fb9b0457SKashyap Desai mpi3mr_flush_delayed_rmhs_list(mrioc); 3276*fb9b0457SKashyap Desai mpi3mr_flush_drv_cmds(mrioc); 3277*fb9b0457SKashyap Desai memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); 3278*fb9b0457SKashyap Desai memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); 3279*fb9b0457SKashyap Desai mpi3mr_cleanup_fwevt_list(mrioc); 3280*fb9b0457SKashyap Desai mpi3mr_flush_host_io(mrioc); 3281*fb9b0457SKashyap Desai mpi3mr_invalidate_devhandles(mrioc); 3282*fb9b0457SKashyap Desai mpi3mr_memset_buffers(mrioc); 3283*fb9b0457SKashyap Desai retval = mpi3mr_init_ioc(mrioc, 1); 3284*fb9b0457SKashyap Desai if (retval) { 3285*fb9b0457SKashyap Desai pr_err(IOCNAME "reinit after soft reset failed: reason %d\n", 3286*fb9b0457SKashyap Desai mrioc->name, reset_reason); 3287*fb9b0457SKashyap Desai goto out; 3288*fb9b0457SKashyap Desai } 3289*fb9b0457SKashyap Desai ssleep(10); 3290*fb9b0457SKashyap Desai 3291*fb9b0457SKashyap Desai out: 3292*fb9b0457SKashyap Desai if (!retval) { 3293*fb9b0457SKashyap Desai mrioc->reset_in_progress = 0; 3294*fb9b0457SKashyap Desai scsi_unblock_requests(mrioc->shost); 3295*fb9b0457SKashyap Desai mpi3mr_rfresh_tgtdevs(mrioc); 3296*fb9b0457SKashyap Desai spin_lock_irqsave(&mrioc->watchdog_lock, flags); 3297*fb9b0457SKashyap Desai if (mrioc->watchdog_work_q) 3298*fb9b0457SKashyap Desai queue_delayed_work(mrioc->watchdog_work_q, 3299*fb9b0457SKashyap Desai &mrioc->watchdog_work, 3300*fb9b0457SKashyap Desai msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); 3301*fb9b0457SKashyap Desai spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); 3302*fb9b0457SKashyap Desai } else { 3303*fb9b0457SKashyap Desai mpi3mr_issue_reset(mrioc, 3304*fb9b0457SKashyap Desai MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); 3305*fb9b0457SKashyap Desai mrioc->unrecoverable = 1; 3306*fb9b0457SKashyap Desai mrioc->reset_in_progress = 0; 3307*fb9b0457SKashyap Desai retval = -1; 3308*fb9b0457SKashyap Desai } 3309*fb9b0457SKashyap Desai 3310*fb9b0457SKashyap Desai mutex_unlock(&mrioc->reset_mutex); 3311*fb9b0457SKashyap Desai ioc_info(mrioc, "%s\n", ((retval == 0) ? "SUCCESS" : "FAILED")); 3312*fb9b0457SKashyap Desai return retval; 3313824a1566SKashyap Desai } 3314