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