xref: /openbmc/linux/drivers/scsi/megaraid/megaraid_sas_base.c (revision ed4543328f7108e1047b83b96ca7f7208747d930)
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(&regs->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, &regs->outbound_intr_mask);
4820d49016bSadam radford 	/* Dummy readl to force pci flush */
4830d49016bSadam radford 	readl(&regs->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(&regs->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, &regs->outbound_intr_status);
5220d49016bSadam radford 
5230d49016bSadam radford 	/* Dummy readl to force pci flush */
5240d49016bSadam radford 	readl(&regs->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, &regs->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(&regs->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, &regs->outbound_intr_mask);
6640d49016bSadam radford 	/* Dummy readl to force pci flush */
6650d49016bSadam radford 	readl(&regs->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(&regs->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, &regs->outbound_doorbell_clear);
7040d49016bSadam radford 
7050d49016bSadam radford 	/* Dummy readl to force pci flush */
7060d49016bSadam radford 	readl(&regs->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(&regs->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, &regs->outbound_intr_mask);
7930d49016bSadam radford 	/* Dummy readl to force pci flush */
7940d49016bSadam radford 	readl(&regs->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(&regs->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, &regs->outbound_intr_status);
8410d49016bSadam radford 
8420d49016bSadam radford 	/*
8430d49016bSadam radford 	 * dummy read to flush PCI
8440d49016bSadam radford 	 */
8450d49016bSadam radford 	readl(&regs->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(&regs->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, &regs->outbound_intr_mask);
9410d49016bSadam radford 	/* Dummy readl to force pci flush */
9420d49016bSadam radford 	readl(&regs->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(&regs->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, &regs->outbound_doorbell_clear);
9840d49016bSadam radford 
9850d49016bSadam radford 	/* Dummy readl to force pci flush */
9860d49016bSadam radford 	readl(&regs->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 = &reg_set->seq_offset;
10248a232bb3SChristoph Hellwig 	u32 __iomem *hostdiag_offset = &reg_set->host_diag;
10250d49016bSadam radford 
1026ebf054b0Sadam radford 	if (instance->instancet == &megasas_instance_template_skinny) {
1027ebf054b0Sadam radford 		seq_offset = &reg_set->fusion_seq_offset;
1028ebf054b0Sadam radford 		hostdiag_offset = &reg_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(&reg[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(&reg[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