11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20d49016bSadam radford /*
30d49016bSadam radford * Linux MegaRAID driver for SAS based RAID controllers
40d49016bSadam radford *
5e399065bSSumit.Saxena@avagotech.com * Copyright (c) 2003-2013 LSI Corporation
6365597cfSShivasharan S * Copyright (c) 2013-2016 Avago Technologies
7365597cfSShivasharan S * Copyright (c) 2016-2018 Broadcom Inc.
80d49016bSadam radford *
9365597cfSShivasharan S * Authors: Broadcom Inc.
100d49016bSadam radford * Sreenivas Bagalkote
110d49016bSadam radford * Sumant Patro
120d49016bSadam radford * Bo Yang
13e399065bSSumit.Saxena@avagotech.com * Adam Radford
14365597cfSShivasharan S * Kashyap Desai <kashyap.desai@broadcom.com>
15365597cfSShivasharan S * Sumit Saxena <sumit.saxena@broadcom.com>
160d49016bSadam radford *
17365597cfSShivasharan S * Send feedback to: megaraidlinux.pdl@broadcom.com
180d49016bSadam radford */
190d49016bSadam radford
200d49016bSadam radford #include <linux/kernel.h>
210d49016bSadam radford #include <linux/types.h>
220d49016bSadam radford #include <linux/pci.h>
230d49016bSadam radford #include <linux/list.h>
240d49016bSadam radford #include <linux/moduleparam.h>
250d49016bSadam radford #include <linux/module.h>
260d49016bSadam radford #include <linux/spinlock.h>
270d49016bSadam radford #include <linux/interrupt.h>
280d49016bSadam radford #include <linux/delay.h>
290d49016bSadam radford #include <linux/uio.h>
300d49016bSadam radford #include <linux/slab.h>
317c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
32318aaef8SShivasharan S #include <asm/unaligned.h>
330d49016bSadam radford #include <linux/fs.h>
340d49016bSadam radford #include <linux/compat.h>
350d49016bSadam radford #include <linux/blkdev.h>
360d49016bSadam radford #include <linux/mutex.h>
370d49016bSadam radford #include <linux/poll.h>
38def3e8dfSShivasharan S #include <linux/vmalloc.h>
3962a04f81SShivasharan S #include <linux/irq_poll.h>
4081e7eb5bSMartin K. Petersen #include <linux/blk-mq-pci.h>
410d49016bSadam radford
420d49016bSadam radford #include <scsi/scsi.h>
430d49016bSadam radford #include <scsi/scsi_cmnd.h>
440d49016bSadam radford #include <scsi/scsi_device.h>
450d49016bSadam radford #include <scsi/scsi_host.h>
464bcde509Sadam radford #include <scsi/scsi_tcq.h>
4796c9603cSShivasharan S #include <scsi/scsi_dbg.h>
489c915a8cSadam radford #include "megaraid_sas_fusion.h"
490d49016bSadam radford #include "megaraid_sas.h"
500d49016bSadam radford
510d49016bSadam radford /*
520d49016bSadam radford * Number of sectors per IO command
530d49016bSadam radford * Will be set in megasas_init_mfi if user does not provide
540d49016bSadam radford */
550d49016bSadam radford static unsigned int max_sectors;
56ea14e462STomas Henzl module_param_named(max_sectors, max_sectors, int, 0444);
570d49016bSadam radford MODULE_PARM_DESC(max_sectors,
580d49016bSadam radford "Maximum number of sectors per IO command");
590d49016bSadam radford
6080d9da98Sadam radford static int msix_disable;
61ea14e462STomas Henzl module_param(msix_disable, int, 0444);
6280d9da98Sadam radford MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0");
6380d9da98Sadam radford
64079eaddfSadam radford static unsigned int msix_vectors;
65ea14e462STomas Henzl module_param(msix_vectors, int, 0444);
66079eaddfSadam radford MODULE_PARM_DESC(msix_vectors, "MSI-X max vector count. Default: Set by FW");
67079eaddfSadam radford
68229fe47cSadam radford static int allow_vf_ioctls;
69ea14e462STomas Henzl module_param(allow_vf_ioctls, int, 0444);
70229fe47cSadam radford MODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0");
71229fe47cSadam radford
72ae09a6c1SSumit.Saxena@avagotech.com static unsigned int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH;
73ea14e462STomas Henzl module_param(throttlequeuedepth, int, 0444);
74c5daa6a9Sadam radford MODULE_PARM_DESC(throttlequeuedepth,
75c5daa6a9Sadam radford "Adapter queue depth when throttled due to I/O timeout. Default: 16");
76c5daa6a9Sadam radford
77e3d178caSSumit Saxena unsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME;
78ea14e462STomas Henzl module_param(resetwaittime, int, 0444);
791401371dSShivasharan S MODULE_PARM_DESC(resetwaittime, "Wait time in (1-180s) after I/O timeout before resetting adapter. Default: 180s");
80c007b8b2Sadam radford
8162aa501dSJason Yan static int smp_affinity_enable = 1;
82ea14e462STomas Henzl module_param(smp_affinity_enable, int, 0444);
8355d9a1d2SColin Ian King MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)");
84ac95136aSSumit.Saxena@avagotech.com
851909a438SJason Yan static int rdpq_enable = 1;
86ea14e462STomas Henzl module_param(rdpq_enable, int, 0444);
871401371dSShivasharan S MODULE_PARM_DESC(rdpq_enable, "Allocate reply queue in chunks for large queue depth enable/disable Default: enable(1)");
88179ac142SSumit Saxena
89308ec459SSumit Saxena unsigned int dual_qdepth_disable;
90ea14e462STomas Henzl module_param(dual_qdepth_disable, int, 0444);
91308ec459SSumit Saxena MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0");
92308ec459SSumit Saxena
931909a438SJason Yan static unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
94ea14e462STomas Henzl module_param(scmd_timeout, int, 0444);
95e3d178caSSumit Saxena MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer.");
96e3d178caSSumit Saxena
97299ee426SChandrakanth Patil int perf_mode = -1;
98299ee426SChandrakanth Patil module_param(perf_mode, int, 0444);
99299ee426SChandrakanth Patil MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options:\n\t\t"
100299ee426SChandrakanth Patil "0 - balanced: High iops and low latency queues are allocated &\n\t\t"
101299ee426SChandrakanth Patil "interrupt coalescing is enabled only on high iops queues\n\t\t"
102299ee426SChandrakanth Patil "1 - iops: High iops queues are not allocated &\n\t\t"
103299ee426SChandrakanth Patil "interrupt coalescing is enabled on all queues\n\t\t"
104299ee426SChandrakanth Patil "2 - latency: High iops queues are not allocated &\n\t\t"
105299ee426SChandrakanth Patil "interrupt coalescing is disabled on all queues\n\t\t"
106299ee426SChandrakanth Patil "default mode is 'balanced'"
107299ee426SChandrakanth Patil );
108299ee426SChandrakanth Patil
109d956a116SShivasharan S int event_log_level = MFI_EVT_CLASS_CRITICAL;
110d956a116SShivasharan S module_param(event_log_level, int, 0644);
111d956a116SShivasharan S MODULE_PARM_DESC(event_log_level, "Asynchronous event logging level- range is: -2(CLASS_DEBUG) to 4(CLASS_DEAD), Default: 2(CLASS_CRITICAL)");
112d956a116SShivasharan S
1139ab089d3SChandrakanth Patil unsigned int enable_sdev_max_qd;
1149ab089d3SChandrakanth Patil module_param(enable_sdev_max_qd, int, 0444);
1159ab089d3SChandrakanth Patil MODULE_PARM_DESC(enable_sdev_max_qd, "Enable sdev max qd as can_queue. Default: 0");
1169ab089d3SChandrakanth Patil
1179e4bec5bSKashyap Desai int poll_queues;
1189e4bec5bSKashyap Desai module_param(poll_queues, int, 0444);
1199e4bec5bSKashyap Desai MODULE_PARM_DESC(poll_queues, "Number of queues to be use for io_uring poll mode.\n\t\t"
1209e4bec5bSKashyap Desai "This parameter is effective only if host_tagset_enable=1 &\n\t\t"
1219e4bec5bSKashyap Desai "It is not applicable for MFI_SERIES. &\n\t\t"
1229e4bec5bSKashyap Desai "Driver will work in latency mode. &\n\t\t"
1239e4bec5bSKashyap Desai "High iops queues are not allocated &\n\t\t"
1249e4bec5bSKashyap Desai );
1259e4bec5bSKashyap Desai
12681e7eb5bSMartin K. Petersen int host_tagset_enable = 1;
12781e7eb5bSMartin K. Petersen module_param(host_tagset_enable, int, 0444);
12881e7eb5bSMartin K. Petersen MODULE_PARM_DESC(host_tagset_enable, "Shared host tagset enable/disable Default: enable(1)");
12981e7eb5bSMartin K. Petersen
1300d49016bSadam radford MODULE_LICENSE("GPL");
1310d49016bSadam radford MODULE_VERSION(MEGASAS_VERSION);
132365597cfSShivasharan S MODULE_AUTHOR("megaraidlinux.pdl@broadcom.com");
133365597cfSShivasharan S MODULE_DESCRIPTION("Broadcom MegaRAID SAS Driver");
1340d49016bSadam radford
135058a8facSadam radford int megasas_transition_to_ready(struct megasas_instance *instance, int ocr);
1360d49016bSadam radford static int megasas_get_pd_list(struct megasas_instance *instance);
13721c9e160Sadam radford static int megasas_ld_list_query(struct megasas_instance *instance,
13821c9e160Sadam radford u8 query_type);
1390d49016bSadam radford static int megasas_issue_init_mfi(struct megasas_instance *instance);
1400d49016bSadam radford static int megasas_register_aen(struct megasas_instance *instance,
1410d49016bSadam radford u32 seq_num, u32 class_locale_word);
14215dd0381SShivasharan S static void megasas_get_pd_info(struct megasas_instance *instance,
14315dd0381SShivasharan S struct scsi_device *sdev);
144ae6874baSKashyap Desai static void
145ae6874baSKashyap Desai megasas_set_ld_removed_by_fw(struct megasas_instance *instance);
146e9495e2dSShivasharan S
1470d49016bSadam radford /*
1480d49016bSadam radford * PCI ID table for all supported controllers
1490d49016bSadam radford */
1500d49016bSadam radford static struct pci_device_id megasas_pci_table[] = {
1510d49016bSadam radford
1520d49016bSadam radford {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064R)},
1530d49016bSadam radford /* xscale IOP */
1540d49016bSadam radford {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078R)},
1550d49016bSadam radford /* ppc IOP */
1560d49016bSadam radford {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078DE)},
1570d49016bSadam radford /* ppc IOP */
1580d49016bSadam radford {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078GEN2)},
1590d49016bSadam radford /* gen2*/
1600d49016bSadam radford {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0079GEN2)},
1610d49016bSadam radford /* gen2*/
1620d49016bSadam radford {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0073SKINNY)},
1630d49016bSadam radford /* skinny*/
1640d49016bSadam radford {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0071SKINNY)},
1650d49016bSadam radford /* skinny*/
1660d49016bSadam radford {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)},
1670d49016bSadam radford /* xscale IOP, vega */
1680d49016bSadam radford {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
1690d49016bSadam radford /* xscale IOP */
1709c915a8cSadam radford {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)},
1719c915a8cSadam radford /* Fusion */
172229fe47cSadam radford {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_PLASMA)},
173229fe47cSadam radford /* Plasma */
17436807e67Sadam radford {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INVADER)},
17536807e67Sadam radford /* Invader */
17621d3c710SSumit.Saxena@lsi.com {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FURY)},
17721d3c710SSumit.Saxena@lsi.com /* Fury */
17890c204bcSsumit.saxena@avagotech.com {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER)},
17990c204bcSsumit.saxena@avagotech.com /* Intruder */
18090c204bcSsumit.saxena@avagotech.com {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER_24)},
18190c204bcSsumit.saxena@avagotech.com /* Intruder 24 port*/
1827364d34bSsumit.saxena@avagotech.com {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_52)},
1837364d34bSsumit.saxena@avagotech.com {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_53)},
18445f4f2ebSSasikumar Chandrasekaran /* VENTURA */
18545f4f2ebSSasikumar Chandrasekaran {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VENTURA)},
186754f1baeSShivasharan S {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CRUSADER)},
18745f4f2ebSSasikumar Chandrasekaran {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_HARPOON)},
18845f4f2ebSSasikumar Chandrasekaran {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_TOMCAT)},
18945f4f2ebSSasikumar Chandrasekaran {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VENTURA_4PORT)},
19045f4f2ebSSasikumar Chandrasekaran {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CRUSADER_4PORT)},
191469f72ddSShivasharan S {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E1)},
192469f72ddSShivasharan S {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E2)},
193469f72ddSShivasharan S {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E5)},
194469f72ddSShivasharan S {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E6)},
195dd807699SChandrakanth Patil {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E0)},
196dd807699SChandrakanth Patil {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E3)},
197dd807699SChandrakanth Patil {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E4)},
198dd807699SChandrakanth Patil {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E7)},
1990d49016bSadam radford {}
2000d49016bSadam radford };
2010d49016bSadam radford
2020d49016bSadam radford MODULE_DEVICE_TABLE(pci, megasas_pci_table);
2030d49016bSadam radford
2040d49016bSadam radford static int megasas_mgmt_majorno;
205229fe47cSadam radford struct megasas_mgmt_info megasas_mgmt_info;
2060d49016bSadam radford static struct fasync_struct *megasas_async_queue;
2070d49016bSadam radford static DEFINE_MUTEX(megasas_async_queue_mutex);
2080d49016bSadam radford
2090d49016bSadam radford static int megasas_poll_wait_aen;
2100d49016bSadam radford static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait);
2110d49016bSadam radford static u32 support_poll_for_event;
2129c915a8cSadam radford u32 megasas_dbg_lvl;
2130d49016bSadam radford static u32 support_device_change;
214f870bcbeSShivasharan S static bool support_nvme_encapsulation;
21558136856SChandrakanth Patil static bool support_pci_lane_margining;
2160d49016bSadam radford
2170d49016bSadam radford /* define lock for aen poll */
218311e87b7SShixin Liu static DEFINE_SPINLOCK(poll_aen_lock);
2190d49016bSadam radford
220ba53572bSShivasharan S extern struct dentry *megasas_debugfs_root;
2219e4bec5bSKashyap Desai extern int megasas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num);
222ba53572bSShivasharan S
2239c915a8cSadam radford void
2240d49016bSadam radford megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
2250d49016bSadam radford u8 alt_status);
226ebf054b0Sadam radford static u32
227de516379SShivasharan S megasas_read_fw_status_reg_gen2(struct megasas_instance *instance);
228ebf054b0Sadam radford static int
229ebf054b0Sadam radford megasas_adp_reset_gen2(struct megasas_instance *instance,
230ebf054b0Sadam radford struct megasas_register_set __iomem *reg_set);
231cd50ba8eSadam radford static irqreturn_t megasas_isr(int irq, void *devp);
232cd50ba8eSadam radford static u32
233cd50ba8eSadam radford megasas_init_adapter_mfi(struct megasas_instance *instance);
234cd50ba8eSadam radford u32
235cd50ba8eSadam radford megasas_build_and_issue_cmd(struct megasas_instance *instance,
236cd50ba8eSadam radford struct scsi_cmnd *scmd);
237cd50ba8eSadam radford static void megasas_complete_cmd_dpc(unsigned long instance_addr);
2389c915a8cSadam radford int
239229fe47cSadam radford wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
240229fe47cSadam radford int seconds);
2419c915a8cSadam radford void megasas_fusion_ocr_wq(struct work_struct *work);
242229fe47cSadam radford static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
243229fe47cSadam radford int initial);
244e5d65b4bSShivasharan S static int
245107a60ddSShivasharan S megasas_set_dma_mask(struct megasas_instance *instance);
246e5d65b4bSShivasharan S static int
247e5d65b4bSShivasharan S megasas_alloc_ctrl_mem(struct megasas_instance *instance);
248e5d65b4bSShivasharan S static inline void
249e5d65b4bSShivasharan S megasas_free_ctrl_mem(struct megasas_instance *instance);
250e5d65b4bSShivasharan S static inline int
251e5d65b4bSShivasharan S megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance);
252e5d65b4bSShivasharan S static inline void
253e5d65b4bSShivasharan S megasas_free_ctrl_dma_buffers(struct megasas_instance *instance);
254e5d65b4bSShivasharan S static inline void
255e5d65b4bSShivasharan S megasas_init_ctrl_params(struct megasas_instance *instance);
256cd50ba8eSadam radford
megasas_readl(struct megasas_instance * instance,const volatile void __iomem * addr)257272652fcSShivasharan S u32 megasas_readl(struct megasas_instance *instance,
258272652fcSShivasharan S const volatile void __iomem *addr)
259272652fcSShivasharan S {
260272652fcSShivasharan S u32 i = 0, ret_val;
261272652fcSShivasharan S /*
262272652fcSShivasharan S * Due to a HW errata in Aero controllers, reads to certain
263272652fcSShivasharan S * Fusion registers could intermittently return all zeroes.
264272652fcSShivasharan S * This behavior is transient in nature and subsequent reads will
265272652fcSShivasharan S * return valid value. As a workaround in driver, retry readl for
266ad347c46SChandrakanth patil * up to thirty times until a non-zero value is read.
267272652fcSShivasharan S */
268272652fcSShivasharan S if (instance->adapter_type == AERO_SERIES) {
269272652fcSShivasharan S do {
270272652fcSShivasharan S ret_val = readl(addr);
271272652fcSShivasharan S i++;
272ad347c46SChandrakanth patil } while (ret_val == 0 && i < 30);
273272652fcSShivasharan S return ret_val;
274272652fcSShivasharan S } else {
275272652fcSShivasharan S return readl(addr);
276272652fcSShivasharan S }
277272652fcSShivasharan S }
278272652fcSShivasharan S
279107a60ddSShivasharan S /**
280107a60ddSShivasharan S * megasas_set_dma_settings - Populate DMA address, length and flags for DCMDs
281107a60ddSShivasharan S * @instance: Adapter soft state
282107a60ddSShivasharan S * @dcmd: DCMD frame inside MFI command
283107a60ddSShivasharan S * @dma_addr: DMA address of buffer to be passed to FW
284107a60ddSShivasharan S * @dma_len: Length of DMA buffer to be passed to FW
285107a60ddSShivasharan S * @return: void
286107a60ddSShivasharan S */
megasas_set_dma_settings(struct megasas_instance * instance,struct megasas_dcmd_frame * dcmd,dma_addr_t dma_addr,u32 dma_len)287107a60ddSShivasharan S void megasas_set_dma_settings(struct megasas_instance *instance,
288107a60ddSShivasharan S struct megasas_dcmd_frame *dcmd,
289107a60ddSShivasharan S dma_addr_t dma_addr, u32 dma_len)
290107a60ddSShivasharan S {
291107a60ddSShivasharan S if (instance->consistent_mask_64bit) {
292107a60ddSShivasharan S dcmd->sgl.sge64[0].phys_addr = cpu_to_le64(dma_addr);
293107a60ddSShivasharan S dcmd->sgl.sge64[0].length = cpu_to_le32(dma_len);
294107a60ddSShivasharan S dcmd->flags = cpu_to_le16(dcmd->flags | MFI_FRAME_SGL64);
295107a60ddSShivasharan S
296107a60ddSShivasharan S } else {
297107a60ddSShivasharan S dcmd->sgl.sge32[0].phys_addr =
298107a60ddSShivasharan S cpu_to_le32(lower_32_bits(dma_addr));
299107a60ddSShivasharan S dcmd->sgl.sge32[0].length = cpu_to_le32(dma_len);
300107a60ddSShivasharan S dcmd->flags = cpu_to_le16(dcmd->flags);
301107a60ddSShivasharan S }
302107a60ddSShivasharan S }
303cd50ba8eSadam radford
3046764f519SYueHaibing static void
megasas_issue_dcmd(struct megasas_instance * instance,struct megasas_cmd * cmd)305cd50ba8eSadam radford megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
306cd50ba8eSadam radford {
307cd50ba8eSadam radford instance->instancet->fire_cmd(instance,
308cd50ba8eSadam radford cmd->frame_phys_addr, 0, instance->reg_set);
309f4fc2093SShivasharan S return;
310cd50ba8eSadam radford }
3110d49016bSadam radford
3120d49016bSadam radford /**
3130d49016bSadam radford * megasas_get_cmd - Get a command from the free pool
3140d49016bSadam radford * @instance: Adapter soft state
3150d49016bSadam radford *
3160d49016bSadam radford * Returns a free command from the pool
3170d49016bSadam radford */
megasas_get_cmd(struct megasas_instance * instance)3189c915a8cSadam radford struct megasas_cmd *megasas_get_cmd(struct megasas_instance
3190d49016bSadam radford *instance)
3200d49016bSadam radford {
3210d49016bSadam radford unsigned long flags;
3220d49016bSadam radford struct megasas_cmd *cmd = NULL;
3230d49016bSadam radford
32490dc9d98SSumit.Saxena@avagotech.com spin_lock_irqsave(&instance->mfi_pool_lock, flags);
3250d49016bSadam radford
3260d49016bSadam radford if (!list_empty(&instance->cmd_pool)) {
3270d49016bSadam radford cmd = list_entry((&instance->cmd_pool)->next,
3280d49016bSadam radford struct megasas_cmd, list);
3290d49016bSadam radford list_del_init(&cmd->list);
3300d49016bSadam radford } else {
3311be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "Command pool empty!\n");
3320d49016bSadam radford }
3330d49016bSadam radford
33490dc9d98SSumit.Saxena@avagotech.com spin_unlock_irqrestore(&instance->mfi_pool_lock, flags);
3350d49016bSadam radford return cmd;
3360d49016bSadam radford }
3370d49016bSadam radford
3380d49016bSadam radford /**
3390d49016bSadam radford * megasas_return_cmd - Return a cmd to free command pool
3400d49016bSadam radford * @instance: Adapter soft state
3410d49016bSadam radford * @cmd: Command packet to be returned to free command pool
3420d49016bSadam radford */
34368b43744SAndi Kleen void
megasas_return_cmd(struct megasas_instance * instance,struct megasas_cmd * cmd)3440d49016bSadam radford megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
3450d49016bSadam radford {
3460d49016bSadam radford unsigned long flags;
3474026e9aaSSumit.Saxena@avagotech.com u32 blk_tags;
3484026e9aaSSumit.Saxena@avagotech.com struct megasas_cmd_fusion *cmd_fusion;
3494026e9aaSSumit.Saxena@avagotech.com struct fusion_context *fusion = instance->ctrl_context;
3504026e9aaSSumit.Saxena@avagotech.com
3514026e9aaSSumit.Saxena@avagotech.com /* This flag is used only for fusion adapter.
3524026e9aaSSumit.Saxena@avagotech.com * Wait for Interrupt for Polled mode DCMD
3534026e9aaSSumit.Saxena@avagotech.com */
3544026e9aaSSumit.Saxena@avagotech.com if (cmd->flags & DRV_DCMD_POLLED_MODE)
3554026e9aaSSumit.Saxena@avagotech.com return;
3560d49016bSadam radford
35790dc9d98SSumit.Saxena@avagotech.com spin_lock_irqsave(&instance->mfi_pool_lock, flags);
3580d49016bSadam radford
3594026e9aaSSumit.Saxena@avagotech.com if (fusion) {
3604026e9aaSSumit.Saxena@avagotech.com blk_tags = instance->max_scsi_cmds + cmd->index;
3614026e9aaSSumit.Saxena@avagotech.com cmd_fusion = fusion->cmd_list[blk_tags];
3624026e9aaSSumit.Saxena@avagotech.com megasas_return_cmd_fusion(instance, cmd_fusion);
3634026e9aaSSumit.Saxena@avagotech.com }
3644026e9aaSSumit.Saxena@avagotech.com cmd->scmd = NULL;
3654026e9aaSSumit.Saxena@avagotech.com cmd->frame_count = 0;
3664026e9aaSSumit.Saxena@avagotech.com cmd->flags = 0;
36721c34006SShivasharan S memset(cmd->frame, 0, instance->mfi_frame_size);
36821c34006SShivasharan S cmd->frame->io.context = cpu_to_le32(cmd->index);
3694026e9aaSSumit.Saxena@avagotech.com if (!fusion && reset_devices)
3704026e9aaSSumit.Saxena@avagotech.com cmd->frame->hdr.cmd = MFI_CMD_INVALID;
3714026e9aaSSumit.Saxena@avagotech.com list_add(&cmd->list, (&instance->cmd_pool)->next);
3724026e9aaSSumit.Saxena@avagotech.com
3734026e9aaSSumit.Saxena@avagotech.com spin_unlock_irqrestore(&instance->mfi_pool_lock, flags);
3744026e9aaSSumit.Saxena@avagotech.com
3754026e9aaSSumit.Saxena@avagotech.com }
3760d49016bSadam radford
377714f5177Ssumit.saxena@avagotech.com static const char *
format_timestamp(uint32_t timestamp)378714f5177Ssumit.saxena@avagotech.com format_timestamp(uint32_t timestamp)
379714f5177Ssumit.saxena@avagotech.com {
380714f5177Ssumit.saxena@avagotech.com static char buffer[32];
381714f5177Ssumit.saxena@avagotech.com
382714f5177Ssumit.saxena@avagotech.com if ((timestamp & 0xff000000) == 0xff000000)
383714f5177Ssumit.saxena@avagotech.com snprintf(buffer, sizeof(buffer), "boot + %us", timestamp &
384714f5177Ssumit.saxena@avagotech.com 0x00ffffff);
385714f5177Ssumit.saxena@avagotech.com else
386714f5177Ssumit.saxena@avagotech.com snprintf(buffer, sizeof(buffer), "%us", timestamp);
387714f5177Ssumit.saxena@avagotech.com return buffer;
388714f5177Ssumit.saxena@avagotech.com }
389714f5177Ssumit.saxena@avagotech.com
390714f5177Ssumit.saxena@avagotech.com static const char *
format_class(int8_t class)391714f5177Ssumit.saxena@avagotech.com format_class(int8_t class)
392714f5177Ssumit.saxena@avagotech.com {
393714f5177Ssumit.saxena@avagotech.com static char buffer[6];
394714f5177Ssumit.saxena@avagotech.com
395714f5177Ssumit.saxena@avagotech.com switch (class) {
396714f5177Ssumit.saxena@avagotech.com case MFI_EVT_CLASS_DEBUG:
397714f5177Ssumit.saxena@avagotech.com return "debug";
398714f5177Ssumit.saxena@avagotech.com case MFI_EVT_CLASS_PROGRESS:
399714f5177Ssumit.saxena@avagotech.com return "progress";
400714f5177Ssumit.saxena@avagotech.com case MFI_EVT_CLASS_INFO:
401714f5177Ssumit.saxena@avagotech.com return "info";
402714f5177Ssumit.saxena@avagotech.com case MFI_EVT_CLASS_WARNING:
403714f5177Ssumit.saxena@avagotech.com return "WARN";
404714f5177Ssumit.saxena@avagotech.com case MFI_EVT_CLASS_CRITICAL:
405714f5177Ssumit.saxena@avagotech.com return "CRIT";
406714f5177Ssumit.saxena@avagotech.com case MFI_EVT_CLASS_FATAL:
407714f5177Ssumit.saxena@avagotech.com return "FATAL";
408714f5177Ssumit.saxena@avagotech.com case MFI_EVT_CLASS_DEAD:
409714f5177Ssumit.saxena@avagotech.com return "DEAD";
410714f5177Ssumit.saxena@avagotech.com default:
411714f5177Ssumit.saxena@avagotech.com snprintf(buffer, sizeof(buffer), "%d", class);
412714f5177Ssumit.saxena@avagotech.com return buffer;
413714f5177Ssumit.saxena@avagotech.com }
414714f5177Ssumit.saxena@avagotech.com }
415714f5177Ssumit.saxena@avagotech.com
416714f5177Ssumit.saxena@avagotech.com /**
417714f5177Ssumit.saxena@avagotech.com * megasas_decode_evt: Decode FW AEN event and print critical event
418714f5177Ssumit.saxena@avagotech.com * for information.
419714f5177Ssumit.saxena@avagotech.com * @instance: Adapter soft state
420714f5177Ssumit.saxena@avagotech.com */
421714f5177Ssumit.saxena@avagotech.com static void
megasas_decode_evt(struct megasas_instance * instance)422714f5177Ssumit.saxena@avagotech.com megasas_decode_evt(struct megasas_instance *instance)
423714f5177Ssumit.saxena@avagotech.com {
424714f5177Ssumit.saxena@avagotech.com struct megasas_evt_detail *evt_detail = instance->evt_detail;
425714f5177Ssumit.saxena@avagotech.com union megasas_evt_class_locale class_locale;
426714f5177Ssumit.saxena@avagotech.com class_locale.word = le32_to_cpu(evt_detail->cl.word);
427714f5177Ssumit.saxena@avagotech.com
428d956a116SShivasharan S if ((event_log_level < MFI_EVT_CLASS_DEBUG) ||
429d956a116SShivasharan S (event_log_level > MFI_EVT_CLASS_DEAD)) {
430d956a116SShivasharan S printk(KERN_WARNING "megaraid_sas: provided event log level is out of range, setting it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n");
431d956a116SShivasharan S event_log_level = MFI_EVT_CLASS_CRITICAL;
432d956a116SShivasharan S }
433d956a116SShivasharan S
434d956a116SShivasharan S if (class_locale.members.class >= event_log_level)
435714f5177Ssumit.saxena@avagotech.com dev_info(&instance->pdev->dev, "%d (%s/0x%04x/%s) - %s\n",
436714f5177Ssumit.saxena@avagotech.com le32_to_cpu(evt_detail->seq_num),
437714f5177Ssumit.saxena@avagotech.com format_timestamp(le32_to_cpu(evt_detail->time_stamp)),
438714f5177Ssumit.saxena@avagotech.com (class_locale.members.locale),
439714f5177Ssumit.saxena@avagotech.com format_class(class_locale.members.class),
440714f5177Ssumit.saxena@avagotech.com evt_detail->description);
441ae6874baSKashyap Desai
442ae6874baSKashyap Desai if (megasas_dbg_lvl & LD_PD_DEBUG)
443ae6874baSKashyap Desai dev_info(&instance->pdev->dev,
444ae6874baSKashyap Desai "evt_detail.args.ld.target_id/index %d/%d\n",
445ae6874baSKashyap Desai evt_detail->args.ld.target_id, evt_detail->args.ld.ld_index);
446ae6874baSKashyap Desai
447714f5177Ssumit.saxena@avagotech.com }
448714f5177Ssumit.saxena@avagotech.com
4492b46e5c1SDamien Le Moal /*
4500d49016bSadam radford * The following functions are defined for xscale
4510d49016bSadam radford * (deviceid : 1064R, PERC5) controllers
4520d49016bSadam radford */
4530d49016bSadam radford
4540d49016bSadam radford /**
4550d49016bSadam radford * megasas_enable_intr_xscale - Enables interrupts
4562b46e5c1SDamien Le Moal * @instance: Adapter soft state
4570d49016bSadam radford */
4580d49016bSadam radford static inline void
megasas_enable_intr_xscale(struct megasas_instance * instance)459d46a3ad6SSumit.Saxena@lsi.com megasas_enable_intr_xscale(struct megasas_instance *instance)
4600d49016bSadam radford {
461d46a3ad6SSumit.Saxena@lsi.com struct megasas_register_set __iomem *regs;
462da0dc9fbSBjorn Helgaas
463d46a3ad6SSumit.Saxena@lsi.com regs = instance->reg_set;
4640d49016bSadam radford writel(0, &(regs)->outbound_intr_mask);
4650d49016bSadam radford
4660d49016bSadam radford /* Dummy readl to force pci flush */
4670d49016bSadam radford readl(®s->outbound_intr_mask);
4680d49016bSadam radford }
4690d49016bSadam radford
4700d49016bSadam radford /**
4710d49016bSadam radford * megasas_disable_intr_xscale -Disables interrupt
4722b46e5c1SDamien Le Moal * @instance: Adapter soft state
4730d49016bSadam radford */
4740d49016bSadam radford static inline void
megasas_disable_intr_xscale(struct megasas_instance * instance)475d46a3ad6SSumit.Saxena@lsi.com megasas_disable_intr_xscale(struct megasas_instance *instance)
4760d49016bSadam radford {
477d46a3ad6SSumit.Saxena@lsi.com struct megasas_register_set __iomem *regs;
4780d49016bSadam radford u32 mask = 0x1f;
479da0dc9fbSBjorn Helgaas
480d46a3ad6SSumit.Saxena@lsi.com regs = instance->reg_set;
4810d49016bSadam radford writel(mask, ®s->outbound_intr_mask);
4820d49016bSadam radford /* Dummy readl to force pci flush */
4830d49016bSadam radford readl(®s->outbound_intr_mask);
4840d49016bSadam radford }
4850d49016bSadam radford
4860d49016bSadam radford /**
4870d49016bSadam radford * megasas_read_fw_status_reg_xscale - returns the current FW status value
4882b46e5c1SDamien Le Moal * @instance: Adapter soft state
4890d49016bSadam radford */
4900d49016bSadam radford static u32
megasas_read_fw_status_reg_xscale(struct megasas_instance * instance)491de516379SShivasharan S megasas_read_fw_status_reg_xscale(struct megasas_instance *instance)
4920d49016bSadam radford {
493de516379SShivasharan S return readl(&instance->reg_set->outbound_msg_0);
4940d49016bSadam radford }
4950d49016bSadam radford /**
496616f6d8dSLee Jones * megasas_clear_intr_xscale - Check & clear interrupt
4972b46e5c1SDamien Le Moal * @instance: Adapter soft state
4980d49016bSadam radford */
4990d49016bSadam radford static int
megasas_clear_intr_xscale(struct megasas_instance * instance)500de516379SShivasharan S megasas_clear_intr_xscale(struct megasas_instance *instance)
5010d49016bSadam radford {
5020d49016bSadam radford u32 status;
5030d49016bSadam radford u32 mfiStatus = 0;
504de516379SShivasharan S struct megasas_register_set __iomem *regs;
505de516379SShivasharan S regs = instance->reg_set;
506da0dc9fbSBjorn Helgaas
5070d49016bSadam radford /*
5080d49016bSadam radford * Check if it is our interrupt
5090d49016bSadam radford */
5100d49016bSadam radford status = readl(®s->outbound_intr_status);
5110d49016bSadam radford
5120d49016bSadam radford if (status & MFI_OB_INTR_STATUS_MASK)
5130d49016bSadam radford mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
5140d49016bSadam radford if (status & MFI_XSCALE_OMR0_CHANGE_INTERRUPT)
5150d49016bSadam radford mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
5160d49016bSadam radford
5170d49016bSadam radford /*
5180d49016bSadam radford * Clear the interrupt by writing back the same value
5190d49016bSadam radford */
5200d49016bSadam radford if (mfiStatus)
5210d49016bSadam radford writel(status, ®s->outbound_intr_status);
5220d49016bSadam radford
5230d49016bSadam radford /* Dummy readl to force pci flush */
5240d49016bSadam radford readl(®s->outbound_intr_status);
5250d49016bSadam radford
5260d49016bSadam radford return mfiStatus;
5270d49016bSadam radford }
5280d49016bSadam radford
5290d49016bSadam radford /**
5300d49016bSadam radford * megasas_fire_cmd_xscale - Sends command to the FW
5312b46e5c1SDamien Le Moal * @instance: Adapter soft state
5320d49016bSadam radford * @frame_phys_addr : Physical address of cmd
5330d49016bSadam radford * @frame_count : Number of frames for the command
5340d49016bSadam radford * @regs : MFI register set
5350d49016bSadam radford */
5360d49016bSadam radford static inline void
megasas_fire_cmd_xscale(struct megasas_instance * instance,dma_addr_t frame_phys_addr,u32 frame_count,struct megasas_register_set __iomem * regs)5370d49016bSadam radford megasas_fire_cmd_xscale(struct megasas_instance *instance,
5380d49016bSadam radford dma_addr_t frame_phys_addr,
5390d49016bSadam radford u32 frame_count,
5400d49016bSadam radford struct megasas_register_set __iomem *regs)
5410d49016bSadam radford {
5420d49016bSadam radford unsigned long flags;
543da0dc9fbSBjorn Helgaas
5440d49016bSadam radford spin_lock_irqsave(&instance->hba_lock, flags);
5450d49016bSadam radford writel((frame_phys_addr >> 3)|(frame_count),
5460d49016bSadam radford &(regs)->inbound_queue_port);
5470d49016bSadam radford spin_unlock_irqrestore(&instance->hba_lock, flags);
5480d49016bSadam radford }
5490d49016bSadam radford
5500d49016bSadam radford /**
5510d49016bSadam radford * megasas_adp_reset_xscale - For controller reset
5522b46e5c1SDamien Le Moal * @instance: Adapter soft state
5530d49016bSadam radford * @regs: MFI register set
5540d49016bSadam radford */
5550d49016bSadam radford static int
megasas_adp_reset_xscale(struct megasas_instance * instance,struct megasas_register_set __iomem * regs)5560d49016bSadam radford megasas_adp_reset_xscale(struct megasas_instance *instance,
5570d49016bSadam radford struct megasas_register_set __iomem *regs)
5580d49016bSadam radford {
5590d49016bSadam radford u32 i;
5600d49016bSadam radford u32 pcidata;
561da0dc9fbSBjorn Helgaas
5620d49016bSadam radford writel(MFI_ADP_RESET, ®s->inbound_doorbell);
5630d49016bSadam radford
5640d49016bSadam radford for (i = 0; i < 3; i++)
5650d49016bSadam radford msleep(1000); /* sleep for 3 secs */
5660d49016bSadam radford pcidata = 0;
5670d49016bSadam radford pci_read_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, &pcidata);
5681be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "pcidata = %x\n", pcidata);
5690d49016bSadam radford if (pcidata & 0x2) {
5701be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "mfi 1068 offset read=%x\n", pcidata);
5710d49016bSadam radford pcidata &= ~0x2;
5720d49016bSadam radford pci_write_config_dword(instance->pdev,
5730d49016bSadam radford MFI_1068_PCSR_OFFSET, pcidata);
5740d49016bSadam radford
5750d49016bSadam radford for (i = 0; i < 2; i++)
5760d49016bSadam radford msleep(1000); /* need to wait 2 secs again */
5770d49016bSadam radford
5780d49016bSadam radford pcidata = 0;
5790d49016bSadam radford pci_read_config_dword(instance->pdev,
5800d49016bSadam radford MFI_1068_FW_HANDSHAKE_OFFSET, &pcidata);
5811be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "1068 offset handshake read=%x\n", pcidata);
5820d49016bSadam radford if ((pcidata & 0xffff0000) == MFI_1068_FW_READY) {
5831be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "1068 offset pcidt=%x\n", pcidata);
5840d49016bSadam radford pcidata = 0;
5850d49016bSadam radford pci_write_config_dword(instance->pdev,
5860d49016bSadam radford MFI_1068_FW_HANDSHAKE_OFFSET, pcidata);
5870d49016bSadam radford }
5880d49016bSadam radford }
5890d49016bSadam radford return 0;
5900d49016bSadam radford }
5910d49016bSadam radford
5920d49016bSadam radford /**
5930d49016bSadam radford * megasas_check_reset_xscale - For controller reset check
5942b46e5c1SDamien Le Moal * @instance: Adapter soft state
5950d49016bSadam radford * @regs: MFI register set
5960d49016bSadam radford */
5970d49016bSadam radford static int
megasas_check_reset_xscale(struct megasas_instance * instance,struct megasas_register_set __iomem * regs)5980d49016bSadam radford megasas_check_reset_xscale(struct megasas_instance *instance,
5990d49016bSadam radford struct megasas_register_set __iomem *regs)
6000d49016bSadam radford {
6018a01a41dSSumit Saxena if ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) &&
60294cd65ddSSumit.Saxena@lsi.com (le32_to_cpu(*instance->consumer) ==
60394cd65ddSSumit.Saxena@lsi.com MEGASAS_ADPRESET_INPROG_SIGN))
6040d49016bSadam radford return 1;
6050d49016bSadam radford return 0;
6060d49016bSadam radford }
6070d49016bSadam radford
6080d49016bSadam radford static struct megasas_instance_template megasas_instance_template_xscale = {
6090d49016bSadam radford
6100d49016bSadam radford .fire_cmd = megasas_fire_cmd_xscale,
6110d49016bSadam radford .enable_intr = megasas_enable_intr_xscale,
6120d49016bSadam radford .disable_intr = megasas_disable_intr_xscale,
6130d49016bSadam radford .clear_intr = megasas_clear_intr_xscale,
6140d49016bSadam radford .read_fw_status_reg = megasas_read_fw_status_reg_xscale,
6150d49016bSadam radford .adp_reset = megasas_adp_reset_xscale,
6160d49016bSadam radford .check_reset = megasas_check_reset_xscale,
617cd50ba8eSadam radford .service_isr = megasas_isr,
618cd50ba8eSadam radford .tasklet = megasas_complete_cmd_dpc,
619cd50ba8eSadam radford .init_adapter = megasas_init_adapter_mfi,
620cd50ba8eSadam radford .build_and_issue_cmd = megasas_build_and_issue_cmd,
621cd50ba8eSadam radford .issue_dcmd = megasas_issue_dcmd,
6220d49016bSadam radford };
6230d49016bSadam radford
6242b46e5c1SDamien Le Moal /*
6250d49016bSadam radford * This is the end of set of functions & definitions specific
6260d49016bSadam radford * to xscale (deviceid : 1064R, PERC5) controllers
6270d49016bSadam radford */
6280d49016bSadam radford
6292b46e5c1SDamien Le Moal /*
6300d49016bSadam radford * The following functions are defined for ppc (deviceid : 0x60)
6310d49016bSadam radford * controllers
6320d49016bSadam radford */
6330d49016bSadam radford
6340d49016bSadam radford /**
6350d49016bSadam radford * megasas_enable_intr_ppc - Enables interrupts
6362b46e5c1SDamien Le Moal * @instance: Adapter soft state
6370d49016bSadam radford */
6380d49016bSadam radford static inline void
megasas_enable_intr_ppc(struct megasas_instance * instance)639d46a3ad6SSumit.Saxena@lsi.com megasas_enable_intr_ppc(struct megasas_instance *instance)
6400d49016bSadam radford {
641d46a3ad6SSumit.Saxena@lsi.com struct megasas_register_set __iomem *regs;
642da0dc9fbSBjorn Helgaas
643d46a3ad6SSumit.Saxena@lsi.com regs = instance->reg_set;
6440d49016bSadam radford writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
6450d49016bSadam radford
6460d49016bSadam radford writel(~0x80000000, &(regs)->outbound_intr_mask);
6470d49016bSadam radford
6480d49016bSadam radford /* Dummy readl to force pci flush */
6490d49016bSadam radford readl(®s->outbound_intr_mask);
6500d49016bSadam radford }
6510d49016bSadam radford
6520d49016bSadam radford /**
6530d49016bSadam radford * megasas_disable_intr_ppc - Disable interrupt
6542b46e5c1SDamien Le Moal * @instance: Adapter soft state
6550d49016bSadam radford */
6560d49016bSadam radford static inline void
megasas_disable_intr_ppc(struct megasas_instance * instance)657d46a3ad6SSumit.Saxena@lsi.com megasas_disable_intr_ppc(struct megasas_instance *instance)
6580d49016bSadam radford {
659d46a3ad6SSumit.Saxena@lsi.com struct megasas_register_set __iomem *regs;
6600d49016bSadam radford u32 mask = 0xFFFFFFFF;
661da0dc9fbSBjorn Helgaas
662d46a3ad6SSumit.Saxena@lsi.com regs = instance->reg_set;
6630d49016bSadam radford writel(mask, ®s->outbound_intr_mask);
6640d49016bSadam radford /* Dummy readl to force pci flush */
6650d49016bSadam radford readl(®s->outbound_intr_mask);
6660d49016bSadam radford }
6670d49016bSadam radford
6680d49016bSadam radford /**
6690d49016bSadam radford * megasas_read_fw_status_reg_ppc - returns the current FW status value
6702b46e5c1SDamien Le Moal * @instance: Adapter soft state
6710d49016bSadam radford */
6720d49016bSadam radford static u32
megasas_read_fw_status_reg_ppc(struct megasas_instance * instance)673de516379SShivasharan S megasas_read_fw_status_reg_ppc(struct megasas_instance *instance)
6740d49016bSadam radford {
675de516379SShivasharan S return readl(&instance->reg_set->outbound_scratch_pad_0);
6760d49016bSadam radford }
6770d49016bSadam radford
6780d49016bSadam radford /**
679616f6d8dSLee Jones * megasas_clear_intr_ppc - Check & clear interrupt
6802b46e5c1SDamien Le Moal * @instance: Adapter soft state
6810d49016bSadam radford */
6820d49016bSadam radford static int
megasas_clear_intr_ppc(struct megasas_instance * instance)683de516379SShivasharan S megasas_clear_intr_ppc(struct megasas_instance *instance)
6840d49016bSadam radford {
6853cc6851fSadam radford u32 status, mfiStatus = 0;
686de516379SShivasharan S struct megasas_register_set __iomem *regs;
687de516379SShivasharan S regs = instance->reg_set;
6883cc6851fSadam radford
6890d49016bSadam radford /*
6900d49016bSadam radford * Check if it is our interrupt
6910d49016bSadam radford */
6920d49016bSadam radford status = readl(®s->outbound_intr_status);
6930d49016bSadam radford
6943cc6851fSadam radford if (status & MFI_REPLY_1078_MESSAGE_INTERRUPT)
6953cc6851fSadam radford mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
6963cc6851fSadam radford
6973cc6851fSadam radford if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT)
6983cc6851fSadam radford mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
6990d49016bSadam radford
7000d49016bSadam radford /*
7010d49016bSadam radford * Clear the interrupt by writing back the same value
7020d49016bSadam radford */
7030d49016bSadam radford writel(status, ®s->outbound_doorbell_clear);
7040d49016bSadam radford
7050d49016bSadam radford /* Dummy readl to force pci flush */
7060d49016bSadam radford readl(®s->outbound_doorbell_clear);
7070d49016bSadam radford
7083cc6851fSadam radford return mfiStatus;
7090d49016bSadam radford }
7103cc6851fSadam radford
7110d49016bSadam radford /**
7120d49016bSadam radford * megasas_fire_cmd_ppc - Sends command to the FW
7132b46e5c1SDamien Le Moal * @instance: Adapter soft state
7140d49016bSadam radford * @frame_phys_addr: Physical address of cmd
7150d49016bSadam radford * @frame_count: Number of frames for the command
7160d49016bSadam radford * @regs: MFI register set
7170d49016bSadam radford */
7180d49016bSadam radford static inline void
megasas_fire_cmd_ppc(struct megasas_instance * instance,dma_addr_t frame_phys_addr,u32 frame_count,struct megasas_register_set __iomem * regs)7190d49016bSadam radford megasas_fire_cmd_ppc(struct megasas_instance *instance,
7200d49016bSadam radford dma_addr_t frame_phys_addr,
7210d49016bSadam radford u32 frame_count,
7220d49016bSadam radford struct megasas_register_set __iomem *regs)
7230d49016bSadam radford {
7240d49016bSadam radford unsigned long flags;
725da0dc9fbSBjorn Helgaas
7260d49016bSadam radford spin_lock_irqsave(&instance->hba_lock, flags);
7270d49016bSadam radford writel((frame_phys_addr | (frame_count<<1))|1,
7280d49016bSadam radford &(regs)->inbound_queue_port);
7290d49016bSadam radford spin_unlock_irqrestore(&instance->hba_lock, flags);
7300d49016bSadam radford }
7310d49016bSadam radford
7320d49016bSadam radford /**
7330d49016bSadam radford * megasas_check_reset_ppc - For controller reset check
7342b46e5c1SDamien Le Moal * @instance: Adapter soft state
7350d49016bSadam radford * @regs: MFI register set
7360d49016bSadam radford */
7370d49016bSadam radford static int
megasas_check_reset_ppc(struct megasas_instance * instance,struct megasas_register_set __iomem * regs)7380d49016bSadam radford megasas_check_reset_ppc(struct megasas_instance *instance,
7390d49016bSadam radford struct megasas_register_set __iomem *regs)
7400d49016bSadam radford {
7418a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
7423cc6851fSadam radford return 1;
7433cc6851fSadam radford
7440d49016bSadam radford return 0;
7450d49016bSadam radford }
7463cc6851fSadam radford
7470d49016bSadam radford static struct megasas_instance_template megasas_instance_template_ppc = {
7480d49016bSadam radford
7490d49016bSadam radford .fire_cmd = megasas_fire_cmd_ppc,
7500d49016bSadam radford .enable_intr = megasas_enable_intr_ppc,
7510d49016bSadam radford .disable_intr = megasas_disable_intr_ppc,
7520d49016bSadam radford .clear_intr = megasas_clear_intr_ppc,
7530d49016bSadam radford .read_fw_status_reg = megasas_read_fw_status_reg_ppc,
7543cc6851fSadam radford .adp_reset = megasas_adp_reset_xscale,
7550d49016bSadam radford .check_reset = megasas_check_reset_ppc,
756cd50ba8eSadam radford .service_isr = megasas_isr,
757cd50ba8eSadam radford .tasklet = megasas_complete_cmd_dpc,
758cd50ba8eSadam radford .init_adapter = megasas_init_adapter_mfi,
759cd50ba8eSadam radford .build_and_issue_cmd = megasas_build_and_issue_cmd,
760cd50ba8eSadam radford .issue_dcmd = megasas_issue_dcmd,
7610d49016bSadam radford };
7620d49016bSadam radford
7630d49016bSadam radford /**
7640d49016bSadam radford * megasas_enable_intr_skinny - Enables interrupts
7652b46e5c1SDamien Le Moal * @instance: Adapter soft state
7660d49016bSadam radford */
7670d49016bSadam radford static inline void
megasas_enable_intr_skinny(struct megasas_instance * instance)768d46a3ad6SSumit.Saxena@lsi.com megasas_enable_intr_skinny(struct megasas_instance *instance)
7690d49016bSadam radford {
770d46a3ad6SSumit.Saxena@lsi.com struct megasas_register_set __iomem *regs;
771da0dc9fbSBjorn Helgaas
772d46a3ad6SSumit.Saxena@lsi.com regs = instance->reg_set;
7730d49016bSadam radford writel(0xFFFFFFFF, &(regs)->outbound_intr_mask);
7740d49016bSadam radford
7750d49016bSadam radford writel(~MFI_SKINNY_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
7760d49016bSadam radford
7770d49016bSadam radford /* Dummy readl to force pci flush */
7780d49016bSadam radford readl(®s->outbound_intr_mask);
7790d49016bSadam radford }
7800d49016bSadam radford
7810d49016bSadam radford /**
7820d49016bSadam radford * megasas_disable_intr_skinny - Disables interrupt
7832b46e5c1SDamien Le Moal * @instance: Adapter soft state
7840d49016bSadam radford */
7850d49016bSadam radford static inline void
megasas_disable_intr_skinny(struct megasas_instance * instance)786d46a3ad6SSumit.Saxena@lsi.com megasas_disable_intr_skinny(struct megasas_instance *instance)
7870d49016bSadam radford {
788d46a3ad6SSumit.Saxena@lsi.com struct megasas_register_set __iomem *regs;
7890d49016bSadam radford u32 mask = 0xFFFFFFFF;
790da0dc9fbSBjorn Helgaas
791d46a3ad6SSumit.Saxena@lsi.com regs = instance->reg_set;
7920d49016bSadam radford writel(mask, ®s->outbound_intr_mask);
7930d49016bSadam radford /* Dummy readl to force pci flush */
7940d49016bSadam radford readl(®s->outbound_intr_mask);
7950d49016bSadam radford }
7960d49016bSadam radford
7970d49016bSadam radford /**
7980d49016bSadam radford * megasas_read_fw_status_reg_skinny - returns the current FW status value
7992b46e5c1SDamien Le Moal * @instance: Adapter soft state
8000d49016bSadam radford */
8010d49016bSadam radford static u32
megasas_read_fw_status_reg_skinny(struct megasas_instance * instance)802de516379SShivasharan S megasas_read_fw_status_reg_skinny(struct megasas_instance *instance)
8030d49016bSadam radford {
804de516379SShivasharan S return readl(&instance->reg_set->outbound_scratch_pad_0);
8050d49016bSadam radford }
8060d49016bSadam radford
8070d49016bSadam radford /**
808616f6d8dSLee Jones * megasas_clear_intr_skinny - Check & clear interrupt
8092b46e5c1SDamien Le Moal * @instance: Adapter soft state
8100d49016bSadam radford */
8110d49016bSadam radford static int
megasas_clear_intr_skinny(struct megasas_instance * instance)812de516379SShivasharan S megasas_clear_intr_skinny(struct megasas_instance *instance)
8130d49016bSadam radford {
8140d49016bSadam radford u32 status;
815ebf054b0Sadam radford u32 mfiStatus = 0;
816de516379SShivasharan S struct megasas_register_set __iomem *regs;
817de516379SShivasharan S regs = instance->reg_set;
818ebf054b0Sadam radford
8190d49016bSadam radford /*
8200d49016bSadam radford * Check if it is our interrupt
8210d49016bSadam radford */
8220d49016bSadam radford status = readl(®s->outbound_intr_status);
8230d49016bSadam radford
8240d49016bSadam radford if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) {
8250d49016bSadam radford return 0;
8260d49016bSadam radford }
8270d49016bSadam radford
8280d49016bSadam radford /*
829ebf054b0Sadam radford * Check if it is our interrupt
830ebf054b0Sadam radford */
831de516379SShivasharan S if ((megasas_read_fw_status_reg_skinny(instance) & MFI_STATE_MASK) ==
832ebf054b0Sadam radford MFI_STATE_FAULT) {
833ebf054b0Sadam radford mfiStatus = MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
834ebf054b0Sadam radford } else
835ebf054b0Sadam radford mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
836ebf054b0Sadam radford
837ebf054b0Sadam radford /*
8380d49016bSadam radford * Clear the interrupt by writing back the same value
8390d49016bSadam radford */
8400d49016bSadam radford writel(status, ®s->outbound_intr_status);
8410d49016bSadam radford
8420d49016bSadam radford /*
8430d49016bSadam radford * dummy read to flush PCI
8440d49016bSadam radford */
8450d49016bSadam radford readl(®s->outbound_intr_status);
8460d49016bSadam radford
847ebf054b0Sadam radford return mfiStatus;
8480d49016bSadam radford }
8490d49016bSadam radford
8500d49016bSadam radford /**
8510d49016bSadam radford * megasas_fire_cmd_skinny - Sends command to the FW
8522b46e5c1SDamien Le Moal * @instance: Adapter soft state
8530d49016bSadam radford * @frame_phys_addr: Physical address of cmd
8540d49016bSadam radford * @frame_count: Number of frames for the command
8550d49016bSadam radford * @regs: MFI register set
8560d49016bSadam radford */
8570d49016bSadam radford static inline void
megasas_fire_cmd_skinny(struct megasas_instance * instance,dma_addr_t frame_phys_addr,u32 frame_count,struct megasas_register_set __iomem * regs)8580d49016bSadam radford megasas_fire_cmd_skinny(struct megasas_instance *instance,
8590d49016bSadam radford dma_addr_t frame_phys_addr,
8600d49016bSadam radford u32 frame_count,
8610d49016bSadam radford struct megasas_register_set __iomem *regs)
8620d49016bSadam radford {
8630d49016bSadam radford unsigned long flags;
864da0dc9fbSBjorn Helgaas
8650d49016bSadam radford spin_lock_irqsave(&instance->hba_lock, flags);
86694cd65ddSSumit.Saxena@lsi.com writel(upper_32_bits(frame_phys_addr),
86794cd65ddSSumit.Saxena@lsi.com &(regs)->inbound_high_queue_port);
86894cd65ddSSumit.Saxena@lsi.com writel((lower_32_bits(frame_phys_addr) | (frame_count<<1))|1,
8690d49016bSadam radford &(regs)->inbound_low_queue_port);
8700d49016bSadam radford spin_unlock_irqrestore(&instance->hba_lock, flags);
8710d49016bSadam radford }
8720d49016bSadam radford
8730d49016bSadam radford /**
8740d49016bSadam radford * megasas_check_reset_skinny - For controller reset check
8752b46e5c1SDamien Le Moal * @instance: Adapter soft state
8760d49016bSadam radford * @regs: MFI register set
8770d49016bSadam radford */
8780d49016bSadam radford static int
megasas_check_reset_skinny(struct megasas_instance * instance,struct megasas_register_set __iomem * regs)8790d49016bSadam radford megasas_check_reset_skinny(struct megasas_instance *instance,
8800d49016bSadam radford struct megasas_register_set __iomem *regs)
8810d49016bSadam radford {
8828a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
8833cc6851fSadam radford return 1;
8843cc6851fSadam radford
8850d49016bSadam radford return 0;
8860d49016bSadam radford }
8870d49016bSadam radford
8880d49016bSadam radford static struct megasas_instance_template megasas_instance_template_skinny = {
8890d49016bSadam radford
8900d49016bSadam radford .fire_cmd = megasas_fire_cmd_skinny,
8910d49016bSadam radford .enable_intr = megasas_enable_intr_skinny,
8920d49016bSadam radford .disable_intr = megasas_disable_intr_skinny,
8930d49016bSadam radford .clear_intr = megasas_clear_intr_skinny,
8940d49016bSadam radford .read_fw_status_reg = megasas_read_fw_status_reg_skinny,
895ebf054b0Sadam radford .adp_reset = megasas_adp_reset_gen2,
8960d49016bSadam radford .check_reset = megasas_check_reset_skinny,
897cd50ba8eSadam radford .service_isr = megasas_isr,
898cd50ba8eSadam radford .tasklet = megasas_complete_cmd_dpc,
899cd50ba8eSadam radford .init_adapter = megasas_init_adapter_mfi,
900cd50ba8eSadam radford .build_and_issue_cmd = megasas_build_and_issue_cmd,
901cd50ba8eSadam radford .issue_dcmd = megasas_issue_dcmd,
9020d49016bSadam radford };
9030d49016bSadam radford
9040d49016bSadam radford
9052b46e5c1SDamien Le Moal /*
9060d49016bSadam radford * The following functions are defined for gen2 (deviceid : 0x78 0x79)
9070d49016bSadam radford * controllers
9080d49016bSadam radford */
9090d49016bSadam radford
9100d49016bSadam radford /**
9110d49016bSadam radford * megasas_enable_intr_gen2 - Enables interrupts
9122b46e5c1SDamien Le Moal * @instance: Adapter soft state
9130d49016bSadam radford */
9140d49016bSadam radford static inline void
megasas_enable_intr_gen2(struct megasas_instance * instance)915d46a3ad6SSumit.Saxena@lsi.com megasas_enable_intr_gen2(struct megasas_instance *instance)
9160d49016bSadam radford {
917d46a3ad6SSumit.Saxena@lsi.com struct megasas_register_set __iomem *regs;
918da0dc9fbSBjorn Helgaas
919d46a3ad6SSumit.Saxena@lsi.com regs = instance->reg_set;
9200d49016bSadam radford writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
9210d49016bSadam radford
9220d49016bSadam radford /* write ~0x00000005 (4 & 1) to the intr mask*/
9230d49016bSadam radford writel(~MFI_GEN2_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
9240d49016bSadam radford
9250d49016bSadam radford /* Dummy readl to force pci flush */
9260d49016bSadam radford readl(®s->outbound_intr_mask);
9270d49016bSadam radford }
9280d49016bSadam radford
9290d49016bSadam radford /**
9300d49016bSadam radford * megasas_disable_intr_gen2 - Disables interrupt
9312b46e5c1SDamien Le Moal * @instance: Adapter soft state
9320d49016bSadam radford */
9330d49016bSadam radford static inline void
megasas_disable_intr_gen2(struct megasas_instance * instance)934d46a3ad6SSumit.Saxena@lsi.com megasas_disable_intr_gen2(struct megasas_instance *instance)
9350d49016bSadam radford {
936d46a3ad6SSumit.Saxena@lsi.com struct megasas_register_set __iomem *regs;
9370d49016bSadam radford u32 mask = 0xFFFFFFFF;
938da0dc9fbSBjorn Helgaas
939d46a3ad6SSumit.Saxena@lsi.com regs = instance->reg_set;
9400d49016bSadam radford writel(mask, ®s->outbound_intr_mask);
9410d49016bSadam radford /* Dummy readl to force pci flush */
9420d49016bSadam radford readl(®s->outbound_intr_mask);
9430d49016bSadam radford }
9440d49016bSadam radford
9450d49016bSadam radford /**
9460d49016bSadam radford * megasas_read_fw_status_reg_gen2 - returns the current FW status value
9472b46e5c1SDamien Le Moal * @instance: Adapter soft state
9480d49016bSadam radford */
9490d49016bSadam radford static u32
megasas_read_fw_status_reg_gen2(struct megasas_instance * instance)950de516379SShivasharan S megasas_read_fw_status_reg_gen2(struct megasas_instance *instance)
9510d49016bSadam radford {
952de516379SShivasharan S return readl(&instance->reg_set->outbound_scratch_pad_0);
9530d49016bSadam radford }
9540d49016bSadam radford
9550d49016bSadam radford /**
956616f6d8dSLee Jones * megasas_clear_intr_gen2 - Check & clear interrupt
9572b46e5c1SDamien Le Moal * @instance: Adapter soft state
9580d49016bSadam radford */
9590d49016bSadam radford static int
megasas_clear_intr_gen2(struct megasas_instance * instance)960de516379SShivasharan S megasas_clear_intr_gen2(struct megasas_instance *instance)
9610d49016bSadam radford {
9620d49016bSadam radford u32 status;
9630d49016bSadam radford u32 mfiStatus = 0;
964de516379SShivasharan S struct megasas_register_set __iomem *regs;
965de516379SShivasharan S regs = instance->reg_set;
966da0dc9fbSBjorn Helgaas
9670d49016bSadam radford /*
9680d49016bSadam radford * Check if it is our interrupt
9690d49016bSadam radford */
9700d49016bSadam radford status = readl(®s->outbound_intr_status);
9710d49016bSadam radford
972b5bccaddSSumit.Saxena@lsi.com if (status & MFI_INTR_FLAG_REPLY_MESSAGE) {
9730d49016bSadam radford mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
9740d49016bSadam radford }
9750d49016bSadam radford if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT) {
9760d49016bSadam radford mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
9770d49016bSadam radford }
9780d49016bSadam radford
9790d49016bSadam radford /*
9800d49016bSadam radford * Clear the interrupt by writing back the same value
9810d49016bSadam radford */
9820d49016bSadam radford if (mfiStatus)
9830d49016bSadam radford writel(status, ®s->outbound_doorbell_clear);
9840d49016bSadam radford
9850d49016bSadam radford /* Dummy readl to force pci flush */
9860d49016bSadam radford readl(®s->outbound_intr_status);
9870d49016bSadam radford
9880d49016bSadam radford return mfiStatus;
9890d49016bSadam radford }
9902b46e5c1SDamien Le Moal
9910d49016bSadam radford /**
9920d49016bSadam radford * megasas_fire_cmd_gen2 - Sends command to the FW
9932b46e5c1SDamien Le Moal * @instance: Adapter soft state
9940d49016bSadam radford * @frame_phys_addr: Physical address of cmd
9950d49016bSadam radford * @frame_count: Number of frames for the command
9960d49016bSadam radford * @regs: MFI register set
9970d49016bSadam radford */
9980d49016bSadam radford static inline void
megasas_fire_cmd_gen2(struct megasas_instance * instance,dma_addr_t frame_phys_addr,u32 frame_count,struct megasas_register_set __iomem * regs)9990d49016bSadam radford megasas_fire_cmd_gen2(struct megasas_instance *instance,
10000d49016bSadam radford dma_addr_t frame_phys_addr,
10010d49016bSadam radford u32 frame_count,
10020d49016bSadam radford struct megasas_register_set __iomem *regs)
10030d49016bSadam radford {
10040d49016bSadam radford unsigned long flags;
1005da0dc9fbSBjorn Helgaas
10060d49016bSadam radford spin_lock_irqsave(&instance->hba_lock, flags);
10070d49016bSadam radford writel((frame_phys_addr | (frame_count<<1))|1,
10080d49016bSadam radford &(regs)->inbound_queue_port);
10090d49016bSadam radford spin_unlock_irqrestore(&instance->hba_lock, flags);
10100d49016bSadam radford }
10110d49016bSadam radford
10120d49016bSadam radford /**
10130d49016bSadam radford * megasas_adp_reset_gen2 - For controller reset
10142b46e5c1SDamien Le Moal * @instance: Adapter soft state
10152b46e5c1SDamien Le Moal * @reg_set: MFI register set
10160d49016bSadam radford */
10170d49016bSadam radford static int
megasas_adp_reset_gen2(struct megasas_instance * instance,struct megasas_register_set __iomem * reg_set)10180d49016bSadam radford megasas_adp_reset_gen2(struct megasas_instance *instance,
10190d49016bSadam radford struct megasas_register_set __iomem *reg_set)
10200d49016bSadam radford {
10210d49016bSadam radford u32 retry = 0 ;
10220d49016bSadam radford u32 HostDiag;
10238a232bb3SChristoph Hellwig u32 __iomem *seq_offset = ®_set->seq_offset;
10248a232bb3SChristoph Hellwig u32 __iomem *hostdiag_offset = ®_set->host_diag;
10250d49016bSadam radford
1026ebf054b0Sadam radford if (instance->instancet == &megasas_instance_template_skinny) {
1027ebf054b0Sadam radford seq_offset = ®_set->fusion_seq_offset;
1028ebf054b0Sadam radford hostdiag_offset = ®_set->fusion_host_diag;
1029ebf054b0Sadam radford }
1030ebf054b0Sadam radford
1031ebf054b0Sadam radford writel(0, seq_offset);
1032ebf054b0Sadam radford writel(4, seq_offset);
1033ebf054b0Sadam radford writel(0xb, seq_offset);
1034ebf054b0Sadam radford writel(2, seq_offset);
1035ebf054b0Sadam radford writel(7, seq_offset);
1036ebf054b0Sadam radford writel(0xd, seq_offset);
1037ebf054b0Sadam radford
10380d49016bSadam radford msleep(1000);
10390d49016bSadam radford
1040ebf054b0Sadam radford HostDiag = (u32)readl(hostdiag_offset);
10410d49016bSadam radford
10420d49016bSadam radford while (!(HostDiag & DIAG_WRITE_ENABLE)) {
10430d49016bSadam radford msleep(100);
1044ebf054b0Sadam radford HostDiag = (u32)readl(hostdiag_offset);
10451be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "RESETGEN2: retry=%x, hostdiag=%x\n",
10460d49016bSadam radford retry, HostDiag);
10470d49016bSadam radford
10480d49016bSadam radford if (retry++ >= 100)
10490d49016bSadam radford return 1;
10500d49016bSadam radford
10510d49016bSadam radford }
10520d49016bSadam radford
10531be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag);
10540d49016bSadam radford
1055ebf054b0Sadam radford writel((HostDiag | DIAG_RESET_ADAPTER), hostdiag_offset);
10560d49016bSadam radford
10570d49016bSadam radford ssleep(10);
10580d49016bSadam radford
1059ebf054b0Sadam radford HostDiag = (u32)readl(hostdiag_offset);
1060da0dc9fbSBjorn Helgaas while (HostDiag & DIAG_RESET_ADAPTER) {
10610d49016bSadam radford msleep(100);
1062ebf054b0Sadam radford HostDiag = (u32)readl(hostdiag_offset);
10631be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "RESET_GEN2: retry=%x, hostdiag=%x\n",
10640d49016bSadam radford retry, HostDiag);
10650d49016bSadam radford
10660d49016bSadam radford if (retry++ >= 1000)
10670d49016bSadam radford return 1;
10680d49016bSadam radford
10690d49016bSadam radford }
10700d49016bSadam radford return 0;
10710d49016bSadam radford }
10720d49016bSadam radford
10730d49016bSadam radford /**
10740d49016bSadam radford * megasas_check_reset_gen2 - For controller reset check
10752b46e5c1SDamien Le Moal * @instance: Adapter soft state
10760d49016bSadam radford * @regs: MFI register set
10770d49016bSadam radford */
10780d49016bSadam radford static int
megasas_check_reset_gen2(struct megasas_instance * instance,struct megasas_register_set __iomem * regs)10790d49016bSadam radford megasas_check_reset_gen2(struct megasas_instance *instance,
10800d49016bSadam radford struct megasas_register_set __iomem *regs)
10810d49016bSadam radford {
10828a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
10830d49016bSadam radford return 1;
10840d49016bSadam radford
10850d49016bSadam radford return 0;
10860d49016bSadam radford }
10870d49016bSadam radford
10880d49016bSadam radford static struct megasas_instance_template megasas_instance_template_gen2 = {
10890d49016bSadam radford
10900d49016bSadam radford .fire_cmd = megasas_fire_cmd_gen2,
10910d49016bSadam radford .enable_intr = megasas_enable_intr_gen2,
10920d49016bSadam radford .disable_intr = megasas_disable_intr_gen2,
10930d49016bSadam radford .clear_intr = megasas_clear_intr_gen2,
10940d49016bSadam radford .read_fw_status_reg = megasas_read_fw_status_reg_gen2,
10950d49016bSadam radford .adp_reset = megasas_adp_reset_gen2,
10960d49016bSadam radford .check_reset = megasas_check_reset_gen2,
1097cd50ba8eSadam radford .service_isr = megasas_isr,
1098cd50ba8eSadam radford .tasklet = megasas_complete_cmd_dpc,
1099cd50ba8eSadam radford .init_adapter = megasas_init_adapter_mfi,
1100cd50ba8eSadam radford .build_and_issue_cmd = megasas_build_and_issue_cmd,
1101cd50ba8eSadam radford .issue_dcmd = megasas_issue_dcmd,
11020d49016bSadam radford };
11030d49016bSadam radford
11042b46e5c1SDamien Le Moal /*
11050d49016bSadam radford * This is the end of set of functions & definitions
11060d49016bSadam radford * specific to gen2 (deviceid : 0x78, 0x79) controllers
11070d49016bSadam radford */
11080d49016bSadam radford
11099c915a8cSadam radford /*
11109c915a8cSadam radford * Template added for TB (Fusion)
11119c915a8cSadam radford */
11129c915a8cSadam radford extern struct megasas_instance_template megasas_instance_template_fusion;
11139c915a8cSadam radford
11140d49016bSadam radford /**
11150d49016bSadam radford * megasas_issue_polled - Issues a polling command
11160d49016bSadam radford * @instance: Adapter soft state
11170d49016bSadam radford * @cmd: Command packet to be issued
11180d49016bSadam radford *
11192be2a988SSumit.Saxena@avagotech.com * For polling, MFI requires the cmd_status to be set to MFI_STAT_INVALID_STATUS before posting.
11200d49016bSadam radford */
11219c915a8cSadam radford int
megasas_issue_polled(struct megasas_instance * instance,struct megasas_cmd * cmd)11220d49016bSadam radford megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
11230d49016bSadam radford {
11240d49016bSadam radford struct megasas_header *frame_hdr = &cmd->frame->hdr;
11250d49016bSadam radford
11266d40afbcSSumit Saxena frame_hdr->cmd_status = MFI_STAT_INVALID_STATUS;
112794cd65ddSSumit.Saxena@lsi.com frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
11280d49016bSadam radford
1129f4fc2093SShivasharan S if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
11306d40afbcSSumit Saxena dev_err(&instance->pdev->dev, "Failed from %s %d\n",
11316d40afbcSSumit Saxena __func__, __LINE__);
1132201a810cSAnand Lodnoor return DCMD_INIT;
11336d40afbcSSumit Saxena }
11340d49016bSadam radford
1135f4fc2093SShivasharan S instance->instancet->issue_dcmd(instance, cmd);
1136f4fc2093SShivasharan S
11376d40afbcSSumit Saxena return wait_and_poll(instance, cmd, instance->requestorId ?
11386d40afbcSSumit Saxena MEGASAS_ROUTINE_WAIT_TIME_VF : MFI_IO_TIMEOUT_SECS);
11390d49016bSadam radford }
11400d49016bSadam radford
11410d49016bSadam radford /**
11420d49016bSadam radford * megasas_issue_blocked_cmd - Synchronous wrapper around regular FW cmds
11430d49016bSadam radford * @instance: Adapter soft state
11440d49016bSadam radford * @cmd: Command to be issued
1145cfbe7554SSumit.Saxena@lsi.com * @timeout: Timeout in seconds
11460d49016bSadam radford *
11470d49016bSadam radford * This function waits on an event for the command to be returned from ISR.
11480d49016bSadam radford * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
11490d49016bSadam radford * Used to issue ioctl commands.
11500d49016bSadam radford */
115190dc9d98SSumit.Saxena@avagotech.com int
megasas_issue_blocked_cmd(struct megasas_instance * instance,struct megasas_cmd * cmd,int timeout)11520d49016bSadam radford megasas_issue_blocked_cmd(struct megasas_instance *instance,
1153cfbe7554SSumit.Saxena@lsi.com struct megasas_cmd *cmd, int timeout)
11540d49016bSadam radford {
1155cfbe7554SSumit.Saxena@lsi.com int ret = 0;
1156201a810cSAnand Lodnoor cmd->cmd_status_drv = DCMD_INIT;
11570d49016bSadam radford
1158f4fc2093SShivasharan S if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
11596d40afbcSSumit Saxena dev_err(&instance->pdev->dev, "Failed from %s %d\n",
11606d40afbcSSumit Saxena __func__, __LINE__);
1161201a810cSAnand Lodnoor return DCMD_INIT;
11626d40afbcSSumit Saxena }
11636d40afbcSSumit Saxena
1164f4fc2093SShivasharan S instance->instancet->issue_dcmd(instance, cmd);
1165f4fc2093SShivasharan S
1166cfbe7554SSumit.Saxena@lsi.com if (timeout) {
1167cfbe7554SSumit.Saxena@lsi.com ret = wait_event_timeout(instance->int_cmd_wait_q,
1168201a810cSAnand Lodnoor cmd->cmd_status_drv != DCMD_INIT, timeout * HZ);
11696d40afbcSSumit Saxena if (!ret) {
11702ce43508SShivasharan S dev_err(&instance->pdev->dev,
11712ce43508SShivasharan S "DCMD(opcode: 0x%x) is timed out, func:%s\n",
11722ce43508SShivasharan S cmd->frame->dcmd.opcode, __func__);
11736d40afbcSSumit Saxena return DCMD_TIMEOUT;
11746d40afbcSSumit Saxena }
1175cfbe7554SSumit.Saxena@lsi.com } else
1176cfbe7554SSumit.Saxena@lsi.com wait_event(instance->int_cmd_wait_q,
1177201a810cSAnand Lodnoor cmd->cmd_status_drv != DCMD_INIT);
11780d49016bSadam radford
1179201a810cSAnand Lodnoor return cmd->cmd_status_drv;
11800d49016bSadam radford }
11810d49016bSadam radford
11820d49016bSadam radford /**
11830d49016bSadam radford * megasas_issue_blocked_abort_cmd - Aborts previously issued cmd
11840d49016bSadam radford * @instance: Adapter soft state
11850d49016bSadam radford * @cmd_to_abort: Previously issued cmd to be aborted
1186cfbe7554SSumit.Saxena@lsi.com * @timeout: Timeout in seconds
11870d49016bSadam radford *
1188cfbe7554SSumit.Saxena@lsi.com * MFI firmware can abort previously issued AEN comamnd (automatic event
11890d49016bSadam radford * notification). The megasas_issue_blocked_abort_cmd() issues such abort
11900d49016bSadam radford * cmd and waits for return status.
11910d49016bSadam radford * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
11920d49016bSadam radford */
11930d49016bSadam radford static int
megasas_issue_blocked_abort_cmd(struct megasas_instance * instance,struct megasas_cmd * cmd_to_abort,int timeout)11940d49016bSadam radford megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
1195cfbe7554SSumit.Saxena@lsi.com struct megasas_cmd *cmd_to_abort, int timeout)
11960d49016bSadam radford {
11970d49016bSadam radford struct megasas_cmd *cmd;
11980d49016bSadam radford struct megasas_abort_frame *abort_fr;
1199cfbe7554SSumit.Saxena@lsi.com int ret = 0;
12002ce43508SShivasharan S u32 opcode;
12010d49016bSadam radford
12020d49016bSadam radford cmd = megasas_get_cmd(instance);
12030d49016bSadam radford
12040d49016bSadam radford if (!cmd)
12050d49016bSadam radford return -1;
12060d49016bSadam radford
12070d49016bSadam radford abort_fr = &cmd->frame->abort;
12080d49016bSadam radford
12090d49016bSadam radford /*
12100d49016bSadam radford * Prepare and issue the abort frame
12110d49016bSadam radford */
12120d49016bSadam radford abort_fr->cmd = MFI_CMD_ABORT;
12132be2a988SSumit.Saxena@avagotech.com abort_fr->cmd_status = MFI_STAT_INVALID_STATUS;
121494cd65ddSSumit.Saxena@lsi.com abort_fr->flags = cpu_to_le16(0);
121594cd65ddSSumit.Saxena@lsi.com abort_fr->abort_context = cpu_to_le32(cmd_to_abort->index);
121694cd65ddSSumit.Saxena@lsi.com abort_fr->abort_mfi_phys_addr_lo =
121794cd65ddSSumit.Saxena@lsi.com cpu_to_le32(lower_32_bits(cmd_to_abort->frame_phys_addr));
121894cd65ddSSumit.Saxena@lsi.com abort_fr->abort_mfi_phys_addr_hi =
121994cd65ddSSumit.Saxena@lsi.com cpu_to_le32(upper_32_bits(cmd_to_abort->frame_phys_addr));
12200d49016bSadam radford
12210d49016bSadam radford cmd->sync_cmd = 1;
1222201a810cSAnand Lodnoor cmd->cmd_status_drv = DCMD_INIT;
12230d49016bSadam radford
1224f4fc2093SShivasharan S if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
12256d40afbcSSumit Saxena dev_err(&instance->pdev->dev, "Failed from %s %d\n",
12266d40afbcSSumit Saxena __func__, __LINE__);
1227201a810cSAnand Lodnoor return DCMD_INIT;
12286d40afbcSSumit Saxena }
12290d49016bSadam radford
1230f4fc2093SShivasharan S instance->instancet->issue_dcmd(instance, cmd);
1231f4fc2093SShivasharan S
1232cfbe7554SSumit.Saxena@lsi.com if (timeout) {
1233cfbe7554SSumit.Saxena@lsi.com ret = wait_event_timeout(instance->abort_cmd_wait_q,
1234201a810cSAnand Lodnoor cmd->cmd_status_drv != DCMD_INIT, timeout * HZ);
1235cfbe7554SSumit.Saxena@lsi.com if (!ret) {
12362ce43508SShivasharan S opcode = cmd_to_abort->frame->dcmd.opcode;
12372ce43508SShivasharan S dev_err(&instance->pdev->dev,
12382ce43508SShivasharan S "Abort(to be aborted DCMD opcode: 0x%x) is timed out func:%s\n",
12392ce43508SShivasharan S opcode, __func__);
12406d40afbcSSumit Saxena return DCMD_TIMEOUT;
1241cfbe7554SSumit.Saxena@lsi.com }
1242cfbe7554SSumit.Saxena@lsi.com } else
1243cfbe7554SSumit.Saxena@lsi.com wait_event(instance->abort_cmd_wait_q,
1244201a810cSAnand Lodnoor cmd->cmd_status_drv != DCMD_INIT);
1245cfbe7554SSumit.Saxena@lsi.com
12460d49016bSadam radford cmd->sync_cmd = 0;
12470d49016bSadam radford
12480d49016bSadam radford megasas_return_cmd(instance, cmd);
1249201a810cSAnand Lodnoor return cmd->cmd_status_drv;
12500d49016bSadam radford }
12510d49016bSadam radford
12520d49016bSadam radford /**
12530d49016bSadam radford * megasas_make_sgl32 - Prepares 32-bit SGL
12540d49016bSadam radford * @instance: Adapter soft state
12550d49016bSadam radford * @scp: SCSI command from the mid-layer
12560d49016bSadam radford * @mfi_sgl: SGL to be filled in
12570d49016bSadam radford *
12580d49016bSadam radford * If successful, this function returns the number of SG elements. Otherwise,
12590d49016bSadam radford * it returnes -1.
12600d49016bSadam radford */
12610d49016bSadam radford static int
megasas_make_sgl32(struct megasas_instance * instance,struct scsi_cmnd * scp,union megasas_sgl * mfi_sgl)12620d49016bSadam radford megasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp,
12630d49016bSadam radford union megasas_sgl *mfi_sgl)
12640d49016bSadam radford {
12650d49016bSadam radford int i;
12660d49016bSadam radford int sge_count;
12670d49016bSadam radford struct scatterlist *os_sgl;
12680d49016bSadam radford
12690d49016bSadam radford sge_count = scsi_dma_map(scp);
12700d49016bSadam radford BUG_ON(sge_count < 0);
12710d49016bSadam radford
12720d49016bSadam radford if (sge_count) {
12730d49016bSadam radford scsi_for_each_sg(scp, os_sgl, sge_count, i) {
127494cd65ddSSumit.Saxena@lsi.com mfi_sgl->sge32[i].length = cpu_to_le32(sg_dma_len(os_sgl));
127594cd65ddSSumit.Saxena@lsi.com mfi_sgl->sge32[i].phys_addr = cpu_to_le32(sg_dma_address(os_sgl));
12760d49016bSadam radford }
12770d49016bSadam radford }
12780d49016bSadam radford return sge_count;
12790d49016bSadam radford }
12800d49016bSadam radford
12810d49016bSadam radford /**
12820d49016bSadam radford * megasas_make_sgl64 - Prepares 64-bit SGL
12830d49016bSadam radford * @instance: Adapter soft state
12840d49016bSadam radford * @scp: SCSI command from the mid-layer
12850d49016bSadam radford * @mfi_sgl: SGL to be filled in
12860d49016bSadam radford *
12870d49016bSadam radford * If successful, this function returns the number of SG elements. Otherwise,
12880d49016bSadam radford * it returnes -1.
12890d49016bSadam radford */
12900d49016bSadam radford static int
megasas_make_sgl64(struct megasas_instance * instance,struct scsi_cmnd * scp,union megasas_sgl * mfi_sgl)12910d49016bSadam radford megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
12920d49016bSadam radford union megasas_sgl *mfi_sgl)
12930d49016bSadam radford {
12940d49016bSadam radford int i;
12950d49016bSadam radford int sge_count;
12960d49016bSadam radford struct scatterlist *os_sgl;
12970d49016bSadam radford
12980d49016bSadam radford sge_count = scsi_dma_map(scp);
12990d49016bSadam radford BUG_ON(sge_count < 0);
13000d49016bSadam radford
13010d49016bSadam radford if (sge_count) {
13020d49016bSadam radford scsi_for_each_sg(scp, os_sgl, sge_count, i) {
130394cd65ddSSumit.Saxena@lsi.com mfi_sgl->sge64[i].length = cpu_to_le32(sg_dma_len(os_sgl));
130494cd65ddSSumit.Saxena@lsi.com mfi_sgl->sge64[i].phys_addr = cpu_to_le64(sg_dma_address(os_sgl));
13050d49016bSadam radford }
13060d49016bSadam radford }
13070d49016bSadam radford return sge_count;
13080d49016bSadam radford }
13090d49016bSadam radford
13100d49016bSadam radford /**
13110d49016bSadam radford * megasas_make_sgl_skinny - Prepares IEEE SGL
13120d49016bSadam radford * @instance: Adapter soft state
13130d49016bSadam radford * @scp: SCSI command from the mid-layer
13140d49016bSadam radford * @mfi_sgl: SGL to be filled in
13150d49016bSadam radford *
13160d49016bSadam radford * If successful, this function returns the number of SG elements. Otherwise,
13170d49016bSadam radford * it returnes -1.
13180d49016bSadam radford */
13190d49016bSadam radford static int
megasas_make_sgl_skinny(struct megasas_instance * instance,struct scsi_cmnd * scp,union megasas_sgl * mfi_sgl)13200d49016bSadam radford megasas_make_sgl_skinny(struct megasas_instance *instance,
13210d49016bSadam radford struct scsi_cmnd *scp, union megasas_sgl *mfi_sgl)
13220d49016bSadam radford {
13230d49016bSadam radford int i;
13240d49016bSadam radford int sge_count;
13250d49016bSadam radford struct scatterlist *os_sgl;
13260d49016bSadam radford
13270d49016bSadam radford sge_count = scsi_dma_map(scp);
13280d49016bSadam radford
13290d49016bSadam radford if (sge_count) {
13300d49016bSadam radford scsi_for_each_sg(scp, os_sgl, sge_count, i) {
133194cd65ddSSumit.Saxena@lsi.com mfi_sgl->sge_skinny[i].length =
133294cd65ddSSumit.Saxena@lsi.com cpu_to_le32(sg_dma_len(os_sgl));
13330d49016bSadam radford mfi_sgl->sge_skinny[i].phys_addr =
133494cd65ddSSumit.Saxena@lsi.com cpu_to_le64(sg_dma_address(os_sgl));
133594cd65ddSSumit.Saxena@lsi.com mfi_sgl->sge_skinny[i].flag = cpu_to_le32(0);
13360d49016bSadam radford }
13370d49016bSadam radford }
13380d49016bSadam radford return sge_count;
13390d49016bSadam radford }
13400d49016bSadam radford
13410d49016bSadam radford /**
13420d49016bSadam radford * megasas_get_frame_count - Computes the number of frames
13430d49016bSadam radford * @frame_type : type of frame- io or pthru frame
13440d49016bSadam radford * @sge_count : number of sg elements
13450d49016bSadam radford *
13460d49016bSadam radford * Returns the number of frames required for numnber of sge's (sge_count)
13470d49016bSadam radford */
13480d49016bSadam radford
megasas_get_frame_count(struct megasas_instance * instance,u8 sge_count,u8 frame_type)13490d49016bSadam radford static u32 megasas_get_frame_count(struct megasas_instance *instance,
13500d49016bSadam radford u8 sge_count, u8 frame_type)
13510d49016bSadam radford {
13520d49016bSadam radford int num_cnt;
13530d49016bSadam radford int sge_bytes;
13540d49016bSadam radford u32 sge_sz;
13550d49016bSadam radford u32 frame_count = 0;
13560d49016bSadam radford
13570d49016bSadam radford sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
13580d49016bSadam radford sizeof(struct megasas_sge32);
13590d49016bSadam radford
13600d49016bSadam radford if (instance->flag_ieee) {
13610d49016bSadam radford sge_sz = sizeof(struct megasas_sge_skinny);
13620d49016bSadam radford }
13630d49016bSadam radford
13640d49016bSadam radford /*
13650d49016bSadam radford * Main frame can contain 2 SGEs for 64-bit SGLs and
13660d49016bSadam radford * 3 SGEs for 32-bit SGLs for ldio &
13670d49016bSadam radford * 1 SGEs for 64-bit SGLs and
13680d49016bSadam radford * 2 SGEs for 32-bit SGLs for pthru frame
13690d49016bSadam radford */
13700d49016bSadam radford if (unlikely(frame_type == PTHRU_FRAME)) {
13710d49016bSadam radford if (instance->flag_ieee == 1) {
13720d49016bSadam radford num_cnt = sge_count - 1;
13730d49016bSadam radford } else if (IS_DMA64)
13740d49016bSadam radford num_cnt = sge_count - 1;
13750d49016bSadam radford else
13760d49016bSadam radford num_cnt = sge_count - 2;
13770d49016bSadam radford } else {
13780d49016bSadam radford if (instance->flag_ieee == 1) {
13790d49016bSadam radford num_cnt = sge_count - 1;
13800d49016bSadam radford } else if (IS_DMA64)
13810d49016bSadam radford num_cnt = sge_count - 2;
13820d49016bSadam radford else
13830d49016bSadam radford num_cnt = sge_count - 3;
13840d49016bSadam radford }
13850d49016bSadam radford
13860d49016bSadam radford if (num_cnt > 0) {
13870d49016bSadam radford sge_bytes = sge_sz * num_cnt;
13880d49016bSadam radford
13890d49016bSadam radford frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
13900d49016bSadam radford ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ;
13910d49016bSadam radford }
13920d49016bSadam radford /* Main frame */
13930d49016bSadam radford frame_count += 1;
13940d49016bSadam radford
13950d49016bSadam radford if (frame_count > 7)
13960d49016bSadam radford frame_count = 8;
13970d49016bSadam radford return frame_count;
13980d49016bSadam radford }
13990d49016bSadam radford
14000d49016bSadam radford /**
14010d49016bSadam radford * megasas_build_dcdb - Prepares a direct cdb (DCDB) command
14020d49016bSadam radford * @instance: Adapter soft state
14030d49016bSadam radford * @scp: SCSI command
14040d49016bSadam radford * @cmd: Command to be prepared in
14050d49016bSadam radford *
14060d49016bSadam radford * This function prepares CDB commands. These are typcially pass-through
14070d49016bSadam radford * commands to the devices.
14080d49016bSadam radford */
14090d49016bSadam radford static int
megasas_build_dcdb(struct megasas_instance * instance,struct scsi_cmnd * scp,struct megasas_cmd * cmd)14100d49016bSadam radford megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
14110d49016bSadam radford struct megasas_cmd *cmd)
14120d49016bSadam radford {
14130d49016bSadam radford u32 is_logical;
14140d49016bSadam radford u32 device_id;
14150d49016bSadam radford u16 flags = 0;
14160d49016bSadam radford struct megasas_pthru_frame *pthru;
14170d49016bSadam radford
14183cabd162SShivasharan S is_logical = MEGASAS_IS_LOGICAL(scp->device);
14194a5c814dSSumit.Saxena@avagotech.com device_id = MEGASAS_DEV_INDEX(scp);
14200d49016bSadam radford pthru = (struct megasas_pthru_frame *)cmd->frame;
14210d49016bSadam radford
142260ee6529SChristoph Hellwig if (scp->sc_data_direction == DMA_TO_DEVICE)
14230d49016bSadam radford flags = MFI_FRAME_DIR_WRITE;
142460ee6529SChristoph Hellwig else if (scp->sc_data_direction == DMA_FROM_DEVICE)
14250d49016bSadam radford flags = MFI_FRAME_DIR_READ;
142660ee6529SChristoph Hellwig else if (scp->sc_data_direction == DMA_NONE)
14270d49016bSadam radford flags = MFI_FRAME_DIR_NONE;
14280d49016bSadam radford
14290d49016bSadam radford if (instance->flag_ieee == 1) {
14300d49016bSadam radford flags |= MFI_FRAME_IEEE;
14310d49016bSadam radford }
14320d49016bSadam radford
14330d49016bSadam radford /*
14340d49016bSadam radford * Prepare the DCDB frame
14350d49016bSadam radford */
14360d49016bSadam radford pthru->cmd = (is_logical) ? MFI_CMD_LD_SCSI_IO : MFI_CMD_PD_SCSI_IO;
14370d49016bSadam radford pthru->cmd_status = 0x0;
14380d49016bSadam radford pthru->scsi_status = 0x0;
14390d49016bSadam radford pthru->target_id = device_id;
14400d49016bSadam radford pthru->lun = scp->device->lun;
14410d49016bSadam radford pthru->cdb_len = scp->cmd_len;
14420d49016bSadam radford pthru->timeout = 0;
14430d49016bSadam radford pthru->pad_0 = 0;
144494cd65ddSSumit.Saxena@lsi.com pthru->flags = cpu_to_le16(flags);
144594cd65ddSSumit.Saxena@lsi.com pthru->data_xfer_len = cpu_to_le32(scsi_bufflen(scp));
14460d49016bSadam radford
14470d49016bSadam radford memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
14480d49016bSadam radford
14490d49016bSadam radford /*
14500d49016bSadam radford * If the command is for the tape device, set the
14510d49016bSadam radford * pthru timeout to the os layer timeout value.
14520d49016bSadam radford */
14530d49016bSadam radford if (scp->device->type == TYPE_TAPE) {
14544bccecf1SBart Van Assche if (scsi_cmd_to_rq(scp)->timeout / HZ > 0xFFFF)
1455c6f5bf81SChristoph Hellwig pthru->timeout = cpu_to_le16(0xFFFF);
14560d49016bSadam radford else
14574bccecf1SBart Van Assche pthru->timeout = cpu_to_le16(scsi_cmd_to_rq(scp)->timeout / HZ);
14580d49016bSadam radford }
14590d49016bSadam radford
14600d49016bSadam radford /*
14610d49016bSadam radford * Construct SGL
14620d49016bSadam radford */
14630d49016bSadam radford if (instance->flag_ieee == 1) {
146494cd65ddSSumit.Saxena@lsi.com pthru->flags |= cpu_to_le16(MFI_FRAME_SGL64);
14650d49016bSadam radford pthru->sge_count = megasas_make_sgl_skinny(instance, scp,
14660d49016bSadam radford &pthru->sgl);
14670d49016bSadam radford } else if (IS_DMA64) {
146894cd65ddSSumit.Saxena@lsi.com pthru->flags |= cpu_to_le16(MFI_FRAME_SGL64);
14690d49016bSadam radford pthru->sge_count = megasas_make_sgl64(instance, scp,
14700d49016bSadam radford &pthru->sgl);
14710d49016bSadam radford } else
14720d49016bSadam radford pthru->sge_count = megasas_make_sgl32(instance, scp,
14730d49016bSadam radford &pthru->sgl);
14740d49016bSadam radford
14750d49016bSadam radford if (pthru->sge_count > instance->max_num_sge) {
14761be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "DCDB too many SGE NUM=%x\n",
14770d49016bSadam radford pthru->sge_count);
14780d49016bSadam radford return 0;
14790d49016bSadam radford }
14800d49016bSadam radford
14810d49016bSadam radford /*
14820d49016bSadam radford * Sense info specific
14830d49016bSadam radford */
14840d49016bSadam radford pthru->sense_len = SCSI_SENSE_BUFFERSIZE;
148594cd65ddSSumit.Saxena@lsi.com pthru->sense_buf_phys_addr_hi =
148694cd65ddSSumit.Saxena@lsi.com cpu_to_le32(upper_32_bits(cmd->sense_phys_addr));
148794cd65ddSSumit.Saxena@lsi.com pthru->sense_buf_phys_addr_lo =
148894cd65ddSSumit.Saxena@lsi.com cpu_to_le32(lower_32_bits(cmd->sense_phys_addr));
14890d49016bSadam radford
14900d49016bSadam radford /*
14910d49016bSadam radford * Compute the total number of frames this command consumes. FW uses
14920d49016bSadam radford * this number to pull sufficient number of frames from host memory.
14930d49016bSadam radford */
14940d49016bSadam radford cmd->frame_count = megasas_get_frame_count(instance, pthru->sge_count,
14950d49016bSadam radford PTHRU_FRAME);
14960d49016bSadam radford
14970d49016bSadam radford return cmd->frame_count;
14980d49016bSadam radford }
14990d49016bSadam radford
15000d49016bSadam radford /**
15010d49016bSadam radford * megasas_build_ldio - Prepares IOs to logical devices
15020d49016bSadam radford * @instance: Adapter soft state
15030d49016bSadam radford * @scp: SCSI command
15040d49016bSadam radford * @cmd: Command to be prepared
15050d49016bSadam radford *
15060d49016bSadam radford * Frames (and accompanying SGLs) for regular SCSI IOs use this function.
15070d49016bSadam radford */
15080d49016bSadam radford static int
megasas_build_ldio(struct megasas_instance * instance,struct scsi_cmnd * scp,struct megasas_cmd * cmd)15090d49016bSadam radford megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
15100d49016bSadam radford struct megasas_cmd *cmd)
15110d49016bSadam radford {
15120d49016bSadam radford u32 device_id;
15130d49016bSadam radford u8 sc = scp->cmnd[0];
15140d49016bSadam radford u16 flags = 0;
15150d49016bSadam radford struct megasas_io_frame *ldio;
15160d49016bSadam radford
15174a5c814dSSumit.Saxena@avagotech.com device_id = MEGASAS_DEV_INDEX(scp);
15180d49016bSadam radford ldio = (struct megasas_io_frame *)cmd->frame;
15190d49016bSadam radford
152060ee6529SChristoph Hellwig if (scp->sc_data_direction == DMA_TO_DEVICE)
15210d49016bSadam radford flags = MFI_FRAME_DIR_WRITE;
152260ee6529SChristoph Hellwig else if (scp->sc_data_direction == DMA_FROM_DEVICE)
15230d49016bSadam radford flags = MFI_FRAME_DIR_READ;
15240d49016bSadam radford
15250d49016bSadam radford if (instance->flag_ieee == 1) {
15260d49016bSadam radford flags |= MFI_FRAME_IEEE;
15270d49016bSadam radford }
15280d49016bSadam radford
15290d49016bSadam radford /*
15300d49016bSadam radford * Prepare the Logical IO frame: 2nd bit is zero for all read cmds
15310d49016bSadam radford */
15320d49016bSadam radford ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ;
15330d49016bSadam radford ldio->cmd_status = 0x0;
15340d49016bSadam radford ldio->scsi_status = 0x0;
15350d49016bSadam radford ldio->target_id = device_id;
15360d49016bSadam radford ldio->timeout = 0;
15370d49016bSadam radford ldio->reserved_0 = 0;
15380d49016bSadam radford ldio->pad_0 = 0;
153994cd65ddSSumit.Saxena@lsi.com ldio->flags = cpu_to_le16(flags);
15400d49016bSadam radford ldio->start_lba_hi = 0;
15410d49016bSadam radford ldio->access_byte = (scp->cmd_len != 6) ? scp->cmnd[1] : 0;
15420d49016bSadam radford
15430d49016bSadam radford /*
15440d49016bSadam radford * 6-byte READ(0x08) or WRITE(0x0A) cdb
15450d49016bSadam radford */
15460d49016bSadam radford if (scp->cmd_len == 6) {
154794cd65ddSSumit.Saxena@lsi.com ldio->lba_count = cpu_to_le32((u32) scp->cmnd[4]);
154894cd65ddSSumit.Saxena@lsi.com ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[1] << 16) |
154994cd65ddSSumit.Saxena@lsi.com ((u32) scp->cmnd[2] << 8) |
155094cd65ddSSumit.Saxena@lsi.com (u32) scp->cmnd[3]);
15510d49016bSadam radford
155294cd65ddSSumit.Saxena@lsi.com ldio->start_lba_lo &= cpu_to_le32(0x1FFFFF);
15530d49016bSadam radford }
15540d49016bSadam radford
15550d49016bSadam radford /*
15560d49016bSadam radford * 10-byte READ(0x28) or WRITE(0x2A) cdb
15570d49016bSadam radford */
15580d49016bSadam radford else if (scp->cmd_len == 10) {
155994cd65ddSSumit.Saxena@lsi.com ldio->lba_count = cpu_to_le32((u32) scp->cmnd[8] |
156094cd65ddSSumit.Saxena@lsi.com ((u32) scp->cmnd[7] << 8));
156194cd65ddSSumit.Saxena@lsi.com ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[2] << 24) |
15620d49016bSadam radford ((u32) scp->cmnd[3] << 16) |
156394cd65ddSSumit.Saxena@lsi.com ((u32) scp->cmnd[4] << 8) |
156494cd65ddSSumit.Saxena@lsi.com (u32) scp->cmnd[5]);
15650d49016bSadam radford }
15660d49016bSadam radford
15670d49016bSadam radford /*
15680d49016bSadam radford * 12-byte READ(0xA8) or WRITE(0xAA) cdb
15690d49016bSadam radford */
15700d49016bSadam radford else if (scp->cmd_len == 12) {
157194cd65ddSSumit.Saxena@lsi.com ldio->lba_count = cpu_to_le32(((u32) scp->cmnd[6] << 24) |
15720d49016bSadam radford ((u32) scp->cmnd[7] << 16) |
157394cd65ddSSumit.Saxena@lsi.com ((u32) scp->cmnd[8] << 8) |
157494cd65ddSSumit.Saxena@lsi.com (u32) scp->cmnd[9]);
15750d49016bSadam radford
157694cd65ddSSumit.Saxena@lsi.com ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[2] << 24) |
15770d49016bSadam radford ((u32) scp->cmnd[3] << 16) |
157894cd65ddSSumit.Saxena@lsi.com ((u32) scp->cmnd[4] << 8) |
157994cd65ddSSumit.Saxena@lsi.com (u32) scp->cmnd[5]);
15800d49016bSadam radford }
15810d49016bSadam radford
15820d49016bSadam radford /*
15830d49016bSadam radford * 16-byte READ(0x88) or WRITE(0x8A) cdb
15840d49016bSadam radford */
15850d49016bSadam radford else if (scp->cmd_len == 16) {
158694cd65ddSSumit.Saxena@lsi.com ldio->lba_count = cpu_to_le32(((u32) scp->cmnd[10] << 24) |
15870d49016bSadam radford ((u32) scp->cmnd[11] << 16) |
158894cd65ddSSumit.Saxena@lsi.com ((u32) scp->cmnd[12] << 8) |
158994cd65ddSSumit.Saxena@lsi.com (u32) scp->cmnd[13]);
15900d49016bSadam radford
159194cd65ddSSumit.Saxena@lsi.com ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[6] << 24) |
15920d49016bSadam radford ((u32) scp->cmnd[7] << 16) |
159394cd65ddSSumit.Saxena@lsi.com ((u32) scp->cmnd[8] << 8) |
159494cd65ddSSumit.Saxena@lsi.com (u32) scp->cmnd[9]);
15950d49016bSadam radford
159694cd65ddSSumit.Saxena@lsi.com ldio->start_lba_hi = cpu_to_le32(((u32) scp->cmnd[2] << 24) |
15970d49016bSadam radford ((u32) scp->cmnd[3] << 16) |
159894cd65ddSSumit.Saxena@lsi.com ((u32) scp->cmnd[4] << 8) |
159994cd65ddSSumit.Saxena@lsi.com (u32) scp->cmnd[5]);
16000d49016bSadam radford
16010d49016bSadam radford }
16020d49016bSadam radford
16030d49016bSadam radford /*
16040d49016bSadam radford * Construct SGL
16050d49016bSadam radford */
16060d49016bSadam radford if (instance->flag_ieee) {
160794cd65ddSSumit.Saxena@lsi.com ldio->flags |= cpu_to_le16(MFI_FRAME_SGL64);
16080d49016bSadam radford ldio->sge_count = megasas_make_sgl_skinny(instance, scp,
16090d49016bSadam radford &ldio->sgl);
16100d49016bSadam radford } else if (IS_DMA64) {
161194cd65ddSSumit.Saxena@lsi.com ldio->flags |= cpu_to_le16(MFI_FRAME_SGL64);
16120d49016bSadam radford ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
16130d49016bSadam radford } else
16140d49016bSadam radford ldio->sge_count = megasas_make_sgl32(instance, scp, &ldio->sgl);
16150d49016bSadam radford
16160d49016bSadam radford if (ldio->sge_count > instance->max_num_sge) {
16171be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "build_ld_io: sge_count = %x\n",
16180d49016bSadam radford ldio->sge_count);
16190d49016bSadam radford return 0;
16200d49016bSadam radford }
16210d49016bSadam radford
16220d49016bSadam radford /*
16230d49016bSadam radford * Sense info specific
16240d49016bSadam radford */
16250d49016bSadam radford ldio->sense_len = SCSI_SENSE_BUFFERSIZE;
16260d49016bSadam radford ldio->sense_buf_phys_addr_hi = 0;
162794cd65ddSSumit.Saxena@lsi.com ldio->sense_buf_phys_addr_lo = cpu_to_le32(cmd->sense_phys_addr);
16280d49016bSadam radford
16290d49016bSadam radford /*
16300d49016bSadam radford * Compute the total number of frames this command consumes. FW uses
16310d49016bSadam radford * this number to pull sufficient number of frames from host memory.
16320d49016bSadam radford */
16330d49016bSadam radford cmd->frame_count = megasas_get_frame_count(instance,
16340d49016bSadam radford ldio->sge_count, IO_FRAME);
16350d49016bSadam radford
16360d49016bSadam radford return cmd->frame_count;
16370d49016bSadam radford }
16380d49016bSadam radford
16390d49016bSadam radford /**
16407497cde8SSumit.Saxena@avagotech.com * megasas_cmd_type - Checks if the cmd is for logical drive/sysPD
16417497cde8SSumit.Saxena@avagotech.com * and whether it's RW or non RW
16422b46e5c1SDamien Le Moal * @cmd: SCSI command
16430d49016bSadam radford *
16440d49016bSadam radford */
megasas_cmd_type(struct scsi_cmnd * cmd)16457497cde8SSumit.Saxena@avagotech.com inline int megasas_cmd_type(struct scsi_cmnd *cmd)
16460d49016bSadam radford {
16477497cde8SSumit.Saxena@avagotech.com int ret;
16487497cde8SSumit.Saxena@avagotech.com
16490d49016bSadam radford switch (cmd->cmnd[0]) {
16500d49016bSadam radford case READ_10:
16510d49016bSadam radford case WRITE_10:
16520d49016bSadam radford case READ_12:
16530d49016bSadam radford case WRITE_12:
16540d49016bSadam radford case READ_6:
16550d49016bSadam radford case WRITE_6:
16560d49016bSadam radford case READ_16:
16570d49016bSadam radford case WRITE_16:
16583cabd162SShivasharan S ret = (MEGASAS_IS_LOGICAL(cmd->device)) ?
16597497cde8SSumit.Saxena@avagotech.com READ_WRITE_LDIO : READ_WRITE_SYSPDIO;
16607497cde8SSumit.Saxena@avagotech.com break;
16610d49016bSadam radford default:
16623cabd162SShivasharan S ret = (MEGASAS_IS_LOGICAL(cmd->device)) ?
16637497cde8SSumit.Saxena@avagotech.com NON_READ_WRITE_LDIO : NON_READ_WRITE_SYSPDIO;
16640d49016bSadam radford }
16657497cde8SSumit.Saxena@avagotech.com return ret;
16660d49016bSadam radford }
16670d49016bSadam radford
16680d49016bSadam radford /**
16690d49016bSadam radford * megasas_dump_pending_frames - Dumps the frame address of all pending cmds
16700d49016bSadam radford * in FW
16710d49016bSadam radford * @instance: Adapter soft state
16720d49016bSadam radford */
16730d49016bSadam radford static inline void
megasas_dump_pending_frames(struct megasas_instance * instance)16740d49016bSadam radford megasas_dump_pending_frames(struct megasas_instance *instance)
16750d49016bSadam radford {
16760d49016bSadam radford struct megasas_cmd *cmd;
16770d49016bSadam radford int i,n;
16780d49016bSadam radford union megasas_sgl *mfi_sgl;
16790d49016bSadam radford struct megasas_io_frame *ldio;
16800d49016bSadam radford struct megasas_pthru_frame *pthru;
16810d49016bSadam radford u32 sgcount;
168250b7f5a2SShivasharan S u16 max_cmd = instance->max_fw_cmds;
16830d49016bSadam radford
16841be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);
16851be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding));
16860d49016bSadam radford if (IS_DMA64)
16871be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no);
16880d49016bSadam radford else
16891be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no);
16900d49016bSadam radford
16911be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "[%d]: Pending OS cmds in FW : \n",instance->host->host_no);
16920d49016bSadam radford for (i = 0; i < max_cmd; i++) {
16930d49016bSadam radford cmd = instance->cmd_list[i];
16940d49016bSadam radford if (!cmd->scmd)
16950d49016bSadam radford continue;
16961be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr);
16977497cde8SSumit.Saxena@avagotech.com if (megasas_cmd_type(cmd->scmd) == READ_WRITE_LDIO) {
16980d49016bSadam radford ldio = (struct megasas_io_frame *)cmd->frame;
16990d49016bSadam radford mfi_sgl = &ldio->sgl;
17000d49016bSadam radford sgcount = ldio->sge_count;
17011be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x,"
170294cd65ddSSumit.Saxena@lsi.com " lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",
170394cd65ddSSumit.Saxena@lsi.com instance->host->host_no, cmd->frame_count, ldio->cmd, ldio->target_id,
170494cd65ddSSumit.Saxena@lsi.com le32_to_cpu(ldio->start_lba_lo), le32_to_cpu(ldio->start_lba_hi),
170594cd65ddSSumit.Saxena@lsi.com le32_to_cpu(ldio->sense_buf_phys_addr_lo), sgcount);
1706da0dc9fbSBjorn Helgaas } else {
17070d49016bSadam radford pthru = (struct megasas_pthru_frame *) cmd->frame;
17080d49016bSadam radford mfi_sgl = &pthru->sgl;
17090d49016bSadam radford sgcount = pthru->sge_count;
17101be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, "
171194cd65ddSSumit.Saxena@lsi.com "lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",
171294cd65ddSSumit.Saxena@lsi.com instance->host->host_no, cmd->frame_count, pthru->cmd, pthru->target_id,
171394cd65ddSSumit.Saxena@lsi.com pthru->lun, pthru->cdb_len, le32_to_cpu(pthru->data_xfer_len),
171494cd65ddSSumit.Saxena@lsi.com le32_to_cpu(pthru->sense_buf_phys_addr_lo), sgcount);
17150d49016bSadam radford }
17160d49016bSadam radford if (megasas_dbg_lvl & MEGASAS_DBG_LVL) {
17170d49016bSadam radford for (n = 0; n < sgcount; n++) {
17180d49016bSadam radford if (IS_DMA64)
17191be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%llx\n",
172094cd65ddSSumit.Saxena@lsi.com le32_to_cpu(mfi_sgl->sge64[n].length),
172194cd65ddSSumit.Saxena@lsi.com le64_to_cpu(mfi_sgl->sge64[n].phys_addr));
17220d49016bSadam radford else
17231be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%x\n",
172494cd65ddSSumit.Saxena@lsi.com le32_to_cpu(mfi_sgl->sge32[n].length),
172594cd65ddSSumit.Saxena@lsi.com le32_to_cpu(mfi_sgl->sge32[n].phys_addr));
17260d49016bSadam radford }
17270d49016bSadam radford }
17280d49016bSadam radford } /*for max_cmd*/
17291be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "[%d]: Pending Internal cmds in FW : \n",instance->host->host_no);
17300d49016bSadam radford for (i = 0; i < max_cmd; i++) {
17310d49016bSadam radford
17320d49016bSadam radford cmd = instance->cmd_list[i];
17330d49016bSadam radford
1734da0dc9fbSBjorn Helgaas if (cmd->sync_cmd == 1)
17351be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "0x%08lx : ", (unsigned long)cmd->frame_phys_addr);
17360d49016bSadam radford }
17371be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "[%d]: Dumping Done\n\n",instance->host->host_no);
17380d49016bSadam radford }
17390d49016bSadam radford
1740cd50ba8eSadam radford u32
megasas_build_and_issue_cmd(struct megasas_instance * instance,struct scsi_cmnd * scmd)1741cd50ba8eSadam radford megasas_build_and_issue_cmd(struct megasas_instance *instance,
1742cd50ba8eSadam radford struct scsi_cmnd *scmd)
1743cd50ba8eSadam radford {
1744cd50ba8eSadam radford struct megasas_cmd *cmd;
1745cd50ba8eSadam radford u32 frame_count;
1746cd50ba8eSadam radford
1747cd50ba8eSadam radford cmd = megasas_get_cmd(instance);
1748cd50ba8eSadam radford if (!cmd)
1749cd50ba8eSadam radford return SCSI_MLQUEUE_HOST_BUSY;
1750cd50ba8eSadam radford
1751cd50ba8eSadam radford /*
1752cd50ba8eSadam radford * Logical drive command
1753cd50ba8eSadam radford */
17547497cde8SSumit.Saxena@avagotech.com if (megasas_cmd_type(scmd) == READ_WRITE_LDIO)
1755cd50ba8eSadam radford frame_count = megasas_build_ldio(instance, scmd, cmd);
1756cd50ba8eSadam radford else
1757cd50ba8eSadam radford frame_count = megasas_build_dcdb(instance, scmd, cmd);
1758cd50ba8eSadam radford
1759cd50ba8eSadam radford if (!frame_count)
1760cd50ba8eSadam radford goto out_return_cmd;
1761cd50ba8eSadam radford
1762cd50ba8eSadam radford cmd->scmd = scmd;
176396e77a27SBart Van Assche megasas_priv(scmd)->cmd_priv = cmd;
1764cd50ba8eSadam radford
1765cd50ba8eSadam radford /*
1766cd50ba8eSadam radford * Issue the command to the FW
1767cd50ba8eSadam radford */
1768cd50ba8eSadam radford atomic_inc(&instance->fw_outstanding);
1769cd50ba8eSadam radford
1770cd50ba8eSadam radford instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
1771cd50ba8eSadam radford cmd->frame_count-1, instance->reg_set);
1772cd50ba8eSadam radford
1773cd50ba8eSadam radford return 0;
1774cd50ba8eSadam radford out_return_cmd:
1775cd50ba8eSadam radford megasas_return_cmd(instance, cmd);
1776f9a9dee6SSumit Saxena return SCSI_MLQUEUE_HOST_BUSY;
1777cd50ba8eSadam radford }
1778cd50ba8eSadam radford
1779cd50ba8eSadam radford
17800d49016bSadam radford /**
17810d49016bSadam radford * megasas_queue_command - Queue entry point
17822b46e5c1SDamien Le Moal * @shost: adapter SCSI host
17830d49016bSadam radford * @scmd: SCSI command to be queued
17840d49016bSadam radford */
17850d49016bSadam radford static int
megasas_queue_command(struct Scsi_Host * shost,struct scsi_cmnd * scmd)1786fb1a24ffSSumit.Saxena@avagotech.com megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
17870d49016bSadam radford {
17880d49016bSadam radford struct megasas_instance *instance;
178918365b13SSumit Saxena struct MR_PRIV_DEVICE *mr_device_priv_data;
1790ae6874baSKashyap Desai u32 ld_tgt_id;
17910d49016bSadam radford
17920d49016bSadam radford instance = (struct megasas_instance *)
17930d49016bSadam radford scmd->device->host->hostdata;
17940d49016bSadam radford
1795aa00832bSSumit.Saxena@avagotech.com if (instance->unload == 1) {
1796aa00832bSSumit.Saxena@avagotech.com scmd->result = DID_NO_CONNECT << 16;
1797012f14b2SBart Van Assche scsi_done(scmd);
1798aa00832bSSumit.Saxena@avagotech.com return 0;
1799aa00832bSSumit.Saxena@avagotech.com }
1800aa00832bSSumit.Saxena@avagotech.com
18010d49016bSadam radford if (instance->issuepend_done == 0)
18020d49016bSadam radford return SCSI_MLQUEUE_HOST_BUSY;
18030d49016bSadam radford
1804b09e66daSSumit.Saxena@lsi.com
1805229fe47cSadam radford /* Check for an mpio path and adjust behavior */
18068a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
1807229fe47cSadam radford if (megasas_check_mpio_paths(instance, scmd) ==
1808f55cf47dSShivasharan S (DID_REQUEUE << 16)) {
1809229fe47cSadam radford return SCSI_MLQUEUE_HOST_BUSY;
1810229fe47cSadam radford } else {
1811229fe47cSadam radford scmd->result = DID_NO_CONNECT << 16;
1812012f14b2SBart Van Assche scsi_done(scmd);
1813229fe47cSadam radford return 0;
1814229fe47cSadam radford }
1815229fe47cSadam radford }
1816229fe47cSadam radford
1817ae6874baSKashyap Desai mr_device_priv_data = scmd->device->hostdata;
1818ae6874baSKashyap Desai if (!mr_device_priv_data ||
1819ae6874baSKashyap Desai (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)) {
1820229fe47cSadam radford scmd->result = DID_NO_CONNECT << 16;
1821012f14b2SBart Van Assche scsi_done(scmd);
1822b09e66daSSumit.Saxena@lsi.com return 0;
1823b09e66daSSumit.Saxena@lsi.com }
1824b09e66daSSumit.Saxena@lsi.com
1825ae6874baSKashyap Desai if (MEGASAS_IS_LOGICAL(scmd->device)) {
1826ae6874baSKashyap Desai ld_tgt_id = MEGASAS_TARGET_ID(scmd->device);
1827ae6874baSKashyap Desai if (instance->ld_tgtid_status[ld_tgt_id] == LD_TARGET_ID_DELETED) {
182818365b13SSumit Saxena scmd->result = DID_NO_CONNECT << 16;
1829012f14b2SBart Van Assche scsi_done(scmd);
183018365b13SSumit Saxena return 0;
183118365b13SSumit Saxena }
1832ae6874baSKashyap Desai }
183318365b13SSumit Saxena
18348a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
18350d49016bSadam radford return SCSI_MLQUEUE_HOST_BUSY;
18360d49016bSadam radford
18378a01a41dSSumit Saxena if (mr_device_priv_data->tm_busy)
183818365b13SSumit Saxena return SCSI_MLQUEUE_DEVICE_BUSY;
183918365b13SSumit Saxena
18400d49016bSadam radford
18410d49016bSadam radford scmd->result = 0;
18420d49016bSadam radford
18433cabd162SShivasharan S if (MEGASAS_IS_LOGICAL(scmd->device) &&
184451087a86SSumit.Saxena@avagotech.com (scmd->device->id >= instance->fw_supported_vd_count ||
184551087a86SSumit.Saxena@avagotech.com scmd->device->lun)) {
18460d49016bSadam radford scmd->result = DID_BAD_TARGET << 16;
18470d49016bSadam radford goto out_done;
18480d49016bSadam radford }
18490d49016bSadam radford
18503cabd162SShivasharan S if ((scmd->cmnd[0] == SYNCHRONIZE_CACHE) &&
18513cabd162SShivasharan S MEGASAS_IS_LOGICAL(scmd->device) &&
1852d0fc91d6SKashyap Desai (!instance->fw_sync_cache_support)) {
18530d49016bSadam radford scmd->result = DID_OK << 16;
18540d49016bSadam radford goto out_done;
18550d49016bSadam radford }
18560d49016bSadam radford
1857f9a9dee6SSumit Saxena return instance->instancet->build_and_issue_cmd(instance, scmd);
18580d49016bSadam radford
18590d49016bSadam radford out_done:
1860012f14b2SBart Van Assche scsi_done(scmd);
18610d49016bSadam radford return 0;
18620d49016bSadam radford }
18630d49016bSadam radford
megasas_lookup_instance(u16 host_no)18640d49016bSadam radford static struct megasas_instance *megasas_lookup_instance(u16 host_no)
18650d49016bSadam radford {
18660d49016bSadam radford int i;
18670d49016bSadam radford
18680d49016bSadam radford for (i = 0; i < megasas_mgmt_info.max_index; i++) {
18690d49016bSadam radford
18700d49016bSadam radford if ((megasas_mgmt_info.instance[i]) &&
18710d49016bSadam radford (megasas_mgmt_info.instance[i]->host->host_no == host_no))
18720d49016bSadam radford return megasas_mgmt_info.instance[i];
18730d49016bSadam radford }
18740d49016bSadam radford
18750d49016bSadam radford return NULL;
18760d49016bSadam radford }
18770d49016bSadam radford
18780b48d12dSsumit.saxena@avagotech.com /*
187915dd0381SShivasharan S * megasas_set_dynamic_target_properties -
188015dd0381SShivasharan S * Device property set by driver may not be static and it is required to be
188115dd0381SShivasharan S * updated after OCR
188215dd0381SShivasharan S *
188315dd0381SShivasharan S * set tm_capable.
188415dd0381SShivasharan S * set dma alignment (only for eedp protection enable vd).
18850b48d12dSsumit.saxena@avagotech.com *
18860b48d12dSsumit.saxena@avagotech.com * @sdev: OS provided scsi device
18870b48d12dSsumit.saxena@avagotech.com *
18880b48d12dSsumit.saxena@avagotech.com * Returns void
18890b48d12dSsumit.saxena@avagotech.com */
megasas_set_dynamic_target_properties(struct scsi_device * sdev,bool is_target_prop)1890e9495e2dSShivasharan S void megasas_set_dynamic_target_properties(struct scsi_device *sdev,
1891e9495e2dSShivasharan S bool is_target_prop)
18920b48d12dSsumit.saxena@avagotech.com {
189315dd0381SShivasharan S u16 pd_index = 0, ld;
189415dd0381SShivasharan S u32 device_id;
18950b48d12dSsumit.saxena@avagotech.com struct megasas_instance *instance;
18960b48d12dSsumit.saxena@avagotech.com struct fusion_context *fusion;
189718365b13SSumit Saxena struct MR_PRIV_DEVICE *mr_device_priv_data;
189818365b13SSumit Saxena struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
18990b48d12dSsumit.saxena@avagotech.com struct MR_LD_RAID *raid;
19000b48d12dSsumit.saxena@avagotech.com struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
19010b48d12dSsumit.saxena@avagotech.com
19020b48d12dSsumit.saxena@avagotech.com instance = megasas_lookup_instance(sdev->host->host_no);
19030b48d12dSsumit.saxena@avagotech.com fusion = instance->ctrl_context;
190418365b13SSumit Saxena mr_device_priv_data = sdev->hostdata;
19050b48d12dSsumit.saxena@avagotech.com
1906ed981b81SShivasharan S if (!fusion || !mr_device_priv_data)
19070b48d12dSsumit.saxena@avagotech.com return;
19080b48d12dSsumit.saxena@avagotech.com
1909ed981b81SShivasharan S if (MEGASAS_IS_LOGICAL(sdev)) {
1910ed981b81SShivasharan S device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
1911ed981b81SShivasharan S + sdev->id;
1912ed981b81SShivasharan S local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
1913ed981b81SShivasharan S ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
1914ed981b81SShivasharan S if (ld >= instance->fw_supported_vd_count)
1915ed981b81SShivasharan S return;
1916ed981b81SShivasharan S raid = MR_LdRaidGet(ld, local_map_ptr);
1917ed981b81SShivasharan S
1918ed981b81SShivasharan S if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER)
191915dd0381SShivasharan S blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
1920ed981b81SShivasharan S
1921ed981b81SShivasharan S mr_device_priv_data->is_tm_capable =
1922ed981b81SShivasharan S raid->capability.tmCapable;
1923a7faf81dSAnand Lodnoor
1924a7faf81dSAnand Lodnoor if (!raid->flags.isEPD)
1925a7faf81dSAnand Lodnoor sdev->no_write_same = 1;
1926a7faf81dSAnand Lodnoor
1927ed981b81SShivasharan S } else if (instance->use_seqnum_jbod_fp) {
192818365b13SSumit Saxena pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
192918365b13SSumit Saxena sdev->id;
193018365b13SSumit Saxena pd_sync = (void *)fusion->pd_seq_sync
193118365b13SSumit Saxena [(instance->pd_seq_map_id - 1) & 1];
193218365b13SSumit Saxena mr_device_priv_data->is_tm_capable =
193318365b13SSumit Saxena pd_sync->seq[pd_index].capability.tmCapable;
19340b48d12dSsumit.saxena@avagotech.com }
1935e9495e2dSShivasharan S
1936e9495e2dSShivasharan S if (is_target_prop && instance->tgt_prop->reset_tmo) {
1937e9495e2dSShivasharan S /*
1938e9495e2dSShivasharan S * If FW provides a target reset timeout value, driver will use
1939e9495e2dSShivasharan S * it. If not set, fallback to default values.
1940e9495e2dSShivasharan S */
1941e9495e2dSShivasharan S mr_device_priv_data->target_reset_tmo =
1942e9495e2dSShivasharan S min_t(u8, instance->max_reset_tmo,
1943e9495e2dSShivasharan S instance->tgt_prop->reset_tmo);
1944e9495e2dSShivasharan S mr_device_priv_data->task_abort_tmo = instance->task_abort_tmo;
1945e9495e2dSShivasharan S } else {
1946e9495e2dSShivasharan S mr_device_priv_data->target_reset_tmo =
1947e9495e2dSShivasharan S MEGASAS_DEFAULT_TM_TIMEOUT;
1948e9495e2dSShivasharan S mr_device_priv_data->task_abort_tmo =
1949e9495e2dSShivasharan S MEGASAS_DEFAULT_TM_TIMEOUT;
1950e9495e2dSShivasharan S }
19510b48d12dSsumit.saxena@avagotech.com }
19520b48d12dSsumit.saxena@avagotech.com
195315dd0381SShivasharan S /*
195415dd0381SShivasharan S * megasas_set_nvme_device_properties -
195515dd0381SShivasharan S * set nomerges=2
195615dd0381SShivasharan S * set virtual page boundary = 4K (current mr_nvme_pg_size is 4K).
195715dd0381SShivasharan S * set maximum io transfer = MDTS of NVME device provided by MR firmware.
195815dd0381SShivasharan S *
195915dd0381SShivasharan S * MR firmware provides value in KB. Caller of this function converts
196015dd0381SShivasharan S * kb into bytes.
196115dd0381SShivasharan S *
196215dd0381SShivasharan S * e.a MDTS=5 means 2^5 * nvme page size. (In case of 4K page size,
196315dd0381SShivasharan S * MR firmware provides value 128 as (32 * 4K) = 128K.
196415dd0381SShivasharan S *
196515dd0381SShivasharan S * @sdev: scsi device
196615dd0381SShivasharan S * @max_io_size: maximum io transfer size
196715dd0381SShivasharan S *
196815dd0381SShivasharan S */
196915dd0381SShivasharan S static inline void
megasas_set_nvme_device_properties(struct scsi_device * sdev,u32 max_io_size)197015dd0381SShivasharan S megasas_set_nvme_device_properties(struct scsi_device *sdev, u32 max_io_size)
19712216c305SSumit Saxena {
19722216c305SSumit Saxena struct megasas_instance *instance;
197315dd0381SShivasharan S u32 mr_nvme_pg_size;
197415dd0381SShivasharan S
197515dd0381SShivasharan S instance = (struct megasas_instance *)sdev->host->hostdata;
197615dd0381SShivasharan S mr_nvme_pg_size = max_t(u32, instance->nvme_page_size,
197715dd0381SShivasharan S MR_DEFAULT_NVME_PAGE_SIZE);
197815dd0381SShivasharan S
197915dd0381SShivasharan S blk_queue_max_hw_sectors(sdev->request_queue, (max_io_size / 512));
198015dd0381SShivasharan S
19818b904b5bSBart Van Assche blk_queue_flag_set(QUEUE_FLAG_NOMERGES, sdev->request_queue);
198215dd0381SShivasharan S blk_queue_virt_boundary(sdev->request_queue, mr_nvme_pg_size - 1);
198315dd0381SShivasharan S }
198415dd0381SShivasharan S
198515dd0381SShivasharan S /*
19869ab089d3SChandrakanth Patil * megasas_set_fw_assisted_qd -
19879ab089d3SChandrakanth Patil * set device queue depth to can_queue
19889ab089d3SChandrakanth Patil * set device queue depth to fw assisted qd
198915dd0381SShivasharan S *
199015dd0381SShivasharan S * @sdev: scsi device
199196188a89SShivasharan S * @is_target_prop true, if fw provided target properties.
199215dd0381SShivasharan S */
megasas_set_fw_assisted_qd(struct scsi_device * sdev,bool is_target_prop)19939ab089d3SChandrakanth Patil static void megasas_set_fw_assisted_qd(struct scsi_device *sdev,
199496188a89SShivasharan S bool is_target_prop)
199515dd0381SShivasharan S {
199615dd0381SShivasharan S u8 interface_type;
199715dd0381SShivasharan S u32 device_qd = MEGASAS_DEFAULT_CMD_PER_LUN;
199896188a89SShivasharan S u32 tgt_device_qd;
199915dd0381SShivasharan S struct megasas_instance *instance;
200015dd0381SShivasharan S struct MR_PRIV_DEVICE *mr_device_priv_data;
20012216c305SSumit Saxena
20022216c305SSumit Saxena instance = megasas_lookup_instance(sdev->host->host_no);
200315dd0381SShivasharan S mr_device_priv_data = sdev->hostdata;
200415dd0381SShivasharan S interface_type = mr_device_priv_data->interface_type;
20052216c305SSumit Saxena
200615dd0381SShivasharan S switch (interface_type) {
20072216c305SSumit Saxena case SAS_PD:
200815dd0381SShivasharan S device_qd = MEGASAS_SAS_QD;
20092216c305SSumit Saxena break;
20102216c305SSumit Saxena case SATA_PD:
201115dd0381SShivasharan S device_qd = MEGASAS_SATA_QD;
20122216c305SSumit Saxena break;
201315dd0381SShivasharan S case NVME_PD:
201415dd0381SShivasharan S device_qd = MEGASAS_NVME_QD;
201515dd0381SShivasharan S break;
201615dd0381SShivasharan S }
20172216c305SSumit Saxena
201896188a89SShivasharan S if (is_target_prop) {
201996188a89SShivasharan S tgt_device_qd = le32_to_cpu(instance->tgt_prop->device_qdepth);
20206c205a66SKashyap Desai if (tgt_device_qd)
20216c205a66SKashyap Desai device_qd = min(instance->host->can_queue,
20226c205a66SKashyap Desai (int)tgt_device_qd);
20239ab089d3SChandrakanth Patil }
20249ab089d3SChandrakanth Patil
20259ab089d3SChandrakanth Patil if (instance->enable_sdev_max_qd && interface_type != UNKNOWN_DRIVE)
20269ab089d3SChandrakanth Patil device_qd = instance->host->can_queue;
20279ab089d3SChandrakanth Patil
20289ab089d3SChandrakanth Patil scsi_change_queue_depth(sdev, device_qd);
20299ab089d3SChandrakanth Patil }
20309ab089d3SChandrakanth Patil
20319ab089d3SChandrakanth Patil /*
20329ab089d3SChandrakanth Patil * megasas_set_static_target_properties -
20339ab089d3SChandrakanth Patil * Device property set by driver are static and it is not required to be
20349ab089d3SChandrakanth Patil * updated after OCR.
20359ab089d3SChandrakanth Patil *
20369ab089d3SChandrakanth Patil * set io timeout
20379ab089d3SChandrakanth Patil * set device queue depth
20389ab089d3SChandrakanth Patil * set nvme device properties. see - megasas_set_nvme_device_properties
20399ab089d3SChandrakanth Patil *
20409ab089d3SChandrakanth Patil * @sdev: scsi device
20419ab089d3SChandrakanth Patil * @is_target_prop true, if fw provided target properties.
20429ab089d3SChandrakanth Patil */
megasas_set_static_target_properties(struct scsi_device * sdev,bool is_target_prop)20439ab089d3SChandrakanth Patil static void megasas_set_static_target_properties(struct scsi_device *sdev,
20449ab089d3SChandrakanth Patil bool is_target_prop)
20459ab089d3SChandrakanth Patil {
20469ab089d3SChandrakanth Patil u32 max_io_size_kb = MR_DEFAULT_NVME_MDTS_KB;
20479ab089d3SChandrakanth Patil struct megasas_instance *instance;
20489ab089d3SChandrakanth Patil
20499ab089d3SChandrakanth Patil instance = megasas_lookup_instance(sdev->host->host_no);
20509ab089d3SChandrakanth Patil
20519ab089d3SChandrakanth Patil /*
20529ab089d3SChandrakanth Patil * The RAID firmware may require extended timeouts.
20539ab089d3SChandrakanth Patil */
20549ab089d3SChandrakanth Patil blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ);
205596188a89SShivasharan S
205696188a89SShivasharan S /* max_io_size_kb will be set to non zero for
205796188a89SShivasharan S * nvme based vd and syspd.
205896188a89SShivasharan S */
20599ab089d3SChandrakanth Patil if (is_target_prop)
206096188a89SShivasharan S max_io_size_kb = le32_to_cpu(instance->tgt_prop->max_io_size_kb);
206196188a89SShivasharan S
206215dd0381SShivasharan S if (instance->nvme_page_size && max_io_size_kb)
206315dd0381SShivasharan S megasas_set_nvme_device_properties(sdev, (max_io_size_kb << 10));
206415dd0381SShivasharan S
20659ab089d3SChandrakanth Patil megasas_set_fw_assisted_qd(sdev, is_target_prop);
20662216c305SSumit Saxena }
20672216c305SSumit Saxena
206818365b13SSumit Saxena
megasas_slave_configure(struct scsi_device * sdev)20690d49016bSadam radford static int megasas_slave_configure(struct scsi_device *sdev)
20700d49016bSadam radford {
2071aed335eeSSumit Saxena u16 pd_index = 0;
2072aed335eeSSumit Saxena struct megasas_instance *instance;
207396188a89SShivasharan S int ret_target_prop = DCMD_FAILED;
207496188a89SShivasharan S bool is_target_prop = false;
2075aed335eeSSumit Saxena
2076aed335eeSSumit Saxena instance = megasas_lookup_instance(sdev->host->host_no);
207730845586SSumit Saxena if (instance->pd_list_not_supported) {
20783cabd162SShivasharan S if (!MEGASAS_IS_LOGICAL(sdev) && sdev->type == TYPE_DISK) {
2079aed335eeSSumit Saxena pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
2080aed335eeSSumit Saxena sdev->id;
2081aed335eeSSumit Saxena if (instance->pd_list[pd_index].driveState !=
2082aed335eeSSumit Saxena MR_PD_STATE_SYSTEM)
2083aed335eeSSumit Saxena return -ENXIO;
2084aed335eeSSumit Saxena }
2085aed335eeSSumit Saxena }
208618365b13SSumit Saxena
2087149c5751SShivasharan S mutex_lock(&instance->reset_mutex);
208815dd0381SShivasharan S /* Send DCMD to Firmware and cache the information */
208915dd0381SShivasharan S if ((instance->pd_info) && !MEGASAS_IS_LOGICAL(sdev))
209015dd0381SShivasharan S megasas_get_pd_info(instance, sdev);
209115dd0381SShivasharan S
209296188a89SShivasharan S /* Some ventura firmware may not have instance->nvme_page_size set.
209396188a89SShivasharan S * Do not send MR_DCMD_DRV_GET_TARGET_PROP
209496188a89SShivasharan S */
209596188a89SShivasharan S if ((instance->tgt_prop) && (instance->nvme_page_size))
209696188a89SShivasharan S ret_target_prop = megasas_get_target_prop(instance, sdev);
209796188a89SShivasharan S
209896188a89SShivasharan S is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false;
209996188a89SShivasharan S megasas_set_static_target_properties(sdev, is_target_prop);
210015dd0381SShivasharan S
210115dd0381SShivasharan S /* This sdev property may change post OCR */
2102e9495e2dSShivasharan S megasas_set_dynamic_target_properties(sdev, is_target_prop);
2103e9495e2dSShivasharan S
2104e9495e2dSShivasharan S mutex_unlock(&instance->reset_mutex);
210507e38d94SSumit.Saxena@avagotech.com
21060d49016bSadam radford return 0;
21070d49016bSadam radford }
21080d49016bSadam radford
megasas_slave_alloc(struct scsi_device * sdev)21090d49016bSadam radford static int megasas_slave_alloc(struct scsi_device *sdev)
21100d49016bSadam radford {
2111ae6874baSKashyap Desai u16 pd_index = 0, ld_tgt_id;
21120d49016bSadam radford struct megasas_instance *instance ;
211318365b13SSumit Saxena struct MR_PRIV_DEVICE *mr_device_priv_data;
2114da0dc9fbSBjorn Helgaas
21150d49016bSadam radford instance = megasas_lookup_instance(sdev->host->host_no);
21163cabd162SShivasharan S if (!MEGASAS_IS_LOGICAL(sdev)) {
21170d49016bSadam radford /*
21180d49016bSadam radford * Open the OS scan to the SYSTEM PD
21190d49016bSadam radford */
21200d49016bSadam radford pd_index =
21210d49016bSadam radford (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
21220d49016bSadam radford sdev->id;
212330845586SSumit Saxena if ((instance->pd_list_not_supported ||
212430845586SSumit Saxena instance->pd_list[pd_index].driveState ==
2125aed335eeSSumit Saxena MR_PD_STATE_SYSTEM)) {
212618365b13SSumit Saxena goto scan_target;
21270d49016bSadam radford }
21280d49016bSadam radford return -ENXIO;
212956495f29SChandrakanth patil } else if (!MEGASAS_IS_LUN_VALID(sdev)) {
213056495f29SChandrakanth patil sdev_printk(KERN_INFO, sdev, "%s: invalid LUN\n", __func__);
213156495f29SChandrakanth patil return -ENXIO;
21320d49016bSadam radford }
213318365b13SSumit Saxena
213418365b13SSumit Saxena scan_target:
213518365b13SSumit Saxena mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data),
213618365b13SSumit Saxena GFP_KERNEL);
213718365b13SSumit Saxena if (!mr_device_priv_data)
213818365b13SSumit Saxena return -ENOMEM;
2139ae6874baSKashyap Desai
2140ae6874baSKashyap Desai if (MEGASAS_IS_LOGICAL(sdev)) {
2141ae6874baSKashyap Desai ld_tgt_id = MEGASAS_TARGET_ID(sdev);
2142ae6874baSKashyap Desai instance->ld_tgtid_status[ld_tgt_id] = LD_TARGET_ID_ACTIVE;
2143ae6874baSKashyap Desai if (megasas_dbg_lvl & LD_PD_DEBUG)
2144ae6874baSKashyap Desai sdev_printk(KERN_INFO, sdev, "LD target ID %d created.\n", ld_tgt_id);
2145ae6874baSKashyap Desai }
2146ae6874baSKashyap Desai
214718365b13SSumit Saxena sdev->hostdata = mr_device_priv_data;
214849524b3cSShivasharan S
214949524b3cSShivasharan S atomic_set(&mr_device_priv_data->r1_ldio_hint,
215049524b3cSShivasharan S instance->r1_ldio_hint_default);
21510d49016bSadam radford return 0;
21520d49016bSadam radford }
21530d49016bSadam radford
megasas_slave_destroy(struct scsi_device * sdev)215418365b13SSumit Saxena static void megasas_slave_destroy(struct scsi_device *sdev)
215518365b13SSumit Saxena {
2156ae6874baSKashyap Desai u16 ld_tgt_id;
2157ae6874baSKashyap Desai struct megasas_instance *instance;
2158ae6874baSKashyap Desai
2159ae6874baSKashyap Desai instance = megasas_lookup_instance(sdev->host->host_no);
2160ae6874baSKashyap Desai
2161ae6874baSKashyap Desai if (MEGASAS_IS_LOGICAL(sdev)) {
216256495f29SChandrakanth patil if (!MEGASAS_IS_LUN_VALID(sdev)) {
216356495f29SChandrakanth patil sdev_printk(KERN_INFO, sdev, "%s: invalid LUN\n", __func__);
216456495f29SChandrakanth patil return;
216556495f29SChandrakanth patil }
2166ae6874baSKashyap Desai ld_tgt_id = MEGASAS_TARGET_ID(sdev);
2167ae6874baSKashyap Desai instance->ld_tgtid_status[ld_tgt_id] = LD_TARGET_ID_DELETED;
2168ae6874baSKashyap Desai if (megasas_dbg_lvl & LD_PD_DEBUG)
2169ae6874baSKashyap Desai sdev_printk(KERN_INFO, sdev,
2170ae6874baSKashyap Desai "LD target ID %d removed from OS stack\n", ld_tgt_id);
2171ae6874baSKashyap Desai }
2172ae6874baSKashyap Desai
217318365b13SSumit Saxena kfree(sdev->hostdata);
217418365b13SSumit Saxena sdev->hostdata = NULL;
217518365b13SSumit Saxena }
217618365b13SSumit Saxena
2177c8dd61efSSumit.Saxena@avagotech.com /*
2178c8dd61efSSumit.Saxena@avagotech.com * megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a
2179c8dd61efSSumit.Saxena@avagotech.com * kill adapter
2180c8dd61efSSumit.Saxena@avagotech.com * @instance: Adapter soft state
2181c8dd61efSSumit.Saxena@avagotech.com *
2182c8dd61efSSumit.Saxena@avagotech.com */
megasas_complete_outstanding_ioctls(struct megasas_instance * instance)21836a6981feSkbuild test robot static void megasas_complete_outstanding_ioctls(struct megasas_instance *instance)
2184c8dd61efSSumit.Saxena@avagotech.com {
2185c8dd61efSSumit.Saxena@avagotech.com int i;
2186c8dd61efSSumit.Saxena@avagotech.com struct megasas_cmd *cmd_mfi;
2187c8dd61efSSumit.Saxena@avagotech.com struct megasas_cmd_fusion *cmd_fusion;
2188c8dd61efSSumit.Saxena@avagotech.com struct fusion_context *fusion = instance->ctrl_context;
2189c8dd61efSSumit.Saxena@avagotech.com
2190c8dd61efSSumit.Saxena@avagotech.com /* Find all outstanding ioctls */
2191c8dd61efSSumit.Saxena@avagotech.com if (fusion) {
2192c8dd61efSSumit.Saxena@avagotech.com for (i = 0; i < instance->max_fw_cmds; i++) {
2193c8dd61efSSumit.Saxena@avagotech.com cmd_fusion = fusion->cmd_list[i];
2194c8dd61efSSumit.Saxena@avagotech.com if (cmd_fusion->sync_cmd_idx != (u32)ULONG_MAX) {
2195c8dd61efSSumit.Saxena@avagotech.com cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
2196c8dd61efSSumit.Saxena@avagotech.com if (cmd_mfi->sync_cmd &&
2197eb3fe263SShivasharan S (cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT)) {
2198eb3fe263SShivasharan S cmd_mfi->frame->hdr.cmd_status =
2199eb3fe263SShivasharan S MFI_STAT_WRONG_STATE;
2200c8dd61efSSumit.Saxena@avagotech.com megasas_complete_cmd(instance,
2201c8dd61efSSumit.Saxena@avagotech.com cmd_mfi, DID_OK);
2202c8dd61efSSumit.Saxena@avagotech.com }
2203c8dd61efSSumit.Saxena@avagotech.com }
2204eb3fe263SShivasharan S }
2205c8dd61efSSumit.Saxena@avagotech.com } else {
2206c8dd61efSSumit.Saxena@avagotech.com for (i = 0; i < instance->max_fw_cmds; i++) {
2207c8dd61efSSumit.Saxena@avagotech.com cmd_mfi = instance->cmd_list[i];
2208c8dd61efSSumit.Saxena@avagotech.com if (cmd_mfi->sync_cmd && cmd_mfi->frame->hdr.cmd !=
2209c8dd61efSSumit.Saxena@avagotech.com MFI_CMD_ABORT)
2210c8dd61efSSumit.Saxena@avagotech.com megasas_complete_cmd(instance, cmd_mfi, DID_OK);
2211c8dd61efSSumit.Saxena@avagotech.com }
2212c8dd61efSSumit.Saxena@avagotech.com }
2213c8dd61efSSumit.Saxena@avagotech.com }
2214c8dd61efSSumit.Saxena@avagotech.com
2215c8dd61efSSumit.Saxena@avagotech.com
megaraid_sas_kill_hba(struct megasas_instance * instance)22169c915a8cSadam radford void megaraid_sas_kill_hba(struct megasas_instance *instance)
22170d49016bSadam radford {
2218eb974f34SAnand Lodnoor if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
2219eb974f34SAnand Lodnoor dev_warn(&instance->pdev->dev,
2220eb974f34SAnand Lodnoor "Adapter already dead, skipping kill HBA\n");
2221eb974f34SAnand Lodnoor return;
2222eb974f34SAnand Lodnoor }
2223eb974f34SAnand Lodnoor
2224c8dd61efSSumit.Saxena@avagotech.com /* Set critical error to block I/O & ioctls in case caller didn't */
22258a01a41dSSumit Saxena atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
2226c8dd61efSSumit.Saxena@avagotech.com /* Wait 1 second to ensure IO or ioctls in build have posted */
2227c8dd61efSSumit.Saxena@avagotech.com msleep(1000);
22280d49016bSadam radford if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
22299c915a8cSadam radford (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
2230e7d36b88SShivasharan S (instance->adapter_type != MFI_SERIES)) {
22315acad9b9SShivasharan S if (!instance->requestorId) {
2232da0dc9fbSBjorn Helgaas writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
2233229fe47cSadam radford /* Flush */
2234229fe47cSadam radford readl(&instance->reg_set->doorbell);
22355acad9b9SShivasharan S }
22368f67c8c5SSumit Saxena if (instance->requestorId && instance->peerIsPresent)
2237229fe47cSadam radford memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
22380d49016bSadam radford } else {
2239c8dd61efSSumit.Saxena@avagotech.com writel(MFI_STOP_ADP,
2240c8dd61efSSumit.Saxena@avagotech.com &instance->reg_set->inbound_doorbell);
22419c915a8cSadam radford }
2242c8dd61efSSumit.Saxena@avagotech.com /* Complete outstanding ioctls when adapter is killed */
2243c8dd61efSSumit.Saxena@avagotech.com megasas_complete_outstanding_ioctls(instance);
22449c915a8cSadam radford }
22459c915a8cSadam radford
22469c915a8cSadam radford /**
22479c915a8cSadam radford * megasas_check_and_restore_queue_depth - Check if queue depth needs to be
22489c915a8cSadam radford * restored to max value
22499c915a8cSadam radford * @instance: Adapter soft state
22509c915a8cSadam radford *
22519c915a8cSadam radford */
22529c915a8cSadam radford void
megasas_check_and_restore_queue_depth(struct megasas_instance * instance)22539c915a8cSadam radford megasas_check_and_restore_queue_depth(struct megasas_instance *instance)
22549c915a8cSadam radford {
22559c915a8cSadam radford unsigned long flags;
2256ae09a6c1SSumit.Saxena@avagotech.com
22579c915a8cSadam radford if (instance->flag & MEGASAS_FW_BUSY
22589c915a8cSadam radford && time_after(jiffies, instance->last_time + 5 * HZ)
2259c5daa6a9Sadam radford && atomic_read(&instance->fw_outstanding) <
2260c5daa6a9Sadam radford instance->throttlequeuedepth + 1) {
22619c915a8cSadam radford
22629c915a8cSadam radford spin_lock_irqsave(instance->host->host_lock, flags);
22639c915a8cSadam radford instance->flag &= ~MEGASAS_FW_BUSY;
22649c915a8cSadam radford
2265308ec459SSumit Saxena instance->host->can_queue = instance->cur_can_queue;
22669c915a8cSadam radford spin_unlock_irqrestore(instance->host->host_lock, flags);
22670d49016bSadam radford }
22680d49016bSadam radford }
22690d49016bSadam radford
22700d49016bSadam radford /**
22710d49016bSadam radford * megasas_complete_cmd_dpc - Returns FW's controller structure
22720d49016bSadam radford * @instance_addr: Address of adapter soft state
22730d49016bSadam radford *
22740d49016bSadam radford * Tasklet to complete cmds
22750d49016bSadam radford */
megasas_complete_cmd_dpc(unsigned long instance_addr)22760d49016bSadam radford static void megasas_complete_cmd_dpc(unsigned long instance_addr)
22770d49016bSadam radford {
22780d49016bSadam radford u32 producer;
22790d49016bSadam radford u32 consumer;
22800d49016bSadam radford u32 context;
22810d49016bSadam radford struct megasas_cmd *cmd;
22820d49016bSadam radford struct megasas_instance *instance =
22830d49016bSadam radford (struct megasas_instance *)instance_addr;
22840d49016bSadam radford unsigned long flags;
22850d49016bSadam radford
22860d49016bSadam radford /* If we have already declared adapter dead, donot complete cmds */
22878a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
22880d49016bSadam radford return;
22890d49016bSadam radford
22900d49016bSadam radford spin_lock_irqsave(&instance->completion_lock, flags);
22910d49016bSadam radford
229294cd65ddSSumit.Saxena@lsi.com producer = le32_to_cpu(*instance->producer);
229394cd65ddSSumit.Saxena@lsi.com consumer = le32_to_cpu(*instance->consumer);
22940d49016bSadam radford
22950d49016bSadam radford while (consumer != producer) {
229694cd65ddSSumit.Saxena@lsi.com context = le32_to_cpu(instance->reply_queue[consumer]);
22970d49016bSadam radford if (context >= instance->max_fw_cmds) {
22981be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "Unexpected context value %x\n",
22990d49016bSadam radford context);
23000d49016bSadam radford BUG();
23010d49016bSadam radford }
23020d49016bSadam radford
23030d49016bSadam radford cmd = instance->cmd_list[context];
23040d49016bSadam radford
23050d49016bSadam radford megasas_complete_cmd(instance, cmd, DID_OK);
23060d49016bSadam radford
23070d49016bSadam radford consumer++;
23080d49016bSadam radford if (consumer == (instance->max_fw_cmds + 1)) {
23090d49016bSadam radford consumer = 0;
23100d49016bSadam radford }
23110d49016bSadam radford }
23120d49016bSadam radford
231394cd65ddSSumit.Saxena@lsi.com *instance->consumer = cpu_to_le32(producer);
23140d49016bSadam radford
23150d49016bSadam radford spin_unlock_irqrestore(&instance->completion_lock, flags);
23160d49016bSadam radford
23170d49016bSadam radford /*
23180d49016bSadam radford * Check if we can restore can_queue
23190d49016bSadam radford */
23209c915a8cSadam radford megasas_check_and_restore_queue_depth(instance);
23210d49016bSadam radford }
23220d49016bSadam radford
2323c251a7beSKees Cook static void megasas_sriov_heartbeat_handler(struct timer_list *t);
2324c251a7beSKees Cook
2325229fe47cSadam radford /**
2326c251a7beSKees Cook * megasas_start_timer - Initializes sriov heartbeat timer object
2327229fe47cSadam radford * @instance: Adapter soft state
2328229fe47cSadam radford *
2329229fe47cSadam radford */
megasas_start_timer(struct megasas_instance * instance)2330c251a7beSKees Cook void megasas_start_timer(struct megasas_instance *instance)
2331229fe47cSadam radford {
2332c251a7beSKees Cook struct timer_list *timer = &instance->sriov_heartbeat_timer;
2333c251a7beSKees Cook
2334c251a7beSKees Cook timer_setup(timer, megasas_sriov_heartbeat_handler, 0);
2335c251a7beSKees Cook timer->expires = jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF;
2336229fe47cSadam radford add_timer(timer);
2337229fe47cSadam radford }
2338229fe47cSadam radford
23390d49016bSadam radford static void
23400d49016bSadam radford megasas_internal_reset_defer_cmds(struct megasas_instance *instance);
23410d49016bSadam radford
23420d49016bSadam radford static void
23430d49016bSadam radford process_fw_state_change_wq(struct work_struct *work);
23440d49016bSadam radford
megasas_do_ocr(struct megasas_instance * instance)23456764f519SYueHaibing static void megasas_do_ocr(struct megasas_instance *instance)
23460d49016bSadam radford {
23470d49016bSadam radford if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
23480d49016bSadam radford (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
23490d49016bSadam radford (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
235094cd65ddSSumit.Saxena@lsi.com *instance->consumer = cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN);
23510d49016bSadam radford }
2352d46a3ad6SSumit.Saxena@lsi.com instance->instancet->disable_intr(instance);
23538a01a41dSSumit Saxena atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
23540d49016bSadam radford instance->issuepend_done = 0;
23550d49016bSadam radford
23560d49016bSadam radford atomic_set(&instance->fw_outstanding, 0);
23570d49016bSadam radford megasas_internal_reset_defer_cmds(instance);
23580d49016bSadam radford process_fw_state_change_wq(&instance->work_init);
23590d49016bSadam radford }
23600d49016bSadam radford
megasas_get_ld_vf_affiliation_111(struct megasas_instance * instance,int initial)23614cbfea88SAdam Radford static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance,
2362229fe47cSadam radford int initial)
2363229fe47cSadam radford {
2364229fe47cSadam radford struct megasas_cmd *cmd;
2365229fe47cSadam radford struct megasas_dcmd_frame *dcmd;
2366229fe47cSadam radford struct MR_LD_VF_AFFILIATION_111 *new_affiliation_111 = NULL;
2367229fe47cSadam radford dma_addr_t new_affiliation_111_h;
2368229fe47cSadam radford int ld, retval = 0;
2369229fe47cSadam radford u8 thisVf;
2370229fe47cSadam radford
2371229fe47cSadam radford cmd = megasas_get_cmd(instance);
2372229fe47cSadam radford
2373229fe47cSadam radford if (!cmd) {
23741be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_vf_affiliation_111:"
23751be18254SBjorn Helgaas "Failed to get cmd for scsi%d\n",
2376229fe47cSadam radford instance->host->host_no);
2377229fe47cSadam radford return -ENOMEM;
2378229fe47cSadam radford }
2379229fe47cSadam radford
2380229fe47cSadam radford dcmd = &cmd->frame->dcmd;
2381229fe47cSadam radford
23824cbfea88SAdam Radford if (!instance->vf_affiliation_111) {
23831be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "SR-IOV: Couldn't get LD/VF "
23841be18254SBjorn Helgaas "affiliation for scsi%d\n", instance->host->host_no);
2385229fe47cSadam radford megasas_return_cmd(instance, cmd);
2386229fe47cSadam radford return -ENOMEM;
2387229fe47cSadam radford }
2388229fe47cSadam radford
2389229fe47cSadam radford if (initial)
2390229fe47cSadam radford memset(instance->vf_affiliation_111, 0,
2391229fe47cSadam radford sizeof(struct MR_LD_VF_AFFILIATION_111));
2392229fe47cSadam radford else {
2393229fe47cSadam radford new_affiliation_111 =
2394750afb08SLuis Chamberlain dma_alloc_coherent(&instance->pdev->dev,
2395229fe47cSadam radford sizeof(struct MR_LD_VF_AFFILIATION_111),
239660ee6529SChristoph Hellwig &new_affiliation_111_h, GFP_KERNEL);
23974cbfea88SAdam Radford if (!new_affiliation_111) {
23981be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate "
23991be18254SBjorn Helgaas "memory for new affiliation for scsi%d\n",
2400229fe47cSadam radford instance->host->host_no);
2401229fe47cSadam radford megasas_return_cmd(instance, cmd);
2402229fe47cSadam radford return -ENOMEM;
2403229fe47cSadam radford }
24044cbfea88SAdam Radford }
24054cbfea88SAdam Radford
24064cbfea88SAdam Radford memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
24074cbfea88SAdam Radford
24084cbfea88SAdam Radford dcmd->cmd = MFI_CMD_DCMD;
24092be2a988SSumit.Saxena@avagotech.com dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
24104cbfea88SAdam Radford dcmd->sge_count = 1;
24112213a467SChristoph Hellwig dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_BOTH);
24124cbfea88SAdam Radford dcmd->timeout = 0;
24134cbfea88SAdam Radford dcmd->pad_0 = 0;
24142213a467SChristoph Hellwig dcmd->data_xfer_len =
24152213a467SChristoph Hellwig cpu_to_le32(sizeof(struct MR_LD_VF_AFFILIATION_111));
24162213a467SChristoph Hellwig dcmd->opcode = cpu_to_le32(MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111);
24174cbfea88SAdam Radford
24184cbfea88SAdam Radford if (initial)
24194cbfea88SAdam Radford dcmd->sgl.sge32[0].phys_addr =
24202213a467SChristoph Hellwig cpu_to_le32(instance->vf_affiliation_111_h);
2421229fe47cSadam radford else
24222213a467SChristoph Hellwig dcmd->sgl.sge32[0].phys_addr =
24232213a467SChristoph Hellwig cpu_to_le32(new_affiliation_111_h);
24244cbfea88SAdam Radford
24252213a467SChristoph Hellwig dcmd->sgl.sge32[0].length = cpu_to_le32(
24262213a467SChristoph Hellwig sizeof(struct MR_LD_VF_AFFILIATION_111));
24274cbfea88SAdam Radford
24281be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for "
24294cbfea88SAdam Radford "scsi%d\n", instance->host->host_no);
24304cbfea88SAdam Radford
24316d40afbcSSumit Saxena if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
24321be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD"
24331be18254SBjorn Helgaas " failed with status 0x%x for scsi%d\n",
24344cbfea88SAdam Radford dcmd->cmd_status, instance->host->host_no);
24354cbfea88SAdam Radford retval = 1; /* Do a scan if we couldn't get affiliation */
24364cbfea88SAdam Radford goto out;
24374cbfea88SAdam Radford }
24384cbfea88SAdam Radford
24394cbfea88SAdam Radford if (!initial) {
24404cbfea88SAdam Radford thisVf = new_affiliation_111->thisVf;
24414cbfea88SAdam Radford for (ld = 0 ; ld < new_affiliation_111->vdCount; ld++)
24424cbfea88SAdam Radford if (instance->vf_affiliation_111->map[ld].policy[thisVf] !=
24434cbfea88SAdam Radford new_affiliation_111->map[ld].policy[thisVf]) {
24441be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "SR-IOV: "
24451be18254SBjorn Helgaas "Got new LD/VF affiliation for scsi%d\n",
24464cbfea88SAdam Radford instance->host->host_no);
24474cbfea88SAdam Radford memcpy(instance->vf_affiliation_111,
24484cbfea88SAdam Radford new_affiliation_111,
24494cbfea88SAdam Radford sizeof(struct MR_LD_VF_AFFILIATION_111));
24504cbfea88SAdam Radford retval = 1;
24514cbfea88SAdam Radford goto out;
24524cbfea88SAdam Radford }
24534cbfea88SAdam Radford }
24544cbfea88SAdam Radford out:
24554cbfea88SAdam Radford if (new_affiliation_111) {
245660ee6529SChristoph Hellwig dma_free_coherent(&instance->pdev->dev,
24574cbfea88SAdam Radford sizeof(struct MR_LD_VF_AFFILIATION_111),
24584cbfea88SAdam Radford new_affiliation_111,
24594cbfea88SAdam Radford new_affiliation_111_h);
24604cbfea88SAdam Radford }
246190dc9d98SSumit.Saxena@avagotech.com
24624cbfea88SAdam Radford megasas_return_cmd(instance, cmd);
24634cbfea88SAdam Radford
24644cbfea88SAdam Radford return retval;
24654cbfea88SAdam Radford }
24664cbfea88SAdam Radford
megasas_get_ld_vf_affiliation_12(struct megasas_instance * instance,int initial)24674cbfea88SAdam Radford static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance,
24684cbfea88SAdam Radford int initial)
24694cbfea88SAdam Radford {
24704cbfea88SAdam Radford struct megasas_cmd *cmd;
24714cbfea88SAdam Radford struct megasas_dcmd_frame *dcmd;
24724cbfea88SAdam Radford struct MR_LD_VF_AFFILIATION *new_affiliation = NULL;
24734cbfea88SAdam Radford struct MR_LD_VF_MAP *newmap = NULL, *savedmap = NULL;
24744cbfea88SAdam Radford dma_addr_t new_affiliation_h;
24754cbfea88SAdam Radford int i, j, retval = 0, found = 0, doscan = 0;
24764cbfea88SAdam Radford u8 thisVf;
24774cbfea88SAdam Radford
24784cbfea88SAdam Radford cmd = megasas_get_cmd(instance);
24794cbfea88SAdam Radford
24804cbfea88SAdam Radford if (!cmd) {
24811be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_vf_affiliation12: "
24821be18254SBjorn Helgaas "Failed to get cmd for scsi%d\n",
24834cbfea88SAdam Radford instance->host->host_no);
24844cbfea88SAdam Radford return -ENOMEM;
24854cbfea88SAdam Radford }
24864cbfea88SAdam Radford
24874cbfea88SAdam Radford dcmd = &cmd->frame->dcmd;
24884cbfea88SAdam Radford
24894cbfea88SAdam Radford if (!instance->vf_affiliation) {
24901be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "SR-IOV: Couldn't get LD/VF "
24911be18254SBjorn Helgaas "affiliation for scsi%d\n", instance->host->host_no);
24924cbfea88SAdam Radford megasas_return_cmd(instance, cmd);
24934cbfea88SAdam Radford return -ENOMEM;
24944cbfea88SAdam Radford }
24954cbfea88SAdam Radford
24964cbfea88SAdam Radford if (initial)
24974cbfea88SAdam Radford memset(instance->vf_affiliation, 0, (MAX_LOGICAL_DRIVES + 1) *
24984cbfea88SAdam Radford sizeof(struct MR_LD_VF_AFFILIATION));
24994cbfea88SAdam Radford else {
25004cbfea88SAdam Radford new_affiliation =
2501750afb08SLuis Chamberlain dma_alloc_coherent(&instance->pdev->dev,
2502750afb08SLuis Chamberlain (MAX_LOGICAL_DRIVES + 1) * sizeof(struct MR_LD_VF_AFFILIATION),
250360ee6529SChristoph Hellwig &new_affiliation_h, GFP_KERNEL);
25044cbfea88SAdam Radford if (!new_affiliation) {
25051be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate "
25061be18254SBjorn Helgaas "memory for new affiliation for scsi%d\n",
25074cbfea88SAdam Radford instance->host->host_no);
25084cbfea88SAdam Radford megasas_return_cmd(instance, cmd);
25094cbfea88SAdam Radford return -ENOMEM;
25104cbfea88SAdam Radford }
2511229fe47cSadam radford }
2512229fe47cSadam radford
2513229fe47cSadam radford memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
2514229fe47cSadam radford
2515229fe47cSadam radford dcmd->cmd = MFI_CMD_DCMD;
25162be2a988SSumit.Saxena@avagotech.com dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
2517229fe47cSadam radford dcmd->sge_count = 1;
25182213a467SChristoph Hellwig dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_BOTH);
2519229fe47cSadam radford dcmd->timeout = 0;
2520229fe47cSadam radford dcmd->pad_0 = 0;
25212213a467SChristoph Hellwig dcmd->data_xfer_len = cpu_to_le32((MAX_LOGICAL_DRIVES + 1) *
25222213a467SChristoph Hellwig sizeof(struct MR_LD_VF_AFFILIATION));
25232213a467SChristoph Hellwig dcmd->opcode = cpu_to_le32(MR_DCMD_LD_VF_MAP_GET_ALL_LDS);
2524229fe47cSadam radford
25254cbfea88SAdam Radford if (initial)
25262213a467SChristoph Hellwig dcmd->sgl.sge32[0].phys_addr =
25272213a467SChristoph Hellwig cpu_to_le32(instance->vf_affiliation_h);
2528229fe47cSadam radford else
25292213a467SChristoph Hellwig dcmd->sgl.sge32[0].phys_addr =
25302213a467SChristoph Hellwig cpu_to_le32(new_affiliation_h);
25314cbfea88SAdam Radford
25322213a467SChristoph Hellwig dcmd->sgl.sge32[0].length = cpu_to_le32((MAX_LOGICAL_DRIVES + 1) *
25332213a467SChristoph Hellwig sizeof(struct MR_LD_VF_AFFILIATION));
2534229fe47cSadam radford
25351be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for "
2536229fe47cSadam radford "scsi%d\n", instance->host->host_no);
2537229fe47cSadam radford
2538229fe47cSadam radford
25396d40afbcSSumit Saxena if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
25401be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD"
25411be18254SBjorn Helgaas " failed with status 0x%x for scsi%d\n",
2542229fe47cSadam radford dcmd->cmd_status, instance->host->host_no);
2543229fe47cSadam radford retval = 1; /* Do a scan if we couldn't get affiliation */
2544229fe47cSadam radford goto out;
2545229fe47cSadam radford }
2546229fe47cSadam radford
2547229fe47cSadam radford if (!initial) {
2548229fe47cSadam radford if (!new_affiliation->ldCount) {
25491be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "SR-IOV: Got new LD/VF "
25501be18254SBjorn Helgaas "affiliation for passive path for scsi%d\n",
2551229fe47cSadam radford instance->host->host_no);
2552229fe47cSadam radford retval = 1;
2553229fe47cSadam radford goto out;
2554229fe47cSadam radford }
2555229fe47cSadam radford newmap = new_affiliation->map;
2556229fe47cSadam radford savedmap = instance->vf_affiliation->map;
2557229fe47cSadam radford thisVf = new_affiliation->thisVf;
25584cbfea88SAdam Radford for (i = 0 ; i < new_affiliation->ldCount; i++) {
25594cbfea88SAdam Radford found = 0;
25604cbfea88SAdam Radford for (j = 0; j < instance->vf_affiliation->ldCount;
25614cbfea88SAdam Radford j++) {
25624cbfea88SAdam Radford if (newmap->ref.targetId ==
25634cbfea88SAdam Radford savedmap->ref.targetId) {
25644cbfea88SAdam Radford found = 1;
25654cbfea88SAdam Radford if (newmap->policy[thisVf] !=
25664cbfea88SAdam Radford savedmap->policy[thisVf]) {
25674cbfea88SAdam Radford doscan = 1;
25684cbfea88SAdam Radford goto out;
25694cbfea88SAdam Radford }
25704cbfea88SAdam Radford }
25714cbfea88SAdam Radford savedmap = (struct MR_LD_VF_MAP *)
25724cbfea88SAdam Radford ((unsigned char *)savedmap +
25734cbfea88SAdam Radford savedmap->size);
25744cbfea88SAdam Radford }
25754cbfea88SAdam Radford if (!found && newmap->policy[thisVf] !=
25764cbfea88SAdam Radford MR_LD_ACCESS_HIDDEN) {
25774cbfea88SAdam Radford doscan = 1;
25784cbfea88SAdam Radford goto out;
25794cbfea88SAdam Radford }
25804cbfea88SAdam Radford newmap = (struct MR_LD_VF_MAP *)
25814cbfea88SAdam Radford ((unsigned char *)newmap + newmap->size);
25824cbfea88SAdam Radford }
25834cbfea88SAdam Radford
25844cbfea88SAdam Radford newmap = new_affiliation->map;
25854cbfea88SAdam Radford savedmap = instance->vf_affiliation->map;
25864cbfea88SAdam Radford
25874cbfea88SAdam Radford for (i = 0 ; i < instance->vf_affiliation->ldCount; i++) {
25884cbfea88SAdam Radford found = 0;
25894cbfea88SAdam Radford for (j = 0 ; j < new_affiliation->ldCount; j++) {
25904cbfea88SAdam Radford if (savedmap->ref.targetId ==
25914cbfea88SAdam Radford newmap->ref.targetId) {
25924cbfea88SAdam Radford found = 1;
2593229fe47cSadam radford if (savedmap->policy[thisVf] !=
2594229fe47cSadam radford newmap->policy[thisVf]) {
25954cbfea88SAdam Radford doscan = 1;
25964cbfea88SAdam Radford goto out;
25974cbfea88SAdam Radford }
25984cbfea88SAdam Radford }
25994cbfea88SAdam Radford newmap = (struct MR_LD_VF_MAP *)
26004cbfea88SAdam Radford ((unsigned char *)newmap +
26014cbfea88SAdam Radford newmap->size);
26024cbfea88SAdam Radford }
26034cbfea88SAdam Radford if (!found && savedmap->policy[thisVf] !=
26044cbfea88SAdam Radford MR_LD_ACCESS_HIDDEN) {
26054cbfea88SAdam Radford doscan = 1;
2606229fe47cSadam radford goto out;
2607229fe47cSadam radford }
2608229fe47cSadam radford savedmap = (struct MR_LD_VF_MAP *)
2609229fe47cSadam radford ((unsigned char *)savedmap +
2610229fe47cSadam radford savedmap->size);
2611229fe47cSadam radford }
2612229fe47cSadam radford }
2613229fe47cSadam radford out:
26144cbfea88SAdam Radford if (doscan) {
26151be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "SR-IOV: Got new LD/VF "
26161be18254SBjorn Helgaas "affiliation for scsi%d\n", instance->host->host_no);
26174cbfea88SAdam Radford memcpy(instance->vf_affiliation, new_affiliation,
26184cbfea88SAdam Radford new_affiliation->size);
26194cbfea88SAdam Radford retval = 1;
26204cbfea88SAdam Radford }
26214cbfea88SAdam Radford
26224cbfea88SAdam Radford if (new_affiliation)
262360ee6529SChristoph Hellwig dma_free_coherent(&instance->pdev->dev,
2624229fe47cSadam radford (MAX_LOGICAL_DRIVES + 1) *
2625229fe47cSadam radford sizeof(struct MR_LD_VF_AFFILIATION),
2626229fe47cSadam radford new_affiliation, new_affiliation_h);
2627229fe47cSadam radford megasas_return_cmd(instance, cmd);
2628229fe47cSadam radford
2629229fe47cSadam radford return retval;
2630229fe47cSadam radford }
2631229fe47cSadam radford
26324cbfea88SAdam Radford /* This function will get the current SR-IOV LD/VF affiliation */
megasas_get_ld_vf_affiliation(struct megasas_instance * instance,int initial)26334cbfea88SAdam Radford static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
26344cbfea88SAdam Radford int initial)
26354cbfea88SAdam Radford {
26364cbfea88SAdam Radford int retval;
26374cbfea88SAdam Radford
26384cbfea88SAdam Radford if (instance->PlasmaFW111)
26394cbfea88SAdam Radford retval = megasas_get_ld_vf_affiliation_111(instance, initial);
26404cbfea88SAdam Radford else
26414cbfea88SAdam Radford retval = megasas_get_ld_vf_affiliation_12(instance, initial);
26424cbfea88SAdam Radford return retval;
26434cbfea88SAdam Radford }
26444cbfea88SAdam Radford
2645229fe47cSadam radford /* This function will tell FW to start the SR-IOV heartbeat */
megasas_sriov_start_heartbeat(struct megasas_instance * instance,int initial)2646229fe47cSadam radford int megasas_sriov_start_heartbeat(struct megasas_instance *instance,
2647229fe47cSadam radford int initial)
2648229fe47cSadam radford {
2649229fe47cSadam radford struct megasas_cmd *cmd;
2650229fe47cSadam radford struct megasas_dcmd_frame *dcmd;
2651229fe47cSadam radford int retval = 0;
2652229fe47cSadam radford
2653229fe47cSadam radford cmd = megasas_get_cmd(instance);
2654229fe47cSadam radford
2655229fe47cSadam radford if (!cmd) {
26561be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_sriov_start_heartbeat: "
26571be18254SBjorn Helgaas "Failed to get cmd for scsi%d\n",
2658229fe47cSadam radford instance->host->host_no);
2659229fe47cSadam radford return -ENOMEM;
2660229fe47cSadam radford }
2661229fe47cSadam radford
2662229fe47cSadam radford dcmd = &cmd->frame->dcmd;
2663229fe47cSadam radford
2664229fe47cSadam radford if (initial) {
2665229fe47cSadam radford instance->hb_host_mem =
2666750afb08SLuis Chamberlain dma_alloc_coherent(&instance->pdev->dev,
2667229fe47cSadam radford sizeof(struct MR_CTRL_HB_HOST_MEM),
2668750afb08SLuis Chamberlain &instance->hb_host_mem_h,
2669750afb08SLuis Chamberlain GFP_KERNEL);
2670229fe47cSadam radford if (!instance->hb_host_mem) {
26711be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate"
26721be18254SBjorn Helgaas " memory for heartbeat host memory for scsi%d\n",
26731be18254SBjorn Helgaas instance->host->host_no);
2674229fe47cSadam radford retval = -ENOMEM;
2675229fe47cSadam radford goto out;
2676229fe47cSadam radford }
2677229fe47cSadam radford }
2678229fe47cSadam radford
2679229fe47cSadam radford memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
2680229fe47cSadam radford
26812213a467SChristoph Hellwig dcmd->mbox.s[0] = cpu_to_le16(sizeof(struct MR_CTRL_HB_HOST_MEM));
2682229fe47cSadam radford dcmd->cmd = MFI_CMD_DCMD;
26832be2a988SSumit.Saxena@avagotech.com dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
2684229fe47cSadam radford dcmd->sge_count = 1;
26852213a467SChristoph Hellwig dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_BOTH);
2686229fe47cSadam radford dcmd->timeout = 0;
2687229fe47cSadam radford dcmd->pad_0 = 0;
26882213a467SChristoph Hellwig dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_CTRL_HB_HOST_MEM));
26892213a467SChristoph Hellwig dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC);
2690107a60ddSShivasharan S
2691107a60ddSShivasharan S megasas_set_dma_settings(instance, dcmd, instance->hb_host_mem_h,
2692107a60ddSShivasharan S sizeof(struct MR_CTRL_HB_HOST_MEM));
2693229fe47cSadam radford
26941be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "SR-IOV: Starting heartbeat for scsi%d\n",
2695229fe47cSadam radford instance->host->host_no);
2696229fe47cSadam radford
2697e7d36b88SShivasharan S if ((instance->adapter_type != MFI_SERIES) &&
2698e7d36b88SShivasharan S !instance->mask_interrupts)
26994026e9aaSSumit.Saxena@avagotech.com retval = megasas_issue_blocked_cmd(instance, cmd,
27004026e9aaSSumit.Saxena@avagotech.com MEGASAS_ROUTINE_WAIT_TIME_VF);
27014026e9aaSSumit.Saxena@avagotech.com else
27024026e9aaSSumit.Saxena@avagotech.com retval = megasas_issue_polled(instance, cmd);
2703229fe47cSadam radford
27044026e9aaSSumit.Saxena@avagotech.com if (retval) {
27052be2a988SSumit.Saxena@avagotech.com dev_warn(&instance->pdev->dev, "SR-IOV: MR_DCMD_CTRL_SHARED_HOST"
27062be2a988SSumit.Saxena@avagotech.com "_MEM_ALLOC DCMD %s for scsi%d\n",
27072be2a988SSumit.Saxena@avagotech.com (dcmd->cmd_status == MFI_STAT_INVALID_STATUS) ?
27082be2a988SSumit.Saxena@avagotech.com "timed out" : "failed", instance->host->host_no);
2709229fe47cSadam radford retval = 1;
2710229fe47cSadam radford }
2711229fe47cSadam radford
2712229fe47cSadam radford out:
2713229fe47cSadam radford megasas_return_cmd(instance, cmd);
2714229fe47cSadam radford
2715229fe47cSadam radford return retval;
2716229fe47cSadam radford }
2717229fe47cSadam radford
2718229fe47cSadam radford /* Handler for SR-IOV heartbeat */
megasas_sriov_heartbeat_handler(struct timer_list * t)2719c251a7beSKees Cook static void megasas_sriov_heartbeat_handler(struct timer_list *t)
2720229fe47cSadam radford {
2721229fe47cSadam radford struct megasas_instance *instance =
2722c251a7beSKees Cook from_timer(instance, t, sriov_heartbeat_timer);
2723229fe47cSadam radford
2724229fe47cSadam radford if (instance->hb_host_mem->HB.fwCounter !=
2725229fe47cSadam radford instance->hb_host_mem->HB.driverCounter) {
2726229fe47cSadam radford instance->hb_host_mem->HB.driverCounter =
2727229fe47cSadam radford instance->hb_host_mem->HB.fwCounter;
2728229fe47cSadam radford mod_timer(&instance->sriov_heartbeat_timer,
2729229fe47cSadam radford jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
2730229fe47cSadam radford } else {
27311be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "SR-IOV: Heartbeat never "
2732229fe47cSadam radford "completed for scsi%d\n", instance->host->host_no);
2733229fe47cSadam radford schedule_work(&instance->work_init);
2734229fe47cSadam radford }
2735229fe47cSadam radford }
2736229fe47cSadam radford
27370d49016bSadam radford /**
27380d49016bSadam radford * megasas_wait_for_outstanding - Wait for all outstanding cmds
27390d49016bSadam radford * @instance: Adapter soft state
27400d49016bSadam radford *
27410d49016bSadam radford * This function waits for up to MEGASAS_RESET_WAIT_TIME seconds for FW to
27420d49016bSadam radford * complete all its outstanding commands. Returns error if one or more IOs
27430d49016bSadam radford * are pending after this time period. It also marks the controller dead.
27440d49016bSadam radford */
megasas_wait_for_outstanding(struct megasas_instance * instance)27450d49016bSadam radford static int megasas_wait_for_outstanding(struct megasas_instance *instance)
27460d49016bSadam radford {
2747ccc7507dSSumit Saxena int i, sl, outstanding;
27480d49016bSadam radford u32 reset_index;
27490d49016bSadam radford u32 wait_time = MEGASAS_RESET_WAIT_TIME;
27500d49016bSadam radford unsigned long flags;
27510d49016bSadam radford struct list_head clist_local;
27520d49016bSadam radford struct megasas_cmd *reset_cmd;
27530d49016bSadam radford u32 fw_state;
27540d49016bSadam radford
2755ccc7507dSSumit Saxena if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
2756ccc7507dSSumit Saxena dev_info(&instance->pdev->dev, "%s:%d HBA is killed.\n",
2757ccc7507dSSumit Saxena __func__, __LINE__);
2758ccc7507dSSumit Saxena return FAILED;
2759ccc7507dSSumit Saxena }
27600d49016bSadam radford
27618a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
27620d49016bSadam radford
27630d49016bSadam radford INIT_LIST_HEAD(&clist_local);
27640d49016bSadam radford spin_lock_irqsave(&instance->hba_lock, flags);
27650d49016bSadam radford list_splice_init(&instance->internal_reset_pending_q,
27660d49016bSadam radford &clist_local);
27670d49016bSadam radford spin_unlock_irqrestore(&instance->hba_lock, flags);
27680d49016bSadam radford
27691be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "HBA reset wait ...\n");
27700d49016bSadam radford for (i = 0; i < wait_time; i++) {
27710d49016bSadam radford msleep(1000);
27728a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL)
27730d49016bSadam radford break;
27740d49016bSadam radford }
27750d49016bSadam radford
27768a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
27771be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "reset: Stopping HBA.\n");
27788a01a41dSSumit Saxena atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
27790d49016bSadam radford return FAILED;
27800d49016bSadam radford }
27810d49016bSadam radford
27820d49016bSadam radford reset_index = 0;
27830d49016bSadam radford while (!list_empty(&clist_local)) {
27840d49016bSadam radford reset_cmd = list_entry((&clist_local)->next,
27850d49016bSadam radford struct megasas_cmd, list);
27860d49016bSadam radford list_del_init(&reset_cmd->list);
27870d49016bSadam radford if (reset_cmd->scmd) {
2788f55cf47dSShivasharan S reset_cmd->scmd->result = DID_REQUEUE << 16;
27891be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "%d:%p reset [%02x]\n",
27900d49016bSadam radford reset_index, reset_cmd,
27915cd049a5SChristoph Hellwig reset_cmd->scmd->cmnd[0]);
27920d49016bSadam radford
2793012f14b2SBart Van Assche scsi_done(reset_cmd->scmd);
27940d49016bSadam radford megasas_return_cmd(instance, reset_cmd);
27950d49016bSadam radford } else if (reset_cmd->sync_cmd) {
27961be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "%p synch cmds"
27970d49016bSadam radford "reset queue\n",
27980d49016bSadam radford reset_cmd);
27990d49016bSadam radford
2800201a810cSAnand Lodnoor reset_cmd->cmd_status_drv = DCMD_INIT;
28010d49016bSadam radford instance->instancet->fire_cmd(instance,
28020d49016bSadam radford reset_cmd->frame_phys_addr,
28030d49016bSadam radford 0, instance->reg_set);
28040d49016bSadam radford } else {
28051be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "%p unexpected"
28060d49016bSadam radford "cmds lst\n",
28070d49016bSadam radford reset_cmd);
28080d49016bSadam radford }
28090d49016bSadam radford reset_index++;
28100d49016bSadam radford }
28110d49016bSadam radford
28120d49016bSadam radford return SUCCESS;
28130d49016bSadam radford }
28140d49016bSadam radford
2815c007b8b2Sadam radford for (i = 0; i < resetwaittime; i++) {
2816ccc7507dSSumit Saxena outstanding = atomic_read(&instance->fw_outstanding);
28170d49016bSadam radford
28180d49016bSadam radford if (!outstanding)
28190d49016bSadam radford break;
28200d49016bSadam radford
28210d49016bSadam radford if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
28221be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "[%2d]waiting for %d "
28230d49016bSadam radford "commands to complete\n",i,outstanding);
28240d49016bSadam radford /*
28250d49016bSadam radford * Call cmd completion routine. Cmd to be
28260d49016bSadam radford * be completed directly without depending on isr.
28270d49016bSadam radford */
28280d49016bSadam radford megasas_complete_cmd_dpc((unsigned long)instance);
28290d49016bSadam radford }
28300d49016bSadam radford
28310d49016bSadam radford msleep(1000);
28320d49016bSadam radford }
28330d49016bSadam radford
28340d49016bSadam radford i = 0;
2835ccc7507dSSumit Saxena outstanding = atomic_read(&instance->fw_outstanding);
2836de516379SShivasharan S fw_state = instance->instancet->read_fw_status_reg(instance) & MFI_STATE_MASK;
28370d49016bSadam radford
2838ccc7507dSSumit Saxena if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
2839ccc7507dSSumit Saxena goto no_outstanding;
2840ccc7507dSSumit Saxena
2841ccc7507dSSumit Saxena if (instance->disableOnlineCtrlReset)
2842ccc7507dSSumit Saxena goto kill_hba_and_failed;
2843ccc7507dSSumit Saxena do {
2844ccc7507dSSumit Saxena if ((fw_state == MFI_STATE_FAULT) || atomic_read(&instance->fw_outstanding)) {
2845ccc7507dSSumit Saxena dev_info(&instance->pdev->dev,
2846efc372c1SColin Ian King "%s:%d waiting_for_outstanding: before issue OCR. FW state = 0x%x, outstanding 0x%x\n",
2847ccc7507dSSumit Saxena __func__, __LINE__, fw_state, atomic_read(&instance->fw_outstanding));
2848ccc7507dSSumit Saxena if (i == 3)
2849ccc7507dSSumit Saxena goto kill_hba_and_failed;
2850ccc7507dSSumit Saxena megasas_do_ocr(instance);
2851ccc7507dSSumit Saxena
2852ccc7507dSSumit Saxena if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
2853ccc7507dSSumit Saxena dev_info(&instance->pdev->dev, "%s:%d OCR failed and HBA is killed.\n",
2854ccc7507dSSumit Saxena __func__, __LINE__);
2855ccc7507dSSumit Saxena return FAILED;
2856ccc7507dSSumit Saxena }
2857ccc7507dSSumit Saxena dev_info(&instance->pdev->dev, "%s:%d waiting_for_outstanding: after issue OCR.\n",
2858ccc7507dSSumit Saxena __func__, __LINE__);
2859ccc7507dSSumit Saxena
2860ccc7507dSSumit Saxena for (sl = 0; sl < 10; sl++)
2861ccc7507dSSumit Saxena msleep(500);
2862ccc7507dSSumit Saxena
2863ccc7507dSSumit Saxena outstanding = atomic_read(&instance->fw_outstanding);
2864ccc7507dSSumit Saxena
2865de516379SShivasharan S fw_state = instance->instancet->read_fw_status_reg(instance) & MFI_STATE_MASK;
2866ccc7507dSSumit Saxena if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
2867ccc7507dSSumit Saxena goto no_outstanding;
28680d49016bSadam radford }
28690d49016bSadam radford i++;
28700d49016bSadam radford } while (i <= 3);
28710d49016bSadam radford
2872ccc7507dSSumit Saxena no_outstanding:
28730d49016bSadam radford
2874ccc7507dSSumit Saxena dev_info(&instance->pdev->dev, "%s:%d no more pending commands remain after reset handling.\n",
2875ccc7507dSSumit Saxena __func__, __LINE__);
28760d49016bSadam radford return SUCCESS;
28770d49016bSadam radford
2878ccc7507dSSumit Saxena kill_hba_and_failed:
2879ccc7507dSSumit Saxena
2880ccc7507dSSumit Saxena /* Reset not supported, kill adapter */
2881ccc7507dSSumit Saxena dev_info(&instance->pdev->dev, "%s:%d killing adapter scsi%d"
2882ccc7507dSSumit Saxena " disableOnlineCtrlReset %d fw_outstanding %d \n",
2883ccc7507dSSumit Saxena __func__, __LINE__, instance->host->host_no, instance->disableOnlineCtrlReset,
2884ccc7507dSSumit Saxena atomic_read(&instance->fw_outstanding));
28850d49016bSadam radford megasas_dump_pending_frames(instance);
2886ccc7507dSSumit Saxena megaraid_sas_kill_hba(instance);
2887ccc7507dSSumit Saxena
28880d49016bSadam radford return FAILED;
28890d49016bSadam radford }
28900d49016bSadam radford
28910d49016bSadam radford /**
28920d49016bSadam radford * megasas_generic_reset - Generic reset routine
28930d49016bSadam radford * @scmd: Mid-layer SCSI command
28940d49016bSadam radford *
28950d49016bSadam radford * This routine implements a generic reset handler for device, bus and host
28960d49016bSadam radford * reset requests. Device, bus and host specific reset handlers can use this
28970d49016bSadam radford * function after they do their specific tasks.
28980d49016bSadam radford */
megasas_generic_reset(struct scsi_cmnd * scmd)28990d49016bSadam radford static int megasas_generic_reset(struct scsi_cmnd *scmd)
29000d49016bSadam radford {
29010d49016bSadam radford int ret_val;
29020d49016bSadam radford struct megasas_instance *instance;
29030d49016bSadam radford
29040d49016bSadam radford instance = (struct megasas_instance *)scmd->device->host->hostdata;
29050d49016bSadam radford
29065cd049a5SChristoph Hellwig scmd_printk(KERN_NOTICE, scmd, "megasas: RESET cmd=%x retries=%x\n",
29075cd049a5SChristoph Hellwig scmd->cmnd[0], scmd->retries);
29080d49016bSadam radford
29098a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
29101be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "cannot recover from previous reset failures\n");
29110d49016bSadam radford return FAILED;
29120d49016bSadam radford }
29130d49016bSadam radford
29140d49016bSadam radford ret_val = megasas_wait_for_outstanding(instance);
29150d49016bSadam radford if (ret_val == SUCCESS)
29161be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "reset successful\n");
29170d49016bSadam radford else
29181be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "failed to do reset\n");
29190d49016bSadam radford
29200d49016bSadam radford return ret_val;
29210d49016bSadam radford }
29220d49016bSadam radford
29230d49016bSadam radford /**
29240d49016bSadam radford * megasas_reset_timer - quiesce the adapter if required
29250d49016bSadam radford * @scmd: scsi cmnd
29260d49016bSadam radford *
29270d49016bSadam radford * Sets the FW busy flag and reduces the host->can_queue if the
29280d49016bSadam radford * cmd has not been completed within the timeout period.
29290d49016bSadam radford */
megasas_reset_timer(struct scsi_cmnd * scmd)2930dee7121eSBart Van Assche static enum scsi_timeout_action megasas_reset_timer(struct scsi_cmnd *scmd)
29310d49016bSadam radford {
29320d49016bSadam radford struct megasas_instance *instance;
29330d49016bSadam radford unsigned long flags;
29340d49016bSadam radford
29350d49016bSadam radford if (time_after(jiffies, scmd->jiffies_at_alloc +
2936e3d178caSSumit Saxena (scmd_timeout * 2) * HZ)) {
2937dee7121eSBart Van Assche return SCSI_EH_NOT_HANDLED;
29380d49016bSadam radford }
29390d49016bSadam radford
2940f575c5d3Sadam radford instance = (struct megasas_instance *)scmd->device->host->hostdata;
29410d49016bSadam radford if (!(instance->flag & MEGASAS_FW_BUSY)) {
29420d49016bSadam radford /* FW is busy, throttle IO */
29430d49016bSadam radford spin_lock_irqsave(instance->host->host_lock, flags);
29440d49016bSadam radford
2945c5daa6a9Sadam radford instance->host->can_queue = instance->throttlequeuedepth;
29460d49016bSadam radford instance->last_time = jiffies;
29470d49016bSadam radford instance->flag |= MEGASAS_FW_BUSY;
29480d49016bSadam radford
29490d49016bSadam radford spin_unlock_irqrestore(instance->host->host_lock, flags);
29500d49016bSadam radford }
2951dee7121eSBart Van Assche return SCSI_EH_RESET_TIMER;
29520d49016bSadam radford }
29530d49016bSadam radford
29540d49016bSadam radford /**
29554fe55035SShivasharan S * megasas_dump - This function will print hexdump of provided buffer.
29564fe55035SShivasharan S * @buf: Buffer to be dumped
29574fe55035SShivasharan S * @sz: Size in bytes
29584fe55035SShivasharan S * @format: Different formats of dumping e.g. format=n will
29594fe55035SShivasharan S * cause only 'n' 32 bit words to be dumped in a single
29604fe55035SShivasharan S * line.
2961def0eab3SShivasharan S */
296296c9603cSShivasharan S inline void
megasas_dump(void * buf,int sz,int format)29634fe55035SShivasharan S megasas_dump(void *buf, int sz, int format)
2964def0eab3SShivasharan S {
2965def0eab3SShivasharan S int i;
29664fe55035SShivasharan S __le32 *buf_loc = (__le32 *)buf;
2967def0eab3SShivasharan S
29684fe55035SShivasharan S for (i = 0; i < (sz / sizeof(__le32)); i++) {
29694fe55035SShivasharan S if ((i % format) == 0) {
29704fe55035SShivasharan S if (i != 0)
29714fe55035SShivasharan S printk(KERN_CONT "\n");
29724fe55035SShivasharan S printk(KERN_CONT "%08x: ", (i * 4));
2973def0eab3SShivasharan S }
29744fe55035SShivasharan S printk(KERN_CONT "%08x ", le32_to_cpu(buf_loc[i]));
29754fe55035SShivasharan S }
29764fe55035SShivasharan S printk(KERN_CONT "\n");
2977def0eab3SShivasharan S }
2978def0eab3SShivasharan S
2979def0eab3SShivasharan S /**
29803d1d9eb7SShivasharan S * megasas_dump_reg_set - This function will print hexdump of register set
29812b46e5c1SDamien Le Moal * @reg_set: Register set to be dumped
29823d1d9eb7SShivasharan S */
29833d1d9eb7SShivasharan S inline void
megasas_dump_reg_set(void __iomem * reg_set)29843d1d9eb7SShivasharan S megasas_dump_reg_set(void __iomem *reg_set)
29853d1d9eb7SShivasharan S {
29863d1d9eb7SShivasharan S unsigned int i, sz = 256;
29873d1d9eb7SShivasharan S u32 __iomem *reg = (u32 __iomem *)reg_set;
29883d1d9eb7SShivasharan S
29893d1d9eb7SShivasharan S for (i = 0; i < (sz / sizeof(u32)); i++)
29903d1d9eb7SShivasharan S printk("%08x: %08x\n", (i * 4), readl(®[i]));
29913d1d9eb7SShivasharan S }
29923d1d9eb7SShivasharan S
29933d1d9eb7SShivasharan S /**
299496c9603cSShivasharan S * megasas_dump_fusion_io - This function will print key details
299596c9603cSShivasharan S * of SCSI IO
299696c9603cSShivasharan S * @scmd: SCSI command pointer of SCSI IO
299796c9603cSShivasharan S */
299896c9603cSShivasharan S void
megasas_dump_fusion_io(struct scsi_cmnd * scmd)299996c9603cSShivasharan S megasas_dump_fusion_io(struct scsi_cmnd *scmd)
300096c9603cSShivasharan S {
300196e77a27SBart Van Assche struct megasas_cmd_fusion *cmd = megasas_priv(scmd)->cmd_priv;
300296c9603cSShivasharan S union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
300396c9603cSShivasharan S struct megasas_instance *instance;
300496c9603cSShivasharan S
300596c9603cSShivasharan S instance = (struct megasas_instance *)scmd->device->host->hostdata;
300696c9603cSShivasharan S
300796c9603cSShivasharan S scmd_printk(KERN_INFO, scmd,
300896c9603cSShivasharan S "scmd: (0x%p) retries: 0x%x allowed: 0x%x\n",
300996c9603cSShivasharan S scmd, scmd->retries, scmd->allowed);
301096c9603cSShivasharan S scsi_print_command(scmd);
301196c9603cSShivasharan S
301296c9603cSShivasharan S if (cmd) {
301396c9603cSShivasharan S req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc;
301496c9603cSShivasharan S scmd_printk(KERN_INFO, scmd, "Request descriptor details:\n");
301596c9603cSShivasharan S scmd_printk(KERN_INFO, scmd,
301696c9603cSShivasharan S "RequestFlags:0x%x MSIxIndex:0x%x SMID:0x%x LMID:0x%x DevHandle:0x%x\n",
301796c9603cSShivasharan S req_desc->SCSIIO.RequestFlags,
301896c9603cSShivasharan S req_desc->SCSIIO.MSIxIndex, req_desc->SCSIIO.SMID,
301996c9603cSShivasharan S req_desc->SCSIIO.LMID, req_desc->SCSIIO.DevHandle);
302096c9603cSShivasharan S
302196c9603cSShivasharan S printk(KERN_INFO "IO request frame:\n");
302296c9603cSShivasharan S megasas_dump(cmd->io_request,
30234fe55035SShivasharan S MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE, 8);
302496c9603cSShivasharan S printk(KERN_INFO "Chain frame:\n");
302596c9603cSShivasharan S megasas_dump(cmd->sg_frame,
30264fe55035SShivasharan S instance->max_chain_frame_sz, 8);
302796c9603cSShivasharan S }
302896c9603cSShivasharan S
302996c9603cSShivasharan S }
303096c9603cSShivasharan S
3031cfb9a30eSShivasharan S /*
3032cfb9a30eSShivasharan S * megasas_dump_sys_regs - This function will dump system registers through
3033cfb9a30eSShivasharan S * sysfs.
3034cfb9a30eSShivasharan S * @reg_set: Pointer to System register set.
3035cfb9a30eSShivasharan S * @buf: Buffer to which output is to be written.
3036cfb9a30eSShivasharan S * @return: Number of bytes written to buffer.
3037cfb9a30eSShivasharan S */
3038cfb9a30eSShivasharan S static inline ssize_t
megasas_dump_sys_regs(void __iomem * reg_set,char * buf)3039cfb9a30eSShivasharan S megasas_dump_sys_regs(void __iomem *reg_set, char *buf)
3040cfb9a30eSShivasharan S {
3041cfb9a30eSShivasharan S unsigned int i, sz = 256;
3042cfb9a30eSShivasharan S int bytes_wrote = 0;
3043cfb9a30eSShivasharan S char *loc = (char *)buf;
3044cfb9a30eSShivasharan S u32 __iomem *reg = (u32 __iomem *)reg_set;
3045cfb9a30eSShivasharan S
3046cfb9a30eSShivasharan S for (i = 0; i < sz / sizeof(u32); i++) {
3047ff33d0e2STakashi Iwai bytes_wrote += scnprintf(loc + bytes_wrote,
3048ff33d0e2STakashi Iwai PAGE_SIZE - bytes_wrote,
3049cfb9a30eSShivasharan S "%08x: %08x\n", (i * 4),
3050cfb9a30eSShivasharan S readl(®[i]));
3051cfb9a30eSShivasharan S }
3052cfb9a30eSShivasharan S return bytes_wrote;
30530d49016bSadam radford }
30540d49016bSadam radford
30550d49016bSadam radford /**
30560d49016bSadam radford * megasas_reset_bus_host - Bus & host reset handler entry point
30572b46e5c1SDamien Le Moal * @scmd: Mid-layer SCSI command
30580d49016bSadam radford */
megasas_reset_bus_host(struct scsi_cmnd * scmd)30590d49016bSadam radford static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
30600d49016bSadam radford {
30610d49016bSadam radford int ret;
30629c915a8cSadam radford struct megasas_instance *instance;
3063da0dc9fbSBjorn Helgaas
30649c915a8cSadam radford instance = (struct megasas_instance *)scmd->device->host->hostdata;
30650d49016bSadam radford
3066def0eab3SShivasharan S scmd_printk(KERN_INFO, scmd,
306796c9603cSShivasharan S "OCR is requested due to IO timeout!!\n");
306896c9603cSShivasharan S
306996c9603cSShivasharan S scmd_printk(KERN_INFO, scmd,
307096c9603cSShivasharan S "SCSI host state: %d SCSI host busy: %d FW outstanding: %d\n",
307196c9603cSShivasharan S scmd->device->host->shost_state,
3072c84b023aSMing Lei scsi_host_busy(scmd->device->host),
3073def0eab3SShivasharan S atomic_read(&instance->fw_outstanding));
30740d49016bSadam radford /*
30750d49016bSadam radford * First wait for all commands to complete
30760d49016bSadam radford */
3077e7d36b88SShivasharan S if (instance->adapter_type == MFI_SERIES) {
3078e7d36b88SShivasharan S ret = megasas_generic_reset(scmd);
3079e7d36b88SShivasharan S } else {
308096c9603cSShivasharan S megasas_dump_fusion_io(scmd);
3081def0eab3SShivasharan S ret = megasas_reset_fusion(scmd->device->host,
3082def0eab3SShivasharan S SCSIIO_TIMEOUT_OCR);
3083e7d36b88SShivasharan S }
30840d49016bSadam radford
30850d49016bSadam radford return ret;
30860d49016bSadam radford }
30870d49016bSadam radford
30880d49016bSadam radford /**
3089bd23d4abSSumit Saxena * megasas_task_abort - Issues task abort request to firmware
3090bd23d4abSSumit Saxena * (supported only for fusion adapters)
3091bd23d4abSSumit Saxena * @scmd: SCSI command pointer
3092bd23d4abSSumit Saxena */
megasas_task_abort(struct scsi_cmnd * scmd)3093bd23d4abSSumit Saxena static int megasas_task_abort(struct scsi_cmnd *scmd)
3094bd23d4abSSumit Saxena {
3095bd23d4abSSumit Saxena int ret;
3096bd23d4abSSumit Saxena struct megasas_instance *instance;
3097bd23d4abSSumit Saxena
3098bd23d4abSSumit Saxena instance = (struct megasas_instance *)scmd->device->host->hostdata;
3099bd23d4abSSumit Saxena
3100e7d36b88SShivasharan S if (instance->adapter_type != MFI_SERIES)
3101bd23d4abSSumit Saxena ret = megasas_task_abort_fusion(scmd);
3102bd23d4abSSumit Saxena else {
3103bd23d4abSSumit Saxena sdev_printk(KERN_NOTICE, scmd->device, "TASK ABORT not supported\n");
3104bd23d4abSSumit Saxena ret = FAILED;
3105bd23d4abSSumit Saxena }
3106bd23d4abSSumit Saxena
3107bd23d4abSSumit Saxena return ret;
3108bd23d4abSSumit Saxena }
3109bd23d4abSSumit Saxena
3110bd23d4abSSumit Saxena /**
3111bd23d4abSSumit Saxena * megasas_reset_target: Issues target reset request to firmware
3112bd23d4abSSumit Saxena * (supported only for fusion adapters)
3113bd23d4abSSumit Saxena * @scmd: SCSI command pointer
3114bd23d4abSSumit Saxena */
megasas_reset_target(struct scsi_cmnd * scmd)3115bd23d4abSSumit Saxena static int megasas_reset_target(struct scsi_cmnd *scmd)
3116bd23d4abSSumit Saxena {
3117bd23d4abSSumit Saxena int ret;
3118bd23d4abSSumit Saxena struct megasas_instance *instance;
3119bd23d4abSSumit Saxena
3120bd23d4abSSumit Saxena instance = (struct megasas_instance *)scmd->device->host->hostdata;
3121bd23d4abSSumit Saxena
3122e7d36b88SShivasharan S if (instance->adapter_type != MFI_SERIES)
3123bd23d4abSSumit Saxena ret = megasas_reset_target_fusion(scmd);
3124bd23d4abSSumit Saxena else {
3125bd23d4abSSumit Saxena sdev_printk(KERN_NOTICE, scmd->device, "TARGET RESET not supported\n");
3126bd23d4abSSumit Saxena ret = FAILED;
3127bd23d4abSSumit Saxena }
3128bd23d4abSSumit Saxena
3129bd23d4abSSumit Saxena return ret;
3130bd23d4abSSumit Saxena }
3131bd23d4abSSumit Saxena
3132bd23d4abSSumit Saxena /**
31330d49016bSadam radford * megasas_bios_param - Returns disk geometry for a disk
31340d49016bSadam radford * @sdev: device handle
31350d49016bSadam radford * @bdev: block device
31360d49016bSadam radford * @capacity: drive capacity
31370d49016bSadam radford * @geom: geometry parameters
31380d49016bSadam radford */
31390d49016bSadam radford static int
megasas_bios_param(struct scsi_device * sdev,struct block_device * bdev,sector_t capacity,int geom[])31400d49016bSadam radford megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
31410d49016bSadam radford sector_t capacity, int geom[])
31420d49016bSadam radford {
31430d49016bSadam radford int heads;
31440d49016bSadam radford int sectors;
31450d49016bSadam radford sector_t cylinders;
31460d49016bSadam radford unsigned long tmp;
3147da0dc9fbSBjorn Helgaas
31480d49016bSadam radford /* Default heads (64) & sectors (32) */
31490d49016bSadam radford heads = 64;
31500d49016bSadam radford sectors = 32;
31510d49016bSadam radford
31520d49016bSadam radford tmp = heads * sectors;
31530d49016bSadam radford cylinders = capacity;
31540d49016bSadam radford
31550d49016bSadam radford sector_div(cylinders, tmp);
31560d49016bSadam radford
31570d49016bSadam radford /*
31580d49016bSadam radford * Handle extended translation size for logical drives > 1Gb
31590d49016bSadam radford */
31600d49016bSadam radford
31610d49016bSadam radford if (capacity >= 0x200000) {
31620d49016bSadam radford heads = 255;
31630d49016bSadam radford sectors = 63;
31640d49016bSadam radford tmp = heads*sectors;
31650d49016bSadam radford cylinders = capacity;
31660d49016bSadam radford sector_div(cylinders, tmp);
31670d49016bSadam radford }
31680d49016bSadam radford
31690d49016bSadam radford geom[0] = heads;
31700d49016bSadam radford geom[1] = sectors;
31710d49016bSadam radford geom[2] = cylinders;
31720d49016bSadam radford
31730d49016bSadam radford return 0;
31740d49016bSadam radford }
31750d49016bSadam radford
megasas_map_queues(struct Scsi_Host * shost)3176a4e1d0b7SBart Van Assche static void megasas_map_queues(struct Scsi_Host *shost)
317781e7eb5bSMartin K. Petersen {
317881e7eb5bSMartin K. Petersen struct megasas_instance *instance;
31799e4bec5bSKashyap Desai int qoff = 0, offset;
31809e4bec5bSKashyap Desai struct blk_mq_queue_map *map;
318181e7eb5bSMartin K. Petersen
318281e7eb5bSMartin K. Petersen instance = (struct megasas_instance *)shost->hostdata;
318381e7eb5bSMartin K. Petersen
318481e7eb5bSMartin K. Petersen if (shost->nr_hw_queues == 1)
3185a4e1d0b7SBart Van Assche return;
318681e7eb5bSMartin K. Petersen
31879e4bec5bSKashyap Desai offset = instance->low_latency_index_start;
31889e4bec5bSKashyap Desai
31899e4bec5bSKashyap Desai /* Setup Default hctx */
31909e4bec5bSKashyap Desai map = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
31919e4bec5bSKashyap Desai map->nr_queues = instance->msix_vectors - offset;
31929e4bec5bSKashyap Desai map->queue_offset = 0;
31939e4bec5bSKashyap Desai blk_mq_pci_map_queues(map, instance->pdev, offset);
31949e4bec5bSKashyap Desai qoff += map->nr_queues;
31959e4bec5bSKashyap Desai offset += map->nr_queues;
31969e4bec5bSKashyap Desai
31978312cd3aSMing Lei /* we never use READ queue, so can't cheat blk-mq */
31988312cd3aSMing Lei shost->tag_set.map[HCTX_TYPE_READ].nr_queues = 0;
31998312cd3aSMing Lei
32009e4bec5bSKashyap Desai /* Setup Poll hctx */
32019e4bec5bSKashyap Desai map = &shost->tag_set.map[HCTX_TYPE_POLL];
32029e4bec5bSKashyap Desai map->nr_queues = instance->iopoll_q_count;
32039e4bec5bSKashyap Desai if (map->nr_queues) {
32049e4bec5bSKashyap Desai /*
32059e4bec5bSKashyap Desai * The poll queue(s) doesn't have an IRQ (and hence IRQ
32069e4bec5bSKashyap Desai * affinity), so use the regular blk-mq cpu mapping
32079e4bec5bSKashyap Desai */
32089e4bec5bSKashyap Desai map->queue_offset = qoff;
32099e4bec5bSKashyap Desai blk_mq_map_queues(map);
32109e4bec5bSKashyap Desai }
321181e7eb5bSMartin K. Petersen }
321281e7eb5bSMartin K. Petersen
32130d49016bSadam radford static void megasas_aen_polling(struct work_struct *work);
32140d49016bSadam radford
32150d49016bSadam radford /**
32160d49016bSadam radford * megasas_service_aen - Processes an event notification
32170d49016bSadam radford * @instance: Adapter soft state
32180d49016bSadam radford * @cmd: AEN command completed by the ISR
32190d49016bSadam radford *
32200d49016bSadam radford * For AEN, driver sends a command down to FW that is held by the FW till an
32210d49016bSadam radford * event occurs. When an event of interest occurs, FW completes the command
32220d49016bSadam radford * that it was previously holding.
32230d49016bSadam radford *
32240d49016bSadam radford * This routines sends SIGIO signal to processes that have registered with the
32250d49016bSadam radford * driver for AEN.
32260d49016bSadam radford */
32270d49016bSadam radford static void
megasas_service_aen(struct megasas_instance * instance,struct megasas_cmd * cmd)32280d49016bSadam radford megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
32290d49016bSadam radford {
32300d49016bSadam radford unsigned long flags;
3231da0dc9fbSBjorn Helgaas
32320d49016bSadam radford /*
32330d49016bSadam radford * Don't signal app if it is just an aborted previously registered aen
32340d49016bSadam radford */
32350d49016bSadam radford if ((!cmd->abort_aen) && (instance->unload == 0)) {
32360d49016bSadam radford spin_lock_irqsave(&poll_aen_lock, flags);
32370d49016bSadam radford megasas_poll_wait_aen = 1;
32380d49016bSadam radford spin_unlock_irqrestore(&poll_aen_lock, flags);
32390d49016bSadam radford wake_up(&megasas_poll_wait);
32400d49016bSadam radford kill_fasync(&megasas_async_queue, SIGIO, POLL_IN);
32410d49016bSadam radford }
32420d49016bSadam radford else
32430d49016bSadam radford cmd->abort_aen = 0;
32440d49016bSadam radford
32450d49016bSadam radford instance->aen_cmd = NULL;
324690dc9d98SSumit.Saxena@avagotech.com
32470d49016bSadam radford megasas_return_cmd(instance, cmd);
32480d49016bSadam radford
32490d49016bSadam radford if ((instance->unload == 0) &&
32500d49016bSadam radford ((instance->issuepend_done == 1))) {
32510d49016bSadam radford struct megasas_aen_event *ev;
3252da0dc9fbSBjorn Helgaas
32530d49016bSadam radford ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
32540d49016bSadam radford if (!ev) {
32551be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "megasas_service_aen: out of memory\n");
32560d49016bSadam radford } else {
32570d49016bSadam radford ev->instance = instance;
32580d49016bSadam radford instance->ev = ev;
3259c1d390d8SXiaotian Feng INIT_DELAYED_WORK(&ev->hotplug_work,
3260c1d390d8SXiaotian Feng megasas_aen_polling);
3261c1d390d8SXiaotian Feng schedule_delayed_work(&ev->hotplug_work, 0);
32620d49016bSadam radford }
32630d49016bSadam radford }
32640d49016bSadam radford }
32650d49016bSadam radford
3266fc62b3fcSSumit.Saxena@avagotech.com static ssize_t
fw_crash_buffer_store(struct device * cdev,struct device_attribute * attr,const char * buf,size_t count)3267d6354683STomas Henzl fw_crash_buffer_store(struct device *cdev,
3268fc62b3fcSSumit.Saxena@avagotech.com struct device_attribute *attr, const char *buf, size_t count)
3269fc62b3fcSSumit.Saxena@avagotech.com {
3270fc62b3fcSSumit.Saxena@avagotech.com struct Scsi_Host *shost = class_to_shost(cdev);
3271fc62b3fcSSumit.Saxena@avagotech.com struct megasas_instance *instance =
3272fc62b3fcSSumit.Saxena@avagotech.com (struct megasas_instance *) shost->hostdata;
3273fc62b3fcSSumit.Saxena@avagotech.com int val = 0;
3274fc62b3fcSSumit.Saxena@avagotech.com
3275fc62b3fcSSumit.Saxena@avagotech.com if (kstrtoint(buf, 0, &val) != 0)
3276fc62b3fcSSumit.Saxena@avagotech.com return -EINVAL;
3277fc62b3fcSSumit.Saxena@avagotech.com
32780b0747d5SJunxiao Bi mutex_lock(&instance->crashdump_lock);
3279fc62b3fcSSumit.Saxena@avagotech.com instance->fw_crash_buffer_offset = val;
32800b0747d5SJunxiao Bi mutex_unlock(&instance->crashdump_lock);
3281fc62b3fcSSumit.Saxena@avagotech.com return strlen(buf);
3282fc62b3fcSSumit.Saxena@avagotech.com }
3283fc62b3fcSSumit.Saxena@avagotech.com
3284fc62b3fcSSumit.Saxena@avagotech.com static ssize_t
fw_crash_buffer_show(struct device * cdev,struct device_attribute * attr,char * buf)3285d6354683STomas Henzl fw_crash_buffer_show(struct device *cdev,
3286fc62b3fcSSumit.Saxena@avagotech.com struct device_attribute *attr, char *buf)
3287fc62b3fcSSumit.Saxena@avagotech.com {
3288fc62b3fcSSumit.Saxena@avagotech.com struct Scsi_Host *shost = class_to_shost(cdev);
3289fc62b3fcSSumit.Saxena@avagotech.com struct megasas_instance *instance =
3290fc62b3fcSSumit.Saxena@avagotech.com (struct megasas_instance *) shost->hostdata;
3291fc62b3fcSSumit.Saxena@avagotech.com u32 size;
3292fc62b3fcSSumit.Saxena@avagotech.com unsigned long dmachunk = CRASH_DMA_BUF_SIZE;
32933b5f307eSJunxiao Bi unsigned long chunk_left_bytes;
3294fc62b3fcSSumit.Saxena@avagotech.com unsigned long src_addr;
3295fc62b3fcSSumit.Saxena@avagotech.com u32 buff_offset;
3296fc62b3fcSSumit.Saxena@avagotech.com
32970b0747d5SJunxiao Bi mutex_lock(&instance->crashdump_lock);
3298fc62b3fcSSumit.Saxena@avagotech.com buff_offset = instance->fw_crash_buffer_offset;
32990808ed6eSTomas Henzl if (!instance->crash_dump_buf ||
3300fc62b3fcSSumit.Saxena@avagotech.com !((instance->fw_crash_state == AVAILABLE) ||
3301fc62b3fcSSumit.Saxena@avagotech.com (instance->fw_crash_state == COPYING))) {
3302fc62b3fcSSumit.Saxena@avagotech.com dev_err(&instance->pdev->dev,
3303fc62b3fcSSumit.Saxena@avagotech.com "Firmware crash dump is not available\n");
33040b0747d5SJunxiao Bi mutex_unlock(&instance->crashdump_lock);
3305fc62b3fcSSumit.Saxena@avagotech.com return -EINVAL;
3306fc62b3fcSSumit.Saxena@avagotech.com }
3307fc62b3fcSSumit.Saxena@avagotech.com
3308da0dc9fbSBjorn Helgaas if (buff_offset > (instance->fw_crash_buffer_size * dmachunk)) {
3309fc62b3fcSSumit.Saxena@avagotech.com dev_err(&instance->pdev->dev,
3310fc62b3fcSSumit.Saxena@avagotech.com "Firmware crash dump offset is out of range\n");
33110b0747d5SJunxiao Bi mutex_unlock(&instance->crashdump_lock);
3312fc62b3fcSSumit.Saxena@avagotech.com return 0;
3313fc62b3fcSSumit.Saxena@avagotech.com }
3314fc62b3fcSSumit.Saxena@avagotech.com
3315fc62b3fcSSumit.Saxena@avagotech.com size = (instance->fw_crash_buffer_size * dmachunk) - buff_offset;
33163b5f307eSJunxiao Bi chunk_left_bytes = dmachunk - (buff_offset % dmachunk);
33173b5f307eSJunxiao Bi size = (size > chunk_left_bytes) ? chunk_left_bytes : size;
3318fc62b3fcSSumit.Saxena@avagotech.com size = (size >= PAGE_SIZE) ? (PAGE_SIZE - 1) : size;
3319fc62b3fcSSumit.Saxena@avagotech.com
3320fc62b3fcSSumit.Saxena@avagotech.com src_addr = (unsigned long)instance->crash_buf[buff_offset / dmachunk] +
3321fc62b3fcSSumit.Saxena@avagotech.com (buff_offset % dmachunk);
3322fc62b3fcSSumit.Saxena@avagotech.com memcpy(buf, (void *)src_addr, size);
33230b0747d5SJunxiao Bi mutex_unlock(&instance->crashdump_lock);
3324fc62b3fcSSumit.Saxena@avagotech.com
3325fc62b3fcSSumit.Saxena@avagotech.com return size;
3326fc62b3fcSSumit.Saxena@avagotech.com }
3327fc62b3fcSSumit.Saxena@avagotech.com
3328fc62b3fcSSumit.Saxena@avagotech.com static ssize_t
fw_crash_buffer_size_show(struct device * cdev,struct device_attribute * attr,char * buf)3329d6354683STomas Henzl fw_crash_buffer_size_show(struct device *cdev,
3330fc62b3fcSSumit.Saxena@avagotech.com struct device_attribute *attr, char *buf)
3331fc62b3fcSSumit.Saxena@avagotech.com {
3332fc62b3fcSSumit.Saxena@avagotech.com struct Scsi_Host *shost = class_to_shost(cdev);
3333fc62b3fcSSumit.Saxena@avagotech.com struct megasas_instance *instance =
3334fc62b3fcSSumit.Saxena@avagotech.com (struct megasas_instance *) shost->hostdata;
3335fc62b3fcSSumit.Saxena@avagotech.com
3336fc62b3fcSSumit.Saxena@avagotech.com return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)
3337fc62b3fcSSumit.Saxena@avagotech.com ((instance->fw_crash_buffer_size) * 1024 * 1024)/PAGE_SIZE);
3338fc62b3fcSSumit.Saxena@avagotech.com }
3339fc62b3fcSSumit.Saxena@avagotech.com
3340fc62b3fcSSumit.Saxena@avagotech.com static ssize_t
fw_crash_state_store(struct device * cdev,struct device_attribute * attr,const char * buf,size_t count)3341d6354683STomas Henzl fw_crash_state_store(struct device *cdev,
3342fc62b3fcSSumit.Saxena@avagotech.com struct device_attribute *attr, const char *buf, size_t count)
3343fc62b3fcSSumit.Saxena@avagotech.com {
3344fc62b3fcSSumit.Saxena@avagotech.com struct Scsi_Host *shost = class_to_shost(cdev);
3345fc62b3fcSSumit.Saxena@avagotech.com struct megasas_instance *instance =
3346fc62b3fcSSumit.Saxena@avagotech.com (struct megasas_instance *) shost->hostdata;
3347fc62b3fcSSumit.Saxena@avagotech.com int val = 0;
3348fc62b3fcSSumit.Saxena@avagotech.com
3349fc62b3fcSSumit.Saxena@avagotech.com if (kstrtoint(buf, 0, &val) != 0)
3350fc62b3fcSSumit.Saxena@avagotech.com return -EINVAL;
3351fc62b3fcSSumit.Saxena@avagotech.com
3352fc62b3fcSSumit.Saxena@avagotech.com if ((val <= AVAILABLE || val > COPY_ERROR)) {
3353fc62b3fcSSumit.Saxena@avagotech.com dev_err(&instance->pdev->dev, "application updates invalid "
3354fc62b3fcSSumit.Saxena@avagotech.com "firmware crash state\n");
3355fc62b3fcSSumit.Saxena@avagotech.com return -EINVAL;
3356fc62b3fcSSumit.Saxena@avagotech.com }
3357fc62b3fcSSumit.Saxena@avagotech.com
3358fc62b3fcSSumit.Saxena@avagotech.com instance->fw_crash_state = val;
3359fc62b3fcSSumit.Saxena@avagotech.com
3360fc62b3fcSSumit.Saxena@avagotech.com if ((val == COPIED) || (val == COPY_ERROR)) {
33610b0747d5SJunxiao Bi mutex_lock(&instance->crashdump_lock);
3362fc62b3fcSSumit.Saxena@avagotech.com megasas_free_host_crash_buffer(instance);
33630b0747d5SJunxiao Bi mutex_unlock(&instance->crashdump_lock);
3364fc62b3fcSSumit.Saxena@avagotech.com if (val == COPY_ERROR)
3365fc62b3fcSSumit.Saxena@avagotech.com dev_info(&instance->pdev->dev, "application failed to "
3366fc62b3fcSSumit.Saxena@avagotech.com "copy Firmware crash dump\n");
3367fc62b3fcSSumit.Saxena@avagotech.com else
3368fc62b3fcSSumit.Saxena@avagotech.com dev_info(&instance->pdev->dev, "Firmware crash dump "
3369fc62b3fcSSumit.Saxena@avagotech.com "copied successfully\n");
3370fc62b3fcSSumit.Saxena@avagotech.com }
3371fc62b3fcSSumit.Saxena@avagotech.com return strlen(buf);
3372fc62b3fcSSumit.Saxena@avagotech.com }
3373fc62b3fcSSumit.Saxena@avagotech.com
3374fc62b3fcSSumit.Saxena@avagotech.com static ssize_t
fw_crash_state_show(struct device * cdev,struct device_attribute * attr,char * buf)3375d6354683STomas Henzl fw_crash_state_show(struct device *cdev,
3376fc62b3fcSSumit.Saxena@avagotech.com struct device_attribute *attr, char *buf)
3377fc62b3fcSSumit.Saxena@avagotech.com {
3378fc62b3fcSSumit.Saxena@avagotech.com struct Scsi_Host *shost = class_to_shost(cdev);
3379fc62b3fcSSumit.Saxena@avagotech.com struct megasas_instance *instance =
3380fc62b3fcSSumit.Saxena@avagotech.com (struct megasas_instance *) shost->hostdata;
3381da0dc9fbSBjorn Helgaas
3382fc62b3fcSSumit.Saxena@avagotech.com return snprintf(buf, PAGE_SIZE, "%d\n", instance->fw_crash_state);
3383fc62b3fcSSumit.Saxena@avagotech.com }
3384fc62b3fcSSumit.Saxena@avagotech.com
3385fc62b3fcSSumit.Saxena@avagotech.com static ssize_t
page_size_show(struct device * cdev,struct device_attribute * attr,char * buf)3386d6354683STomas Henzl page_size_show(struct device *cdev,
3387fc62b3fcSSumit.Saxena@avagotech.com struct device_attribute *attr, char *buf)
3388fc62b3fcSSumit.Saxena@avagotech.com {
3389fc62b3fcSSumit.Saxena@avagotech.com return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1);
3390fc62b3fcSSumit.Saxena@avagotech.com }
3391fc62b3fcSSumit.Saxena@avagotech.com
3392308ec459SSumit Saxena static ssize_t
ldio_outstanding_show(struct device * cdev,struct device_attribute * attr,char * buf)3393d6354683STomas Henzl ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
3394308ec459SSumit Saxena char *buf)
3395308ec459SSumit Saxena {
3396308ec459SSumit Saxena struct Scsi_Host *shost = class_to_shost(cdev);
3397308ec459SSumit Saxena struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
3398308ec459SSumit Saxena
3399308ec459SSumit Saxena return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->ldio_outstanding));
3400308ec459SSumit Saxena }
3401308ec459SSumit Saxena
340288d155c6SShivasharan S static ssize_t
fw_cmds_outstanding_show(struct device * cdev,struct device_attribute * attr,char * buf)3403d6354683STomas Henzl fw_cmds_outstanding_show(struct device *cdev,
340488d155c6SShivasharan S struct device_attribute *attr, char *buf)
340588d155c6SShivasharan S {
340688d155c6SShivasharan S struct Scsi_Host *shost = class_to_shost(cdev);
340788d155c6SShivasharan S struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
340888d155c6SShivasharan S
340988d155c6SShivasharan S return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->fw_outstanding));
341088d155c6SShivasharan S }
341188d155c6SShivasharan S
3412cfb9a30eSShivasharan S static ssize_t
enable_sdev_max_qd_show(struct device * cdev,struct device_attribute * attr,char * buf)34139ab089d3SChandrakanth Patil enable_sdev_max_qd_show(struct device *cdev,
34149ab089d3SChandrakanth Patil struct device_attribute *attr, char *buf)
34159ab089d3SChandrakanth Patil {
34169ab089d3SChandrakanth Patil struct Scsi_Host *shost = class_to_shost(cdev);
34179ab089d3SChandrakanth Patil struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
34189ab089d3SChandrakanth Patil
34199ab089d3SChandrakanth Patil return snprintf(buf, PAGE_SIZE, "%d\n", instance->enable_sdev_max_qd);
34209ab089d3SChandrakanth Patil }
34219ab089d3SChandrakanth Patil
34229ab089d3SChandrakanth Patil static ssize_t
enable_sdev_max_qd_store(struct device * cdev,struct device_attribute * attr,const char * buf,size_t count)34239ab089d3SChandrakanth Patil enable_sdev_max_qd_store(struct device *cdev,
34249ab089d3SChandrakanth Patil struct device_attribute *attr, const char *buf, size_t count)
34259ab089d3SChandrakanth Patil {
34269ab089d3SChandrakanth Patil struct Scsi_Host *shost = class_to_shost(cdev);
34279ab089d3SChandrakanth Patil struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
34289ab089d3SChandrakanth Patil u32 val = 0;
34299ab089d3SChandrakanth Patil bool is_target_prop;
34309ab089d3SChandrakanth Patil int ret_target_prop = DCMD_FAILED;
34319ab089d3SChandrakanth Patil struct scsi_device *sdev;
34329ab089d3SChandrakanth Patil
34339ab089d3SChandrakanth Patil if (kstrtou32(buf, 0, &val) != 0) {
34349ab089d3SChandrakanth Patil pr_err("megasas: could not set enable_sdev_max_qd\n");
34359ab089d3SChandrakanth Patil return -EINVAL;
34369ab089d3SChandrakanth Patil }
34379ab089d3SChandrakanth Patil
34389ab089d3SChandrakanth Patil mutex_lock(&instance->reset_mutex);
34399ab089d3SChandrakanth Patil if (val)
34409ab089d3SChandrakanth Patil instance->enable_sdev_max_qd = true;
34419ab089d3SChandrakanth Patil else
34429ab089d3SChandrakanth Patil instance->enable_sdev_max_qd = false;
34439ab089d3SChandrakanth Patil
34449ab089d3SChandrakanth Patil shost_for_each_device(sdev, shost) {
34459ab089d3SChandrakanth Patil ret_target_prop = megasas_get_target_prop(instance, sdev);
34469ab089d3SChandrakanth Patil is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false;
34479ab089d3SChandrakanth Patil megasas_set_fw_assisted_qd(sdev, is_target_prop);
34489ab089d3SChandrakanth Patil }
34499ab089d3SChandrakanth Patil mutex_unlock(&instance->reset_mutex);
34509ab089d3SChandrakanth Patil
34519ab089d3SChandrakanth Patil return strlen(buf);
34529ab089d3SChandrakanth Patil }
34539ab089d3SChandrakanth Patil
34549ab089d3SChandrakanth Patil static ssize_t
dump_system_regs_show(struct device * cdev,struct device_attribute * attr,char * buf)3455d6354683STomas Henzl dump_system_regs_show(struct device *cdev,
3456cfb9a30eSShivasharan S struct device_attribute *attr, char *buf)
3457cfb9a30eSShivasharan S {
3458cfb9a30eSShivasharan S struct Scsi_Host *shost = class_to_shost(cdev);
3459cfb9a30eSShivasharan S struct megasas_instance *instance =
3460cfb9a30eSShivasharan S (struct megasas_instance *)shost->hostdata;
3461cfb9a30eSShivasharan S
3462cfb9a30eSShivasharan S return megasas_dump_sys_regs(instance->reg_set, buf);
3463cfb9a30eSShivasharan S }
3464cfb9a30eSShivasharan S
3465a6024a9eSShivasharan S static ssize_t
raid_map_id_show(struct device * cdev,struct device_attribute * attr,char * buf)3466d6354683STomas Henzl raid_map_id_show(struct device *cdev, struct device_attribute *attr,
3467a6024a9eSShivasharan S char *buf)
3468a6024a9eSShivasharan S {
3469a6024a9eSShivasharan S struct Scsi_Host *shost = class_to_shost(cdev);
3470a6024a9eSShivasharan S struct megasas_instance *instance =
3471a6024a9eSShivasharan S (struct megasas_instance *)shost->hostdata;
3472a6024a9eSShivasharan S
3473a6024a9eSShivasharan S return snprintf(buf, PAGE_SIZE, "%ld\n",
3474a6024a9eSShivasharan S (unsigned long)instance->map_id);
3475a6024a9eSShivasharan S }
3476a6024a9eSShivasharan S
3477d6354683STomas Henzl static DEVICE_ATTR_RW(fw_crash_buffer);
3478d6354683STomas Henzl static DEVICE_ATTR_RO(fw_crash_buffer_size);
3479d6354683STomas Henzl static DEVICE_ATTR_RW(fw_crash_state);
3480d6354683STomas Henzl static DEVICE_ATTR_RO(page_size);
3481d6354683STomas Henzl static DEVICE_ATTR_RO(ldio_outstanding);
3482d6354683STomas Henzl static DEVICE_ATTR_RO(fw_cmds_outstanding);
34839ab089d3SChandrakanth Patil static DEVICE_ATTR_RW(enable_sdev_max_qd);
3484d6354683STomas Henzl static DEVICE_ATTR_RO(dump_system_regs);
3485d6354683STomas Henzl static DEVICE_ATTR_RO(raid_map_id);
3486fc62b3fcSSumit.Saxena@avagotech.com
348709723bb2SBart Van Assche static struct attribute *megaraid_host_attrs[] = {
348809723bb2SBart Van Assche &dev_attr_fw_crash_buffer_size.attr,
348909723bb2SBart Van Assche &dev_attr_fw_crash_buffer.attr,
349009723bb2SBart Van Assche &dev_attr_fw_crash_state.attr,
349109723bb2SBart Van Assche &dev_attr_page_size.attr,
349209723bb2SBart Van Assche &dev_attr_ldio_outstanding.attr,
349309723bb2SBart Van Assche &dev_attr_fw_cmds_outstanding.attr,
349409723bb2SBart Van Assche &dev_attr_enable_sdev_max_qd.attr,
349509723bb2SBart Van Assche &dev_attr_dump_system_regs.attr,
349609723bb2SBart Van Assche &dev_attr_raid_map_id.attr,
3497fc62b3fcSSumit.Saxena@avagotech.com NULL,
3498fc62b3fcSSumit.Saxena@avagotech.com };
3499fc62b3fcSSumit.Saxena@avagotech.com
350009723bb2SBart Van Assche ATTRIBUTE_GROUPS(megaraid_host);
350109723bb2SBart Van Assche
35020d49016bSadam radford /*
35030d49016bSadam radford * Scsi host template for megaraid_sas driver
35040d49016bSadam radford */
3505264e222bSBart Van Assche static const struct scsi_host_template megasas_template = {
35060d49016bSadam radford
35070d49016bSadam radford .module = THIS_MODULE,
350843cd7fe4SSumit.Saxena@avagotech.com .name = "Avago SAS based MegaRAID driver",
35090d49016bSadam radford .proc_name = "megaraid_sas",
35100d49016bSadam radford .slave_configure = megasas_slave_configure,
35110d49016bSadam radford .slave_alloc = megasas_slave_alloc,
351218365b13SSumit Saxena .slave_destroy = megasas_slave_destroy,
35130d49016bSadam radford .queuecommand = megasas_queue_command,
3514bd23d4abSSumit Saxena .eh_target_reset_handler = megasas_reset_target,
3515bd23d4abSSumit Saxena .eh_abort_handler = megasas_task_abort,
35160d49016bSadam radford .eh_host_reset_handler = megasas_reset_bus_host,
35170d49016bSadam radford .eh_timed_out = megasas_reset_timer,
351809723bb2SBart Van Assche .shost_groups = megaraid_host_groups,
35190d49016bSadam radford .bios_param = megasas_bios_param,
352081e7eb5bSMartin K. Petersen .map_queues = megasas_map_queues,
35219e4bec5bSKashyap Desai .mq_poll = megasas_blk_mq_poll,
3522db5ed4dfSChristoph Hellwig .change_queue_depth = scsi_change_queue_depth,
352307d9aa14SChristoph Hellwig .max_segment_size = 0xffffffff,
352496e77a27SBart Van Assche .cmd_size = sizeof(struct megasas_cmd_priv),
35250d49016bSadam radford };
35260d49016bSadam radford
35270d49016bSadam radford /**
35280d49016bSadam radford * megasas_complete_int_cmd - Completes an internal command
35290d49016bSadam radford * @instance: Adapter soft state
35300d49016bSadam radford * @cmd: Command to be completed
35310d49016bSadam radford *
35320d49016bSadam radford * The megasas_issue_blocked_cmd() function waits for a command to complete
35330d49016bSadam radford * after it issues a command. This function wakes up that waiting routine by
35340d49016bSadam radford * calling wake_up() on the wait queue.
35350d49016bSadam radford */
35360d49016bSadam radford static void
megasas_complete_int_cmd(struct megasas_instance * instance,struct megasas_cmd * cmd)35370d49016bSadam radford megasas_complete_int_cmd(struct megasas_instance *instance,
35380d49016bSadam radford struct megasas_cmd *cmd)
35390d49016bSadam radford {
3540201a810cSAnand Lodnoor if (cmd->cmd_status_drv == DCMD_INIT)
3541201a810cSAnand Lodnoor cmd->cmd_status_drv =
3542201a810cSAnand Lodnoor (cmd->frame->io.cmd_status == MFI_STAT_OK) ?
3543201a810cSAnand Lodnoor DCMD_SUCCESS : DCMD_FAILED;
3544201a810cSAnand Lodnoor
35450d49016bSadam radford wake_up(&instance->int_cmd_wait_q);
35460d49016bSadam radford }
35470d49016bSadam radford
35480d49016bSadam radford /**
35490d49016bSadam radford * megasas_complete_abort - Completes aborting a command
35500d49016bSadam radford * @instance: Adapter soft state
35510d49016bSadam radford * @cmd: Cmd that was issued to abort another cmd
35520d49016bSadam radford *
35530d49016bSadam radford * The megasas_issue_blocked_abort_cmd() function waits on abort_cmd_wait_q
35540d49016bSadam radford * after it issues an abort on a previously issued command. This function
35550d49016bSadam radford * wakes up all functions waiting on the same wait queue.
35560d49016bSadam radford */
35570d49016bSadam radford static void
megasas_complete_abort(struct megasas_instance * instance,struct megasas_cmd * cmd)35580d49016bSadam radford megasas_complete_abort(struct megasas_instance *instance,
35590d49016bSadam radford struct megasas_cmd *cmd)
35600d49016bSadam radford {
35610d49016bSadam radford if (cmd->sync_cmd) {
35620d49016bSadam radford cmd->sync_cmd = 0;
3563201a810cSAnand Lodnoor cmd->cmd_status_drv = DCMD_SUCCESS;
35640d49016bSadam radford wake_up(&instance->abort_cmd_wait_q);
35650d49016bSadam radford }
35660d49016bSadam radford }
35670d49016bSadam radford
3568ae6874baSKashyap Desai static void
megasas_set_ld_removed_by_fw(struct megasas_instance * instance)3569ae6874baSKashyap Desai megasas_set_ld_removed_by_fw(struct megasas_instance *instance)
3570ae6874baSKashyap Desai {
3571ae6874baSKashyap Desai uint i;
3572ae6874baSKashyap Desai
3573ae6874baSKashyap Desai for (i = 0; (i < MEGASAS_MAX_LD_IDS); i++) {
3574ae6874baSKashyap Desai if (instance->ld_ids_prev[i] != 0xff &&
3575ae6874baSKashyap Desai instance->ld_ids_from_raidmap[i] == 0xff) {
3576ae6874baSKashyap Desai if (megasas_dbg_lvl & LD_PD_DEBUG)
3577ae6874baSKashyap Desai dev_info(&instance->pdev->dev,
3578ae6874baSKashyap Desai "LD target ID %d removed from RAID map\n", i);
3579ae6874baSKashyap Desai instance->ld_tgtid_status[i] = LD_TARGET_ID_DELETED;
3580ae6874baSKashyap Desai }
3581ae6874baSKashyap Desai }
3582ae6874baSKashyap Desai }
3583ae6874baSKashyap Desai
35840d49016bSadam radford /**
35850d49016bSadam radford * megasas_complete_cmd - Completes a command
35860d49016bSadam radford * @instance: Adapter soft state
35870d49016bSadam radford * @cmd: Command to be completed
35880d49016bSadam radford * @alt_status: If non-zero, use this value as status to
35890d49016bSadam radford * SCSI mid-layer instead of the value returned
35900d49016bSadam radford * by the FW. This should be used if caller wants
35910d49016bSadam radford * an alternate status (as in the case of aborted
35920d49016bSadam radford * commands)
35930d49016bSadam radford */
35949c915a8cSadam radford void
megasas_complete_cmd(struct megasas_instance * instance,struct megasas_cmd * cmd,u8 alt_status)35950d49016bSadam radford megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
35960d49016bSadam radford u8 alt_status)
35970d49016bSadam radford {
35980d49016bSadam radford int exception = 0;
35990d49016bSadam radford struct megasas_header *hdr = &cmd->frame->hdr;
36000d49016bSadam radford unsigned long flags;
36019c915a8cSadam radford struct fusion_context *fusion = instance->ctrl_context;
36023761cb4cSsumit.saxena@avagotech.com u32 opcode, status;
36030d49016bSadam radford
36040d49016bSadam radford /* flag for the retry reset */
36050d49016bSadam radford cmd->retry_for_fw_reset = 0;
36060d49016bSadam radford
36070d49016bSadam radford if (cmd->scmd)
360896e77a27SBart Van Assche megasas_priv(cmd->scmd)->cmd_priv = NULL;
36090d49016bSadam radford
36100d49016bSadam radford switch (hdr->cmd) {
3611e5f93a36Sadam radford case MFI_CMD_INVALID:
3612e5f93a36Sadam radford /* Some older 1068 controller FW may keep a pended
3613e5f93a36Sadam radford MR_DCMD_CTRL_EVENT_GET_INFO left over from the main kernel
3614e5f93a36Sadam radford when booting the kdump kernel. Ignore this command to
3615e5f93a36Sadam radford prevent a kernel panic on shutdown of the kdump kernel. */
36161be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "MFI_CMD_INVALID command "
36171be18254SBjorn Helgaas "completed\n");
36181be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "If you have a controller "
36191be18254SBjorn Helgaas "other than PERC5, please upgrade your firmware\n");
3620e5f93a36Sadam radford break;
36210d49016bSadam radford case MFI_CMD_PD_SCSI_IO:
36220d49016bSadam radford case MFI_CMD_LD_SCSI_IO:
36230d49016bSadam radford
36240d49016bSadam radford /*
36250d49016bSadam radford * MFI_CMD_PD_SCSI_IO and MFI_CMD_LD_SCSI_IO could have been
36260d49016bSadam radford * issued either through an IO path or an IOCTL path. If it
36270d49016bSadam radford * was via IOCTL, we will send it to internal completion.
36280d49016bSadam radford */
36290d49016bSadam radford if (cmd->sync_cmd) {
36300d49016bSadam radford cmd->sync_cmd = 0;
36310d49016bSadam radford megasas_complete_int_cmd(instance, cmd);
36320d49016bSadam radford break;
36330d49016bSadam radford }
3634df561f66SGustavo A. R. Silva fallthrough;
36350d49016bSadam radford
36360d49016bSadam radford case MFI_CMD_LD_READ:
36370d49016bSadam radford case MFI_CMD_LD_WRITE:
36380d49016bSadam radford
36390d49016bSadam radford if (alt_status) {
36400d49016bSadam radford cmd->scmd->result = alt_status << 16;
36410d49016bSadam radford exception = 1;
36420d49016bSadam radford }
36430d49016bSadam radford
36440d49016bSadam radford if (exception) {
36450d49016bSadam radford
36460d49016bSadam radford atomic_dec(&instance->fw_outstanding);
36470d49016bSadam radford
36480d49016bSadam radford scsi_dma_unmap(cmd->scmd);
3649012f14b2SBart Van Assche scsi_done(cmd->scmd);
36500d49016bSadam radford megasas_return_cmd(instance, cmd);
36510d49016bSadam radford
36520d49016bSadam radford break;
36530d49016bSadam radford }
36540d49016bSadam radford
36550d49016bSadam radford switch (hdr->cmd_status) {
36560d49016bSadam radford
36570d49016bSadam radford case MFI_STAT_OK:
36580d49016bSadam radford cmd->scmd->result = DID_OK << 16;
36590d49016bSadam radford break;
36600d49016bSadam radford
36610d49016bSadam radford case MFI_STAT_SCSI_IO_FAILED:
36620d49016bSadam radford case MFI_STAT_LD_INIT_IN_PROGRESS:
36630d49016bSadam radford cmd->scmd->result =
36640d49016bSadam radford (DID_ERROR << 16) | hdr->scsi_status;
36650d49016bSadam radford break;
36660d49016bSadam radford
36670d49016bSadam radford case MFI_STAT_SCSI_DONE_WITH_ERROR:
36680d49016bSadam radford
36690d49016bSadam radford cmd->scmd->result = (DID_OK << 16) | hdr->scsi_status;
36700d49016bSadam radford
36710d49016bSadam radford if (hdr->scsi_status == SAM_STAT_CHECK_CONDITION) {
36720d49016bSadam radford memset(cmd->scmd->sense_buffer, 0,
36730d49016bSadam radford SCSI_SENSE_BUFFERSIZE);
36740d49016bSadam radford memcpy(cmd->scmd->sense_buffer, cmd->sense,
36750d49016bSadam radford hdr->sense_len);
36760d49016bSadam radford }
36770d49016bSadam radford
36780d49016bSadam radford break;
36790d49016bSadam radford
36800d49016bSadam radford case MFI_STAT_LD_OFFLINE:
36810d49016bSadam radford case MFI_STAT_DEVICE_NOT_FOUND:
36820d49016bSadam radford cmd->scmd->result = DID_BAD_TARGET << 16;
36830d49016bSadam radford break;
36840d49016bSadam radford
36850d49016bSadam radford default:
36861be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "MFI FW status %#x\n",
36870d49016bSadam radford hdr->cmd_status);
36880d49016bSadam radford cmd->scmd->result = DID_ERROR << 16;
36890d49016bSadam radford break;
36900d49016bSadam radford }
36910d49016bSadam radford
36920d49016bSadam radford atomic_dec(&instance->fw_outstanding);
36930d49016bSadam radford
36940d49016bSadam radford scsi_dma_unmap(cmd->scmd);
3695012f14b2SBart Van Assche scsi_done(cmd->scmd);
36960d49016bSadam radford megasas_return_cmd(instance, cmd);
36970d49016bSadam radford
36980d49016bSadam radford break;
36990d49016bSadam radford
37000d49016bSadam radford case MFI_CMD_SMP:
37010d49016bSadam radford case MFI_CMD_STP:
3702f870bcbeSShivasharan S case MFI_CMD_NVME:
370358136856SChandrakanth Patil case MFI_CMD_TOOLBOX:
370482add4e1SShivasharan S megasas_complete_int_cmd(instance, cmd);
370582add4e1SShivasharan S break;
370682add4e1SShivasharan S
37070d49016bSadam radford case MFI_CMD_DCMD:
370894cd65ddSSumit.Saxena@lsi.com opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
37099c915a8cSadam radford /* Check for LD map update */
371094cd65ddSSumit.Saxena@lsi.com if ((opcode == MR_DCMD_LD_MAP_GET_INFO)
371194cd65ddSSumit.Saxena@lsi.com && (cmd->frame->dcmd.mbox.b[1] == 1)) {
3712bc93d425SSumit.Saxena@lsi.com fusion->fast_path_io = 0;
37139c915a8cSadam radford spin_lock_irqsave(instance->host->host_lock, flags);
37145f19f7c8SShivasharan S status = cmd->frame->hdr.cmd_status;
37153761cb4cSsumit.saxena@avagotech.com instance->map_update_cmd = NULL;
37165f19f7c8SShivasharan S if (status != MFI_STAT_OK) {
37175f19f7c8SShivasharan S if (status != MFI_STAT_NOT_FOUND)
37181be18254SBjorn Helgaas dev_warn(&instance->pdev->dev, "map syncfailed, status = 0x%x\n",
37199c915a8cSadam radford cmd->frame->hdr.cmd_status);
37209c915a8cSadam radford else {
37214026e9aaSSumit.Saxena@avagotech.com megasas_return_cmd(instance, cmd);
37229c915a8cSadam radford spin_unlock_irqrestore(
37239c915a8cSadam radford instance->host->host_lock,
37249c915a8cSadam radford flags);
37259c915a8cSadam radford break;
37269c915a8cSadam radford }
37275f19f7c8SShivasharan S }
37285f19f7c8SShivasharan S
37294026e9aaSSumit.Saxena@avagotech.com megasas_return_cmd(instance, cmd);
3730bc93d425SSumit.Saxena@lsi.com
3731bc93d425SSumit.Saxena@lsi.com /*
3732bc93d425SSumit.Saxena@lsi.com * Set fast path IO to ZERO.
3733bc93d425SSumit.Saxena@lsi.com * Validate Map will set proper value.
3734bc93d425SSumit.Saxena@lsi.com * Meanwhile all IOs will go as LD IO.
3735bc93d425SSumit.Saxena@lsi.com */
37365f19f7c8SShivasharan S if (status == MFI_STAT_OK &&
37375f19f7c8SShivasharan S (MR_ValidateMapInfo(instance, (instance->map_id + 1)))) {
37385f19f7c8SShivasharan S instance->map_id++;
37399c915a8cSadam radford fusion->fast_path_io = 1;
37405f19f7c8SShivasharan S } else {
37419c915a8cSadam radford fusion->fast_path_io = 0;
37425f19f7c8SShivasharan S }
37435f19f7c8SShivasharan S
3744ae6874baSKashyap Desai if (instance->adapter_type >= INVADER_SERIES)
3745ae6874baSKashyap Desai megasas_set_ld_removed_by_fw(instance);
3746ae6874baSKashyap Desai
37479c915a8cSadam radford megasas_sync_map_info(instance);
37489c915a8cSadam radford spin_unlock_irqrestore(instance->host->host_lock,
37499c915a8cSadam radford flags);
3750ae6874baSKashyap Desai
37519c915a8cSadam radford break;
37529c915a8cSadam radford }
375394cd65ddSSumit.Saxena@lsi.com if (opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
375494cd65ddSSumit.Saxena@lsi.com opcode == MR_DCMD_CTRL_EVENT_GET) {
37550d49016bSadam radford spin_lock_irqsave(&poll_aen_lock, flags);
37560d49016bSadam radford megasas_poll_wait_aen = 0;
37570d49016bSadam radford spin_unlock_irqrestore(&poll_aen_lock, flags);
37580d49016bSadam radford }
37590d49016bSadam radford
37603761cb4cSsumit.saxena@avagotech.com /* FW has an updated PD sequence */
37613761cb4cSsumit.saxena@avagotech.com if ((opcode == MR_DCMD_SYSTEM_PD_MAP_GET_INFO) &&
37623761cb4cSsumit.saxena@avagotech.com (cmd->frame->dcmd.mbox.b[0] == 1)) {
37633761cb4cSsumit.saxena@avagotech.com
37643761cb4cSsumit.saxena@avagotech.com spin_lock_irqsave(instance->host->host_lock, flags);
37653761cb4cSsumit.saxena@avagotech.com status = cmd->frame->hdr.cmd_status;
37663761cb4cSsumit.saxena@avagotech.com instance->jbod_seq_cmd = NULL;
37673761cb4cSsumit.saxena@avagotech.com megasas_return_cmd(instance, cmd);
37683761cb4cSsumit.saxena@avagotech.com
37693761cb4cSsumit.saxena@avagotech.com if (status == MFI_STAT_OK) {
37703761cb4cSsumit.saxena@avagotech.com instance->pd_seq_map_id++;
37713761cb4cSsumit.saxena@avagotech.com /* Re-register a pd sync seq num cmd */
37723761cb4cSsumit.saxena@avagotech.com if (megasas_sync_pd_seq_num(instance, true))
37733761cb4cSsumit.saxena@avagotech.com instance->use_seqnum_jbod_fp = false;
37743761cb4cSsumit.saxena@avagotech.com } else
37753761cb4cSsumit.saxena@avagotech.com instance->use_seqnum_jbod_fp = false;
37763761cb4cSsumit.saxena@avagotech.com
37773761cb4cSsumit.saxena@avagotech.com spin_unlock_irqrestore(instance->host->host_lock, flags);
37783761cb4cSsumit.saxena@avagotech.com break;
37793761cb4cSsumit.saxena@avagotech.com }
37803761cb4cSsumit.saxena@avagotech.com
37810d49016bSadam radford /*
37820d49016bSadam radford * See if got an event notification
37830d49016bSadam radford */
378494cd65ddSSumit.Saxena@lsi.com if (opcode == MR_DCMD_CTRL_EVENT_WAIT)
37850d49016bSadam radford megasas_service_aen(instance, cmd);
37860d49016bSadam radford else
37870d49016bSadam radford megasas_complete_int_cmd(instance, cmd);
37880d49016bSadam radford
37890d49016bSadam radford break;
37900d49016bSadam radford
37910d49016bSadam radford case MFI_CMD_ABORT:
37920d49016bSadam radford /*
37930d49016bSadam radford * Cmd issued to abort another cmd returned
37940d49016bSadam radford */
37950d49016bSadam radford megasas_complete_abort(instance, cmd);
37960d49016bSadam radford break;
37970d49016bSadam radford
37980d49016bSadam radford default:
37991be18254SBjorn Helgaas dev_info(&instance->pdev->dev, "Unknown command completed! [0x%X]\n",
38000d49016bSadam radford hdr->cmd);
380182add4e1SShivasharan S megasas_complete_int_cmd(instance, cmd);
38020d49016bSadam radford break;
38030d49016bSadam radford }
38040d49016bSadam radford }
38050d49016bSadam radford
38060d49016bSadam radford /**
38070d49016bSadam radford * megasas_issue_pending_cmds_again - issue all pending cmds
38080d49016bSadam radford * in FW again because of the fw reset
38090d49016bSadam radford * @instance: Adapter soft state
38100d49016bSadam radford */
38110d49016bSadam radford static inline void
megasas_issue_pending_cmds_again(struct megasas_instance * instance)38120d49016bSadam radford megasas_issue_pending_cmds_again(struct megasas_instance *instance)
38130d49016bSadam radford {
38140d49016bSadam radford struct megasas_cmd *cmd;
38150d49016bSadam radford struct list_head clist_local;
38160d49016bSadam radford union megasas_evt_class_locale class_locale;
38170d49016bSadam radford unsigned long flags;
38180d49016bSadam radford u32 seq_num;
38190d49016bSadam radford
38200d49016bSadam radford INIT_LIST_HEAD(&clist_local);
38210d49016bSadam radford spin_lock_irqsave(&instance->hba_lock, flags);
38220d49016bSadam radford list_splice_init(&instance->internal_reset_pending_q, &clist_local);
38230d49016bSadam radford spin_unlock_irqrestore(&instance->hba_lock, flags);
38240d49016bSadam radford
38250d49016bSadam radford while (!list_empty(&clist_local)) {
38260d49016bSadam radford cmd = list_entry((&clist_local)->next,
38270d49016bSadam radford struct megasas_cmd, list);
38280d49016bSadam radford list_del_init(&cmd->list);
38290d49016bSadam radford
38300d49016bSadam radford if (cmd->sync_cmd || cmd->scmd) {
38311be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "command %p, %p:%d"
38321be18254SBjorn Helgaas "detected to be pending while HBA reset\n",
38330d49016bSadam radford cmd, cmd->scmd, cmd->sync_cmd);
38340d49016bSadam radford
38350d49016bSadam radford cmd->retry_for_fw_reset++;
38360d49016bSadam radford
38370d49016bSadam radford if (cmd->retry_for_fw_reset == 3) {
38381be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "cmd %p, %p:%d"
38390d49016bSadam radford "was tried multiple times during reset."
38400d49016bSadam radford "Shutting down the HBA\n",
38410d49016bSadam radford cmd, cmd->scmd, cmd->sync_cmd);
3842c8dd61efSSumit.Saxena@avagotech.com instance->instancet->disable_intr(instance);
3843c8dd61efSSumit.Saxena@avagotech.com atomic_set(&instance->fw_reset_no_pci_access, 1);
38440d49016bSadam radford megaraid_sas_kill_hba(instance);
38450d49016bSadam radford return;
38460d49016bSadam radford }
38470d49016bSadam radford }
38480d49016bSadam radford
38490d49016bSadam radford if (cmd->sync_cmd == 1) {
38500d49016bSadam radford if (cmd->scmd) {
38511be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "unexpected"
38520d49016bSadam radford "cmd attached to internal command!\n");
38530d49016bSadam radford }
38541be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "%p synchronous cmd"
38550d49016bSadam radford "on the internal reset queue,"
38560d49016bSadam radford "issue it again.\n", cmd);
3857201a810cSAnand Lodnoor cmd->cmd_status_drv = DCMD_INIT;
38580d49016bSadam radford instance->instancet->fire_cmd(instance,
38590d49016bSadam radford cmd->frame_phys_addr,
38600d49016bSadam radford 0, instance->reg_set);
38610d49016bSadam radford } else if (cmd->scmd) {
38621be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "%p scsi cmd [%02x]"
38630d49016bSadam radford "detected on the internal queue, issue again.\n",
38645cd049a5SChristoph Hellwig cmd, cmd->scmd->cmnd[0]);
38650d49016bSadam radford
38660d49016bSadam radford atomic_inc(&instance->fw_outstanding);
38670d49016bSadam radford instance->instancet->fire_cmd(instance,
38680d49016bSadam radford cmd->frame_phys_addr,
38690d49016bSadam radford cmd->frame_count-1, instance->reg_set);
38700d49016bSadam radford } else {
38711be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "%p unexpected cmd on the"
38720d49016bSadam radford "internal reset defer list while re-issue!!\n",
38730d49016bSadam radford cmd);
38740d49016bSadam radford }
38750d49016bSadam radford }
38760d49016bSadam radford
38770d49016bSadam radford if (instance->aen_cmd) {
38781be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "aen_cmd in def process\n");
38790d49016bSadam radford megasas_return_cmd(instance, instance->aen_cmd);
38800d49016bSadam radford
38810d49016bSadam radford instance->aen_cmd = NULL;
38820d49016bSadam radford }
38830d49016bSadam radford
38840d49016bSadam radford /*
38850d49016bSadam radford * Initiate AEN (Asynchronous Event Notification)
38860d49016bSadam radford */
38870d49016bSadam radford seq_num = instance->last_seq_num;
38880d49016bSadam radford class_locale.members.reserved = 0;
38890d49016bSadam radford class_locale.members.locale = MR_EVT_LOCALE_ALL;
38900d49016bSadam radford class_locale.members.class = MR_EVT_CLASS_DEBUG;
38910d49016bSadam radford
38920d49016bSadam radford megasas_register_aen(instance, seq_num, class_locale.word);
38930d49016bSadam radford }
38940d49016bSadam radford
38952b46e5c1SDamien Le Moal /*
38960d49016bSadam radford * Move the internal reset pending commands to a deferred queue.
38970d49016bSadam radford *
38980d49016bSadam radford * We move the commands pending at internal reset time to a
38990d49016bSadam radford * pending queue. This queue would be flushed after successful
39000d49016bSadam radford * completion of the internal reset sequence. if the internal reset
39010d49016bSadam radford * did not complete in time, the kernel reset handler would flush
39020d49016bSadam radford * these commands.
39032b46e5c1SDamien Le Moal */
39040d49016bSadam radford static void
megasas_internal_reset_defer_cmds(struct megasas_instance * instance)39050d49016bSadam radford megasas_internal_reset_defer_cmds(struct megasas_instance *instance)
39060d49016bSadam radford {
39070d49016bSadam radford struct megasas_cmd *cmd;
39080d49016bSadam radford int i;
390950b7f5a2SShivasharan S u16 max_cmd = instance->max_fw_cmds;
39100d49016bSadam radford u32 defer_index;
39110d49016bSadam radford unsigned long flags;
39120d49016bSadam radford
39130d49016bSadam radford defer_index = 0;
391490dc9d98SSumit.Saxena@avagotech.com spin_lock_irqsave(&instance->mfi_pool_lock, flags);
39150d49016bSadam radford for (i = 0; i < max_cmd; i++) {
39160d49016bSadam radford cmd = instance->cmd_list[i];
39170d49016bSadam radford if (cmd->sync_cmd == 1 || cmd->scmd) {
39181be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "moving cmd[%d]:%p:%d:%p"
39190d49016bSadam radford "on the defer queue as internal\n",
39200d49016bSadam radford defer_index, cmd, cmd->sync_cmd, cmd->scmd);
39210d49016bSadam radford
39220d49016bSadam radford if (!list_empty(&cmd->list)) {
39231be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "ERROR while"
39240d49016bSadam radford " moving this cmd:%p, %d %p, it was"
39250d49016bSadam radford "discovered on some list?\n",
39260d49016bSadam radford cmd, cmd->sync_cmd, cmd->scmd);
39270d49016bSadam radford
39280d49016bSadam radford list_del_init(&cmd->list);
39290d49016bSadam radford }
39300d49016bSadam radford defer_index++;
39310d49016bSadam radford list_add_tail(&cmd->list,
39320d49016bSadam radford &instance->internal_reset_pending_q);
39330d49016bSadam radford }
39340d49016bSadam radford }
393590dc9d98SSumit.Saxena@avagotech.com spin_unlock_irqrestore(&instance->mfi_pool_lock, flags);
39360d49016bSadam radford }
39370d49016bSadam radford
39380d49016bSadam radford
39390d49016bSadam radford static void
process_fw_state_change_wq(struct work_struct * work)39400d49016bSadam radford process_fw_state_change_wq(struct work_struct *work)
39410d49016bSadam radford {
39420d49016bSadam radford struct megasas_instance *instance =
39430d49016bSadam radford container_of(work, struct megasas_instance, work_init);
39440d49016bSadam radford u32 wait;
39450d49016bSadam radford unsigned long flags;
39460d49016bSadam radford
39478a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) != MEGASAS_ADPRESET_SM_INFAULT) {
39481be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "error, recovery st %x\n",
39498a01a41dSSumit Saxena atomic_read(&instance->adprecovery));
39500d49016bSadam radford return ;
39510d49016bSadam radford }
39520d49016bSadam radford
39538a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
39541be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "FW detected to be in fault"
39550d49016bSadam radford "state, restarting it...\n");
39560d49016bSadam radford
3957d46a3ad6SSumit.Saxena@lsi.com instance->instancet->disable_intr(instance);
39580d49016bSadam radford atomic_set(&instance->fw_outstanding, 0);
39590d49016bSadam radford
39600d49016bSadam radford atomic_set(&instance->fw_reset_no_pci_access, 1);
39610d49016bSadam radford instance->instancet->adp_reset(instance, instance->reg_set);
39620d49016bSadam radford atomic_set(&instance->fw_reset_no_pci_access, 0);
39630d49016bSadam radford
39641be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "FW restarted successfully,"
39650d49016bSadam radford "initiating next stage...\n");
39660d49016bSadam radford
39671be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "HBA recovery state machine,"
39680d49016bSadam radford "state 2 starting...\n");
39690d49016bSadam radford
3970da0dc9fbSBjorn Helgaas /* waiting for about 20 second before start the second init */
39710d49016bSadam radford for (wait = 0; wait < 30; wait++) {
39720d49016bSadam radford msleep(1000);
39730d49016bSadam radford }
39740d49016bSadam radford
3975058a8facSadam radford if (megasas_transition_to_ready(instance, 1)) {
39761be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "adapter not ready\n");
39770d49016bSadam radford
3978c8dd61efSSumit.Saxena@avagotech.com atomic_set(&instance->fw_reset_no_pci_access, 1);
39790d49016bSadam radford megaraid_sas_kill_hba(instance);
39800d49016bSadam radford return ;
39810d49016bSadam radford }
39820d49016bSadam radford
39830d49016bSadam radford if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
39840d49016bSadam radford (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
39850d49016bSadam radford (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)
39860d49016bSadam radford ) {
39870d49016bSadam radford *instance->consumer = *instance->producer;
39880d49016bSadam radford } else {
39890d49016bSadam radford *instance->consumer = 0;
39900d49016bSadam radford *instance->producer = 0;
39910d49016bSadam radford }
39920d49016bSadam radford
39930d49016bSadam radford megasas_issue_init_mfi(instance);
39940d49016bSadam radford
39950d49016bSadam radford spin_lock_irqsave(&instance->hba_lock, flags);
39968a01a41dSSumit Saxena atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
39970d49016bSadam radford spin_unlock_irqrestore(&instance->hba_lock, flags);
3998d46a3ad6SSumit.Saxena@lsi.com instance->instancet->enable_intr(instance);
39990d49016bSadam radford
40000d49016bSadam radford megasas_issue_pending_cmds_again(instance);
40010d49016bSadam radford instance->issuepend_done = 1;
40020d49016bSadam radford }
40030d49016bSadam radford }
40040d49016bSadam radford
40050d49016bSadam radford /**
40060d49016bSadam radford * megasas_deplete_reply_queue - Processes all completed commands
40070d49016bSadam radford * @instance: Adapter soft state
40080d49016bSadam radford * @alt_status: Alternate status to be returned to
40090d49016bSadam radford * SCSI mid-layer instead of the status
40100d49016bSadam radford * returned by the FW
40110d49016bSadam radford * Note: this must be called with hba lock held
40120d49016bSadam radford */
40130d49016bSadam radford static int
megasas_deplete_reply_queue(struct megasas_instance * instance,u8 alt_status)40140d49016bSadam radford megasas_deplete_reply_queue(struct megasas_instance *instance,
40150d49016bSadam radford u8 alt_status)
40160d49016bSadam radford {
40170d49016bSadam radford u32 mfiStatus;
40180d49016bSadam radford u32 fw_state;
40190d49016bSadam radford
40204e62671aSColin Ian King if (instance->instancet->check_reset(instance, instance->reg_set) == 1)
40210d49016bSadam radford return IRQ_HANDLED;
40220d49016bSadam radford
4023de516379SShivasharan S mfiStatus = instance->instancet->clear_intr(instance);
4024de516379SShivasharan S if (mfiStatus == 0) {
4025e1419191Sadam radford /* Hardware may not set outbound_intr_status in MSI-X mode */
4026c8e858feSadam radford if (!instance->msix_vectors)
40270d49016bSadam radford return IRQ_NONE;
40280d49016bSadam radford }
40290d49016bSadam radford
40300d49016bSadam radford instance->mfiStatus = mfiStatus;
40310d49016bSadam radford
40320d49016bSadam radford if ((mfiStatus & MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE)) {
40330d49016bSadam radford fw_state = instance->instancet->read_fw_status_reg(
4034de516379SShivasharan S instance) & MFI_STATE_MASK;
40350d49016bSadam radford
40360d49016bSadam radford if (fw_state != MFI_STATE_FAULT) {
40371be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "fw state:%x\n",
40380d49016bSadam radford fw_state);
40390d49016bSadam radford }
40400d49016bSadam radford
40410d49016bSadam radford if ((fw_state == MFI_STATE_FAULT) &&
40420d49016bSadam radford (instance->disableOnlineCtrlReset == 0)) {
40431be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "wait adp restart\n");
40440d49016bSadam radford
40450d49016bSadam radford if ((instance->pdev->device ==
40460d49016bSadam radford PCI_DEVICE_ID_LSI_SAS1064R) ||
40470d49016bSadam radford (instance->pdev->device ==
40480d49016bSadam radford PCI_DEVICE_ID_DELL_PERC5) ||
40490d49016bSadam radford (instance->pdev->device ==
40500d49016bSadam radford PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
40510d49016bSadam radford
40520d49016bSadam radford *instance->consumer =
405394cd65ddSSumit.Saxena@lsi.com cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN);
40540d49016bSadam radford }
40550d49016bSadam radford
40560d49016bSadam radford
4057d46a3ad6SSumit.Saxena@lsi.com instance->instancet->disable_intr(instance);
40588a01a41dSSumit Saxena atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
40590d49016bSadam radford instance->issuepend_done = 0;
40600d49016bSadam radford
40610d49016bSadam radford atomic_set(&instance->fw_outstanding, 0);
40620d49016bSadam radford megasas_internal_reset_defer_cmds(instance);
40630d49016bSadam radford
40641be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "fwState=%x, stage:%d\n",
40658a01a41dSSumit Saxena fw_state, atomic_read(&instance->adprecovery));
40660d49016bSadam radford
40670d49016bSadam radford schedule_work(&instance->work_init);
40680d49016bSadam radford return IRQ_HANDLED;
40690d49016bSadam radford
40700d49016bSadam radford } else {
40711be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "fwstate:%x, dis_OCR=%x\n",
40720d49016bSadam radford fw_state, instance->disableOnlineCtrlReset);
40730d49016bSadam radford }
40740d49016bSadam radford }
40750d49016bSadam radford
40760d49016bSadam radford tasklet_schedule(&instance->isr_tasklet);
40770d49016bSadam radford return IRQ_HANDLED;
40780d49016bSadam radford }
40792b46e5c1SDamien Le Moal
40800d49016bSadam radford /**
40810d49016bSadam radford * megasas_isr - isr entry point
40822b46e5c1SDamien Le Moal * @irq: IRQ number
40832b46e5c1SDamien Le Moal * @devp: IRQ context address
40840d49016bSadam radford */
megasas_isr(int irq,void * devp)40850d49016bSadam radford static irqreturn_t megasas_isr(int irq, void *devp)
40860d49016bSadam radford {
4087c8e858feSadam radford struct megasas_irq_context *irq_context = devp;
4088c8e858feSadam radford struct megasas_instance *instance = irq_context->instance;
40890d49016bSadam radford unsigned long flags;
40900d49016bSadam radford irqreturn_t rc;
40910d49016bSadam radford
4092c8e858feSadam radford if (atomic_read(&instance->fw_reset_no_pci_access))
40930d49016bSadam radford return IRQ_HANDLED;
40940d49016bSadam radford
40950d49016bSadam radford spin_lock_irqsave(&instance->hba_lock, flags);
40960d49016bSadam radford rc = megasas_deplete_reply_queue(instance, DID_OK);
40970d49016bSadam radford spin_unlock_irqrestore(&instance->hba_lock, flags);
40980d49016bSadam radford
40990d49016bSadam radford return rc;
41000d49016bSadam radford }
41010d49016bSadam radford
41020d49016bSadam radford /**
41030d49016bSadam radford * megasas_transition_to_ready - Move the FW to READY state
41040d49016bSadam radford * @instance: Adapter soft state
41052b46e5c1SDamien Le Moal * @ocr: Adapter reset state
41060d49016bSadam radford *
41070d49016bSadam radford * During the initialization, FW passes can potentially be in any one of
41080d49016bSadam radford * several possible states. If the FW in operational, waiting-for-handshake
41090d49016bSadam radford * states, driver must take steps to bring it to ready state. Otherwise, it
41100d49016bSadam radford * has to wait for the ready state.
41110d49016bSadam radford */
41129c915a8cSadam radford int
megasas_transition_to_ready(struct megasas_instance * instance,int ocr)4113058a8facSadam radford megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
41140d49016bSadam radford {
41150d49016bSadam radford int i;
41160d49016bSadam radford u8 max_wait;
41170d49016bSadam radford u32 fw_state;
41180d49016bSadam radford u32 abs_state, curr_abs_state;
41190d49016bSadam radford
4120de516379SShivasharan S abs_state = instance->instancet->read_fw_status_reg(instance);
4121bc6ac5e8STomas Henzl fw_state = abs_state & MFI_STATE_MASK;
41220d49016bSadam radford
41230d49016bSadam radford if (fw_state != MFI_STATE_READY)
41241be18254SBjorn Helgaas dev_info(&instance->pdev->dev, "Waiting for FW to come to ready"
41250d49016bSadam radford " state\n");
41260d49016bSadam radford
41270d49016bSadam radford while (fw_state != MFI_STATE_READY) {
41280d49016bSadam radford
41290d49016bSadam radford switch (fw_state) {
41300d49016bSadam radford
41310d49016bSadam radford case MFI_STATE_FAULT:
4132b6661342SShivasharan S dev_printk(KERN_ERR, &instance->pdev->dev,
4133b6661342SShivasharan S "FW in FAULT state, Fault code:0x%x subcode:0x%x func:%s\n",
4134b6661342SShivasharan S abs_state & MFI_STATE_FAULT_CODE,
4135b6661342SShivasharan S abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
4136058a8facSadam radford if (ocr) {
41371ac515efSadam radford max_wait = MEGASAS_RESET_WAIT_TIME;
41381ac515efSadam radford break;
41393d1d9eb7SShivasharan S } else {
41403d1d9eb7SShivasharan S dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
41413d1d9eb7SShivasharan S megasas_dump_reg_set(instance->reg_set);
4142058a8facSadam radford return -ENODEV;
41433d1d9eb7SShivasharan S }
41440d49016bSadam radford
41450d49016bSadam radford case MFI_STATE_WAIT_HANDSHAKE:
41460d49016bSadam radford /*
41470d49016bSadam radford * Set the CLR bit in inbound doorbell
41480d49016bSadam radford */
41490d49016bSadam radford if ((instance->pdev->device ==
41500d49016bSadam radford PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
41510d49016bSadam radford (instance->pdev->device ==
41529c915a8cSadam radford PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
4153e7d36b88SShivasharan S (instance->adapter_type != MFI_SERIES))
41540d49016bSadam radford writel(
41550d49016bSadam radford MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
41569c915a8cSadam radford &instance->reg_set->doorbell);
41575a8cb85bSsumit.saxena@avagotech.com else
41580d49016bSadam radford writel(
41590d49016bSadam radford MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
41600d49016bSadam radford &instance->reg_set->inbound_doorbell);
41610d49016bSadam radford
41620d49016bSadam radford max_wait = MEGASAS_RESET_WAIT_TIME;
41630d49016bSadam radford break;
41640d49016bSadam radford
41650d49016bSadam radford case MFI_STATE_BOOT_MESSAGE_PENDING:
41660d49016bSadam radford if ((instance->pdev->device ==
41670d49016bSadam radford PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
41680d49016bSadam radford (instance->pdev->device ==
41699c915a8cSadam radford PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
4170e7d36b88SShivasharan S (instance->adapter_type != MFI_SERIES))
41710d49016bSadam radford writel(MFI_INIT_HOTPLUG,
41729c915a8cSadam radford &instance->reg_set->doorbell);
41735a8cb85bSsumit.saxena@avagotech.com else
41740d49016bSadam radford writel(MFI_INIT_HOTPLUG,
41750d49016bSadam radford &instance->reg_set->inbound_doorbell);
41760d49016bSadam radford
41770d49016bSadam radford max_wait = MEGASAS_RESET_WAIT_TIME;
41780d49016bSadam radford break;
41790d49016bSadam radford
41800d49016bSadam radford case MFI_STATE_OPERATIONAL:
41810d49016bSadam radford /*
41820d49016bSadam radford * Bring it to READY state; assuming max wait 10 secs
41830d49016bSadam radford */
4184d46a3ad6SSumit.Saxena@lsi.com instance->instancet->disable_intr(instance);
41850d49016bSadam radford if ((instance->pdev->device ==
41860d49016bSadam radford PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
41870d49016bSadam radford (instance->pdev->device ==
41889c915a8cSadam radford PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
4189e7d36b88SShivasharan S (instance->adapter_type != MFI_SERIES)) {
41900d49016bSadam radford writel(MFI_RESET_FLAGS,
41919c915a8cSadam radford &instance->reg_set->doorbell);
41925a8cb85bSsumit.saxena@avagotech.com
4193e7d36b88SShivasharan S if (instance->adapter_type != MFI_SERIES) {
41949c915a8cSadam radford for (i = 0; i < (10 * 1000); i += 20) {
4195272652fcSShivasharan S if (megasas_readl(
4196272652fcSShivasharan S instance,
41979c915a8cSadam radford &instance->
41989c915a8cSadam radford reg_set->
41999c915a8cSadam radford doorbell) & 1)
42009c915a8cSadam radford msleep(20);
42019c915a8cSadam radford else
42029c915a8cSadam radford break;
42039c915a8cSadam radford }
42049c915a8cSadam radford }
42050d49016bSadam radford } else
42060d49016bSadam radford writel(MFI_RESET_FLAGS,
42070d49016bSadam radford &instance->reg_set->inbound_doorbell);
42080d49016bSadam radford
42090d49016bSadam radford max_wait = MEGASAS_RESET_WAIT_TIME;
42100d49016bSadam radford break;
42110d49016bSadam radford
42120d49016bSadam radford case MFI_STATE_UNDEFINED:
42130d49016bSadam radford /*
42140d49016bSadam radford * This state should not last for more than 2 seconds
42150d49016bSadam radford */
42160d49016bSadam radford max_wait = MEGASAS_RESET_WAIT_TIME;
42170d49016bSadam radford break;
42180d49016bSadam radford
42190d49016bSadam radford case MFI_STATE_BB_INIT:
42200d49016bSadam radford max_wait = MEGASAS_RESET_WAIT_TIME;
42210d49016bSadam radford break;
42220d49016bSadam radford
42230d49016bSadam radford case MFI_STATE_FW_INIT:
42240d49016bSadam radford max_wait = MEGASAS_RESET_WAIT_TIME;
42250d49016bSadam radford break;
42260d49016bSadam radford
42270d49016bSadam radford case MFI_STATE_FW_INIT_2:
42280d49016bSadam radford max_wait = MEGASAS_RESET_WAIT_TIME;
42290d49016bSadam radford break;
42300d49016bSadam radford
42310d49016bSadam radford case MFI_STATE_DEVICE_SCAN:
42320d49016bSadam radford max_wait = MEGASAS_RESET_WAIT_TIME;
42330d49016bSadam radford break;
42340d49016bSadam radford
42350d49016bSadam radford case MFI_STATE_FLUSH_CACHE:
42360d49016bSadam radford max_wait = MEGASAS_RESET_WAIT_TIME;
42370d49016bSadam radford break;
42380d49016bSadam radford
42390d49016bSadam radford default:
42401be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "Unknown state 0x%x\n",
42410d49016bSadam radford fw_state);
42423d1d9eb7SShivasharan S dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
42433d1d9eb7SShivasharan S megasas_dump_reg_set(instance->reg_set);
42440d49016bSadam radford return -ENODEV;
42450d49016bSadam radford }
42460d49016bSadam radford
42470d49016bSadam radford /*
42480d49016bSadam radford * The cur_state should not last for more than max_wait secs
42490d49016bSadam radford */
425031b6a05fSSteve Sistare for (i = 0; i < max_wait * 50; i++) {
4251bc6ac5e8STomas Henzl curr_abs_state = instance->instancet->
4252de516379SShivasharan S read_fw_status_reg(instance);
42530d49016bSadam radford
42540d49016bSadam radford if (abs_state == curr_abs_state) {
425531b6a05fSSteve Sistare msleep(20);
42560d49016bSadam radford } else
42570d49016bSadam radford break;
42580d49016bSadam radford }
42590d49016bSadam radford
42600d49016bSadam radford /*
42610d49016bSadam radford * Return error if fw_state hasn't changed after max_wait
42620d49016bSadam radford */
42630d49016bSadam radford if (curr_abs_state == abs_state) {
42641be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW state [%d] hasn't changed "
42650d49016bSadam radford "in %d secs\n", fw_state, max_wait);
42663d1d9eb7SShivasharan S dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
42673d1d9eb7SShivasharan S megasas_dump_reg_set(instance->reg_set);
42680d49016bSadam radford return -ENODEV;
42690d49016bSadam radford }
4270bc6ac5e8STomas Henzl
4271bc6ac5e8STomas Henzl abs_state = curr_abs_state;
4272bc6ac5e8STomas Henzl fw_state = curr_abs_state & MFI_STATE_MASK;
42730d49016bSadam radford }
42741be18254SBjorn Helgaas dev_info(&instance->pdev->dev, "FW now in Ready state\n");
42750d49016bSadam radford
42760d49016bSadam radford return 0;
42770d49016bSadam radford }
42780d49016bSadam radford
42790d49016bSadam radford /**
42800d49016bSadam radford * megasas_teardown_frame_pool - Destroy the cmd frame DMA pool
42810d49016bSadam radford * @instance: Adapter soft state
42820d49016bSadam radford */
megasas_teardown_frame_pool(struct megasas_instance * instance)42830d49016bSadam radford static void megasas_teardown_frame_pool(struct megasas_instance *instance)
42840d49016bSadam radford {
42850d49016bSadam radford int i;
428650b7f5a2SShivasharan S u16 max_cmd = instance->max_mfi_cmds;
42870d49016bSadam radford struct megasas_cmd *cmd;
42880d49016bSadam radford
42890d49016bSadam radford if (!instance->frame_dma_pool)
42900d49016bSadam radford return;
42910d49016bSadam radford
42920d49016bSadam radford /*
42930d49016bSadam radford * Return all frames to pool
42940d49016bSadam radford */
42950d49016bSadam radford for (i = 0; i < max_cmd; i++) {
42960d49016bSadam radford
42970d49016bSadam radford cmd = instance->cmd_list[i];
42980d49016bSadam radford
42990d49016bSadam radford if (cmd->frame)
4300fc69d86dSRomain Perier dma_pool_free(instance->frame_dma_pool, cmd->frame,
43010d49016bSadam radford cmd->frame_phys_addr);
43020d49016bSadam radford
43030d49016bSadam radford if (cmd->sense)
4304fc69d86dSRomain Perier dma_pool_free(instance->sense_dma_pool, cmd->sense,
43050d49016bSadam radford cmd->sense_phys_addr);
43060d49016bSadam radford }
43070d49016bSadam radford
43080d49016bSadam radford /*
43090d49016bSadam radford * Now destroy the pool itself
43100d49016bSadam radford */
4311fc69d86dSRomain Perier dma_pool_destroy(instance->frame_dma_pool);
4312fc69d86dSRomain Perier dma_pool_destroy(instance->sense_dma_pool);
43130d49016bSadam radford
43140d49016bSadam radford instance->frame_dma_pool = NULL;
43150d49016bSadam radford instance->sense_dma_pool = NULL;
43160d49016bSadam radford }
43170d49016bSadam radford
43180d49016bSadam radford /**
43190d49016bSadam radford * megasas_create_frame_pool - Creates DMA pool for cmd frames
43200d49016bSadam radford * @instance: Adapter soft state
43210d49016bSadam radford *
43220d49016bSadam radford * Each command packet has an embedded DMA memory buffer that is used for
43230d49016bSadam radford * filling MFI frame and the SG list that immediately follows the frame. This
43240d49016bSadam radford * function creates those DMA memory buffers for each command packet by using
43250d49016bSadam radford * PCI pool facility.
43260d49016bSadam radford */
megasas_create_frame_pool(struct megasas_instance * instance)43270d49016bSadam radford static int megasas_create_frame_pool(struct megasas_instance *instance)
43280d49016bSadam radford {
43290d49016bSadam radford int i;
433050b7f5a2SShivasharan S u16 max_cmd;
43310d49016bSadam radford u32 frame_count;
43320d49016bSadam radford struct megasas_cmd *cmd;
43330d49016bSadam radford
43349c915a8cSadam radford max_cmd = instance->max_mfi_cmds;
43350d49016bSadam radford
43360d49016bSadam radford /*
4337200aed58SSumit.Saxena@avagotech.com * For MFI controllers.
4338200aed58SSumit.Saxena@avagotech.com * max_num_sge = 60
4339200aed58SSumit.Saxena@avagotech.com * max_sge_sz = 16 byte (sizeof megasas_sge_skinny)
4340200aed58SSumit.Saxena@avagotech.com * Total 960 byte (15 MFI frame of 64 byte)
4341200aed58SSumit.Saxena@avagotech.com *
4342200aed58SSumit.Saxena@avagotech.com * Fusion adapter require only 3 extra frame.
4343200aed58SSumit.Saxena@avagotech.com * max_num_sge = 16 (defined as MAX_IOCTL_SGE)
4344200aed58SSumit.Saxena@avagotech.com * max_sge_sz = 12 byte (sizeof megasas_sge64)
4345200aed58SSumit.Saxena@avagotech.com * Total 192 byte (3 MFI frame of 64 byte)
43460d49016bSadam radford */
4347e7d36b88SShivasharan S frame_count = (instance->adapter_type == MFI_SERIES) ?
4348e7d36b88SShivasharan S (15 + 1) : (3 + 1);
434921c34006SShivasharan S instance->mfi_frame_size = MEGAMFI_FRAME_SIZE * frame_count;
43500d49016bSadam radford /*
43510d49016bSadam radford * Use DMA pool facility provided by PCI layer
43520d49016bSadam radford */
4353fc69d86dSRomain Perier instance->frame_dma_pool = dma_pool_create("megasas frame pool",
4354fc69d86dSRomain Perier &instance->pdev->dev,
4355fc69d86dSRomain Perier instance->mfi_frame_size, 256, 0);
43560d49016bSadam radford
43570d49016bSadam radford if (!instance->frame_dma_pool) {
43581be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup frame pool\n");
43590d49016bSadam radford return -ENOMEM;
43600d49016bSadam radford }
43610d49016bSadam radford
4362fc69d86dSRomain Perier instance->sense_dma_pool = dma_pool_create("megasas sense pool",
4363fc69d86dSRomain Perier &instance->pdev->dev, 128,
4364fc69d86dSRomain Perier 4, 0);
43650d49016bSadam radford
43660d49016bSadam radford if (!instance->sense_dma_pool) {
43671be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool\n");
43680d49016bSadam radford
4369fc69d86dSRomain Perier dma_pool_destroy(instance->frame_dma_pool);
43700d49016bSadam radford instance->frame_dma_pool = NULL;
43710d49016bSadam radford
43720d49016bSadam radford return -ENOMEM;
43730d49016bSadam radford }
43740d49016bSadam radford
43750d49016bSadam radford /*
43760d49016bSadam radford * Allocate and attach a frame to each of the commands in cmd_list.
43770d49016bSadam radford * By making cmd->index as the context instead of the &cmd, we can
43780d49016bSadam radford * always use 32bit context regardless of the architecture
43790d49016bSadam radford */
43800d49016bSadam radford for (i = 0; i < max_cmd; i++) {
43810d49016bSadam radford
43820d49016bSadam radford cmd = instance->cmd_list[i];
43830d49016bSadam radford
438461b142afSSouptick Joarder cmd->frame = dma_pool_zalloc(instance->frame_dma_pool,
43850d49016bSadam radford GFP_KERNEL, &cmd->frame_phys_addr);
43860d49016bSadam radford
4387fc69d86dSRomain Perier cmd->sense = dma_pool_alloc(instance->sense_dma_pool,
43880d49016bSadam radford GFP_KERNEL, &cmd->sense_phys_addr);
43890d49016bSadam radford
43900d49016bSadam radford /*
43910d49016bSadam radford * megasas_teardown_frame_pool() takes care of freeing
43920d49016bSadam radford * whatever has been allocated
43930d49016bSadam radford */
43940d49016bSadam radford if (!cmd->frame || !cmd->sense) {
4395fc69d86dSRomain Perier dev_printk(KERN_DEBUG, &instance->pdev->dev, "dma_pool_alloc failed\n");
43960d49016bSadam radford megasas_teardown_frame_pool(instance);
43970d49016bSadam radford return -ENOMEM;
43980d49016bSadam radford }
43990d49016bSadam radford
440094cd65ddSSumit.Saxena@lsi.com cmd->frame->io.context = cpu_to_le32(cmd->index);
44010d49016bSadam radford cmd->frame->io.pad_0 = 0;
4402e7d36b88SShivasharan S if ((instance->adapter_type == MFI_SERIES) && reset_devices)
4403e5f93a36Sadam radford cmd->frame->hdr.cmd = MFI_CMD_INVALID;
44040d49016bSadam radford }
44050d49016bSadam radford
44060d49016bSadam radford return 0;
44070d49016bSadam radford }
44080d49016bSadam radford
44090d49016bSadam radford /**
44100d49016bSadam radford * megasas_free_cmds - Free all the cmds in the free cmd pool
44110d49016bSadam radford * @instance: Adapter soft state
44120d49016bSadam radford */
megasas_free_cmds(struct megasas_instance * instance)44139c915a8cSadam radford void megasas_free_cmds(struct megasas_instance *instance)
44140d49016bSadam radford {
44150d49016bSadam radford int i;
4416da0dc9fbSBjorn Helgaas
44170d49016bSadam radford /* First free the MFI frame pool */
44180d49016bSadam radford megasas_teardown_frame_pool(instance);
44190d49016bSadam radford
44200d49016bSadam radford /* Free all the commands in the cmd_list */
44219c915a8cSadam radford for (i = 0; i < instance->max_mfi_cmds; i++)
44229c915a8cSadam radford
44230d49016bSadam radford kfree(instance->cmd_list[i]);
44240d49016bSadam radford
44250d49016bSadam radford /* Free the cmd_list buffer itself */
44260d49016bSadam radford kfree(instance->cmd_list);
44270d49016bSadam radford instance->cmd_list = NULL;
44280d49016bSadam radford
44290d49016bSadam radford INIT_LIST_HEAD(&instance->cmd_pool);
44300d49016bSadam radford }
44310d49016bSadam radford
44320d49016bSadam radford /**
44330d49016bSadam radford * megasas_alloc_cmds - Allocates the command packets
44340d49016bSadam radford * @instance: Adapter soft state
44350d49016bSadam radford *
44360d49016bSadam radford * Each command that is issued to the FW, whether IO commands from the OS or
44370d49016bSadam radford * internal commands like IOCTLs, are wrapped in local data structure called
44380d49016bSadam radford * megasas_cmd. The frame embedded in this megasas_cmd is actually issued to
44390d49016bSadam radford * the FW.
44400d49016bSadam radford *
44410d49016bSadam radford * Each frame has a 32-bit field called context (tag). This context is used
44420d49016bSadam radford * to get back the megasas_cmd from the frame when a frame gets completed in
44430d49016bSadam radford * the ISR. Typically the address of the megasas_cmd itself would be used as
44440d49016bSadam radford * the context. But we wanted to keep the differences between 32 and 64 bit
44450d49016bSadam radford * systems to the mininum. We always use 32 bit integers for the context. In
44460d49016bSadam radford * this driver, the 32 bit values are the indices into an array cmd_list.
44470d49016bSadam radford * This array is used only to look up the megasas_cmd given the context. The
44480d49016bSadam radford * free commands themselves are maintained in a linked list called cmd_pool.
44490d49016bSadam radford */
megasas_alloc_cmds(struct megasas_instance * instance)44509c915a8cSadam radford int megasas_alloc_cmds(struct megasas_instance *instance)
44510d49016bSadam radford {
44520d49016bSadam radford int i;
44530d49016bSadam radford int j;
445450b7f5a2SShivasharan S u16 max_cmd;
44550d49016bSadam radford struct megasas_cmd *cmd;
44560d49016bSadam radford
44579c915a8cSadam radford max_cmd = instance->max_mfi_cmds;
44580d49016bSadam radford
44590d49016bSadam radford /*
44600d49016bSadam radford * instance->cmd_list is an array of struct megasas_cmd pointers.
44610d49016bSadam radford * Allocate the dynamic array first and then allocate individual
44620d49016bSadam radford * commands.
44630d49016bSadam radford */
44640d49016bSadam radford instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL);
44650d49016bSadam radford
44660d49016bSadam radford if (!instance->cmd_list) {
44671be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory\n");
44680d49016bSadam radford return -ENOMEM;
44690d49016bSadam radford }
44700d49016bSadam radford
44710d49016bSadam radford for (i = 0; i < max_cmd; i++) {
44720d49016bSadam radford instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
44730d49016bSadam radford GFP_KERNEL);
44740d49016bSadam radford
44750d49016bSadam radford if (!instance->cmd_list[i]) {
44760d49016bSadam radford
44770d49016bSadam radford for (j = 0; j < i; j++)
44780d49016bSadam radford kfree(instance->cmd_list[j]);
44790d49016bSadam radford
44800d49016bSadam radford kfree(instance->cmd_list);
44810d49016bSadam radford instance->cmd_list = NULL;
44820d49016bSadam radford
44830d49016bSadam radford return -ENOMEM;
44840d49016bSadam radford }
44850d49016bSadam radford }
44860d49016bSadam radford
44870d49016bSadam radford for (i = 0; i < max_cmd; i++) {
44880d49016bSadam radford cmd = instance->cmd_list[i];
44890d49016bSadam radford memset(cmd, 0, sizeof(struct megasas_cmd));
44900d49016bSadam radford cmd->index = i;
44910d49016bSadam radford cmd->scmd = NULL;
44920d49016bSadam radford cmd->instance = instance;
44930d49016bSadam radford
44940d49016bSadam radford list_add_tail(&cmd->list, &instance->cmd_pool);
44950d49016bSadam radford }
44960d49016bSadam radford
44970d49016bSadam radford /*
44980d49016bSadam radford * Create a frame pool and assign one frame to each cmd
44990d49016bSadam radford */
45000d49016bSadam radford if (megasas_create_frame_pool(instance)) {
45011be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n");
45020d49016bSadam radford megasas_free_cmds(instance);
4503bcf3b67dSJason Yan return -ENOMEM;
45040d49016bSadam radford }
45050d49016bSadam radford
45060d49016bSadam radford return 0;
45070d49016bSadam radford }
45080d49016bSadam radford
45090d49016bSadam radford /*
45106d40afbcSSumit Saxena * dcmd_timeout_ocr_possible - Check if OCR is possible based on Driver/FW state.
45116d40afbcSSumit Saxena * @instance: Adapter soft state
45126d40afbcSSumit Saxena *
45136d40afbcSSumit Saxena * Return 0 for only Fusion adapter, if driver load/unload is not in progress
45146d40afbcSSumit Saxena * or FW is not under OCR.
45156d40afbcSSumit Saxena */
45166d40afbcSSumit Saxena inline int
dcmd_timeout_ocr_possible(struct megasas_instance * instance)45176d40afbcSSumit Saxena dcmd_timeout_ocr_possible(struct megasas_instance *instance) {
45186d40afbcSSumit Saxena
4519e7d36b88SShivasharan S if (instance->adapter_type == MFI_SERIES)
45206d40afbcSSumit Saxena return KILL_ADAPTER;
45216d40afbcSSumit Saxena else if (instance->unload ||
45226d753727SAnand Lodnoor test_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE,
45236d753727SAnand Lodnoor &instance->reset_flags))
45246d40afbcSSumit Saxena return IGNORE_TIMEOUT;
45256d40afbcSSumit Saxena else
45266d40afbcSSumit Saxena return INITIATE_OCR;
45276d40afbcSSumit Saxena }
45286d40afbcSSumit Saxena
452915dd0381SShivasharan S static void
megasas_get_pd_info(struct megasas_instance * instance,struct scsi_device * sdev)453015dd0381SShivasharan S megasas_get_pd_info(struct megasas_instance *instance, struct scsi_device *sdev)
45312216c305SSumit Saxena {
45322216c305SSumit Saxena int ret;
45332216c305SSumit Saxena struct megasas_cmd *cmd;
45342216c305SSumit Saxena struct megasas_dcmd_frame *dcmd;
45352216c305SSumit Saxena
453615dd0381SShivasharan S struct MR_PRIV_DEVICE *mr_device_priv_data;
453715dd0381SShivasharan S u16 device_id = 0;
453815dd0381SShivasharan S
453915dd0381SShivasharan S device_id = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
45402216c305SSumit Saxena cmd = megasas_get_cmd(instance);
45412216c305SSumit Saxena
45422216c305SSumit Saxena if (!cmd) {
45432216c305SSumit Saxena dev_err(&instance->pdev->dev, "Failed to get cmd %s\n", __func__);
454415dd0381SShivasharan S return;
45452216c305SSumit Saxena }
45462216c305SSumit Saxena
45472216c305SSumit Saxena dcmd = &cmd->frame->dcmd;
45482216c305SSumit Saxena
45492216c305SSumit Saxena memset(instance->pd_info, 0, sizeof(*instance->pd_info));
45502216c305SSumit Saxena memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
45512216c305SSumit Saxena
45522216c305SSumit Saxena dcmd->mbox.s[0] = cpu_to_le16(device_id);
45532216c305SSumit Saxena dcmd->cmd = MFI_CMD_DCMD;
45542216c305SSumit Saxena dcmd->cmd_status = 0xFF;
45552216c305SSumit Saxena dcmd->sge_count = 1;
4556107a60ddSShivasharan S dcmd->flags = MFI_FRAME_DIR_READ;
45572216c305SSumit Saxena dcmd->timeout = 0;
45582216c305SSumit Saxena dcmd->pad_0 = 0;
45592216c305SSumit Saxena dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_PD_INFO));
45602216c305SSumit Saxena dcmd->opcode = cpu_to_le32(MR_DCMD_PD_GET_INFO);
45612216c305SSumit Saxena
4562107a60ddSShivasharan S megasas_set_dma_settings(instance, dcmd, instance->pd_info_h,
4563107a60ddSShivasharan S sizeof(struct MR_PD_INFO));
45642216c305SSumit Saxena
4565e7d36b88SShivasharan S if ((instance->adapter_type != MFI_SERIES) &&
4566e7d36b88SShivasharan S !instance->mask_interrupts)
45672216c305SSumit Saxena ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
45682216c305SSumit Saxena else
45692216c305SSumit Saxena ret = megasas_issue_polled(instance, cmd);
45702216c305SSumit Saxena
45712216c305SSumit Saxena switch (ret) {
45722216c305SSumit Saxena case DCMD_SUCCESS:
457315dd0381SShivasharan S mr_device_priv_data = sdev->hostdata;
457415dd0381SShivasharan S le16_to_cpus((u16 *)&instance->pd_info->state.ddf.pdType);
457515dd0381SShivasharan S mr_device_priv_data->interface_type =
45762216c305SSumit Saxena instance->pd_info->state.ddf.pdType.intf;
45772216c305SSumit Saxena break;
45782216c305SSumit Saxena
45792216c305SSumit Saxena case DCMD_TIMEOUT:
45802216c305SSumit Saxena
45812216c305SSumit Saxena switch (dcmd_timeout_ocr_possible(instance)) {
45822216c305SSumit Saxena case INITIATE_OCR:
45832216c305SSumit Saxena cmd->flags |= DRV_DCMD_SKIP_REFIRE;
45847fa3174bSChandrakanth Patil mutex_unlock(&instance->reset_mutex);
45852216c305SSumit Saxena megasas_reset_fusion(instance->host,
45862216c305SSumit Saxena MFI_IO_TIMEOUT_OCR);
45877fa3174bSChandrakanth Patil mutex_lock(&instance->reset_mutex);
45882216c305SSumit Saxena break;
45892216c305SSumit Saxena case KILL_ADAPTER:
45902216c305SSumit Saxena megaraid_sas_kill_hba(instance);
45912216c305SSumit Saxena break;
45922216c305SSumit Saxena case IGNORE_TIMEOUT:
45932216c305SSumit Saxena dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
45942216c305SSumit Saxena __func__, __LINE__);
45952216c305SSumit Saxena break;
45962216c305SSumit Saxena }
45972216c305SSumit Saxena
45982216c305SSumit Saxena break;
45992216c305SSumit Saxena }
46002216c305SSumit Saxena
46012216c305SSumit Saxena if (ret != DCMD_TIMEOUT)
46022216c305SSumit Saxena megasas_return_cmd(instance, cmd);
46032216c305SSumit Saxena
460415dd0381SShivasharan S return;
46052216c305SSumit Saxena }
46066d40afbcSSumit Saxena /*
46070d49016bSadam radford * megasas_get_pd_list_info - Returns FW's pd_list structure
46080d49016bSadam radford * @instance: Adapter soft state
46090d49016bSadam radford * @pd_list: pd_list structure
46100d49016bSadam radford *
46110d49016bSadam radford * Issues an internal command (DCMD) to get the FW's controller PD
46120d49016bSadam radford * list structure. This information is mainly used to find out SYSTEM
46130d49016bSadam radford * supported by the FW.
46140d49016bSadam radford */
46150d49016bSadam radford static int
megasas_get_pd_list(struct megasas_instance * instance)46160d49016bSadam radford megasas_get_pd_list(struct megasas_instance *instance)
46170d49016bSadam radford {
46180d49016bSadam radford int ret = 0, pd_index = 0;
46190d49016bSadam radford struct megasas_cmd *cmd;
46200d49016bSadam radford struct megasas_dcmd_frame *dcmd;
46210d49016bSadam radford struct MR_PD_LIST *ci;
46220d49016bSadam radford struct MR_PD_ADDRESS *pd_addr;
46230d49016bSadam radford
4624d9083160SSumit Saxena if (instance->pd_list_not_supported) {
4625d9083160SSumit Saxena dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY "
4626d9083160SSumit Saxena "not supported by firmware\n");
4627d9083160SSumit Saxena return ret;
4628d9083160SSumit Saxena }
4629d9083160SSumit Saxena
46309b3d028fSShivasharan S ci = instance->pd_list_buf;
46319b3d028fSShivasharan S
46320d49016bSadam radford cmd = megasas_get_cmd(instance);
46330d49016bSadam radford
46340d49016bSadam radford if (!cmd) {
46351be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "(get_pd_list): Failed to get cmd\n");
46360d49016bSadam radford return -ENOMEM;
46370d49016bSadam radford }
46380d49016bSadam radford
46390d49016bSadam radford dcmd = &cmd->frame->dcmd;
46400d49016bSadam radford
46410d49016bSadam radford memset(ci, 0, sizeof(*ci));
46420d49016bSadam radford memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
46430d49016bSadam radford
46440d49016bSadam radford dcmd->mbox.b[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
46450d49016bSadam radford dcmd->mbox.b[1] = 0;
46460d49016bSadam radford dcmd->cmd = MFI_CMD_DCMD;
46472be2a988SSumit.Saxena@avagotech.com dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
46480d49016bSadam radford dcmd->sge_count = 1;
4649107a60ddSShivasharan S dcmd->flags = MFI_FRAME_DIR_READ;
46500d49016bSadam radford dcmd->timeout = 0;
46510d49016bSadam radford dcmd->pad_0 = 0;
465294cd65ddSSumit.Saxena@lsi.com dcmd->data_xfer_len = cpu_to_le32(MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST));
465394cd65ddSSumit.Saxena@lsi.com dcmd->opcode = cpu_to_le32(MR_DCMD_PD_LIST_QUERY);
46540d49016bSadam radford
4655107a60ddSShivasharan S megasas_set_dma_settings(instance, dcmd, instance->pd_list_buf_h,
4656107a60ddSShivasharan S (MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST)));
46570d49016bSadam radford
4658e7d36b88SShivasharan S if ((instance->adapter_type != MFI_SERIES) &&
4659e7d36b88SShivasharan S !instance->mask_interrupts)
466090dc9d98SSumit.Saxena@avagotech.com ret = megasas_issue_blocked_cmd(instance, cmd,
46616d40afbcSSumit Saxena MFI_IO_TIMEOUT_SECS);
466290dc9d98SSumit.Saxena@avagotech.com else
466390dc9d98SSumit.Saxena@avagotech.com ret = megasas_issue_polled(instance, cmd);
46640d49016bSadam radford
46656d40afbcSSumit Saxena switch (ret) {
46666d40afbcSSumit Saxena case DCMD_FAILED:
466730845586SSumit Saxena dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY "
466830845586SSumit Saxena "failed/not supported by firmware\n");
466930845586SSumit Saxena
4670e7d36b88SShivasharan S if (instance->adapter_type != MFI_SERIES)
46716d40afbcSSumit Saxena megaraid_sas_kill_hba(instance);
467230845586SSumit Saxena else
467330845586SSumit Saxena instance->pd_list_not_supported = 1;
46746d40afbcSSumit Saxena break;
46756d40afbcSSumit Saxena case DCMD_TIMEOUT:
46760d49016bSadam radford
46776d40afbcSSumit Saxena switch (dcmd_timeout_ocr_possible(instance)) {
46786d40afbcSSumit Saxena case INITIATE_OCR:
46796d40afbcSSumit Saxena cmd->flags |= DRV_DCMD_SKIP_REFIRE;
46806d40afbcSSumit Saxena /*
46816d40afbcSSumit Saxena * DCMD failed from AEN path.
46826d40afbcSSumit Saxena * AEN path already hold reset_mutex to avoid PCI access
46836d40afbcSSumit Saxena * while OCR is in progress.
46846d40afbcSSumit Saxena */
46856d40afbcSSumit Saxena mutex_unlock(&instance->reset_mutex);
46866d40afbcSSumit Saxena megasas_reset_fusion(instance->host,
46876d40afbcSSumit Saxena MFI_IO_TIMEOUT_OCR);
46886d40afbcSSumit Saxena mutex_lock(&instance->reset_mutex);
46896d40afbcSSumit Saxena break;
46906d40afbcSSumit Saxena case KILL_ADAPTER:
46916d40afbcSSumit Saxena megaraid_sas_kill_hba(instance);
46926d40afbcSSumit Saxena break;
46936d40afbcSSumit Saxena case IGNORE_TIMEOUT:
46946d40afbcSSumit Saxena dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d \n",
46956d40afbcSSumit Saxena __func__, __LINE__);
46966d40afbcSSumit Saxena break;
46976d40afbcSSumit Saxena }
46986d40afbcSSumit Saxena
46996d40afbcSSumit Saxena break;
47006d40afbcSSumit Saxena
47016d40afbcSSumit Saxena case DCMD_SUCCESS:
47020d49016bSadam radford pd_addr = ci->addr;
47030a11c0b0SShivasharan S if (megasas_dbg_lvl & LD_PD_DEBUG)
47040a11c0b0SShivasharan S dev_info(&instance->pdev->dev, "%s, sysPD count: 0x%x\n",
47050a11c0b0SShivasharan S __func__, le32_to_cpu(ci->count));
47060d49016bSadam radford
47076d40afbcSSumit Saxena if ((le32_to_cpu(ci->count) >
47086d40afbcSSumit Saxena (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL)))
47096d40afbcSSumit Saxena break;
47100d49016bSadam radford
4711999ece0aSSumit.Saxena@lsi.com memset(instance->local_pd_list, 0,
47120d49016bSadam radford MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
47130d49016bSadam radford
471494cd65ddSSumit.Saxena@lsi.com for (pd_index = 0; pd_index < le32_to_cpu(ci->count); pd_index++) {
4715999ece0aSSumit.Saxena@lsi.com instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].tid =
471694cd65ddSSumit.Saxena@lsi.com le16_to_cpu(pd_addr->deviceId);
4717999ece0aSSumit.Saxena@lsi.com instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveType =
47180d49016bSadam radford pd_addr->scsiDevType;
4719999ece0aSSumit.Saxena@lsi.com instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveState =
47200d49016bSadam radford MR_PD_STATE_SYSTEM;
47210a11c0b0SShivasharan S if (megasas_dbg_lvl & LD_PD_DEBUG)
47220a11c0b0SShivasharan S dev_info(&instance->pdev->dev,
47230a11c0b0SShivasharan S "PD%d: targetID: 0x%03x deviceType:0x%x\n",
47240a11c0b0SShivasharan S pd_index, le16_to_cpu(pd_addr->deviceId),
47250a11c0b0SShivasharan S pd_addr->scsiDevType);
47260d49016bSadam radford pd_addr++;
47270d49016bSadam radford }
47286d40afbcSSumit Saxena
4729999ece0aSSumit.Saxena@lsi.com memcpy(instance->pd_list, instance->local_pd_list,
4730999ece0aSSumit.Saxena@lsi.com sizeof(instance->pd_list));
47316d40afbcSSumit Saxena break;
47326d40afbcSSumit Saxena
47330d49016bSadam radford }
47340d49016bSadam radford
47356d40afbcSSumit Saxena if (ret != DCMD_TIMEOUT)
47360d49016bSadam radford megasas_return_cmd(instance, cmd);
47370d49016bSadam radford
47380d49016bSadam radford return ret;
47390d49016bSadam radford }
47400d49016bSadam radford
47410d49016bSadam radford /*
47420d49016bSadam radford * megasas_get_ld_list_info - Returns FW's ld_list structure
47430d49016bSadam radford * @instance: Adapter soft state
47440d49016bSadam radford * @ld_list: ld_list structure
47450d49016bSadam radford *
47460d49016bSadam radford * Issues an internal command (DCMD) to get the FW's controller PD
47470d49016bSadam radford * list structure. This information is mainly used to find out SYSTEM
47480d49016bSadam radford * supported by the FW.
47490d49016bSadam radford */
47500d49016bSadam radford static int
megasas_get_ld_list(struct megasas_instance * instance)47510d49016bSadam radford megasas_get_ld_list(struct megasas_instance *instance)
47520d49016bSadam radford {
47530d49016bSadam radford int ret = 0, ld_index = 0, ids = 0;
47540d49016bSadam radford struct megasas_cmd *cmd;
47550d49016bSadam radford struct megasas_dcmd_frame *dcmd;
47560d49016bSadam radford struct MR_LD_LIST *ci;
47570d49016bSadam radford dma_addr_t ci_h = 0;
475894cd65ddSSumit.Saxena@lsi.com u32 ld_count;
47590d49016bSadam radford
47609b3d028fSShivasharan S ci = instance->ld_list_buf;
47619b3d028fSShivasharan S ci_h = instance->ld_list_buf_h;
47629b3d028fSShivasharan S
47630d49016bSadam radford cmd = megasas_get_cmd(instance);
47640d49016bSadam radford
47650d49016bSadam radford if (!cmd) {
47661be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_list: Failed to get cmd\n");
47670d49016bSadam radford return -ENOMEM;
47680d49016bSadam radford }
47690d49016bSadam radford
47700d49016bSadam radford dcmd = &cmd->frame->dcmd;
47710d49016bSadam radford
47720d49016bSadam radford memset(ci, 0, sizeof(*ci));
47730d49016bSadam radford memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
47740d49016bSadam radford
477551087a86SSumit.Saxena@avagotech.com if (instance->supportmax256vd)
477651087a86SSumit.Saxena@avagotech.com dcmd->mbox.b[0] = 1;
47770d49016bSadam radford dcmd->cmd = MFI_CMD_DCMD;
47782be2a988SSumit.Saxena@avagotech.com dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
47790d49016bSadam radford dcmd->sge_count = 1;
4780107a60ddSShivasharan S dcmd->flags = MFI_FRAME_DIR_READ;
47810d49016bSadam radford dcmd->timeout = 0;
478294cd65ddSSumit.Saxena@lsi.com dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_LD_LIST));
478394cd65ddSSumit.Saxena@lsi.com dcmd->opcode = cpu_to_le32(MR_DCMD_LD_GET_LIST);
47840d49016bSadam radford dcmd->pad_0 = 0;
47850d49016bSadam radford
4786107a60ddSShivasharan S megasas_set_dma_settings(instance, dcmd, ci_h,
4787107a60ddSShivasharan S sizeof(struct MR_LD_LIST));
4788107a60ddSShivasharan S
4789e7d36b88SShivasharan S if ((instance->adapter_type != MFI_SERIES) &&
4790e7d36b88SShivasharan S !instance->mask_interrupts)
479190dc9d98SSumit.Saxena@avagotech.com ret = megasas_issue_blocked_cmd(instance, cmd,
47926d40afbcSSumit Saxena MFI_IO_TIMEOUT_SECS);
479390dc9d98SSumit.Saxena@avagotech.com else
479490dc9d98SSumit.Saxena@avagotech.com ret = megasas_issue_polled(instance, cmd);
479590dc9d98SSumit.Saxena@avagotech.com
479694cd65ddSSumit.Saxena@lsi.com ld_count = le32_to_cpu(ci->ldCount);
479794cd65ddSSumit.Saxena@lsi.com
47986d40afbcSSumit Saxena switch (ret) {
47996d40afbcSSumit Saxena case DCMD_FAILED:
48006d40afbcSSumit Saxena megaraid_sas_kill_hba(instance);
48016d40afbcSSumit Saxena break;
48026d40afbcSSumit Saxena case DCMD_TIMEOUT:
48030d49016bSadam radford
48046d40afbcSSumit Saxena switch (dcmd_timeout_ocr_possible(instance)) {
48056d40afbcSSumit Saxena case INITIATE_OCR:
48066d40afbcSSumit Saxena cmd->flags |= DRV_DCMD_SKIP_REFIRE;
48076d40afbcSSumit Saxena /*
48086d40afbcSSumit Saxena * DCMD failed from AEN path.
48096d40afbcSSumit Saxena * AEN path already hold reset_mutex to avoid PCI access
48106d40afbcSSumit Saxena * while OCR is in progress.
48116d40afbcSSumit Saxena */
48126d40afbcSSumit Saxena mutex_unlock(&instance->reset_mutex);
48136d40afbcSSumit Saxena megasas_reset_fusion(instance->host,
48146d40afbcSSumit Saxena MFI_IO_TIMEOUT_OCR);
48156d40afbcSSumit Saxena mutex_lock(&instance->reset_mutex);
48166d40afbcSSumit Saxena break;
48176d40afbcSSumit Saxena case KILL_ADAPTER:
48186d40afbcSSumit Saxena megaraid_sas_kill_hba(instance);
48196d40afbcSSumit Saxena break;
48206d40afbcSSumit Saxena case IGNORE_TIMEOUT:
48216d40afbcSSumit Saxena dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
48226d40afbcSSumit Saxena __func__, __LINE__);
48236d40afbcSSumit Saxena break;
48246d40afbcSSumit Saxena }
48256d40afbcSSumit Saxena
48266d40afbcSSumit Saxena break;
48276d40afbcSSumit Saxena
48286d40afbcSSumit Saxena case DCMD_SUCCESS:
48290a11c0b0SShivasharan S if (megasas_dbg_lvl & LD_PD_DEBUG)
48300a11c0b0SShivasharan S dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n",
48310a11c0b0SShivasharan S __func__, ld_count);
48320a11c0b0SShivasharan S
48336d40afbcSSumit Saxena if (ld_count > instance->fw_supported_vd_count)
48346d40afbcSSumit Saxena break;
48356d40afbcSSumit Saxena
483651087a86SSumit.Saxena@avagotech.com memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT);
48370d49016bSadam radford
483894cd65ddSSumit.Saxena@lsi.com for (ld_index = 0; ld_index < ld_count; ld_index++) {
48390d49016bSadam radford if (ci->ldList[ld_index].state != 0) {
48400d49016bSadam radford ids = ci->ldList[ld_index].ref.targetId;
48416d40afbcSSumit Saxena instance->ld_ids[ids] = ci->ldList[ld_index].ref.targetId;
48420a11c0b0SShivasharan S if (megasas_dbg_lvl & LD_PD_DEBUG)
48430a11c0b0SShivasharan S dev_info(&instance->pdev->dev,
48440a11c0b0SShivasharan S "LD%d: targetID: 0x%03x\n",
48450a11c0b0SShivasharan S ld_index, ids);
48460d49016bSadam radford }
48470d49016bSadam radford }
48480d49016bSadam radford
48496d40afbcSSumit Saxena break;
48506d40afbcSSumit Saxena }
48510d49016bSadam radford
48526d40afbcSSumit Saxena if (ret != DCMD_TIMEOUT)
48530d49016bSadam radford megasas_return_cmd(instance, cmd);
48546d40afbcSSumit Saxena
48550d49016bSadam radford return ret;
48560d49016bSadam radford }
48570d49016bSadam radford
48580d49016bSadam radford /**
485921c9e160Sadam radford * megasas_ld_list_query - Returns FW's ld_list structure
486021c9e160Sadam radford * @instance: Adapter soft state
48612b46e5c1SDamien Le Moal * @query_type: ld_list structure type
486221c9e160Sadam radford *
486321c9e160Sadam radford * Issues an internal command (DCMD) to get the FW's controller PD
486421c9e160Sadam radford * list structure. This information is mainly used to find out SYSTEM
486521c9e160Sadam radford * supported by the FW.
486621c9e160Sadam radford */
486721c9e160Sadam radford static int
megasas_ld_list_query(struct megasas_instance * instance,u8 query_type)486821c9e160Sadam radford megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
486921c9e160Sadam radford {
487021c9e160Sadam radford int ret = 0, ld_index = 0, ids = 0;
487121c9e160Sadam radford struct megasas_cmd *cmd;
487221c9e160Sadam radford struct megasas_dcmd_frame *dcmd;
487321c9e160Sadam radford struct MR_LD_TARGETID_LIST *ci;
487421c9e160Sadam radford dma_addr_t ci_h = 0;
487594cd65ddSSumit.Saxena@lsi.com u32 tgtid_count;
487621c9e160Sadam radford
48779b3d028fSShivasharan S ci = instance->ld_targetid_list_buf;
48789b3d028fSShivasharan S ci_h = instance->ld_targetid_list_buf_h;
48799b3d028fSShivasharan S
488021c9e160Sadam radford cmd = megasas_get_cmd(instance);
488121c9e160Sadam radford
488221c9e160Sadam radford if (!cmd) {
48831be18254SBjorn Helgaas dev_warn(&instance->pdev->dev,
48841be18254SBjorn Helgaas "megasas_ld_list_query: Failed to get cmd\n");
488521c9e160Sadam radford return -ENOMEM;
488621c9e160Sadam radford }
488721c9e160Sadam radford
488821c9e160Sadam radford dcmd = &cmd->frame->dcmd;
488921c9e160Sadam radford
489021c9e160Sadam radford memset(ci, 0, sizeof(*ci));
489121c9e160Sadam radford memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
489221c9e160Sadam radford
489321c9e160Sadam radford dcmd->mbox.b[0] = query_type;
489451087a86SSumit.Saxena@avagotech.com if (instance->supportmax256vd)
489551087a86SSumit.Saxena@avagotech.com dcmd->mbox.b[2] = 1;
489621c9e160Sadam radford
489721c9e160Sadam radford dcmd->cmd = MFI_CMD_DCMD;
48982be2a988SSumit.Saxena@avagotech.com dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
489921c9e160Sadam radford dcmd->sge_count = 1;
4900107a60ddSShivasharan S dcmd->flags = MFI_FRAME_DIR_READ;
490121c9e160Sadam radford dcmd->timeout = 0;
490294cd65ddSSumit.Saxena@lsi.com dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_LD_TARGETID_LIST));
490394cd65ddSSumit.Saxena@lsi.com dcmd->opcode = cpu_to_le32(MR_DCMD_LD_LIST_QUERY);
490421c9e160Sadam radford dcmd->pad_0 = 0;
490521c9e160Sadam radford
4906107a60ddSShivasharan S megasas_set_dma_settings(instance, dcmd, ci_h,
4907107a60ddSShivasharan S sizeof(struct MR_LD_TARGETID_LIST));
4908107a60ddSShivasharan S
4909e7d36b88SShivasharan S if ((instance->adapter_type != MFI_SERIES) &&
4910e7d36b88SShivasharan S !instance->mask_interrupts)
49116d40afbcSSumit Saxena ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
491290dc9d98SSumit.Saxena@avagotech.com else
491390dc9d98SSumit.Saxena@avagotech.com ret = megasas_issue_polled(instance, cmd);
491421c9e160Sadam radford
49156d40afbcSSumit Saxena switch (ret) {
49166d40afbcSSumit Saxena case DCMD_FAILED:
49176d40afbcSSumit Saxena dev_info(&instance->pdev->dev,
49186d40afbcSSumit Saxena "DCMD not supported by firmware - %s %d\n",
49196d40afbcSSumit Saxena __func__, __LINE__);
49206d40afbcSSumit Saxena ret = megasas_get_ld_list(instance);
49216d40afbcSSumit Saxena break;
49226d40afbcSSumit Saxena case DCMD_TIMEOUT:
49236d40afbcSSumit Saxena switch (dcmd_timeout_ocr_possible(instance)) {
49246d40afbcSSumit Saxena case INITIATE_OCR:
49256d40afbcSSumit Saxena cmd->flags |= DRV_DCMD_SKIP_REFIRE;
49266d40afbcSSumit Saxena /*
49276d40afbcSSumit Saxena * DCMD failed from AEN path.
49286d40afbcSSumit Saxena * AEN path already hold reset_mutex to avoid PCI access
49296d40afbcSSumit Saxena * while OCR is in progress.
49306d40afbcSSumit Saxena */
49316d40afbcSSumit Saxena mutex_unlock(&instance->reset_mutex);
49326d40afbcSSumit Saxena megasas_reset_fusion(instance->host,
49336d40afbcSSumit Saxena MFI_IO_TIMEOUT_OCR);
49346d40afbcSSumit Saxena mutex_lock(&instance->reset_mutex);
49356d40afbcSSumit Saxena break;
49366d40afbcSSumit Saxena case KILL_ADAPTER:
49376d40afbcSSumit Saxena megaraid_sas_kill_hba(instance);
49386d40afbcSSumit Saxena break;
49396d40afbcSSumit Saxena case IGNORE_TIMEOUT:
49406d40afbcSSumit Saxena dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
49416d40afbcSSumit Saxena __func__, __LINE__);
49426d40afbcSSumit Saxena break;
49436d40afbcSSumit Saxena }
49446d40afbcSSumit Saxena
49456d40afbcSSumit Saxena break;
49466d40afbcSSumit Saxena case DCMD_SUCCESS:
494794cd65ddSSumit.Saxena@lsi.com tgtid_count = le32_to_cpu(ci->count);
494894cd65ddSSumit.Saxena@lsi.com
49490a11c0b0SShivasharan S if (megasas_dbg_lvl & LD_PD_DEBUG)
49500a11c0b0SShivasharan S dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n",
49510a11c0b0SShivasharan S __func__, tgtid_count);
49520a11c0b0SShivasharan S
49536d40afbcSSumit Saxena if ((tgtid_count > (instance->fw_supported_vd_count)))
49546d40afbcSSumit Saxena break;
49556d40afbcSSumit Saxena
495621c9e160Sadam radford memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
495794cd65ddSSumit.Saxena@lsi.com for (ld_index = 0; ld_index < tgtid_count; ld_index++) {
495821c9e160Sadam radford ids = ci->targetId[ld_index];
495921c9e160Sadam radford instance->ld_ids[ids] = ci->targetId[ld_index];
49600a11c0b0SShivasharan S if (megasas_dbg_lvl & LD_PD_DEBUG)
49610a11c0b0SShivasharan S dev_info(&instance->pdev->dev, "LD%d: targetID: 0x%03x\n",
49620a11c0b0SShivasharan S ld_index, ci->targetId[ld_index]);
496321c9e160Sadam radford }
496421c9e160Sadam radford
49656d40afbcSSumit Saxena break;
496621c9e160Sadam radford }
496721c9e160Sadam radford
49686d40afbcSSumit Saxena if (ret != DCMD_TIMEOUT)
496921c9e160Sadam radford megasas_return_cmd(instance, cmd);
497021c9e160Sadam radford
497121c9e160Sadam radford return ret;
497221c9e160Sadam radford }
497321c9e160Sadam radford
4974f6fe5731SShivasharan S /**
4975616f6d8dSLee Jones * megasas_host_device_list_query
4976f6fe5731SShivasharan S * dcmd.opcode - MR_DCMD_CTRL_DEVICE_LIST_GET
4977f6fe5731SShivasharan S * dcmd.mbox - reserved
4978f6fe5731SShivasharan S * dcmd.sge IN - ptr to return MR_HOST_DEVICE_LIST structure
4979f6fe5731SShivasharan S * Desc: This DCMD will return the combined device list
4980f6fe5731SShivasharan S * Status: MFI_STAT_OK - List returned successfully
4981f6fe5731SShivasharan S * MFI_STAT_INVALID_CMD - Firmware support for the feature has been
4982f6fe5731SShivasharan S * disabled
4983f6fe5731SShivasharan S * @instance: Adapter soft state
4984f6fe5731SShivasharan S * @is_probe: Driver probe check
4985f6fe5731SShivasharan S * Return: 0 if DCMD succeeded
4986f6fe5731SShivasharan S * non-zero if failed
4987f6fe5731SShivasharan S */
49887c3f8ca8SYueHaibing static int
megasas_host_device_list_query(struct megasas_instance * instance,bool is_probe)4989f6fe5731SShivasharan S megasas_host_device_list_query(struct megasas_instance *instance,
4990f6fe5731SShivasharan S bool is_probe)
4991f6fe5731SShivasharan S {
4992f6fe5731SShivasharan S int ret, i, target_id;
4993f6fe5731SShivasharan S struct megasas_cmd *cmd;
4994f6fe5731SShivasharan S struct megasas_dcmd_frame *dcmd;
4995f6fe5731SShivasharan S struct MR_HOST_DEVICE_LIST *ci;
4996f6fe5731SShivasharan S u32 count;
4997f6fe5731SShivasharan S dma_addr_t ci_h;
4998f6fe5731SShivasharan S
4999f6fe5731SShivasharan S ci = instance->host_device_list_buf;
5000f6fe5731SShivasharan S ci_h = instance->host_device_list_buf_h;
5001f6fe5731SShivasharan S
5002f6fe5731SShivasharan S cmd = megasas_get_cmd(instance);
5003f6fe5731SShivasharan S
5004f6fe5731SShivasharan S if (!cmd) {
5005f6fe5731SShivasharan S dev_warn(&instance->pdev->dev,
5006f6fe5731SShivasharan S "%s: failed to get cmd\n",
5007f6fe5731SShivasharan S __func__);
5008f6fe5731SShivasharan S return -ENOMEM;
5009f6fe5731SShivasharan S }
5010f6fe5731SShivasharan S
5011f6fe5731SShivasharan S dcmd = &cmd->frame->dcmd;
5012f6fe5731SShivasharan S
5013f6fe5731SShivasharan S memset(ci, 0, sizeof(*ci));
5014f6fe5731SShivasharan S memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
5015f6fe5731SShivasharan S
5016f6fe5731SShivasharan S dcmd->mbox.b[0] = is_probe ? 0 : 1;
5017f6fe5731SShivasharan S dcmd->cmd = MFI_CMD_DCMD;
5018f6fe5731SShivasharan S dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
5019f6fe5731SShivasharan S dcmd->sge_count = 1;
5020f6fe5731SShivasharan S dcmd->flags = MFI_FRAME_DIR_READ;
5021f6fe5731SShivasharan S dcmd->timeout = 0;
5022f6fe5731SShivasharan S dcmd->pad_0 = 0;
5023f6fe5731SShivasharan S dcmd->data_xfer_len = cpu_to_le32(HOST_DEVICE_LIST_SZ);
5024f6fe5731SShivasharan S dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_DEVICE_LIST_GET);
5025f6fe5731SShivasharan S
5026f6fe5731SShivasharan S megasas_set_dma_settings(instance, dcmd, ci_h, HOST_DEVICE_LIST_SZ);
5027f6fe5731SShivasharan S
5028f6fe5731SShivasharan S if (!instance->mask_interrupts) {
5029f6fe5731SShivasharan S ret = megasas_issue_blocked_cmd(instance, cmd,
5030f6fe5731SShivasharan S MFI_IO_TIMEOUT_SECS);
5031f6fe5731SShivasharan S } else {
5032f6fe5731SShivasharan S ret = megasas_issue_polled(instance, cmd);
5033f6fe5731SShivasharan S cmd->flags |= DRV_DCMD_SKIP_REFIRE;
5034f6fe5731SShivasharan S }
5035f6fe5731SShivasharan S
5036f6fe5731SShivasharan S switch (ret) {
5037f6fe5731SShivasharan S case DCMD_SUCCESS:
5038f6fe5731SShivasharan S /* Fill the internal pd_list and ld_ids array based on
5039f6fe5731SShivasharan S * targetIds returned by FW
5040f6fe5731SShivasharan S */
5041f6fe5731SShivasharan S count = le32_to_cpu(ci->count);
5042f6fe5731SShivasharan S
5043a4413a58SChandrakanth Patil if (count > (MEGASAS_MAX_PD + MAX_LOGICAL_DRIVES_EXT))
5044a4413a58SChandrakanth Patil break;
5045a4413a58SChandrakanth Patil
50460a11c0b0SShivasharan S if (megasas_dbg_lvl & LD_PD_DEBUG)
50470a11c0b0SShivasharan S dev_info(&instance->pdev->dev, "%s, Device count: 0x%x\n",
50480a11c0b0SShivasharan S __func__, count);
50490a11c0b0SShivasharan S
5050f6fe5731SShivasharan S memset(instance->local_pd_list, 0,
5051f6fe5731SShivasharan S MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
5052f6fe5731SShivasharan S memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT);
5053f6fe5731SShivasharan S for (i = 0; i < count; i++) {
5054f6fe5731SShivasharan S target_id = le16_to_cpu(ci->host_device_list[i].target_id);
5055f6fe5731SShivasharan S if (ci->host_device_list[i].flags.u.bits.is_sys_pd) {
5056f6fe5731SShivasharan S instance->local_pd_list[target_id].tid = target_id;
5057f6fe5731SShivasharan S instance->local_pd_list[target_id].driveType =
5058f6fe5731SShivasharan S ci->host_device_list[i].scsi_type;
5059f6fe5731SShivasharan S instance->local_pd_list[target_id].driveState =
5060f6fe5731SShivasharan S MR_PD_STATE_SYSTEM;
50610a11c0b0SShivasharan S if (megasas_dbg_lvl & LD_PD_DEBUG)
50620a11c0b0SShivasharan S dev_info(&instance->pdev->dev,
50630a11c0b0SShivasharan S "Device %d: PD targetID: 0x%03x deviceType:0x%x\n",
50640a11c0b0SShivasharan S i, target_id, ci->host_device_list[i].scsi_type);
5065f6fe5731SShivasharan S } else {
5066f6fe5731SShivasharan S instance->ld_ids[target_id] = target_id;
50670a11c0b0SShivasharan S if (megasas_dbg_lvl & LD_PD_DEBUG)
50680a11c0b0SShivasharan S dev_info(&instance->pdev->dev,
50690a11c0b0SShivasharan S "Device %d: LD targetID: 0x%03x\n",
50700a11c0b0SShivasharan S i, target_id);
5071f6fe5731SShivasharan S }
5072f6fe5731SShivasharan S }
5073f6fe5731SShivasharan S
5074f6fe5731SShivasharan S memcpy(instance->pd_list, instance->local_pd_list,
5075f6fe5731SShivasharan S sizeof(instance->pd_list));
5076f6fe5731SShivasharan S break;
5077f6fe5731SShivasharan S
5078f6fe5731SShivasharan S case DCMD_TIMEOUT:
5079f6fe5731SShivasharan S switch (dcmd_timeout_ocr_possible(instance)) {
5080f6fe5731SShivasharan S case INITIATE_OCR:
5081f6fe5731SShivasharan S cmd->flags |= DRV_DCMD_SKIP_REFIRE;
50827fa3174bSChandrakanth Patil mutex_unlock(&instance->reset_mutex);
5083f6fe5731SShivasharan S megasas_reset_fusion(instance->host,
5084f6fe5731SShivasharan S MFI_IO_TIMEOUT_OCR);
50857fa3174bSChandrakanth Patil mutex_lock(&instance->reset_mutex);
5086f6fe5731SShivasharan S break;
5087f6fe5731SShivasharan S case KILL_ADAPTER:
5088f6fe5731SShivasharan S megaraid_sas_kill_hba(instance);
5089f6fe5731SShivasharan S break;
5090f6fe5731SShivasharan S case IGNORE_TIMEOUT:
5091f6fe5731SShivasharan S dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
5092f6fe5731SShivasharan S __func__, __LINE__);
5093f6fe5731SShivasharan S break;
5094f6fe5731SShivasharan S }
5095f6fe5731SShivasharan S break;
5096f6fe5731SShivasharan S case DCMD_FAILED:
5097f6fe5731SShivasharan S dev_err(&instance->pdev->dev,
5098f6fe5731SShivasharan S "%s: MR_DCMD_CTRL_DEVICE_LIST_GET failed\n",
5099f6fe5731SShivasharan S __func__);
5100f6fe5731SShivasharan S break;
5101f6fe5731SShivasharan S }
5102f6fe5731SShivasharan S
5103f6fe5731SShivasharan S if (ret != DCMD_TIMEOUT)
5104f6fe5731SShivasharan S megasas_return_cmd(instance, cmd);
5105f6fe5731SShivasharan S
5106f6fe5731SShivasharan S return ret;
5107f6fe5731SShivasharan S }
5108f6fe5731SShivasharan S
5109d009b576SSumit.Saxena@avagotech.com /*
5110d009b576SSumit.Saxena@avagotech.com * megasas_update_ext_vd_details : Update details w.r.t Extended VD
5111d009b576SSumit.Saxena@avagotech.com * instance : Controller's instance
5112d009b576SSumit.Saxena@avagotech.com */
megasas_update_ext_vd_details(struct megasas_instance * instance)5113d009b576SSumit.Saxena@avagotech.com static void megasas_update_ext_vd_details(struct megasas_instance *instance)
5114d009b576SSumit.Saxena@avagotech.com {
5115d009b576SSumit.Saxena@avagotech.com struct fusion_context *fusion;
5116d889344eSSasikumar Chandrasekaran u32 ventura_map_sz = 0;
5117d009b576SSumit.Saxena@avagotech.com
5118d009b576SSumit.Saxena@avagotech.com fusion = instance->ctrl_context;
5119d009b576SSumit.Saxena@avagotech.com /* For MFI based controllers return dummy success */
5120d009b576SSumit.Saxena@avagotech.com if (!fusion)
5121d009b576SSumit.Saxena@avagotech.com return;
5122d009b576SSumit.Saxena@avagotech.com
5123d009b576SSumit.Saxena@avagotech.com instance->supportmax256vd =
51249ad18a9cSShivasharan S instance->ctrl_info_buf->adapterOperations3.supportMaxExtLDs;
5125d009b576SSumit.Saxena@avagotech.com /* Below is additional check to address future FW enhancement */
51269ad18a9cSShivasharan S if (instance->ctrl_info_buf->max_lds > 64)
5127d009b576SSumit.Saxena@avagotech.com instance->supportmax256vd = 1;
5128d009b576SSumit.Saxena@avagotech.com
5129d009b576SSumit.Saxena@avagotech.com instance->drv_supported_vd_count = MEGASAS_MAX_LD_CHANNELS
5130d009b576SSumit.Saxena@avagotech.com * MEGASAS_MAX_DEV_PER_CHANNEL;
5131d009b576SSumit.Saxena@avagotech.com instance->drv_supported_pd_count = MEGASAS_MAX_PD_CHANNELS
5132d009b576SSumit.Saxena@avagotech.com * MEGASAS_MAX_DEV_PER_CHANNEL;
5133d009b576SSumit.Saxena@avagotech.com if (instance->supportmax256vd) {
5134d009b576SSumit.Saxena@avagotech.com instance->fw_supported_vd_count = MAX_LOGICAL_DRIVES_EXT;
5135d009b576SSumit.Saxena@avagotech.com instance->fw_supported_pd_count = MAX_PHYSICAL_DEVICES;
5136d009b576SSumit.Saxena@avagotech.com } else {
5137d009b576SSumit.Saxena@avagotech.com instance->fw_supported_vd_count = MAX_LOGICAL_DRIVES;
5138d009b576SSumit.Saxena@avagotech.com instance->fw_supported_pd_count = MAX_PHYSICAL_DEVICES;
5139d009b576SSumit.Saxena@avagotech.com }
5140d88da09aSSumit.Saxena@avagotech.com
5141d88da09aSSumit.Saxena@avagotech.com dev_info(&instance->pdev->dev,
5142cba67d92SShivasharan S "FW provided supportMaxExtLDs: %d\tmax_lds: %d\n",
5143cba67d92SShivasharan S instance->ctrl_info_buf->adapterOperations3.supportMaxExtLDs ? 1 : 0,
5144cba67d92SShivasharan S instance->ctrl_info_buf->max_lds);
5145d009b576SSumit.Saxena@avagotech.com
5146d889344eSSasikumar Chandrasekaran if (instance->max_raid_mapsize) {
5147d889344eSSasikumar Chandrasekaran ventura_map_sz = instance->max_raid_mapsize *
5148d889344eSSasikumar Chandrasekaran MR_MIN_MAP_SIZE; /* 64k */
5149d889344eSSasikumar Chandrasekaran fusion->current_map_sz = ventura_map_sz;
5150d889344eSSasikumar Chandrasekaran fusion->max_map_sz = ventura_map_sz;
5151d889344eSSasikumar Chandrasekaran } else {
515241e83026SGustavo A. R. Silva fusion->old_map_sz =
5153d67790ddSKees Cook struct_size_t(struct MR_FW_RAID_MAP, ldSpanMap,
5154ac23b92bSGustavo A. R. Silva instance->fw_supported_vd_count);
5155d889344eSSasikumar Chandrasekaran fusion->new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT);
5156d009b576SSumit.Saxena@avagotech.com
5157d889344eSSasikumar Chandrasekaran fusion->max_map_sz =
5158d889344eSSasikumar Chandrasekaran max(fusion->old_map_sz, fusion->new_map_sz);
5159d009b576SSumit.Saxena@avagotech.com
5160d009b576SSumit.Saxena@avagotech.com if (instance->supportmax256vd)
5161d889344eSSasikumar Chandrasekaran fusion->current_map_sz = fusion->new_map_sz;
5162d009b576SSumit.Saxena@avagotech.com else
5163d889344eSSasikumar Chandrasekaran fusion->current_map_sz = fusion->old_map_sz;
5164d889344eSSasikumar Chandrasekaran }
5165d889344eSSasikumar Chandrasekaran /* irrespective of FW raid maps, driver raid map is constant */
5166d889344eSSasikumar Chandrasekaran fusion->drv_map_sz = sizeof(struct MR_DRV_RAID_MAP_ALL);
5167d009b576SSumit.Saxena@avagotech.com }
5168d009b576SSumit.Saxena@avagotech.com
5169f0c21df6SShivasharan S /*
5170f0c21df6SShivasharan S * dcmd.opcode - MR_DCMD_CTRL_SNAPDUMP_GET_PROPERTIES
5171f0c21df6SShivasharan S * dcmd.hdr.length - number of bytes to read
5172f0c21df6SShivasharan S * dcmd.sge - Ptr to MR_SNAPDUMP_PROPERTIES
5173f0c21df6SShivasharan S * Desc: Fill in snapdump properties
5174f0c21df6SShivasharan S * Status: MFI_STAT_OK- Command successful
5175f0c21df6SShivasharan S */
megasas_get_snapdump_properties(struct megasas_instance * instance)5176f0c21df6SShivasharan S void megasas_get_snapdump_properties(struct megasas_instance *instance)
5177f0c21df6SShivasharan S {
5178f0c21df6SShivasharan S int ret = 0;
5179f0c21df6SShivasharan S struct megasas_cmd *cmd;
5180f0c21df6SShivasharan S struct megasas_dcmd_frame *dcmd;
5181f0c21df6SShivasharan S struct MR_SNAPDUMP_PROPERTIES *ci;
5182f0c21df6SShivasharan S dma_addr_t ci_h = 0;
5183f0c21df6SShivasharan S
5184f0c21df6SShivasharan S ci = instance->snapdump_prop;
5185f0c21df6SShivasharan S ci_h = instance->snapdump_prop_h;
5186f0c21df6SShivasharan S
5187f0c21df6SShivasharan S if (!ci)
5188f0c21df6SShivasharan S return;
5189f0c21df6SShivasharan S
5190f0c21df6SShivasharan S cmd = megasas_get_cmd(instance);
5191f0c21df6SShivasharan S
5192f0c21df6SShivasharan S if (!cmd) {
5193f0c21df6SShivasharan S dev_dbg(&instance->pdev->dev, "Failed to get a free cmd\n");
5194f0c21df6SShivasharan S return;
5195f0c21df6SShivasharan S }
5196f0c21df6SShivasharan S
5197f0c21df6SShivasharan S dcmd = &cmd->frame->dcmd;
5198f0c21df6SShivasharan S
5199f0c21df6SShivasharan S memset(ci, 0, sizeof(*ci));
5200f0c21df6SShivasharan S memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
5201f0c21df6SShivasharan S
5202f0c21df6SShivasharan S dcmd->cmd = MFI_CMD_DCMD;
5203f0c21df6SShivasharan S dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
5204f0c21df6SShivasharan S dcmd->sge_count = 1;
5205f0c21df6SShivasharan S dcmd->flags = MFI_FRAME_DIR_READ;
5206f0c21df6SShivasharan S dcmd->timeout = 0;
5207f0c21df6SShivasharan S dcmd->pad_0 = 0;
5208f0c21df6SShivasharan S dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_SNAPDUMP_PROPERTIES));
5209f0c21df6SShivasharan S dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_SNAPDUMP_GET_PROPERTIES);
5210f0c21df6SShivasharan S
5211f0c21df6SShivasharan S megasas_set_dma_settings(instance, dcmd, ci_h,
5212f0c21df6SShivasharan S sizeof(struct MR_SNAPDUMP_PROPERTIES));
5213f0c21df6SShivasharan S
5214f0c21df6SShivasharan S if (!instance->mask_interrupts) {
5215f0c21df6SShivasharan S ret = megasas_issue_blocked_cmd(instance, cmd,
5216f0c21df6SShivasharan S MFI_IO_TIMEOUT_SECS);
5217f0c21df6SShivasharan S } else {
5218f0c21df6SShivasharan S ret = megasas_issue_polled(instance, cmd);
5219f0c21df6SShivasharan S cmd->flags |= DRV_DCMD_SKIP_REFIRE;
5220f0c21df6SShivasharan S }
5221f0c21df6SShivasharan S
5222f0c21df6SShivasharan S switch (ret) {
5223f0c21df6SShivasharan S case DCMD_SUCCESS:
5224f0c21df6SShivasharan S instance->snapdump_wait_time =
5225f0c21df6SShivasharan S min_t(u8, ci->trigger_min_num_sec_before_ocr,
5226f0c21df6SShivasharan S MEGASAS_MAX_SNAP_DUMP_WAIT_TIME);
5227f0c21df6SShivasharan S break;
5228f0c21df6SShivasharan S
5229f0c21df6SShivasharan S case DCMD_TIMEOUT:
5230f0c21df6SShivasharan S switch (dcmd_timeout_ocr_possible(instance)) {
5231f0c21df6SShivasharan S case INITIATE_OCR:
5232f0c21df6SShivasharan S cmd->flags |= DRV_DCMD_SKIP_REFIRE;
52337fa3174bSChandrakanth Patil mutex_unlock(&instance->reset_mutex);
5234f0c21df6SShivasharan S megasas_reset_fusion(instance->host,
5235f0c21df6SShivasharan S MFI_IO_TIMEOUT_OCR);
52367fa3174bSChandrakanth Patil mutex_lock(&instance->reset_mutex);
5237f0c21df6SShivasharan S break;
5238f0c21df6SShivasharan S case KILL_ADAPTER:
5239f0c21df6SShivasharan S megaraid_sas_kill_hba(instance);
5240f0c21df6SShivasharan S break;
5241f0c21df6SShivasharan S case IGNORE_TIMEOUT:
5242f0c21df6SShivasharan S dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
5243f0c21df6SShivasharan S __func__, __LINE__);
5244f0c21df6SShivasharan S break;
5245f0c21df6SShivasharan S }
5246f0c21df6SShivasharan S }
5247f0c21df6SShivasharan S
5248f0c21df6SShivasharan S if (ret != DCMD_TIMEOUT)
5249f0c21df6SShivasharan S megasas_return_cmd(instance, cmd);
5250f0c21df6SShivasharan S }
5251f0c21df6SShivasharan S
525221c9e160Sadam radford /**
5253616f6d8dSLee Jones * megasas_get_ctrl_info - Returns FW's controller structure
52540d49016bSadam radford * @instance: Adapter soft state
52550d49016bSadam radford *
52560d49016bSadam radford * Issues an internal command (DCMD) to get the FW's controller structure.
52570d49016bSadam radford * This information is mainly used to find out the maximum IO transfer per
52580d49016bSadam radford * command supported by the FW.
52590d49016bSadam radford */
526051087a86SSumit.Saxena@avagotech.com int
megasas_get_ctrl_info(struct megasas_instance * instance)5261d009b576SSumit.Saxena@avagotech.com megasas_get_ctrl_info(struct megasas_instance *instance)
52620d49016bSadam radford {
52630d49016bSadam radford int ret = 0;
52640d49016bSadam radford struct megasas_cmd *cmd;
52650d49016bSadam radford struct megasas_dcmd_frame *dcmd;
52660d49016bSadam radford struct megasas_ctrl_info *ci;
52670d49016bSadam radford dma_addr_t ci_h = 0;
52680d49016bSadam radford
52699b3d028fSShivasharan S ci = instance->ctrl_info_buf;
52709b3d028fSShivasharan S ci_h = instance->ctrl_info_buf_h;
5271d009b576SSumit.Saxena@avagotech.com
52720d49016bSadam radford cmd = megasas_get_cmd(instance);
52730d49016bSadam radford
52740d49016bSadam radford if (!cmd) {
52751be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get a free cmd\n");
52760d49016bSadam radford return -ENOMEM;
52770d49016bSadam radford }
52780d49016bSadam radford
52790d49016bSadam radford dcmd = &cmd->frame->dcmd;
52800d49016bSadam radford
52810d49016bSadam radford memset(ci, 0, sizeof(*ci));
52820d49016bSadam radford memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
52830d49016bSadam radford
52840d49016bSadam radford dcmd->cmd = MFI_CMD_DCMD;
52852be2a988SSumit.Saxena@avagotech.com dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
52860d49016bSadam radford dcmd->sge_count = 1;
5287107a60ddSShivasharan S dcmd->flags = MFI_FRAME_DIR_READ;
52880d49016bSadam radford dcmd->timeout = 0;
52890d49016bSadam radford dcmd->pad_0 = 0;
529094cd65ddSSumit.Saxena@lsi.com dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_ctrl_info));
529194cd65ddSSumit.Saxena@lsi.com dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_GET_INFO);
529251087a86SSumit.Saxena@avagotech.com dcmd->mbox.b[0] = 1;
52930d49016bSadam radford
5294107a60ddSShivasharan S megasas_set_dma_settings(instance, dcmd, ci_h,
5295107a60ddSShivasharan S sizeof(struct megasas_ctrl_info));
5296107a60ddSShivasharan S
5297e7d36b88SShivasharan S if ((instance->adapter_type != MFI_SERIES) &&
529854b28049SShivasharan S !instance->mask_interrupts) {
52996d40afbcSSumit Saxena ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
530054b28049SShivasharan S } else {
530190dc9d98SSumit.Saxena@avagotech.com ret = megasas_issue_polled(instance, cmd);
530254b28049SShivasharan S cmd->flags |= DRV_DCMD_SKIP_REFIRE;
530354b28049SShivasharan S }
530490dc9d98SSumit.Saxena@avagotech.com
53056d40afbcSSumit Saxena switch (ret) {
53066d40afbcSSumit Saxena case DCMD_SUCCESS:
53076d40afbcSSumit Saxena /* Save required controller information in
53086d40afbcSSumit Saxena * CPU endianness format.
53096d40afbcSSumit Saxena */
53109ad18a9cSShivasharan S le32_to_cpus((u32 *)&ci->properties.OnOffProperties);
5311f0c21df6SShivasharan S le16_to_cpus((u16 *)&ci->properties.on_off_properties2);
53129ad18a9cSShivasharan S le32_to_cpus((u32 *)&ci->adapterOperations2);
53139ad18a9cSShivasharan S le32_to_cpus((u32 *)&ci->adapterOperations3);
53149ad18a9cSShivasharan S le16_to_cpus((u16 *)&ci->adapter_operations4);
531558136856SChandrakanth Patil le32_to_cpus((u32 *)&ci->adapter_operations5);
53166d40afbcSSumit Saxena
53176d40afbcSSumit Saxena /* Update the latest Ext VD info.
53186d40afbcSSumit Saxena * From Init path, store current firmware details.
53196d40afbcSSumit Saxena * From OCR path, detect any firmware properties changes.
53206d40afbcSSumit Saxena * in case of Firmware upgrade without system reboot.
53216d40afbcSSumit Saxena */
5322d009b576SSumit.Saxena@avagotech.com megasas_update_ext_vd_details(instance);
532359db5a93SChandrakanth Patil instance->support_seqnum_jbod_fp =
53249ad18a9cSShivasharan S ci->adapterOperations3.useSeqNumJbodFP;
5325ede7c3ceSSasikumar Chandrasekaran instance->support_morethan256jbod =
53269ad18a9cSShivasharan S ci->adapter_operations4.support_pd_map_target_id;
5327f870bcbeSShivasharan S instance->support_nvme_passthru =
5328f870bcbeSShivasharan S ci->adapter_operations4.support_nvme_passthru;
532958136856SChandrakanth Patil instance->support_pci_lane_margining =
533058136856SChandrakanth Patil ci->adapter_operations5.support_pci_lane_margining;
5331e9495e2dSShivasharan S instance->task_abort_tmo = ci->TaskAbortTO;
5332e9495e2dSShivasharan S instance->max_reset_tmo = ci->MaxResetTO;
53336d40afbcSSumit Saxena
53346d40afbcSSumit Saxena /*Check whether controller is iMR or MR */
53359ad18a9cSShivasharan S instance->is_imr = (ci->memory_size ? 0 : 1);
5336f0c21df6SShivasharan S
5337f0c21df6SShivasharan S instance->snapdump_wait_time =
5338f0c21df6SShivasharan S (ci->properties.on_off_properties2.enable_snap_dump ?
5339f0c21df6SShivasharan S MEGASAS_DEFAULT_SNAP_DUMP_WAIT_TIME : 0);
5340f0c21df6SShivasharan S
5341f6fe5731SShivasharan S instance->enable_fw_dev_list =
5342f6fe5731SShivasharan S ci->properties.on_off_properties2.enable_fw_dev_list;
5343f6fe5731SShivasharan S
53444026e9aaSSumit.Saxena@avagotech.com dev_info(&instance->pdev->dev,
53454026e9aaSSumit.Saxena@avagotech.com "controller type\t: %s(%dMB)\n",
53464026e9aaSSumit.Saxena@avagotech.com instance->is_imr ? "iMR" : "MR",
53479ad18a9cSShivasharan S le16_to_cpu(ci->memory_size));
53486d40afbcSSumit Saxena
5349c4bd2654Ssumit.saxena@avagotech.com instance->disableOnlineCtrlReset =
53509ad18a9cSShivasharan S ci->properties.OnOffProperties.disableOnlineCtrlReset;
53513222251dSsumit.saxena@avagotech.com instance->secure_jbod_support =
53529ad18a9cSShivasharan S ci->adapterOperations3.supportSecurityonJBOD;
53536d40afbcSSumit Saxena dev_info(&instance->pdev->dev, "Online Controller Reset(OCR)\t: %s\n",
53546d40afbcSSumit Saxena instance->disableOnlineCtrlReset ? "Disabled" : "Enabled");
53553222251dSsumit.saxena@avagotech.com dev_info(&instance->pdev->dev, "Secure JBOD support\t: %s\n",
53563222251dSsumit.saxena@avagotech.com instance->secure_jbod_support ? "Yes" : "No");
5357f870bcbeSShivasharan S dev_info(&instance->pdev->dev, "NVMe passthru support\t: %s\n",
5358f870bcbeSShivasharan S instance->support_nvme_passthru ? "Yes" : "No");
5359e9495e2dSShivasharan S dev_info(&instance->pdev->dev,
5360e9495e2dSShivasharan S "FW provided TM TaskAbort/Reset timeout\t: %d secs/%d secs\n",
5361e9495e2dSShivasharan S instance->task_abort_tmo, instance->max_reset_tmo);
536259db5a93SChandrakanth Patil dev_info(&instance->pdev->dev, "JBOD sequence map support\t: %s\n",
536359db5a93SChandrakanth Patil instance->support_seqnum_jbod_fp ? "Yes" : "No");
536458136856SChandrakanth Patil dev_info(&instance->pdev->dev, "PCI Lane Margining support\t: %s\n",
536558136856SChandrakanth Patil instance->support_pci_lane_margining ? "Yes" : "No");
5366e9495e2dSShivasharan S
53676d40afbcSSumit Saxena break;
53686d40afbcSSumit Saxena
53696d40afbcSSumit Saxena case DCMD_TIMEOUT:
53706d40afbcSSumit Saxena switch (dcmd_timeout_ocr_possible(instance)) {
53716d40afbcSSumit Saxena case INITIATE_OCR:
53726d40afbcSSumit Saxena cmd->flags |= DRV_DCMD_SKIP_REFIRE;
53737fa3174bSChandrakanth Patil mutex_unlock(&instance->reset_mutex);
53746d40afbcSSumit Saxena megasas_reset_fusion(instance->host,
53756d40afbcSSumit Saxena MFI_IO_TIMEOUT_OCR);
53767fa3174bSChandrakanth Patil mutex_lock(&instance->reset_mutex);
53776d40afbcSSumit Saxena break;
53786d40afbcSSumit Saxena case KILL_ADAPTER:
53796d40afbcSSumit Saxena megaraid_sas_kill_hba(instance);
53806d40afbcSSumit Saxena break;
53816d40afbcSSumit Saxena case IGNORE_TIMEOUT:
53826d40afbcSSumit Saxena dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
53836d40afbcSSumit Saxena __func__, __LINE__);
53846d40afbcSSumit Saxena break;
53856d40afbcSSumit Saxena }
53862747e6beSShivasharan S break;
53876d40afbcSSumit Saxena case DCMD_FAILED:
53886d40afbcSSumit Saxena megaraid_sas_kill_hba(instance);
53896d40afbcSSumit Saxena break;
53906d40afbcSSumit Saxena
5391d009b576SSumit.Saxena@avagotech.com }
53920d49016bSadam radford
53932747e6beSShivasharan S if (ret != DCMD_TIMEOUT)
53940d49016bSadam radford megasas_return_cmd(instance, cmd);
53956d40afbcSSumit Saxena
53960d49016bSadam radford return ret;
53970d49016bSadam radford }
53980d49016bSadam radford
5399fc62b3fcSSumit.Saxena@avagotech.com /*
5400fc62b3fcSSumit.Saxena@avagotech.com * megasas_set_crash_dump_params - Sends address of crash dump DMA buffer
5401fc62b3fcSSumit.Saxena@avagotech.com * to firmware
5402fc62b3fcSSumit.Saxena@avagotech.com *
5403fc62b3fcSSumit.Saxena@avagotech.com * @instance: Adapter soft state
5404fc62b3fcSSumit.Saxena@avagotech.com * @crash_buf_state - tell FW to turn ON/OFF crash dump feature
5405fc62b3fcSSumit.Saxena@avagotech.com MR_CRASH_BUF_TURN_OFF = 0
5406fc62b3fcSSumit.Saxena@avagotech.com MR_CRASH_BUF_TURN_ON = 1
5407fc62b3fcSSumit.Saxena@avagotech.com * @return 0 on success non-zero on failure.
5408fc62b3fcSSumit.Saxena@avagotech.com * Issues an internal command (DCMD) to set parameters for crash dump feature.
5409fc62b3fcSSumit.Saxena@avagotech.com * Driver will send address of crash dump DMA buffer and set mbox to tell FW
5410fc62b3fcSSumit.Saxena@avagotech.com * that driver supports crash dump feature. This DCMD will be sent only if
5411fc62b3fcSSumit.Saxena@avagotech.com * crash dump feature is supported by the FW.
5412fc62b3fcSSumit.Saxena@avagotech.com *
5413fc62b3fcSSumit.Saxena@avagotech.com */
megasas_set_crash_dump_params(struct megasas_instance * instance,u8 crash_buf_state)5414fc62b3fcSSumit.Saxena@avagotech.com int megasas_set_crash_dump_params(struct megasas_instance *instance,
5415fc62b3fcSSumit.Saxena@avagotech.com u8 crash_buf_state)
5416fc62b3fcSSumit.Saxena@avagotech.com {
5417fc62b3fcSSumit.Saxena@avagotech.com int ret = 0;
5418fc62b3fcSSumit.Saxena@avagotech.com struct megasas_cmd *cmd;
5419fc62b3fcSSumit.Saxena@avagotech.com struct megasas_dcmd_frame *dcmd;
5420fc62b3fcSSumit.Saxena@avagotech.com
5421fc62b3fcSSumit.Saxena@avagotech.com cmd = megasas_get_cmd(instance);
5422fc62b3fcSSumit.Saxena@avagotech.com
5423fc62b3fcSSumit.Saxena@avagotech.com if (!cmd) {
5424fc62b3fcSSumit.Saxena@avagotech.com dev_err(&instance->pdev->dev, "Failed to get a free cmd\n");
5425fc62b3fcSSumit.Saxena@avagotech.com return -ENOMEM;
5426fc62b3fcSSumit.Saxena@avagotech.com }
5427fc62b3fcSSumit.Saxena@avagotech.com
5428fc62b3fcSSumit.Saxena@avagotech.com
5429fc62b3fcSSumit.Saxena@avagotech.com dcmd = &cmd->frame->dcmd;
5430fc62b3fcSSumit.Saxena@avagotech.com
5431fc62b3fcSSumit.Saxena@avagotech.com memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
5432fc62b3fcSSumit.Saxena@avagotech.com dcmd->mbox.b[0] = crash_buf_state;
5433fc62b3fcSSumit.Saxena@avagotech.com dcmd->cmd = MFI_CMD_DCMD;
54342be2a988SSumit.Saxena@avagotech.com dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
5435fc62b3fcSSumit.Saxena@avagotech.com dcmd->sge_count = 1;
5436107a60ddSShivasharan S dcmd->flags = MFI_FRAME_DIR_NONE;
5437fc62b3fcSSumit.Saxena@avagotech.com dcmd->timeout = 0;
5438fc62b3fcSSumit.Saxena@avagotech.com dcmd->pad_0 = 0;
5439fc62b3fcSSumit.Saxena@avagotech.com dcmd->data_xfer_len = cpu_to_le32(CRASH_DMA_BUF_SIZE);
5440fc62b3fcSSumit.Saxena@avagotech.com dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_SET_CRASH_DUMP_PARAMS);
5441fc62b3fcSSumit.Saxena@avagotech.com
5442107a60ddSShivasharan S megasas_set_dma_settings(instance, dcmd, instance->crash_dump_h,
5443107a60ddSShivasharan S CRASH_DMA_BUF_SIZE);
5444fc62b3fcSSumit.Saxena@avagotech.com
5445e7d36b88SShivasharan S if ((instance->adapter_type != MFI_SERIES) &&
5446e7d36b88SShivasharan S !instance->mask_interrupts)
54476d40afbcSSumit Saxena ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
5448fc62b3fcSSumit.Saxena@avagotech.com else
544990dc9d98SSumit.Saxena@avagotech.com ret = megasas_issue_polled(instance, cmd);
545090dc9d98SSumit.Saxena@avagotech.com
54516d40afbcSSumit Saxena if (ret == DCMD_TIMEOUT) {
54526d40afbcSSumit Saxena switch (dcmd_timeout_ocr_possible(instance)) {
54536d40afbcSSumit Saxena case INITIATE_OCR:
54546d40afbcSSumit Saxena cmd->flags |= DRV_DCMD_SKIP_REFIRE;
54556d40afbcSSumit Saxena megasas_reset_fusion(instance->host,
54566d40afbcSSumit Saxena MFI_IO_TIMEOUT_OCR);
54576d40afbcSSumit Saxena break;
54586d40afbcSSumit Saxena case KILL_ADAPTER:
54596d40afbcSSumit Saxena megaraid_sas_kill_hba(instance);
54606d40afbcSSumit Saxena break;
54616d40afbcSSumit Saxena case IGNORE_TIMEOUT:
54626d40afbcSSumit Saxena dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
54636d40afbcSSumit Saxena __func__, __LINE__);
54646d40afbcSSumit Saxena break;
54656d40afbcSSumit Saxena }
54666d40afbcSSumit Saxena } else
5467fc62b3fcSSumit.Saxena@avagotech.com megasas_return_cmd(instance, cmd);
54686d40afbcSSumit Saxena
5469fc62b3fcSSumit.Saxena@avagotech.com return ret;
5470fc62b3fcSSumit.Saxena@avagotech.com }
5471fc62b3fcSSumit.Saxena@avagotech.com
54720d49016bSadam radford /**
54730d49016bSadam radford * megasas_issue_init_mfi - Initializes the FW
54740d49016bSadam radford * @instance: Adapter soft state
54750d49016bSadam radford *
54760d49016bSadam radford * Issues the INIT MFI cmd
54770d49016bSadam radford */
54780d49016bSadam radford static int
megasas_issue_init_mfi(struct megasas_instance * instance)54790d49016bSadam radford megasas_issue_init_mfi(struct megasas_instance *instance)
54800d49016bSadam radford {
54819ab9ed38SChristoph Hellwig __le32 context;
54820d49016bSadam radford struct megasas_cmd *cmd;
54830d49016bSadam radford struct megasas_init_frame *init_frame;
54840d49016bSadam radford struct megasas_init_queue_info *initq_info;
54850d49016bSadam radford dma_addr_t init_frame_h;
54860d49016bSadam radford dma_addr_t initq_info_h;
54870d49016bSadam radford
54880d49016bSadam radford /*
54890d49016bSadam radford * Prepare a init frame. Note the init frame points to queue info
54900d49016bSadam radford * structure. Each frame has SGL allocated after first 64 bytes. For
54910d49016bSadam radford * this frame - since we don't need any SGL - we use SGL's space as
54920d49016bSadam radford * queue info structure
54930d49016bSadam radford *
54940d49016bSadam radford * We will not get a NULL command below. We just created the pool.
54950d49016bSadam radford */
54960d49016bSadam radford cmd = megasas_get_cmd(instance);
54970d49016bSadam radford
54980d49016bSadam radford init_frame = (struct megasas_init_frame *)cmd->frame;
54990d49016bSadam radford initq_info = (struct megasas_init_queue_info *)
55000d49016bSadam radford ((unsigned long)init_frame + 64);
55010d49016bSadam radford
55020d49016bSadam radford init_frame_h = cmd->frame_phys_addr;
55030d49016bSadam radford initq_info_h = init_frame_h + 64;
55040d49016bSadam radford
55050d49016bSadam radford context = init_frame->context;
55060d49016bSadam radford memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
55070d49016bSadam radford memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
55080d49016bSadam radford init_frame->context = context;
55090d49016bSadam radford
551094cd65ddSSumit.Saxena@lsi.com initq_info->reply_queue_entries = cpu_to_le32(instance->max_fw_cmds + 1);
551194cd65ddSSumit.Saxena@lsi.com initq_info->reply_queue_start_phys_addr_lo = cpu_to_le32(instance->reply_queue_h);
55120d49016bSadam radford
551394cd65ddSSumit.Saxena@lsi.com initq_info->producer_index_phys_addr_lo = cpu_to_le32(instance->producer_h);
551494cd65ddSSumit.Saxena@lsi.com initq_info->consumer_index_phys_addr_lo = cpu_to_le32(instance->consumer_h);
55150d49016bSadam radford
55160d49016bSadam radford init_frame->cmd = MFI_CMD_INIT;
55172be2a988SSumit.Saxena@avagotech.com init_frame->cmd_status = MFI_STAT_INVALID_STATUS;
551894cd65ddSSumit.Saxena@lsi.com init_frame->queue_info_new_phys_addr_lo =
551994cd65ddSSumit.Saxena@lsi.com cpu_to_le32(lower_32_bits(initq_info_h));
552094cd65ddSSumit.Saxena@lsi.com init_frame->queue_info_new_phys_addr_hi =
552194cd65ddSSumit.Saxena@lsi.com cpu_to_le32(upper_32_bits(initq_info_h));
55220d49016bSadam radford
552394cd65ddSSumit.Saxena@lsi.com init_frame->data_xfer_len = cpu_to_le32(sizeof(struct megasas_init_queue_info));
55240d49016bSadam radford
55250d49016bSadam radford /*
55260d49016bSadam radford * disable the intr before firing the init frame to FW
55270d49016bSadam radford */
5528d46a3ad6SSumit.Saxena@lsi.com instance->instancet->disable_intr(instance);
55290d49016bSadam radford
55300d49016bSadam radford /*
55310d49016bSadam radford * Issue the init frame in polled mode
55320d49016bSadam radford */
55330d49016bSadam radford
55340d49016bSadam radford if (megasas_issue_polled(instance, cmd)) {
55351be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "Failed to init firmware\n");
55360d49016bSadam radford megasas_return_cmd(instance, cmd);
55370d49016bSadam radford goto fail_fw_init;
55380d49016bSadam radford }
55390d49016bSadam radford
55400d49016bSadam radford megasas_return_cmd(instance, cmd);
55410d49016bSadam radford
55420d49016bSadam radford return 0;
55430d49016bSadam radford
55440d49016bSadam radford fail_fw_init:
55450d49016bSadam radford return -EINVAL;
55460d49016bSadam radford }
55470d49016bSadam radford
5548cd50ba8eSadam radford static u32
megasas_init_adapter_mfi(struct megasas_instance * instance)5549cd50ba8eSadam radford megasas_init_adapter_mfi(struct megasas_instance *instance)
55500d49016bSadam radford {
55510d49016bSadam radford u32 context_sz;
55520d49016bSadam radford u32 reply_q_sz;
55530d49016bSadam radford
55540d49016bSadam radford /*
55550d49016bSadam radford * Get various operational parameters from status register
55560d49016bSadam radford */
5557de516379SShivasharan S instance->max_fw_cmds = instance->instancet->read_fw_status_reg(instance) & 0x00FFFF;
55580d49016bSadam radford /*
55590d49016bSadam radford * Reduce the max supported cmds by 1. This is to ensure that the
55600d49016bSadam radford * reply_q_sz (1 more than the max cmd that driver may send)
55610d49016bSadam radford * does not exceed max cmds that the FW can support
55620d49016bSadam radford */
55630d49016bSadam radford instance->max_fw_cmds = instance->max_fw_cmds-1;
55649c915a8cSadam radford instance->max_mfi_cmds = instance->max_fw_cmds;
5565de516379SShivasharan S instance->max_num_sge = (instance->instancet->read_fw_status_reg(instance) & 0xFF0000) >>
55660d49016bSadam radford 0x10;
55670d49016bSadam radford /*
5568f26ac3a1SSumit.Saxena@avagotech.com * For MFI skinny adapters, MEGASAS_SKINNY_INT_CMDS commands
5569f26ac3a1SSumit.Saxena@avagotech.com * are reserved for IOCTL + driver's internal DCMDs.
5570f26ac3a1SSumit.Saxena@avagotech.com */
5571f26ac3a1SSumit.Saxena@avagotech.com if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
5572f26ac3a1SSumit.Saxena@avagotech.com (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
5573f26ac3a1SSumit.Saxena@avagotech.com instance->max_scsi_cmds = (instance->max_fw_cmds -
5574f26ac3a1SSumit.Saxena@avagotech.com MEGASAS_SKINNY_INT_CMDS);
5575f26ac3a1SSumit.Saxena@avagotech.com sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS);
5576f26ac3a1SSumit.Saxena@avagotech.com } else {
5577f26ac3a1SSumit.Saxena@avagotech.com instance->max_scsi_cmds = (instance->max_fw_cmds -
5578f26ac3a1SSumit.Saxena@avagotech.com MEGASAS_INT_CMDS);
5579f26ac3a1SSumit.Saxena@avagotech.com sema_init(&instance->ioctl_sem, (MEGASAS_MFI_IOCTL_CMDS));
5580f26ac3a1SSumit.Saxena@avagotech.com }
5581f26ac3a1SSumit.Saxena@avagotech.com
5582308ec459SSumit Saxena instance->cur_can_queue = instance->max_scsi_cmds;
5583f26ac3a1SSumit.Saxena@avagotech.com /*
55840d49016bSadam radford * Create a pool of commands
55850d49016bSadam radford */
55860d49016bSadam radford if (megasas_alloc_cmds(instance))
55870d49016bSadam radford goto fail_alloc_cmds;
55880d49016bSadam radford
55890d49016bSadam radford /*
55900d49016bSadam radford * Allocate memory for reply queue. Length of reply queue should
55910d49016bSadam radford * be _one_ more than the maximum commands handled by the firmware.
55920d49016bSadam radford *
55930d49016bSadam radford * Note: When FW completes commands, it places corresponding contex
55940d49016bSadam radford * values in this circular reply queue. This circular queue is a fairly
55950d49016bSadam radford * typical producer-consumer queue. FW is the producer (of completed
55960d49016bSadam radford * commands) and the driver is the consumer.
55970d49016bSadam radford */
55980d49016bSadam radford context_sz = sizeof(u32);
55990d49016bSadam radford reply_q_sz = context_sz * (instance->max_fw_cmds + 1);
56000d49016bSadam radford
560160ee6529SChristoph Hellwig instance->reply_queue = dma_alloc_coherent(&instance->pdev->dev,
560260ee6529SChristoph Hellwig reply_q_sz, &instance->reply_queue_h, GFP_KERNEL);
56030d49016bSadam radford
56040d49016bSadam radford if (!instance->reply_queue) {
56051be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "Out of DMA mem for reply queue\n");
56060d49016bSadam radford goto fail_reply_queue;
56070d49016bSadam radford }
56080d49016bSadam radford
56090d49016bSadam radford if (megasas_issue_init_mfi(instance))
56100d49016bSadam radford goto fail_fw_init;
56110d49016bSadam radford
5612d009b576SSumit.Saxena@avagotech.com if (megasas_get_ctrl_info(instance)) {
561351087a86SSumit.Saxena@avagotech.com dev_err(&instance->pdev->dev, "(%d): Could get controller info "
561451087a86SSumit.Saxena@avagotech.com "Fail from %s %d\n", instance->unique_id,
561551087a86SSumit.Saxena@avagotech.com __func__, __LINE__);
561651087a86SSumit.Saxena@avagotech.com goto fail_fw_init;
561751087a86SSumit.Saxena@avagotech.com }
561851087a86SSumit.Saxena@avagotech.com
56190d49016bSadam radford instance->fw_support_ieee = 0;
56200d49016bSadam radford instance->fw_support_ieee =
5621de516379SShivasharan S (instance->instancet->read_fw_status_reg(instance) &
56220d49016bSadam radford 0x04000000);
56230d49016bSadam radford
56241be18254SBjorn Helgaas dev_notice(&instance->pdev->dev, "megasas_init_mfi: fw_support_ieee=%d",
56250d49016bSadam radford instance->fw_support_ieee);
56260d49016bSadam radford
56270d49016bSadam radford if (instance->fw_support_ieee)
56280d49016bSadam radford instance->flag_ieee = 1;
56290d49016bSadam radford
5630cd50ba8eSadam radford return 0;
5631cd50ba8eSadam radford
5632cd50ba8eSadam radford fail_fw_init:
5633cd50ba8eSadam radford
563460ee6529SChristoph Hellwig dma_free_coherent(&instance->pdev->dev, reply_q_sz,
5635cd50ba8eSadam radford instance->reply_queue, instance->reply_queue_h);
5636cd50ba8eSadam radford fail_reply_queue:
5637cd50ba8eSadam radford megasas_free_cmds(instance);
5638cd50ba8eSadam radford
5639cd50ba8eSadam radford fail_alloc_cmds:
5640cd50ba8eSadam radford return 1;
5641cd50ba8eSadam radford }
5642cd50ba8eSadam radford
564362a04f81SShivasharan S static
megasas_setup_irq_poll(struct megasas_instance * instance)564462a04f81SShivasharan S void megasas_setup_irq_poll(struct megasas_instance *instance)
564562a04f81SShivasharan S {
564662a04f81SShivasharan S struct megasas_irq_context *irq_ctx;
564762a04f81SShivasharan S u32 count, i;
564862a04f81SShivasharan S
564962a04f81SShivasharan S count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
565062a04f81SShivasharan S
565162a04f81SShivasharan S /* Initialize IRQ poll */
565262a04f81SShivasharan S for (i = 0; i < count; i++) {
565362a04f81SShivasharan S irq_ctx = &instance->irq_context[i];
565462a04f81SShivasharan S irq_ctx->os_irq = pci_irq_vector(instance->pdev, i);
565562a04f81SShivasharan S irq_ctx->irq_poll_scheduled = false;
565662a04f81SShivasharan S irq_poll_init(&irq_ctx->irqpoll,
565762a04f81SShivasharan S instance->threshold_reply_count,
565862a04f81SShivasharan S megasas_irqpoll);
565962a04f81SShivasharan S }
566062a04f81SShivasharan S }
566162a04f81SShivasharan S
5662d3557fc8SSumit.Saxena@avagotech.com /*
5663fad119b7SHannes Reinecke * megasas_setup_irqs_ioapic - register legacy interrupts.
5664d3557fc8SSumit.Saxena@avagotech.com * @instance: Adapter soft state
5665d3557fc8SSumit.Saxena@avagotech.com *
5666d3557fc8SSumit.Saxena@avagotech.com * Do not enable interrupt, only setup ISRs.
5667d3557fc8SSumit.Saxena@avagotech.com *
5668d3557fc8SSumit.Saxena@avagotech.com * Return 0 on success.
5669d3557fc8SSumit.Saxena@avagotech.com */
5670d3557fc8SSumit.Saxena@avagotech.com static int
megasas_setup_irqs_ioapic(struct megasas_instance * instance)5671d3557fc8SSumit.Saxena@avagotech.com megasas_setup_irqs_ioapic(struct megasas_instance *instance)
5672d3557fc8SSumit.Saxena@avagotech.com {
5673d3557fc8SSumit.Saxena@avagotech.com struct pci_dev *pdev;
5674d3557fc8SSumit.Saxena@avagotech.com
5675d3557fc8SSumit.Saxena@avagotech.com pdev = instance->pdev;
5676d3557fc8SSumit.Saxena@avagotech.com instance->irq_context[0].instance = instance;
5677d3557fc8SSumit.Saxena@avagotech.com instance->irq_context[0].MSIxIndex = 0;
5678ff7ca7fdSChandrakanth Patil snprintf(instance->irq_context->name, MEGASAS_MSIX_NAME_LEN, "%s%u",
5679ff7ca7fdSChandrakanth Patil "megasas", instance->host->host_no);
5680fad119b7SHannes Reinecke if (request_irq(pci_irq_vector(pdev, 0),
5681fad119b7SHannes Reinecke instance->instancet->service_isr, IRQF_SHARED,
5682ff7ca7fdSChandrakanth Patil instance->irq_context->name, &instance->irq_context[0])) {
5683d3557fc8SSumit.Saxena@avagotech.com dev_err(&instance->pdev->dev,
5684d3557fc8SSumit.Saxena@avagotech.com "Failed to register IRQ from %s %d\n",
5685d3557fc8SSumit.Saxena@avagotech.com __func__, __LINE__);
5686d3557fc8SSumit.Saxena@avagotech.com return -1;
5687d3557fc8SSumit.Saxena@avagotech.com }
5688299ee426SChandrakanth Patil instance->perf_mode = MR_LATENCY_PERF_MODE;
5689132147d7SChandrakanth Patil instance->low_latency_index_start = 0;
5690d3557fc8SSumit.Saxena@avagotech.com return 0;
5691d3557fc8SSumit.Saxena@avagotech.com }
5692d3557fc8SSumit.Saxena@avagotech.com
5693d3557fc8SSumit.Saxena@avagotech.com /**
5694d3557fc8SSumit.Saxena@avagotech.com * megasas_setup_irqs_msix - register MSI-x interrupts.
5695d3557fc8SSumit.Saxena@avagotech.com * @instance: Adapter soft state
5696d3557fc8SSumit.Saxena@avagotech.com * @is_probe: Driver probe check
5697d3557fc8SSumit.Saxena@avagotech.com *
5698d3557fc8SSumit.Saxena@avagotech.com * Do not enable interrupt, only setup ISRs.
5699d3557fc8SSumit.Saxena@avagotech.com *
5700d3557fc8SSumit.Saxena@avagotech.com * Return 0 on success.
5701d3557fc8SSumit.Saxena@avagotech.com */
5702d3557fc8SSumit.Saxena@avagotech.com static int
megasas_setup_irqs_msix(struct megasas_instance * instance,u8 is_probe)5703d3557fc8SSumit.Saxena@avagotech.com megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe)
5704d3557fc8SSumit.Saxena@avagotech.com {
5705fad119b7SHannes Reinecke int i, j;
5706d3557fc8SSumit.Saxena@avagotech.com struct pci_dev *pdev;
5707d3557fc8SSumit.Saxena@avagotech.com
5708d3557fc8SSumit.Saxena@avagotech.com pdev = instance->pdev;
5709d3557fc8SSumit.Saxena@avagotech.com
5710d3557fc8SSumit.Saxena@avagotech.com /* Try MSI-x */
5711d3557fc8SSumit.Saxena@avagotech.com for (i = 0; i < instance->msix_vectors; i++) {
5712d3557fc8SSumit.Saxena@avagotech.com instance->irq_context[i].instance = instance;
5713d3557fc8SSumit.Saxena@avagotech.com instance->irq_context[i].MSIxIndex = i;
5714ff7ca7fdSChandrakanth Patil snprintf(instance->irq_context[i].name, MEGASAS_MSIX_NAME_LEN, "%s%u-msix%u",
5715ff7ca7fdSChandrakanth Patil "megasas", instance->host->host_no, i);
5716fad119b7SHannes Reinecke if (request_irq(pci_irq_vector(pdev, i),
5717ff7ca7fdSChandrakanth Patil instance->instancet->service_isr, 0, instance->irq_context[i].name,
5718d3557fc8SSumit.Saxena@avagotech.com &instance->irq_context[i])) {
5719d3557fc8SSumit.Saxena@avagotech.com dev_err(&instance->pdev->dev,
5720d3557fc8SSumit.Saxena@avagotech.com "Failed to register IRQ for vector %d.\n", i);
57211eb81df5STomas Henzl for (j = 0; j < i; j++) {
57221eb81df5STomas Henzl if (j < instance->low_latency_index_start)
57238049da6fSNitesh Narayan Lal irq_update_affinity_hint(
57241eb81df5STomas Henzl pci_irq_vector(pdev, j), NULL);
5725fad119b7SHannes Reinecke free_irq(pci_irq_vector(pdev, j),
5726d3557fc8SSumit.Saxena@avagotech.com &instance->irq_context[j]);
57271eb81df5STomas Henzl }
5728d3557fc8SSumit.Saxena@avagotech.com /* Retry irq register for IO_APIC*/
5729d3557fc8SSumit.Saxena@avagotech.com instance->msix_vectors = 0;
57301d15d909SShivasharan S instance->msix_load_balance = false;
573164ff64b9SShivasharan S if (is_probe) {
573264ff64b9SShivasharan S pci_free_irq_vectors(instance->pdev);
5733d3557fc8SSumit.Saxena@avagotech.com return megasas_setup_irqs_ioapic(instance);
573464ff64b9SShivasharan S } else {
5735d3557fc8SSumit.Saxena@avagotech.com return -1;
5736d3557fc8SSumit.Saxena@avagotech.com }
5737d3557fc8SSumit.Saxena@avagotech.com }
573864ff64b9SShivasharan S }
57391d15d909SShivasharan S
5740d3557fc8SSumit.Saxena@avagotech.com return 0;
5741d3557fc8SSumit.Saxena@avagotech.com }
5742d3557fc8SSumit.Saxena@avagotech.com
5743d3557fc8SSumit.Saxena@avagotech.com /*
5744d3557fc8SSumit.Saxena@avagotech.com * megasas_destroy_irqs- unregister interrupts.
5745d3557fc8SSumit.Saxena@avagotech.com * @instance: Adapter soft state
5746d3557fc8SSumit.Saxena@avagotech.com * return: void
5747d3557fc8SSumit.Saxena@avagotech.com */
5748d3557fc8SSumit.Saxena@avagotech.com static void
megasas_destroy_irqs(struct megasas_instance * instance)5749d3557fc8SSumit.Saxena@avagotech.com megasas_destroy_irqs(struct megasas_instance *instance) {
5750d3557fc8SSumit.Saxena@avagotech.com
5751d3557fc8SSumit.Saxena@avagotech.com int i;
575262a04f81SShivasharan S int count;
575362a04f81SShivasharan S struct megasas_irq_context *irq_ctx;
575462a04f81SShivasharan S
575562a04f81SShivasharan S count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
575662a04f81SShivasharan S if (instance->adapter_type != MFI_SERIES) {
575762a04f81SShivasharan S for (i = 0; i < count; i++) {
575862a04f81SShivasharan S irq_ctx = &instance->irq_context[i];
575962a04f81SShivasharan S irq_poll_disable(&irq_ctx->irqpoll);
576062a04f81SShivasharan S }
576162a04f81SShivasharan S }
5762d3557fc8SSumit.Saxena@avagotech.com
5763d3557fc8SSumit.Saxena@avagotech.com if (instance->msix_vectors)
5764d3557fc8SSumit.Saxena@avagotech.com for (i = 0; i < instance->msix_vectors; i++) {
57651eb81df5STomas Henzl if (i < instance->low_latency_index_start)
57668049da6fSNitesh Narayan Lal irq_update_affinity_hint(
57671eb81df5STomas Henzl pci_irq_vector(instance->pdev, i), NULL);
5768fad119b7SHannes Reinecke free_irq(pci_irq_vector(instance->pdev, i),
5769d3557fc8SSumit.Saxena@avagotech.com &instance->irq_context[i]);
5770d3557fc8SSumit.Saxena@avagotech.com }
5771d3557fc8SSumit.Saxena@avagotech.com else
5772fad119b7SHannes Reinecke free_irq(pci_irq_vector(instance->pdev, 0),
5773fad119b7SHannes Reinecke &instance->irq_context[0]);
5774d3557fc8SSumit.Saxena@avagotech.com }
5775d3557fc8SSumit.Saxena@avagotech.com
5776cd50ba8eSadam radford /**
57773761cb4cSsumit.saxena@avagotech.com * megasas_setup_jbod_map - setup jbod map for FP seq_number.
57783761cb4cSsumit.saxena@avagotech.com * @instance: Adapter soft state
57793761cb4cSsumit.saxena@avagotech.com *
57803761cb4cSsumit.saxena@avagotech.com * Return 0 on success.
57813761cb4cSsumit.saxena@avagotech.com */
57823761cb4cSsumit.saxena@avagotech.com void
megasas_setup_jbod_map(struct megasas_instance * instance)57833761cb4cSsumit.saxena@avagotech.com megasas_setup_jbod_map(struct megasas_instance *instance)
57843761cb4cSsumit.saxena@avagotech.com {
57853761cb4cSsumit.saxena@avagotech.com int i;
57863761cb4cSsumit.saxena@avagotech.com struct fusion_context *fusion = instance->ctrl_context;
578748658213SGustavo A. R. Silva size_t pd_seq_map_sz;
57883761cb4cSsumit.saxena@avagotech.com
5789d67790ddSKees Cook pd_seq_map_sz = struct_size_t(struct MR_PD_CFG_SEQ_NUM_SYNC, seq,
579048658213SGustavo A. R. Silva MAX_PHYSICAL_DEVICES);
57913761cb4cSsumit.saxena@avagotech.com
579259db5a93SChandrakanth Patil instance->use_seqnum_jbod_fp =
579359db5a93SChandrakanth Patil instance->support_seqnum_jbod_fp;
57943761cb4cSsumit.saxena@avagotech.com if (reset_devices || !fusion ||
579559db5a93SChandrakanth Patil !instance->support_seqnum_jbod_fp) {
57963761cb4cSsumit.saxena@avagotech.com dev_info(&instance->pdev->dev,
579759db5a93SChandrakanth Patil "JBOD sequence map is disabled %s %d\n",
57983761cb4cSsumit.saxena@avagotech.com __func__, __LINE__);
57993761cb4cSsumit.saxena@avagotech.com instance->use_seqnum_jbod_fp = false;
58003761cb4cSsumit.saxena@avagotech.com return;
58013761cb4cSsumit.saxena@avagotech.com }
58023761cb4cSsumit.saxena@avagotech.com
58033761cb4cSsumit.saxena@avagotech.com if (fusion->pd_seq_sync[0])
58043761cb4cSsumit.saxena@avagotech.com goto skip_alloc;
58053761cb4cSsumit.saxena@avagotech.com
58063761cb4cSsumit.saxena@avagotech.com for (i = 0; i < JBOD_MAPS_COUNT; i++) {
58073761cb4cSsumit.saxena@avagotech.com fusion->pd_seq_sync[i] = dma_alloc_coherent
58083761cb4cSsumit.saxena@avagotech.com (&instance->pdev->dev, pd_seq_map_sz,
58093761cb4cSsumit.saxena@avagotech.com &fusion->pd_seq_phys[i], GFP_KERNEL);
58103761cb4cSsumit.saxena@avagotech.com if (!fusion->pd_seq_sync[i]) {
58113761cb4cSsumit.saxena@avagotech.com dev_err(&instance->pdev->dev,
58123761cb4cSsumit.saxena@avagotech.com "Failed to allocate memory from %s %d\n",
58133761cb4cSsumit.saxena@avagotech.com __func__, __LINE__);
58143761cb4cSsumit.saxena@avagotech.com if (i == 1) {
58153761cb4cSsumit.saxena@avagotech.com dma_free_coherent(&instance->pdev->dev,
58163761cb4cSsumit.saxena@avagotech.com pd_seq_map_sz, fusion->pd_seq_sync[0],
58173761cb4cSsumit.saxena@avagotech.com fusion->pd_seq_phys[0]);
58183761cb4cSsumit.saxena@avagotech.com fusion->pd_seq_sync[0] = NULL;
58193761cb4cSsumit.saxena@avagotech.com }
58203761cb4cSsumit.saxena@avagotech.com instance->use_seqnum_jbod_fp = false;
58213761cb4cSsumit.saxena@avagotech.com return;
58223761cb4cSsumit.saxena@avagotech.com }
58233761cb4cSsumit.saxena@avagotech.com }
58243761cb4cSsumit.saxena@avagotech.com
58253761cb4cSsumit.saxena@avagotech.com skip_alloc:
58263761cb4cSsumit.saxena@avagotech.com if (!megasas_sync_pd_seq_num(instance, false) &&
58273761cb4cSsumit.saxena@avagotech.com !megasas_sync_pd_seq_num(instance, true))
58283761cb4cSsumit.saxena@avagotech.com instance->use_seqnum_jbod_fp = true;
58293761cb4cSsumit.saxena@avagotech.com else
58303761cb4cSsumit.saxena@avagotech.com instance->use_seqnum_jbod_fp = false;
58313761cb4cSsumit.saxena@avagotech.com }
58323761cb4cSsumit.saxena@avagotech.com
megasas_setup_reply_map(struct megasas_instance * instance)5833adbe5523SMing Lei static void megasas_setup_reply_map(struct megasas_instance *instance)
5834adbe5523SMing Lei {
5835adbe5523SMing Lei const struct cpumask *mask;
5836132147d7SChandrakanth Patil unsigned int queue, cpu, low_latency_index_start;
5837adbe5523SMing Lei
5838132147d7SChandrakanth Patil low_latency_index_start = instance->low_latency_index_start;
5839132147d7SChandrakanth Patil
5840132147d7SChandrakanth Patil for (queue = low_latency_index_start; queue < instance->msix_vectors; queue++) {
5841adbe5523SMing Lei mask = pci_irq_get_affinity(instance->pdev, queue);
5842adbe5523SMing Lei if (!mask)
5843adbe5523SMing Lei goto fallback;
5844adbe5523SMing Lei
5845adbe5523SMing Lei for_each_cpu(cpu, mask)
5846adbe5523SMing Lei instance->reply_map[cpu] = queue;
5847adbe5523SMing Lei }
5848adbe5523SMing Lei return;
5849adbe5523SMing Lei
5850adbe5523SMing Lei fallback:
5851132147d7SChandrakanth Patil queue = low_latency_index_start;
5852132147d7SChandrakanth Patil for_each_possible_cpu(cpu) {
5853132147d7SChandrakanth Patil instance->reply_map[cpu] = queue;
5854132147d7SChandrakanth Patil if (queue == (instance->msix_vectors - 1))
5855132147d7SChandrakanth Patil queue = low_latency_index_start;
5856132147d7SChandrakanth Patil else
5857132147d7SChandrakanth Patil queue++;
5858132147d7SChandrakanth Patil }
5859adbe5523SMing Lei }
5860adbe5523SMing Lei
58613761cb4cSsumit.saxena@avagotech.com /**
5862daa06811SShivasharan S * megasas_get_device_list - Get the PD and LD device list from FW.
5863daa06811SShivasharan S * @instance: Adapter soft state
5864daa06811SShivasharan S * @return: Success or failure
5865daa06811SShivasharan S *
5866daa06811SShivasharan S * Issue DCMDs to Firmware to get the PD and LD list.
5867f6fe5731SShivasharan S * Based on the FW support, driver sends the HOST_DEVICE_LIST or combination
5868f6fe5731SShivasharan S * of PD_LIST/LD_LIST_QUERY DCMDs to get the device list.
5869daa06811SShivasharan S */
5870daa06811SShivasharan S static
megasas_get_device_list(struct megasas_instance * instance)5871daa06811SShivasharan S int megasas_get_device_list(struct megasas_instance *instance)
5872daa06811SShivasharan S {
5873f6fe5731SShivasharan S if (instance->enable_fw_dev_list) {
5874f6fe5731SShivasharan S if (megasas_host_device_list_query(instance, true))
5875f6fe5731SShivasharan S return FAILED;
5876f6fe5731SShivasharan S } else {
5877daa06811SShivasharan S if (megasas_get_pd_list(instance) < 0) {
5878daa06811SShivasharan S dev_err(&instance->pdev->dev, "failed to get PD list\n");
5879daa06811SShivasharan S return FAILED;
5880daa06811SShivasharan S }
5881daa06811SShivasharan S
5882daa06811SShivasharan S if (megasas_ld_list_query(instance,
5883daa06811SShivasharan S MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) {
5884daa06811SShivasharan S dev_err(&instance->pdev->dev, "failed to get LD list\n");
5885daa06811SShivasharan S return FAILED;
5886daa06811SShivasharan S }
5887f6fe5731SShivasharan S }
5888daa06811SShivasharan S
5889daa06811SShivasharan S return SUCCESS;
5890daa06811SShivasharan S }
5891132147d7SChandrakanth Patil
5892f0b9e7bdSChandrakanth Patil /**
58938049da6fSNitesh Narayan Lal * megasas_set_high_iops_queue_affinity_and_hint - Set affinity and hint
58948049da6fSNitesh Narayan Lal * for high IOPS queues
5895f0b9e7bdSChandrakanth Patil * @instance: Adapter soft state
5896f0b9e7bdSChandrakanth Patil * return: void
5897f0b9e7bdSChandrakanth Patil */
5898f0b9e7bdSChandrakanth Patil static inline void
megasas_set_high_iops_queue_affinity_and_hint(struct megasas_instance * instance)58998049da6fSNitesh Narayan Lal megasas_set_high_iops_queue_affinity_and_hint(struct megasas_instance *instance)
5900f0b9e7bdSChandrakanth Patil {
5901f0b9e7bdSChandrakanth Patil int i;
59028049da6fSNitesh Narayan Lal unsigned int irq;
59038049da6fSNitesh Narayan Lal const struct cpumask *mask;
5904f0b9e7bdSChandrakanth Patil
5905299ee426SChandrakanth Patil if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
59068049da6fSNitesh Narayan Lal mask = cpumask_of_node(dev_to_node(&instance->pdev->dev));
5907f0b9e7bdSChandrakanth Patil
59088049da6fSNitesh Narayan Lal for (i = 0; i < instance->low_latency_index_start; i++) {
59098049da6fSNitesh Narayan Lal irq = pci_irq_vector(instance->pdev, i);
59108049da6fSNitesh Narayan Lal irq_set_affinity_and_hint(irq, mask);
59118049da6fSNitesh Narayan Lal }
5912f0b9e7bdSChandrakanth Patil }
5913f0b9e7bdSChandrakanth Patil }
5914f0b9e7bdSChandrakanth Patil
5915132147d7SChandrakanth Patil static int
__megasas_alloc_irq_vectors(struct megasas_instance * instance)5916132147d7SChandrakanth Patil __megasas_alloc_irq_vectors(struct megasas_instance *instance)
5917132147d7SChandrakanth Patil {
5918132147d7SChandrakanth Patil int i, irq_flags;
5919132147d7SChandrakanth Patil struct irq_affinity desc = { .pre_vectors = instance->low_latency_index_start };
5920132147d7SChandrakanth Patil struct irq_affinity *descp = &desc;
5921132147d7SChandrakanth Patil
5922132147d7SChandrakanth Patil irq_flags = PCI_IRQ_MSIX;
5923132147d7SChandrakanth Patil
5924132147d7SChandrakanth Patil if (instance->smp_affinity_enable)
59259e4bec5bSKashyap Desai irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES;
5926132147d7SChandrakanth Patil else
5927132147d7SChandrakanth Patil descp = NULL;
5928132147d7SChandrakanth Patil
59299e4bec5bSKashyap Desai /* Do not allocate msix vectors for poll_queues.
59309e4bec5bSKashyap Desai * msix_vectors is always within a range of FW supported reply queue.
59319e4bec5bSKashyap Desai */
5932132147d7SChandrakanth Patil i = pci_alloc_irq_vectors_affinity(instance->pdev,
5933132147d7SChandrakanth Patil instance->low_latency_index_start,
59349e4bec5bSKashyap Desai instance->msix_vectors - instance->iopoll_q_count, irq_flags, descp);
5935132147d7SChandrakanth Patil
5936132147d7SChandrakanth Patil return i;
5937132147d7SChandrakanth Patil }
5938132147d7SChandrakanth Patil
5939132147d7SChandrakanth Patil /**
5940132147d7SChandrakanth Patil * megasas_alloc_irq_vectors - Allocate IRQ vectors/enable MSI-x vectors
5941132147d7SChandrakanth Patil * @instance: Adapter soft state
5942132147d7SChandrakanth Patil * return: void
5943132147d7SChandrakanth Patil */
5944132147d7SChandrakanth Patil static void
megasas_alloc_irq_vectors(struct megasas_instance * instance)5945132147d7SChandrakanth Patil megasas_alloc_irq_vectors(struct megasas_instance *instance)
5946132147d7SChandrakanth Patil {
5947132147d7SChandrakanth Patil int i;
5948132147d7SChandrakanth Patil unsigned int num_msix_req;
5949132147d7SChandrakanth Patil
59509e4bec5bSKashyap Desai instance->iopoll_q_count = 0;
59519e4bec5bSKashyap Desai if ((instance->adapter_type != MFI_SERIES) &&
59529e4bec5bSKashyap Desai poll_queues) {
59539e4bec5bSKashyap Desai
59549e4bec5bSKashyap Desai instance->perf_mode = MR_LATENCY_PERF_MODE;
59559e4bec5bSKashyap Desai instance->low_latency_index_start = 1;
59569e4bec5bSKashyap Desai
59579e4bec5bSKashyap Desai /* reserve for default and non-mananged pre-vector. */
59589e4bec5bSKashyap Desai if (instance->msix_vectors > (poll_queues + 2))
59599e4bec5bSKashyap Desai instance->iopoll_q_count = poll_queues;
59609e4bec5bSKashyap Desai else
59619e4bec5bSKashyap Desai instance->iopoll_q_count = 0;
59629e4bec5bSKashyap Desai
59639e4bec5bSKashyap Desai num_msix_req = num_online_cpus() + instance->low_latency_index_start;
59649e4bec5bSKashyap Desai instance->msix_vectors = min(num_msix_req,
59659e4bec5bSKashyap Desai instance->msix_vectors);
59669e4bec5bSKashyap Desai
59679e4bec5bSKashyap Desai }
59689e4bec5bSKashyap Desai
5969132147d7SChandrakanth Patil i = __megasas_alloc_irq_vectors(instance);
5970132147d7SChandrakanth Patil
59719e4bec5bSKashyap Desai if (((instance->perf_mode == MR_BALANCED_PERF_MODE)
59729e4bec5bSKashyap Desai || instance->iopoll_q_count) &&
59739e4bec5bSKashyap Desai (i != (instance->msix_vectors - instance->iopoll_q_count))) {
5974132147d7SChandrakanth Patil if (instance->msix_vectors)
5975132147d7SChandrakanth Patil pci_free_irq_vectors(instance->pdev);
5976132147d7SChandrakanth Patil /* Disable Balanced IOPS mode and try realloc vectors */
5977299ee426SChandrakanth Patil instance->perf_mode = MR_LATENCY_PERF_MODE;
5978132147d7SChandrakanth Patil instance->low_latency_index_start = 1;
5979132147d7SChandrakanth Patil num_msix_req = num_online_cpus() + instance->low_latency_index_start;
5980132147d7SChandrakanth Patil
5981132147d7SChandrakanth Patil instance->msix_vectors = min(num_msix_req,
5982132147d7SChandrakanth Patil instance->msix_vectors);
5983132147d7SChandrakanth Patil
59849e4bec5bSKashyap Desai instance->iopoll_q_count = 0;
5985132147d7SChandrakanth Patil i = __megasas_alloc_irq_vectors(instance);
5986132147d7SChandrakanth Patil
5987132147d7SChandrakanth Patil }
5988132147d7SChandrakanth Patil
5989132147d7SChandrakanth Patil dev_info(&instance->pdev->dev,
59909e4bec5bSKashyap Desai "requested/available msix %d/%d poll_queue %d\n",
59919e4bec5bSKashyap Desai instance->msix_vectors - instance->iopoll_q_count,
59929e4bec5bSKashyap Desai i, instance->iopoll_q_count);
5993132147d7SChandrakanth Patil
5994132147d7SChandrakanth Patil if (i > 0)
5995132147d7SChandrakanth Patil instance->msix_vectors = i;
5996132147d7SChandrakanth Patil else
5997132147d7SChandrakanth Patil instance->msix_vectors = 0;
5998132147d7SChandrakanth Patil
5999f0b9e7bdSChandrakanth Patil if (instance->smp_affinity_enable)
60008049da6fSNitesh Narayan Lal megasas_set_high_iops_queue_affinity_and_hint(instance);
6001132147d7SChandrakanth Patil }
6002132147d7SChandrakanth Patil
6003daa06811SShivasharan S /**
6004cd50ba8eSadam radford * megasas_init_fw - Initializes the FW
6005cd50ba8eSadam radford * @instance: Adapter soft state
6006cd50ba8eSadam radford *
6007cd50ba8eSadam radford * This is the main function for initializing firmware
6008cd50ba8eSadam radford */
6009cd50ba8eSadam radford
megasas_init_fw(struct megasas_instance * instance)6010cd50ba8eSadam radford static int megasas_init_fw(struct megasas_instance *instance)
6011cd50ba8eSadam radford {
6012cd50ba8eSadam radford u32 max_sectors_1;
601315dd0381SShivasharan S u32 max_sectors_2, tmp_sectors, msix_enable;
601481b76452SShivasharan S u32 scratch_pad_1, scratch_pad_2, scratch_pad_3, status_reg;
601511f8a7b3SBen Collins resource_size_t base_addr;
60169a598710SShivasharan S void *base_addr_phys;
601751087a86SSumit.Saxena@avagotech.com struct megasas_ctrl_info *ctrl_info = NULL;
6018cd50ba8eSadam radford unsigned long bar_list;
6019ce88418dSShivasharan S int i, j, loop;
6020229fe47cSadam radford struct IOV_111 *iovPtr;
60215a8cb85bSsumit.saxena@avagotech.com struct fusion_context *fusion;
6022132147d7SChandrakanth Patil bool intr_coalescing;
6023132147d7SChandrakanth Patil unsigned int num_msix_req;
6024299ee426SChandrakanth Patil u16 lnksta, speed;
60255a8cb85bSsumit.saxena@avagotech.com
60265a8cb85bSsumit.saxena@avagotech.com fusion = instance->ctrl_context;
6027cd50ba8eSadam radford
6028cd50ba8eSadam radford /* Find first memory bar */
6029cd50ba8eSadam radford bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
603051f9039fSChristophe JAILLET instance->bar = find_first_bit(&bar_list, BITS_PER_LONG);
6031e7f85168SYinghai Lu if (pci_request_selected_regions(instance->pdev, 1<<instance->bar,
6032cd50ba8eSadam radford "megasas: LSI")) {
60331be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "IO memory region busy!\n");
6034cd50ba8eSadam radford return -EBUSY;
6035cd50ba8eSadam radford }
6036cd50ba8eSadam radford
603711f8a7b3SBen Collins base_addr = pci_resource_start(instance->pdev, instance->bar);
60384bdc0d67SChristoph Hellwig instance->reg_set = ioremap(base_addr, 8192);
6039cd50ba8eSadam radford
6040cd50ba8eSadam radford if (!instance->reg_set) {
60411be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to map IO mem\n");
6042cd50ba8eSadam radford goto fail_ioremap;
6043cd50ba8eSadam radford }
6044cd50ba8eSadam radford
60459a598710SShivasharan S base_addr_phys = &base_addr;
60469a598710SShivasharan S dev_printk(KERN_DEBUG, &instance->pdev->dev,
60479a598710SShivasharan S "BAR:0x%lx BAR's base_addr(phys):%pa mapped virt_addr:0x%p\n",
60489a598710SShivasharan S instance->bar, base_addr_phys, instance->reg_set);
60499a598710SShivasharan S
6050e7d36b88SShivasharan S if (instance->adapter_type != MFI_SERIES)
60519c915a8cSadam radford instance->instancet = &megasas_instance_template_fusion;
60529581ebebSSasikumar Chandrasekaran else {
60539581ebebSSasikumar Chandrasekaran switch (instance->pdev->device) {
6054cd50ba8eSadam radford case PCI_DEVICE_ID_LSI_SAS1078R:
6055cd50ba8eSadam radford case PCI_DEVICE_ID_LSI_SAS1078DE:
6056cd50ba8eSadam radford instance->instancet = &megasas_instance_template_ppc;
6057cd50ba8eSadam radford break;
6058cd50ba8eSadam radford case PCI_DEVICE_ID_LSI_SAS1078GEN2:
6059cd50ba8eSadam radford case PCI_DEVICE_ID_LSI_SAS0079GEN2:
6060cd50ba8eSadam radford instance->instancet = &megasas_instance_template_gen2;
6061cd50ba8eSadam radford break;
6062cd50ba8eSadam radford case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
6063cd50ba8eSadam radford case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
6064cd50ba8eSadam radford instance->instancet = &megasas_instance_template_skinny;
6065cd50ba8eSadam radford break;
6066cd50ba8eSadam radford case PCI_DEVICE_ID_LSI_SAS1064R:
6067cd50ba8eSadam radford case PCI_DEVICE_ID_DELL_PERC5:
6068cd50ba8eSadam radford default:
6069cd50ba8eSadam radford instance->instancet = &megasas_instance_template_xscale;
60709581ebebSSasikumar Chandrasekaran instance->pd_list_not_supported = 1;
6071cd50ba8eSadam radford break;
6072cd50ba8eSadam radford }
60739581ebebSSasikumar Chandrasekaran }
6074cd50ba8eSadam radford
60756431f5d7SSumit.Saxena@lsi.com if (megasas_transition_to_ready(instance, 0)) {
607678409d4bSShivasharan S dev_info(&instance->pdev->dev,
607778409d4bSShivasharan S "Failed to transition controller to ready from %s!\n",
607878409d4bSShivasharan S __func__);
6079f10fb852SShivasharan S if (instance->adapter_type != MFI_SERIES) {
6080de93b40dSShivasharan S status_reg = instance->instancet->read_fw_status_reg(
6081de516379SShivasharan S instance);
6082f10fb852SShivasharan S if (status_reg & MFI_RESET_ADAPTER) {
608378409d4bSShivasharan S if (megasas_adp_reset_wait_for_ready
608478409d4bSShivasharan S (instance, true, 0) == FAILED)
6085f10fb852SShivasharan S goto fail_ready_state;
6086f10fb852SShivasharan S } else {
6087f10fb852SShivasharan S goto fail_ready_state;
6088de93b40dSShivasharan S }
6089f10fb852SShivasharan S } else {
60906431f5d7SSumit.Saxena@lsi.com atomic_set(&instance->fw_reset_no_pci_access, 1);
60916431f5d7SSumit.Saxena@lsi.com instance->instancet->adp_reset
60926431f5d7SSumit.Saxena@lsi.com (instance, instance->reg_set);
60936431f5d7SSumit.Saxena@lsi.com atomic_set(&instance->fw_reset_no_pci_access, 0);
60946431f5d7SSumit.Saxena@lsi.com
6095de93b40dSShivasharan S /*waiting for about 30 second before retry*/
60966431f5d7SSumit.Saxena@lsi.com ssleep(30);
60976431f5d7SSumit.Saxena@lsi.com
6098058a8facSadam radford if (megasas_transition_to_ready(instance, 0))
6099cd50ba8eSadam radford goto fail_ready_state;
6100de93b40dSShivasharan S }
610178409d4bSShivasharan S
610278409d4bSShivasharan S dev_info(&instance->pdev->dev,
610378409d4bSShivasharan S "FW restarted successfully from %s!\n",
610478409d4bSShivasharan S __func__);
61056431f5d7SSumit.Saxena@lsi.com }
6106cd50ba8eSadam radford
6107e5d65b4bSShivasharan S megasas_init_ctrl_params(instance);
6108e5d65b4bSShivasharan S
6109107a60ddSShivasharan S if (megasas_set_dma_mask(instance))
6110e5d65b4bSShivasharan S goto fail_ready_state;
6111e5d65b4bSShivasharan S
6112e5d65b4bSShivasharan S if (megasas_alloc_ctrl_mem(instance))
6113e5d65b4bSShivasharan S goto fail_alloc_dma_buf;
6114e5d65b4bSShivasharan S
6115e5d65b4bSShivasharan S if (megasas_alloc_ctrl_dma_buffers(instance))
6116e5d65b4bSShivasharan S goto fail_alloc_dma_buf;
6117e5d65b4bSShivasharan S
6118e5d65b4bSShivasharan S fusion = instance->ctrl_context;
6119e5d65b4bSShivasharan S
6120630d42b7SShivasharan S if (instance->adapter_type >= VENTURA_SERIES) {
612181b76452SShivasharan S scratch_pad_2 =
6122272652fcSShivasharan S megasas_readl(instance,
6123272652fcSShivasharan S &instance->reg_set->outbound_scratch_pad_2);
612481b76452SShivasharan S instance->max_raid_mapsize = ((scratch_pad_2 >>
6125d889344eSSasikumar Chandrasekaran MR_MAX_RAID_MAP_SIZE_OFFSET_SHIFT) &
6126d889344eSSasikumar Chandrasekaran MR_MAX_RAID_MAP_SIZE_MASK);
6127d889344eSSasikumar Chandrasekaran }
6128d46a3ad6SSumit.Saxena@lsi.com
61299ab089d3SChandrakanth Patil instance->enable_sdev_max_qd = enable_sdev_max_qd;
61309ab089d3SChandrakanth Patil
61317fc55700SChandrakanth Patil switch (instance->adapter_type) {
61327fc55700SChandrakanth Patil case VENTURA_SERIES:
613349f2bf10SChandrakanth Patil fusion->pcie_bw_limitation = true;
61347fc55700SChandrakanth Patil break;
61357fc55700SChandrakanth Patil case AERO_SERIES:
61367fc55700SChandrakanth Patil fusion->r56_div_offload = true;
61377fc55700SChandrakanth Patil break;
61387fc55700SChandrakanth Patil default:
61397fc55700SChandrakanth Patil break;
61407fc55700SChandrakanth Patil }
614149f2bf10SChandrakanth Patil
61423f1abce4Sadam radford /* Check if MSI-X is supported while in ready state */
6143de516379SShivasharan S msix_enable = (instance->instancet->read_fw_status_reg(instance) &
61443f1abce4Sadam radford 0x4000000) >> 0x1a;
6145c8e858feSadam radford if (msix_enable && !msix_disable) {
6146fad119b7SHannes Reinecke
6147272652fcSShivasharan S scratch_pad_1 = megasas_readl
6148272652fcSShivasharan S (instance, &instance->reg_set->outbound_scratch_pad_1);
6149c8e858feSadam radford /* Check max MSI-X vectors */
61505a8cb85bSsumit.saxena@avagotech.com if (fusion) {
6151c365178fSShivasharan S if (instance->adapter_type == THUNDERBOLT_SERIES) {
6152c365178fSShivasharan S /* Thunderbolt Series*/
615381b76452SShivasharan S instance->msix_vectors = (scratch_pad_1
6154d46a3ad6SSumit.Saxena@lsi.com & MR_MAX_REPLY_QUEUES_OFFSET) + 1;
6155e29c3221SShivasharan S } else {
615681b76452SShivasharan S instance->msix_vectors = ((scratch_pad_1
6157d46a3ad6SSumit.Saxena@lsi.com & MR_MAX_REPLY_QUEUES_EXT_OFFSET)
6158d46a3ad6SSumit.Saxena@lsi.com >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
6159e29c3221SShivasharan S
6160e29c3221SShivasharan S /*
6161e29c3221SShivasharan S * For Invader series, > 8 MSI-x vectors
6162e29c3221SShivasharan S * supported by FW/HW implies combined
6163e29c3221SShivasharan S * reply queue mode is enabled.
6164e29c3221SShivasharan S * For Ventura series, > 16 MSI-x vectors
6165e29c3221SShivasharan S * supported by FW/HW implies combined
6166e29c3221SShivasharan S * reply queue mode is enabled.
6167e29c3221SShivasharan S */
6168e29c3221SShivasharan S switch (instance->adapter_type) {
6169e29c3221SShivasharan S case INVADER_SERIES:
6170e29c3221SShivasharan S if (instance->msix_vectors > 8)
6171e29c3221SShivasharan S instance->msix_combined = true;
6172e29c3221SShivasharan S break;
6173154a7cdeSShivasharan S case AERO_SERIES:
6174e29c3221SShivasharan S case VENTURA_SERIES:
61752493c67eSSasikumar Chandrasekaran if (instance->msix_vectors > 16)
61762493c67eSSasikumar Chandrasekaran instance->msix_combined = true;
6177e29c3221SShivasharan S break;
6178e29c3221SShivasharan S }
61792493c67eSSasikumar Chandrasekaran
6180179ac142SSumit Saxena if (rdpq_enable)
618181b76452SShivasharan S instance->is_rdpq = (scratch_pad_1 & MR_RDPQ_MODE_OFFSET) ?
6182179ac142SSumit Saxena 1 : 0;
61831d15d909SShivasharan S
61841175b884SShivasharan S if (instance->adapter_type >= INVADER_SERIES &&
61851175b884SShivasharan S !instance->msix_combined) {
61861d15d909SShivasharan S instance->msix_load_balance = true;
61871d15d909SShivasharan S instance->smp_affinity_enable = false;
61881d15d909SShivasharan S }
61891d15d909SShivasharan S
6190d46a3ad6SSumit.Saxena@lsi.com /* Save 1-15 reply post index address to local memory
6191d46a3ad6SSumit.Saxena@lsi.com * Index 0 is already saved from reg offset
6192d46a3ad6SSumit.Saxena@lsi.com * MPI2_REPLY_POST_HOST_INDEX_OFFSET
6193d46a3ad6SSumit.Saxena@lsi.com */
6194d46a3ad6SSumit.Saxena@lsi.com for (loop = 1; loop < MR_MAX_MSIX_REG_ARRAY; loop++) {
6195d46a3ad6SSumit.Saxena@lsi.com instance->reply_post_host_index_addr[loop] =
61968a232bb3SChristoph Hellwig (u32 __iomem *)
61978a232bb3SChristoph Hellwig ((u8 __iomem *)instance->reg_set +
6198d46a3ad6SSumit.Saxena@lsi.com MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET
6199d46a3ad6SSumit.Saxena@lsi.com + (loop * 0x10));
6200d46a3ad6SSumit.Saxena@lsi.com }
62015a8cb85bSsumit.saxena@avagotech.com }
6202ce88418dSShivasharan S
6203ce88418dSShivasharan S dev_info(&instance->pdev->dev,
6204ce88418dSShivasharan S "firmware supports msix\t: (%d)",
6205ce88418dSShivasharan S instance->msix_vectors);
6206d46a3ad6SSumit.Saxena@lsi.com if (msix_vectors)
6207d46a3ad6SSumit.Saxena@lsi.com instance->msix_vectors = min(msix_vectors,
6208d46a3ad6SSumit.Saxena@lsi.com instance->msix_vectors);
62095a8cb85bSsumit.saxena@avagotech.com } else /* MFI adapters */
6210c8e858feSadam radford instance->msix_vectors = 1;
62111d15d909SShivasharan S
6212132147d7SChandrakanth Patil
6213132147d7SChandrakanth Patil /*
6214132147d7SChandrakanth Patil * For Aero (if some conditions are met), driver will configure a
6215132147d7SChandrakanth Patil * few additional reply queues with interrupt coalescing enabled.
6216132147d7SChandrakanth Patil * These queues with interrupt coalescing enabled are called
6217132147d7SChandrakanth Patil * High IOPS queues and rest of reply queues (based on number of
6218132147d7SChandrakanth Patil * logical CPUs) are termed as Low latency queues.
6219132147d7SChandrakanth Patil *
6220132147d7SChandrakanth Patil * Total Number of reply queues = High IOPS queues + low latency queues
6221132147d7SChandrakanth Patil *
6222132147d7SChandrakanth Patil * For rest of fusion adapters, 1 additional reply queue will be
6223132147d7SChandrakanth Patil * reserved for management commands, rest of reply queues
6224132147d7SChandrakanth Patil * (based on number of logical CPUs) will be used for IOs and
6225132147d7SChandrakanth Patil * referenced as IO queues.
6226132147d7SChandrakanth Patil * Total Number of reply queues = 1 + IO queues
6227132147d7SChandrakanth Patil *
6228132147d7SChandrakanth Patil * MFI adapters supports single MSI-x so single reply queue
6229132147d7SChandrakanth Patil * will be used for IO and management commands.
6230132147d7SChandrakanth Patil */
6231132147d7SChandrakanth Patil
6232132147d7SChandrakanth Patil intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ?
6233132147d7SChandrakanth Patil true : false;
6234132147d7SChandrakanth Patil if (intr_coalescing &&
6235132147d7SChandrakanth Patil (num_online_cpus() >= MR_HIGH_IOPS_QUEUE_COUNT) &&
6236132147d7SChandrakanth Patil (instance->msix_vectors == MEGASAS_MAX_MSIX_QUEUES))
6237299ee426SChandrakanth Patil instance->perf_mode = MR_BALANCED_PERF_MODE;
6238c8e858feSadam radford else
6239299ee426SChandrakanth Patil instance->perf_mode = MR_LATENCY_PERF_MODE;
6240132147d7SChandrakanth Patil
6241299ee426SChandrakanth Patil
6242299ee426SChandrakanth Patil if (instance->adapter_type == AERO_SERIES) {
6243299ee426SChandrakanth Patil pcie_capability_read_word(instance->pdev, PCI_EXP_LNKSTA, &lnksta);
6244299ee426SChandrakanth Patil speed = lnksta & PCI_EXP_LNKSTA_CLS;
6245299ee426SChandrakanth Patil
6246299ee426SChandrakanth Patil /*
6247299ee426SChandrakanth Patil * For Aero, if PCIe link speed is <16 GT/s, then driver should operate
6248299ee426SChandrakanth Patil * in latency perf mode and enable R1 PCI bandwidth algorithm
6249299ee426SChandrakanth Patil */
6250299ee426SChandrakanth Patil if (speed < 0x4) {
6251299ee426SChandrakanth Patil instance->perf_mode = MR_LATENCY_PERF_MODE;
6252299ee426SChandrakanth Patil fusion->pcie_bw_limitation = true;
6253299ee426SChandrakanth Patil }
6254299ee426SChandrakanth Patil
6255299ee426SChandrakanth Patil /*
6256299ee426SChandrakanth Patil * Performance mode settings provided through module parameter-perf_mode will
6257299ee426SChandrakanth Patil * take affect only for:
6258299ee426SChandrakanth Patil * 1. Aero family of adapters.
6259299ee426SChandrakanth Patil * 2. When user sets module parameter- perf_mode in range of 0-2.
6260299ee426SChandrakanth Patil */
6261299ee426SChandrakanth Patil if ((perf_mode >= MR_BALANCED_PERF_MODE) &&
6262299ee426SChandrakanth Patil (perf_mode <= MR_LATENCY_PERF_MODE))
6263299ee426SChandrakanth Patil instance->perf_mode = perf_mode;
6264299ee426SChandrakanth Patil /*
6265299ee426SChandrakanth Patil * If intr coalescing is not supported by controller FW, then IOPS
6266299ee426SChandrakanth Patil * and Balanced modes are not feasible.
6267299ee426SChandrakanth Patil */
6268299ee426SChandrakanth Patil if (!intr_coalescing)
6269299ee426SChandrakanth Patil instance->perf_mode = MR_LATENCY_PERF_MODE;
6270299ee426SChandrakanth Patil
6271299ee426SChandrakanth Patil }
6272299ee426SChandrakanth Patil
6273299ee426SChandrakanth Patil if (instance->perf_mode == MR_BALANCED_PERF_MODE)
6274132147d7SChandrakanth Patil instance->low_latency_index_start =
6275132147d7SChandrakanth Patil MR_HIGH_IOPS_QUEUE_COUNT;
6276132147d7SChandrakanth Patil else
6277132147d7SChandrakanth Patil instance->low_latency_index_start = 1;
6278132147d7SChandrakanth Patil
6279132147d7SChandrakanth Patil num_msix_req = num_online_cpus() + instance->low_latency_index_start;
6280132147d7SChandrakanth Patil
6281132147d7SChandrakanth Patil instance->msix_vectors = min(num_msix_req,
6282132147d7SChandrakanth Patil instance->msix_vectors);
6283132147d7SChandrakanth Patil
6284132147d7SChandrakanth Patil megasas_alloc_irq_vectors(instance);
6285132147d7SChandrakanth Patil if (!instance->msix_vectors)
62861d15d909SShivasharan S instance->msix_load_balance = false;
6287c8e858feSadam radford }
62882493c67eSSasikumar Chandrasekaran /*
62892493c67eSSasikumar Chandrasekaran * MSI-X host index 0 is common for all adapter.
62902493c67eSSasikumar Chandrasekaran * It is used for all MPT based Adapters.
62912493c67eSSasikumar Chandrasekaran */
62922493c67eSSasikumar Chandrasekaran if (instance->msix_combined) {
62932493c67eSSasikumar Chandrasekaran instance->reply_post_host_index_addr[0] =
62942493c67eSSasikumar Chandrasekaran (u32 *)((u8 *)instance->reg_set +
62952493c67eSSasikumar Chandrasekaran MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET);
62962493c67eSSasikumar Chandrasekaran } else {
62972493c67eSSasikumar Chandrasekaran instance->reply_post_host_index_addr[0] =
62982493c67eSSasikumar Chandrasekaran (u32 *)((u8 *)instance->reg_set +
62992493c67eSSasikumar Chandrasekaran MPI2_REPLY_POST_HOST_INDEX_OFFSET);
63002493c67eSSasikumar Chandrasekaran }
63012493c67eSSasikumar Chandrasekaran
630264ff64b9SShivasharan S if (!instance->msix_vectors) {
6303fad119b7SHannes Reinecke i = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_LEGACY);
6304fad119b7SHannes Reinecke if (i < 0)
63058a25fa17SShivasharan S goto fail_init_adapter;
630664ff64b9SShivasharan S }
63073f1abce4Sadam radford
6308adbe5523SMing Lei megasas_setup_reply_map(instance);
6309adbe5523SMing Lei
6310d3557fc8SSumit.Saxena@avagotech.com dev_info(&instance->pdev->dev,
6311d3557fc8SSumit.Saxena@avagotech.com "current msix/online cpus\t: (%d/%d)\n",
6312d3557fc8SSumit.Saxena@avagotech.com instance->msix_vectors, (unsigned int)num_online_cpus());
6313179ac142SSumit Saxena dev_info(&instance->pdev->dev,
6314179ac142SSumit Saxena "RDPQ mode\t: (%s)\n", instance->is_rdpq ? "enabled" : "disabled");
6315d3557fc8SSumit.Saxena@avagotech.com
631691626c27Ssumit.saxena@avagotech.com tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
631791626c27Ssumit.saxena@avagotech.com (unsigned long)instance);
631891626c27Ssumit.saxena@avagotech.com
631951087a86SSumit.Saxena@avagotech.com /*
632051087a86SSumit.Saxena@avagotech.com * Below are default value for legacy Firmware.
632151087a86SSumit.Saxena@avagotech.com * non-fusion based controllers
632251087a86SSumit.Saxena@avagotech.com */
632351087a86SSumit.Saxena@avagotech.com instance->fw_supported_vd_count = MAX_LOGICAL_DRIVES;
632451087a86SSumit.Saxena@avagotech.com instance->fw_supported_pd_count = MAX_PHYSICAL_DEVICES;
6325cd50ba8eSadam radford /* Get operational params, sge flags, send init cmd to controller */
6326cd50ba8eSadam radford if (instance->instancet->init_adapter(instance))
6327eb1b1237Sadam radford goto fail_init_adapter;
6328cd50ba8eSadam radford
6329630d42b7SShivasharan S if (instance->adapter_type >= VENTURA_SERIES) {
633081b76452SShivasharan S scratch_pad_3 =
6331272652fcSShivasharan S megasas_readl(instance,
6332272652fcSShivasharan S &instance->reg_set->outbound_scratch_pad_3);
633381b76452SShivasharan S if ((scratch_pad_3 & MR_NVME_PAGE_SIZE_MASK) >=
633415dd0381SShivasharan S MR_DEFAULT_NVME_PAGE_SHIFT)
633515dd0381SShivasharan S instance->nvme_page_size =
633681b76452SShivasharan S (1 << (scratch_pad_3 & MR_NVME_PAGE_SIZE_MASK));
633715dd0381SShivasharan S
633815dd0381SShivasharan S dev_info(&instance->pdev->dev,
633915dd0381SShivasharan S "NVME page size\t: (%d)\n", instance->nvme_page_size);
634015dd0381SShivasharan S }
634115dd0381SShivasharan S
634218103efcSTomas Henzl if (instance->msix_vectors ?
634318103efcSTomas Henzl megasas_setup_irqs_msix(instance, 1) :
634418103efcSTomas Henzl megasas_setup_irqs_ioapic(instance))
634518103efcSTomas Henzl goto fail_init_adapter;
6346258c3af2STomas Henzl
634762a04f81SShivasharan S if (instance->adapter_type != MFI_SERIES)
634862a04f81SShivasharan S megasas_setup_irq_poll(instance);
634962a04f81SShivasharan S
6350d3557fc8SSumit.Saxena@avagotech.com instance->instancet->enable_intr(instance);
6351cd50ba8eSadam radford
635213f30771SAndy Lutomirski dev_info(&instance->pdev->dev, "INIT adapter done\n");
6353cd50ba8eSadam radford
63543761cb4cSsumit.saxena@avagotech.com megasas_setup_jbod_map(instance);
63553761cb4cSsumit.saxena@avagotech.com
6356daa06811SShivasharan S if (megasas_get_device_list(instance) != SUCCESS) {
6357daa06811SShivasharan S dev_err(&instance->pdev->dev,
6358daa06811SShivasharan S "%s: megasas_get_device_list failed\n",
6359daa06811SShivasharan S __func__);
636072bff2d1SShivasharan S goto fail_get_ld_pd_list;
636158968fc8SHannes Reinecke }
63620d49016bSadam radford
6363fdd84e25SSasikumar Chandrasekaran /* stream detection initialization */
6364630d42b7SShivasharan S if (instance->adapter_type >= VENTURA_SERIES) {
6365fdd84e25SSasikumar Chandrasekaran fusion->stream_detect_by_ld =
63666396bb22SKees Cook kcalloc(MAX_LOGICAL_DRIVES_EXT,
63676396bb22SKees Cook sizeof(struct LD_STREAM_DETECT *),
6368fdd84e25SSasikumar Chandrasekaran GFP_KERNEL);
6369fdd84e25SSasikumar Chandrasekaran if (!fusion->stream_detect_by_ld) {
6370fdd84e25SSasikumar Chandrasekaran dev_err(&instance->pdev->dev,
6371fdd84e25SSasikumar Chandrasekaran "unable to allocate stream detection for pool of LDs\n");
6372fdd84e25SSasikumar Chandrasekaran goto fail_get_ld_pd_list;
6373fdd84e25SSasikumar Chandrasekaran }
6374fdd84e25SSasikumar Chandrasekaran for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i) {
6375fdd84e25SSasikumar Chandrasekaran fusion->stream_detect_by_ld[i] =
6376e05ee4e9SShivasharan S kzalloc(sizeof(struct LD_STREAM_DETECT),
6377fdd84e25SSasikumar Chandrasekaran GFP_KERNEL);
6378fdd84e25SSasikumar Chandrasekaran if (!fusion->stream_detect_by_ld[i]) {
6379fdd84e25SSasikumar Chandrasekaran dev_err(&instance->pdev->dev,
6380fdd84e25SSasikumar Chandrasekaran "unable to allocate stream detect by LD\n ");
6381fdd84e25SSasikumar Chandrasekaran for (j = 0; j < i; ++j)
6382fdd84e25SSasikumar Chandrasekaran kfree(fusion->stream_detect_by_ld[j]);
6383fdd84e25SSasikumar Chandrasekaran kfree(fusion->stream_detect_by_ld);
6384fdd84e25SSasikumar Chandrasekaran fusion->stream_detect_by_ld = NULL;
6385fdd84e25SSasikumar Chandrasekaran goto fail_get_ld_pd_list;
6386fdd84e25SSasikumar Chandrasekaran }
6387fdd84e25SSasikumar Chandrasekaran fusion->stream_detect_by_ld[i]->mru_bit_map
6388fdd84e25SSasikumar Chandrasekaran = MR_STREAM_BITMAP;
6389fdd84e25SSasikumar Chandrasekaran }
6390fdd84e25SSasikumar Chandrasekaran }
6391fdd84e25SSasikumar Chandrasekaran
63920d49016bSadam radford /*
63930d49016bSadam radford * Compute the max allowed sectors per IO: The controller info has two
63940d49016bSadam radford * limits on max sectors. Driver should use the minimum of these two.
63950d49016bSadam radford *
63960d49016bSadam radford * 1 << stripe_sz_ops.min = max sectors per strip
63970d49016bSadam radford *
63980d49016bSadam radford * Note that older firmwares ( < FW ver 30) didn't report information
63990d49016bSadam radford * to calculate max_sectors_1. So the number ended up as zero always.
64000d49016bSadam radford */
64010d49016bSadam radford tmp_sectors = 0;
64029ad18a9cSShivasharan S ctrl_info = instance->ctrl_info_buf;
64030d49016bSadam radford
64040d49016bSadam radford max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) *
640594cd65ddSSumit.Saxena@lsi.com le16_to_cpu(ctrl_info->max_strips_per_io);
640694cd65ddSSumit.Saxena@lsi.com max_sectors_2 = le32_to_cpu(ctrl_info->max_request_size);
64070d49016bSadam radford
64080d49016bSadam radford tmp_sectors = min_t(u32, max_sectors_1, max_sectors_2);
6409404a8a1aSSumit.Saxena@lsi.com
64108f67c8c5SSumit Saxena instance->peerIsPresent = ctrl_info->cluster.peerIsPresent;
64118f67c8c5SSumit Saxena instance->passive = ctrl_info->cluster.passive;
64128f67c8c5SSumit Saxena memcpy(instance->clusterId, ctrl_info->clusterId, sizeof(instance->clusterId));
6413bc93d425SSumit.Saxena@lsi.com instance->UnevenSpanSupport =
6414bc93d425SSumit.Saxena@lsi.com ctrl_info->adapterOperations2.supportUnevenSpans;
6415bc93d425SSumit.Saxena@lsi.com if (instance->UnevenSpanSupport) {
6416bc93d425SSumit.Saxena@lsi.com struct fusion_context *fusion = instance->ctrl_context;
64175f19f7c8SShivasharan S if (MR_ValidateMapInfo(instance, instance->map_id))
6418bc93d425SSumit.Saxena@lsi.com fusion->fast_path_io = 1;
6419bc93d425SSumit.Saxena@lsi.com else
6420bc93d425SSumit.Saxena@lsi.com fusion->fast_path_io = 0;
6421bc93d425SSumit.Saxena@lsi.com
6422bc93d425SSumit.Saxena@lsi.com }
6423229fe47cSadam radford if (ctrl_info->host_interface.SRIOV) {
642492bb6505Ssumit.saxena@avagotech.com instance->requestorId = ctrl_info->iov.requestorId;
642592bb6505Ssumit.saxena@avagotech.com if (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) {
6426229fe47cSadam radford if (!ctrl_info->adapterOperations2.activePassive)
6427229fe47cSadam radford instance->PlasmaFW111 = 1;
6428229fe47cSadam radford
642992bb6505Ssumit.saxena@avagotech.com dev_info(&instance->pdev->dev, "SR-IOV: firmware type: %s\n",
643092bb6505Ssumit.saxena@avagotech.com instance->PlasmaFW111 ? "1.11" : "new");
643192bb6505Ssumit.saxena@avagotech.com
643292bb6505Ssumit.saxena@avagotech.com if (instance->PlasmaFW111) {
643392bb6505Ssumit.saxena@avagotech.com iovPtr = (struct IOV_111 *)
643492bb6505Ssumit.saxena@avagotech.com ((unsigned char *)ctrl_info + IOV_111_OFFSET);
6435229fe47cSadam radford instance->requestorId = iovPtr->requestorId;
6436229fe47cSadam radford }
643792bb6505Ssumit.saxena@avagotech.com }
643892bb6505Ssumit.saxena@avagotech.com dev_info(&instance->pdev->dev, "SRIOV: VF requestorId %d\n",
643992bb6505Ssumit.saxena@avagotech.com instance->requestorId);
6440229fe47cSadam radford }
6441fc62b3fcSSumit.Saxena@avagotech.com
6442fc62b3fcSSumit.Saxena@avagotech.com instance->crash_dump_fw_support =
6443fc62b3fcSSumit.Saxena@avagotech.com ctrl_info->adapterOperations3.supportCrashDump;
6444fc62b3fcSSumit.Saxena@avagotech.com instance->crash_dump_drv_support =
6445fc62b3fcSSumit.Saxena@avagotech.com (instance->crash_dump_fw_support &&
6446fc62b3fcSSumit.Saxena@avagotech.com instance->crash_dump_buf);
6447d88da09aSSumit.Saxena@avagotech.com if (instance->crash_dump_drv_support)
6448fc62b3fcSSumit.Saxena@avagotech.com megasas_set_crash_dump_params(instance,
6449fc62b3fcSSumit.Saxena@avagotech.com MR_CRASH_BUF_TURN_OFF);
6450fc62b3fcSSumit.Saxena@avagotech.com
6451d88da09aSSumit.Saxena@avagotech.com else {
6452fc62b3fcSSumit.Saxena@avagotech.com if (instance->crash_dump_buf)
645360ee6529SChristoph Hellwig dma_free_coherent(&instance->pdev->dev,
6454fc62b3fcSSumit.Saxena@avagotech.com CRASH_DMA_BUF_SIZE,
6455fc62b3fcSSumit.Saxena@avagotech.com instance->crash_dump_buf,
6456fc62b3fcSSumit.Saxena@avagotech.com instance->crash_dump_h);
6457fc62b3fcSSumit.Saxena@avagotech.com instance->crash_dump_buf = NULL;
6458fc62b3fcSSumit.Saxena@avagotech.com }
64597497cde8SSumit.Saxena@avagotech.com
6460f0c21df6SShivasharan S if (instance->snapdump_wait_time) {
6461f0c21df6SShivasharan S megasas_get_snapdump_properties(instance);
6462f0c21df6SShivasharan S dev_info(&instance->pdev->dev, "Snap dump wait time\t: %d\n",
6463f0c21df6SShivasharan S instance->snapdump_wait_time);
6464f0c21df6SShivasharan S }
6465d88da09aSSumit.Saxena@avagotech.com
6466d88da09aSSumit.Saxena@avagotech.com dev_info(&instance->pdev->dev,
6467d88da09aSSumit.Saxena@avagotech.com "pci id\t\t: (0x%04x)/(0x%04x)/(0x%04x)/(0x%04x)\n",
6468d88da09aSSumit.Saxena@avagotech.com le16_to_cpu(ctrl_info->pci.vendor_id),
6469d88da09aSSumit.Saxena@avagotech.com le16_to_cpu(ctrl_info->pci.device_id),
6470d88da09aSSumit.Saxena@avagotech.com le16_to_cpu(ctrl_info->pci.sub_vendor_id),
6471d88da09aSSumit.Saxena@avagotech.com le16_to_cpu(ctrl_info->pci.sub_device_id));
6472d88da09aSSumit.Saxena@avagotech.com dev_info(&instance->pdev->dev, "unevenspan support : %s\n",
6473d88da09aSSumit.Saxena@avagotech.com instance->UnevenSpanSupport ? "yes" : "no");
6474d88da09aSSumit.Saxena@avagotech.com dev_info(&instance->pdev->dev, "firmware crash dump : %s\n",
6475d88da09aSSumit.Saxena@avagotech.com instance->crash_dump_drv_support ? "yes" : "no");
647659db5a93SChandrakanth Patil dev_info(&instance->pdev->dev, "JBOD sequence map : %s\n",
647759db5a93SChandrakanth Patil instance->use_seqnum_jbod_fp ? "enabled" : "disabled");
6478d88da09aSSumit.Saxena@avagotech.com
64790d49016bSadam radford instance->max_sectors_per_req = instance->max_num_sge *
6480357ae967Ssumit.saxena@avagotech.com SGE_BUFFER_SIZE / 512;
64810d49016bSadam radford if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
64820d49016bSadam radford instance->max_sectors_per_req = tmp_sectors;
64830d49016bSadam radford
6484ae09a6c1SSumit.Saxena@avagotech.com /* Check for valid throttlequeuedepth module parameter */
6485ae09a6c1SSumit.Saxena@avagotech.com if (throttlequeuedepth &&
6486ae09a6c1SSumit.Saxena@avagotech.com throttlequeuedepth <= instance->max_scsi_cmds)
6487ae09a6c1SSumit.Saxena@avagotech.com instance->throttlequeuedepth = throttlequeuedepth;
6488ae09a6c1SSumit.Saxena@avagotech.com else
6489c5daa6a9Sadam radford instance->throttlequeuedepth =
6490c5daa6a9Sadam radford MEGASAS_THROTTLE_QUEUE_DEPTH;
6491c5daa6a9Sadam radford
6492e636a7a4SShivasharan S if ((resetwaittime < 1) ||
6493e636a7a4SShivasharan S (resetwaittime > MEGASAS_RESET_WAIT_TIME))
6494e3d178caSSumit Saxena resetwaittime = MEGASAS_RESET_WAIT_TIME;
6495e3d178caSSumit Saxena
6496e3d178caSSumit Saxena if ((scmd_timeout < 10) || (scmd_timeout > MEGASAS_DEFAULT_CMD_TIMEOUT))
6497e3d178caSSumit Saxena scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
64980d49016bSadam radford
6499229fe47cSadam radford /* Launch SR-IOV heartbeat timer */
6500229fe47cSadam radford if (instance->requestorId) {
65012e47e4e6SShivasharan S if (!megasas_sriov_start_heartbeat(instance, 1)) {
6502c251a7beSKees Cook megasas_start_timer(instance);
65032e47e4e6SShivasharan S } else {
6504229fe47cSadam radford instance->skip_heartbeat_timer_del = 1;
65052e47e4e6SShivasharan S goto fail_get_ld_pd_list;
65062e47e4e6SShivasharan S }
6507229fe47cSadam radford }
6508229fe47cSadam radford
65093f6194afSShivasharan S /*
65103f6194afSShivasharan S * Create and start watchdog thread which will monitor
65113f6194afSShivasharan S * controller state every 1 sec and trigger OCR when
65123f6194afSShivasharan S * it enters fault state
65133f6194afSShivasharan S */
65143f6194afSShivasharan S if (instance->adapter_type != MFI_SERIES)
65153f6194afSShivasharan S if (megasas_fusion_start_watchdog(instance) != SUCCESS)
65163f6194afSShivasharan S goto fail_start_watchdog;
65173f6194afSShivasharan S
65180d49016bSadam radford return 0;
65190d49016bSadam radford
65203f6194afSShivasharan S fail_start_watchdog:
65213f6194afSShivasharan S if (instance->requestorId && !instance->skip_heartbeat_timer_del)
65223f6194afSShivasharan S del_timer_sync(&instance->sriov_heartbeat_timer);
6523fdd84e25SSasikumar Chandrasekaran fail_get_ld_pd_list:
6524fdd84e25SSasikumar Chandrasekaran instance->instancet->disable_intr(instance);
6525fad119b7SHannes Reinecke megasas_destroy_irqs(instance);
65268a25fa17SShivasharan S fail_init_adapter:
6527d3557fc8SSumit.Saxena@avagotech.com if (instance->msix_vectors)
6528fad119b7SHannes Reinecke pci_free_irq_vectors(instance->pdev);
6529d3557fc8SSumit.Saxena@avagotech.com instance->msix_vectors = 0;
6530e5d65b4bSShivasharan S fail_alloc_dma_buf:
6531e5d65b4bSShivasharan S megasas_free_ctrl_dma_buffers(instance);
6532e5d65b4bSShivasharan S megasas_free_ctrl_mem(instance);
65330d49016bSadam radford fail_ready_state:
65340d49016bSadam radford iounmap(instance->reg_set);
65350d49016bSadam radford
65360d49016bSadam radford fail_ioremap:
6537e7f85168SYinghai Lu pci_release_selected_regions(instance->pdev, 1<<instance->bar);
65380d49016bSadam radford
653972bff2d1SShivasharan S dev_err(&instance->pdev->dev, "Failed from %s %d\n",
654072bff2d1SShivasharan S __func__, __LINE__);
65410d49016bSadam radford return -EINVAL;
65420d49016bSadam radford }
65430d49016bSadam radford
65440d49016bSadam radford /**
65450d49016bSadam radford * megasas_release_mfi - Reverses the FW initialization
65464b63b286SGeert Uytterhoeven * @instance: Adapter soft state
65470d49016bSadam radford */
megasas_release_mfi(struct megasas_instance * instance)65480d49016bSadam radford static void megasas_release_mfi(struct megasas_instance *instance)
65490d49016bSadam radford {
65509c915a8cSadam radford u32 reply_q_sz = sizeof(u32) *(instance->max_mfi_cmds + 1);
65510d49016bSadam radford
65529c915a8cSadam radford if (instance->reply_queue)
655360ee6529SChristoph Hellwig dma_free_coherent(&instance->pdev->dev, reply_q_sz,
65540d49016bSadam radford instance->reply_queue, instance->reply_queue_h);
65550d49016bSadam radford
65560d49016bSadam radford megasas_free_cmds(instance);
65570d49016bSadam radford
65580d49016bSadam radford iounmap(instance->reg_set);
65590d49016bSadam radford
6560e7f85168SYinghai Lu pci_release_selected_regions(instance->pdev, 1<<instance->bar);
65610d49016bSadam radford }
65620d49016bSadam radford
65630d49016bSadam radford /**
65640d49016bSadam radford * megasas_get_seq_num - Gets latest event sequence numbers
65650d49016bSadam radford * @instance: Adapter soft state
65660d49016bSadam radford * @eli: FW event log sequence numbers information
65670d49016bSadam radford *
65680d49016bSadam radford * FW maintains a log of all events in a non-volatile area. Upper layers would
65690d49016bSadam radford * usually find out the latest sequence number of the events, the seq number at
65700d49016bSadam radford * the boot etc. They would "read" all the events below the latest seq number
65710d49016bSadam radford * by issuing a direct fw cmd (DCMD). For the future events (beyond latest seq
65720d49016bSadam radford * number), they would subsribe to AEN (asynchronous event notification) and
65730d49016bSadam radford * wait for the events to happen.
65740d49016bSadam radford */
65750d49016bSadam radford static int
megasas_get_seq_num(struct megasas_instance * instance,struct megasas_evt_log_info * eli)65760d49016bSadam radford megasas_get_seq_num(struct megasas_instance *instance,
65770d49016bSadam radford struct megasas_evt_log_info *eli)
65780d49016bSadam radford {
65790d49016bSadam radford struct megasas_cmd *cmd;
65800d49016bSadam radford struct megasas_dcmd_frame *dcmd;
65810d49016bSadam radford struct megasas_evt_log_info *el_info;
65820d49016bSadam radford dma_addr_t el_info_h = 0;
6583b051cc66SShivasharan S int ret;
65840d49016bSadam radford
65850d49016bSadam radford cmd = megasas_get_cmd(instance);
65860d49016bSadam radford
65870d49016bSadam radford if (!cmd) {
65880d49016bSadam radford return -ENOMEM;
65890d49016bSadam radford }
65900d49016bSadam radford
65910d49016bSadam radford dcmd = &cmd->frame->dcmd;
6592750afb08SLuis Chamberlain el_info = dma_alloc_coherent(&instance->pdev->dev,
6593750afb08SLuis Chamberlain sizeof(struct megasas_evt_log_info),
6594750afb08SLuis Chamberlain &el_info_h, GFP_KERNEL);
65950d49016bSadam radford if (!el_info) {
65960d49016bSadam radford megasas_return_cmd(instance, cmd);
65970d49016bSadam radford return -ENOMEM;
65980d49016bSadam radford }
65990d49016bSadam radford
66000d49016bSadam radford memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
66010d49016bSadam radford
66020d49016bSadam radford dcmd->cmd = MFI_CMD_DCMD;
66030d49016bSadam radford dcmd->cmd_status = 0x0;
66040d49016bSadam radford dcmd->sge_count = 1;
6605107a60ddSShivasharan S dcmd->flags = MFI_FRAME_DIR_READ;
66060d49016bSadam radford dcmd->timeout = 0;
66070d49016bSadam radford dcmd->pad_0 = 0;
660894cd65ddSSumit.Saxena@lsi.com dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_evt_log_info));
660994cd65ddSSumit.Saxena@lsi.com dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_EVENT_GET_INFO);
6610107a60ddSShivasharan S
6611107a60ddSShivasharan S megasas_set_dma_settings(instance, dcmd, el_info_h,
6612107a60ddSShivasharan S sizeof(struct megasas_evt_log_info));
66130d49016bSadam radford
6614b051cc66SShivasharan S ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
6615b051cc66SShivasharan S if (ret != DCMD_SUCCESS) {
6616b051cc66SShivasharan S dev_err(&instance->pdev->dev, "Failed from %s %d\n",
6617b051cc66SShivasharan S __func__, __LINE__);
6618b051cc66SShivasharan S goto dcmd_failed;
6619b051cc66SShivasharan S }
6620b051cc66SShivasharan S
66210d49016bSadam radford /*
66220d49016bSadam radford * Copy the data back into callers buffer
66230d49016bSadam radford */
662448100b0eSChristoph Hellwig eli->newest_seq_num = el_info->newest_seq_num;
662548100b0eSChristoph Hellwig eli->oldest_seq_num = el_info->oldest_seq_num;
662648100b0eSChristoph Hellwig eli->clear_seq_num = el_info->clear_seq_num;
662748100b0eSChristoph Hellwig eli->shutdown_seq_num = el_info->shutdown_seq_num;
662848100b0eSChristoph Hellwig eli->boot_seq_num = el_info->boot_seq_num;
66290d49016bSadam radford
6630b051cc66SShivasharan S dcmd_failed:
663160ee6529SChristoph Hellwig dma_free_coherent(&instance->pdev->dev,
663260ee6529SChristoph Hellwig sizeof(struct megasas_evt_log_info),
66330d49016bSadam radford el_info, el_info_h);
66340d49016bSadam radford
66350d49016bSadam radford megasas_return_cmd(instance, cmd);
66360d49016bSadam radford
6637b051cc66SShivasharan S return ret;
66380d49016bSadam radford }
66390d49016bSadam radford
66400d49016bSadam radford /**
66410d49016bSadam radford * megasas_register_aen - Registers for asynchronous event notification
66420d49016bSadam radford * @instance: Adapter soft state
66430d49016bSadam radford * @seq_num: The starting sequence number
66442b46e5c1SDamien Le Moal * @class_locale_word: Class of the event
66450d49016bSadam radford *
66460d49016bSadam radford * This function subscribes for AEN for events beyond the @seq_num. It requests
66470d49016bSadam radford * to be notified if and only if the event is of type @class_locale
66480d49016bSadam radford */
66490d49016bSadam radford static int
megasas_register_aen(struct megasas_instance * instance,u32 seq_num,u32 class_locale_word)66500d49016bSadam radford megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
66510d49016bSadam radford u32 class_locale_word)
66520d49016bSadam radford {
66530d49016bSadam radford int ret_val;
66540d49016bSadam radford struct megasas_cmd *cmd;
66550d49016bSadam radford struct megasas_dcmd_frame *dcmd;
66560d49016bSadam radford union megasas_evt_class_locale curr_aen;
66570d49016bSadam radford union megasas_evt_class_locale prev_aen;
66580d49016bSadam radford
66590d49016bSadam radford /*
66600d49016bSadam radford * If there an AEN pending already (aen_cmd), check if the
66610d49016bSadam radford * class_locale of that pending AEN is inclusive of the new
66620d49016bSadam radford * AEN request we currently have. If it is, then we don't have
66630d49016bSadam radford * to do anything. In other words, whichever events the current
66640d49016bSadam radford * AEN request is subscribing to, have already been subscribed
66650d49016bSadam radford * to.
66660d49016bSadam radford *
66670d49016bSadam radford * If the old_cmd is _not_ inclusive, then we have to abort
66680d49016bSadam radford * that command, form a class_locale that is superset of both
66690d49016bSadam radford * old and current and re-issue to the FW
66700d49016bSadam radford */
66710d49016bSadam radford
66720d49016bSadam radford curr_aen.word = class_locale_word;
66730d49016bSadam radford
66740d49016bSadam radford if (instance->aen_cmd) {
66750d49016bSadam radford
6676a9555534SChristoph Hellwig prev_aen.word =
6677a9555534SChristoph Hellwig le32_to_cpu(instance->aen_cmd->frame->dcmd.mbox.w[1]);
66780d49016bSadam radford
667991b3d9f0SShivasharan S if ((curr_aen.members.class < MFI_EVT_CLASS_DEBUG) ||
668091b3d9f0SShivasharan S (curr_aen.members.class > MFI_EVT_CLASS_DEAD)) {
668191b3d9f0SShivasharan S dev_info(&instance->pdev->dev,
668291b3d9f0SShivasharan S "%s %d out of range class %d send by application\n",
668391b3d9f0SShivasharan S __func__, __LINE__, curr_aen.members.class);
668491b3d9f0SShivasharan S return 0;
668591b3d9f0SShivasharan S }
668691b3d9f0SShivasharan S
66870d49016bSadam radford /*
66880d49016bSadam radford * A class whose enum value is smaller is inclusive of all
66890d49016bSadam radford * higher values. If a PROGRESS (= -1) was previously
66900d49016bSadam radford * registered, then a new registration requests for higher
66910d49016bSadam radford * classes need not be sent to FW. They are automatically
66920d49016bSadam radford * included.
66930d49016bSadam radford *
66940d49016bSadam radford * Locale numbers don't have such hierarchy. They are bitmap
66950d49016bSadam radford * values
66960d49016bSadam radford */
66970d49016bSadam radford if ((prev_aen.members.class <= curr_aen.members.class) &&
66983993a862SSumit.Saxena@lsi.com !((prev_aen.members.locale & curr_aen.members.locale) ^
66990d49016bSadam radford curr_aen.members.locale)) {
67000d49016bSadam radford /*
67010d49016bSadam radford * Previously issued event registration includes
67020d49016bSadam radford * current request. Nothing to do.
67030d49016bSadam radford */
67040d49016bSadam radford return 0;
67050d49016bSadam radford } else {
67063993a862SSumit.Saxena@lsi.com curr_aen.members.locale |= prev_aen.members.locale;
67070d49016bSadam radford
67080d49016bSadam radford if (prev_aen.members.class < curr_aen.members.class)
67090d49016bSadam radford curr_aen.members.class = prev_aen.members.class;
67100d49016bSadam radford
67110d49016bSadam radford instance->aen_cmd->abort_aen = 1;
67120d49016bSadam radford ret_val = megasas_issue_blocked_abort_cmd(instance,
67130d49016bSadam radford instance->
6714cfbe7554SSumit.Saxena@lsi.com aen_cmd, 30);
67150d49016bSadam radford
67160d49016bSadam radford if (ret_val) {
67171be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to abort "
67180d49016bSadam radford "previous AEN command\n");
67190d49016bSadam radford return ret_val;
67200d49016bSadam radford }
67210d49016bSadam radford }
67220d49016bSadam radford }
67230d49016bSadam radford
67240d49016bSadam radford cmd = megasas_get_cmd(instance);
67250d49016bSadam radford
67260d49016bSadam radford if (!cmd)
67270d49016bSadam radford return -ENOMEM;
67280d49016bSadam radford
67290d49016bSadam radford dcmd = &cmd->frame->dcmd;
67300d49016bSadam radford
67310d49016bSadam radford memset(instance->evt_detail, 0, sizeof(struct megasas_evt_detail));
67320d49016bSadam radford
67330d49016bSadam radford /*
67340d49016bSadam radford * Prepare DCMD for aen registration
67350d49016bSadam radford */
67360d49016bSadam radford memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
67370d49016bSadam radford
67380d49016bSadam radford dcmd->cmd = MFI_CMD_DCMD;
67390d49016bSadam radford dcmd->cmd_status = 0x0;
67400d49016bSadam radford dcmd->sge_count = 1;
6741107a60ddSShivasharan S dcmd->flags = MFI_FRAME_DIR_READ;
67420d49016bSadam radford dcmd->timeout = 0;
67430d49016bSadam radford dcmd->pad_0 = 0;
674494cd65ddSSumit.Saxena@lsi.com dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_evt_detail));
674594cd65ddSSumit.Saxena@lsi.com dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_EVENT_WAIT);
674694cd65ddSSumit.Saxena@lsi.com dcmd->mbox.w[0] = cpu_to_le32(seq_num);
67470d49016bSadam radford instance->last_seq_num = seq_num;
674894cd65ddSSumit.Saxena@lsi.com dcmd->mbox.w[1] = cpu_to_le32(curr_aen.word);
6749107a60ddSShivasharan S
6750107a60ddSShivasharan S megasas_set_dma_settings(instance, dcmd, instance->evt_detail_h,
6751107a60ddSShivasharan S sizeof(struct megasas_evt_detail));
67520d49016bSadam radford
67530d49016bSadam radford if (instance->aen_cmd != NULL) {
67540d49016bSadam radford megasas_return_cmd(instance, cmd);
67550d49016bSadam radford return 0;
67560d49016bSadam radford }
67570d49016bSadam radford
67580d49016bSadam radford /*
67590d49016bSadam radford * Store reference to the cmd used to register for AEN. When an
67600d49016bSadam radford * application wants us to register for AEN, we have to abort this
67610d49016bSadam radford * cmd and re-register with a new EVENT LOCALE supplied by that app
67620d49016bSadam radford */
67630d49016bSadam radford instance->aen_cmd = cmd;
67640d49016bSadam radford
67650d49016bSadam radford /*
67660d49016bSadam radford * Issue the aen registration frame
67670d49016bSadam radford */
67689c915a8cSadam radford instance->instancet->issue_dcmd(instance, cmd);
67690d49016bSadam radford
67700d49016bSadam radford return 0;
67710d49016bSadam radford }
67720d49016bSadam radford
677396188a89SShivasharan S /* megasas_get_target_prop - Send DCMD with below details to firmware.
677496188a89SShivasharan S *
677596188a89SShivasharan S * This DCMD will fetch few properties of LD/system PD defined
677696188a89SShivasharan S * in MR_TARGET_DEV_PROPERTIES. eg. Queue Depth, MDTS value.
677796188a89SShivasharan S *
677896188a89SShivasharan S * DCMD send by drivers whenever new target is added to the OS.
677996188a89SShivasharan S *
678096188a89SShivasharan S * dcmd.opcode - MR_DCMD_DEV_GET_TARGET_PROP
678196188a89SShivasharan S * dcmd.mbox.b[0] - DCMD is to be fired for LD or system PD.
678296188a89SShivasharan S * 0 = system PD, 1 = LD.
678396188a89SShivasharan S * dcmd.mbox.s[1] - TargetID for LD/system PD.
678496188a89SShivasharan S * dcmd.sge IN - Pointer to return MR_TARGET_DEV_PROPERTIES.
678596188a89SShivasharan S *
678696188a89SShivasharan S * @instance: Adapter soft state
678796188a89SShivasharan S * @sdev: OS provided scsi device
678896188a89SShivasharan S *
678996188a89SShivasharan S * Returns 0 on success non-zero on failure.
679096188a89SShivasharan S */
6791e9495e2dSShivasharan S int
megasas_get_target_prop(struct megasas_instance * instance,struct scsi_device * sdev)679296188a89SShivasharan S megasas_get_target_prop(struct megasas_instance *instance,
679396188a89SShivasharan S struct scsi_device *sdev)
679496188a89SShivasharan S {
679596188a89SShivasharan S int ret;
679696188a89SShivasharan S struct megasas_cmd *cmd;
679796188a89SShivasharan S struct megasas_dcmd_frame *dcmd;
6798c8f96df5SShivasharan S u16 targetId = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) +
6799c8f96df5SShivasharan S sdev->id;
680096188a89SShivasharan S
680196188a89SShivasharan S cmd = megasas_get_cmd(instance);
680296188a89SShivasharan S
680396188a89SShivasharan S if (!cmd) {
680496188a89SShivasharan S dev_err(&instance->pdev->dev,
680596188a89SShivasharan S "Failed to get cmd %s\n", __func__);
680696188a89SShivasharan S return -ENOMEM;
680796188a89SShivasharan S }
680896188a89SShivasharan S
680996188a89SShivasharan S dcmd = &cmd->frame->dcmd;
681096188a89SShivasharan S
681196188a89SShivasharan S memset(instance->tgt_prop, 0, sizeof(*instance->tgt_prop));
681296188a89SShivasharan S memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
681396188a89SShivasharan S dcmd->mbox.b[0] = MEGASAS_IS_LOGICAL(sdev);
681496188a89SShivasharan S
681596188a89SShivasharan S dcmd->mbox.s[1] = cpu_to_le16(targetId);
681696188a89SShivasharan S dcmd->cmd = MFI_CMD_DCMD;
681796188a89SShivasharan S dcmd->cmd_status = 0xFF;
681896188a89SShivasharan S dcmd->sge_count = 1;
6819107a60ddSShivasharan S dcmd->flags = MFI_FRAME_DIR_READ;
682096188a89SShivasharan S dcmd->timeout = 0;
682196188a89SShivasharan S dcmd->pad_0 = 0;
682296188a89SShivasharan S dcmd->data_xfer_len =
682396188a89SShivasharan S cpu_to_le32(sizeof(struct MR_TARGET_PROPERTIES));
682496188a89SShivasharan S dcmd->opcode = cpu_to_le32(MR_DCMD_DRV_GET_TARGET_PROP);
682596188a89SShivasharan S
6826107a60ddSShivasharan S megasas_set_dma_settings(instance, dcmd, instance->tgt_prop_h,
6827107a60ddSShivasharan S sizeof(struct MR_TARGET_PROPERTIES));
682896188a89SShivasharan S
6829e7d36b88SShivasharan S if ((instance->adapter_type != MFI_SERIES) &&
6830e7d36b88SShivasharan S !instance->mask_interrupts)
683196188a89SShivasharan S ret = megasas_issue_blocked_cmd(instance,
683296188a89SShivasharan S cmd, MFI_IO_TIMEOUT_SECS);
683396188a89SShivasharan S else
683496188a89SShivasharan S ret = megasas_issue_polled(instance, cmd);
683596188a89SShivasharan S
683696188a89SShivasharan S switch (ret) {
683796188a89SShivasharan S case DCMD_TIMEOUT:
683896188a89SShivasharan S switch (dcmd_timeout_ocr_possible(instance)) {
683996188a89SShivasharan S case INITIATE_OCR:
684096188a89SShivasharan S cmd->flags |= DRV_DCMD_SKIP_REFIRE;
68417fa3174bSChandrakanth Patil mutex_unlock(&instance->reset_mutex);
684296188a89SShivasharan S megasas_reset_fusion(instance->host,
684396188a89SShivasharan S MFI_IO_TIMEOUT_OCR);
68447fa3174bSChandrakanth Patil mutex_lock(&instance->reset_mutex);
684596188a89SShivasharan S break;
684696188a89SShivasharan S case KILL_ADAPTER:
684796188a89SShivasharan S megaraid_sas_kill_hba(instance);
684896188a89SShivasharan S break;
684996188a89SShivasharan S case IGNORE_TIMEOUT:
685096188a89SShivasharan S dev_info(&instance->pdev->dev,
685196188a89SShivasharan S "Ignore DCMD timeout: %s %d\n",
685296188a89SShivasharan S __func__, __LINE__);
685396188a89SShivasharan S break;
685496188a89SShivasharan S }
685596188a89SShivasharan S break;
685696188a89SShivasharan S
685796188a89SShivasharan S default:
685896188a89SShivasharan S megasas_return_cmd(instance, cmd);
685996188a89SShivasharan S }
686096188a89SShivasharan S if (ret != DCMD_SUCCESS)
686196188a89SShivasharan S dev_err(&instance->pdev->dev,
686296188a89SShivasharan S "return from %s %d return value %d\n",
686396188a89SShivasharan S __func__, __LINE__, ret);
686496188a89SShivasharan S
686596188a89SShivasharan S return ret;
686696188a89SShivasharan S }
686796188a89SShivasharan S
68680d49016bSadam radford /**
68690d49016bSadam radford * megasas_start_aen - Subscribes to AEN during driver load time
68700d49016bSadam radford * @instance: Adapter soft state
68710d49016bSadam radford */
megasas_start_aen(struct megasas_instance * instance)68720d49016bSadam radford static int megasas_start_aen(struct megasas_instance *instance)
68730d49016bSadam radford {
68740d49016bSadam radford struct megasas_evt_log_info eli;
68750d49016bSadam radford union megasas_evt_class_locale class_locale;
68760d49016bSadam radford
68770d49016bSadam radford /*
68780d49016bSadam radford * Get the latest sequence number from FW
68790d49016bSadam radford */
68800d49016bSadam radford memset(&eli, 0, sizeof(eli));
68810d49016bSadam radford
68820d49016bSadam radford if (megasas_get_seq_num(instance, &eli))
68830d49016bSadam radford return -1;
68840d49016bSadam radford
68850d49016bSadam radford /*
68860d49016bSadam radford * Register AEN with FW for latest sequence number plus 1
68870d49016bSadam radford */
68880d49016bSadam radford class_locale.members.reserved = 0;
68890d49016bSadam radford class_locale.members.locale = MR_EVT_LOCALE_ALL;
68900d49016bSadam radford class_locale.members.class = MR_EVT_CLASS_DEBUG;
68910d49016bSadam radford
689294cd65ddSSumit.Saxena@lsi.com return megasas_register_aen(instance,
689348100b0eSChristoph Hellwig le32_to_cpu(eli.newest_seq_num) + 1,
68940d49016bSadam radford class_locale.word);
68950d49016bSadam radford }
68960d49016bSadam radford
68970d49016bSadam radford /**
68980d49016bSadam radford * megasas_io_attach - Attaches this driver to SCSI mid-layer
68990d49016bSadam radford * @instance: Adapter soft state
69000d49016bSadam radford */
megasas_io_attach(struct megasas_instance * instance)69010d49016bSadam radford static int megasas_io_attach(struct megasas_instance *instance)
69020d49016bSadam radford {
69030d49016bSadam radford struct Scsi_Host *host = instance->host;
69040d49016bSadam radford
69050d49016bSadam radford /*
69060d49016bSadam radford * Export parameters required by SCSI mid-layer
69070d49016bSadam radford */
69080d49016bSadam radford host->unique_id = instance->unique_id;
6909ae09a6c1SSumit.Saxena@avagotech.com host->can_queue = instance->max_scsi_cmds;
69100d49016bSadam radford host->this_id = instance->init_id;
69110d49016bSadam radford host->sg_tablesize = instance->max_num_sge;
691242a8d2b3Sadam radford
691342a8d2b3Sadam radford if (instance->fw_support_ieee)
691442a8d2b3Sadam radford instance->max_sectors_per_req = MEGASAS_MAX_SECTORS_IEEE;
691542a8d2b3Sadam radford
69160d49016bSadam radford /*
69170d49016bSadam radford * Check if the module parameter value for max_sectors can be used
69180d49016bSadam radford */
69190d49016bSadam radford if (max_sectors && max_sectors < instance->max_sectors_per_req)
69200d49016bSadam radford instance->max_sectors_per_req = max_sectors;
69210d49016bSadam radford else {
69220d49016bSadam radford if (max_sectors) {
69230d49016bSadam radford if (((instance->pdev->device ==
69240d49016bSadam radford PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
69250d49016bSadam radford (instance->pdev->device ==
69260d49016bSadam radford PCI_DEVICE_ID_LSI_SAS0079GEN2)) &&
69270d49016bSadam radford (max_sectors <= MEGASAS_MAX_SECTORS)) {
69280d49016bSadam radford instance->max_sectors_per_req = max_sectors;
69290d49016bSadam radford } else {
69301be18254SBjorn Helgaas dev_info(&instance->pdev->dev, "max_sectors should be > 0"
69310d49016bSadam radford "and <= %d (or < 1MB for GEN2 controller)\n",
69320d49016bSadam radford instance->max_sectors_per_req);
69330d49016bSadam radford }
69340d49016bSadam radford }
69350d49016bSadam radford }
69360d49016bSadam radford
69370d49016bSadam radford host->max_sectors = instance->max_sectors_per_req;
69389c915a8cSadam radford host->cmd_per_lun = MEGASAS_DEFAULT_CMD_PER_LUN;
69390d49016bSadam radford host->max_channel = MEGASAS_MAX_CHANNELS - 1;
69400d49016bSadam radford host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL;
69410d49016bSadam radford host->max_lun = MEGASAS_MAX_LUN;
69420d49016bSadam radford host->max_cmd_len = 16;
69430d49016bSadam radford
694481e7eb5bSMartin K. Petersen /* Use shared host tagset only for fusion adaptors
694581e7eb5bSMartin K. Petersen * if there are managed interrupts (smp affinity enabled case).
694681e7eb5bSMartin K. Petersen * Single msix_vectors in kdump, so shared host tag is also disabled.
694781e7eb5bSMartin K. Petersen */
694881e7eb5bSMartin K. Petersen
694981e7eb5bSMartin K. Petersen host->host_tagset = 0;
695081e7eb5bSMartin K. Petersen host->nr_hw_queues = 1;
695181e7eb5bSMartin K. Petersen
695281e7eb5bSMartin K. Petersen if ((instance->adapter_type != MFI_SERIES) &&
695381e7eb5bSMartin K. Petersen (instance->msix_vectors > instance->low_latency_index_start) &&
695481e7eb5bSMartin K. Petersen host_tagset_enable &&
695581e7eb5bSMartin K. Petersen instance->smp_affinity_enable) {
695681e7eb5bSMartin K. Petersen host->host_tagset = 1;
695781e7eb5bSMartin K. Petersen host->nr_hw_queues = instance->msix_vectors -
69589e4bec5bSKashyap Desai instance->low_latency_index_start + instance->iopoll_q_count;
69599e4bec5bSKashyap Desai if (instance->iopoll_q_count)
69609e4bec5bSKashyap Desai host->nr_maps = 3;
69619e4bec5bSKashyap Desai } else {
69629e4bec5bSKashyap Desai instance->iopoll_q_count = 0;
696381e7eb5bSMartin K. Petersen }
696481e7eb5bSMartin K. Petersen
696581e7eb5bSMartin K. Petersen dev_info(&instance->pdev->dev,
69669e4bec5bSKashyap Desai "Max firmware commands: %d shared with default "
69679e4bec5bSKashyap Desai "hw_queues = %d poll_queues %d\n", instance->max_fw_cmds,
69689e4bec5bSKashyap Desai host->nr_hw_queues - instance->iopoll_q_count,
69699e4bec5bSKashyap Desai instance->iopoll_q_count);
69700d49016bSadam radford /*
69710d49016bSadam radford * Notify the mid-layer about the new controller
69720d49016bSadam radford */
69730d49016bSadam radford if (scsi_add_host(host, &instance->pdev->dev)) {
69744026e9aaSSumit.Saxena@avagotech.com dev_err(&instance->pdev->dev,
69754026e9aaSSumit.Saxena@avagotech.com "Failed to add host from %s %d\n",
69764026e9aaSSumit.Saxena@avagotech.com __func__, __LINE__);
69770d49016bSadam radford return -ENODEV;
69780d49016bSadam radford }
69790d49016bSadam radford
69800d49016bSadam radford return 0;
69810d49016bSadam radford }
69820d49016bSadam radford
6983107a60ddSShivasharan S /**
6984107a60ddSShivasharan S * megasas_set_dma_mask - Set DMA mask for supported controllers
6985107a60ddSShivasharan S *
6986107a60ddSShivasharan S * @instance: Adapter soft state
6987107a60ddSShivasharan S * Description:
6988107a60ddSShivasharan S *
6989894169dbSShivasharan S * For Ventura, driver/FW will operate in 63bit DMA addresses.
6990107a60ddSShivasharan S *
6991107a60ddSShivasharan S * For invader-
6992107a60ddSShivasharan S * By default, driver/FW will operate in 32bit DMA addresses
6993107a60ddSShivasharan S * for consistent DMA mapping but if 32 bit consistent
6994894169dbSShivasharan S * DMA mask fails, driver will try with 63 bit consistent
6995894169dbSShivasharan S * mask provided FW is true 63bit DMA capable
6996107a60ddSShivasharan S *
6997107a60ddSShivasharan S * For older controllers(Thunderbolt and MFI based adapters)-
6998107a60ddSShivasharan S * driver/FW will operate in 32 bit consistent DMA addresses.
6999107a60ddSShivasharan S */
70000d49016bSadam radford static int
megasas_set_dma_mask(struct megasas_instance * instance)7001107a60ddSShivasharan S megasas_set_dma_mask(struct megasas_instance *instance)
70020d49016bSadam radford {
7003107a60ddSShivasharan S u64 consistent_mask;
7004107a60ddSShivasharan S struct pci_dev *pdev;
700581b76452SShivasharan S u32 scratch_pad_1;
70060d49016bSadam radford
7007107a60ddSShivasharan S pdev = instance->pdev;
7008630d42b7SShivasharan S consistent_mask = (instance->adapter_type >= VENTURA_SERIES) ?
7009894169dbSShivasharan S DMA_BIT_MASK(63) : DMA_BIT_MASK(32);
7010107a60ddSShivasharan S
7011107a60ddSShivasharan S if (IS_DMA64) {
7012894169dbSShivasharan S if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(63)) &&
7013107a60ddSShivasharan S dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))
70140d49016bSadam radford goto fail_set_dma_mask;
7015107a60ddSShivasharan S
7016894169dbSShivasharan S if ((*pdev->dev.dma_mask == DMA_BIT_MASK(63)) &&
7017107a60ddSShivasharan S (dma_set_coherent_mask(&pdev->dev, consistent_mask) &&
7018107a60ddSShivasharan S dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))) {
701946de63e2SSumit.Saxena@lsi.com /*
7020107a60ddSShivasharan S * If 32 bit DMA mask fails, then try for 64 bit mask
7021107a60ddSShivasharan S * for FW capable of handling 64 bit DMA.
702246de63e2SSumit.Saxena@lsi.com */
7023272652fcSShivasharan S scratch_pad_1 = megasas_readl
7024272652fcSShivasharan S (instance, &instance->reg_set->outbound_scratch_pad_1);
7025107a60ddSShivasharan S
702681b76452SShivasharan S if (!(scratch_pad_1 & MR_CAN_HANDLE_64_BIT_DMA_OFFSET))
7027107a60ddSShivasharan S goto fail_set_dma_mask;
7028107a60ddSShivasharan S else if (dma_set_mask_and_coherent(&pdev->dev,
7029894169dbSShivasharan S DMA_BIT_MASK(63)))
703046de63e2SSumit.Saxena@lsi.com goto fail_set_dma_mask;
703146de63e2SSumit.Saxena@lsi.com }
7032107a60ddSShivasharan S } else if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))
7033107a60ddSShivasharan S goto fail_set_dma_mask;
7034107a60ddSShivasharan S
7035107a60ddSShivasharan S if (pdev->dev.coherent_dma_mask == DMA_BIT_MASK(32))
7036107a60ddSShivasharan S instance->consistent_mask_64bit = false;
7037107a60ddSShivasharan S else
7038107a60ddSShivasharan S instance->consistent_mask_64bit = true;
7039107a60ddSShivasharan S
7040107a60ddSShivasharan S dev_info(&pdev->dev, "%s bit DMA mask and %s bit consistent mask\n",
7041d1f38d99STomas Henzl ((*pdev->dev.dma_mask == DMA_BIT_MASK(63)) ? "63" : "32"),
7042894169dbSShivasharan S (instance->consistent_mask_64bit ? "63" : "32"));
704394cd65ddSSumit.Saxena@lsi.com
70440d49016bSadam radford return 0;
70450d49016bSadam radford
70460d49016bSadam radford fail_set_dma_mask:
7047107a60ddSShivasharan S dev_err(&pdev->dev, "Failed to set DMA mask\n");
7048107a60ddSShivasharan S return -1;
7049107a60ddSShivasharan S
70500d49016bSadam radford }
70510d49016bSadam radford
7052c365178fSShivasharan S /*
7053c365178fSShivasharan S * megasas_set_adapter_type - Set adapter type.
7054c365178fSShivasharan S * Supported controllers can be divided in
7055154a7cdeSShivasharan S * different categories-
7056154a7cdeSShivasharan S * enum MR_ADAPTER_TYPE {
7057c365178fSShivasharan S * MFI_SERIES = 1,
7058c365178fSShivasharan S * THUNDERBOLT_SERIES = 2,
7059c365178fSShivasharan S * INVADER_SERIES = 3,
7060c365178fSShivasharan S * VENTURA_SERIES = 4,
7061154a7cdeSShivasharan S * AERO_SERIES = 5,
7062c365178fSShivasharan S * };
7063c365178fSShivasharan S * @instance: Adapter soft state
7064c365178fSShivasharan S * return: void
7065c365178fSShivasharan S */
megasas_set_adapter_type(struct megasas_instance * instance)7066c365178fSShivasharan S static inline void megasas_set_adapter_type(struct megasas_instance *instance)
7067c365178fSShivasharan S {
7068754f1baeSShivasharan S if ((instance->pdev->vendor == PCI_VENDOR_ID_DELL) &&
7069754f1baeSShivasharan S (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5)) {
7070754f1baeSShivasharan S instance->adapter_type = MFI_SERIES;
7071754f1baeSShivasharan S } else {
7072c365178fSShivasharan S switch (instance->pdev->device) {
7073469f72ddSShivasharan S case PCI_DEVICE_ID_LSI_AERO_10E1:
7074469f72ddSShivasharan S case PCI_DEVICE_ID_LSI_AERO_10E2:
7075469f72ddSShivasharan S case PCI_DEVICE_ID_LSI_AERO_10E5:
7076469f72ddSShivasharan S case PCI_DEVICE_ID_LSI_AERO_10E6:
7077154a7cdeSShivasharan S instance->adapter_type = AERO_SERIES;
7078154a7cdeSShivasharan S break;
7079c365178fSShivasharan S case PCI_DEVICE_ID_LSI_VENTURA:
7080754f1baeSShivasharan S case PCI_DEVICE_ID_LSI_CRUSADER:
7081c365178fSShivasharan S case PCI_DEVICE_ID_LSI_HARPOON:
7082c365178fSShivasharan S case PCI_DEVICE_ID_LSI_TOMCAT:
7083c365178fSShivasharan S case PCI_DEVICE_ID_LSI_VENTURA_4PORT:
7084c365178fSShivasharan S case PCI_DEVICE_ID_LSI_CRUSADER_4PORT:
7085c365178fSShivasharan S instance->adapter_type = VENTURA_SERIES;
7086c365178fSShivasharan S break;
7087c365178fSShivasharan S case PCI_DEVICE_ID_LSI_FUSION:
7088c365178fSShivasharan S case PCI_DEVICE_ID_LSI_PLASMA:
7089c365178fSShivasharan S instance->adapter_type = THUNDERBOLT_SERIES;
7090c365178fSShivasharan S break;
7091c365178fSShivasharan S case PCI_DEVICE_ID_LSI_INVADER:
7092c365178fSShivasharan S case PCI_DEVICE_ID_LSI_INTRUDER:
7093c365178fSShivasharan S case PCI_DEVICE_ID_LSI_INTRUDER_24:
7094c365178fSShivasharan S case PCI_DEVICE_ID_LSI_CUTLASS_52:
7095c365178fSShivasharan S case PCI_DEVICE_ID_LSI_CUTLASS_53:
7096c365178fSShivasharan S case PCI_DEVICE_ID_LSI_FURY:
7097c365178fSShivasharan S instance->adapter_type = INVADER_SERIES;
7098c365178fSShivasharan S break;
7099c365178fSShivasharan S default: /* For all other supported controllers */
7100c365178fSShivasharan S instance->adapter_type = MFI_SERIES;
7101c365178fSShivasharan S break;
7102c365178fSShivasharan S }
7103c365178fSShivasharan S }
7104754f1baeSShivasharan S }
7105c365178fSShivasharan S
megasas_alloc_mfi_ctrl_mem(struct megasas_instance * instance)710649a7a4adSShivasharan S static inline int megasas_alloc_mfi_ctrl_mem(struct megasas_instance *instance)
710749a7a4adSShivasharan S {
710860ee6529SChristoph Hellwig instance->producer = dma_alloc_coherent(&instance->pdev->dev,
710960ee6529SChristoph Hellwig sizeof(u32), &instance->producer_h, GFP_KERNEL);
711060ee6529SChristoph Hellwig instance->consumer = dma_alloc_coherent(&instance->pdev->dev,
711160ee6529SChristoph Hellwig sizeof(u32), &instance->consumer_h, GFP_KERNEL);
711249a7a4adSShivasharan S
711349a7a4adSShivasharan S if (!instance->producer || !instance->consumer) {
711449a7a4adSShivasharan S dev_err(&instance->pdev->dev,
711549a7a4adSShivasharan S "Failed to allocate memory for producer, consumer\n");
711649a7a4adSShivasharan S return -1;
711749a7a4adSShivasharan S }
711849a7a4adSShivasharan S
711949a7a4adSShivasharan S *instance->producer = 0;
712049a7a4adSShivasharan S *instance->consumer = 0;
712149a7a4adSShivasharan S return 0;
712249a7a4adSShivasharan S }
712349a7a4adSShivasharan S
712449a7a4adSShivasharan S /**
712549a7a4adSShivasharan S * megasas_alloc_ctrl_mem - Allocate per controller memory for core data
712649a7a4adSShivasharan S * structures which are not common across MFI
712749a7a4adSShivasharan S * adapters and fusion adapters.
712849a7a4adSShivasharan S * For MFI based adapters, allocate producer and
712949a7a4adSShivasharan S * consumer buffers. For fusion adapters, allocate
713049a7a4adSShivasharan S * memory for fusion context.
713149a7a4adSShivasharan S * @instance: Adapter soft state
713249a7a4adSShivasharan S * return: 0 for SUCCESS
713349a7a4adSShivasharan S */
megasas_alloc_ctrl_mem(struct megasas_instance * instance)713449a7a4adSShivasharan S static int megasas_alloc_ctrl_mem(struct megasas_instance *instance)
713549a7a4adSShivasharan S {
71366396bb22SKees Cook instance->reply_map = kcalloc(nr_cpu_ids, sizeof(unsigned int),
7137adbe5523SMing Lei GFP_KERNEL);
7138adbe5523SMing Lei if (!instance->reply_map)
7139adbe5523SMing Lei return -ENOMEM;
7140adbe5523SMing Lei
714149a7a4adSShivasharan S switch (instance->adapter_type) {
714249a7a4adSShivasharan S case MFI_SERIES:
714349a7a4adSShivasharan S if (megasas_alloc_mfi_ctrl_mem(instance))
71447dd6f4afSGuixin Liu return -ENOMEM;
714549a7a4adSShivasharan S break;
7146154a7cdeSShivasharan S case AERO_SERIES:
714749a7a4adSShivasharan S case VENTURA_SERIES:
714849a7a4adSShivasharan S case THUNDERBOLT_SERIES:
714949a7a4adSShivasharan S case INVADER_SERIES:
715049a7a4adSShivasharan S if (megasas_alloc_fusion_context(instance))
71517dd6f4afSGuixin Liu return -ENOMEM;
715249a7a4adSShivasharan S break;
715349a7a4adSShivasharan S }
715449a7a4adSShivasharan S
715549a7a4adSShivasharan S return 0;
715649a7a4adSShivasharan S }
715749a7a4adSShivasharan S
715849a7a4adSShivasharan S /*
715949a7a4adSShivasharan S * megasas_free_ctrl_mem - Free fusion context for fusion adapters and
716049a7a4adSShivasharan S * producer, consumer buffers for MFI adapters
716149a7a4adSShivasharan S *
716249a7a4adSShivasharan S * @instance - Adapter soft instance
716349a7a4adSShivasharan S *
716449a7a4adSShivasharan S */
megasas_free_ctrl_mem(struct megasas_instance * instance)716549a7a4adSShivasharan S static inline void megasas_free_ctrl_mem(struct megasas_instance *instance)
716649a7a4adSShivasharan S {
7167adbe5523SMing Lei kfree(instance->reply_map);
716849a7a4adSShivasharan S if (instance->adapter_type == MFI_SERIES) {
716949a7a4adSShivasharan S if (instance->producer)
717060ee6529SChristoph Hellwig dma_free_coherent(&instance->pdev->dev, sizeof(u32),
717149a7a4adSShivasharan S instance->producer,
717249a7a4adSShivasharan S instance->producer_h);
717349a7a4adSShivasharan S if (instance->consumer)
717460ee6529SChristoph Hellwig dma_free_coherent(&instance->pdev->dev, sizeof(u32),
717549a7a4adSShivasharan S instance->consumer,
717649a7a4adSShivasharan S instance->consumer_h);
717749a7a4adSShivasharan S } else {
717849a7a4adSShivasharan S megasas_free_fusion_context(instance);
717949a7a4adSShivasharan S }
718049a7a4adSShivasharan S }
718149a7a4adSShivasharan S
71820d49016bSadam radford /**
71831b4bed20SShivasharan S * megasas_alloc_ctrl_dma_buffers - Allocate consistent DMA buffers during
71841b4bed20SShivasharan S * driver load time
71851b4bed20SShivasharan S *
71862b46e5c1SDamien Le Moal * @instance: Adapter soft instance
71872b46e5c1SDamien Le Moal *
71882b46e5c1SDamien Le Moal * @return: O for SUCCESS
71891b4bed20SShivasharan S */
71901b4bed20SShivasharan S static inline
megasas_alloc_ctrl_dma_buffers(struct megasas_instance * instance)71911b4bed20SShivasharan S int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
71921b4bed20SShivasharan S {
71931b4bed20SShivasharan S struct pci_dev *pdev = instance->pdev;
71949b3d028fSShivasharan S struct fusion_context *fusion = instance->ctrl_context;
71951b4bed20SShivasharan S
719660ee6529SChristoph Hellwig instance->evt_detail = dma_alloc_coherent(&pdev->dev,
71971b4bed20SShivasharan S sizeof(struct megasas_evt_detail),
719860ee6529SChristoph Hellwig &instance->evt_detail_h, GFP_KERNEL);
71991b4bed20SShivasharan S
72001b4bed20SShivasharan S if (!instance->evt_detail) {
72011b4bed20SShivasharan S dev_err(&instance->pdev->dev,
72021b4bed20SShivasharan S "Failed to allocate event detail buffer\n");
72031b4bed20SShivasharan S return -ENOMEM;
72041b4bed20SShivasharan S }
72051b4bed20SShivasharan S
72069b3d028fSShivasharan S if (fusion) {
72079b3d028fSShivasharan S fusion->ioc_init_request =
72089b3d028fSShivasharan S dma_alloc_coherent(&pdev->dev,
72099b3d028fSShivasharan S sizeof(struct MPI2_IOC_INIT_REQUEST),
72109b3d028fSShivasharan S &fusion->ioc_init_request_phys,
72119b3d028fSShivasharan S GFP_KERNEL);
72129b3d028fSShivasharan S
72139b3d028fSShivasharan S if (!fusion->ioc_init_request) {
72149b3d028fSShivasharan S dev_err(&pdev->dev,
72159b201b5dSGuixin Liu "Failed to allocate ioc init request\n");
72169b3d028fSShivasharan S return -ENOMEM;
72179b3d028fSShivasharan S }
7218f0c21df6SShivasharan S
7219f0c21df6SShivasharan S instance->snapdump_prop = dma_alloc_coherent(&pdev->dev,
7220f0c21df6SShivasharan S sizeof(struct MR_SNAPDUMP_PROPERTIES),
7221f0c21df6SShivasharan S &instance->snapdump_prop_h, GFP_KERNEL);
7222f0c21df6SShivasharan S
7223f0c21df6SShivasharan S if (!instance->snapdump_prop)
7224f0c21df6SShivasharan S dev_err(&pdev->dev,
7225f0c21df6SShivasharan S "Failed to allocate snapdump properties buffer\n");
7226f6fe5731SShivasharan S
7227f6fe5731SShivasharan S instance->host_device_list_buf = dma_alloc_coherent(&pdev->dev,
7228f6fe5731SShivasharan S HOST_DEVICE_LIST_SZ,
7229f6fe5731SShivasharan S &instance->host_device_list_buf_h,
7230f6fe5731SShivasharan S GFP_KERNEL);
7231f6fe5731SShivasharan S
7232f6fe5731SShivasharan S if (!instance->host_device_list_buf) {
7233f6fe5731SShivasharan S dev_err(&pdev->dev,
7234f6fe5731SShivasharan S "Failed to allocate targetid list buffer\n");
7235f6fe5731SShivasharan S return -ENOMEM;
7236f6fe5731SShivasharan S }
7237f6fe5731SShivasharan S
72389b3d028fSShivasharan S }
72399b3d028fSShivasharan S
72409b3d028fSShivasharan S instance->pd_list_buf =
724160ee6529SChristoph Hellwig dma_alloc_coherent(&pdev->dev,
72429b3d028fSShivasharan S MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
724360ee6529SChristoph Hellwig &instance->pd_list_buf_h, GFP_KERNEL);
72449b3d028fSShivasharan S
72459b3d028fSShivasharan S if (!instance->pd_list_buf) {
72469b3d028fSShivasharan S dev_err(&pdev->dev, "Failed to allocate PD list buffer\n");
72479b3d028fSShivasharan S return -ENOMEM;
72489b3d028fSShivasharan S }
72499b3d028fSShivasharan S
72509b3d028fSShivasharan S instance->ctrl_info_buf =
725160ee6529SChristoph Hellwig dma_alloc_coherent(&pdev->dev,
72529b3d028fSShivasharan S sizeof(struct megasas_ctrl_info),
725360ee6529SChristoph Hellwig &instance->ctrl_info_buf_h, GFP_KERNEL);
72549b3d028fSShivasharan S
72559b3d028fSShivasharan S if (!instance->ctrl_info_buf) {
72569b3d028fSShivasharan S dev_err(&pdev->dev,
72579b3d028fSShivasharan S "Failed to allocate controller info buffer\n");
72589b3d028fSShivasharan S return -ENOMEM;
72599b3d028fSShivasharan S }
72609b3d028fSShivasharan S
72619b3d028fSShivasharan S instance->ld_list_buf =
726260ee6529SChristoph Hellwig dma_alloc_coherent(&pdev->dev,
72639b3d028fSShivasharan S sizeof(struct MR_LD_LIST),
726460ee6529SChristoph Hellwig &instance->ld_list_buf_h, GFP_KERNEL);
72659b3d028fSShivasharan S
72669b3d028fSShivasharan S if (!instance->ld_list_buf) {
72679b3d028fSShivasharan S dev_err(&pdev->dev, "Failed to allocate LD list buffer\n");
72689b3d028fSShivasharan S return -ENOMEM;
72699b3d028fSShivasharan S }
72709b3d028fSShivasharan S
72719b3d028fSShivasharan S instance->ld_targetid_list_buf =
727260ee6529SChristoph Hellwig dma_alloc_coherent(&pdev->dev,
72739b3d028fSShivasharan S sizeof(struct MR_LD_TARGETID_LIST),
727460ee6529SChristoph Hellwig &instance->ld_targetid_list_buf_h, GFP_KERNEL);
72759b3d028fSShivasharan S
72769b3d028fSShivasharan S if (!instance->ld_targetid_list_buf) {
72779b3d028fSShivasharan S dev_err(&pdev->dev,
72789b3d028fSShivasharan S "Failed to allocate LD targetid list buffer\n");
72799b3d028fSShivasharan S return -ENOMEM;
72809b3d028fSShivasharan S }
72819b3d028fSShivasharan S
72821b4bed20SShivasharan S if (!reset_devices) {
72831b4bed20SShivasharan S instance->system_info_buf =
728460ee6529SChristoph Hellwig dma_alloc_coherent(&pdev->dev,
72851b4bed20SShivasharan S sizeof(struct MR_DRV_SYSTEM_INFO),
728660ee6529SChristoph Hellwig &instance->system_info_h, GFP_KERNEL);
72871b4bed20SShivasharan S instance->pd_info =
728860ee6529SChristoph Hellwig dma_alloc_coherent(&pdev->dev,
72891b4bed20SShivasharan S sizeof(struct MR_PD_INFO),
729060ee6529SChristoph Hellwig &instance->pd_info_h, GFP_KERNEL);
72911b4bed20SShivasharan S instance->tgt_prop =
729260ee6529SChristoph Hellwig dma_alloc_coherent(&pdev->dev,
72931b4bed20SShivasharan S sizeof(struct MR_TARGET_PROPERTIES),
729460ee6529SChristoph Hellwig &instance->tgt_prop_h, GFP_KERNEL);
72951b4bed20SShivasharan S instance->crash_dump_buf =
729660ee6529SChristoph Hellwig dma_alloc_coherent(&pdev->dev, CRASH_DMA_BUF_SIZE,
729760ee6529SChristoph Hellwig &instance->crash_dump_h, GFP_KERNEL);
72981b4bed20SShivasharan S
72991b4bed20SShivasharan S if (!instance->system_info_buf)
73001b4bed20SShivasharan S dev_err(&instance->pdev->dev,
73011b4bed20SShivasharan S "Failed to allocate system info buffer\n");
73021b4bed20SShivasharan S
73031b4bed20SShivasharan S if (!instance->pd_info)
73041b4bed20SShivasharan S dev_err(&instance->pdev->dev,
73051b4bed20SShivasharan S "Failed to allocate pd_info buffer\n");
73061b4bed20SShivasharan S
73071b4bed20SShivasharan S if (!instance->tgt_prop)
73081b4bed20SShivasharan S dev_err(&instance->pdev->dev,
73091b4bed20SShivasharan S "Failed to allocate tgt_prop buffer\n");
73101b4bed20SShivasharan S
73111b4bed20SShivasharan S if (!instance->crash_dump_buf)
73121b4bed20SShivasharan S dev_err(&instance->pdev->dev,
73131b4bed20SShivasharan S "Failed to allocate crash dump buffer\n");
73141b4bed20SShivasharan S }
73151b4bed20SShivasharan S
73161b4bed20SShivasharan S return 0;
73171b4bed20SShivasharan S }
73181b4bed20SShivasharan S
73191b4bed20SShivasharan S /*
73201b4bed20SShivasharan S * megasas_free_ctrl_dma_buffers - Free consistent DMA buffers allocated
73211b4bed20SShivasharan S * during driver load time
73221b4bed20SShivasharan S *
73231b4bed20SShivasharan S * @instance- Adapter soft instance
73241b4bed20SShivasharan S *
73251b4bed20SShivasharan S */
73261b4bed20SShivasharan S static inline
megasas_free_ctrl_dma_buffers(struct megasas_instance * instance)73271b4bed20SShivasharan S void megasas_free_ctrl_dma_buffers(struct megasas_instance *instance)
73281b4bed20SShivasharan S {
73291b4bed20SShivasharan S struct pci_dev *pdev = instance->pdev;
73309b3d028fSShivasharan S struct fusion_context *fusion = instance->ctrl_context;
73311b4bed20SShivasharan S
73321b4bed20SShivasharan S if (instance->evt_detail)
733360ee6529SChristoph Hellwig dma_free_coherent(&pdev->dev, sizeof(struct megasas_evt_detail),
73341b4bed20SShivasharan S instance->evt_detail,
73351b4bed20SShivasharan S instance->evt_detail_h);
73361b4bed20SShivasharan S
73379b3d028fSShivasharan S if (fusion && fusion->ioc_init_request)
73389b3d028fSShivasharan S dma_free_coherent(&pdev->dev,
73399b3d028fSShivasharan S sizeof(struct MPI2_IOC_INIT_REQUEST),
73409b3d028fSShivasharan S fusion->ioc_init_request,
73419b3d028fSShivasharan S fusion->ioc_init_request_phys);
73429b3d028fSShivasharan S
73439b3d028fSShivasharan S if (instance->pd_list_buf)
734460ee6529SChristoph Hellwig dma_free_coherent(&pdev->dev,
73459b3d028fSShivasharan S MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
73469b3d028fSShivasharan S instance->pd_list_buf,
73479b3d028fSShivasharan S instance->pd_list_buf_h);
73489b3d028fSShivasharan S
73499b3d028fSShivasharan S if (instance->ld_list_buf)
735060ee6529SChristoph Hellwig dma_free_coherent(&pdev->dev, sizeof(struct MR_LD_LIST),
73519b3d028fSShivasharan S instance->ld_list_buf,
73529b3d028fSShivasharan S instance->ld_list_buf_h);
73539b3d028fSShivasharan S
73549b3d028fSShivasharan S if (instance->ld_targetid_list_buf)
735560ee6529SChristoph Hellwig dma_free_coherent(&pdev->dev, sizeof(struct MR_LD_TARGETID_LIST),
73569b3d028fSShivasharan S instance->ld_targetid_list_buf,
73579b3d028fSShivasharan S instance->ld_targetid_list_buf_h);
73589b3d028fSShivasharan S
73599b3d028fSShivasharan S if (instance->ctrl_info_buf)
736060ee6529SChristoph Hellwig dma_free_coherent(&pdev->dev, sizeof(struct megasas_ctrl_info),
73619b3d028fSShivasharan S instance->ctrl_info_buf,
73629b3d028fSShivasharan S instance->ctrl_info_buf_h);
73639b3d028fSShivasharan S
73641b4bed20SShivasharan S if (instance->system_info_buf)
736560ee6529SChristoph Hellwig dma_free_coherent(&pdev->dev, sizeof(struct MR_DRV_SYSTEM_INFO),
73661b4bed20SShivasharan S instance->system_info_buf,
73671b4bed20SShivasharan S instance->system_info_h);
73681b4bed20SShivasharan S
73691b4bed20SShivasharan S if (instance->pd_info)
737060ee6529SChristoph Hellwig dma_free_coherent(&pdev->dev, sizeof(struct MR_PD_INFO),
73711b4bed20SShivasharan S instance->pd_info, instance->pd_info_h);
73721b4bed20SShivasharan S
73731b4bed20SShivasharan S if (instance->tgt_prop)
737460ee6529SChristoph Hellwig dma_free_coherent(&pdev->dev, sizeof(struct MR_TARGET_PROPERTIES),
73751b4bed20SShivasharan S instance->tgt_prop, instance->tgt_prop_h);
73761b4bed20SShivasharan S
73771b4bed20SShivasharan S if (instance->crash_dump_buf)
737860ee6529SChristoph Hellwig dma_free_coherent(&pdev->dev, CRASH_DMA_BUF_SIZE,
73791b4bed20SShivasharan S instance->crash_dump_buf,
73801b4bed20SShivasharan S instance->crash_dump_h);
7381f0c21df6SShivasharan S
7382f0c21df6SShivasharan S if (instance->snapdump_prop)
7383f0c21df6SShivasharan S dma_free_coherent(&pdev->dev,
7384f0c21df6SShivasharan S sizeof(struct MR_SNAPDUMP_PROPERTIES),
7385f0c21df6SShivasharan S instance->snapdump_prop,
7386f0c21df6SShivasharan S instance->snapdump_prop_h);
7387f6fe5731SShivasharan S
7388f6fe5731SShivasharan S if (instance->host_device_list_buf)
7389f6fe5731SShivasharan S dma_free_coherent(&pdev->dev,
7390f6fe5731SShivasharan S HOST_DEVICE_LIST_SZ,
7391f6fe5731SShivasharan S instance->host_device_list_buf,
7392f6fe5731SShivasharan S instance->host_device_list_buf_h);
7393f6fe5731SShivasharan S
73941b4bed20SShivasharan S }
73951b4bed20SShivasharan S
73967535f27dSShivasharan S /*
73977535f27dSShivasharan S * megasas_init_ctrl_params - Initialize controller's instance
73987535f27dSShivasharan S * parameters before FW init
73997535f27dSShivasharan S * @instance - Adapter soft instance
74007535f27dSShivasharan S * @return - void
74017535f27dSShivasharan S */
megasas_init_ctrl_params(struct megasas_instance * instance)74027535f27dSShivasharan S static inline void megasas_init_ctrl_params(struct megasas_instance *instance)
74037535f27dSShivasharan S {
74047535f27dSShivasharan S instance->fw_crash_state = UNAVAILABLE;
74057535f27dSShivasharan S
74067535f27dSShivasharan S megasas_poll_wait_aen = 0;
74077535f27dSShivasharan S instance->issuepend_done = 1;
74087535f27dSShivasharan S atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
74097535f27dSShivasharan S
74107535f27dSShivasharan S /*
74117535f27dSShivasharan S * Initialize locks and queues
74127535f27dSShivasharan S */
74137535f27dSShivasharan S INIT_LIST_HEAD(&instance->cmd_pool);
74147535f27dSShivasharan S INIT_LIST_HEAD(&instance->internal_reset_pending_q);
74157535f27dSShivasharan S
74167535f27dSShivasharan S atomic_set(&instance->fw_outstanding, 0);
74171d15d909SShivasharan S atomic64_set(&instance->total_io_count, 0);
74187535f27dSShivasharan S
74197535f27dSShivasharan S init_waitqueue_head(&instance->int_cmd_wait_q);
74207535f27dSShivasharan S init_waitqueue_head(&instance->abort_cmd_wait_q);
74217535f27dSShivasharan S
74220b0747d5SJunxiao Bi mutex_init(&instance->crashdump_lock);
74237535f27dSShivasharan S spin_lock_init(&instance->mfi_pool_lock);
74247535f27dSShivasharan S spin_lock_init(&instance->hba_lock);
74257535f27dSShivasharan S spin_lock_init(&instance->stream_lock);
74267535f27dSShivasharan S spin_lock_init(&instance->completion_lock);
74277535f27dSShivasharan S
74287535f27dSShivasharan S mutex_init(&instance->reset_mutex);
74297535f27dSShivasharan S
74307535f27dSShivasharan S if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
74317535f27dSShivasharan S (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY))
74327535f27dSShivasharan S instance->flag_ieee = 1;
74337535f27dSShivasharan S
74347535f27dSShivasharan S instance->flag = 0;
74357535f27dSShivasharan S instance->unload = 1;
74367535f27dSShivasharan S instance->last_time = 0;
74377535f27dSShivasharan S instance->disableOnlineCtrlReset = 1;
74387535f27dSShivasharan S instance->UnevenSpanSupport = 0;
74391d15d909SShivasharan S instance->smp_affinity_enable = smp_affinity_enable ? true : false;
74401d15d909SShivasharan S instance->msix_load_balance = false;
74417535f27dSShivasharan S
74423f6194afSShivasharan S if (instance->adapter_type != MFI_SERIES)
74437535f27dSShivasharan S INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
74443f6194afSShivasharan S else
74457535f27dSShivasharan S INIT_WORK(&instance->work_init, process_fw_state_change_wq);
74467535f27dSShivasharan S }
74470d49016bSadam radford
74480d49016bSadam radford /**
74490d49016bSadam radford * megasas_probe_one - PCI hotplug entry point
74500d49016bSadam radford * @pdev: PCI device structure
74510d49016bSadam radford * @id: PCI ids of supported hotplugged adapter
74520d49016bSadam radford */
megasas_probe_one(struct pci_dev * pdev,const struct pci_device_id * id)74536f039790SGreg Kroah-Hartman static int megasas_probe_one(struct pci_dev *pdev,
74546f039790SGreg Kroah-Hartman const struct pci_device_id *id)
74550d49016bSadam radford {
7456d3557fc8SSumit.Saxena@avagotech.com int rval, pos;
74570d49016bSadam radford struct Scsi_Host *host;
74580d49016bSadam radford struct megasas_instance *instance;
745966192dfeSadam radford u16 control = 0;
746066192dfeSadam radford
7461469f72ddSShivasharan S switch (pdev->device) {
7462dd807699SChandrakanth Patil case PCI_DEVICE_ID_LSI_AERO_10E0:
7463dd807699SChandrakanth Patil case PCI_DEVICE_ID_LSI_AERO_10E3:
7464dd807699SChandrakanth Patil case PCI_DEVICE_ID_LSI_AERO_10E4:
7465dd807699SChandrakanth Patil case PCI_DEVICE_ID_LSI_AERO_10E7:
7466dd807699SChandrakanth Patil dev_err(&pdev->dev, "Adapter is in non secure mode\n");
7467dd807699SChandrakanth Patil return 1;
7468469f72ddSShivasharan S case PCI_DEVICE_ID_LSI_AERO_10E1:
7469469f72ddSShivasharan S case PCI_DEVICE_ID_LSI_AERO_10E5:
7470469f72ddSShivasharan S dev_info(&pdev->dev, "Adapter is in configurable secure mode\n");
7471469f72ddSShivasharan S break;
7472469f72ddSShivasharan S }
7473469f72ddSShivasharan S
747466192dfeSadam radford /* Reset MSI-X in the kdump kernel */
747566192dfeSadam radford if (reset_devices) {
747666192dfeSadam radford pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
747766192dfeSadam radford if (pos) {
747899369065SBjorn Helgaas pci_read_config_word(pdev, pos + PCI_MSIX_FLAGS,
747966192dfeSadam radford &control);
748066192dfeSadam radford if (control & PCI_MSIX_FLAGS_ENABLE) {
748166192dfeSadam radford dev_info(&pdev->dev, "resetting MSI-X\n");
748266192dfeSadam radford pci_write_config_word(pdev,
748399369065SBjorn Helgaas pos + PCI_MSIX_FLAGS,
748466192dfeSadam radford control &
748566192dfeSadam radford ~PCI_MSIX_FLAGS_ENABLE);
748666192dfeSadam radford }
748766192dfeSadam radford }
748866192dfeSadam radford }
74890d49016bSadam radford
74900d49016bSadam radford /*
74910d49016bSadam radford * PCI prepping: enable device set bus mastering and dma mask
74920d49016bSadam radford */
74930d49016bSadam radford rval = pci_enable_device_mem(pdev);
74940d49016bSadam radford
74950d49016bSadam radford if (rval) {
74960d49016bSadam radford return rval;
74970d49016bSadam radford }
74980d49016bSadam radford
74990d49016bSadam radford pci_set_master(pdev);
75000d49016bSadam radford
75010d49016bSadam radford host = scsi_host_alloc(&megasas_template,
75020d49016bSadam radford sizeof(struct megasas_instance));
75030d49016bSadam radford
75040d49016bSadam radford if (!host) {
75051be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &pdev->dev, "scsi_host_alloc failed\n");
75060d49016bSadam radford goto fail_alloc_instance;
75070d49016bSadam radford }
75080d49016bSadam radford
75090d49016bSadam radford instance = (struct megasas_instance *)host->hostdata;
75100d49016bSadam radford memset(instance, 0, sizeof(*instance));
75110d49016bSadam radford atomic_set(&instance->fw_reset_no_pci_access, 0);
75120d49016bSadam radford
75130d49016bSadam radford /*
75140d49016bSadam radford * Initialize PCI related and misc parameters
75150d49016bSadam radford */
75160d49016bSadam radford instance->pdev = pdev;
75170d49016bSadam radford instance->host = host;
7518a46421fdSJialin Zhang instance->unique_id = pci_dev_id(pdev);
75190d49016bSadam radford instance->init_id = MEGASAS_DEFAULT_INIT_ID;
75200d49016bSadam radford
7521c365178fSShivasharan S megasas_set_adapter_type(instance);
75220d49016bSadam radford
75230d49016bSadam radford /*
75240a77066aSadam radford * Initialize MFI Firmware
75250a77066aSadam radford */
75260a77066aSadam radford if (megasas_init_fw(instance))
75270a77066aSadam radford goto fail_init_mfi;
75280a77066aSadam radford
7529229fe47cSadam radford if (instance->requestorId) {
7530229fe47cSadam radford if (instance->PlasmaFW111) {
7531229fe47cSadam radford instance->vf_affiliation_111 =
753260ee6529SChristoph Hellwig dma_alloc_coherent(&pdev->dev,
753360ee6529SChristoph Hellwig sizeof(struct MR_LD_VF_AFFILIATION_111),
753460ee6529SChristoph Hellwig &instance->vf_affiliation_111_h,
753560ee6529SChristoph Hellwig GFP_KERNEL);
7536229fe47cSadam radford if (!instance->vf_affiliation_111)
75371be18254SBjorn Helgaas dev_warn(&pdev->dev, "Can't allocate "
7538229fe47cSadam radford "memory for VF affiliation buffer\n");
7539229fe47cSadam radford } else {
7540229fe47cSadam radford instance->vf_affiliation =
754160ee6529SChristoph Hellwig dma_alloc_coherent(&pdev->dev,
7542229fe47cSadam radford (MAX_LOGICAL_DRIVES + 1) *
7543229fe47cSadam radford sizeof(struct MR_LD_VF_AFFILIATION),
754460ee6529SChristoph Hellwig &instance->vf_affiliation_h,
754560ee6529SChristoph Hellwig GFP_KERNEL);
7546229fe47cSadam radford if (!instance->vf_affiliation)
75471be18254SBjorn Helgaas dev_warn(&pdev->dev, "Can't allocate "
7548229fe47cSadam radford "memory for VF affiliation buffer\n");
7549229fe47cSadam radford }
7550229fe47cSadam radford }
7551229fe47cSadam radford
75520d49016bSadam radford /*
75530d49016bSadam radford * Store instance in PCI softstate
75540d49016bSadam radford */
75550d49016bSadam radford pci_set_drvdata(pdev, instance);
75560d49016bSadam radford
75570d49016bSadam radford /*
75580d49016bSadam radford * Add this controller to megasas_mgmt_info structure so that it
75590d49016bSadam radford * can be exported to management applications
75600d49016bSadam radford */
75610d49016bSadam radford megasas_mgmt_info.count++;
75620d49016bSadam radford megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = instance;
75630d49016bSadam radford megasas_mgmt_info.max_index++;
75640d49016bSadam radford
75650d49016bSadam radford /*
7566541f90b7Sadam radford * Register with SCSI mid-layer
7567541f90b7Sadam radford */
7568541f90b7Sadam radford if (megasas_io_attach(instance))
7569541f90b7Sadam radford goto fail_io_attach;
7570541f90b7Sadam radford
7571541f90b7Sadam radford instance->unload = 0;
7572aa00832bSSumit.Saxena@avagotech.com /*
7573aa00832bSSumit.Saxena@avagotech.com * Trigger SCSI to scan our drives
7574aa00832bSSumit.Saxena@avagotech.com */
7575f6fe5731SShivasharan S if (!instance->enable_fw_dev_list ||
7576f6fe5731SShivasharan S (instance->host_device_list_buf->count > 0))
7577aa00832bSSumit.Saxena@avagotech.com scsi_scan_host(host);
7578541f90b7Sadam radford
7579541f90b7Sadam radford /*
75800d49016bSadam radford * Initiate AEN (Asynchronous Event Notification)
75810d49016bSadam radford */
75820d49016bSadam radford if (megasas_start_aen(instance)) {
75831be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &pdev->dev, "start aen failed\n");
75840d49016bSadam radford goto fail_start_aen;
75850d49016bSadam radford }
75860d49016bSadam radford
7587ba53572bSShivasharan S megasas_setup_debugfs(instance);
7588ba53572bSShivasharan S
75899ea81f81SAdam Radford /* Get current SR-IOV LD/VF affiliation */
75909ea81f81SAdam Radford if (instance->requestorId)
75919ea81f81SAdam Radford megasas_get_ld_vf_affiliation(instance, 1);
75929ea81f81SAdam Radford
75930d49016bSadam radford return 0;
75940d49016bSadam radford
75950d49016bSadam radford fail_start_aen:
7596b5438f48SChandrakanth Patil instance->unload = 1;
7597b5438f48SChandrakanth Patil scsi_remove_host(instance->host);
75980d49016bSadam radford fail_io_attach:
75990d49016bSadam radford megasas_mgmt_info.count--;
76000d49016bSadam radford megasas_mgmt_info.max_index--;
760161f0c3c7Sweiping zhang megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = NULL;
76020d49016bSadam radford
7603b5438f48SChandrakanth Patil if (instance->requestorId && !instance->skip_heartbeat_timer_del)
7604b5438f48SChandrakanth Patil del_timer_sync(&instance->sriov_heartbeat_timer);
7605b5438f48SChandrakanth Patil
7606d46a3ad6SSumit.Saxena@lsi.com instance->instancet->disable_intr(instance);
7607d3557fc8SSumit.Saxena@avagotech.com megasas_destroy_irqs(instance);
7608d3557fc8SSumit.Saxena@avagotech.com
7609e7d36b88SShivasharan S if (instance->adapter_type != MFI_SERIES)
7610eb1b1237Sadam radford megasas_release_fusion(instance);
7611eb1b1237Sadam radford else
7612eb1b1237Sadam radford megasas_release_mfi(instance);
7613b5438f48SChandrakanth Patil
7614c8e858feSadam radford if (instance->msix_vectors)
7615fad119b7SHannes Reinecke pci_free_irq_vectors(instance->pdev);
7616b5438f48SChandrakanth Patil instance->msix_vectors = 0;
7617b5438f48SChandrakanth Patil
7618b5438f48SChandrakanth Patil if (instance->fw_crash_state != UNAVAILABLE)
7619b5438f48SChandrakanth Patil megasas_free_host_crash_buffer(instance);
7620b5438f48SChandrakanth Patil
7621b5438f48SChandrakanth Patil if (instance->adapter_type != MFI_SERIES)
7622b5438f48SChandrakanth Patil megasas_fusion_stop_watchdog(instance);
7623d3557fc8SSumit.Saxena@avagotech.com fail_init_mfi:
76240d49016bSadam radford scsi_host_put(host);
76250d49016bSadam radford fail_alloc_instance:
76260d49016bSadam radford pci_disable_device(pdev);
76270d49016bSadam radford
76280d49016bSadam radford return -ENODEV;
76290d49016bSadam radford }
76300d49016bSadam radford
76310d49016bSadam radford /**
76320d49016bSadam radford * megasas_flush_cache - Requests FW to flush all its caches
76330d49016bSadam radford * @instance: Adapter soft state
76340d49016bSadam radford */
megasas_flush_cache(struct megasas_instance * instance)76350d49016bSadam radford static void megasas_flush_cache(struct megasas_instance *instance)
76360d49016bSadam radford {
76370d49016bSadam radford struct megasas_cmd *cmd;
76380d49016bSadam radford struct megasas_dcmd_frame *dcmd;
76390d49016bSadam radford
76408a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
76410d49016bSadam radford return;
76420d49016bSadam radford
76430d49016bSadam radford cmd = megasas_get_cmd(instance);
76440d49016bSadam radford
76450d49016bSadam radford if (!cmd)
76460d49016bSadam radford return;
76470d49016bSadam radford
76480d49016bSadam radford dcmd = &cmd->frame->dcmd;
76490d49016bSadam radford
76500d49016bSadam radford memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
76510d49016bSadam radford
76520d49016bSadam radford dcmd->cmd = MFI_CMD_DCMD;
76530d49016bSadam radford dcmd->cmd_status = 0x0;
76540d49016bSadam radford dcmd->sge_count = 0;
765594cd65ddSSumit.Saxena@lsi.com dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_NONE);
76560d49016bSadam radford dcmd->timeout = 0;
76570d49016bSadam radford dcmd->pad_0 = 0;
76580d49016bSadam radford dcmd->data_xfer_len = 0;
765994cd65ddSSumit.Saxena@lsi.com dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_CACHE_FLUSH);
76600d49016bSadam radford dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
76610d49016bSadam radford
76626d40afbcSSumit Saxena if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS)
76636d40afbcSSumit Saxena != DCMD_SUCCESS) {
76646d40afbcSSumit Saxena dev_err(&instance->pdev->dev,
76656d40afbcSSumit Saxena "return from %s %d\n", __func__, __LINE__);
76666d40afbcSSumit Saxena return;
76676d40afbcSSumit Saxena }
76680d49016bSadam radford
76690d49016bSadam radford megasas_return_cmd(instance, cmd);
76700d49016bSadam radford }
76710d49016bSadam radford
76720d49016bSadam radford /**
76730d49016bSadam radford * megasas_shutdown_controller - Instructs FW to shutdown the controller
76740d49016bSadam radford * @instance: Adapter soft state
76750d49016bSadam radford * @opcode: Shutdown/Hibernate
76760d49016bSadam radford */
megasas_shutdown_controller(struct megasas_instance * instance,u32 opcode)76770d49016bSadam radford static void megasas_shutdown_controller(struct megasas_instance *instance,
76780d49016bSadam radford u32 opcode)
76790d49016bSadam radford {
76800d49016bSadam radford struct megasas_cmd *cmd;
76810d49016bSadam radford struct megasas_dcmd_frame *dcmd;
76820d49016bSadam radford
76838a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
76840d49016bSadam radford return;
76850d49016bSadam radford
76860d49016bSadam radford cmd = megasas_get_cmd(instance);
76870d49016bSadam radford
76880d49016bSadam radford if (!cmd)
76890d49016bSadam radford return;
76900d49016bSadam radford
76910d49016bSadam radford if (instance->aen_cmd)
7692cfbe7554SSumit.Saxena@lsi.com megasas_issue_blocked_abort_cmd(instance,
76936d40afbcSSumit Saxena instance->aen_cmd, MFI_IO_TIMEOUT_SECS);
76949c915a8cSadam radford if (instance->map_update_cmd)
76959c915a8cSadam radford megasas_issue_blocked_abort_cmd(instance,
76966d40afbcSSumit Saxena instance->map_update_cmd, MFI_IO_TIMEOUT_SECS);
76973761cb4cSsumit.saxena@avagotech.com if (instance->jbod_seq_cmd)
76983761cb4cSsumit.saxena@avagotech.com megasas_issue_blocked_abort_cmd(instance,
76996d40afbcSSumit Saxena instance->jbod_seq_cmd, MFI_IO_TIMEOUT_SECS);
77003761cb4cSsumit.saxena@avagotech.com
77010d49016bSadam radford dcmd = &cmd->frame->dcmd;
77020d49016bSadam radford
77030d49016bSadam radford memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
77040d49016bSadam radford
77050d49016bSadam radford dcmd->cmd = MFI_CMD_DCMD;
77060d49016bSadam radford dcmd->cmd_status = 0x0;
77070d49016bSadam radford dcmd->sge_count = 0;
770894cd65ddSSumit.Saxena@lsi.com dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_NONE);
77090d49016bSadam radford dcmd->timeout = 0;
77100d49016bSadam radford dcmd->pad_0 = 0;
77110d49016bSadam radford dcmd->data_xfer_len = 0;
771294cd65ddSSumit.Saxena@lsi.com dcmd->opcode = cpu_to_le32(opcode);
77130d49016bSadam radford
77146d40afbcSSumit Saxena if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS)
77156d40afbcSSumit Saxena != DCMD_SUCCESS) {
77166d40afbcSSumit Saxena dev_err(&instance->pdev->dev,
77176d40afbcSSumit Saxena "return from %s %d\n", __func__, __LINE__);
77186d40afbcSSumit Saxena return;
77196d40afbcSSumit Saxena }
77200d49016bSadam radford
77210d49016bSadam radford megasas_return_cmd(instance, cmd);
77220d49016bSadam radford }
77230d49016bSadam radford
77240d49016bSadam radford /**
77250d49016bSadam radford * megasas_suspend - driver suspend entry point
7726977001dfSVaibhav Gupta * @dev: Device structure
77270d49016bSadam radford */
7728977001dfSVaibhav Gupta static int __maybe_unused
megasas_suspend(struct device * dev)7729977001dfSVaibhav Gupta megasas_suspend(struct device *dev)
77300d49016bSadam radford {
77310d49016bSadam radford struct megasas_instance *instance;
77320d49016bSadam radford
7733977001dfSVaibhav Gupta instance = dev_get_drvdata(dev);
7734dd807699SChandrakanth Patil
7735dd807699SChandrakanth Patil if (!instance)
7736dd807699SChandrakanth Patil return 0;
7737dd807699SChandrakanth Patil
77380d49016bSadam radford instance->unload = 1;
77390d49016bSadam radford
7740977001dfSVaibhav Gupta dev_info(dev, "%s is called\n", __func__);
7741f7331f18SShivasharan S
7742229fe47cSadam radford /* Shutdown SR-IOV heartbeat timer */
7743229fe47cSadam radford if (instance->requestorId && !instance->skip_heartbeat_timer_del)
7744229fe47cSadam radford del_timer_sync(&instance->sriov_heartbeat_timer);
7745229fe47cSadam radford
77463f6194afSShivasharan S /* Stop the FW fault detection watchdog */
77473f6194afSShivasharan S if (instance->adapter_type != MFI_SERIES)
77483f6194afSShivasharan S megasas_fusion_stop_watchdog(instance);
77493f6194afSShivasharan S
77500d49016bSadam radford megasas_flush_cache(instance);
77510d49016bSadam radford megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
77520d49016bSadam radford
77530d49016bSadam radford /* cancel the delayed work if this work still in queue */
77540d49016bSadam radford if (instance->ev != NULL) {
77550d49016bSadam radford struct megasas_aen_event *ev = instance->ev;
7756c1d390d8SXiaotian Feng cancel_delayed_work_sync(&ev->hotplug_work);
77570d49016bSadam radford instance->ev = NULL;
77580d49016bSadam radford }
77590d49016bSadam radford
77600d49016bSadam radford tasklet_kill(&instance->isr_tasklet);
77610d49016bSadam radford
77620d49016bSadam radford pci_set_drvdata(instance->pdev, instance);
7763d46a3ad6SSumit.Saxena@lsi.com instance->instancet->disable_intr(instance);
7764c8e858feSadam radford
7765d3557fc8SSumit.Saxena@avagotech.com megasas_destroy_irqs(instance);
7766d3557fc8SSumit.Saxena@avagotech.com
7767c8e858feSadam radford if (instance->msix_vectors)
7768fad119b7SHannes Reinecke pci_free_irq_vectors(instance->pdev);
77690d49016bSadam radford
77700d49016bSadam radford return 0;
77710d49016bSadam radford }
77720d49016bSadam radford
77730d49016bSadam radford /**
77740d49016bSadam radford * megasas_resume- driver resume entry point
7775977001dfSVaibhav Gupta * @dev: Device structure
77760d49016bSadam radford */
7777977001dfSVaibhav Gupta static int __maybe_unused
megasas_resume(struct device * dev)7778977001dfSVaibhav Gupta megasas_resume(struct device *dev)
77790d49016bSadam radford {
7780d3557fc8SSumit.Saxena@avagotech.com int rval;
77810d49016bSadam radford struct Scsi_Host *host;
77820d49016bSadam radford struct megasas_instance *instance;
7783499e7246SAnand Lodnoor u32 status_reg;
77840d49016bSadam radford
7785977001dfSVaibhav Gupta instance = dev_get_drvdata(dev);
7786dd807699SChandrakanth Patil
7787dd807699SChandrakanth Patil if (!instance)
7788dd807699SChandrakanth Patil return 0;
7789dd807699SChandrakanth Patil
77900d49016bSadam radford host = instance->host;
77910d49016bSadam radford
7792977001dfSVaibhav Gupta dev_info(dev, "%s is called\n", __func__);
77930d49016bSadam radford
7794107a60ddSShivasharan S /*
7795107a60ddSShivasharan S * We expect the FW state to be READY
7796107a60ddSShivasharan S */
7797499e7246SAnand Lodnoor
7798499e7246SAnand Lodnoor if (megasas_transition_to_ready(instance, 0)) {
7799499e7246SAnand Lodnoor dev_info(&instance->pdev->dev,
7800499e7246SAnand Lodnoor "Failed to transition controller to ready from %s!\n",
7801499e7246SAnand Lodnoor __func__);
7802499e7246SAnand Lodnoor if (instance->adapter_type != MFI_SERIES) {
7803499e7246SAnand Lodnoor status_reg =
7804499e7246SAnand Lodnoor instance->instancet->read_fw_status_reg(instance);
7805499e7246SAnand Lodnoor if (!(status_reg & MFI_RESET_ADAPTER) ||
7806499e7246SAnand Lodnoor ((megasas_adp_reset_wait_for_ready
7807499e7246SAnand Lodnoor (instance, true, 0)) == FAILED))
7808499e7246SAnand Lodnoor goto fail_ready_state;
7809499e7246SAnand Lodnoor } else {
7810499e7246SAnand Lodnoor atomic_set(&instance->fw_reset_no_pci_access, 1);
7811499e7246SAnand Lodnoor instance->instancet->adp_reset
7812499e7246SAnand Lodnoor (instance, instance->reg_set);
7813499e7246SAnand Lodnoor atomic_set(&instance->fw_reset_no_pci_access, 0);
7814499e7246SAnand Lodnoor
7815499e7246SAnand Lodnoor /* waiting for about 30 seconds before retry */
7816499e7246SAnand Lodnoor ssleep(30);
7817499e7246SAnand Lodnoor
7818107a60ddSShivasharan S if (megasas_transition_to_ready(instance, 0))
7819107a60ddSShivasharan S goto fail_ready_state;
7820499e7246SAnand Lodnoor }
7821107a60ddSShivasharan S
7822499e7246SAnand Lodnoor dev_info(&instance->pdev->dev,
7823499e7246SAnand Lodnoor "FW restarted successfully from %s!\n",
7824499e7246SAnand Lodnoor __func__);
7825499e7246SAnand Lodnoor }
7826107a60ddSShivasharan S if (megasas_set_dma_mask(instance))
78270d49016bSadam radford goto fail_set_dma_mask;
78280d49016bSadam radford
78290d49016bSadam radford /*
78300d49016bSadam radford * Initialize MFI Firmware
78310d49016bSadam radford */
78320d49016bSadam radford
78330d49016bSadam radford atomic_set(&instance->fw_outstanding, 0);
783441fae9a4SShivasharan S atomic_set(&instance->ldio_outstanding, 0);
78350d49016bSadam radford
78363f1abce4Sadam radford /* Now re-enable MSI-X */
783792b4f9d1SHannes Reinecke if (instance->msix_vectors)
783892b4f9d1SHannes Reinecke megasas_alloc_irq_vectors(instance);
783992b4f9d1SHannes Reinecke
784092b4f9d1SHannes Reinecke if (!instance->msix_vectors) {
784192b4f9d1SHannes Reinecke rval = pci_alloc_irq_vectors(instance->pdev, 1, 1,
784292b4f9d1SHannes Reinecke PCI_IRQ_LEGACY);
7843fad119b7SHannes Reinecke if (rval < 0)
7844dd088128SAlexander Gordeev goto fail_reenable_msix;
784592b4f9d1SHannes Reinecke }
78463f1abce4Sadam radford
7847adbe5523SMing Lei megasas_setup_reply_map(instance);
7848adbe5523SMing Lei
7849e7d36b88SShivasharan S if (instance->adapter_type != MFI_SERIES) {
78509c915a8cSadam radford megasas_reset_reply_desc(instance);
78519c915a8cSadam radford if (megasas_ioc_init_fusion(instance)) {
78529c915a8cSadam radford megasas_free_cmds(instance);
78539c915a8cSadam radford megasas_free_cmds_fusion(instance);
78549c915a8cSadam radford goto fail_init_mfi;
78559c915a8cSadam radford }
78569c915a8cSadam radford if (!megasas_get_map_info(instance))
78579c915a8cSadam radford megasas_sync_map_info(instance);
78585a8cb85bSsumit.saxena@avagotech.com } else {
78599c915a8cSadam radford *instance->producer = 0;
78609c915a8cSadam radford *instance->consumer = 0;
78610d49016bSadam radford if (megasas_issue_init_mfi(instance))
78620d49016bSadam radford goto fail_init_mfi;
78639c915a8cSadam radford }
78640d49016bSadam radford
7865c3b10a55SShivasharan S if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS)
7866c3b10a55SShivasharan S goto fail_init_mfi;
7867c3b10a55SShivasharan S
78689c915a8cSadam radford tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
78690d49016bSadam radford (unsigned long)instance);
78700d49016bSadam radford
7871d3557fc8SSumit.Saxena@avagotech.com if (instance->msix_vectors ?
7872d3557fc8SSumit.Saxena@avagotech.com megasas_setup_irqs_msix(instance, 0) :
7873d3557fc8SSumit.Saxena@avagotech.com megasas_setup_irqs_ioapic(instance))
7874d3557fc8SSumit.Saxena@avagotech.com goto fail_init_mfi;
78750d49016bSadam radford
787662a04f81SShivasharan S if (instance->adapter_type != MFI_SERIES)
787762a04f81SShivasharan S megasas_setup_irq_poll(instance);
787862a04f81SShivasharan S
7879229fe47cSadam radford /* Re-launch SR-IOV heartbeat timer */
7880229fe47cSadam radford if (instance->requestorId) {
7881229fe47cSadam radford if (!megasas_sriov_start_heartbeat(instance, 0))
7882c251a7beSKees Cook megasas_start_timer(instance);
78835765c5b8SSumit.Saxena@avagotech.com else {
7884229fe47cSadam radford instance->skip_heartbeat_timer_del = 1;
78855765c5b8SSumit.Saxena@avagotech.com goto fail_init_mfi;
78865765c5b8SSumit.Saxena@avagotech.com }
7887229fe47cSadam radford }
7888229fe47cSadam radford
7889d46a3ad6SSumit.Saxena@lsi.com instance->instancet->enable_intr(instance);
78903761cb4cSsumit.saxena@avagotech.com megasas_setup_jbod_map(instance);
78910d49016bSadam radford instance->unload = 0;
78920d49016bSadam radford
7893541f90b7Sadam radford /*
7894541f90b7Sadam radford * Initiate AEN (Asynchronous Event Notification)
7895541f90b7Sadam radford */
7896541f90b7Sadam radford if (megasas_start_aen(instance))
78971be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "Start AEN failed\n");
7898541f90b7Sadam radford
78993f6194afSShivasharan S /* Re-launch FW fault watchdog */
79003f6194afSShivasharan S if (instance->adapter_type != MFI_SERIES)
79013f6194afSShivasharan S if (megasas_fusion_start_watchdog(instance) != SUCCESS)
79023f6194afSShivasharan S goto fail_start_watchdog;
79033f6194afSShivasharan S
79040d49016bSadam radford return 0;
79050d49016bSadam radford
79063f6194afSShivasharan S fail_start_watchdog:
79073f6194afSShivasharan S if (instance->requestorId && !instance->skip_heartbeat_timer_del)
79083f6194afSShivasharan S del_timer_sync(&instance->sriov_heartbeat_timer);
79090d49016bSadam radford fail_init_mfi:
79101b4bed20SShivasharan S megasas_free_ctrl_dma_buffers(instance);
791149a7a4adSShivasharan S megasas_free_ctrl_mem(instance);
79120d49016bSadam radford scsi_host_put(host);
79130d49016bSadam radford
7914107a60ddSShivasharan S fail_reenable_msix:
79150d49016bSadam radford fail_set_dma_mask:
79160d49016bSadam radford fail_ready_state:
79170d49016bSadam radford
79180d49016bSadam radford return -ENODEV;
79190d49016bSadam radford }
79200d49016bSadam radford
7921a1dfd62cSKashyap Desai static inline int
megasas_wait_for_adapter_operational(struct megasas_instance * instance)7922a1dfd62cSKashyap Desai megasas_wait_for_adapter_operational(struct megasas_instance *instance)
7923a1dfd62cSKashyap Desai {
7924a1dfd62cSKashyap Desai int wait_time = MEGASAS_RESET_WAIT_TIME * 2;
7925a1dfd62cSKashyap Desai int i;
79269c9db8b7SShivasharan S u8 adp_state;
7927a1dfd62cSKashyap Desai
7928a1dfd62cSKashyap Desai for (i = 0; i < wait_time; i++) {
79299c9db8b7SShivasharan S adp_state = atomic_read(&instance->adprecovery);
79309c9db8b7SShivasharan S if ((adp_state == MEGASAS_HBA_OPERATIONAL) ||
79319c9db8b7SShivasharan S (adp_state == MEGASAS_HW_CRITICAL_ERROR))
7932a1dfd62cSKashyap Desai break;
7933a1dfd62cSKashyap Desai
7934a1dfd62cSKashyap Desai if (!(i % MEGASAS_RESET_NOTICE_INTERVAL))
7935a1dfd62cSKashyap Desai dev_notice(&instance->pdev->dev, "waiting for controller reset to finish\n");
7936a1dfd62cSKashyap Desai
7937a1dfd62cSKashyap Desai msleep(1000);
7938a1dfd62cSKashyap Desai }
7939a1dfd62cSKashyap Desai
79409c9db8b7SShivasharan S if (adp_state != MEGASAS_HBA_OPERATIONAL) {
79419c9db8b7SShivasharan S dev_info(&instance->pdev->dev,
79429c9db8b7SShivasharan S "%s HBA failed to become operational, adp_state %d\n",
79439c9db8b7SShivasharan S __func__, adp_state);
7944a1dfd62cSKashyap Desai return 1;
7945a1dfd62cSKashyap Desai }
7946a1dfd62cSKashyap Desai
7947a1dfd62cSKashyap Desai return 0;
7948a1dfd62cSKashyap Desai }
7949a1dfd62cSKashyap Desai
79500d49016bSadam radford /**
79510d49016bSadam radford * megasas_detach_one - PCI hot"un"plug entry point
79520d49016bSadam radford * @pdev: PCI device structure
79530d49016bSadam radford */
megasas_detach_one(struct pci_dev * pdev)79546f039790SGreg Kroah-Hartman static void megasas_detach_one(struct pci_dev *pdev)
79550d49016bSadam radford {
79560d49016bSadam radford int i;
79570d49016bSadam radford struct Scsi_Host *host;
79580d49016bSadam radford struct megasas_instance *instance;
79599c915a8cSadam radford struct fusion_context *fusion;
796048658213SGustavo A. R. Silva size_t pd_seq_map_sz;
79610d49016bSadam radford
79620d49016bSadam radford instance = pci_get_drvdata(pdev);
7963dd807699SChandrakanth Patil
7964dd807699SChandrakanth Patil if (!instance)
7965dd807699SChandrakanth Patil return;
7966dd807699SChandrakanth Patil
79670d49016bSadam radford host = instance->host;
79689c915a8cSadam radford fusion = instance->ctrl_context;
79690d49016bSadam radford
7970229fe47cSadam radford /* Shutdown SR-IOV heartbeat timer */
7971229fe47cSadam radford if (instance->requestorId && !instance->skip_heartbeat_timer_del)
7972229fe47cSadam radford del_timer_sync(&instance->sriov_heartbeat_timer);
7973229fe47cSadam radford
79743f6194afSShivasharan S /* Stop the FW fault detection watchdog */
79753f6194afSShivasharan S if (instance->adapter_type != MFI_SERIES)
79763f6194afSShivasharan S megasas_fusion_stop_watchdog(instance);
79773f6194afSShivasharan S
7978fc62b3fcSSumit.Saxena@avagotech.com if (instance->fw_crash_state != UNAVAILABLE)
7979fc62b3fcSSumit.Saxena@avagotech.com megasas_free_host_crash_buffer(instance);
79800d49016bSadam radford scsi_remove_host(instance->host);
7981f3f7920bSShivasharan S instance->unload = 1;
7982a1dfd62cSKashyap Desai
7983a1dfd62cSKashyap Desai if (megasas_wait_for_adapter_operational(instance))
7984a1dfd62cSKashyap Desai goto skip_firing_dcmds;
7985a1dfd62cSKashyap Desai
79860d49016bSadam radford megasas_flush_cache(instance);
79870d49016bSadam radford megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
79880d49016bSadam radford
7989a1dfd62cSKashyap Desai skip_firing_dcmds:
79900d49016bSadam radford /* cancel the delayed work if this work still in queue*/
79910d49016bSadam radford if (instance->ev != NULL) {
79920d49016bSadam radford struct megasas_aen_event *ev = instance->ev;
7993c1d390d8SXiaotian Feng cancel_delayed_work_sync(&ev->hotplug_work);
79940d49016bSadam radford instance->ev = NULL;
79950d49016bSadam radford }
79960d49016bSadam radford
7997cfbe7554SSumit.Saxena@lsi.com /* cancel all wait events */
7998cfbe7554SSumit.Saxena@lsi.com wake_up_all(&instance->int_cmd_wait_q);
7999cfbe7554SSumit.Saxena@lsi.com
80000d49016bSadam radford tasklet_kill(&instance->isr_tasklet);
80010d49016bSadam radford
80020d49016bSadam radford /*
80030d49016bSadam radford * Take the instance off the instance array. Note that we will not
80040d49016bSadam radford * decrement the max_index. We let this array be sparse array
80050d49016bSadam radford */
80060d49016bSadam radford for (i = 0; i < megasas_mgmt_info.max_index; i++) {
80070d49016bSadam radford if (megasas_mgmt_info.instance[i] == instance) {
80080d49016bSadam radford megasas_mgmt_info.count--;
80090d49016bSadam radford megasas_mgmt_info.instance[i] = NULL;
80100d49016bSadam radford
80110d49016bSadam radford break;
80120d49016bSadam radford }
80130d49016bSadam radford }
80140d49016bSadam radford
8015d46a3ad6SSumit.Saxena@lsi.com instance->instancet->disable_intr(instance);
80160d49016bSadam radford
8017d3557fc8SSumit.Saxena@avagotech.com megasas_destroy_irqs(instance);
8018d3557fc8SSumit.Saxena@avagotech.com
8019c8e858feSadam radford if (instance->msix_vectors)
8020fad119b7SHannes Reinecke pci_free_irq_vectors(instance->pdev);
80210d49016bSadam radford
8022630d42b7SShivasharan S if (instance->adapter_type >= VENTURA_SERIES) {
8023fdd84e25SSasikumar Chandrasekaran for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i)
8024fdd84e25SSasikumar Chandrasekaran kfree(fusion->stream_detect_by_ld[i]);
8025fdd84e25SSasikumar Chandrasekaran kfree(fusion->stream_detect_by_ld);
8026fdd84e25SSasikumar Chandrasekaran fusion->stream_detect_by_ld = NULL;
8027fdd84e25SSasikumar Chandrasekaran }
8028fdd84e25SSasikumar Chandrasekaran
8029fdd84e25SSasikumar Chandrasekaran
8030e7d36b88SShivasharan S if (instance->adapter_type != MFI_SERIES) {
80319c915a8cSadam radford megasas_release_fusion(instance);
803248658213SGustavo A. R. Silva pd_seq_map_sz =
8033d67790ddSKees Cook struct_size_t(struct MR_PD_CFG_SEQ_NUM_SYNC,
803448658213SGustavo A. R. Silva seq, MAX_PHYSICAL_DEVICES);
803551087a86SSumit.Saxena@avagotech.com for (i = 0; i < 2 ; i++) {
80369c915a8cSadam radford if (fusion->ld_map[i])
80379c915a8cSadam radford dma_free_coherent(&instance->pdev->dev,
803851087a86SSumit.Saxena@avagotech.com fusion->max_map_sz,
80399c915a8cSadam radford fusion->ld_map[i],
804051087a86SSumit.Saxena@avagotech.com fusion->ld_map_phys[i]);
8041def3e8dfSShivasharan S if (fusion->ld_drv_map[i]) {
8042def3e8dfSShivasharan S if (is_vmalloc_addr(fusion->ld_drv_map[i]))
8043def3e8dfSShivasharan S vfree(fusion->ld_drv_map[i]);
8044def3e8dfSShivasharan S else
804551087a86SSumit.Saxena@avagotech.com free_pages((ulong)fusion->ld_drv_map[i],
804651087a86SSumit.Saxena@avagotech.com fusion->drv_map_pages);
8047def3e8dfSShivasharan S }
8048def3e8dfSShivasharan S
8049546e559cSMaurizio Lombardi if (fusion->pd_seq_sync[i])
80503761cb4cSsumit.saxena@avagotech.com dma_free_coherent(&instance->pdev->dev,
80513761cb4cSsumit.saxena@avagotech.com pd_seq_map_sz,
80523761cb4cSsumit.saxena@avagotech.com fusion->pd_seq_sync[i],
80533761cb4cSsumit.saxena@avagotech.com fusion->pd_seq_phys[i]);
805451087a86SSumit.Saxena@avagotech.com }
80555a8cb85bSsumit.saxena@avagotech.com } else {
80560d49016bSadam radford megasas_release_mfi(instance);
80579c915a8cSadam radford }
80580d49016bSadam radford
8059229fe47cSadam radford if (instance->vf_affiliation)
806060ee6529SChristoph Hellwig dma_free_coherent(&pdev->dev, (MAX_LOGICAL_DRIVES + 1) *
8061229fe47cSadam radford sizeof(struct MR_LD_VF_AFFILIATION),
8062229fe47cSadam radford instance->vf_affiliation,
8063229fe47cSadam radford instance->vf_affiliation_h);
8064229fe47cSadam radford
8065229fe47cSadam radford if (instance->vf_affiliation_111)
806660ee6529SChristoph Hellwig dma_free_coherent(&pdev->dev,
8067229fe47cSadam radford sizeof(struct MR_LD_VF_AFFILIATION_111),
8068229fe47cSadam radford instance->vf_affiliation_111,
8069229fe47cSadam radford instance->vf_affiliation_111_h);
8070229fe47cSadam radford
8071229fe47cSadam radford if (instance->hb_host_mem)
807260ee6529SChristoph Hellwig dma_free_coherent(&pdev->dev, sizeof(struct MR_CTRL_HB_HOST_MEM),
8073229fe47cSadam radford instance->hb_host_mem,
8074229fe47cSadam radford instance->hb_host_mem_h);
8075229fe47cSadam radford
80761b4bed20SShivasharan S megasas_free_ctrl_dma_buffers(instance);
8077fc62b3fcSSumit.Saxena@avagotech.com
807849a7a4adSShivasharan S megasas_free_ctrl_mem(instance);
80795765c5b8SSumit.Saxena@avagotech.com
8080ba53572bSShivasharan S megasas_destroy_debugfs(instance);
8081ba53572bSShivasharan S
80820d49016bSadam radford scsi_host_put(host);
80830d49016bSadam radford
80840d49016bSadam radford pci_disable_device(pdev);
80850d49016bSadam radford }
80860d49016bSadam radford
80870d49016bSadam radford /**
80880d49016bSadam radford * megasas_shutdown - Shutdown entry point
808949885410SVaibhav Gupta * @pdev: PCI device structure
80900d49016bSadam radford */
megasas_shutdown(struct pci_dev * pdev)80910d49016bSadam radford static void megasas_shutdown(struct pci_dev *pdev)
80920d49016bSadam radford {
80930d49016bSadam radford struct megasas_instance *instance = pci_get_drvdata(pdev);
8094c8e858feSadam radford
8095dd807699SChandrakanth Patil if (!instance)
8096dd807699SChandrakanth Patil return;
8097dd807699SChandrakanth Patil
80980d49016bSadam radford instance->unload = 1;
8099a1dfd62cSKashyap Desai
8100a1dfd62cSKashyap Desai if (megasas_wait_for_adapter_operational(instance))
8101a1dfd62cSKashyap Desai goto skip_firing_dcmds;
8102a1dfd62cSKashyap Desai
81030d49016bSadam radford megasas_flush_cache(instance);
81040d49016bSadam radford megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
8105a1dfd62cSKashyap Desai
8106a1dfd62cSKashyap Desai skip_firing_dcmds:
8107d46a3ad6SSumit.Saxena@lsi.com instance->instancet->disable_intr(instance);
8108d3557fc8SSumit.Saxena@avagotech.com megasas_destroy_irqs(instance);
8109d3557fc8SSumit.Saxena@avagotech.com
8110c8e858feSadam radford if (instance->msix_vectors)
8111fad119b7SHannes Reinecke pci_free_irq_vectors(instance->pdev);
81120d49016bSadam radford }
81130d49016bSadam radford
81142b46e5c1SDamien Le Moal /*
81150d49016bSadam radford * megasas_mgmt_open - char node "open" entry point
81162b46e5c1SDamien Le Moal * @inode: char node inode
81172b46e5c1SDamien Le Moal * @filep: char node file
81180d49016bSadam radford */
megasas_mgmt_open(struct inode * inode,struct file * filep)81190d49016bSadam radford static int megasas_mgmt_open(struct inode *inode, struct file *filep)
81200d49016bSadam radford {
81210d49016bSadam radford /*
81220d49016bSadam radford * Allow only those users with admin rights
81230d49016bSadam radford */
81240d49016bSadam radford if (!capable(CAP_SYS_ADMIN))
81250d49016bSadam radford return -EACCES;
81260d49016bSadam radford
81270d49016bSadam radford return 0;
81280d49016bSadam radford }
81290d49016bSadam radford
81302b46e5c1SDamien Le Moal /*
81310d49016bSadam radford * megasas_mgmt_fasync - Async notifier registration from applications
81322b46e5c1SDamien Le Moal * @fd: char node file descriptor number
81332b46e5c1SDamien Le Moal * @filep: char node file
81342b46e5c1SDamien Le Moal * @mode: notifier on/off
81350d49016bSadam radford *
81360d49016bSadam radford * This function adds the calling process to a driver global queue. When an
81370d49016bSadam radford * event occurs, SIGIO will be sent to all processes in this queue.
81380d49016bSadam radford */
megasas_mgmt_fasync(int fd,struct file * filep,int mode)81390d49016bSadam radford static int megasas_mgmt_fasync(int fd, struct file *filep, int mode)
81400d49016bSadam radford {
81410d49016bSadam radford int rc;
81420d49016bSadam radford
81430d49016bSadam radford mutex_lock(&megasas_async_queue_mutex);
81440d49016bSadam radford
81450d49016bSadam radford rc = fasync_helper(fd, filep, mode, &megasas_async_queue);
81460d49016bSadam radford
81470d49016bSadam radford mutex_unlock(&megasas_async_queue_mutex);
81480d49016bSadam radford
81490d49016bSadam radford if (rc >= 0) {
81500d49016bSadam radford /* For sanity check when we get ioctl */
81510d49016bSadam radford filep->private_data = filep;
81520d49016bSadam radford return 0;
81530d49016bSadam radford }
81540d49016bSadam radford
81550d49016bSadam radford printk(KERN_DEBUG "megasas: fasync_helper failed [%d]\n", rc);
81560d49016bSadam radford
81570d49016bSadam radford return rc;
81580d49016bSadam radford }
81590d49016bSadam radford
81602b46e5c1SDamien Le Moal /*
81610d49016bSadam radford * megasas_mgmt_poll - char node "poll" entry point
81622b46e5c1SDamien Le Moal * @filep: char node file
81632b46e5c1SDamien Le Moal * @wait: Events to poll for
81642b46e5c1SDamien Le Moal */
megasas_mgmt_poll(struct file * file,poll_table * wait)8165afc9a42bSAl Viro static __poll_t megasas_mgmt_poll(struct file *file, poll_table *wait)
81660d49016bSadam radford {
8167afc9a42bSAl Viro __poll_t mask;
81680d49016bSadam radford unsigned long flags;
8169da0dc9fbSBjorn Helgaas
81700d49016bSadam radford poll_wait(file, &megasas_poll_wait, wait);
81710d49016bSadam radford spin_lock_irqsave(&poll_aen_lock, flags);
81720d49016bSadam radford if (megasas_poll_wait_aen)
8173a9a08845SLinus Torvalds mask = (EPOLLIN | EPOLLRDNORM);
81740d49016bSadam radford else
81750d49016bSadam radford mask = 0;
817651087a86SSumit.Saxena@avagotech.com megasas_poll_wait_aen = 0;
81770d49016bSadam radford spin_unlock_irqrestore(&poll_aen_lock, flags);
81780d49016bSadam radford return mask;
81790d49016bSadam radford }
81800d49016bSadam radford
8181fc62b3fcSSumit.Saxena@avagotech.com /*
8182fc62b3fcSSumit.Saxena@avagotech.com * megasas_set_crash_dump_params_ioctl:
8183fc62b3fcSSumit.Saxena@avagotech.com * Send CRASH_DUMP_MODE DCMD to all controllers
8184fc62b3fcSSumit.Saxena@avagotech.com * @cmd: MFI command frame
8185fc62b3fcSSumit.Saxena@avagotech.com */
8186fc62b3fcSSumit.Saxena@avagotech.com
megasas_set_crash_dump_params_ioctl(struct megasas_cmd * cmd)8187da0dc9fbSBjorn Helgaas static int megasas_set_crash_dump_params_ioctl(struct megasas_cmd *cmd)
8188fc62b3fcSSumit.Saxena@avagotech.com {
8189fc62b3fcSSumit.Saxena@avagotech.com struct megasas_instance *local_instance;
8190fc62b3fcSSumit.Saxena@avagotech.com int i, error = 0;
8191fc62b3fcSSumit.Saxena@avagotech.com int crash_support;
8192fc62b3fcSSumit.Saxena@avagotech.com
8193fc62b3fcSSumit.Saxena@avagotech.com crash_support = cmd->frame->dcmd.mbox.w[0];
8194fc62b3fcSSumit.Saxena@avagotech.com
8195fc62b3fcSSumit.Saxena@avagotech.com for (i = 0; i < megasas_mgmt_info.max_index; i++) {
8196fc62b3fcSSumit.Saxena@avagotech.com local_instance = megasas_mgmt_info.instance[i];
8197fc62b3fcSSumit.Saxena@avagotech.com if (local_instance && local_instance->crash_dump_drv_support) {
81988a01a41dSSumit Saxena if ((atomic_read(&local_instance->adprecovery) ==
8199fc62b3fcSSumit.Saxena@avagotech.com MEGASAS_HBA_OPERATIONAL) &&
8200fc62b3fcSSumit.Saxena@avagotech.com !megasas_set_crash_dump_params(local_instance,
8201fc62b3fcSSumit.Saxena@avagotech.com crash_support)) {
8202fc62b3fcSSumit.Saxena@avagotech.com local_instance->crash_dump_app_support =
8203fc62b3fcSSumit.Saxena@avagotech.com crash_support;
8204fc62b3fcSSumit.Saxena@avagotech.com dev_info(&local_instance->pdev->dev,
8205fc62b3fcSSumit.Saxena@avagotech.com "Application firmware crash "
8206fc62b3fcSSumit.Saxena@avagotech.com "dump mode set success\n");
8207fc62b3fcSSumit.Saxena@avagotech.com error = 0;
8208fc62b3fcSSumit.Saxena@avagotech.com } else {
8209fc62b3fcSSumit.Saxena@avagotech.com dev_info(&local_instance->pdev->dev,
8210fc62b3fcSSumit.Saxena@avagotech.com "Application firmware crash "
8211fc62b3fcSSumit.Saxena@avagotech.com "dump mode set failed\n");
8212fc62b3fcSSumit.Saxena@avagotech.com error = -1;
8213fc62b3fcSSumit.Saxena@avagotech.com }
8214fc62b3fcSSumit.Saxena@avagotech.com }
8215fc62b3fcSSumit.Saxena@avagotech.com }
8216fc62b3fcSSumit.Saxena@avagotech.com return error;
8217fc62b3fcSSumit.Saxena@avagotech.com }
8218fc62b3fcSSumit.Saxena@avagotech.com
82190d49016bSadam radford /**
82200d49016bSadam radford * megasas_mgmt_fw_ioctl - Issues management ioctls to FW
82210d49016bSadam radford * @instance: Adapter soft state
82222b46e5c1SDamien Le Moal * @user_ioc: User's ioctl packet
82232b46e5c1SDamien Le Moal * @ioc: ioctl packet
82240d49016bSadam radford */
82250d49016bSadam radford static int
megasas_mgmt_fw_ioctl(struct megasas_instance * instance,struct megasas_iocpacket __user * user_ioc,struct megasas_iocpacket * ioc)82260d49016bSadam radford megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
82270d49016bSadam radford struct megasas_iocpacket __user * user_ioc,
82280d49016bSadam radford struct megasas_iocpacket *ioc)
82290d49016bSadam radford {
8230107a60ddSShivasharan S struct megasas_sge64 *kern_sge64 = NULL;
8231107a60ddSShivasharan S struct megasas_sge32 *kern_sge32 = NULL;
82320d49016bSadam radford struct megasas_cmd *cmd;
82330d49016bSadam radford void *kbuff_arr[MAX_IOCTL_SGE];
82340d49016bSadam radford dma_addr_t buf_handle = 0;
82350d49016bSadam radford int error = 0, i;
82360d49016bSadam radford void *sense = NULL;
82370d49016bSadam radford dma_addr_t sense_handle;
8238381d34e3SArnd Bergmann void *sense_ptr;
823982add4e1SShivasharan S u32 opcode = 0;
8240201a810cSAnand Lodnoor int ret = DCMD_SUCCESS;
82410d49016bSadam radford
82420d49016bSadam radford memset(kbuff_arr, 0, sizeof(kbuff_arr));
82430d49016bSadam radford
82440d49016bSadam radford if (ioc->sge_count > MAX_IOCTL_SGE) {
82451be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "SGE count [%d] > max limit [%d]\n",
82460d49016bSadam radford ioc->sge_count, MAX_IOCTL_SGE);
82470d49016bSadam radford return -EINVAL;
82480d49016bSadam radford }
82490d49016bSadam radford
8250f870bcbeSShivasharan S if ((ioc->frame.hdr.cmd >= MFI_CMD_OP_COUNT) ||
8251f870bcbeSShivasharan S ((ioc->frame.hdr.cmd == MFI_CMD_NVME) &&
825258136856SChandrakanth Patil !instance->support_nvme_passthru) ||
825358136856SChandrakanth Patil ((ioc->frame.hdr.cmd == MFI_CMD_TOOLBOX) &&
825458136856SChandrakanth Patil !instance->support_pci_lane_margining)) {
825582add4e1SShivasharan S dev_err(&instance->pdev->dev,
825682add4e1SShivasharan S "Received invalid ioctl command 0x%x\n",
825782add4e1SShivasharan S ioc->frame.hdr.cmd);
825882add4e1SShivasharan S return -ENOTSUPP;
825982add4e1SShivasharan S }
826082add4e1SShivasharan S
82610d49016bSadam radford cmd = megasas_get_cmd(instance);
82620d49016bSadam radford if (!cmd) {
82631be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get a cmd packet\n");
82640d49016bSadam radford return -ENOMEM;
82650d49016bSadam radford }
82660d49016bSadam radford
82670d49016bSadam radford /*
82680d49016bSadam radford * User's IOCTL packet has 2 frames (maximum). Copy those two
82690d49016bSadam radford * frames into our cmd's frames. cmd->frame's context will get
82700d49016bSadam radford * overwritten when we copy from user's frames. So set that value
82710d49016bSadam radford * alone separately
82720d49016bSadam radford */
82730d49016bSadam radford memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
827494cd65ddSSumit.Saxena@lsi.com cmd->frame->hdr.context = cpu_to_le32(cmd->index);
82750d49016bSadam radford cmd->frame->hdr.pad_0 = 0;
8276107a60ddSShivasharan S
8277107a60ddSShivasharan S cmd->frame->hdr.flags &= (~MFI_FRAME_IEEE);
8278107a60ddSShivasharan S
8279107a60ddSShivasharan S if (instance->consistent_mask_64bit)
8280107a60ddSShivasharan S cmd->frame->hdr.flags |= cpu_to_le16((MFI_FRAME_SGL64 |
828194cd65ddSSumit.Saxena@lsi.com MFI_FRAME_SENSE64));
8282107a60ddSShivasharan S else
8283107a60ddSShivasharan S cmd->frame->hdr.flags &= cpu_to_le16(~(MFI_FRAME_SGL64 |
8284882be7c3Sadam radford MFI_FRAME_SENSE64));
828582add4e1SShivasharan S
828682add4e1SShivasharan S if (cmd->frame->hdr.cmd == MFI_CMD_DCMD)
82878823abedSShivasharan S opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
82880d49016bSadam radford
82898823abedSShivasharan S if (opcode == MR_DCMD_CTRL_SHUTDOWN) {
82907fa3174bSChandrakanth Patil mutex_lock(&instance->reset_mutex);
829195c06086SShivasharan S if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS) {
829295c06086SShivasharan S megasas_return_cmd(instance, cmd);
82937fa3174bSChandrakanth Patil mutex_unlock(&instance->reset_mutex);
829495c06086SShivasharan S return -1;
829595c06086SShivasharan S }
82967fa3174bSChandrakanth Patil mutex_unlock(&instance->reset_mutex);
829795c06086SShivasharan S }
829895c06086SShivasharan S
82998823abedSShivasharan S if (opcode == MR_DRIVER_SET_APP_CRASHDUMP_MODE) {
8300fc62b3fcSSumit.Saxena@avagotech.com error = megasas_set_crash_dump_params_ioctl(cmd);
8301fc62b3fcSSumit.Saxena@avagotech.com megasas_return_cmd(instance, cmd);
8302fc62b3fcSSumit.Saxena@avagotech.com return error;
8303fc62b3fcSSumit.Saxena@avagotech.com }
8304fc62b3fcSSumit.Saxena@avagotech.com
83050d49016bSadam radford /*
83060d49016bSadam radford * The management interface between applications and the fw uses
83070d49016bSadam radford * MFI frames. E.g, RAID configuration changes, LD property changes
83080d49016bSadam radford * etc are accomplishes through different kinds of MFI frames. The
83090d49016bSadam radford * driver needs to care only about substituting user buffers with
83100d49016bSadam radford * kernel buffers in SGLs. The location of SGL is embedded in the
83110d49016bSadam radford * struct iocpacket itself.
83120d49016bSadam radford */
8313107a60ddSShivasharan S if (instance->consistent_mask_64bit)
8314107a60ddSShivasharan S kern_sge64 = (struct megasas_sge64 *)
8315107a60ddSShivasharan S ((unsigned long)cmd->frame + ioc->sgl_off);
8316107a60ddSShivasharan S else
83170d49016bSadam radford kern_sge32 = (struct megasas_sge32 *)
83180d49016bSadam radford ((unsigned long)cmd->frame + ioc->sgl_off);
83190d49016bSadam radford
83200d49016bSadam radford /*
83210d49016bSadam radford * For each user buffer, create a mirror buffer and copy in
83220d49016bSadam radford */
83230d49016bSadam radford for (i = 0; i < ioc->sge_count; i++) {
832498cb7e44SBjørn Mork if (!ioc->sgl[i].iov_len)
832598cb7e44SBjørn Mork continue;
832698cb7e44SBjørn Mork
83270d49016bSadam radford kbuff_arr[i] = dma_alloc_coherent(&instance->pdev->dev,
83280d49016bSadam radford ioc->sgl[i].iov_len,
83290d49016bSadam radford &buf_handle, GFP_KERNEL);
83300d49016bSadam radford if (!kbuff_arr[i]) {
83311be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to alloc "
83320d49016bSadam radford "kernel SGL buffer for IOCTL\n");
83330d49016bSadam radford error = -ENOMEM;
83340d49016bSadam radford goto out;
83350d49016bSadam radford }
83360d49016bSadam radford
83370d49016bSadam radford /*
83380d49016bSadam radford * We don't change the dma_coherent_mask, so
833960ee6529SChristoph Hellwig * dma_alloc_coherent only returns 32bit addresses
83400d49016bSadam radford */
8341107a60ddSShivasharan S if (instance->consistent_mask_64bit) {
8342107a60ddSShivasharan S kern_sge64[i].phys_addr = cpu_to_le64(buf_handle);
8343107a60ddSShivasharan S kern_sge64[i].length = cpu_to_le32(ioc->sgl[i].iov_len);
8344107a60ddSShivasharan S } else {
834594cd65ddSSumit.Saxena@lsi.com kern_sge32[i].phys_addr = cpu_to_le32(buf_handle);
834694cd65ddSSumit.Saxena@lsi.com kern_sge32[i].length = cpu_to_le32(ioc->sgl[i].iov_len);
8347107a60ddSShivasharan S }
83480d49016bSadam radford
83490d49016bSadam radford /*
83500d49016bSadam radford * We created a kernel buffer corresponding to the
83510d49016bSadam radford * user buffer. Now copy in from the user buffer
83520d49016bSadam radford */
83530d49016bSadam radford if (copy_from_user(kbuff_arr[i], ioc->sgl[i].iov_base,
83540d49016bSadam radford (u32) (ioc->sgl[i].iov_len))) {
83550d49016bSadam radford error = -EFAULT;
83560d49016bSadam radford goto out;
83570d49016bSadam radford }
83580d49016bSadam radford }
83590d49016bSadam radford
83600d49016bSadam radford if (ioc->sense_len) {
8361381d34e3SArnd Bergmann /* make sure the pointer is part of the frame */
8362381d34e3SArnd Bergmann if (ioc->sense_off >
8363381d34e3SArnd Bergmann (sizeof(union megasas_frame) - sizeof(__le64))) {
8364381d34e3SArnd Bergmann error = -EINVAL;
8365381d34e3SArnd Bergmann goto out;
8366381d34e3SArnd Bergmann }
8367381d34e3SArnd Bergmann
83680d49016bSadam radford sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len,
83690d49016bSadam radford &sense_handle, GFP_KERNEL);
83700d49016bSadam radford if (!sense) {
83710d49016bSadam radford error = -ENOMEM;
83720d49016bSadam radford goto out;
83730d49016bSadam radford }
83740d49016bSadam radford
8375b1120365SArnd Bergmann /* always store 64 bits regardless of addressing */
8376381d34e3SArnd Bergmann sense_ptr = (void *)cmd->frame + ioc->sense_off;
8377381d34e3SArnd Bergmann put_unaligned_le64(sense_handle, sense_ptr);
83780d49016bSadam radford }
83790d49016bSadam radford
83800d49016bSadam radford /*
83810d49016bSadam radford * Set the sync_cmd flag so that the ISR knows not to complete this
83820d49016bSadam radford * cmd to the SCSI mid-layer
83830d49016bSadam radford */
83840d49016bSadam radford cmd->sync_cmd = 1;
8385201a810cSAnand Lodnoor
8386201a810cSAnand Lodnoor ret = megasas_issue_blocked_cmd(instance, cmd, 0);
8387201a810cSAnand Lodnoor switch (ret) {
8388201a810cSAnand Lodnoor case DCMD_INIT:
8389201a810cSAnand Lodnoor case DCMD_BUSY:
83906d40afbcSSumit Saxena cmd->sync_cmd = 0;
83916d40afbcSSumit Saxena dev_err(&instance->pdev->dev,
839282add4e1SShivasharan S "return -EBUSY from %s %d cmd 0x%x opcode 0x%x cmd->cmd_status_drv 0x%x\n",
839382add4e1SShivasharan S __func__, __LINE__, cmd->frame->hdr.cmd, opcode,
839482add4e1SShivasharan S cmd->cmd_status_drv);
8395201a810cSAnand Lodnoor error = -EBUSY;
8396201a810cSAnand Lodnoor goto out;
83976d40afbcSSumit Saxena }
83986d40afbcSSumit Saxena
83990d49016bSadam radford cmd->sync_cmd = 0;
84000d49016bSadam radford
8401aa00832bSSumit.Saxena@avagotech.com if (instance->unload == 1) {
8402aa00832bSSumit.Saxena@avagotech.com dev_info(&instance->pdev->dev, "Driver unload is in progress "
8403aa00832bSSumit.Saxena@avagotech.com "don't submit data to application\n");
8404aa00832bSSumit.Saxena@avagotech.com goto out;
8405aa00832bSSumit.Saxena@avagotech.com }
84060d49016bSadam radford /*
84070d49016bSadam radford * copy out the kernel buffers to user buffers
84080d49016bSadam radford */
84090d49016bSadam radford for (i = 0; i < ioc->sge_count; i++) {
84100d49016bSadam radford if (copy_to_user(ioc->sgl[i].iov_base, kbuff_arr[i],
84110d49016bSadam radford ioc->sgl[i].iov_len)) {
84120d49016bSadam radford error = -EFAULT;
84130d49016bSadam radford goto out;
84140d49016bSadam radford }
84150d49016bSadam radford }
84160d49016bSadam radford
84170d49016bSadam radford /*
84180d49016bSadam radford * copy out the sense
84190d49016bSadam radford */
84200d49016bSadam radford if (ioc->sense_len) {
8421bba84aecSArnd Bergmann void __user *uptr;
84220d49016bSadam radford /*
84230d49016bSadam radford * sense_ptr points to the location that has the user
84240d49016bSadam radford * sense buffer address
84250d49016bSadam radford */
8426bba84aecSArnd Bergmann sense_ptr = (void *)ioc->frame.raw + ioc->sense_off;
8427bba84aecSArnd Bergmann if (in_compat_syscall())
8428bba84aecSArnd Bergmann uptr = compat_ptr(get_unaligned((compat_uptr_t *)
8429bba84aecSArnd Bergmann sense_ptr));
8430bba84aecSArnd Bergmann else
8431bba84aecSArnd Bergmann uptr = get_unaligned((void __user **)sense_ptr);
84320d49016bSadam radford
8433bba84aecSArnd Bergmann if (copy_to_user(uptr, sense, ioc->sense_len)) {
84341be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "Failed to copy out to user "
84350d49016bSadam radford "sense data\n");
84360d49016bSadam radford error = -EFAULT;
84370d49016bSadam radford goto out;
84380d49016bSadam radford }
84390d49016bSadam radford }
84400d49016bSadam radford
84410d49016bSadam radford /*
84420d49016bSadam radford * copy the status codes returned by the fw
84430d49016bSadam radford */
84440d49016bSadam radford if (copy_to_user(&user_ioc->frame.hdr.cmd_status,
84450d49016bSadam radford &cmd->frame->hdr.cmd_status, sizeof(u8))) {
84461be18254SBjorn Helgaas dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error copying out cmd_status\n");
84470d49016bSadam radford error = -EFAULT;
84480d49016bSadam radford }
84490d49016bSadam radford
84500d49016bSadam radford out:
84510d49016bSadam radford if (sense) {
84520d49016bSadam radford dma_free_coherent(&instance->pdev->dev, ioc->sense_len,
84530d49016bSadam radford sense, sense_handle);
84540d49016bSadam radford }
84550d49016bSadam radford
84567a6a731bSBjørn Mork for (i = 0; i < ioc->sge_count; i++) {
84573deb9438SArnd Bergmann if (kbuff_arr[i]) {
8458107a60ddSShivasharan S if (instance->consistent_mask_64bit)
8459107a60ddSShivasharan S dma_free_coherent(&instance->pdev->dev,
8460107a60ddSShivasharan S le32_to_cpu(kern_sge64[i].length),
8461107a60ddSShivasharan S kbuff_arr[i],
8462107a60ddSShivasharan S le64_to_cpu(kern_sge64[i].phys_addr));
8463107a60ddSShivasharan S else
84640d49016bSadam radford dma_free_coherent(&instance->pdev->dev,
846594cd65ddSSumit.Saxena@lsi.com le32_to_cpu(kern_sge32[i].length),
84667a6a731bSBjørn Mork kbuff_arr[i],
846794cd65ddSSumit.Saxena@lsi.com le32_to_cpu(kern_sge32[i].phys_addr));
846890dc9d98SSumit.Saxena@avagotech.com kbuff_arr[i] = NULL;
84690d49016bSadam radford }
84703deb9438SArnd Bergmann }
84710d49016bSadam radford
84720d49016bSadam radford megasas_return_cmd(instance, cmd);
84730d49016bSadam radford return error;
84740d49016bSadam radford }
84750d49016bSadam radford
8476bba84aecSArnd Bergmann static struct megasas_iocpacket *
megasas_compat_iocpacket_get_user(void __user * arg)8477bba84aecSArnd Bergmann megasas_compat_iocpacket_get_user(void __user *arg)
8478bba84aecSArnd Bergmann {
8479bba84aecSArnd Bergmann struct megasas_iocpacket *ioc;
8480bba84aecSArnd Bergmann struct compat_megasas_iocpacket __user *cioc = arg;
8481bba84aecSArnd Bergmann size_t size;
8482bba84aecSArnd Bergmann int err = -EFAULT;
8483bba84aecSArnd Bergmann int i;
8484bba84aecSArnd Bergmann
8485bba84aecSArnd Bergmann ioc = kzalloc(sizeof(*ioc), GFP_KERNEL);
8486bba84aecSArnd Bergmann if (!ioc)
8487bba84aecSArnd Bergmann return ERR_PTR(-ENOMEM);
8488bba84aecSArnd Bergmann size = offsetof(struct megasas_iocpacket, frame) + sizeof(ioc->frame);
8489bba84aecSArnd Bergmann if (copy_from_user(ioc, arg, size))
8490bba84aecSArnd Bergmann goto out;
8491bba84aecSArnd Bergmann
8492bba84aecSArnd Bergmann for (i = 0; i < MAX_IOCTL_SGE; i++) {
8493bba84aecSArnd Bergmann compat_uptr_t iov_base;
8494bba84aecSArnd Bergmann
8495bba84aecSArnd Bergmann if (get_user(iov_base, &cioc->sgl[i].iov_base) ||
8496bba84aecSArnd Bergmann get_user(ioc->sgl[i].iov_len, &cioc->sgl[i].iov_len))
8497bba84aecSArnd Bergmann goto out;
8498bba84aecSArnd Bergmann
8499bba84aecSArnd Bergmann ioc->sgl[i].iov_base = compat_ptr(iov_base);
8500bba84aecSArnd Bergmann }
8501bba84aecSArnd Bergmann
8502bba84aecSArnd Bergmann return ioc;
8503bba84aecSArnd Bergmann out:
8504bba84aecSArnd Bergmann kfree(ioc);
8505bba84aecSArnd Bergmann return ERR_PTR(err);
8506bba84aecSArnd Bergmann }
8507bba84aecSArnd Bergmann
megasas_mgmt_ioctl_fw(struct file * file,unsigned long arg)85080d49016bSadam radford static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
85090d49016bSadam radford {
85100d49016bSadam radford struct megasas_iocpacket __user *user_ioc =
85110d49016bSadam radford (struct megasas_iocpacket __user *)arg;
85120d49016bSadam radford struct megasas_iocpacket *ioc;
85130d49016bSadam radford struct megasas_instance *instance;
85140d49016bSadam radford int error;
85150d49016bSadam radford
8516bba84aecSArnd Bergmann if (in_compat_syscall())
8517bba84aecSArnd Bergmann ioc = megasas_compat_iocpacket_get_user(user_ioc);
8518bba84aecSArnd Bergmann else
8519bba84aecSArnd Bergmann ioc = memdup_user(user_ioc, sizeof(struct megasas_iocpacket));
8520bba84aecSArnd Bergmann
8521709ab231SMarkus Elfring if (IS_ERR(ioc))
8522709ab231SMarkus Elfring return PTR_ERR(ioc);
85230d49016bSadam radford
85240d49016bSadam radford instance = megasas_lookup_instance(ioc->host_no);
85250d49016bSadam radford if (!instance) {
85260d49016bSadam radford error = -ENODEV;
85270d49016bSadam radford goto out_kfree_ioc;
85280d49016bSadam radford }
85290d49016bSadam radford
8530229fe47cSadam radford /* Block ioctls in VF mode */
8531229fe47cSadam radford if (instance->requestorId && !allow_vf_ioctls) {
8532229fe47cSadam radford error = -ENODEV;
8533229fe47cSadam radford goto out_kfree_ioc;
8534229fe47cSadam radford }
8535229fe47cSadam radford
85368a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
85371be18254SBjorn Helgaas dev_err(&instance->pdev->dev, "Controller in crit error\n");
85380d49016bSadam radford error = -ENODEV;
85390d49016bSadam radford goto out_kfree_ioc;
85400d49016bSadam radford }
85410d49016bSadam radford
85420d49016bSadam radford if (instance->unload == 1) {
85430d49016bSadam radford error = -ENODEV;
85440d49016bSadam radford goto out_kfree_ioc;
85450d49016bSadam radford }
85460d49016bSadam radford
85470d49016bSadam radford if (down_interruptible(&instance->ioctl_sem)) {
85480d49016bSadam radford error = -ERESTARTSYS;
85490d49016bSadam radford goto out_kfree_ioc;
85500d49016bSadam radford }
85510d49016bSadam radford
8552619831f2SShivasharan S if (megasas_wait_for_adapter_operational(instance)) {
85530d49016bSadam radford error = -ENODEV;
8554c64e483eSDan Carpenter goto out_up;
85550d49016bSadam radford }
85560d49016bSadam radford
85570d49016bSadam radford error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc);
8558c64e483eSDan Carpenter out_up:
85590d49016bSadam radford up(&instance->ioctl_sem);
85600d49016bSadam radford
85610d49016bSadam radford out_kfree_ioc:
85620d49016bSadam radford kfree(ioc);
85630d49016bSadam radford return error;
85640d49016bSadam radford }
85650d49016bSadam radford
megasas_mgmt_ioctl_aen(struct file * file,unsigned long arg)85660d49016bSadam radford static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
85670d49016bSadam radford {
85680d49016bSadam radford struct megasas_instance *instance;
85690d49016bSadam radford struct megasas_aen aen;
85700d49016bSadam radford int error;
85710d49016bSadam radford
85720d49016bSadam radford if (file->private_data != file) {
85730d49016bSadam radford printk(KERN_DEBUG "megasas: fasync_helper was not "
85740d49016bSadam radford "called first\n");
85750d49016bSadam radford return -EINVAL;
85760d49016bSadam radford }
85770d49016bSadam radford
85780d49016bSadam radford if (copy_from_user(&aen, (void __user *)arg, sizeof(aen)))
85790d49016bSadam radford return -EFAULT;
85800d49016bSadam radford
85810d49016bSadam radford instance = megasas_lookup_instance(aen.host_no);
85820d49016bSadam radford
85830d49016bSadam radford if (!instance)
85840d49016bSadam radford return -ENODEV;
85850d49016bSadam radford
85868a01a41dSSumit Saxena if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
85870d49016bSadam radford return -ENODEV;
85880d49016bSadam radford }
85890d49016bSadam radford
85900d49016bSadam radford if (instance->unload == 1) {
85910d49016bSadam radford return -ENODEV;
85920d49016bSadam radford }
85930d49016bSadam radford
8594619831f2SShivasharan S if (megasas_wait_for_adapter_operational(instance))
85950d49016bSadam radford return -ENODEV;
85960d49016bSadam radford
859711c71cb4SSumit Saxena mutex_lock(&instance->reset_mutex);
85980d49016bSadam radford error = megasas_register_aen(instance, aen.seq_num,
85990d49016bSadam radford aen.class_locale_word);
860011c71cb4SSumit Saxena mutex_unlock(&instance->reset_mutex);
86010d49016bSadam radford return error;
86020d49016bSadam radford }
86030d49016bSadam radford
86040d49016bSadam radford /**
86050d49016bSadam radford * megasas_mgmt_ioctl - char node ioctl entry point
86062b46e5c1SDamien Le Moal * @file: char device file pointer
86072b46e5c1SDamien Le Moal * @cmd: ioctl command
86082b46e5c1SDamien Le Moal * @arg: ioctl command arguments address
86090d49016bSadam radford */
86100d49016bSadam radford static long
megasas_mgmt_ioctl(struct file * file,unsigned int cmd,unsigned long arg)86110d49016bSadam radford megasas_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
86120d49016bSadam radford {
86130d49016bSadam radford switch (cmd) {
86140d49016bSadam radford case MEGASAS_IOC_FIRMWARE:
86150d49016bSadam radford return megasas_mgmt_ioctl_fw(file, arg);
86160d49016bSadam radford
86170d49016bSadam radford case MEGASAS_IOC_GET_AEN:
86180d49016bSadam radford return megasas_mgmt_ioctl_aen(file, arg);
86190d49016bSadam radford }
86200d49016bSadam radford
86210d49016bSadam radford return -ENOTTY;
86220d49016bSadam radford }
86230d49016bSadam radford
86240d49016bSadam radford #ifdef CONFIG_COMPAT
86250d49016bSadam radford static long
megasas_mgmt_compat_ioctl(struct file * file,unsigned int cmd,unsigned long arg)86260d49016bSadam radford megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd,
86270d49016bSadam radford unsigned long arg)
86280d49016bSadam radford {
86290d49016bSadam radford switch (cmd) {
86300d49016bSadam radford case MEGASAS_IOC_FIRMWARE32:
8631bba84aecSArnd Bergmann return megasas_mgmt_ioctl_fw(file, arg);
86320d49016bSadam radford case MEGASAS_IOC_GET_AEN:
86330d49016bSadam radford return megasas_mgmt_ioctl_aen(file, arg);
86340d49016bSadam radford }
86350d49016bSadam radford
86360d49016bSadam radford return -ENOTTY;
86370d49016bSadam radford }
86380d49016bSadam radford #endif
86390d49016bSadam radford
86400d49016bSadam radford /*
86410d49016bSadam radford * File operations structure for management interface
86420d49016bSadam radford */
86430d49016bSadam radford static const struct file_operations megasas_mgmt_fops = {
86440d49016bSadam radford .owner = THIS_MODULE,
86450d49016bSadam radford .open = megasas_mgmt_open,
86460d49016bSadam radford .fasync = megasas_mgmt_fasync,
86470d49016bSadam radford .unlocked_ioctl = megasas_mgmt_ioctl,
86480d49016bSadam radford .poll = megasas_mgmt_poll,
86490d49016bSadam radford #ifdef CONFIG_COMPAT
86500d49016bSadam radford .compat_ioctl = megasas_mgmt_compat_ioctl,
86510d49016bSadam radford #endif
86520d49016bSadam radford .llseek = noop_llseek,
86530d49016bSadam radford };
86540d49016bSadam radford
8655977001dfSVaibhav Gupta static SIMPLE_DEV_PM_OPS(megasas_pm_ops, megasas_suspend, megasas_resume);
8656977001dfSVaibhav Gupta
86570d49016bSadam radford /*
86580d49016bSadam radford * PCI hotplug support registration structure
86590d49016bSadam radford */
86600d49016bSadam radford static struct pci_driver megasas_pci_driver = {
86610d49016bSadam radford
86620d49016bSadam radford .name = "megaraid_sas",
86630d49016bSadam radford .id_table = megasas_pci_table,
86640d49016bSadam radford .probe = megasas_probe_one,
86656f039790SGreg Kroah-Hartman .remove = megasas_detach_one,
8666977001dfSVaibhav Gupta .driver.pm = &megasas_pm_ops,
86670d49016bSadam radford .shutdown = megasas_shutdown,
86680d49016bSadam radford };
86690d49016bSadam radford
86700d49016bSadam radford /*
86710d49016bSadam radford * Sysfs driver attributes
86720d49016bSadam radford */
version_show(struct device_driver * dd,char * buf)8673e14a3967SGreg Kroah-Hartman static ssize_t version_show(struct device_driver *dd, char *buf)
86740d49016bSadam radford {
86750d49016bSadam radford return snprintf(buf, strlen(MEGASAS_VERSION) + 2, "%s\n",
86760d49016bSadam radford MEGASAS_VERSION);
86770d49016bSadam radford }
8678e14a3967SGreg Kroah-Hartman static DRIVER_ATTR_RO(version);
86790d49016bSadam radford
release_date_show(struct device_driver * dd,char * buf)8680e14a3967SGreg Kroah-Hartman static ssize_t release_date_show(struct device_driver *dd, char *buf)
868109fced19SSumit.Saxena@avagotech.com {
868209fced19SSumit.Saxena@avagotech.com return snprintf(buf, strlen(MEGASAS_RELDATE) + 2, "%s\n",
868309fced19SSumit.Saxena@avagotech.com MEGASAS_RELDATE);
868409fced19SSumit.Saxena@avagotech.com }
8685e14a3967SGreg Kroah-Hartman static DRIVER_ATTR_RO(release_date);
868609fced19SSumit.Saxena@avagotech.com
support_poll_for_event_show(struct device_driver * dd,char * buf)8687e14a3967SGreg Kroah-Hartman static ssize_t support_poll_for_event_show(struct device_driver *dd, char *buf)
86880d49016bSadam radford {
86890d49016bSadam radford return sprintf(buf, "%u\n", support_poll_for_event);
86900d49016bSadam radford }
8691e14a3967SGreg Kroah-Hartman static DRIVER_ATTR_RO(support_poll_for_event);
86920d49016bSadam radford
support_device_change_show(struct device_driver * dd,char * buf)8693e14a3967SGreg Kroah-Hartman static ssize_t support_device_change_show(struct device_driver *dd, char *buf)
86940d49016bSadam radford {
86950d49016bSadam radford return sprintf(buf, "%u\n", support_device_change);
86960d49016bSadam radford }
8697e14a3967SGreg Kroah-Hartman static DRIVER_ATTR_RO(support_device_change);
86980d49016bSadam radford
dbg_lvl_show(struct device_driver * dd,char * buf)8699e14a3967SGreg Kroah-Hartman static ssize_t dbg_lvl_show(struct device_driver *dd, char *buf)
87000d49016bSadam radford {
87010d49016bSadam radford return sprintf(buf, "%u\n", megasas_dbg_lvl);
87020d49016bSadam radford }
87030d49016bSadam radford
dbg_lvl_store(struct device_driver * dd,const char * buf,size_t count)8704e14a3967SGreg Kroah-Hartman static ssize_t dbg_lvl_store(struct device_driver *dd, const char *buf,
8705e14a3967SGreg Kroah-Hartman size_t count)
87060d49016bSadam radford {
87070d49016bSadam radford int retval = count;
8708da0dc9fbSBjorn Helgaas
87090d49016bSadam radford if (sscanf(buf, "%u", &megasas_dbg_lvl) < 1) {
87100d49016bSadam radford printk(KERN_ERR "megasas: could not set dbg_lvl\n");
87110d49016bSadam radford retval = -EINVAL;
87120d49016bSadam radford }
87130d49016bSadam radford return retval;
87140d49016bSadam radford }
8715e14a3967SGreg Kroah-Hartman static DRIVER_ATTR_RW(dbg_lvl);
87160d49016bSadam radford
8717f870bcbeSShivasharan S static ssize_t
support_nvme_encapsulation_show(struct device_driver * dd,char * buf)8718f870bcbeSShivasharan S support_nvme_encapsulation_show(struct device_driver *dd, char *buf)
8719f870bcbeSShivasharan S {
8720f870bcbeSShivasharan S return sprintf(buf, "%u\n", support_nvme_encapsulation);
8721f870bcbeSShivasharan S }
8722f870bcbeSShivasharan S
8723f870bcbeSShivasharan S static DRIVER_ATTR_RO(support_nvme_encapsulation);
8724f870bcbeSShivasharan S
872558136856SChandrakanth Patil static ssize_t
support_pci_lane_margining_show(struct device_driver * dd,char * buf)872658136856SChandrakanth Patil support_pci_lane_margining_show(struct device_driver *dd, char *buf)
872758136856SChandrakanth Patil {
872858136856SChandrakanth Patil return sprintf(buf, "%u\n", support_pci_lane_margining);
872958136856SChandrakanth Patil }
873058136856SChandrakanth Patil
873158136856SChandrakanth Patil static DRIVER_ATTR_RO(support_pci_lane_margining);
873258136856SChandrakanth Patil
megasas_remove_scsi_device(struct scsi_device * sdev)8733b4a42213SShivasharan S static inline void megasas_remove_scsi_device(struct scsi_device *sdev)
8734b4a42213SShivasharan S {
8735b4a42213SShivasharan S sdev_printk(KERN_INFO, sdev, "SCSI device is removed\n");
8736b4a42213SShivasharan S scsi_remove_device(sdev);
8737b4a42213SShivasharan S scsi_device_put(sdev);
8738b4a42213SShivasharan S }
8739b4a42213SShivasharan S
874044abbaf6SShivasharan S /**
874144abbaf6SShivasharan S * megasas_update_device_list - Update the PD and LD device list from FW
874244abbaf6SShivasharan S * after an AEN event notification
874344abbaf6SShivasharan S * @instance: Adapter soft state
874444abbaf6SShivasharan S * @event_type: Indicates type of event (PD or LD event)
874544abbaf6SShivasharan S *
874644abbaf6SShivasharan S * @return: Success or failure
874744abbaf6SShivasharan S *
874844abbaf6SShivasharan S * Issue DCMDs to Firmware to update the internal device list in driver.
8749f6fe5731SShivasharan S * Based on the FW support, driver sends the HOST_DEVICE_LIST or combination
8750f6fe5731SShivasharan S * of PD_LIST/LD_LIST_QUERY DCMDs to get the device list.
875144abbaf6SShivasharan S */
875244abbaf6SShivasharan S static
megasas_update_device_list(struct megasas_instance * instance,int event_type)875344abbaf6SShivasharan S int megasas_update_device_list(struct megasas_instance *instance,
875444abbaf6SShivasharan S int event_type)
87550d49016bSadam radford {
875617883cd5SGuixin Liu int dcmd_ret;
875744abbaf6SShivasharan S
8758f6fe5731SShivasharan S if (instance->enable_fw_dev_list) {
875917883cd5SGuixin Liu return megasas_host_device_list_query(instance, false);
8760f6fe5731SShivasharan S } else {
876144abbaf6SShivasharan S if (event_type & SCAN_PD_CHANNEL) {
876244abbaf6SShivasharan S dcmd_ret = megasas_get_pd_list(instance);
876344abbaf6SShivasharan S if (dcmd_ret != DCMD_SUCCESS)
876417883cd5SGuixin Liu return dcmd_ret;
876544abbaf6SShivasharan S }
876644abbaf6SShivasharan S
876744abbaf6SShivasharan S if (event_type & SCAN_VD_CHANNEL) {
876844abbaf6SShivasharan S if (!instance->requestorId ||
876917dfd54dSjing yangyang megasas_get_ld_vf_affiliation(instance, 0)) {
877017883cd5SGuixin Liu return megasas_ld_list_query(instance,
877144abbaf6SShivasharan S MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
877244abbaf6SShivasharan S }
877344abbaf6SShivasharan S }
8774f6fe5731SShivasharan S }
877517883cd5SGuixin Liu return DCMD_SUCCESS;
877644abbaf6SShivasharan S }
877744abbaf6SShivasharan S
877844abbaf6SShivasharan S /**
877944abbaf6SShivasharan S * megasas_add_remove_devices - Add/remove devices to SCSI mid-layer
878044abbaf6SShivasharan S * after an AEN event notification
878144abbaf6SShivasharan S * @instance: Adapter soft state
878244abbaf6SShivasharan S * @scan_type: Indicates type of devices (PD/LD) to add
878344abbaf6SShivasharan S * @return void
878444abbaf6SShivasharan S */
878544abbaf6SShivasharan S static
megasas_add_remove_devices(struct megasas_instance * instance,int scan_type)878644abbaf6SShivasharan S void megasas_add_remove_devices(struct megasas_instance *instance,
878744abbaf6SShivasharan S int scan_type)
878844abbaf6SShivasharan S {
878944abbaf6SShivasharan S int i, j;
87900d49016bSadam radford u16 pd_index = 0;
87910d49016bSadam radford u16 ld_index = 0;
8792f6fe5731SShivasharan S u16 channel = 0, id = 0;
879344abbaf6SShivasharan S struct Scsi_Host *host;
879444abbaf6SShivasharan S struct scsi_device *sdev1;
8795f6fe5731SShivasharan S struct MR_HOST_DEVICE_LIST *targetid_list = NULL;
8796f6fe5731SShivasharan S struct MR_HOST_DEVICE_LIST_ENTRY *targetid_entry = NULL;
87970d49016bSadam radford
87980d49016bSadam radford host = instance->host;
87990d49016bSadam radford
8800f6fe5731SShivasharan S if (instance->enable_fw_dev_list) {
8801f6fe5731SShivasharan S targetid_list = instance->host_device_list_buf;
8802f6fe5731SShivasharan S for (i = 0; i < targetid_list->count; i++) {
8803f6fe5731SShivasharan S targetid_entry = &targetid_list->host_device_list[i];
8804f6fe5731SShivasharan S if (targetid_entry->flags.u.bits.is_sys_pd) {
8805f6fe5731SShivasharan S channel = le16_to_cpu(targetid_entry->target_id) /
8806f6fe5731SShivasharan S MEGASAS_MAX_DEV_PER_CHANNEL;
8807f6fe5731SShivasharan S id = le16_to_cpu(targetid_entry->target_id) %
8808f6fe5731SShivasharan S MEGASAS_MAX_DEV_PER_CHANNEL;
88090d49016bSadam radford } else {
8810f6fe5731SShivasharan S channel = MEGASAS_MAX_PD_CHANNELS +
8811f6fe5731SShivasharan S (le16_to_cpu(targetid_entry->target_id) /
8812f6fe5731SShivasharan S MEGASAS_MAX_DEV_PER_CHANNEL);
8813f6fe5731SShivasharan S id = le16_to_cpu(targetid_entry->target_id) %
8814f6fe5731SShivasharan S MEGASAS_MAX_DEV_PER_CHANNEL;
8815f6fe5731SShivasharan S }
8816f6fe5731SShivasharan S sdev1 = scsi_device_lookup(host, channel, id, 0);
8817f6fe5731SShivasharan S if (!sdev1) {
8818f6fe5731SShivasharan S scsi_add_device(host, channel, id, 0);
8819f6fe5731SShivasharan S } else {
8820f6fe5731SShivasharan S scsi_device_put(sdev1);
8821f6fe5731SShivasharan S }
8822f6fe5731SShivasharan S }
88230d49016bSadam radford }
88240d49016bSadam radford
882544abbaf6SShivasharan S if (scan_type & SCAN_PD_CHANNEL) {
88260d49016bSadam radford for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
88270d49016bSadam radford for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
88280d49016bSadam radford pd_index = i * MEGASAS_MAX_DEV_PER_CHANNEL + j;
88290d49016bSadam radford sdev1 = scsi_device_lookup(host, i, j, 0);
88300d49016bSadam radford if (instance->pd_list[pd_index].driveState ==
88310d49016bSadam radford MR_PD_STATE_SYSTEM) {
883211c71cb4SSumit Saxena if (!sdev1)
88330d49016bSadam radford scsi_add_device(host, i, j, 0);
883411c71cb4SSumit Saxena else
88350d49016bSadam radford scsi_device_put(sdev1);
88360d49016bSadam radford } else {
8837b4a42213SShivasharan S if (sdev1)
8838b4a42213SShivasharan S megasas_remove_scsi_device(sdev1);
88390d49016bSadam radford }
88400d49016bSadam radford }
88410d49016bSadam radford }
884258968fc8SHannes Reinecke }
88430d49016bSadam radford
884444abbaf6SShivasharan S if (scan_type & SCAN_VD_CHANNEL) {
88450d49016bSadam radford for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
884611c71cb4SSumit Saxena for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
884711c71cb4SSumit Saxena ld_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
884844abbaf6SShivasharan S sdev1 = scsi_device_lookup(host,
884944abbaf6SShivasharan S MEGASAS_MAX_PD_CHANNELS + i, j, 0);
885011c71cb4SSumit Saxena if (instance->ld_ids[ld_index] != 0xff) {
8851229fe47cSadam radford if (!sdev1)
8852229fe47cSadam radford scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
8853229fe47cSadam radford else
88540d49016bSadam radford scsi_device_put(sdev1);
88550d49016bSadam radford } else {
8856b4a42213SShivasharan S if (sdev1)
8857b4a42213SShivasharan S megasas_remove_scsi_device(sdev1);
88580d49016bSadam radford }
88590d49016bSadam radford }
88600d49016bSadam radford }
88610d49016bSadam radford }
886211c71cb4SSumit Saxena
886344abbaf6SShivasharan S }
886444abbaf6SShivasharan S
886544abbaf6SShivasharan S static void
megasas_aen_polling(struct work_struct * work)886644abbaf6SShivasharan S megasas_aen_polling(struct work_struct *work)
886744abbaf6SShivasharan S {
886844abbaf6SShivasharan S struct megasas_aen_event *ev =
886944abbaf6SShivasharan S container_of(work, struct megasas_aen_event, hotplug_work.work);
887044abbaf6SShivasharan S struct megasas_instance *instance = ev->instance;
887144abbaf6SShivasharan S union megasas_evt_class_locale class_locale;
887244abbaf6SShivasharan S int event_type = 0;
8873de19212cSYueHaibing u32 seq_num;
8874ae6874baSKashyap Desai u16 ld_target_id;
887544abbaf6SShivasharan S int error;
887644abbaf6SShivasharan S u8 dcmd_ret = DCMD_SUCCESS;
8877ae6874baSKashyap Desai struct scsi_device *sdev1;
887844abbaf6SShivasharan S
887944abbaf6SShivasharan S if (!instance) {
888044abbaf6SShivasharan S printk(KERN_ERR "invalid instance!\n");
888144abbaf6SShivasharan S kfree(ev);
888244abbaf6SShivasharan S return;
888344abbaf6SShivasharan S }
888444abbaf6SShivasharan S
888544abbaf6SShivasharan S /* Don't run the event workqueue thread if OCR is running */
888644abbaf6SShivasharan S mutex_lock(&instance->reset_mutex);
888744abbaf6SShivasharan S
888844abbaf6SShivasharan S instance->ev = NULL;
888944abbaf6SShivasharan S if (instance->evt_detail) {
889044abbaf6SShivasharan S megasas_decode_evt(instance);
889144abbaf6SShivasharan S
889244abbaf6SShivasharan S switch (le32_to_cpu(instance->evt_detail->code)) {
889344abbaf6SShivasharan S
889444abbaf6SShivasharan S case MR_EVT_PD_INSERTED:
889544abbaf6SShivasharan S case MR_EVT_PD_REMOVED:
889644abbaf6SShivasharan S event_type = SCAN_PD_CHANNEL;
889744abbaf6SShivasharan S break;
889844abbaf6SShivasharan S
889944abbaf6SShivasharan S case MR_EVT_LD_OFFLINE:
890044abbaf6SShivasharan S case MR_EVT_LD_DELETED:
8901ae6874baSKashyap Desai ld_target_id = instance->evt_detail->args.ld.target_id;
8902ae6874baSKashyap Desai sdev1 = scsi_device_lookup(instance->host,
8903ae6874baSKashyap Desai MEGASAS_MAX_PD_CHANNELS +
8904ae6874baSKashyap Desai (ld_target_id / MEGASAS_MAX_DEV_PER_CHANNEL),
89059b78d8faSGuixin Liu (ld_target_id % MEGASAS_MAX_DEV_PER_CHANNEL),
8906ae6874baSKashyap Desai 0);
8907*f5078314STomas Henzl if (sdev1) {
8908*f5078314STomas Henzl mutex_unlock(&instance->reset_mutex);
8909ae6874baSKashyap Desai megasas_remove_scsi_device(sdev1);
8910*f5078314STomas Henzl mutex_lock(&instance->reset_mutex);
8911*f5078314STomas Henzl }
8912ae6874baSKashyap Desai
8913ae6874baSKashyap Desai event_type = SCAN_VD_CHANNEL;
8914ae6874baSKashyap Desai break;
891544abbaf6SShivasharan S case MR_EVT_LD_CREATED:
891644abbaf6SShivasharan S event_type = SCAN_VD_CHANNEL;
891744abbaf6SShivasharan S break;
891844abbaf6SShivasharan S
8919ae6874baSKashyap Desai case MR_EVT_CFG_CLEARED:
892044abbaf6SShivasharan S case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
892144abbaf6SShivasharan S case MR_EVT_FOREIGN_CFG_IMPORTED:
892244abbaf6SShivasharan S case MR_EVT_LD_STATE_CHANGE:
892344abbaf6SShivasharan S event_type = SCAN_PD_CHANNEL | SCAN_VD_CHANNEL;
892444abbaf6SShivasharan S dev_info(&instance->pdev->dev, "scanning for scsi%d...\n",
892544abbaf6SShivasharan S instance->host->host_no);
892644abbaf6SShivasharan S break;
892744abbaf6SShivasharan S
892844abbaf6SShivasharan S case MR_EVT_CTRL_PROP_CHANGED:
892944abbaf6SShivasharan S dcmd_ret = megasas_get_ctrl_info(instance);
893044abbaf6SShivasharan S if (dcmd_ret == DCMD_SUCCESS &&
893144abbaf6SShivasharan S instance->snapdump_wait_time) {
893244abbaf6SShivasharan S megasas_get_snapdump_properties(instance);
893344abbaf6SShivasharan S dev_info(&instance->pdev->dev,
893444abbaf6SShivasharan S "Snap dump wait time\t: %d\n",
893544abbaf6SShivasharan S instance->snapdump_wait_time);
893644abbaf6SShivasharan S }
893744abbaf6SShivasharan S break;
893844abbaf6SShivasharan S default:
893944abbaf6SShivasharan S event_type = 0;
894044abbaf6SShivasharan S break;
894144abbaf6SShivasharan S }
894244abbaf6SShivasharan S } else {
894344abbaf6SShivasharan S dev_err(&instance->pdev->dev, "invalid evt_detail!\n");
894444abbaf6SShivasharan S mutex_unlock(&instance->reset_mutex);
894544abbaf6SShivasharan S kfree(ev);
894644abbaf6SShivasharan S return;
894744abbaf6SShivasharan S }
894844abbaf6SShivasharan S
894944abbaf6SShivasharan S if (event_type)
895044abbaf6SShivasharan S dcmd_ret = megasas_update_device_list(instance, event_type);
895144abbaf6SShivasharan S
895244abbaf6SShivasharan S mutex_unlock(&instance->reset_mutex);
895344abbaf6SShivasharan S
895444abbaf6SShivasharan S if (event_type && dcmd_ret == DCMD_SUCCESS)
895544abbaf6SShivasharan S megasas_add_remove_devices(instance, event_type);
895644abbaf6SShivasharan S
89576d40afbcSSumit Saxena if (dcmd_ret == DCMD_SUCCESS)
895811c71cb4SSumit Saxena seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
895911c71cb4SSumit Saxena else
896011c71cb4SSumit Saxena seq_num = instance->last_seq_num;
896111c71cb4SSumit Saxena
896211c71cb4SSumit Saxena /* Register AEN with FW for latest sequence number plus 1 */
896311c71cb4SSumit Saxena class_locale.members.reserved = 0;
896411c71cb4SSumit Saxena class_locale.members.locale = MR_EVT_LOCALE_ALL;
896511c71cb4SSumit Saxena class_locale.members.class = MR_EVT_CLASS_DEBUG;
89660d49016bSadam radford
89670d49016bSadam radford if (instance->aen_cmd != NULL) {
89680d49016bSadam radford kfree(ev);
89690d49016bSadam radford return;
89700d49016bSadam radford }
89710d49016bSadam radford
897211c71cb4SSumit Saxena mutex_lock(&instance->reset_mutex);
89730d49016bSadam radford error = megasas_register_aen(instance, seq_num,
89740d49016bSadam radford class_locale.word);
89750d49016bSadam radford if (error)
897611c71cb4SSumit Saxena dev_err(&instance->pdev->dev,
897711c71cb4SSumit Saxena "register aen failed error %x\n", error);
89780d49016bSadam radford
897911c71cb4SSumit Saxena mutex_unlock(&instance->reset_mutex);
89800d49016bSadam radford kfree(ev);
89810d49016bSadam radford }
89820d49016bSadam radford
89830d49016bSadam radford /**
89840d49016bSadam radford * megasas_init - Driver load entry point
89850d49016bSadam radford */
megasas_init(void)89860d49016bSadam radford static int __init megasas_init(void)
89870d49016bSadam radford {
89880d49016bSadam radford int rval;
89890d49016bSadam radford
89900d49016bSadam radford /*
8991c3e385a1SSumit Saxena * Booted in kdump kernel, minimize memory footprints by
8992c3e385a1SSumit Saxena * disabling few features
8993c3e385a1SSumit Saxena */
8994c3e385a1SSumit Saxena if (reset_devices) {
8995c3e385a1SSumit Saxena msix_vectors = 1;
8996c3e385a1SSumit Saxena rdpq_enable = 0;
8997c3e385a1SSumit Saxena dual_qdepth_disable = 1;
89989e4bec5bSKashyap Desai poll_queues = 0;
8999c3e385a1SSumit Saxena }
9000c3e385a1SSumit Saxena
9001c3e385a1SSumit Saxena /*
90020d49016bSadam radford * Announce driver version and other information
90030d49016bSadam radford */
9004d98a6debSSumit.Saxena@avagotech.com pr_info("megasas: %s\n", MEGASAS_VERSION);
90050d49016bSadam radford
900627b571ccSGuixin Liu megasas_dbg_lvl = 0;
90070d49016bSadam radford support_poll_for_event = 2;
90080d49016bSadam radford support_device_change = 1;
9009f870bcbeSShivasharan S support_nvme_encapsulation = true;
901058136856SChandrakanth Patil support_pci_lane_margining = true;
90110d49016bSadam radford
90120d49016bSadam radford memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
90130d49016bSadam radford
90140d49016bSadam radford /*
90150d49016bSadam radford * Register character device node
90160d49016bSadam radford */
90170d49016bSadam radford rval = register_chrdev(0, "megaraid_sas_ioctl", &megasas_mgmt_fops);
90180d49016bSadam radford
90190d49016bSadam radford if (rval < 0) {
90200d49016bSadam radford printk(KERN_DEBUG "megasas: failed to open device node\n");
90210d49016bSadam radford return rval;
90220d49016bSadam radford }
90230d49016bSadam radford
90240d49016bSadam radford megasas_mgmt_majorno = rval;
90250d49016bSadam radford
9026ba53572bSShivasharan S megasas_init_debugfs();
9027ba53572bSShivasharan S
90280d49016bSadam radford /*
90290d49016bSadam radford * Register ourselves as PCI hotplug module
90300d49016bSadam radford */
90310d49016bSadam radford rval = pci_register_driver(&megasas_pci_driver);
90320d49016bSadam radford
90330d49016bSadam radford if (rval) {
90346774def6SMasanari Iida printk(KERN_DEBUG "megasas: PCI hotplug registration failed \n");
90350d49016bSadam radford goto err_pcidrv;
90360d49016bSadam radford }
90370d49016bSadam radford
9038d956a116SShivasharan S if ((event_log_level < MFI_EVT_CLASS_DEBUG) ||
9039d956a116SShivasharan S (event_log_level > MFI_EVT_CLASS_DEAD)) {
9040359603a3SColin Ian King pr_warn("megaraid_sas: provided event log level is out of range, setting it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n");
9041d956a116SShivasharan S event_log_level = MFI_EVT_CLASS_CRITICAL;
9042d956a116SShivasharan S }
9043d956a116SShivasharan S
90440d49016bSadam radford rval = driver_create_file(&megasas_pci_driver.driver,
90450d49016bSadam radford &driver_attr_version);
90460d49016bSadam radford if (rval)
90470d49016bSadam radford goto err_dcf_attr_ver;
90480d49016bSadam radford
90490d49016bSadam radford rval = driver_create_file(&megasas_pci_driver.driver,
905009fced19SSumit.Saxena@avagotech.com &driver_attr_release_date);
905109fced19SSumit.Saxena@avagotech.com if (rval)
905209fced19SSumit.Saxena@avagotech.com goto err_dcf_rel_date;
905309fced19SSumit.Saxena@avagotech.com
905409fced19SSumit.Saxena@avagotech.com rval = driver_create_file(&megasas_pci_driver.driver,
90550d49016bSadam radford &driver_attr_support_poll_for_event);
90560d49016bSadam radford if (rval)
90570d49016bSadam radford goto err_dcf_support_poll_for_event;
90580d49016bSadam radford
90590d49016bSadam radford rval = driver_create_file(&megasas_pci_driver.driver,
90600d49016bSadam radford &driver_attr_dbg_lvl);
90610d49016bSadam radford if (rval)
90620d49016bSadam radford goto err_dcf_dbg_lvl;
90630d49016bSadam radford rval = driver_create_file(&megasas_pci_driver.driver,
90640d49016bSadam radford &driver_attr_support_device_change);
90650d49016bSadam radford if (rval)
90660d49016bSadam radford goto err_dcf_support_device_change;
90670d49016bSadam radford
9068f870bcbeSShivasharan S rval = driver_create_file(&megasas_pci_driver.driver,
9069f870bcbeSShivasharan S &driver_attr_support_nvme_encapsulation);
9070f870bcbeSShivasharan S if (rval)
9071f870bcbeSShivasharan S goto err_dcf_support_nvme_encapsulation;
9072f870bcbeSShivasharan S
907358136856SChandrakanth Patil rval = driver_create_file(&megasas_pci_driver.driver,
907458136856SChandrakanth Patil &driver_attr_support_pci_lane_margining);
907558136856SChandrakanth Patil if (rval)
907658136856SChandrakanth Patil goto err_dcf_support_pci_lane_margining;
907758136856SChandrakanth Patil
90780d49016bSadam radford return rval;
90790d49016bSadam radford
908058136856SChandrakanth Patil err_dcf_support_pci_lane_margining:
908158136856SChandrakanth Patil driver_remove_file(&megasas_pci_driver.driver,
908258136856SChandrakanth Patil &driver_attr_support_nvme_encapsulation);
908358136856SChandrakanth Patil
9084f870bcbeSShivasharan S err_dcf_support_nvme_encapsulation:
9085f870bcbeSShivasharan S driver_remove_file(&megasas_pci_driver.driver,
9086f870bcbeSShivasharan S &driver_attr_support_device_change);
9087f870bcbeSShivasharan S
90880d49016bSadam radford err_dcf_support_device_change:
90890d49016bSadam radford driver_remove_file(&megasas_pci_driver.driver,
90900d49016bSadam radford &driver_attr_dbg_lvl);
90910d49016bSadam radford err_dcf_dbg_lvl:
90920d49016bSadam radford driver_remove_file(&megasas_pci_driver.driver,
90930d49016bSadam radford &driver_attr_support_poll_for_event);
90940d49016bSadam radford err_dcf_support_poll_for_event:
909509fced19SSumit.Saxena@avagotech.com driver_remove_file(&megasas_pci_driver.driver,
909609fced19SSumit.Saxena@avagotech.com &driver_attr_release_date);
909709fced19SSumit.Saxena@avagotech.com err_dcf_rel_date:
90980d49016bSadam radford driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
90990d49016bSadam radford err_dcf_attr_ver:
91000d49016bSadam radford pci_unregister_driver(&megasas_pci_driver);
91010d49016bSadam radford err_pcidrv:
9102ba53572bSShivasharan S megasas_exit_debugfs();
91030d49016bSadam radford unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
91040d49016bSadam radford return rval;
91050d49016bSadam radford }
91060d49016bSadam radford
91070d49016bSadam radford /**
91080d49016bSadam radford * megasas_exit - Driver unload entry point
91090d49016bSadam radford */
megasas_exit(void)91100d49016bSadam radford static void __exit megasas_exit(void)
91110d49016bSadam radford {
91120d49016bSadam radford driver_remove_file(&megasas_pci_driver.driver,
91130d49016bSadam radford &driver_attr_dbg_lvl);
91140d49016bSadam radford driver_remove_file(&megasas_pci_driver.driver,
91150d49016bSadam radford &driver_attr_support_poll_for_event);
91160d49016bSadam radford driver_remove_file(&megasas_pci_driver.driver,
91170d49016bSadam radford &driver_attr_support_device_change);
911809fced19SSumit.Saxena@avagotech.com driver_remove_file(&megasas_pci_driver.driver,
911909fced19SSumit.Saxena@avagotech.com &driver_attr_release_date);
91200d49016bSadam radford driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
9121f870bcbeSShivasharan S driver_remove_file(&megasas_pci_driver.driver,
9122f870bcbeSShivasharan S &driver_attr_support_nvme_encapsulation);
912358136856SChandrakanth Patil driver_remove_file(&megasas_pci_driver.driver,
912458136856SChandrakanth Patil &driver_attr_support_pci_lane_margining);
91250d49016bSadam radford
91260d49016bSadam radford pci_unregister_driver(&megasas_pci_driver);
9127ba53572bSShivasharan S megasas_exit_debugfs();
91280d49016bSadam radford unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
91290d49016bSadam radford }
91300d49016bSadam radford
91310d49016bSadam radford module_init(megasas_init);
91320d49016bSadam radford module_exit(megasas_exit);
9133