xref: /openbmc/linux/drivers/scsi/mpi3mr/mpi3mr_os.c (revision 9144f784f852f9a125cabe9927b986d909bfa439)
1824a1566SKashyap Desai // SPDX-License-Identifier: GPL-2.0-or-later
2824a1566SKashyap Desai /*
3824a1566SKashyap Desai  * Driver for Broadcom MPI3 Storage Controllers
4824a1566SKashyap Desai  *
5e74f2fbdSRanjan Kumar  * Copyright (C) 2017-2023 Broadcom Inc.
6824a1566SKashyap Desai  *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
7824a1566SKashyap Desai  *
8824a1566SKashyap Desai  */
9824a1566SKashyap Desai 
10824a1566SKashyap Desai #include "mpi3mr.h"
11d424303dSGuixin Liu #include <linux/idr.h>
12824a1566SKashyap Desai 
13824a1566SKashyap Desai /* global driver scop variables */
14824a1566SKashyap Desai LIST_HEAD(mrioc_list);
15824a1566SKashyap Desai DEFINE_SPINLOCK(mrioc_list_lock);
16d424303dSGuixin Liu static DEFINE_IDA(mrioc_ida);
17824a1566SKashyap Desai static int warn_non_secure_ctlr;
1843ca1100SSumit Saxena atomic64_t event_counter;
19824a1566SKashyap Desai 
20824a1566SKashyap Desai MODULE_AUTHOR(MPI3MR_DRIVER_AUTHOR);
21824a1566SKashyap Desai MODULE_DESCRIPTION(MPI3MR_DRIVER_DESC);
22824a1566SKashyap Desai MODULE_LICENSE(MPI3MR_DRIVER_LICENSE);
23824a1566SKashyap Desai MODULE_VERSION(MPI3MR_DRIVER_VERSION);
24824a1566SKashyap Desai 
25824a1566SKashyap Desai /* Module parameters*/
2674e1f30aSKashyap Desai int prot_mask = -1;
2774e1f30aSKashyap Desai module_param(prot_mask, int, 0);
2874e1f30aSKashyap Desai MODULE_PARM_DESC(prot_mask, "Host protection capabilities mask, def=0x07");
2974e1f30aSKashyap Desai 
306fe3a4abSYang Yingliang static int prot_guard_mask = 3;
3174e1f30aSKashyap Desai module_param(prot_guard_mask, int, 0);
3274e1f30aSKashyap Desai MODULE_PARM_DESC(prot_guard_mask, " Host protection guard mask, def=3");
336fe3a4abSYang Yingliang static int logging_level;
34824a1566SKashyap Desai module_param(logging_level, int, 0);
35824a1566SKashyap Desai MODULE_PARM_DESC(logging_level,
36824a1566SKashyap Desai 	" bits for enabling additional logging info (default=0)");
37d9adb81eSRanjan Kumar static int max_sgl_entries = MPI3MR_DEFAULT_SGL_ENTRIES;
38d9adb81eSRanjan Kumar module_param(max_sgl_entries, int, 0444);
39d9adb81eSRanjan Kumar MODULE_PARM_DESC(max_sgl_entries,
40d9adb81eSRanjan Kumar 	"Preferred max number of SG entries to be used for a single I/O\n"
41d9adb81eSRanjan Kumar 	"The actual value will be determined by the driver\n"
42d9adb81eSRanjan Kumar 	"(Minimum=256, Maximum=2048, default=256)");
43824a1566SKashyap Desai 
44023ab2a9SKashyap Desai /* Forward declarations*/
45c1af985dSSreekanth Reddy static void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
46c1af985dSSreekanth Reddy 	struct mpi3mr_drv_cmd *cmdparam, u32 event_ctx);
47c1af985dSSreekanth Reddy 
48cf1ce8b7SSreekanth Reddy #define MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION	(0xFFFF)
49cf1ce8b7SSreekanth Reddy 
502745ce0eSSreekanth Reddy #define MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH	(0xFFFE)
512745ce0eSSreekanth Reddy 
52023ab2a9SKashyap Desai /**
53023ab2a9SKashyap Desai  * mpi3mr_host_tag_for_scmd - Get host tag for a scmd
54023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
55023ab2a9SKashyap Desai  * @scmd: SCSI command reference
56023ab2a9SKashyap Desai  *
57023ab2a9SKashyap Desai  * Calculate the host tag based on block tag for a given scmd.
58023ab2a9SKashyap Desai  *
59023ab2a9SKashyap Desai  * Return: Valid host tag or MPI3MR_HOSTTAG_INVALID.
60023ab2a9SKashyap Desai  */
mpi3mr_host_tag_for_scmd(struct mpi3mr_ioc * mrioc,struct scsi_cmnd * scmd)61023ab2a9SKashyap Desai static u16 mpi3mr_host_tag_for_scmd(struct mpi3mr_ioc *mrioc,
62023ab2a9SKashyap Desai 	struct scsi_cmnd *scmd)
63023ab2a9SKashyap Desai {
64023ab2a9SKashyap Desai 	struct scmd_priv *priv = NULL;
65023ab2a9SKashyap Desai 	u32 unique_tag;
66023ab2a9SKashyap Desai 	u16 host_tag, hw_queue;
67023ab2a9SKashyap Desai 
6869868c3bSBart Van Assche 	unique_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
69023ab2a9SKashyap Desai 
70023ab2a9SKashyap Desai 	hw_queue = blk_mq_unique_tag_to_hwq(unique_tag);
71023ab2a9SKashyap Desai 	if (hw_queue >= mrioc->num_op_reply_q)
72023ab2a9SKashyap Desai 		return MPI3MR_HOSTTAG_INVALID;
73023ab2a9SKashyap Desai 	host_tag = blk_mq_unique_tag_to_tag(unique_tag);
74023ab2a9SKashyap Desai 
75023ab2a9SKashyap Desai 	if (WARN_ON(host_tag >= mrioc->max_host_ios))
76023ab2a9SKashyap Desai 		return MPI3MR_HOSTTAG_INVALID;
77023ab2a9SKashyap Desai 
78023ab2a9SKashyap Desai 	priv = scsi_cmd_priv(scmd);
79023ab2a9SKashyap Desai 	/*host_tag 0 is invalid hence incrementing by 1*/
80023ab2a9SKashyap Desai 	priv->host_tag = host_tag + 1;
81023ab2a9SKashyap Desai 	priv->scmd = scmd;
82023ab2a9SKashyap Desai 	priv->in_lld_scope = 1;
83023ab2a9SKashyap Desai 	priv->req_q_idx = hw_queue;
8474e1f30aSKashyap Desai 	priv->meta_chain_idx = -1;
85023ab2a9SKashyap Desai 	priv->chain_idx = -1;
8674e1f30aSKashyap Desai 	priv->meta_sg_valid = 0;
87023ab2a9SKashyap Desai 	return priv->host_tag;
88023ab2a9SKashyap Desai }
89023ab2a9SKashyap Desai 
90023ab2a9SKashyap Desai /**
91023ab2a9SKashyap Desai  * mpi3mr_scmd_from_host_tag - Get SCSI command from host tag
92023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
93023ab2a9SKashyap Desai  * @host_tag: Host tag
94023ab2a9SKashyap Desai  * @qidx: Operational queue index
95023ab2a9SKashyap Desai  *
96023ab2a9SKashyap Desai  * Identify the block tag from the host tag and queue index and
97023ab2a9SKashyap Desai  * retrieve associated scsi command using scsi_host_find_tag().
98023ab2a9SKashyap Desai  *
99023ab2a9SKashyap Desai  * Return: SCSI command reference or NULL.
100023ab2a9SKashyap Desai  */
mpi3mr_scmd_from_host_tag(struct mpi3mr_ioc * mrioc,u16 host_tag,u16 qidx)101023ab2a9SKashyap Desai static struct scsi_cmnd *mpi3mr_scmd_from_host_tag(
102023ab2a9SKashyap Desai 	struct mpi3mr_ioc *mrioc, u16 host_tag, u16 qidx)
103023ab2a9SKashyap Desai {
104023ab2a9SKashyap Desai 	struct scsi_cmnd *scmd = NULL;
105023ab2a9SKashyap Desai 	struct scmd_priv *priv = NULL;
106023ab2a9SKashyap Desai 	u32 unique_tag = host_tag - 1;
107023ab2a9SKashyap Desai 
108023ab2a9SKashyap Desai 	if (WARN_ON(host_tag > mrioc->max_host_ios))
109023ab2a9SKashyap Desai 		goto out;
110023ab2a9SKashyap Desai 
111023ab2a9SKashyap Desai 	unique_tag |= (qidx << BLK_MQ_UNIQUE_TAG_BITS);
112023ab2a9SKashyap Desai 
113023ab2a9SKashyap Desai 	scmd = scsi_host_find_tag(mrioc->shost, unique_tag);
114023ab2a9SKashyap Desai 	if (scmd) {
115023ab2a9SKashyap Desai 		priv = scsi_cmd_priv(scmd);
116023ab2a9SKashyap Desai 		if (!priv->in_lld_scope)
117023ab2a9SKashyap Desai 			scmd = NULL;
118023ab2a9SKashyap Desai 	}
119023ab2a9SKashyap Desai out:
120023ab2a9SKashyap Desai 	return scmd;
121023ab2a9SKashyap Desai }
122023ab2a9SKashyap Desai 
123023ab2a9SKashyap Desai /**
124023ab2a9SKashyap Desai  * mpi3mr_clear_scmd_priv - Cleanup SCSI command private date
125023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
126023ab2a9SKashyap Desai  * @scmd: SCSI command reference
127023ab2a9SKashyap Desai  *
128023ab2a9SKashyap Desai  * Invalidate the SCSI command private data to mark the command
129023ab2a9SKashyap Desai  * is not in LLD scope anymore.
130023ab2a9SKashyap Desai  *
131023ab2a9SKashyap Desai  * Return: Nothing.
132023ab2a9SKashyap Desai  */
mpi3mr_clear_scmd_priv(struct mpi3mr_ioc * mrioc,struct scsi_cmnd * scmd)133023ab2a9SKashyap Desai static void mpi3mr_clear_scmd_priv(struct mpi3mr_ioc *mrioc,
134023ab2a9SKashyap Desai 	struct scsi_cmnd *scmd)
135023ab2a9SKashyap Desai {
136023ab2a9SKashyap Desai 	struct scmd_priv *priv = NULL;
137023ab2a9SKashyap Desai 
138023ab2a9SKashyap Desai 	priv = scsi_cmd_priv(scmd);
139023ab2a9SKashyap Desai 
140023ab2a9SKashyap Desai 	if (WARN_ON(priv->in_lld_scope == 0))
141023ab2a9SKashyap Desai 		return;
142023ab2a9SKashyap Desai 	priv->host_tag = MPI3MR_HOSTTAG_INVALID;
143023ab2a9SKashyap Desai 	priv->req_q_idx = 0xFFFF;
144023ab2a9SKashyap Desai 	priv->scmd = NULL;
145023ab2a9SKashyap Desai 	priv->in_lld_scope = 0;
14674e1f30aSKashyap Desai 	priv->meta_sg_valid = 0;
147023ab2a9SKashyap Desai 	if (priv->chain_idx >= 0) {
148023ab2a9SKashyap Desai 		clear_bit(priv->chain_idx, mrioc->chain_bitmap);
149023ab2a9SKashyap Desai 		priv->chain_idx = -1;
150023ab2a9SKashyap Desai 	}
15174e1f30aSKashyap Desai 	if (priv->meta_chain_idx >= 0) {
15274e1f30aSKashyap Desai 		clear_bit(priv->meta_chain_idx, mrioc->chain_bitmap);
15374e1f30aSKashyap Desai 		priv->meta_chain_idx = -1;
15474e1f30aSKashyap Desai 	}
155023ab2a9SKashyap Desai }
156023ab2a9SKashyap Desai 
15713ef29eaSKashyap Desai static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_ioc *mrioc, u16 handle,
15813ef29eaSKashyap Desai 	struct mpi3mr_drv_cmd *cmdparam, u8 iou_rc);
15913ef29eaSKashyap Desai static void mpi3mr_fwevt_worker(struct work_struct *work);
16013ef29eaSKashyap Desai 
16113ef29eaSKashyap Desai /**
16213ef29eaSKashyap Desai  * mpi3mr_fwevt_free - firmware event memory dealloctor
16313ef29eaSKashyap Desai  * @r: k reference pointer of the firmware event
16413ef29eaSKashyap Desai  *
16513ef29eaSKashyap Desai  * Free firmware event memory when no reference.
16613ef29eaSKashyap Desai  */
mpi3mr_fwevt_free(struct kref * r)16713ef29eaSKashyap Desai static void mpi3mr_fwevt_free(struct kref *r)
16813ef29eaSKashyap Desai {
16913ef29eaSKashyap Desai 	kfree(container_of(r, struct mpi3mr_fwevt, ref_count));
17013ef29eaSKashyap Desai }
17113ef29eaSKashyap Desai 
17213ef29eaSKashyap Desai /**
17313ef29eaSKashyap Desai  * mpi3mr_fwevt_get - k reference incrementor
17413ef29eaSKashyap Desai  * @fwevt: Firmware event reference
17513ef29eaSKashyap Desai  *
17613ef29eaSKashyap Desai  * Increment firmware event reference count.
17713ef29eaSKashyap Desai  */
mpi3mr_fwevt_get(struct mpi3mr_fwevt * fwevt)17813ef29eaSKashyap Desai static void mpi3mr_fwevt_get(struct mpi3mr_fwevt *fwevt)
17913ef29eaSKashyap Desai {
18013ef29eaSKashyap Desai 	kref_get(&fwevt->ref_count);
18113ef29eaSKashyap Desai }
18213ef29eaSKashyap Desai 
18313ef29eaSKashyap Desai /**
18413ef29eaSKashyap Desai  * mpi3mr_fwevt_put - k reference decrementor
18513ef29eaSKashyap Desai  * @fwevt: Firmware event reference
18613ef29eaSKashyap Desai  *
18713ef29eaSKashyap Desai  * decrement firmware event reference count.
18813ef29eaSKashyap Desai  */
mpi3mr_fwevt_put(struct mpi3mr_fwevt * fwevt)18913ef29eaSKashyap Desai static void mpi3mr_fwevt_put(struct mpi3mr_fwevt *fwevt)
19013ef29eaSKashyap Desai {
19113ef29eaSKashyap Desai 	kref_put(&fwevt->ref_count, mpi3mr_fwevt_free);
19213ef29eaSKashyap Desai }
19313ef29eaSKashyap Desai 
19413ef29eaSKashyap Desai /**
19513ef29eaSKashyap Desai  * mpi3mr_alloc_fwevt - Allocate firmware event
19613ef29eaSKashyap Desai  * @len: length of firmware event data to allocate
19713ef29eaSKashyap Desai  *
19813ef29eaSKashyap Desai  * Allocate firmware event with required length and initialize
19913ef29eaSKashyap Desai  * the reference counter.
20013ef29eaSKashyap Desai  *
20113ef29eaSKashyap Desai  * Return: firmware event reference.
20213ef29eaSKashyap Desai  */
mpi3mr_alloc_fwevt(int len)20313ef29eaSKashyap Desai static struct mpi3mr_fwevt *mpi3mr_alloc_fwevt(int len)
20413ef29eaSKashyap Desai {
20513ef29eaSKashyap Desai 	struct mpi3mr_fwevt *fwevt;
20613ef29eaSKashyap Desai 
20713ef29eaSKashyap Desai 	fwevt = kzalloc(sizeof(*fwevt) + len, GFP_ATOMIC);
20813ef29eaSKashyap Desai 	if (!fwevt)
20913ef29eaSKashyap Desai 		return NULL;
21013ef29eaSKashyap Desai 
21113ef29eaSKashyap Desai 	kref_init(&fwevt->ref_count);
21213ef29eaSKashyap Desai 	return fwevt;
21313ef29eaSKashyap Desai }
21413ef29eaSKashyap Desai 
21513ef29eaSKashyap Desai /**
21613ef29eaSKashyap Desai  * mpi3mr_fwevt_add_to_list - Add firmware event to the list
21713ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
21813ef29eaSKashyap Desai  * @fwevt: Firmware event reference
21913ef29eaSKashyap Desai  *
22013ef29eaSKashyap Desai  * Add the given firmware event to the firmware event list.
22113ef29eaSKashyap Desai  *
22213ef29eaSKashyap Desai  * Return: Nothing.
22313ef29eaSKashyap Desai  */
mpi3mr_fwevt_add_to_list(struct mpi3mr_ioc * mrioc,struct mpi3mr_fwevt * fwevt)22413ef29eaSKashyap Desai static void mpi3mr_fwevt_add_to_list(struct mpi3mr_ioc *mrioc,
22513ef29eaSKashyap Desai 	struct mpi3mr_fwevt *fwevt)
22613ef29eaSKashyap Desai {
22713ef29eaSKashyap Desai 	unsigned long flags;
22813ef29eaSKashyap Desai 
22913ef29eaSKashyap Desai 	if (!mrioc->fwevt_worker_thread)
23013ef29eaSKashyap Desai 		return;
23113ef29eaSKashyap Desai 
23213ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->fwevt_lock, flags);
23313ef29eaSKashyap Desai 	/* get fwevt reference count while adding it to fwevt_list */
23413ef29eaSKashyap Desai 	mpi3mr_fwevt_get(fwevt);
23513ef29eaSKashyap Desai 	INIT_LIST_HEAD(&fwevt->list);
23613ef29eaSKashyap Desai 	list_add_tail(&fwevt->list, &mrioc->fwevt_list);
23713ef29eaSKashyap Desai 	INIT_WORK(&fwevt->work, mpi3mr_fwevt_worker);
23813ef29eaSKashyap Desai 	/* get fwevt reference count while enqueueing it to worker queue */
23913ef29eaSKashyap Desai 	mpi3mr_fwevt_get(fwevt);
24013ef29eaSKashyap Desai 	queue_work(mrioc->fwevt_worker_thread, &fwevt->work);
24113ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
24213ef29eaSKashyap Desai }
24313ef29eaSKashyap Desai 
24413ef29eaSKashyap Desai /**
24513ef29eaSKashyap Desai  * mpi3mr_fwevt_del_from_list - Delete firmware event from list
24613ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
24713ef29eaSKashyap Desai  * @fwevt: Firmware event reference
24813ef29eaSKashyap Desai  *
24913ef29eaSKashyap Desai  * Delete the given firmware event from the firmware event list.
25013ef29eaSKashyap Desai  *
25113ef29eaSKashyap Desai  * Return: Nothing.
25213ef29eaSKashyap Desai  */
mpi3mr_fwevt_del_from_list(struct mpi3mr_ioc * mrioc,struct mpi3mr_fwevt * fwevt)25313ef29eaSKashyap Desai static void mpi3mr_fwevt_del_from_list(struct mpi3mr_ioc *mrioc,
25413ef29eaSKashyap Desai 	struct mpi3mr_fwevt *fwevt)
25513ef29eaSKashyap Desai {
25613ef29eaSKashyap Desai 	unsigned long flags;
25713ef29eaSKashyap Desai 
25813ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->fwevt_lock, flags);
25913ef29eaSKashyap Desai 	if (!list_empty(&fwevt->list)) {
26013ef29eaSKashyap Desai 		list_del_init(&fwevt->list);
26113ef29eaSKashyap Desai 		/*
26213ef29eaSKashyap Desai 		 * Put fwevt reference count after
26313ef29eaSKashyap Desai 		 * removing it from fwevt_list
26413ef29eaSKashyap Desai 		 */
26513ef29eaSKashyap Desai 		mpi3mr_fwevt_put(fwevt);
26613ef29eaSKashyap Desai 	}
26713ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
26813ef29eaSKashyap Desai }
26913ef29eaSKashyap Desai 
27013ef29eaSKashyap Desai /**
27113ef29eaSKashyap Desai  * mpi3mr_dequeue_fwevt - Dequeue firmware event from the list
27213ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
27313ef29eaSKashyap Desai  *
27413ef29eaSKashyap Desai  * Dequeue a firmware event from the firmware event list.
27513ef29eaSKashyap Desai  *
27613ef29eaSKashyap Desai  * Return: firmware event.
27713ef29eaSKashyap Desai  */
mpi3mr_dequeue_fwevt(struct mpi3mr_ioc * mrioc)27813ef29eaSKashyap Desai static struct mpi3mr_fwevt *mpi3mr_dequeue_fwevt(
27913ef29eaSKashyap Desai 	struct mpi3mr_ioc *mrioc)
28013ef29eaSKashyap Desai {
28113ef29eaSKashyap Desai 	unsigned long flags;
28213ef29eaSKashyap Desai 	struct mpi3mr_fwevt *fwevt = NULL;
28313ef29eaSKashyap Desai 
28413ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->fwevt_lock, flags);
28513ef29eaSKashyap Desai 	if (!list_empty(&mrioc->fwevt_list)) {
28613ef29eaSKashyap Desai 		fwevt = list_first_entry(&mrioc->fwevt_list,
28713ef29eaSKashyap Desai 		    struct mpi3mr_fwevt, list);
28813ef29eaSKashyap Desai 		list_del_init(&fwevt->list);
28913ef29eaSKashyap Desai 		/*
29013ef29eaSKashyap Desai 		 * Put fwevt reference count after
29113ef29eaSKashyap Desai 		 * removing it from fwevt_list
29213ef29eaSKashyap Desai 		 */
29313ef29eaSKashyap Desai 		mpi3mr_fwevt_put(fwevt);
29413ef29eaSKashyap Desai 	}
29513ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
29613ef29eaSKashyap Desai 
29713ef29eaSKashyap Desai 	return fwevt;
29813ef29eaSKashyap Desai }
29913ef29eaSKashyap Desai 
30013ef29eaSKashyap Desai /**
301580e6742SSreekanth Reddy  * mpi3mr_cancel_work - cancel firmware event
302580e6742SSreekanth Reddy  * @fwevt: fwevt object which needs to be canceled
30313ef29eaSKashyap Desai  *
30413ef29eaSKashyap Desai  * Return: Nothing.
30513ef29eaSKashyap Desai  */
mpi3mr_cancel_work(struct mpi3mr_fwevt * fwevt)306580e6742SSreekanth Reddy static void mpi3mr_cancel_work(struct mpi3mr_fwevt *fwevt)
30713ef29eaSKashyap Desai {
30813ef29eaSKashyap Desai 	/*
30913ef29eaSKashyap Desai 	 * Wait on the fwevt to complete. If this returns 1, then
310580e6742SSreekanth Reddy 	 * the event was never executed.
31113ef29eaSKashyap Desai 	 *
31213ef29eaSKashyap Desai 	 * If it did execute, we wait for it to finish, and the put will
31313ef29eaSKashyap Desai 	 * happen from mpi3mr_process_fwevt()
31413ef29eaSKashyap Desai 	 */
31513ef29eaSKashyap Desai 	if (cancel_work_sync(&fwevt->work)) {
31613ef29eaSKashyap Desai 		/*
31713ef29eaSKashyap Desai 		 * Put fwevt reference count after
31813ef29eaSKashyap Desai 		 * dequeuing it from worker queue
31913ef29eaSKashyap Desai 		 */
32013ef29eaSKashyap Desai 		mpi3mr_fwevt_put(fwevt);
32113ef29eaSKashyap Desai 		/*
32213ef29eaSKashyap Desai 		 * Put fwevt reference count to neutralize
32313ef29eaSKashyap Desai 		 * kref_init increment
32413ef29eaSKashyap Desai 		 */
32513ef29eaSKashyap Desai 		mpi3mr_fwevt_put(fwevt);
32613ef29eaSKashyap Desai 	}
32713ef29eaSKashyap Desai }
328580e6742SSreekanth Reddy 
329580e6742SSreekanth Reddy /**
330580e6742SSreekanth Reddy  * mpi3mr_cleanup_fwevt_list - Cleanup firmware event list
331580e6742SSreekanth Reddy  * @mrioc: Adapter instance reference
332580e6742SSreekanth Reddy  *
333580e6742SSreekanth Reddy  * Flush all pending firmware events from the firmware event
334580e6742SSreekanth Reddy  * list.
335580e6742SSreekanth Reddy  *
336580e6742SSreekanth Reddy  * Return: Nothing.
337580e6742SSreekanth Reddy  */
mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc * mrioc)338580e6742SSreekanth Reddy void mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc)
339580e6742SSreekanth Reddy {
340580e6742SSreekanth Reddy 	struct mpi3mr_fwevt *fwevt = NULL;
341580e6742SSreekanth Reddy 
342580e6742SSreekanth Reddy 	if ((list_empty(&mrioc->fwevt_list) && !mrioc->current_event) ||
343580e6742SSreekanth Reddy 	    !mrioc->fwevt_worker_thread)
344580e6742SSreekanth Reddy 		return;
345580e6742SSreekanth Reddy 
346580e6742SSreekanth Reddy 	while ((fwevt = mpi3mr_dequeue_fwevt(mrioc)))
347580e6742SSreekanth Reddy 		mpi3mr_cancel_work(fwevt);
348580e6742SSreekanth Reddy 
349580e6742SSreekanth Reddy 	if (mrioc->current_event) {
350580e6742SSreekanth Reddy 		fwevt = mrioc->current_event;
351580e6742SSreekanth Reddy 		/*
352580e6742SSreekanth Reddy 		 * Don't call cancel_work_sync() API for the
353580e6742SSreekanth Reddy 		 * fwevt work if the controller reset is
354580e6742SSreekanth Reddy 		 * get called as part of processing the
355580e6742SSreekanth Reddy 		 * same fwevt work (or) when worker thread is
356580e6742SSreekanth Reddy 		 * waiting for device add/remove APIs to complete.
357580e6742SSreekanth Reddy 		 * Otherwise we will see deadlock.
358580e6742SSreekanth Reddy 		 */
359580e6742SSreekanth Reddy 		if (current_work() == &fwevt->work || fwevt->pending_at_sml) {
360580e6742SSreekanth Reddy 			fwevt->discard = 1;
361580e6742SSreekanth Reddy 			return;
362580e6742SSreekanth Reddy 		}
363580e6742SSreekanth Reddy 
364580e6742SSreekanth Reddy 		mpi3mr_cancel_work(fwevt);
365580e6742SSreekanth Reddy 	}
36613ef29eaSKashyap Desai }
36713ef29eaSKashyap Desai 
36813ef29eaSKashyap Desai /**
369cf1ce8b7SSreekanth Reddy  * mpi3mr_queue_qd_reduction_event - Queue TG QD reduction event
370cf1ce8b7SSreekanth Reddy  * @mrioc: Adapter instance reference
371cf1ce8b7SSreekanth Reddy  * @tg: Throttle group information pointer
372cf1ce8b7SSreekanth Reddy  *
373cf1ce8b7SSreekanth Reddy  * Accessor to queue on synthetically generated driver event to
374cf1ce8b7SSreekanth Reddy  * the event worker thread, the driver event will be used to
375cf1ce8b7SSreekanth Reddy  * reduce the QD of all VDs in the TG from the worker thread.
376cf1ce8b7SSreekanth Reddy  *
377cf1ce8b7SSreekanth Reddy  * Return: None.
378cf1ce8b7SSreekanth Reddy  */
mpi3mr_queue_qd_reduction_event(struct mpi3mr_ioc * mrioc,struct mpi3mr_throttle_group_info * tg)379cf1ce8b7SSreekanth Reddy static void mpi3mr_queue_qd_reduction_event(struct mpi3mr_ioc *mrioc,
380cf1ce8b7SSreekanth Reddy 	struct mpi3mr_throttle_group_info *tg)
381cf1ce8b7SSreekanth Reddy {
382cf1ce8b7SSreekanth Reddy 	struct mpi3mr_fwevt *fwevt;
383cf1ce8b7SSreekanth Reddy 	u16 sz = sizeof(struct mpi3mr_throttle_group_info *);
384cf1ce8b7SSreekanth Reddy 
385cf1ce8b7SSreekanth Reddy 	/*
386cf1ce8b7SSreekanth Reddy 	 * If the QD reduction event is already queued due to throttle and if
387cf1ce8b7SSreekanth Reddy 	 * the QD is not restored through device info change event
388cf1ce8b7SSreekanth Reddy 	 * then dont queue further reduction events
389cf1ce8b7SSreekanth Reddy 	 */
390cf1ce8b7SSreekanth Reddy 	if (tg->fw_qd != tg->modified_qd)
391cf1ce8b7SSreekanth Reddy 		return;
392cf1ce8b7SSreekanth Reddy 
393cf1ce8b7SSreekanth Reddy 	fwevt = mpi3mr_alloc_fwevt(sz);
394cf1ce8b7SSreekanth Reddy 	if (!fwevt) {
395cf1ce8b7SSreekanth Reddy 		ioc_warn(mrioc, "failed to queue TG QD reduction event\n");
396cf1ce8b7SSreekanth Reddy 		return;
397cf1ce8b7SSreekanth Reddy 	}
398cf1ce8b7SSreekanth Reddy 	*(struct mpi3mr_throttle_group_info **)fwevt->event_data = tg;
399cf1ce8b7SSreekanth Reddy 	fwevt->mrioc = mrioc;
400cf1ce8b7SSreekanth Reddy 	fwevt->event_id = MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION;
401cf1ce8b7SSreekanth Reddy 	fwevt->send_ack = 0;
402cf1ce8b7SSreekanth Reddy 	fwevt->process_evt = 1;
403cf1ce8b7SSreekanth Reddy 	fwevt->evt_ctx = 0;
404cf1ce8b7SSreekanth Reddy 	fwevt->event_data_size = sz;
405cf1ce8b7SSreekanth Reddy 	tg->modified_qd = max_t(u16, (tg->fw_qd * tg->qd_reduction) / 10, 8);
406cf1ce8b7SSreekanth Reddy 
407cf1ce8b7SSreekanth Reddy 	dprint_event_bh(mrioc, "qd reduction event queued for tg_id(%d)\n",
408cf1ce8b7SSreekanth Reddy 	    tg->id);
409cf1ce8b7SSreekanth Reddy 	mpi3mr_fwevt_add_to_list(mrioc, fwevt);
410cf1ce8b7SSreekanth Reddy }
411cf1ce8b7SSreekanth Reddy 
412cf1ce8b7SSreekanth Reddy /**
413fb9b0457SKashyap Desai  * mpi3mr_invalidate_devhandles -Invalidate device handles
414fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
415fb9b0457SKashyap Desai  *
416fb9b0457SKashyap Desai  * Invalidate the device handles in the target device structures
417fb9b0457SKashyap Desai  * . Called post reset prior to reinitializing the controller.
418fb9b0457SKashyap Desai  *
419fb9b0457SKashyap Desai  * Return: Nothing.
420fb9b0457SKashyap Desai  */
mpi3mr_invalidate_devhandles(struct mpi3mr_ioc * mrioc)421fb9b0457SKashyap Desai void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc)
422fb9b0457SKashyap Desai {
423fb9b0457SKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev;
424fb9b0457SKashyap Desai 	struct mpi3mr_stgt_priv_data *tgt_priv;
425fb9b0457SKashyap Desai 
426fb9b0457SKashyap Desai 	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
427fb9b0457SKashyap Desai 		tgtdev->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
428fb9b0457SKashyap Desai 		if (tgtdev->starget && tgtdev->starget->hostdata) {
429fb9b0457SKashyap Desai 			tgt_priv = tgtdev->starget->hostdata;
430fb9b0457SKashyap Desai 			tgt_priv->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
431f10af057SSreekanth Reddy 			tgt_priv->io_throttle_enabled = 0;
432f10af057SSreekanth Reddy 			tgt_priv->io_divert = 0;
433f10af057SSreekanth Reddy 			tgt_priv->throttle_group = NULL;
434e7a8648eSRanjan Kumar 			tgt_priv->wslen = 0;
4357f90bc70SSreekanth Reddy 			if (tgtdev->host_exposed)
4367f90bc70SSreekanth Reddy 				atomic_set(&tgt_priv->block_io, 1);
437fb9b0457SKashyap Desai 		}
438fb9b0457SKashyap Desai 	}
439fb9b0457SKashyap Desai }
440fb9b0457SKashyap Desai 
441fb9b0457SKashyap Desai /**
44271e80106SKashyap Desai  * mpi3mr_print_scmd - print individual SCSI command
44371e80106SKashyap Desai  * @rq: Block request
44471e80106SKashyap Desai  * @data: Adapter instance reference
44571e80106SKashyap Desai  *
44671e80106SKashyap Desai  * Print the SCSI command details if it is in LLD scope.
44771e80106SKashyap Desai  *
44871e80106SKashyap Desai  * Return: true always.
44971e80106SKashyap Desai  */
mpi3mr_print_scmd(struct request * rq,void * data)4502dd6532eSJohn Garry static bool mpi3mr_print_scmd(struct request *rq, void *data)
45171e80106SKashyap Desai {
45271e80106SKashyap Desai 	struct mpi3mr_ioc *mrioc = (struct mpi3mr_ioc *)data;
45371e80106SKashyap Desai 	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
45471e80106SKashyap Desai 	struct scmd_priv *priv = NULL;
45571e80106SKashyap Desai 
45671e80106SKashyap Desai 	if (scmd) {
45771e80106SKashyap Desai 		priv = scsi_cmd_priv(scmd);
45871e80106SKashyap Desai 		if (!priv->in_lld_scope)
45971e80106SKashyap Desai 			goto out;
46071e80106SKashyap Desai 
46171e80106SKashyap Desai 		ioc_info(mrioc, "%s :Host Tag = %d, qid = %d\n",
46271e80106SKashyap Desai 		    __func__, priv->host_tag, priv->req_q_idx + 1);
46371e80106SKashyap Desai 		scsi_print_command(scmd);
46471e80106SKashyap Desai 	}
46571e80106SKashyap Desai 
46671e80106SKashyap Desai out:
46771e80106SKashyap Desai 	return(true);
46871e80106SKashyap Desai }
46971e80106SKashyap Desai 
47071e80106SKashyap Desai /**
471fb9b0457SKashyap Desai  * mpi3mr_flush_scmd - Flush individual SCSI command
472fb9b0457SKashyap Desai  * @rq: Block request
473fb9b0457SKashyap Desai  * @data: Adapter instance reference
474fb9b0457SKashyap Desai  *
475fb9b0457SKashyap Desai  * Return the SCSI command to the upper layers if it is in LLD
476fb9b0457SKashyap Desai  * scope.
477fb9b0457SKashyap Desai  *
478fb9b0457SKashyap Desai  * Return: true always.
479fb9b0457SKashyap Desai  */
480fb9b0457SKashyap Desai 
mpi3mr_flush_scmd(struct request * rq,void * data)4812dd6532eSJohn Garry static bool mpi3mr_flush_scmd(struct request *rq, void *data)
482fb9b0457SKashyap Desai {
483fb9b0457SKashyap Desai 	struct mpi3mr_ioc *mrioc = (struct mpi3mr_ioc *)data;
484fb9b0457SKashyap Desai 	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
485fb9b0457SKashyap Desai 	struct scmd_priv *priv = NULL;
486fb9b0457SKashyap Desai 
487fb9b0457SKashyap Desai 	if (scmd) {
488fb9b0457SKashyap Desai 		priv = scsi_cmd_priv(scmd);
489fb9b0457SKashyap Desai 		if (!priv->in_lld_scope)
490fb9b0457SKashyap Desai 			goto out;
491fb9b0457SKashyap Desai 
49274e1f30aSKashyap Desai 		if (priv->meta_sg_valid)
49374e1f30aSKashyap Desai 			dma_unmap_sg(&mrioc->pdev->dev, scsi_prot_sglist(scmd),
49474e1f30aSKashyap Desai 			    scsi_prot_sg_count(scmd), scmd->sc_data_direction);
495fb9b0457SKashyap Desai 		mpi3mr_clear_scmd_priv(mrioc, scmd);
496fb9b0457SKashyap Desai 		scsi_dma_unmap(scmd);
497fb9b0457SKashyap Desai 		scmd->result = DID_RESET << 16;
498fb9b0457SKashyap Desai 		scsi_print_command(scmd);
4991a30fd18SBart Van Assche 		scsi_done(scmd);
500fb9b0457SKashyap Desai 		mrioc->flush_io_count++;
501fb9b0457SKashyap Desai 	}
502fb9b0457SKashyap Desai 
503fb9b0457SKashyap Desai out:
504fb9b0457SKashyap Desai 	return(true);
505fb9b0457SKashyap Desai }
506fb9b0457SKashyap Desai 
507fb9b0457SKashyap Desai /**
508a91603a5SSreekanth Reddy  * mpi3mr_count_dev_pending - Count commands pending for a lun
509a91603a5SSreekanth Reddy  * @rq: Block request
510a91603a5SSreekanth Reddy  * @data: SCSI device reference
511a91603a5SSreekanth Reddy  *
512a91603a5SSreekanth Reddy  * This is an iterator function called for each SCSI command in
513a91603a5SSreekanth Reddy  * a host and if the command is pending in the LLD for the
514a91603a5SSreekanth Reddy  * specific device(lun) then device specific pending I/O counter
515a91603a5SSreekanth Reddy  * is updated in the device structure.
516a91603a5SSreekanth Reddy  *
517a91603a5SSreekanth Reddy  * Return: true always.
518a91603a5SSreekanth Reddy  */
519a91603a5SSreekanth Reddy 
mpi3mr_count_dev_pending(struct request * rq,void * data)5202dd6532eSJohn Garry static bool mpi3mr_count_dev_pending(struct request *rq, void *data)
521a91603a5SSreekanth Reddy {
522a91603a5SSreekanth Reddy 	struct scsi_device *sdev = (struct scsi_device *)data;
523a91603a5SSreekanth Reddy 	struct mpi3mr_sdev_priv_data *sdev_priv_data = sdev->hostdata;
524a91603a5SSreekanth Reddy 	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
525a91603a5SSreekanth Reddy 	struct scmd_priv *priv;
526a91603a5SSreekanth Reddy 
527a91603a5SSreekanth Reddy 	if (scmd) {
528a91603a5SSreekanth Reddy 		priv = scsi_cmd_priv(scmd);
529a91603a5SSreekanth Reddy 		if (!priv->in_lld_scope)
530a91603a5SSreekanth Reddy 			goto out;
531a91603a5SSreekanth Reddy 		if (scmd->device == sdev)
532a91603a5SSreekanth Reddy 			sdev_priv_data->pend_count++;
533a91603a5SSreekanth Reddy 	}
534a91603a5SSreekanth Reddy 
535a91603a5SSreekanth Reddy out:
536a91603a5SSreekanth Reddy 	return true;
537a91603a5SSreekanth Reddy }
538a91603a5SSreekanth Reddy 
539a91603a5SSreekanth Reddy /**
540a91603a5SSreekanth Reddy  * mpi3mr_count_tgt_pending - Count commands pending for target
541a91603a5SSreekanth Reddy  * @rq: Block request
542a91603a5SSreekanth Reddy  * @data: SCSI target reference
543a91603a5SSreekanth Reddy  *
544a91603a5SSreekanth Reddy  * This is an iterator function called for each SCSI command in
545a91603a5SSreekanth Reddy  * a host and if the command is pending in the LLD for the
546a91603a5SSreekanth Reddy  * specific target then target specific pending I/O counter is
547a91603a5SSreekanth Reddy  * updated in the target structure.
548a91603a5SSreekanth Reddy  *
549a91603a5SSreekanth Reddy  * Return: true always.
550a91603a5SSreekanth Reddy  */
551a91603a5SSreekanth Reddy 
mpi3mr_count_tgt_pending(struct request * rq,void * data)5522dd6532eSJohn Garry static bool mpi3mr_count_tgt_pending(struct request *rq, void *data)
553a91603a5SSreekanth Reddy {
554a91603a5SSreekanth Reddy 	struct scsi_target *starget = (struct scsi_target *)data;
555a91603a5SSreekanth Reddy 	struct mpi3mr_stgt_priv_data *stgt_priv_data = starget->hostdata;
556a91603a5SSreekanth Reddy 	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
557a91603a5SSreekanth Reddy 	struct scmd_priv *priv;
558a91603a5SSreekanth Reddy 
559a91603a5SSreekanth Reddy 	if (scmd) {
560a91603a5SSreekanth Reddy 		priv = scsi_cmd_priv(scmd);
561a91603a5SSreekanth Reddy 		if (!priv->in_lld_scope)
562a91603a5SSreekanth Reddy 			goto out;
563a91603a5SSreekanth Reddy 		if (scmd->device && (scsi_target(scmd->device) == starget))
564a91603a5SSreekanth Reddy 			stgt_priv_data->pend_count++;
565a91603a5SSreekanth Reddy 	}
566a91603a5SSreekanth Reddy 
567a91603a5SSreekanth Reddy out:
568a91603a5SSreekanth Reddy 	return true;
569a91603a5SSreekanth Reddy }
570a91603a5SSreekanth Reddy 
571a91603a5SSreekanth Reddy /**
572fb9b0457SKashyap Desai  * mpi3mr_flush_host_io -  Flush host I/Os
573fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
574fb9b0457SKashyap Desai  *
575fb9b0457SKashyap Desai  * Flush all of the pending I/Os by calling
576fb9b0457SKashyap Desai  * blk_mq_tagset_busy_iter() for each possible tag. This is
577fb9b0457SKashyap Desai  * executed post controller reset
578fb9b0457SKashyap Desai  *
579fb9b0457SKashyap Desai  * Return: Nothing.
580fb9b0457SKashyap Desai  */
mpi3mr_flush_host_io(struct mpi3mr_ioc * mrioc)581fb9b0457SKashyap Desai void mpi3mr_flush_host_io(struct mpi3mr_ioc *mrioc)
582fb9b0457SKashyap Desai {
583fb9b0457SKashyap Desai 	struct Scsi_Host *shost = mrioc->shost;
584fb9b0457SKashyap Desai 
585fb9b0457SKashyap Desai 	mrioc->flush_io_count = 0;
586fb9b0457SKashyap Desai 	ioc_info(mrioc, "%s :Flushing Host I/O cmds post reset\n", __func__);
587fb9b0457SKashyap Desai 	blk_mq_tagset_busy_iter(&shost->tag_set,
588fb9b0457SKashyap Desai 	    mpi3mr_flush_scmd, (void *)mrioc);
589fb9b0457SKashyap Desai 	ioc_info(mrioc, "%s :Flushed %d Host I/O cmds\n", __func__,
590fb9b0457SKashyap Desai 	    mrioc->flush_io_count);
591fb9b0457SKashyap Desai }
592fb9b0457SKashyap Desai 
593fb9b0457SKashyap Desai /**
594f2a79d20SSreekanth Reddy  * mpi3mr_flush_cmds_for_unrecovered_controller - Flush all pending cmds
595f2a79d20SSreekanth Reddy  * @mrioc: Adapter instance reference
596f2a79d20SSreekanth Reddy  *
597f2a79d20SSreekanth Reddy  * This function waits for currently running IO poll threads to
598f2a79d20SSreekanth Reddy  * exit and then flushes all host I/Os and any internal pending
599f2a79d20SSreekanth Reddy  * cmds. This is executed after controller is marked as
600f2a79d20SSreekanth Reddy  * unrecoverable.
601f2a79d20SSreekanth Reddy  *
602f2a79d20SSreekanth Reddy  * Return: Nothing.
603f2a79d20SSreekanth Reddy  */
mpi3mr_flush_cmds_for_unrecovered_controller(struct mpi3mr_ioc * mrioc)604f2a79d20SSreekanth Reddy void mpi3mr_flush_cmds_for_unrecovered_controller(struct mpi3mr_ioc *mrioc)
605f2a79d20SSreekanth Reddy {
606f2a79d20SSreekanth Reddy 	struct Scsi_Host *shost = mrioc->shost;
607f2a79d20SSreekanth Reddy 	int i;
608f2a79d20SSreekanth Reddy 
609f2a79d20SSreekanth Reddy 	if (!mrioc->unrecoverable)
610f2a79d20SSreekanth Reddy 		return;
611f2a79d20SSreekanth Reddy 
612f2a79d20SSreekanth Reddy 	if (mrioc->op_reply_qinfo) {
613f2a79d20SSreekanth Reddy 		for (i = 0; i < mrioc->num_queues; i++) {
614f2a79d20SSreekanth Reddy 			while (atomic_read(&mrioc->op_reply_qinfo[i].in_use))
615f2a79d20SSreekanth Reddy 				udelay(500);
616f2a79d20SSreekanth Reddy 			atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0);
617f2a79d20SSreekanth Reddy 		}
618f2a79d20SSreekanth Reddy 	}
619f2a79d20SSreekanth Reddy 	mrioc->flush_io_count = 0;
620f2a79d20SSreekanth Reddy 	blk_mq_tagset_busy_iter(&shost->tag_set,
621f2a79d20SSreekanth Reddy 	    mpi3mr_flush_scmd, (void *)mrioc);
622f2a79d20SSreekanth Reddy 	mpi3mr_flush_delayed_cmd_lists(mrioc);
623f2a79d20SSreekanth Reddy 	mpi3mr_flush_drv_cmds(mrioc);
624f2a79d20SSreekanth Reddy }
625f2a79d20SSreekanth Reddy 
626f2a79d20SSreekanth Reddy /**
62713ef29eaSKashyap Desai  * mpi3mr_alloc_tgtdev - target device allocator
62813ef29eaSKashyap Desai  *
62913ef29eaSKashyap Desai  * Allocate target device instance and initialize the reference
63013ef29eaSKashyap Desai  * count
63113ef29eaSKashyap Desai  *
63213ef29eaSKashyap Desai  * Return: target device instance.
63313ef29eaSKashyap Desai  */
mpi3mr_alloc_tgtdev(void)63413ef29eaSKashyap Desai static struct mpi3mr_tgt_dev *mpi3mr_alloc_tgtdev(void)
63513ef29eaSKashyap Desai {
63613ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev;
63713ef29eaSKashyap Desai 
63813ef29eaSKashyap Desai 	tgtdev = kzalloc(sizeof(*tgtdev), GFP_ATOMIC);
63913ef29eaSKashyap Desai 	if (!tgtdev)
64013ef29eaSKashyap Desai 		return NULL;
64113ef29eaSKashyap Desai 	kref_init(&tgtdev->ref_count);
64213ef29eaSKashyap Desai 	return tgtdev;
64313ef29eaSKashyap Desai }
64413ef29eaSKashyap Desai 
64513ef29eaSKashyap Desai /**
64613ef29eaSKashyap Desai  * mpi3mr_tgtdev_add_to_list -Add tgtdevice to the list
64713ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
64813ef29eaSKashyap Desai  * @tgtdev: Target device
64913ef29eaSKashyap Desai  *
65013ef29eaSKashyap Desai  * Add the target device to the target device list
65113ef29eaSKashyap Desai  *
65213ef29eaSKashyap Desai  * Return: Nothing.
65313ef29eaSKashyap Desai  */
mpi3mr_tgtdev_add_to_list(struct mpi3mr_ioc * mrioc,struct mpi3mr_tgt_dev * tgtdev)65413ef29eaSKashyap Desai static void mpi3mr_tgtdev_add_to_list(struct mpi3mr_ioc *mrioc,
65513ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev)
65613ef29eaSKashyap Desai {
65713ef29eaSKashyap Desai 	unsigned long flags;
65813ef29eaSKashyap Desai 
65913ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
66013ef29eaSKashyap Desai 	mpi3mr_tgtdev_get(tgtdev);
66113ef29eaSKashyap Desai 	INIT_LIST_HEAD(&tgtdev->list);
66213ef29eaSKashyap Desai 	list_add_tail(&tgtdev->list, &mrioc->tgtdev_list);
6633f1254edSRanjan Kumar 	tgtdev->state = MPI3MR_DEV_CREATED;
66413ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
66513ef29eaSKashyap Desai }
66613ef29eaSKashyap Desai 
66713ef29eaSKashyap Desai /**
66813ef29eaSKashyap Desai  * mpi3mr_tgtdev_del_from_list -Delete tgtdevice from the list
66913ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
67013ef29eaSKashyap Desai  * @tgtdev: Target device
6713f1254edSRanjan Kumar  * @must_delete: Must delete the target device from the list irrespective
6723f1254edSRanjan Kumar  * of the device state.
67313ef29eaSKashyap Desai  *
67413ef29eaSKashyap Desai  * Remove the target device from the target device list
67513ef29eaSKashyap Desai  *
67613ef29eaSKashyap Desai  * Return: Nothing.
67713ef29eaSKashyap Desai  */
mpi3mr_tgtdev_del_from_list(struct mpi3mr_ioc * mrioc,struct mpi3mr_tgt_dev * tgtdev,bool must_delete)67813ef29eaSKashyap Desai static void mpi3mr_tgtdev_del_from_list(struct mpi3mr_ioc *mrioc,
6793f1254edSRanjan Kumar 	struct mpi3mr_tgt_dev *tgtdev, bool must_delete)
68013ef29eaSKashyap Desai {
68113ef29eaSKashyap Desai 	unsigned long flags;
68213ef29eaSKashyap Desai 
68313ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
6843f1254edSRanjan Kumar 	if ((tgtdev->state == MPI3MR_DEV_REMOVE_HS_STARTED) || (must_delete == true)) {
68513ef29eaSKashyap Desai 		if (!list_empty(&tgtdev->list)) {
68613ef29eaSKashyap Desai 			list_del_init(&tgtdev->list);
6873f1254edSRanjan Kumar 			tgtdev->state = MPI3MR_DEV_DELETED;
68813ef29eaSKashyap Desai 			mpi3mr_tgtdev_put(tgtdev);
68913ef29eaSKashyap Desai 		}
6903f1254edSRanjan Kumar 	}
69113ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
69213ef29eaSKashyap Desai }
69313ef29eaSKashyap Desai 
69413ef29eaSKashyap Desai /**
69513ef29eaSKashyap Desai  * __mpi3mr_get_tgtdev_by_handle -Get tgtdev from device handle
69613ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
69713ef29eaSKashyap Desai  * @handle: Device handle
69813ef29eaSKashyap Desai  *
69913ef29eaSKashyap Desai  * Accessor to retrieve target device from the device handle.
70013ef29eaSKashyap Desai  * Non Lock version
70113ef29eaSKashyap Desai  *
70213ef29eaSKashyap Desai  * Return: Target device reference.
70313ef29eaSKashyap Desai  */
__mpi3mr_get_tgtdev_by_handle(struct mpi3mr_ioc * mrioc,u16 handle)70413ef29eaSKashyap Desai static struct mpi3mr_tgt_dev  *__mpi3mr_get_tgtdev_by_handle(
70513ef29eaSKashyap Desai 	struct mpi3mr_ioc *mrioc, u16 handle)
70613ef29eaSKashyap Desai {
70713ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev;
70813ef29eaSKashyap Desai 
70913ef29eaSKashyap Desai 	assert_spin_locked(&mrioc->tgtdev_lock);
71013ef29eaSKashyap Desai 	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
71113ef29eaSKashyap Desai 		if (tgtdev->dev_handle == handle)
71213ef29eaSKashyap Desai 			goto found_tgtdev;
71313ef29eaSKashyap Desai 	return NULL;
71413ef29eaSKashyap Desai 
71513ef29eaSKashyap Desai found_tgtdev:
71613ef29eaSKashyap Desai 	mpi3mr_tgtdev_get(tgtdev);
71713ef29eaSKashyap Desai 	return tgtdev;
71813ef29eaSKashyap Desai }
71913ef29eaSKashyap Desai 
72013ef29eaSKashyap Desai /**
72113ef29eaSKashyap Desai  * mpi3mr_get_tgtdev_by_handle -Get tgtdev from device handle
72213ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
72313ef29eaSKashyap Desai  * @handle: Device handle
72413ef29eaSKashyap Desai  *
72513ef29eaSKashyap Desai  * Accessor to retrieve target device from the device handle.
72613ef29eaSKashyap Desai  * Lock version
72713ef29eaSKashyap Desai  *
72813ef29eaSKashyap Desai  * Return: Target device reference.
72913ef29eaSKashyap Desai  */
mpi3mr_get_tgtdev_by_handle(struct mpi3mr_ioc * mrioc,u16 handle)730506bc1a0SSumit Saxena struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_handle(
73113ef29eaSKashyap Desai 	struct mpi3mr_ioc *mrioc, u16 handle)
73213ef29eaSKashyap Desai {
73313ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev;
73413ef29eaSKashyap Desai 	unsigned long flags;
73513ef29eaSKashyap Desai 
73613ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
73713ef29eaSKashyap Desai 	tgtdev = __mpi3mr_get_tgtdev_by_handle(mrioc, handle);
73813ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
73913ef29eaSKashyap Desai 	return tgtdev;
74013ef29eaSKashyap Desai }
74113ef29eaSKashyap Desai 
74213ef29eaSKashyap Desai /**
74313ef29eaSKashyap Desai  * __mpi3mr_get_tgtdev_by_perst_id -Get tgtdev from persist ID
74413ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
74513ef29eaSKashyap Desai  * @persist_id: Persistent ID
74613ef29eaSKashyap Desai  *
74713ef29eaSKashyap Desai  * Accessor to retrieve target device from the Persistent ID.
74813ef29eaSKashyap Desai  * Non Lock version
74913ef29eaSKashyap Desai  *
75013ef29eaSKashyap Desai  * Return: Target device reference.
75113ef29eaSKashyap Desai  */
__mpi3mr_get_tgtdev_by_perst_id(struct mpi3mr_ioc * mrioc,u16 persist_id)75213ef29eaSKashyap Desai static struct mpi3mr_tgt_dev  *__mpi3mr_get_tgtdev_by_perst_id(
75313ef29eaSKashyap Desai 	struct mpi3mr_ioc *mrioc, u16 persist_id)
75413ef29eaSKashyap Desai {
75513ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev;
75613ef29eaSKashyap Desai 
75713ef29eaSKashyap Desai 	assert_spin_locked(&mrioc->tgtdev_lock);
75813ef29eaSKashyap Desai 	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
75913ef29eaSKashyap Desai 		if (tgtdev->perst_id == persist_id)
76013ef29eaSKashyap Desai 			goto found_tgtdev;
76113ef29eaSKashyap Desai 	return NULL;
76213ef29eaSKashyap Desai 
76313ef29eaSKashyap Desai found_tgtdev:
76413ef29eaSKashyap Desai 	mpi3mr_tgtdev_get(tgtdev);
76513ef29eaSKashyap Desai 	return tgtdev;
76613ef29eaSKashyap Desai }
76713ef29eaSKashyap Desai 
76813ef29eaSKashyap Desai /**
76913ef29eaSKashyap Desai  * mpi3mr_get_tgtdev_by_perst_id -Get tgtdev from persistent ID
77013ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
77113ef29eaSKashyap Desai  * @persist_id: Persistent ID
77213ef29eaSKashyap Desai  *
77313ef29eaSKashyap Desai  * Accessor to retrieve target device from the Persistent ID.
77413ef29eaSKashyap Desai  * Lock version
77513ef29eaSKashyap Desai  *
77613ef29eaSKashyap Desai  * Return: Target device reference.
77713ef29eaSKashyap Desai  */
mpi3mr_get_tgtdev_by_perst_id(struct mpi3mr_ioc * mrioc,u16 persist_id)77813ef29eaSKashyap Desai static struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_perst_id(
77913ef29eaSKashyap Desai 	struct mpi3mr_ioc *mrioc, u16 persist_id)
78013ef29eaSKashyap Desai {
78113ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev;
78213ef29eaSKashyap Desai 	unsigned long flags;
78313ef29eaSKashyap Desai 
78413ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
78513ef29eaSKashyap Desai 	tgtdev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, persist_id);
78613ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
78713ef29eaSKashyap Desai 	return tgtdev;
78813ef29eaSKashyap Desai }
78913ef29eaSKashyap Desai 
79013ef29eaSKashyap Desai /**
79113ef29eaSKashyap Desai  * __mpi3mr_get_tgtdev_from_tgtpriv -Get tgtdev from tgt private
79213ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
79313ef29eaSKashyap Desai  * @tgt_priv: Target private data
79413ef29eaSKashyap Desai  *
79513ef29eaSKashyap Desai  * Accessor to return target device from the target private
79613ef29eaSKashyap Desai  * data. Non Lock version
79713ef29eaSKashyap Desai  *
79813ef29eaSKashyap Desai  * Return: Target device reference.
79913ef29eaSKashyap Desai  */
__mpi3mr_get_tgtdev_from_tgtpriv(struct mpi3mr_ioc * mrioc,struct mpi3mr_stgt_priv_data * tgt_priv)80013ef29eaSKashyap Desai static struct mpi3mr_tgt_dev  *__mpi3mr_get_tgtdev_from_tgtpriv(
80113ef29eaSKashyap Desai 	struct mpi3mr_ioc *mrioc, struct mpi3mr_stgt_priv_data *tgt_priv)
80213ef29eaSKashyap Desai {
80313ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev;
80413ef29eaSKashyap Desai 
80513ef29eaSKashyap Desai 	assert_spin_locked(&mrioc->tgtdev_lock);
80613ef29eaSKashyap Desai 	tgtdev = tgt_priv->tgt_dev;
80713ef29eaSKashyap Desai 	if (tgtdev)
80813ef29eaSKashyap Desai 		mpi3mr_tgtdev_get(tgtdev);
80913ef29eaSKashyap Desai 	return tgtdev;
81013ef29eaSKashyap Desai }
81113ef29eaSKashyap Desai 
81213ef29eaSKashyap Desai /**
813f10af057SSreekanth Reddy  * mpi3mr_set_io_divert_for_all_vd_in_tg -set divert for TG VDs
814f10af057SSreekanth Reddy  * @mrioc: Adapter instance reference
815f10af057SSreekanth Reddy  * @tg: Throttle group information pointer
816f10af057SSreekanth Reddy  * @divert_value: 1 or 0
817f10af057SSreekanth Reddy  *
818f10af057SSreekanth Reddy  * Accessor to set io_divert flag for each device associated
819f10af057SSreekanth Reddy  * with the given throttle group with the given value.
820f10af057SSreekanth Reddy  *
821f10af057SSreekanth Reddy  * Return: None.
822f10af057SSreekanth Reddy  */
mpi3mr_set_io_divert_for_all_vd_in_tg(struct mpi3mr_ioc * mrioc,struct mpi3mr_throttle_group_info * tg,u8 divert_value)823f10af057SSreekanth Reddy static void mpi3mr_set_io_divert_for_all_vd_in_tg(struct mpi3mr_ioc *mrioc,
824f10af057SSreekanth Reddy 	struct mpi3mr_throttle_group_info *tg, u8 divert_value)
825f10af057SSreekanth Reddy {
826f10af057SSreekanth Reddy 	unsigned long flags;
827f10af057SSreekanth Reddy 	struct mpi3mr_tgt_dev *tgtdev;
828f10af057SSreekanth Reddy 	struct mpi3mr_stgt_priv_data *tgt_priv;
829f10af057SSreekanth Reddy 
830f10af057SSreekanth Reddy 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
831f10af057SSreekanth Reddy 	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
832f10af057SSreekanth Reddy 		if (tgtdev->starget && tgtdev->starget->hostdata) {
833f10af057SSreekanth Reddy 			tgt_priv = tgtdev->starget->hostdata;
834f10af057SSreekanth Reddy 			if (tgt_priv->throttle_group == tg)
835f10af057SSreekanth Reddy 				tgt_priv->io_divert = divert_value;
836f10af057SSreekanth Reddy 		}
837f10af057SSreekanth Reddy 	}
838f10af057SSreekanth Reddy 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
839f10af057SSreekanth Reddy }
840f10af057SSreekanth Reddy 
841f10af057SSreekanth Reddy /**
842580e6742SSreekanth Reddy  * mpi3mr_print_device_event_notice - print notice related to post processing of
843580e6742SSreekanth Reddy  *					device event after controller reset.
844580e6742SSreekanth Reddy  *
845580e6742SSreekanth Reddy  * @mrioc: Adapter instance reference
846580e6742SSreekanth Reddy  * @device_add: true for device add event and false for device removal event
847580e6742SSreekanth Reddy  *
848580e6742SSreekanth Reddy  * Return: None.
849580e6742SSreekanth Reddy  */
mpi3mr_print_device_event_notice(struct mpi3mr_ioc * mrioc,bool device_add)85042fc9feeSSreekanth Reddy void mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc,
851580e6742SSreekanth Reddy 	bool device_add)
852580e6742SSreekanth Reddy {
853580e6742SSreekanth Reddy 	ioc_notice(mrioc, "Device %s was in progress before the reset and\n",
854580e6742SSreekanth Reddy 	    (device_add ? "addition" : "removal"));
855580e6742SSreekanth Reddy 	ioc_notice(mrioc, "completed after reset, verify whether the exposed devices\n");
856580e6742SSreekanth Reddy 	ioc_notice(mrioc, "are matched with attached devices for correctness\n");
857580e6742SSreekanth Reddy }
858580e6742SSreekanth Reddy 
859580e6742SSreekanth Reddy /**
86013ef29eaSKashyap Desai  * mpi3mr_remove_tgtdev_from_host - Remove dev from upper layers
86113ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
86213ef29eaSKashyap Desai  * @tgtdev: Target device structure
86313ef29eaSKashyap Desai  *
86413ef29eaSKashyap Desai  * Checks whether the device is exposed to upper layers and if it
86513ef29eaSKashyap Desai  * is then remove the device from upper layers by calling
86613ef29eaSKashyap Desai  * scsi_remove_target().
86713ef29eaSKashyap Desai  *
86813ef29eaSKashyap Desai  * Return: 0 on success, non zero on failure.
86913ef29eaSKashyap Desai  */
mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc * mrioc,struct mpi3mr_tgt_dev * tgtdev)870e22bae30SSreekanth Reddy void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc,
87113ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev)
87213ef29eaSKashyap Desai {
87313ef29eaSKashyap Desai 	struct mpi3mr_stgt_priv_data *tgt_priv;
87413ef29eaSKashyap Desai 
87513ef29eaSKashyap Desai 	ioc_info(mrioc, "%s :Removing handle(0x%04x), wwid(0x%016llx)\n",
87613ef29eaSKashyap Desai 	    __func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid);
87713ef29eaSKashyap Desai 	if (tgtdev->starget && tgtdev->starget->hostdata) {
87813ef29eaSKashyap Desai 		tgt_priv = tgtdev->starget->hostdata;
8797f90bc70SSreekanth Reddy 		atomic_set(&tgt_priv->block_io, 0);
88013ef29eaSKashyap Desai 		tgt_priv->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
88113ef29eaSKashyap Desai 	}
88213ef29eaSKashyap Desai 
8837f56c791SSreekanth Reddy 	if (!mrioc->sas_transport_enabled || (tgtdev->dev_type !=
8847f56c791SSreekanth Reddy 	    MPI3_DEVICE_DEVFORM_SAS_SATA) || tgtdev->non_stl) {
88513ef29eaSKashyap Desai 		if (tgtdev->starget) {
886580e6742SSreekanth Reddy 			if (mrioc->current_event)
887580e6742SSreekanth Reddy 				mrioc->current_event->pending_at_sml = 1;
88813ef29eaSKashyap Desai 			scsi_remove_target(&tgtdev->starget->dev);
88913ef29eaSKashyap Desai 			tgtdev->host_exposed = 0;
890580e6742SSreekanth Reddy 			if (mrioc->current_event) {
891580e6742SSreekanth Reddy 				mrioc->current_event->pending_at_sml = 0;
892580e6742SSreekanth Reddy 				if (mrioc->current_event->discard) {
8937f56c791SSreekanth Reddy 					mpi3mr_print_device_event_notice(mrioc,
8947f56c791SSreekanth Reddy 					    false);
895580e6742SSreekanth Reddy 					return;
896580e6742SSreekanth Reddy 				}
897580e6742SSreekanth Reddy 			}
89813ef29eaSKashyap Desai 		}
8997f56c791SSreekanth Reddy 	} else
9007f56c791SSreekanth Reddy 		mpi3mr_remove_tgtdev_from_sas_transport(mrioc, tgtdev);
9017f56c791SSreekanth Reddy 
90213ef29eaSKashyap Desai 	ioc_info(mrioc, "%s :Removed handle(0x%04x), wwid(0x%016llx)\n",
90313ef29eaSKashyap Desai 	    __func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid);
90413ef29eaSKashyap Desai }
90513ef29eaSKashyap Desai 
90613ef29eaSKashyap Desai /**
90713ef29eaSKashyap Desai  * mpi3mr_report_tgtdev_to_host - Expose device to upper layers
90813ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
90913ef29eaSKashyap Desai  * @perst_id: Persistent ID of the device
91013ef29eaSKashyap Desai  *
91113ef29eaSKashyap Desai  * Checks whether the device can be exposed to upper layers and
91213ef29eaSKashyap Desai  * if it is not then expose the device to upper layers by
91313ef29eaSKashyap Desai  * calling scsi_scan_target().
91413ef29eaSKashyap Desai  *
91513ef29eaSKashyap Desai  * Return: 0 on success, non zero on failure.
91613ef29eaSKashyap Desai  */
mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc * mrioc,u16 perst_id)91713ef29eaSKashyap Desai static int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc,
91813ef29eaSKashyap Desai 	u16 perst_id)
91913ef29eaSKashyap Desai {
92013ef29eaSKashyap Desai 	int retval = 0;
92113ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev;
92213ef29eaSKashyap Desai 
9237f56c791SSreekanth Reddy 	if (mrioc->reset_in_progress)
9247f56c791SSreekanth Reddy 		return -1;
9257f56c791SSreekanth Reddy 
92613ef29eaSKashyap Desai 	tgtdev = mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id);
92713ef29eaSKashyap Desai 	if (!tgtdev) {
92813ef29eaSKashyap Desai 		retval = -1;
92913ef29eaSKashyap Desai 		goto out;
93013ef29eaSKashyap Desai 	}
9317f56c791SSreekanth Reddy 	if (tgtdev->is_hidden || tgtdev->host_exposed) {
93213ef29eaSKashyap Desai 		retval = -1;
93313ef29eaSKashyap Desai 		goto out;
93413ef29eaSKashyap Desai 	}
9357f56c791SSreekanth Reddy 	if (!mrioc->sas_transport_enabled || (tgtdev->dev_type !=
9367f56c791SSreekanth Reddy 	    MPI3_DEVICE_DEVFORM_SAS_SATA) || tgtdev->non_stl){
93713ef29eaSKashyap Desai 		tgtdev->host_exposed = 1;
938580e6742SSreekanth Reddy 		if (mrioc->current_event)
939580e6742SSreekanth Reddy 			mrioc->current_event->pending_at_sml = 1;
9407f56c791SSreekanth Reddy 		scsi_scan_target(&mrioc->shost->shost_gendev,
9417f56c791SSreekanth Reddy 		    mrioc->scsi_device_channel, tgtdev->perst_id,
94213ef29eaSKashyap Desai 		    SCAN_WILD_CARD, SCSI_SCAN_INITIAL);
94313ef29eaSKashyap Desai 		if (!tgtdev->starget)
94413ef29eaSKashyap Desai 			tgtdev->host_exposed = 0;
945580e6742SSreekanth Reddy 		if (mrioc->current_event) {
946580e6742SSreekanth Reddy 			mrioc->current_event->pending_at_sml = 0;
947580e6742SSreekanth Reddy 			if (mrioc->current_event->discard) {
948580e6742SSreekanth Reddy 				mpi3mr_print_device_event_notice(mrioc, true);
949580e6742SSreekanth Reddy 				goto out;
950580e6742SSreekanth Reddy 			}
951580e6742SSreekanth Reddy 		}
9527f56c791SSreekanth Reddy 	} else
9537f56c791SSreekanth Reddy 		mpi3mr_report_tgtdev_to_sas_transport(mrioc, tgtdev);
95413ef29eaSKashyap Desai out:
95513ef29eaSKashyap Desai 	if (tgtdev)
95613ef29eaSKashyap Desai 		mpi3mr_tgtdev_put(tgtdev);
95713ef29eaSKashyap Desai 
95813ef29eaSKashyap Desai 	return retval;
95913ef29eaSKashyap Desai }
96013ef29eaSKashyap Desai 
96113ef29eaSKashyap Desai /**
9620ea17734SKashyap Desai  * mpi3mr_change_queue_depth- Change QD callback handler
9630ea17734SKashyap Desai  * @sdev: SCSI device reference
9640ea17734SKashyap Desai  * @q_depth: Queue depth
9650ea17734SKashyap Desai  *
9660ea17734SKashyap Desai  * Validate and limit QD and call scsi_change_queue_depth.
9670ea17734SKashyap Desai  *
9680ea17734SKashyap Desai  * Return: return value of scsi_change_queue_depth
9690ea17734SKashyap Desai  */
mpi3mr_change_queue_depth(struct scsi_device * sdev,int q_depth)9700ea17734SKashyap Desai static int mpi3mr_change_queue_depth(struct scsi_device *sdev,
9710ea17734SKashyap Desai 	int q_depth)
9720ea17734SKashyap Desai {
9730ea17734SKashyap Desai 	struct scsi_target *starget = scsi_target(sdev);
9740ea17734SKashyap Desai 	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
9750ea17734SKashyap Desai 	int retval = 0;
9760ea17734SKashyap Desai 
9770ea17734SKashyap Desai 	if (!sdev->tagged_supported)
9780ea17734SKashyap Desai 		q_depth = 1;
9790ea17734SKashyap Desai 	if (q_depth > shost->can_queue)
9800ea17734SKashyap Desai 		q_depth = shost->can_queue;
9810ea17734SKashyap Desai 	else if (!q_depth)
9820ea17734SKashyap Desai 		q_depth = MPI3MR_DEFAULT_SDEV_QD;
9830ea17734SKashyap Desai 	retval = scsi_change_queue_depth(sdev, q_depth);
984cf1ce8b7SSreekanth Reddy 	sdev->max_queue_depth = sdev->queue_depth;
9850ea17734SKashyap Desai 
9860ea17734SKashyap Desai 	return retval;
9870ea17734SKashyap Desai }
9880ea17734SKashyap Desai 
9890ea17734SKashyap Desai /**
9908e653455SKashyap Desai  * mpi3mr_update_sdev - Update SCSI device information
9918e653455SKashyap Desai  * @sdev: SCSI device reference
9928e653455SKashyap Desai  * @data: target device reference
9938e653455SKashyap Desai  *
9948e653455SKashyap Desai  * This is an iterator function called for each SCSI device in a
9958e653455SKashyap Desai  * target to update the target specific information into each
9968e653455SKashyap Desai  * SCSI device.
9978e653455SKashyap Desai  *
9988e653455SKashyap Desai  * Return: Nothing.
9998e653455SKashyap Desai  */
10008e653455SKashyap Desai static void
mpi3mr_update_sdev(struct scsi_device * sdev,void * data)10018e653455SKashyap Desai mpi3mr_update_sdev(struct scsi_device *sdev, void *data)
10028e653455SKashyap Desai {
10038e653455SKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev;
10048e653455SKashyap Desai 
10058e653455SKashyap Desai 	tgtdev = (struct mpi3mr_tgt_dev *)data;
10068e653455SKashyap Desai 	if (!tgtdev)
10078e653455SKashyap Desai 		return;
10088e653455SKashyap Desai 
10090ea17734SKashyap Desai 	mpi3mr_change_queue_depth(sdev, tgtdev->q_depth);
10108e653455SKashyap Desai 	switch (tgtdev->dev_type) {
10118e653455SKashyap Desai 	case MPI3_DEVICE_DEVFORM_PCIE:
10128e653455SKashyap Desai 		/*The block layer hw sector size = 512*/
101317d6b9cfSSreekanth Reddy 		if ((tgtdev->dev_spec.pcie_inf.dev_info &
101417d6b9cfSSreekanth Reddy 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) ==
101517d6b9cfSSreekanth Reddy 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) {
10168e653455SKashyap Desai 			blk_queue_max_hw_sectors(sdev->request_queue,
10178e653455SKashyap Desai 			    tgtdev->dev_spec.pcie_inf.mdts / 512);
101817d6b9cfSSreekanth Reddy 			if (tgtdev->dev_spec.pcie_inf.pgsz == 0)
101917d6b9cfSSreekanth Reddy 				blk_queue_virt_boundary(sdev->request_queue,
102017d6b9cfSSreekanth Reddy 				    ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1));
102117d6b9cfSSreekanth Reddy 			else
10228e653455SKashyap Desai 				blk_queue_virt_boundary(sdev->request_queue,
10238e653455SKashyap Desai 				    ((1 << tgtdev->dev_spec.pcie_inf.pgsz) - 1));
102417d6b9cfSSreekanth Reddy 		}
10258e653455SKashyap Desai 		break;
10268e653455SKashyap Desai 	default:
10278e653455SKashyap Desai 		break;
10288e653455SKashyap Desai 	}
10298e653455SKashyap Desai }
10308e653455SKashyap Desai 
10318e653455SKashyap Desai /**
103213ef29eaSKashyap Desai  * mpi3mr_rfresh_tgtdevs - Refresh target device exposure
103313ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
103413ef29eaSKashyap Desai  *
103513ef29eaSKashyap Desai  * This is executed post controller reset to identify any
103613ef29eaSKashyap Desai  * missing devices during reset and remove from the upper layers
103713ef29eaSKashyap Desai  * or expose any newly detected device to the upper layers.
103813ef29eaSKashyap Desai  *
103913ef29eaSKashyap Desai  * Return: Nothing.
104013ef29eaSKashyap Desai  */
104113ef29eaSKashyap Desai 
mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc * mrioc)104213ef29eaSKashyap Desai void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc)
104313ef29eaSKashyap Desai {
104413ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next;
1045d9a5ab0eSRanjan Kumar 	struct mpi3mr_stgt_priv_data *tgt_priv;
1046d9a5ab0eSRanjan Kumar 
1047d9a5ab0eSRanjan Kumar 	dprint_reset(mrioc, "refresh target devices: check for removals\n");
1048d9a5ab0eSRanjan Kumar 	list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
1049d9a5ab0eSRanjan Kumar 	    list) {
1050d9a5ab0eSRanjan Kumar 		if ((tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) &&
1051fc6742c1SChandrakanth patil 		     tgtdev->is_hidden &&
1052d9a5ab0eSRanjan Kumar 		     tgtdev->host_exposed && tgtdev->starget &&
1053d9a5ab0eSRanjan Kumar 		     tgtdev->starget->hostdata) {
1054d9a5ab0eSRanjan Kumar 			tgt_priv = tgtdev->starget->hostdata;
1055d9a5ab0eSRanjan Kumar 			tgt_priv->dev_removed = 1;
1056d9a5ab0eSRanjan Kumar 			atomic_set(&tgt_priv->block_io, 0);
1057d9a5ab0eSRanjan Kumar 		}
1058d9a5ab0eSRanjan Kumar 	}
105913ef29eaSKashyap Desai 
106013ef29eaSKashyap Desai 	list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
106113ef29eaSKashyap Desai 	    list) {
10622dd8389fSSreekanth Reddy 		if (tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) {
10632dd8389fSSreekanth Reddy 			dprint_reset(mrioc, "removing target device with perst_id(%d)\n",
10642dd8389fSSreekanth Reddy 			    tgtdev->perst_id);
10652dd8389fSSreekanth Reddy 			if (tgtdev->host_exposed)
106613ef29eaSKashyap Desai 				mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
10673f1254edSRanjan Kumar 			mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, true);
106813ef29eaSKashyap Desai 			mpi3mr_tgtdev_put(tgtdev);
1069fc6742c1SChandrakanth patil 		} else if (tgtdev->is_hidden & tgtdev->host_exposed) {
1070fc6742c1SChandrakanth patil 			dprint_reset(mrioc, "hiding target device with perst_id(%d)\n",
1071fc6742c1SChandrakanth patil 				     tgtdev->perst_id);
1072fc6742c1SChandrakanth patil 			mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
107313ef29eaSKashyap Desai 		}
107413ef29eaSKashyap Desai 	}
107513ef29eaSKashyap Desai 
107613ef29eaSKashyap Desai 	tgtdev = NULL;
107713ef29eaSKashyap Desai 	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
107813ef29eaSKashyap Desai 		if ((tgtdev->dev_handle != MPI3MR_INVALID_DEV_HANDLE) &&
10793ddc8b84SChandrakanth patil 		    !tgtdev->is_hidden) {
10803ddc8b84SChandrakanth patil 			if (!tgtdev->host_exposed)
10813ddc8b84SChandrakanth patil 				mpi3mr_report_tgtdev_to_host(mrioc,
10823ddc8b84SChandrakanth patil 							     tgtdev->perst_id);
10833ddc8b84SChandrakanth patil 			else if (tgtdev->starget)
10843ddc8b84SChandrakanth patil 				starget_for_each_device(tgtdev->starget,
10853ddc8b84SChandrakanth patil 							(void *)tgtdev, mpi3mr_update_sdev);
10863ddc8b84SChandrakanth patil 	}
108713ef29eaSKashyap Desai 	}
108813ef29eaSKashyap Desai }
108913ef29eaSKashyap Desai 
109013ef29eaSKashyap Desai /**
109113ef29eaSKashyap Desai  * mpi3mr_update_tgtdev - DevStatusChange evt bottomhalf
109213ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
109313ef29eaSKashyap Desai  * @tgtdev: Target device internal structure
109413ef29eaSKashyap Desai  * @dev_pg0: New device page0
1095f10af057SSreekanth Reddy  * @is_added: Flag to indicate the device is just added
109613ef29eaSKashyap Desai  *
109713ef29eaSKashyap Desai  * Update the information from the device page0 into the driver
109813ef29eaSKashyap Desai  * cached target device structure.
109913ef29eaSKashyap Desai  *
110013ef29eaSKashyap Desai  * Return: Nothing.
110113ef29eaSKashyap Desai  */
mpi3mr_update_tgtdev(struct mpi3mr_ioc * mrioc,struct mpi3mr_tgt_dev * tgtdev,struct mpi3_device_page0 * dev_pg0,bool is_added)110213ef29eaSKashyap Desai static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
1103f10af057SSreekanth Reddy 	struct mpi3mr_tgt_dev *tgtdev, struct mpi3_device_page0 *dev_pg0,
1104f10af057SSreekanth Reddy 	bool is_added)
110513ef29eaSKashyap Desai {
110613ef29eaSKashyap Desai 	u16 flags = 0;
1107f10af057SSreekanth Reddy 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
11087188c03fSSreekanth Reddy 	struct mpi3mr_enclosure_node *enclosure_dev = NULL;
110974e1f30aSKashyap Desai 	u8 prot_mask = 0;
111013ef29eaSKashyap Desai 
111113ef29eaSKashyap Desai 	tgtdev->perst_id = le16_to_cpu(dev_pg0->persistent_id);
111213ef29eaSKashyap Desai 	tgtdev->dev_handle = le16_to_cpu(dev_pg0->dev_handle);
111313ef29eaSKashyap Desai 	tgtdev->dev_type = dev_pg0->device_form;
1114c4723e68SSreekanth Reddy 	tgtdev->io_unit_port = dev_pg0->io_unit_port;
111513ef29eaSKashyap Desai 	tgtdev->encl_handle = le16_to_cpu(dev_pg0->enclosure_handle);
111613ef29eaSKashyap Desai 	tgtdev->parent_handle = le16_to_cpu(dev_pg0->parent_dev_handle);
111713ef29eaSKashyap Desai 	tgtdev->slot = le16_to_cpu(dev_pg0->slot);
111813ef29eaSKashyap Desai 	tgtdev->q_depth = le16_to_cpu(dev_pg0->queue_depth);
111913ef29eaSKashyap Desai 	tgtdev->wwid = le64_to_cpu(dev_pg0->wwid);
11207188c03fSSreekanth Reddy 	tgtdev->devpg0_flag = le16_to_cpu(dev_pg0->flags);
112113ef29eaSKashyap Desai 
11227188c03fSSreekanth Reddy 	if (tgtdev->encl_handle)
11237188c03fSSreekanth Reddy 		enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc,
11247188c03fSSreekanth Reddy 		    tgtdev->encl_handle);
11257188c03fSSreekanth Reddy 	if (enclosure_dev)
11267188c03fSSreekanth Reddy 		tgtdev->enclosure_logical_id = le64_to_cpu(
11277188c03fSSreekanth Reddy 		    enclosure_dev->pg0.enclosure_logical_id);
11287188c03fSSreekanth Reddy 
11297188c03fSSreekanth Reddy 	flags = tgtdev->devpg0_flag;
11307188c03fSSreekanth Reddy 
113113ef29eaSKashyap Desai 	tgtdev->is_hidden = (flags & MPI3_DEVICE0_FLAGS_HIDDEN);
113213ef29eaSKashyap Desai 
1133f10af057SSreekanth Reddy 	if (is_added == true)
1134f10af057SSreekanth Reddy 		tgtdev->io_throttle_enabled =
1135f10af057SSreekanth Reddy 		    (flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0;
1136f10af057SSreekanth Reddy 
1137e7a8648eSRanjan Kumar 	switch (flags & MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_MASK) {
1138e7a8648eSRanjan Kumar 	case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_256_LB:
1139e7a8648eSRanjan Kumar 		tgtdev->wslen = MPI3MR_WRITE_SAME_MAX_LEN_256_BLKS;
1140e7a8648eSRanjan Kumar 		break;
1141e7a8648eSRanjan Kumar 	case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_2048_LB:
1142e7a8648eSRanjan Kumar 		tgtdev->wslen = MPI3MR_WRITE_SAME_MAX_LEN_2048_BLKS;
1143e7a8648eSRanjan Kumar 		break;
1144e7a8648eSRanjan Kumar 	case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_NO_LIMIT:
1145e7a8648eSRanjan Kumar 	default:
1146e7a8648eSRanjan Kumar 		tgtdev->wslen = 0;
1147e7a8648eSRanjan Kumar 		break;
1148e7a8648eSRanjan Kumar 	}
1149f10af057SSreekanth Reddy 
115013ef29eaSKashyap Desai 	if (tgtdev->starget && tgtdev->starget->hostdata) {
115113ef29eaSKashyap Desai 		scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
115213ef29eaSKashyap Desai 		    tgtdev->starget->hostdata;
115313ef29eaSKashyap Desai 		scsi_tgt_priv_data->perst_id = tgtdev->perst_id;
115413ef29eaSKashyap Desai 		scsi_tgt_priv_data->dev_handle = tgtdev->dev_handle;
115513ef29eaSKashyap Desai 		scsi_tgt_priv_data->dev_type = tgtdev->dev_type;
1156f10af057SSreekanth Reddy 		scsi_tgt_priv_data->io_throttle_enabled =
1157f10af057SSreekanth Reddy 		    tgtdev->io_throttle_enabled;
11587f90bc70SSreekanth Reddy 		if (is_added == true)
11597f90bc70SSreekanth Reddy 			atomic_set(&scsi_tgt_priv_data->block_io, 0);
1160e7a8648eSRanjan Kumar 		scsi_tgt_priv_data->wslen = tgtdev->wslen;
116113ef29eaSKashyap Desai 	}
116213ef29eaSKashyap Desai 
1163ba68779aSSreekanth Reddy 	switch (dev_pg0->access_status) {
1164ba68779aSSreekanth Reddy 	case MPI3_DEVICE0_ASTATUS_NO_ERRORS:
1165ba68779aSSreekanth Reddy 	case MPI3_DEVICE0_ASTATUS_PREPARE:
1166ba68779aSSreekanth Reddy 	case MPI3_DEVICE0_ASTATUS_NEEDS_INITIALIZATION:
1167ba68779aSSreekanth Reddy 	case MPI3_DEVICE0_ASTATUS_DEVICE_MISSING_DELAY:
1168ba68779aSSreekanth Reddy 		break;
1169ba68779aSSreekanth Reddy 	default:
1170ba68779aSSreekanth Reddy 		tgtdev->is_hidden = 1;
1171ba68779aSSreekanth Reddy 		break;
1172ba68779aSSreekanth Reddy 	}
1173ba68779aSSreekanth Reddy 
117413ef29eaSKashyap Desai 	switch (tgtdev->dev_type) {
117513ef29eaSKashyap Desai 	case MPI3_DEVICE_DEVFORM_SAS_SATA:
117613ef29eaSKashyap Desai 	{
117713ef29eaSKashyap Desai 		struct mpi3_device0_sas_sata_format *sasinf =
117813ef29eaSKashyap Desai 		    &dev_pg0->device_specific.sas_sata_format;
117913ef29eaSKashyap Desai 		u16 dev_info = le16_to_cpu(sasinf->device_info);
118013ef29eaSKashyap Desai 
118113ef29eaSKashyap Desai 		tgtdev->dev_spec.sas_sata_inf.dev_info = dev_info;
118213ef29eaSKashyap Desai 		tgtdev->dev_spec.sas_sata_inf.sas_address =
118313ef29eaSKashyap Desai 		    le64_to_cpu(sasinf->sas_address);
11847f56c791SSreekanth Reddy 		tgtdev->dev_spec.sas_sata_inf.phy_id = sasinf->phy_num;
11857f56c791SSreekanth Reddy 		tgtdev->dev_spec.sas_sata_inf.attached_phy_id =
11867f56c791SSreekanth Reddy 		    sasinf->attached_phy_identifier;
118713ef29eaSKashyap Desai 		if ((dev_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) !=
118813ef29eaSKashyap Desai 		    MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE)
118913ef29eaSKashyap Desai 			tgtdev->is_hidden = 1;
119013ef29eaSKashyap Desai 		else if (!(dev_info & (MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET |
119113ef29eaSKashyap Desai 		    MPI3_SAS_DEVICE_INFO_SSP_TARGET)))
119213ef29eaSKashyap Desai 			tgtdev->is_hidden = 1;
1193c4723e68SSreekanth Reddy 
1194c4723e68SSreekanth Reddy 		if (((tgtdev->devpg0_flag &
1195c4723e68SSreekanth Reddy 		    MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)
1196c4723e68SSreekanth Reddy 		    && (tgtdev->devpg0_flag &
1197c4723e68SSreekanth Reddy 		    MPI3_DEVICE0_FLAGS_ATT_METHOD_VIRTUAL)) ||
1198c4723e68SSreekanth Reddy 		    (tgtdev->parent_handle == 0xFFFF))
1199c4723e68SSreekanth Reddy 			tgtdev->non_stl = 1;
12002745ce0eSSreekanth Reddy 		if (tgtdev->dev_spec.sas_sata_inf.hba_port)
12012745ce0eSSreekanth Reddy 			tgtdev->dev_spec.sas_sata_inf.hba_port->port_id =
12022745ce0eSSreekanth Reddy 			    dev_pg0->io_unit_port;
120313ef29eaSKashyap Desai 		break;
120413ef29eaSKashyap Desai 	}
12058e653455SKashyap Desai 	case MPI3_DEVICE_DEVFORM_PCIE:
12068e653455SKashyap Desai 	{
12078e653455SKashyap Desai 		struct mpi3_device0_pcie_format *pcieinf =
12088e653455SKashyap Desai 		    &dev_pg0->device_specific.pcie_format;
12098e653455SKashyap Desai 		u16 dev_info = le16_to_cpu(pcieinf->device_info);
12108e653455SKashyap Desai 
121117d6b9cfSSreekanth Reddy 		tgtdev->dev_spec.pcie_inf.dev_info = dev_info;
12128e653455SKashyap Desai 		tgtdev->dev_spec.pcie_inf.capb =
12138e653455SKashyap Desai 		    le32_to_cpu(pcieinf->capabilities);
12148e653455SKashyap Desai 		tgtdev->dev_spec.pcie_inf.mdts = MPI3MR_DEFAULT_MDTS;
12158e653455SKashyap Desai 		/* 2^12 = 4096 */
12168e653455SKashyap Desai 		tgtdev->dev_spec.pcie_inf.pgsz = 12;
12178e653455SKashyap Desai 		if (dev_pg0->access_status == MPI3_DEVICE0_ASTATUS_NO_ERRORS) {
12188e653455SKashyap Desai 			tgtdev->dev_spec.pcie_inf.mdts =
12198e653455SKashyap Desai 			    le32_to_cpu(pcieinf->maximum_data_transfer_size);
12208e653455SKashyap Desai 			tgtdev->dev_spec.pcie_inf.pgsz = pcieinf->page_size;
12218e653455SKashyap Desai 			tgtdev->dev_spec.pcie_inf.reset_to =
12224f08b963SSreekanth Reddy 			    max_t(u8, pcieinf->controller_reset_to,
12234f08b963SSreekanth Reddy 			     MPI3MR_INTADMCMD_TIMEOUT);
12248e653455SKashyap Desai 			tgtdev->dev_spec.pcie_inf.abort_to =
12254f08b963SSreekanth Reddy 			    max_t(u8, pcieinf->nvme_abort_to,
12264f08b963SSreekanth Reddy 			    MPI3MR_INTADMCMD_TIMEOUT);
12278e653455SKashyap Desai 		}
12288e653455SKashyap Desai 		if (tgtdev->dev_spec.pcie_inf.mdts > (1024 * 1024))
12298e653455SKashyap Desai 			tgtdev->dev_spec.pcie_inf.mdts = (1024 * 1024);
123017d6b9cfSSreekanth Reddy 		if (((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) !=
123117d6b9cfSSreekanth Reddy 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) &&
123217d6b9cfSSreekanth Reddy 		    ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) !=
123317d6b9cfSSreekanth Reddy 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE))
12348e653455SKashyap Desai 			tgtdev->is_hidden = 1;
1235c4723e68SSreekanth Reddy 		tgtdev->non_stl = 1;
123662e528b8SSreekanth Reddy 		if (!mrioc->shost)
123762e528b8SSreekanth Reddy 			break;
123874e1f30aSKashyap Desai 		prot_mask = scsi_host_get_prot(mrioc->shost);
123974e1f30aSKashyap Desai 		if (prot_mask & SHOST_DIX_TYPE0_PROTECTION) {
124074e1f30aSKashyap Desai 			scsi_host_set_prot(mrioc->shost, prot_mask & 0x77);
124174e1f30aSKashyap Desai 			ioc_info(mrioc,
124274e1f30aSKashyap Desai 			    "%s : Disabling DIX0 prot capability\n", __func__);
124374e1f30aSKashyap Desai 			ioc_info(mrioc,
124474e1f30aSKashyap Desai 			    "because HBA does not support DIX0 operation on NVME drives\n");
124574e1f30aSKashyap Desai 		}
12468e653455SKashyap Desai 		break;
12478e653455SKashyap Desai 	}
124813ef29eaSKashyap Desai 	case MPI3_DEVICE_DEVFORM_VD:
124913ef29eaSKashyap Desai 	{
125013ef29eaSKashyap Desai 		struct mpi3_device0_vd_format *vdinf =
125113ef29eaSKashyap Desai 		    &dev_pg0->device_specific.vd_format;
1252f10af057SSreekanth Reddy 		struct mpi3mr_throttle_group_info *tg = NULL;
1253f10af057SSreekanth Reddy 		u16 vdinf_io_throttle_group =
1254f10af057SSreekanth Reddy 		    le16_to_cpu(vdinf->io_throttle_group);
125513ef29eaSKashyap Desai 
1256f10af057SSreekanth Reddy 		tgtdev->dev_spec.vd_inf.state = vdinf->vd_state;
125713ef29eaSKashyap Desai 		if (vdinf->vd_state == MPI3_DEVICE0_VD_STATE_OFFLINE)
125813ef29eaSKashyap Desai 			tgtdev->is_hidden = 1;
1259c4723e68SSreekanth Reddy 		tgtdev->non_stl = 1;
1260f10af057SSreekanth Reddy 		tgtdev->dev_spec.vd_inf.tg_id = vdinf_io_throttle_group;
1261f10af057SSreekanth Reddy 		tgtdev->dev_spec.vd_inf.tg_high =
1262f10af057SSreekanth Reddy 		    le16_to_cpu(vdinf->io_throttle_group_high) * 2048;
1263f10af057SSreekanth Reddy 		tgtdev->dev_spec.vd_inf.tg_low =
1264f10af057SSreekanth Reddy 		    le16_to_cpu(vdinf->io_throttle_group_low) * 2048;
1265f10af057SSreekanth Reddy 		if (vdinf_io_throttle_group < mrioc->num_io_throttle_group) {
1266f10af057SSreekanth Reddy 			tg = mrioc->throttle_groups + vdinf_io_throttle_group;
1267f10af057SSreekanth Reddy 			tg->id = vdinf_io_throttle_group;
1268f10af057SSreekanth Reddy 			tg->high = tgtdev->dev_spec.vd_inf.tg_high;
1269f10af057SSreekanth Reddy 			tg->low = tgtdev->dev_spec.vd_inf.tg_low;
1270cf1ce8b7SSreekanth Reddy 			tg->qd_reduction =
1271cf1ce8b7SSreekanth Reddy 			    tgtdev->dev_spec.vd_inf.tg_qd_reduction;
1272cf1ce8b7SSreekanth Reddy 			if (is_added == true)
1273cf1ce8b7SSreekanth Reddy 				tg->fw_qd = tgtdev->q_depth;
1274cf1ce8b7SSreekanth Reddy 			tg->modified_qd = tgtdev->q_depth;
1275f10af057SSreekanth Reddy 		}
1276f10af057SSreekanth Reddy 		tgtdev->dev_spec.vd_inf.tg = tg;
1277f10af057SSreekanth Reddy 		if (scsi_tgt_priv_data)
1278f10af057SSreekanth Reddy 			scsi_tgt_priv_data->throttle_group = tg;
127913ef29eaSKashyap Desai 		break;
128013ef29eaSKashyap Desai 	}
128113ef29eaSKashyap Desai 	default:
128213ef29eaSKashyap Desai 		break;
128313ef29eaSKashyap Desai 	}
128413ef29eaSKashyap Desai }
128513ef29eaSKashyap Desai 
128613ef29eaSKashyap Desai /**
128713ef29eaSKashyap Desai  * mpi3mr_devstatuschg_evt_bh - DevStatusChange evt bottomhalf
128813ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
128913ef29eaSKashyap Desai  * @fwevt: Firmware event information.
129013ef29eaSKashyap Desai  *
129113ef29eaSKashyap Desai  * Process Device status Change event and based on device's new
129213ef29eaSKashyap Desai  * information, either expose the device to the upper layers, or
129313ef29eaSKashyap Desai  * remove the device from upper layers.
129413ef29eaSKashyap Desai  *
129513ef29eaSKashyap Desai  * Return: Nothing.
129613ef29eaSKashyap Desai  */
mpi3mr_devstatuschg_evt_bh(struct mpi3mr_ioc * mrioc,struct mpi3mr_fwevt * fwevt)129713ef29eaSKashyap Desai static void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_ioc *mrioc,
129813ef29eaSKashyap Desai 	struct mpi3mr_fwevt *fwevt)
129913ef29eaSKashyap Desai {
130013ef29eaSKashyap Desai 	u16 dev_handle = 0;
130113ef29eaSKashyap Desai 	u8 uhide = 0, delete = 0, cleanup = 0;
130213ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev = NULL;
130313ef29eaSKashyap Desai 	struct mpi3_event_data_device_status_change *evtdata =
130413ef29eaSKashyap Desai 	    (struct mpi3_event_data_device_status_change *)fwevt->event_data;
130513ef29eaSKashyap Desai 
130613ef29eaSKashyap Desai 	dev_handle = le16_to_cpu(evtdata->dev_handle);
130713ef29eaSKashyap Desai 	ioc_info(mrioc,
130813ef29eaSKashyap Desai 	    "%s :device status change: handle(0x%04x): reason code(0x%x)\n",
130913ef29eaSKashyap Desai 	    __func__, dev_handle, evtdata->reason_code);
131013ef29eaSKashyap Desai 	switch (evtdata->reason_code) {
131113ef29eaSKashyap Desai 	case MPI3_EVENT_DEV_STAT_RC_HIDDEN:
131213ef29eaSKashyap Desai 		delete = 1;
131313ef29eaSKashyap Desai 		break;
131413ef29eaSKashyap Desai 	case MPI3_EVENT_DEV_STAT_RC_NOT_HIDDEN:
131513ef29eaSKashyap Desai 		uhide = 1;
131613ef29eaSKashyap Desai 		break;
131713ef29eaSKashyap Desai 	case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING:
131813ef29eaSKashyap Desai 		delete = 1;
131913ef29eaSKashyap Desai 		cleanup = 1;
132013ef29eaSKashyap Desai 		break;
132113ef29eaSKashyap Desai 	default:
132213ef29eaSKashyap Desai 		ioc_info(mrioc, "%s :Unhandled reason code(0x%x)\n", __func__,
132313ef29eaSKashyap Desai 		    evtdata->reason_code);
132413ef29eaSKashyap Desai 		break;
132513ef29eaSKashyap Desai 	}
132613ef29eaSKashyap Desai 
132713ef29eaSKashyap Desai 	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
132813ef29eaSKashyap Desai 	if (!tgtdev)
132913ef29eaSKashyap Desai 		goto out;
133013ef29eaSKashyap Desai 	if (uhide) {
133113ef29eaSKashyap Desai 		tgtdev->is_hidden = 0;
133213ef29eaSKashyap Desai 		if (!tgtdev->host_exposed)
133313ef29eaSKashyap Desai 			mpi3mr_report_tgtdev_to_host(mrioc, tgtdev->perst_id);
133413ef29eaSKashyap Desai 	}
13353f1254edSRanjan Kumar 
133613ef29eaSKashyap Desai 	if (delete)
133713ef29eaSKashyap Desai 		mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
13383f1254edSRanjan Kumar 
133913ef29eaSKashyap Desai 	if (cleanup) {
13403f1254edSRanjan Kumar 		mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, false);
134113ef29eaSKashyap Desai 		mpi3mr_tgtdev_put(tgtdev);
134213ef29eaSKashyap Desai 	}
134313ef29eaSKashyap Desai 
134413ef29eaSKashyap Desai out:
134513ef29eaSKashyap Desai 	if (tgtdev)
134613ef29eaSKashyap Desai 		mpi3mr_tgtdev_put(tgtdev);
134713ef29eaSKashyap Desai }
134813ef29eaSKashyap Desai 
134913ef29eaSKashyap Desai /**
135013ef29eaSKashyap Desai  * mpi3mr_devinfochg_evt_bh - DeviceInfoChange evt bottomhalf
135113ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
135213ef29eaSKashyap Desai  * @dev_pg0: New device page0
135313ef29eaSKashyap Desai  *
135413ef29eaSKashyap Desai  * Process Device Info Change event and based on device's new
135513ef29eaSKashyap Desai  * information, either expose the device to the upper layers, or
135613ef29eaSKashyap Desai  * remove the device from upper layers or update the details of
135713ef29eaSKashyap Desai  * the device.
135813ef29eaSKashyap Desai  *
135913ef29eaSKashyap Desai  * Return: Nothing.
136013ef29eaSKashyap Desai  */
mpi3mr_devinfochg_evt_bh(struct mpi3mr_ioc * mrioc,struct mpi3_device_page0 * dev_pg0)136113ef29eaSKashyap Desai static void mpi3mr_devinfochg_evt_bh(struct mpi3mr_ioc *mrioc,
136213ef29eaSKashyap Desai 	struct mpi3_device_page0 *dev_pg0)
136313ef29eaSKashyap Desai {
136413ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev = NULL;
136513ef29eaSKashyap Desai 	u16 dev_handle = 0, perst_id = 0;
136613ef29eaSKashyap Desai 
136713ef29eaSKashyap Desai 	perst_id = le16_to_cpu(dev_pg0->persistent_id);
136813ef29eaSKashyap Desai 	dev_handle = le16_to_cpu(dev_pg0->dev_handle);
136913ef29eaSKashyap Desai 	ioc_info(mrioc,
137013ef29eaSKashyap Desai 	    "%s :Device info change: handle(0x%04x): persist_id(0x%x)\n",
137113ef29eaSKashyap Desai 	    __func__, dev_handle, perst_id);
137213ef29eaSKashyap Desai 	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
137313ef29eaSKashyap Desai 	if (!tgtdev)
137413ef29eaSKashyap Desai 		goto out;
1375f10af057SSreekanth Reddy 	mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, false);
137613ef29eaSKashyap Desai 	if (!tgtdev->is_hidden && !tgtdev->host_exposed)
137713ef29eaSKashyap Desai 		mpi3mr_report_tgtdev_to_host(mrioc, perst_id);
137813ef29eaSKashyap Desai 	if (tgtdev->is_hidden && tgtdev->host_exposed)
137913ef29eaSKashyap Desai 		mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
13808e653455SKashyap Desai 	if (!tgtdev->is_hidden && tgtdev->host_exposed && tgtdev->starget)
13818e653455SKashyap Desai 		starget_for_each_device(tgtdev->starget, (void *)tgtdev,
13828e653455SKashyap Desai 		    mpi3mr_update_sdev);
138313ef29eaSKashyap Desai out:
138413ef29eaSKashyap Desai 	if (tgtdev)
138513ef29eaSKashyap Desai 		mpi3mr_tgtdev_put(tgtdev);
138613ef29eaSKashyap Desai }
138713ef29eaSKashyap Desai 
138813ef29eaSKashyap Desai /**
1389130fc180SSreekanth Reddy  * mpi3mr_free_enclosure_list - release enclosures
1390130fc180SSreekanth Reddy  * @mrioc: Adapter instance reference
1391130fc180SSreekanth Reddy  *
1392130fc180SSreekanth Reddy  * Free memory allocated during encloure add.
1393130fc180SSreekanth Reddy  *
1394130fc180SSreekanth Reddy  * Return nothing.
1395130fc180SSreekanth Reddy  */
mpi3mr_free_enclosure_list(struct mpi3mr_ioc * mrioc)1396130fc180SSreekanth Reddy void mpi3mr_free_enclosure_list(struct mpi3mr_ioc *mrioc)
1397130fc180SSreekanth Reddy {
1398130fc180SSreekanth Reddy 	struct mpi3mr_enclosure_node *enclosure_dev, *enclosure_dev_next;
1399130fc180SSreekanth Reddy 
1400130fc180SSreekanth Reddy 	list_for_each_entry_safe(enclosure_dev,
1401130fc180SSreekanth Reddy 	    enclosure_dev_next, &mrioc->enclosure_list, list) {
1402130fc180SSreekanth Reddy 		list_del(&enclosure_dev->list);
1403130fc180SSreekanth Reddy 		kfree(enclosure_dev);
1404130fc180SSreekanth Reddy 	}
1405130fc180SSreekanth Reddy }
1406130fc180SSreekanth Reddy 
1407130fc180SSreekanth Reddy /**
14087188c03fSSreekanth Reddy  * mpi3mr_enclosure_find_by_handle - enclosure search by handle
14097188c03fSSreekanth Reddy  * @mrioc: Adapter instance reference
14107188c03fSSreekanth Reddy  * @handle: Firmware device handle of the enclosure
14117188c03fSSreekanth Reddy  *
14127188c03fSSreekanth Reddy  * This searches for enclosure device based on handle, then returns the
14137188c03fSSreekanth Reddy  * enclosure object.
14147188c03fSSreekanth Reddy  *
14157188c03fSSreekanth Reddy  * Return: Enclosure object reference or NULL
14167188c03fSSreekanth Reddy  */
mpi3mr_enclosure_find_by_handle(struct mpi3mr_ioc * mrioc,u16 handle)14177188c03fSSreekanth Reddy struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle(
14187188c03fSSreekanth Reddy 	struct mpi3mr_ioc *mrioc, u16 handle)
14197188c03fSSreekanth Reddy {
14207188c03fSSreekanth Reddy 	struct mpi3mr_enclosure_node *enclosure_dev, *r = NULL;
14217188c03fSSreekanth Reddy 
14227188c03fSSreekanth Reddy 	list_for_each_entry(enclosure_dev, &mrioc->enclosure_list, list) {
14237188c03fSSreekanth Reddy 		if (le16_to_cpu(enclosure_dev->pg0.enclosure_handle) != handle)
14247188c03fSSreekanth Reddy 			continue;
14257188c03fSSreekanth Reddy 		r = enclosure_dev;
14267188c03fSSreekanth Reddy 		goto out;
14277188c03fSSreekanth Reddy 	}
14287188c03fSSreekanth Reddy out:
14297188c03fSSreekanth Reddy 	return r;
14307188c03fSSreekanth Reddy }
14317188c03fSSreekanth Reddy 
14327188c03fSSreekanth Reddy /**
14337188c03fSSreekanth Reddy  * mpi3mr_encldev_add_chg_evt_debug - debug for enclosure event
14347188c03fSSreekanth Reddy  * @mrioc: Adapter instance reference
14357188c03fSSreekanth Reddy  * @encl_pg0: Enclosure page 0.
14367188c03fSSreekanth Reddy  * @is_added: Added event or not
14377188c03fSSreekanth Reddy  *
14387188c03fSSreekanth Reddy  * Return nothing.
14397188c03fSSreekanth Reddy  */
mpi3mr_encldev_add_chg_evt_debug(struct mpi3mr_ioc * mrioc,struct mpi3_enclosure_page0 * encl_pg0,u8 is_added)14407188c03fSSreekanth Reddy static void mpi3mr_encldev_add_chg_evt_debug(struct mpi3mr_ioc *mrioc,
14417188c03fSSreekanth Reddy 	struct mpi3_enclosure_page0 *encl_pg0, u8 is_added)
14427188c03fSSreekanth Reddy {
14437188c03fSSreekanth Reddy 	char *reason_str = NULL;
14447188c03fSSreekanth Reddy 
14457188c03fSSreekanth Reddy 	if (!(mrioc->logging_level & MPI3_DEBUG_EVENT_WORK_TASK))
14467188c03fSSreekanth Reddy 		return;
14477188c03fSSreekanth Reddy 
14487188c03fSSreekanth Reddy 	if (is_added)
14497188c03fSSreekanth Reddy 		reason_str = "enclosure added";
14507188c03fSSreekanth Reddy 	else
14517188c03fSSreekanth Reddy 		reason_str = "enclosure dev status changed";
14527188c03fSSreekanth Reddy 
14537188c03fSSreekanth Reddy 	ioc_info(mrioc,
14547188c03fSSreekanth Reddy 	    "%s: handle(0x%04x), enclosure logical id(0x%016llx)\n",
14557188c03fSSreekanth Reddy 	    reason_str, le16_to_cpu(encl_pg0->enclosure_handle),
14567188c03fSSreekanth Reddy 	    (unsigned long long)le64_to_cpu(encl_pg0->enclosure_logical_id));
14577188c03fSSreekanth Reddy 	ioc_info(mrioc,
14587188c03fSSreekanth Reddy 	    "number of slots(%d), port(%d), flags(0x%04x), present(%d)\n",
14597188c03fSSreekanth Reddy 	    le16_to_cpu(encl_pg0->num_slots), encl_pg0->io_unit_port,
14607188c03fSSreekanth Reddy 	    le16_to_cpu(encl_pg0->flags),
14617188c03fSSreekanth Reddy 	    ((le16_to_cpu(encl_pg0->flags) &
14627188c03fSSreekanth Reddy 	      MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4));
14637188c03fSSreekanth Reddy }
14647188c03fSSreekanth Reddy 
14657188c03fSSreekanth Reddy /**
14667188c03fSSreekanth Reddy  * mpi3mr_encldev_add_chg_evt_bh - Enclosure evt bottomhalf
14677188c03fSSreekanth Reddy  * @mrioc: Adapter instance reference
14687188c03fSSreekanth Reddy  * @fwevt: Firmware event reference
14697188c03fSSreekanth Reddy  *
14707188c03fSSreekanth Reddy  * Prints information about the Enclosure device status or
14717188c03fSSreekanth Reddy  * Enclosure add events if logging is enabled and add or remove
14727188c03fSSreekanth Reddy  * the enclosure from the controller's internal list of
14737188c03fSSreekanth Reddy  * enclosures.
14747188c03fSSreekanth Reddy  *
14757188c03fSSreekanth Reddy  * Return: Nothing.
14767188c03fSSreekanth Reddy  */
mpi3mr_encldev_add_chg_evt_bh(struct mpi3mr_ioc * mrioc,struct mpi3mr_fwevt * fwevt)14777188c03fSSreekanth Reddy static void mpi3mr_encldev_add_chg_evt_bh(struct mpi3mr_ioc *mrioc,
14787188c03fSSreekanth Reddy 	struct mpi3mr_fwevt *fwevt)
14797188c03fSSreekanth Reddy {
14807188c03fSSreekanth Reddy 	struct mpi3mr_enclosure_node *enclosure_dev = NULL;
14817188c03fSSreekanth Reddy 	struct mpi3_enclosure_page0 *encl_pg0;
14827188c03fSSreekanth Reddy 	u16 encl_handle;
14837188c03fSSreekanth Reddy 	u8 added, present;
14847188c03fSSreekanth Reddy 
14857188c03fSSreekanth Reddy 	encl_pg0 = (struct mpi3_enclosure_page0 *) fwevt->event_data;
14867188c03fSSreekanth Reddy 	added = (fwevt->event_id == MPI3_EVENT_ENCL_DEVICE_ADDED) ? 1 : 0;
14877188c03fSSreekanth Reddy 	mpi3mr_encldev_add_chg_evt_debug(mrioc, encl_pg0, added);
14887188c03fSSreekanth Reddy 
14897188c03fSSreekanth Reddy 
14907188c03fSSreekanth Reddy 	encl_handle = le16_to_cpu(encl_pg0->enclosure_handle);
14917188c03fSSreekanth Reddy 	present = ((le16_to_cpu(encl_pg0->flags) &
14927188c03fSSreekanth Reddy 	      MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4);
14937188c03fSSreekanth Reddy 
14947188c03fSSreekanth Reddy 	if (encl_handle)
14957188c03fSSreekanth Reddy 		enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc,
14967188c03fSSreekanth Reddy 		    encl_handle);
14977188c03fSSreekanth Reddy 	if (!enclosure_dev && present) {
14987188c03fSSreekanth Reddy 		enclosure_dev =
14997188c03fSSreekanth Reddy 			kzalloc(sizeof(struct mpi3mr_enclosure_node),
15007188c03fSSreekanth Reddy 			    GFP_KERNEL);
15017188c03fSSreekanth Reddy 		if (!enclosure_dev)
15027188c03fSSreekanth Reddy 			return;
15037188c03fSSreekanth Reddy 		list_add_tail(&enclosure_dev->list,
15047188c03fSSreekanth Reddy 		    &mrioc->enclosure_list);
15057188c03fSSreekanth Reddy 	}
15067188c03fSSreekanth Reddy 	if (enclosure_dev) {
15077188c03fSSreekanth Reddy 		if (!present) {
15087188c03fSSreekanth Reddy 			list_del(&enclosure_dev->list);
15097188c03fSSreekanth Reddy 			kfree(enclosure_dev);
15107188c03fSSreekanth Reddy 		} else
15117188c03fSSreekanth Reddy 			memcpy(&enclosure_dev->pg0, encl_pg0,
15127188c03fSSreekanth Reddy 			    sizeof(enclosure_dev->pg0));
15137188c03fSSreekanth Reddy 
15147188c03fSSreekanth Reddy 	}
15157188c03fSSreekanth Reddy }
15167188c03fSSreekanth Reddy 
15177188c03fSSreekanth Reddy /**
15189fc4abfeSKashyap Desai  * mpi3mr_sastopochg_evt_debug - SASTopoChange details
15199fc4abfeSKashyap Desai  * @mrioc: Adapter instance reference
15209fc4abfeSKashyap Desai  * @event_data: SAS topology change list event data
15219fc4abfeSKashyap Desai  *
15229fc4abfeSKashyap Desai  * Prints information about the SAS topology change event.
15239fc4abfeSKashyap Desai  *
15249fc4abfeSKashyap Desai  * Return: Nothing.
15259fc4abfeSKashyap Desai  */
15269fc4abfeSKashyap Desai static void
mpi3mr_sastopochg_evt_debug(struct mpi3mr_ioc * mrioc,struct mpi3_event_data_sas_topology_change_list * event_data)15279fc4abfeSKashyap Desai mpi3mr_sastopochg_evt_debug(struct mpi3mr_ioc *mrioc,
15289fc4abfeSKashyap Desai 	struct mpi3_event_data_sas_topology_change_list *event_data)
15299fc4abfeSKashyap Desai {
15309fc4abfeSKashyap Desai 	int i;
15319fc4abfeSKashyap Desai 	u16 handle;
15329fc4abfeSKashyap Desai 	u8 reason_code, phy_number;
15339fc4abfeSKashyap Desai 	char *status_str = NULL;
15349fc4abfeSKashyap Desai 	u8 link_rate, prev_link_rate;
15359fc4abfeSKashyap Desai 
15369fc4abfeSKashyap Desai 	switch (event_data->exp_status) {
15379fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
15389fc4abfeSKashyap Desai 		status_str = "remove";
15399fc4abfeSKashyap Desai 		break;
15409fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_TOPO_ES_RESPONDING:
15419fc4abfeSKashyap Desai 		status_str =  "responding";
15429fc4abfeSKashyap Desai 		break;
15439fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
15449fc4abfeSKashyap Desai 		status_str = "remove delay";
15459fc4abfeSKashyap Desai 		break;
15469fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_TOPO_ES_NO_EXPANDER:
15479fc4abfeSKashyap Desai 		status_str = "direct attached";
15489fc4abfeSKashyap Desai 		break;
15499fc4abfeSKashyap Desai 	default:
15509fc4abfeSKashyap Desai 		status_str = "unknown status";
15519fc4abfeSKashyap Desai 		break;
15529fc4abfeSKashyap Desai 	}
15539fc4abfeSKashyap Desai 	ioc_info(mrioc, "%s :sas topology change: (%s)\n",
15549fc4abfeSKashyap Desai 	    __func__, status_str);
15559fc4abfeSKashyap Desai 	ioc_info(mrioc,
1556c4723e68SSreekanth Reddy 	    "%s :\texpander_handle(0x%04x), port(%d), enclosure_handle(0x%04x) start_phy(%02d), num_entries(%d)\n",
15579fc4abfeSKashyap Desai 	    __func__, le16_to_cpu(event_data->expander_dev_handle),
1558c4723e68SSreekanth Reddy 	    event_data->io_unit_port,
15599fc4abfeSKashyap Desai 	    le16_to_cpu(event_data->enclosure_handle),
15609fc4abfeSKashyap Desai 	    event_data->start_phy_num, event_data->num_entries);
15619fc4abfeSKashyap Desai 	for (i = 0; i < event_data->num_entries; i++) {
15629fc4abfeSKashyap Desai 		handle = le16_to_cpu(event_data->phy_entry[i].attached_dev_handle);
15639fc4abfeSKashyap Desai 		if (!handle)
15649fc4abfeSKashyap Desai 			continue;
15659fc4abfeSKashyap Desai 		phy_number = event_data->start_phy_num + i;
15669fc4abfeSKashyap Desai 		reason_code = event_data->phy_entry[i].status &
15679fc4abfeSKashyap Desai 		    MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
15689fc4abfeSKashyap Desai 		switch (reason_code) {
15699fc4abfeSKashyap Desai 		case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
15709fc4abfeSKashyap Desai 			status_str = "target remove";
15719fc4abfeSKashyap Desai 			break;
15729fc4abfeSKashyap Desai 		case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING:
15739fc4abfeSKashyap Desai 			status_str = "delay target remove";
15749fc4abfeSKashyap Desai 			break;
15759fc4abfeSKashyap Desai 		case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
15769fc4abfeSKashyap Desai 			status_str = "link status change";
15779fc4abfeSKashyap Desai 			break;
15789fc4abfeSKashyap Desai 		case MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE:
15799fc4abfeSKashyap Desai 			status_str = "link status no change";
15809fc4abfeSKashyap Desai 			break;
15819fc4abfeSKashyap Desai 		case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING:
15829fc4abfeSKashyap Desai 			status_str = "target responding";
15839fc4abfeSKashyap Desai 			break;
15849fc4abfeSKashyap Desai 		default:
15859fc4abfeSKashyap Desai 			status_str = "unknown";
15869fc4abfeSKashyap Desai 			break;
15879fc4abfeSKashyap Desai 		}
15889fc4abfeSKashyap Desai 		link_rate = event_data->phy_entry[i].link_rate >> 4;
15899fc4abfeSKashyap Desai 		prev_link_rate = event_data->phy_entry[i].link_rate & 0xF;
15909fc4abfeSKashyap Desai 		ioc_info(mrioc,
15919fc4abfeSKashyap Desai 		    "%s :\tphy(%02d), attached_handle(0x%04x): %s: link rate: new(0x%02x), old(0x%02x)\n",
15929fc4abfeSKashyap Desai 		    __func__, phy_number, handle, status_str, link_rate,
15939fc4abfeSKashyap Desai 		    prev_link_rate);
15949fc4abfeSKashyap Desai 	}
15959fc4abfeSKashyap Desai }
15969fc4abfeSKashyap Desai 
15979fc4abfeSKashyap Desai /**
159813ef29eaSKashyap Desai  * mpi3mr_sastopochg_evt_bh - SASTopologyChange evt bottomhalf
159913ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
160013ef29eaSKashyap Desai  * @fwevt: Firmware event reference
160113ef29eaSKashyap Desai  *
160213ef29eaSKashyap Desai  * Prints information about the SAS topology change event and
160313ef29eaSKashyap Desai  * for "not responding" event code, removes the device from the
160413ef29eaSKashyap Desai  * upper layers.
160513ef29eaSKashyap Desai  *
160613ef29eaSKashyap Desai  * Return: Nothing.
160713ef29eaSKashyap Desai  */
mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc * mrioc,struct mpi3mr_fwevt * fwevt)160813ef29eaSKashyap Desai static void mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc *mrioc,
160913ef29eaSKashyap Desai 	struct mpi3mr_fwevt *fwevt)
161013ef29eaSKashyap Desai {
161113ef29eaSKashyap Desai 	struct mpi3_event_data_sas_topology_change_list *event_data =
161213ef29eaSKashyap Desai 	    (struct mpi3_event_data_sas_topology_change_list *)fwevt->event_data;
161313ef29eaSKashyap Desai 	int i;
161413ef29eaSKashyap Desai 	u16 handle;
161513ef29eaSKashyap Desai 	u8 reason_code;
16167f56c791SSreekanth Reddy 	u64 exp_sas_address = 0, parent_sas_address = 0;
1617e22bae30SSreekanth Reddy 	struct mpi3mr_hba_port *hba_port = NULL;
161813ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev = NULL;
1619e22bae30SSreekanth Reddy 	struct mpi3mr_sas_node *sas_expander = NULL;
16207f56c791SSreekanth Reddy 	unsigned long flags;
16217f56c791SSreekanth Reddy 	u8 link_rate, prev_link_rate, parent_phy_number;
162213ef29eaSKashyap Desai 
16239fc4abfeSKashyap Desai 	mpi3mr_sastopochg_evt_debug(mrioc, event_data);
16247f56c791SSreekanth Reddy 	if (mrioc->sas_transport_enabled) {
16257f56c791SSreekanth Reddy 		hba_port = mpi3mr_get_hba_port_by_id(mrioc,
16267f56c791SSreekanth Reddy 		    event_data->io_unit_port);
16277f56c791SSreekanth Reddy 		if (le16_to_cpu(event_data->expander_dev_handle)) {
16287f56c791SSreekanth Reddy 			spin_lock_irqsave(&mrioc->sas_node_lock, flags);
16297f56c791SSreekanth Reddy 			sas_expander = __mpi3mr_expander_find_by_handle(mrioc,
16307f56c791SSreekanth Reddy 			    le16_to_cpu(event_data->expander_dev_handle));
16317f56c791SSreekanth Reddy 			if (sas_expander) {
16327f56c791SSreekanth Reddy 				exp_sas_address = sas_expander->sas_address;
16337f56c791SSreekanth Reddy 				hba_port = sas_expander->hba_port;
16347f56c791SSreekanth Reddy 			}
16357f56c791SSreekanth Reddy 			spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
16367f56c791SSreekanth Reddy 			parent_sas_address = exp_sas_address;
16377f56c791SSreekanth Reddy 		} else
16387f56c791SSreekanth Reddy 			parent_sas_address = mrioc->sas_hba.sas_address;
16397f56c791SSreekanth Reddy 	}
16409fc4abfeSKashyap Desai 
164113ef29eaSKashyap Desai 	for (i = 0; i < event_data->num_entries; i++) {
1642580e6742SSreekanth Reddy 		if (fwevt->discard)
1643580e6742SSreekanth Reddy 			return;
164413ef29eaSKashyap Desai 		handle = le16_to_cpu(event_data->phy_entry[i].attached_dev_handle);
164513ef29eaSKashyap Desai 		if (!handle)
164613ef29eaSKashyap Desai 			continue;
164713ef29eaSKashyap Desai 		tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
164813ef29eaSKashyap Desai 		if (!tgtdev)
164913ef29eaSKashyap Desai 			continue;
165013ef29eaSKashyap Desai 
165113ef29eaSKashyap Desai 		reason_code = event_data->phy_entry[i].status &
165213ef29eaSKashyap Desai 		    MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
165313ef29eaSKashyap Desai 
165413ef29eaSKashyap Desai 		switch (reason_code) {
165513ef29eaSKashyap Desai 		case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
165613ef29eaSKashyap Desai 			if (tgtdev->host_exposed)
165713ef29eaSKashyap Desai 				mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
16583f1254edSRanjan Kumar 			mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, false);
165913ef29eaSKashyap Desai 			mpi3mr_tgtdev_put(tgtdev);
166013ef29eaSKashyap Desai 			break;
16617f56c791SSreekanth Reddy 		case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING:
16627f56c791SSreekanth Reddy 		case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
16637f56c791SSreekanth Reddy 		case MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE:
16647f56c791SSreekanth Reddy 		{
16657f56c791SSreekanth Reddy 			if (!mrioc->sas_transport_enabled || tgtdev->non_stl
16667f56c791SSreekanth Reddy 			    || tgtdev->is_hidden)
16677f56c791SSreekanth Reddy 				break;
16687f56c791SSreekanth Reddy 			link_rate = event_data->phy_entry[i].link_rate >> 4;
16697f56c791SSreekanth Reddy 			prev_link_rate = event_data->phy_entry[i].link_rate & 0xF;
16707f56c791SSreekanth Reddy 			if (link_rate == prev_link_rate)
16717f56c791SSreekanth Reddy 				break;
16727f56c791SSreekanth Reddy 			if (!parent_sas_address)
16737f56c791SSreekanth Reddy 				break;
16747f56c791SSreekanth Reddy 			parent_phy_number = event_data->start_phy_num + i;
16757f56c791SSreekanth Reddy 			mpi3mr_update_links(mrioc, parent_sas_address, handle,
16767f56c791SSreekanth Reddy 			    parent_phy_number, link_rate, hba_port);
16777f56c791SSreekanth Reddy 			break;
16787f56c791SSreekanth Reddy 		}
167913ef29eaSKashyap Desai 		default:
168013ef29eaSKashyap Desai 			break;
168113ef29eaSKashyap Desai 		}
168213ef29eaSKashyap Desai 		if (tgtdev)
168313ef29eaSKashyap Desai 			mpi3mr_tgtdev_put(tgtdev);
168413ef29eaSKashyap Desai 	}
1685e22bae30SSreekanth Reddy 
1686e22bae30SSreekanth Reddy 	if (mrioc->sas_transport_enabled && (event_data->exp_status ==
1687e22bae30SSreekanth Reddy 	    MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING)) {
1688e22bae30SSreekanth Reddy 		if (sas_expander)
1689e22bae30SSreekanth Reddy 			mpi3mr_expander_remove(mrioc, exp_sas_address,
1690e22bae30SSreekanth Reddy 			    hba_port);
1691e22bae30SSreekanth Reddy 	}
169213ef29eaSKashyap Desai }
169313ef29eaSKashyap Desai 
169413ef29eaSKashyap Desai /**
16959fc4abfeSKashyap Desai  * mpi3mr_pcietopochg_evt_debug - PCIeTopoChange details
16969fc4abfeSKashyap Desai  * @mrioc: Adapter instance reference
16979fc4abfeSKashyap Desai  * @event_data: PCIe topology change list event data
16989fc4abfeSKashyap Desai  *
16999fc4abfeSKashyap Desai  * Prints information about the PCIe topology change event.
17009fc4abfeSKashyap Desai  *
17019fc4abfeSKashyap Desai  * Return: Nothing.
17029fc4abfeSKashyap Desai  */
17039fc4abfeSKashyap Desai static void
mpi3mr_pcietopochg_evt_debug(struct mpi3mr_ioc * mrioc,struct mpi3_event_data_pcie_topology_change_list * event_data)17049fc4abfeSKashyap Desai mpi3mr_pcietopochg_evt_debug(struct mpi3mr_ioc *mrioc,
17059fc4abfeSKashyap Desai 	struct mpi3_event_data_pcie_topology_change_list *event_data)
17069fc4abfeSKashyap Desai {
17079fc4abfeSKashyap Desai 	int i;
17089fc4abfeSKashyap Desai 	u16 handle;
17099fc4abfeSKashyap Desai 	u16 reason_code;
17109fc4abfeSKashyap Desai 	u8 port_number;
17119fc4abfeSKashyap Desai 	char *status_str = NULL;
17129fc4abfeSKashyap Desai 	u8 link_rate, prev_link_rate;
17139fc4abfeSKashyap Desai 
17149fc4abfeSKashyap Desai 	switch (event_data->switch_status) {
17159fc4abfeSKashyap Desai 	case MPI3_EVENT_PCIE_TOPO_SS_NOT_RESPONDING:
17169fc4abfeSKashyap Desai 		status_str = "remove";
17179fc4abfeSKashyap Desai 		break;
17189fc4abfeSKashyap Desai 	case MPI3_EVENT_PCIE_TOPO_SS_RESPONDING:
17199fc4abfeSKashyap Desai 		status_str =  "responding";
17209fc4abfeSKashyap Desai 		break;
17219fc4abfeSKashyap Desai 	case MPI3_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING:
17229fc4abfeSKashyap Desai 		status_str = "remove delay";
17239fc4abfeSKashyap Desai 		break;
17249fc4abfeSKashyap Desai 	case MPI3_EVENT_PCIE_TOPO_SS_NO_PCIE_SWITCH:
17259fc4abfeSKashyap Desai 		status_str = "direct attached";
17269fc4abfeSKashyap Desai 		break;
17279fc4abfeSKashyap Desai 	default:
17289fc4abfeSKashyap Desai 		status_str = "unknown status";
17299fc4abfeSKashyap Desai 		break;
17309fc4abfeSKashyap Desai 	}
17319fc4abfeSKashyap Desai 	ioc_info(mrioc, "%s :pcie topology change: (%s)\n",
17329fc4abfeSKashyap Desai 	    __func__, status_str);
17339fc4abfeSKashyap Desai 	ioc_info(mrioc,
17349fc4abfeSKashyap Desai 	    "%s :\tswitch_handle(0x%04x), enclosure_handle(0x%04x) start_port(%02d), num_entries(%d)\n",
17359fc4abfeSKashyap Desai 	    __func__, le16_to_cpu(event_data->switch_dev_handle),
17369fc4abfeSKashyap Desai 	    le16_to_cpu(event_data->enclosure_handle),
17379fc4abfeSKashyap Desai 	    event_data->start_port_num, event_data->num_entries);
17389fc4abfeSKashyap Desai 	for (i = 0; i < event_data->num_entries; i++) {
17399fc4abfeSKashyap Desai 		handle =
17409fc4abfeSKashyap Desai 		    le16_to_cpu(event_data->port_entry[i].attached_dev_handle);
17419fc4abfeSKashyap Desai 		if (!handle)
17429fc4abfeSKashyap Desai 			continue;
17439fc4abfeSKashyap Desai 		port_number = event_data->start_port_num + i;
17449fc4abfeSKashyap Desai 		reason_code = event_data->port_entry[i].port_status;
17459fc4abfeSKashyap Desai 		switch (reason_code) {
17469fc4abfeSKashyap Desai 		case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
17479fc4abfeSKashyap Desai 			status_str = "target remove";
17489fc4abfeSKashyap Desai 			break;
17499fc4abfeSKashyap Desai 		case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING:
17509fc4abfeSKashyap Desai 			status_str = "delay target remove";
17519fc4abfeSKashyap Desai 			break;
17529fc4abfeSKashyap Desai 		case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
17539fc4abfeSKashyap Desai 			status_str = "link status change";
17549fc4abfeSKashyap Desai 			break;
17559fc4abfeSKashyap Desai 		case MPI3_EVENT_PCIE_TOPO_PS_NO_CHANGE:
17569fc4abfeSKashyap Desai 			status_str = "link status no change";
17579fc4abfeSKashyap Desai 			break;
17589fc4abfeSKashyap Desai 		case MPI3_EVENT_PCIE_TOPO_PS_RESPONDING:
17599fc4abfeSKashyap Desai 			status_str = "target responding";
17609fc4abfeSKashyap Desai 			break;
17619fc4abfeSKashyap Desai 		default:
17629fc4abfeSKashyap Desai 			status_str = "unknown";
17639fc4abfeSKashyap Desai 			break;
17649fc4abfeSKashyap Desai 		}
17659fc4abfeSKashyap Desai 		link_rate = event_data->port_entry[i].current_port_info &
17669fc4abfeSKashyap Desai 		    MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK;
17679fc4abfeSKashyap Desai 		prev_link_rate = event_data->port_entry[i].previous_port_info &
17689fc4abfeSKashyap Desai 		    MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK;
17699fc4abfeSKashyap Desai 		ioc_info(mrioc,
17709fc4abfeSKashyap Desai 		    "%s :\tport(%02d), attached_handle(0x%04x): %s: link rate: new(0x%02x), old(0x%02x)\n",
17719fc4abfeSKashyap Desai 		    __func__, port_number, handle, status_str, link_rate,
17729fc4abfeSKashyap Desai 		    prev_link_rate);
17739fc4abfeSKashyap Desai 	}
17749fc4abfeSKashyap Desai }
17759fc4abfeSKashyap Desai 
17769fc4abfeSKashyap Desai /**
17778e653455SKashyap Desai  * mpi3mr_pcietopochg_evt_bh - PCIeTopologyChange evt bottomhalf
17788e653455SKashyap Desai  * @mrioc: Adapter instance reference
17798e653455SKashyap Desai  * @fwevt: Firmware event reference
17808e653455SKashyap Desai  *
17818e653455SKashyap Desai  * Prints information about the PCIe topology change event and
17828e653455SKashyap Desai  * for "not responding" event code, removes the device from the
17838e653455SKashyap Desai  * upper layers.
17848e653455SKashyap Desai  *
17858e653455SKashyap Desai  * Return: Nothing.
17868e653455SKashyap Desai  */
mpi3mr_pcietopochg_evt_bh(struct mpi3mr_ioc * mrioc,struct mpi3mr_fwevt * fwevt)17878e653455SKashyap Desai static void mpi3mr_pcietopochg_evt_bh(struct mpi3mr_ioc *mrioc,
17888e653455SKashyap Desai 	struct mpi3mr_fwevt *fwevt)
17898e653455SKashyap Desai {
17908e653455SKashyap Desai 	struct mpi3_event_data_pcie_topology_change_list *event_data =
17918e653455SKashyap Desai 	    (struct mpi3_event_data_pcie_topology_change_list *)fwevt->event_data;
17928e653455SKashyap Desai 	int i;
17938e653455SKashyap Desai 	u16 handle;
17948e653455SKashyap Desai 	u8 reason_code;
17958e653455SKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev = NULL;
17968e653455SKashyap Desai 
17979fc4abfeSKashyap Desai 	mpi3mr_pcietopochg_evt_debug(mrioc, event_data);
17989fc4abfeSKashyap Desai 
17998e653455SKashyap Desai 	for (i = 0; i < event_data->num_entries; i++) {
1800580e6742SSreekanth Reddy 		if (fwevt->discard)
1801580e6742SSreekanth Reddy 			return;
18028e653455SKashyap Desai 		handle =
18038e653455SKashyap Desai 		    le16_to_cpu(event_data->port_entry[i].attached_dev_handle);
18048e653455SKashyap Desai 		if (!handle)
18058e653455SKashyap Desai 			continue;
18068e653455SKashyap Desai 		tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
18078e653455SKashyap Desai 		if (!tgtdev)
18088e653455SKashyap Desai 			continue;
18098e653455SKashyap Desai 
18108e653455SKashyap Desai 		reason_code = event_data->port_entry[i].port_status;
18118e653455SKashyap Desai 
18128e653455SKashyap Desai 		switch (reason_code) {
18138e653455SKashyap Desai 		case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
18148e653455SKashyap Desai 			if (tgtdev->host_exposed)
18158e653455SKashyap Desai 				mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
18163f1254edSRanjan Kumar 			mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, false);
18178e653455SKashyap Desai 			mpi3mr_tgtdev_put(tgtdev);
18188e653455SKashyap Desai 			break;
18198e653455SKashyap Desai 		default:
18208e653455SKashyap Desai 			break;
18218e653455SKashyap Desai 		}
18228e653455SKashyap Desai 		if (tgtdev)
18238e653455SKashyap Desai 			mpi3mr_tgtdev_put(tgtdev);
18248e653455SKashyap Desai 	}
18258e653455SKashyap Desai }
18268e653455SKashyap Desai 
18278e653455SKashyap Desai /**
182843ca1100SSumit Saxena  * mpi3mr_logdata_evt_bh -  Log data event bottomhalf
182943ca1100SSumit Saxena  * @mrioc: Adapter instance reference
183043ca1100SSumit Saxena  * @fwevt: Firmware event reference
183143ca1100SSumit Saxena  *
183243ca1100SSumit Saxena  * Extracts the event data and calls application interfacing
183343ca1100SSumit Saxena  * function to process the event further.
183443ca1100SSumit Saxena  *
183543ca1100SSumit Saxena  * Return: Nothing.
183643ca1100SSumit Saxena  */
mpi3mr_logdata_evt_bh(struct mpi3mr_ioc * mrioc,struct mpi3mr_fwevt * fwevt)183743ca1100SSumit Saxena static void mpi3mr_logdata_evt_bh(struct mpi3mr_ioc *mrioc,
183843ca1100SSumit Saxena 	struct mpi3mr_fwevt *fwevt)
183943ca1100SSumit Saxena {
184043ca1100SSumit Saxena 	mpi3mr_app_save_logdata(mrioc, fwevt->event_data,
184143ca1100SSumit Saxena 	    fwevt->event_data_size);
184243ca1100SSumit Saxena }
184343ca1100SSumit Saxena 
184443ca1100SSumit Saxena /**
1845cf1ce8b7SSreekanth Reddy  * mpi3mr_update_sdev_qd - Update SCSI device queue depath
1846cf1ce8b7SSreekanth Reddy  * @sdev: SCSI device reference
1847cf1ce8b7SSreekanth Reddy  * @data: Queue depth reference
1848cf1ce8b7SSreekanth Reddy  *
1849cf1ce8b7SSreekanth Reddy  * This is an iterator function called for each SCSI device in a
1850cf1ce8b7SSreekanth Reddy  * target to update the QD of each SCSI device.
1851cf1ce8b7SSreekanth Reddy  *
1852cf1ce8b7SSreekanth Reddy  * Return: Nothing.
1853cf1ce8b7SSreekanth Reddy  */
mpi3mr_update_sdev_qd(struct scsi_device * sdev,void * data)1854cf1ce8b7SSreekanth Reddy static void mpi3mr_update_sdev_qd(struct scsi_device *sdev, void *data)
1855cf1ce8b7SSreekanth Reddy {
1856cf1ce8b7SSreekanth Reddy 	u16 *q_depth = (u16 *)data;
1857cf1ce8b7SSreekanth Reddy 
1858cf1ce8b7SSreekanth Reddy 	scsi_change_queue_depth(sdev, (int)*q_depth);
1859cf1ce8b7SSreekanth Reddy 	sdev->max_queue_depth = sdev->queue_depth;
1860cf1ce8b7SSreekanth Reddy }
1861cf1ce8b7SSreekanth Reddy 
1862cf1ce8b7SSreekanth Reddy /**
1863cf1ce8b7SSreekanth Reddy  * mpi3mr_set_qd_for_all_vd_in_tg -set QD for TG VDs
1864cf1ce8b7SSreekanth Reddy  * @mrioc: Adapter instance reference
1865cf1ce8b7SSreekanth Reddy  * @tg: Throttle group information pointer
1866cf1ce8b7SSreekanth Reddy  *
1867cf1ce8b7SSreekanth Reddy  * Accessor to reduce QD for each device associated with the
1868cf1ce8b7SSreekanth Reddy  * given throttle group.
1869cf1ce8b7SSreekanth Reddy  *
1870cf1ce8b7SSreekanth Reddy  * Return: None.
1871cf1ce8b7SSreekanth Reddy  */
mpi3mr_set_qd_for_all_vd_in_tg(struct mpi3mr_ioc * mrioc,struct mpi3mr_throttle_group_info * tg)1872cf1ce8b7SSreekanth Reddy static void mpi3mr_set_qd_for_all_vd_in_tg(struct mpi3mr_ioc *mrioc,
1873cf1ce8b7SSreekanth Reddy 	struct mpi3mr_throttle_group_info *tg)
1874cf1ce8b7SSreekanth Reddy {
1875cf1ce8b7SSreekanth Reddy 	unsigned long flags;
1876cf1ce8b7SSreekanth Reddy 	struct mpi3mr_tgt_dev *tgtdev;
1877cf1ce8b7SSreekanth Reddy 	struct mpi3mr_stgt_priv_data *tgt_priv;
1878cf1ce8b7SSreekanth Reddy 
1879cf1ce8b7SSreekanth Reddy 
1880cf1ce8b7SSreekanth Reddy 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
1881cf1ce8b7SSreekanth Reddy 	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
1882cf1ce8b7SSreekanth Reddy 		if (tgtdev->starget && tgtdev->starget->hostdata) {
1883cf1ce8b7SSreekanth Reddy 			tgt_priv = tgtdev->starget->hostdata;
1884cf1ce8b7SSreekanth Reddy 			if (tgt_priv->throttle_group == tg) {
1885cf1ce8b7SSreekanth Reddy 				dprint_event_bh(mrioc,
1886cf1ce8b7SSreekanth Reddy 				    "updating qd due to throttling for persist_id(%d) original_qd(%d), reduced_qd (%d)\n",
1887cf1ce8b7SSreekanth Reddy 				    tgt_priv->perst_id, tgtdev->q_depth,
1888cf1ce8b7SSreekanth Reddy 				    tg->modified_qd);
1889cf1ce8b7SSreekanth Reddy 				starget_for_each_device(tgtdev->starget,
1890cf1ce8b7SSreekanth Reddy 				    (void *)&tg->modified_qd,
1891cf1ce8b7SSreekanth Reddy 				    mpi3mr_update_sdev_qd);
1892cf1ce8b7SSreekanth Reddy 			}
1893cf1ce8b7SSreekanth Reddy 		}
1894cf1ce8b7SSreekanth Reddy 	}
1895cf1ce8b7SSreekanth Reddy 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
1896cf1ce8b7SSreekanth Reddy }
1897cf1ce8b7SSreekanth Reddy 
1898cf1ce8b7SSreekanth Reddy /**
189913ef29eaSKashyap Desai  * mpi3mr_fwevt_bh - Firmware event bottomhalf handler
190013ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
190113ef29eaSKashyap Desai  * @fwevt: Firmware event reference
190213ef29eaSKashyap Desai  *
190313ef29eaSKashyap Desai  * Identifies the firmware event and calls corresponding bottomg
190413ef29eaSKashyap Desai  * half handler and sends event acknowledgment if required.
190513ef29eaSKashyap Desai  *
190613ef29eaSKashyap Desai  * Return: Nothing.
190713ef29eaSKashyap Desai  */
mpi3mr_fwevt_bh(struct mpi3mr_ioc * mrioc,struct mpi3mr_fwevt * fwevt)190813ef29eaSKashyap Desai static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
190913ef29eaSKashyap Desai 	struct mpi3mr_fwevt *fwevt)
191013ef29eaSKashyap Desai {
1911c4723e68SSreekanth Reddy 	struct mpi3_device_page0 *dev_pg0 = NULL;
1912e22bae30SSreekanth Reddy 	u16 perst_id, handle, dev_info;
1913e22bae30SSreekanth Reddy 	struct mpi3_device0_sas_sata_format *sasinf = NULL;
1914c4723e68SSreekanth Reddy 
191513ef29eaSKashyap Desai 	mpi3mr_fwevt_del_from_list(mrioc, fwevt);
1916580e6742SSreekanth Reddy 	mrioc->current_event = fwevt;
191713ef29eaSKashyap Desai 
191813ef29eaSKashyap Desai 	if (mrioc->stop_drv_processing)
191913ef29eaSKashyap Desai 		goto out;
192013ef29eaSKashyap Desai 
1921f2a79d20SSreekanth Reddy 	if (mrioc->unrecoverable) {
1922f2a79d20SSreekanth Reddy 		dprint_event_bh(mrioc,
1923f2a79d20SSreekanth Reddy 		    "ignoring event(0x%02x) in bottom half handler due to unrecoverable controller\n",
1924f2a79d20SSreekanth Reddy 		    fwevt->event_id);
1925f2a79d20SSreekanth Reddy 		goto out;
1926f2a79d20SSreekanth Reddy 	}
1927f2a79d20SSreekanth Reddy 
192813ef29eaSKashyap Desai 	if (!fwevt->process_evt)
192913ef29eaSKashyap Desai 		goto evt_ack;
193013ef29eaSKashyap Desai 
193113ef29eaSKashyap Desai 	switch (fwevt->event_id) {
193213ef29eaSKashyap Desai 	case MPI3_EVENT_DEVICE_ADDED:
193313ef29eaSKashyap Desai 	{
1934e22bae30SSreekanth Reddy 		dev_pg0 = (struct mpi3_device_page0 *)fwevt->event_data;
1935e22bae30SSreekanth Reddy 		perst_id = le16_to_cpu(dev_pg0->persistent_id);
1936e22bae30SSreekanth Reddy 		handle = le16_to_cpu(dev_pg0->dev_handle);
1937e22bae30SSreekanth Reddy 		if (perst_id != MPI3_DEVICE0_PERSISTENTID_INVALID)
1938e22bae30SSreekanth Reddy 			mpi3mr_report_tgtdev_to_host(mrioc, perst_id);
1939e22bae30SSreekanth Reddy 		else if (mrioc->sas_transport_enabled &&
1940e22bae30SSreekanth Reddy 		    (dev_pg0->device_form == MPI3_DEVICE_DEVFORM_SAS_SATA)) {
1941e22bae30SSreekanth Reddy 			sasinf = &dev_pg0->device_specific.sas_sata_format;
1942e22bae30SSreekanth Reddy 			dev_info = le16_to_cpu(sasinf->device_info);
1943e22bae30SSreekanth Reddy 			if (!mrioc->sas_hba.num_phys)
1944e22bae30SSreekanth Reddy 				mpi3mr_sas_host_add(mrioc);
1945e22bae30SSreekanth Reddy 			else
1946e22bae30SSreekanth Reddy 				mpi3mr_sas_host_refresh(mrioc);
1947e22bae30SSreekanth Reddy 
1948e22bae30SSreekanth Reddy 			if (mpi3mr_is_expander_device(dev_info))
1949e22bae30SSreekanth Reddy 				mpi3mr_expander_add(mrioc, handle);
1950e22bae30SSreekanth Reddy 		}
195113ef29eaSKashyap Desai 		break;
195213ef29eaSKashyap Desai 	}
195313ef29eaSKashyap Desai 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
195413ef29eaSKashyap Desai 	{
1955c4723e68SSreekanth Reddy 		dev_pg0 = (struct mpi3_device_page0 *)fwevt->event_data;
1956c4723e68SSreekanth Reddy 		perst_id = le16_to_cpu(dev_pg0->persistent_id);
1957c4723e68SSreekanth Reddy 		if (perst_id != MPI3_DEVICE0_PERSISTENTID_INVALID)
1958c4723e68SSreekanth Reddy 			mpi3mr_devinfochg_evt_bh(mrioc, dev_pg0);
195913ef29eaSKashyap Desai 		break;
196013ef29eaSKashyap Desai 	}
196113ef29eaSKashyap Desai 	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
196213ef29eaSKashyap Desai 	{
196313ef29eaSKashyap Desai 		mpi3mr_devstatuschg_evt_bh(mrioc, fwevt);
196413ef29eaSKashyap Desai 		break;
196513ef29eaSKashyap Desai 	}
19667188c03fSSreekanth Reddy 	case MPI3_EVENT_ENCL_DEVICE_ADDED:
19677188c03fSSreekanth Reddy 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
19687188c03fSSreekanth Reddy 	{
19697188c03fSSreekanth Reddy 		mpi3mr_encldev_add_chg_evt_bh(mrioc, fwevt);
19707188c03fSSreekanth Reddy 		break;
19717188c03fSSreekanth Reddy 	}
19727188c03fSSreekanth Reddy 
197313ef29eaSKashyap Desai 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
197413ef29eaSKashyap Desai 	{
197513ef29eaSKashyap Desai 		mpi3mr_sastopochg_evt_bh(mrioc, fwevt);
197613ef29eaSKashyap Desai 		break;
197713ef29eaSKashyap Desai 	}
19788e653455SKashyap Desai 	case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
19798e653455SKashyap Desai 	{
19808e653455SKashyap Desai 		mpi3mr_pcietopochg_evt_bh(mrioc, fwevt);
19818e653455SKashyap Desai 		break;
19828e653455SKashyap Desai 	}
198343ca1100SSumit Saxena 	case MPI3_EVENT_LOG_DATA:
198443ca1100SSumit Saxena 	{
198543ca1100SSumit Saxena 		mpi3mr_logdata_evt_bh(mrioc, fwevt);
198643ca1100SSumit Saxena 		break;
198743ca1100SSumit Saxena 	}
1988cf1ce8b7SSreekanth Reddy 	case MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION:
1989cf1ce8b7SSreekanth Reddy 	{
1990cf1ce8b7SSreekanth Reddy 		struct mpi3mr_throttle_group_info *tg;
1991cf1ce8b7SSreekanth Reddy 
1992cf1ce8b7SSreekanth Reddy 		tg = *(struct mpi3mr_throttle_group_info **)fwevt->event_data;
1993cf1ce8b7SSreekanth Reddy 		dprint_event_bh(mrioc,
1994cf1ce8b7SSreekanth Reddy 		    "qd reduction event processed for tg_id(%d) reduction_needed(%d)\n",
1995cf1ce8b7SSreekanth Reddy 		    tg->id, tg->need_qd_reduction);
1996cf1ce8b7SSreekanth Reddy 		if (tg->need_qd_reduction) {
1997cf1ce8b7SSreekanth Reddy 			mpi3mr_set_qd_for_all_vd_in_tg(mrioc, tg);
1998cf1ce8b7SSreekanth Reddy 			tg->need_qd_reduction = 0;
1999cf1ce8b7SSreekanth Reddy 		}
2000cf1ce8b7SSreekanth Reddy 		break;
2001cf1ce8b7SSreekanth Reddy 	}
20022745ce0eSSreekanth Reddy 	case MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH:
20032745ce0eSSreekanth Reddy 	{
20042745ce0eSSreekanth Reddy 		while (mrioc->device_refresh_on)
20052745ce0eSSreekanth Reddy 			msleep(500);
20062745ce0eSSreekanth Reddy 
20072745ce0eSSreekanth Reddy 		dprint_event_bh(mrioc,
20082745ce0eSSreekanth Reddy 		    "scan for non responding and newly added devices after soft reset started\n");
20092745ce0eSSreekanth Reddy 		if (mrioc->sas_transport_enabled) {
20102745ce0eSSreekanth Reddy 			mpi3mr_refresh_sas_ports(mrioc);
20112745ce0eSSreekanth Reddy 			mpi3mr_refresh_expanders(mrioc);
20122745ce0eSSreekanth Reddy 		}
20132745ce0eSSreekanth Reddy 		mpi3mr_rfresh_tgtdevs(mrioc);
20142745ce0eSSreekanth Reddy 		ioc_info(mrioc,
20152745ce0eSSreekanth Reddy 		    "scan for non responding and newly added devices after soft reset completed\n");
20162745ce0eSSreekanth Reddy 		break;
20172745ce0eSSreekanth Reddy 	}
201813ef29eaSKashyap Desai 	default:
201913ef29eaSKashyap Desai 		break;
202013ef29eaSKashyap Desai 	}
202113ef29eaSKashyap Desai 
202213ef29eaSKashyap Desai evt_ack:
202313ef29eaSKashyap Desai 	if (fwevt->send_ack)
2024c1af985dSSreekanth Reddy 		mpi3mr_process_event_ack(mrioc, fwevt->event_id,
202513ef29eaSKashyap Desai 		    fwevt->evt_ctx);
202613ef29eaSKashyap Desai out:
202713ef29eaSKashyap Desai 	/* Put fwevt reference count to neutralize kref_init increment */
202813ef29eaSKashyap Desai 	mpi3mr_fwevt_put(fwevt);
202913ef29eaSKashyap Desai 	mrioc->current_event = NULL;
203013ef29eaSKashyap Desai }
203113ef29eaSKashyap Desai 
203213ef29eaSKashyap Desai /**
203313ef29eaSKashyap Desai  * mpi3mr_fwevt_worker - Firmware event worker
203413ef29eaSKashyap Desai  * @work: Work struct containing firmware event
203513ef29eaSKashyap Desai  *
203613ef29eaSKashyap Desai  * Extracts the firmware event and calls mpi3mr_fwevt_bh.
203713ef29eaSKashyap Desai  *
203813ef29eaSKashyap Desai  * Return: Nothing.
203913ef29eaSKashyap Desai  */
mpi3mr_fwevt_worker(struct work_struct * work)204013ef29eaSKashyap Desai static void mpi3mr_fwevt_worker(struct work_struct *work)
204113ef29eaSKashyap Desai {
204213ef29eaSKashyap Desai 	struct mpi3mr_fwevt *fwevt = container_of(work, struct mpi3mr_fwevt,
204313ef29eaSKashyap Desai 	    work);
204413ef29eaSKashyap Desai 	mpi3mr_fwevt_bh(fwevt->mrioc, fwevt);
204513ef29eaSKashyap Desai 	/*
204613ef29eaSKashyap Desai 	 * Put fwevt reference count after
204713ef29eaSKashyap Desai 	 * dequeuing it from worker queue
204813ef29eaSKashyap Desai 	 */
204913ef29eaSKashyap Desai 	mpi3mr_fwevt_put(fwevt);
205013ef29eaSKashyap Desai }
205113ef29eaSKashyap Desai 
205213ef29eaSKashyap Desai /**
205313ef29eaSKashyap Desai  * mpi3mr_create_tgtdev - Create and add a target device
205413ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
205513ef29eaSKashyap Desai  * @dev_pg0: Device Page 0 data
205613ef29eaSKashyap Desai  *
205713ef29eaSKashyap Desai  * If the device specified by the device page 0 data is not
205813ef29eaSKashyap Desai  * present in the driver's internal list, allocate the memory
205913ef29eaSKashyap Desai  * for the device, populate the data and add to the list, else
206013ef29eaSKashyap Desai  * update the device data.  The key is persistent ID.
206113ef29eaSKashyap Desai  *
206213ef29eaSKashyap Desai  * Return: 0 on success, -ENOMEM on memory allocation failure
206313ef29eaSKashyap Desai  */
mpi3mr_create_tgtdev(struct mpi3mr_ioc * mrioc,struct mpi3_device_page0 * dev_pg0)206413ef29eaSKashyap Desai static int mpi3mr_create_tgtdev(struct mpi3mr_ioc *mrioc,
206513ef29eaSKashyap Desai 	struct mpi3_device_page0 *dev_pg0)
206613ef29eaSKashyap Desai {
206713ef29eaSKashyap Desai 	int retval = 0;
206813ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev = NULL;
206913ef29eaSKashyap Desai 	u16 perst_id = 0;
20703f1254edSRanjan Kumar 	unsigned long flags;
207113ef29eaSKashyap Desai 
207213ef29eaSKashyap Desai 	perst_id = le16_to_cpu(dev_pg0->persistent_id);
2073c4723e68SSreekanth Reddy 	if (perst_id == MPI3_DEVICE0_PERSISTENTID_INVALID)
2074c4723e68SSreekanth Reddy 		return retval;
2075c4723e68SSreekanth Reddy 
20763f1254edSRanjan Kumar 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
20773f1254edSRanjan Kumar 	tgtdev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id);
20783f1254edSRanjan Kumar 	if (tgtdev)
20793f1254edSRanjan Kumar 		tgtdev->state = MPI3MR_DEV_CREATED;
20803f1254edSRanjan Kumar 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
20813f1254edSRanjan Kumar 
208213ef29eaSKashyap Desai 	if (tgtdev) {
2083f10af057SSreekanth Reddy 		mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, true);
208413ef29eaSKashyap Desai 		mpi3mr_tgtdev_put(tgtdev);
208513ef29eaSKashyap Desai 	} else {
208613ef29eaSKashyap Desai 		tgtdev = mpi3mr_alloc_tgtdev();
208713ef29eaSKashyap Desai 		if (!tgtdev)
208813ef29eaSKashyap Desai 			return -ENOMEM;
2089f10af057SSreekanth Reddy 		mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, true);
209013ef29eaSKashyap Desai 		mpi3mr_tgtdev_add_to_list(mrioc, tgtdev);
209113ef29eaSKashyap Desai 	}
209213ef29eaSKashyap Desai 
209313ef29eaSKashyap Desai 	return retval;
209413ef29eaSKashyap Desai }
209513ef29eaSKashyap Desai 
209613ef29eaSKashyap Desai /**
2097c1af985dSSreekanth Reddy  * mpi3mr_flush_delayed_cmd_lists - Flush pending commands
209813ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
209913ef29eaSKashyap Desai  *
2100c1af985dSSreekanth Reddy  * Flush pending commands in the delayed lists due to a
2101c1af985dSSreekanth Reddy  * controller reset or driver removal as a cleanup.
210213ef29eaSKashyap Desai  *
210313ef29eaSKashyap Desai  * Return: Nothing
210413ef29eaSKashyap Desai  */
mpi3mr_flush_delayed_cmd_lists(struct mpi3mr_ioc * mrioc)2105c1af985dSSreekanth Reddy void mpi3mr_flush_delayed_cmd_lists(struct mpi3mr_ioc *mrioc)
210613ef29eaSKashyap Desai {
210713ef29eaSKashyap Desai 	struct delayed_dev_rmhs_node *_rmhs_node;
2108c1af985dSSreekanth Reddy 	struct delayed_evt_ack_node *_evtack_node;
210913ef29eaSKashyap Desai 
2110c1af985dSSreekanth Reddy 	dprint_reset(mrioc, "flushing delayed dev_remove_hs commands\n");
211113ef29eaSKashyap Desai 	while (!list_empty(&mrioc->delayed_rmhs_list)) {
211213ef29eaSKashyap Desai 		_rmhs_node = list_entry(mrioc->delayed_rmhs_list.next,
211313ef29eaSKashyap Desai 		    struct delayed_dev_rmhs_node, list);
211413ef29eaSKashyap Desai 		list_del(&_rmhs_node->list);
211513ef29eaSKashyap Desai 		kfree(_rmhs_node);
211613ef29eaSKashyap Desai 	}
2117c1af985dSSreekanth Reddy 	dprint_reset(mrioc, "flushing delayed event ack commands\n");
2118c1af985dSSreekanth Reddy 	while (!list_empty(&mrioc->delayed_evtack_cmds_list)) {
2119c1af985dSSreekanth Reddy 		_evtack_node = list_entry(mrioc->delayed_evtack_cmds_list.next,
2120c1af985dSSreekanth Reddy 		    struct delayed_evt_ack_node, list);
2121c1af985dSSreekanth Reddy 		list_del(&_evtack_node->list);
2122c1af985dSSreekanth Reddy 		kfree(_evtack_node);
2123c1af985dSSreekanth Reddy 	}
212413ef29eaSKashyap Desai }
212513ef29eaSKashyap Desai 
212613ef29eaSKashyap Desai /**
212713ef29eaSKashyap Desai  * mpi3mr_dev_rmhs_complete_iou - Device removal IOUC completion
212813ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
212913ef29eaSKashyap Desai  * @drv_cmd: Internal command tracker
213013ef29eaSKashyap Desai  *
213113ef29eaSKashyap Desai  * Issues a target reset TM to the firmware from the device
213213ef29eaSKashyap Desai  * removal TM pend list or retry the removal handshake sequence
213313ef29eaSKashyap Desai  * based on the IOU control request IOC status.
213413ef29eaSKashyap Desai  *
213513ef29eaSKashyap Desai  * Return: Nothing
213613ef29eaSKashyap Desai  */
mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_ioc * mrioc,struct mpi3mr_drv_cmd * drv_cmd)213713ef29eaSKashyap Desai static void mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_ioc *mrioc,
213813ef29eaSKashyap Desai 	struct mpi3mr_drv_cmd *drv_cmd)
213913ef29eaSKashyap Desai {
214013ef29eaSKashyap Desai 	u16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
214113ef29eaSKashyap Desai 	struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL;
214213ef29eaSKashyap Desai 
2143b3911ab3SSreekanth Reddy 	if (drv_cmd->state & MPI3MR_CMD_RESET)
2144b3911ab3SSreekanth Reddy 		goto clear_drv_cmd;
2145b3911ab3SSreekanth Reddy 
214613ef29eaSKashyap Desai 	ioc_info(mrioc,
214713ef29eaSKashyap Desai 	    "%s :dev_rmhs_iouctrl_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x)\n",
214813ef29eaSKashyap Desai 	    __func__, drv_cmd->dev_handle, drv_cmd->ioc_status,
214913ef29eaSKashyap Desai 	    drv_cmd->ioc_loginfo);
215013ef29eaSKashyap Desai 	if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) {
215113ef29eaSKashyap Desai 		if (drv_cmd->retry_count < MPI3MR_DEV_RMHS_RETRY_COUNT) {
215213ef29eaSKashyap Desai 			drv_cmd->retry_count++;
215313ef29eaSKashyap Desai 			ioc_info(mrioc,
215413ef29eaSKashyap Desai 			    "%s :dev_rmhs_iouctrl_complete: handle(0x%04x)retrying handshake retry=%d\n",
215513ef29eaSKashyap Desai 			    __func__, drv_cmd->dev_handle,
215613ef29eaSKashyap Desai 			    drv_cmd->retry_count);
215713ef29eaSKashyap Desai 			mpi3mr_dev_rmhs_send_tm(mrioc, drv_cmd->dev_handle,
215813ef29eaSKashyap Desai 			    drv_cmd, drv_cmd->iou_rc);
215913ef29eaSKashyap Desai 			return;
216013ef29eaSKashyap Desai 		}
216113ef29eaSKashyap Desai 		ioc_err(mrioc,
216213ef29eaSKashyap Desai 		    "%s :dev removal handshake failed after all retries: handle(0x%04x)\n",
216313ef29eaSKashyap Desai 		    __func__, drv_cmd->dev_handle);
216413ef29eaSKashyap Desai 	} else {
216513ef29eaSKashyap Desai 		ioc_info(mrioc,
216613ef29eaSKashyap Desai 		    "%s :dev removal handshake completed successfully: handle(0x%04x)\n",
216713ef29eaSKashyap Desai 		    __func__, drv_cmd->dev_handle);
216813ef29eaSKashyap Desai 		clear_bit(drv_cmd->dev_handle, mrioc->removepend_bitmap);
216913ef29eaSKashyap Desai 	}
217013ef29eaSKashyap Desai 
217113ef29eaSKashyap Desai 	if (!list_empty(&mrioc->delayed_rmhs_list)) {
217213ef29eaSKashyap Desai 		delayed_dev_rmhs = list_entry(mrioc->delayed_rmhs_list.next,
217313ef29eaSKashyap Desai 		    struct delayed_dev_rmhs_node, list);
217413ef29eaSKashyap Desai 		drv_cmd->dev_handle = delayed_dev_rmhs->handle;
217513ef29eaSKashyap Desai 		drv_cmd->retry_count = 0;
217613ef29eaSKashyap Desai 		drv_cmd->iou_rc = delayed_dev_rmhs->iou_rc;
217713ef29eaSKashyap Desai 		ioc_info(mrioc,
217813ef29eaSKashyap Desai 		    "%s :dev_rmhs_iouctrl_complete: processing delayed TM: handle(0x%04x)\n",
217913ef29eaSKashyap Desai 		    __func__, drv_cmd->dev_handle);
218013ef29eaSKashyap Desai 		mpi3mr_dev_rmhs_send_tm(mrioc, drv_cmd->dev_handle, drv_cmd,
218113ef29eaSKashyap Desai 		    drv_cmd->iou_rc);
218213ef29eaSKashyap Desai 		list_del(&delayed_dev_rmhs->list);
218313ef29eaSKashyap Desai 		kfree(delayed_dev_rmhs);
218413ef29eaSKashyap Desai 		return;
218513ef29eaSKashyap Desai 	}
2186b3911ab3SSreekanth Reddy 
2187b3911ab3SSreekanth Reddy clear_drv_cmd:
218813ef29eaSKashyap Desai 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
218913ef29eaSKashyap Desai 	drv_cmd->callback = NULL;
219013ef29eaSKashyap Desai 	drv_cmd->retry_count = 0;
219113ef29eaSKashyap Desai 	drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
219213ef29eaSKashyap Desai 	clear_bit(cmd_idx, mrioc->devrem_bitmap);
219313ef29eaSKashyap Desai }
219413ef29eaSKashyap Desai 
219513ef29eaSKashyap Desai /**
219613ef29eaSKashyap Desai  * mpi3mr_dev_rmhs_complete_tm - Device removal TM completion
219713ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
219813ef29eaSKashyap Desai  * @drv_cmd: Internal command tracker
219913ef29eaSKashyap Desai  *
220013ef29eaSKashyap Desai  * Issues a target reset TM to the firmware from the device
220113ef29eaSKashyap Desai  * removal TM pend list or issue IO unit control request as
220213ef29eaSKashyap Desai  * part of device removal or hidden acknowledgment handshake.
220313ef29eaSKashyap Desai  *
220413ef29eaSKashyap Desai  * Return: Nothing
220513ef29eaSKashyap Desai  */
mpi3mr_dev_rmhs_complete_tm(struct mpi3mr_ioc * mrioc,struct mpi3mr_drv_cmd * drv_cmd)220613ef29eaSKashyap Desai static void mpi3mr_dev_rmhs_complete_tm(struct mpi3mr_ioc *mrioc,
220713ef29eaSKashyap Desai 	struct mpi3mr_drv_cmd *drv_cmd)
220813ef29eaSKashyap Desai {
220913ef29eaSKashyap Desai 	struct mpi3_iounit_control_request iou_ctrl;
221013ef29eaSKashyap Desai 	u16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
221113ef29eaSKashyap Desai 	struct mpi3_scsi_task_mgmt_reply *tm_reply = NULL;
221213ef29eaSKashyap Desai 	int retval;
221313ef29eaSKashyap Desai 
2214b3911ab3SSreekanth Reddy 	if (drv_cmd->state & MPI3MR_CMD_RESET)
2215b3911ab3SSreekanth Reddy 		goto clear_drv_cmd;
2216b3911ab3SSreekanth Reddy 
221713ef29eaSKashyap Desai 	if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID)
221813ef29eaSKashyap Desai 		tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply;
221913ef29eaSKashyap Desai 
222013ef29eaSKashyap Desai 	if (tm_reply)
222113ef29eaSKashyap Desai 		pr_info(IOCNAME
222213ef29eaSKashyap Desai 		    "dev_rmhs_tr_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x), term_count(%d)\n",
222313ef29eaSKashyap Desai 		    mrioc->name, drv_cmd->dev_handle, drv_cmd->ioc_status,
222413ef29eaSKashyap Desai 		    drv_cmd->ioc_loginfo,
222513ef29eaSKashyap Desai 		    le32_to_cpu(tm_reply->termination_count));
222613ef29eaSKashyap Desai 
222713ef29eaSKashyap Desai 	pr_info(IOCNAME "Issuing IOU CTL: handle(0x%04x) dev_rmhs idx(%d)\n",
222813ef29eaSKashyap Desai 	    mrioc->name, drv_cmd->dev_handle, cmd_idx);
222913ef29eaSKashyap Desai 
223013ef29eaSKashyap Desai 	memset(&iou_ctrl, 0, sizeof(iou_ctrl));
223113ef29eaSKashyap Desai 
223213ef29eaSKashyap Desai 	drv_cmd->state = MPI3MR_CMD_PENDING;
223313ef29eaSKashyap Desai 	drv_cmd->is_waiting = 0;
223413ef29eaSKashyap Desai 	drv_cmd->callback = mpi3mr_dev_rmhs_complete_iou;
223513ef29eaSKashyap Desai 	iou_ctrl.operation = drv_cmd->iou_rc;
223613ef29eaSKashyap Desai 	iou_ctrl.param16[0] = cpu_to_le16(drv_cmd->dev_handle);
223713ef29eaSKashyap Desai 	iou_ctrl.host_tag = cpu_to_le16(drv_cmd->host_tag);
223813ef29eaSKashyap Desai 	iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
223913ef29eaSKashyap Desai 
224013ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl, sizeof(iou_ctrl),
224113ef29eaSKashyap Desai 	    1);
224213ef29eaSKashyap Desai 	if (retval) {
224313ef29eaSKashyap Desai 		pr_err(IOCNAME "Issue DevRmHsTMIOUCTL: Admin post failed\n",
224413ef29eaSKashyap Desai 		    mrioc->name);
2245b3911ab3SSreekanth Reddy 		goto clear_drv_cmd;
224613ef29eaSKashyap Desai 	}
224713ef29eaSKashyap Desai 
224813ef29eaSKashyap Desai 	return;
2249b3911ab3SSreekanth Reddy clear_drv_cmd:
225013ef29eaSKashyap Desai 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
225113ef29eaSKashyap Desai 	drv_cmd->callback = NULL;
225213ef29eaSKashyap Desai 	drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
225313ef29eaSKashyap Desai 	drv_cmd->retry_count = 0;
225413ef29eaSKashyap Desai 	clear_bit(cmd_idx, mrioc->devrem_bitmap);
225513ef29eaSKashyap Desai }
225613ef29eaSKashyap Desai 
225713ef29eaSKashyap Desai /**
225813ef29eaSKashyap Desai  * mpi3mr_dev_rmhs_send_tm - Issue TM for device removal
225913ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
226013ef29eaSKashyap Desai  * @handle: Device handle
226113ef29eaSKashyap Desai  * @cmdparam: Internal command tracker
226213ef29eaSKashyap Desai  * @iou_rc: IO unit reason code
226313ef29eaSKashyap Desai  *
226413ef29eaSKashyap Desai  * Issues a target reset TM to the firmware or add it to a pend
226513ef29eaSKashyap Desai  * list as part of device removal or hidden acknowledgment
226613ef29eaSKashyap Desai  * handshake.
226713ef29eaSKashyap Desai  *
226813ef29eaSKashyap Desai  * Return: Nothing
226913ef29eaSKashyap Desai  */
mpi3mr_dev_rmhs_send_tm(struct mpi3mr_ioc * mrioc,u16 handle,struct mpi3mr_drv_cmd * cmdparam,u8 iou_rc)227013ef29eaSKashyap Desai static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_ioc *mrioc, u16 handle,
227113ef29eaSKashyap Desai 	struct mpi3mr_drv_cmd *cmdparam, u8 iou_rc)
227213ef29eaSKashyap Desai {
227313ef29eaSKashyap Desai 	struct mpi3_scsi_task_mgmt_request tm_req;
227413ef29eaSKashyap Desai 	int retval = 0;
227513ef29eaSKashyap Desai 	u16 cmd_idx = MPI3MR_NUM_DEVRMCMD;
227613ef29eaSKashyap Desai 	u8 retrycount = 5;
227713ef29eaSKashyap Desai 	struct mpi3mr_drv_cmd *drv_cmd = cmdparam;
227813ef29eaSKashyap Desai 	struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL;
22793f1254edSRanjan Kumar 	struct mpi3mr_tgt_dev *tgtdev = NULL;
22803f1254edSRanjan Kumar 	unsigned long flags;
22813f1254edSRanjan Kumar 
22823f1254edSRanjan Kumar 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
22833f1254edSRanjan Kumar 	tgtdev = __mpi3mr_get_tgtdev_by_handle(mrioc, handle);
22843f1254edSRanjan Kumar 	if (tgtdev && (iou_rc == MPI3_CTRL_OP_REMOVE_DEVICE))
22853f1254edSRanjan Kumar 		tgtdev->state = MPI3MR_DEV_REMOVE_HS_STARTED;
22863f1254edSRanjan Kumar 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
228713ef29eaSKashyap Desai 
228813ef29eaSKashyap Desai 	if (drv_cmd)
228913ef29eaSKashyap Desai 		goto issue_cmd;
229013ef29eaSKashyap Desai 	do {
229113ef29eaSKashyap Desai 		cmd_idx = find_first_zero_bit(mrioc->devrem_bitmap,
229213ef29eaSKashyap Desai 		    MPI3MR_NUM_DEVRMCMD);
229313ef29eaSKashyap Desai 		if (cmd_idx < MPI3MR_NUM_DEVRMCMD) {
229413ef29eaSKashyap Desai 			if (!test_and_set_bit(cmd_idx, mrioc->devrem_bitmap))
229513ef29eaSKashyap Desai 				break;
229613ef29eaSKashyap Desai 			cmd_idx = MPI3MR_NUM_DEVRMCMD;
229713ef29eaSKashyap Desai 		}
229813ef29eaSKashyap Desai 	} while (retrycount--);
229913ef29eaSKashyap Desai 
230013ef29eaSKashyap Desai 	if (cmd_idx >= MPI3MR_NUM_DEVRMCMD) {
230113ef29eaSKashyap Desai 		delayed_dev_rmhs = kzalloc(sizeof(*delayed_dev_rmhs),
230213ef29eaSKashyap Desai 		    GFP_ATOMIC);
230313ef29eaSKashyap Desai 		if (!delayed_dev_rmhs)
230413ef29eaSKashyap Desai 			return;
230513ef29eaSKashyap Desai 		INIT_LIST_HEAD(&delayed_dev_rmhs->list);
230613ef29eaSKashyap Desai 		delayed_dev_rmhs->handle = handle;
230713ef29eaSKashyap Desai 		delayed_dev_rmhs->iou_rc = iou_rc;
230813ef29eaSKashyap Desai 		list_add_tail(&delayed_dev_rmhs->list,
230913ef29eaSKashyap Desai 		    &mrioc->delayed_rmhs_list);
231013ef29eaSKashyap Desai 		ioc_info(mrioc, "%s :DevRmHs: tr:handle(0x%04x) is postponed\n",
231113ef29eaSKashyap Desai 		    __func__, handle);
231213ef29eaSKashyap Desai 		return;
231313ef29eaSKashyap Desai 	}
231413ef29eaSKashyap Desai 	drv_cmd = &mrioc->dev_rmhs_cmds[cmd_idx];
231513ef29eaSKashyap Desai 
231613ef29eaSKashyap Desai issue_cmd:
231713ef29eaSKashyap Desai 	cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
231813ef29eaSKashyap Desai 	ioc_info(mrioc,
231913ef29eaSKashyap Desai 	    "%s :Issuing TR TM: for devhandle 0x%04x with dev_rmhs %d\n",
232013ef29eaSKashyap Desai 	    __func__, handle, cmd_idx);
232113ef29eaSKashyap Desai 
232213ef29eaSKashyap Desai 	memset(&tm_req, 0, sizeof(tm_req));
232313ef29eaSKashyap Desai 	if (drv_cmd->state & MPI3MR_CMD_PENDING) {
232413ef29eaSKashyap Desai 		ioc_err(mrioc, "%s :Issue TM: Command is in use\n", __func__);
232513ef29eaSKashyap Desai 		goto out;
232613ef29eaSKashyap Desai 	}
232713ef29eaSKashyap Desai 	drv_cmd->state = MPI3MR_CMD_PENDING;
232813ef29eaSKashyap Desai 	drv_cmd->is_waiting = 0;
232913ef29eaSKashyap Desai 	drv_cmd->callback = mpi3mr_dev_rmhs_complete_tm;
233013ef29eaSKashyap Desai 	drv_cmd->dev_handle = handle;
233113ef29eaSKashyap Desai 	drv_cmd->iou_rc = iou_rc;
233213ef29eaSKashyap Desai 	tm_req.dev_handle = cpu_to_le16(handle);
233313ef29eaSKashyap Desai 	tm_req.task_type = MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
233413ef29eaSKashyap Desai 	tm_req.host_tag = cpu_to_le16(drv_cmd->host_tag);
233513ef29eaSKashyap Desai 	tm_req.task_host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INVALID);
233613ef29eaSKashyap Desai 	tm_req.function = MPI3_FUNCTION_SCSI_TASK_MGMT;
233713ef29eaSKashyap Desai 
233813ef29eaSKashyap Desai 	set_bit(handle, mrioc->removepend_bitmap);
233913ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &tm_req, sizeof(tm_req), 1);
234013ef29eaSKashyap Desai 	if (retval) {
234113ef29eaSKashyap Desai 		ioc_err(mrioc, "%s :Issue DevRmHsTM: Admin Post failed\n",
234213ef29eaSKashyap Desai 		    __func__);
234313ef29eaSKashyap Desai 		goto out_failed;
234413ef29eaSKashyap Desai 	}
234513ef29eaSKashyap Desai out:
234613ef29eaSKashyap Desai 	return;
234713ef29eaSKashyap Desai out_failed:
234813ef29eaSKashyap Desai 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
234913ef29eaSKashyap Desai 	drv_cmd->callback = NULL;
235013ef29eaSKashyap Desai 	drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
235113ef29eaSKashyap Desai 	drv_cmd->retry_count = 0;
235213ef29eaSKashyap Desai 	clear_bit(cmd_idx, mrioc->devrem_bitmap);
235313ef29eaSKashyap Desai }
235413ef29eaSKashyap Desai 
235513ef29eaSKashyap Desai /**
2356c1af985dSSreekanth Reddy  * mpi3mr_complete_evt_ack - event ack request completion
2357c1af985dSSreekanth Reddy  * @mrioc: Adapter instance reference
2358c1af985dSSreekanth Reddy  * @drv_cmd: Internal command tracker
2359c1af985dSSreekanth Reddy  *
2360c1af985dSSreekanth Reddy  * This is the completion handler for non blocking event
2361c1af985dSSreekanth Reddy  * acknowledgment sent to the firmware and this will issue any
2362c1af985dSSreekanth Reddy  * pending event acknowledgment request.
2363c1af985dSSreekanth Reddy  *
2364c1af985dSSreekanth Reddy  * Return: Nothing
2365c1af985dSSreekanth Reddy  */
mpi3mr_complete_evt_ack(struct mpi3mr_ioc * mrioc,struct mpi3mr_drv_cmd * drv_cmd)2366c1af985dSSreekanth Reddy static void mpi3mr_complete_evt_ack(struct mpi3mr_ioc *mrioc,
2367c1af985dSSreekanth Reddy 	struct mpi3mr_drv_cmd *drv_cmd)
2368c1af985dSSreekanth Reddy {
2369c1af985dSSreekanth Reddy 	u16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
2370c1af985dSSreekanth Reddy 	struct delayed_evt_ack_node *delayed_evtack = NULL;
2371c1af985dSSreekanth Reddy 
2372b3911ab3SSreekanth Reddy 	if (drv_cmd->state & MPI3MR_CMD_RESET)
2373b3911ab3SSreekanth Reddy 		goto clear_drv_cmd;
2374b3911ab3SSreekanth Reddy 
2375c1af985dSSreekanth Reddy 	if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2376c1af985dSSreekanth Reddy 		dprint_event_th(mrioc,
2377c1af985dSSreekanth Reddy 		    "immediate event ack failed with ioc_status(0x%04x) log_info(0x%08x)\n",
2378c1af985dSSreekanth Reddy 		    (drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2379c1af985dSSreekanth Reddy 		    drv_cmd->ioc_loginfo);
2380c1af985dSSreekanth Reddy 	}
2381c1af985dSSreekanth Reddy 
2382c1af985dSSreekanth Reddy 	if (!list_empty(&mrioc->delayed_evtack_cmds_list)) {
2383c1af985dSSreekanth Reddy 		delayed_evtack =
2384c1af985dSSreekanth Reddy 			list_entry(mrioc->delayed_evtack_cmds_list.next,
2385c1af985dSSreekanth Reddy 			    struct delayed_evt_ack_node, list);
2386c1af985dSSreekanth Reddy 		mpi3mr_send_event_ack(mrioc, delayed_evtack->event, drv_cmd,
2387c1af985dSSreekanth Reddy 		    delayed_evtack->event_ctx);
2388c1af985dSSreekanth Reddy 		list_del(&delayed_evtack->list);
2389c1af985dSSreekanth Reddy 		kfree(delayed_evtack);
2390c1af985dSSreekanth Reddy 		return;
2391c1af985dSSreekanth Reddy 	}
2392b3911ab3SSreekanth Reddy clear_drv_cmd:
2393c1af985dSSreekanth Reddy 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
2394c1af985dSSreekanth Reddy 	drv_cmd->callback = NULL;
2395c1af985dSSreekanth Reddy 	clear_bit(cmd_idx, mrioc->evtack_cmds_bitmap);
2396c1af985dSSreekanth Reddy }
2397c1af985dSSreekanth Reddy 
2398c1af985dSSreekanth Reddy /**
2399c1af985dSSreekanth Reddy  * mpi3mr_send_event_ack - Issue event acknwoledgment request
2400c1af985dSSreekanth Reddy  * @mrioc: Adapter instance reference
2401c1af985dSSreekanth Reddy  * @event: MPI3 event id
2402c1af985dSSreekanth Reddy  * @cmdparam: Internal command tracker
2403c1af985dSSreekanth Reddy  * @event_ctx: event context
2404c1af985dSSreekanth Reddy  *
2405c1af985dSSreekanth Reddy  * Issues event acknowledgment request to the firmware if there
2406c1af985dSSreekanth Reddy  * is a free command to send the event ack else it to a pend
2407c1af985dSSreekanth Reddy  * list so that it will be processed on a completion of a prior
2408c1af985dSSreekanth Reddy  * event acknowledgment .
2409c1af985dSSreekanth Reddy  *
2410c1af985dSSreekanth Reddy  * Return: Nothing
2411c1af985dSSreekanth Reddy  */
mpi3mr_send_event_ack(struct mpi3mr_ioc * mrioc,u8 event,struct mpi3mr_drv_cmd * cmdparam,u32 event_ctx)2412c1af985dSSreekanth Reddy static void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
2413c1af985dSSreekanth Reddy 	struct mpi3mr_drv_cmd *cmdparam, u32 event_ctx)
2414c1af985dSSreekanth Reddy {
2415c1af985dSSreekanth Reddy 	struct mpi3_event_ack_request evtack_req;
2416c1af985dSSreekanth Reddy 	int retval = 0;
2417c1af985dSSreekanth Reddy 	u8 retrycount = 5;
2418c1af985dSSreekanth Reddy 	u16 cmd_idx = MPI3MR_NUM_EVTACKCMD;
2419c1af985dSSreekanth Reddy 	struct mpi3mr_drv_cmd *drv_cmd = cmdparam;
2420c1af985dSSreekanth Reddy 	struct delayed_evt_ack_node *delayed_evtack = NULL;
2421c1af985dSSreekanth Reddy 
2422c1af985dSSreekanth Reddy 	if (drv_cmd) {
2423c1af985dSSreekanth Reddy 		dprint_event_th(mrioc,
2424c1af985dSSreekanth Reddy 		    "sending delayed event ack in the top half for event(0x%02x), event_ctx(0x%08x)\n",
2425c1af985dSSreekanth Reddy 		    event, event_ctx);
2426c1af985dSSreekanth Reddy 		goto issue_cmd;
2427c1af985dSSreekanth Reddy 	}
2428c1af985dSSreekanth Reddy 	dprint_event_th(mrioc,
2429c1af985dSSreekanth Reddy 	    "sending event ack in the top half for event(0x%02x), event_ctx(0x%08x)\n",
2430c1af985dSSreekanth Reddy 	    event, event_ctx);
2431c1af985dSSreekanth Reddy 	do {
2432c1af985dSSreekanth Reddy 		cmd_idx = find_first_zero_bit(mrioc->evtack_cmds_bitmap,
2433c1af985dSSreekanth Reddy 		    MPI3MR_NUM_EVTACKCMD);
2434c1af985dSSreekanth Reddy 		if (cmd_idx < MPI3MR_NUM_EVTACKCMD) {
2435c1af985dSSreekanth Reddy 			if (!test_and_set_bit(cmd_idx,
2436c1af985dSSreekanth Reddy 			    mrioc->evtack_cmds_bitmap))
2437c1af985dSSreekanth Reddy 				break;
2438c1af985dSSreekanth Reddy 			cmd_idx = MPI3MR_NUM_EVTACKCMD;
2439c1af985dSSreekanth Reddy 		}
2440c1af985dSSreekanth Reddy 	} while (retrycount--);
2441c1af985dSSreekanth Reddy 
2442c1af985dSSreekanth Reddy 	if (cmd_idx >= MPI3MR_NUM_EVTACKCMD) {
2443c1af985dSSreekanth Reddy 		delayed_evtack = kzalloc(sizeof(*delayed_evtack),
2444c1af985dSSreekanth Reddy 		    GFP_ATOMIC);
2445c1af985dSSreekanth Reddy 		if (!delayed_evtack)
2446c1af985dSSreekanth Reddy 			return;
2447c1af985dSSreekanth Reddy 		INIT_LIST_HEAD(&delayed_evtack->list);
2448c1af985dSSreekanth Reddy 		delayed_evtack->event = event;
2449c1af985dSSreekanth Reddy 		delayed_evtack->event_ctx = event_ctx;
2450c1af985dSSreekanth Reddy 		list_add_tail(&delayed_evtack->list,
2451c1af985dSSreekanth Reddy 		    &mrioc->delayed_evtack_cmds_list);
2452c1af985dSSreekanth Reddy 		dprint_event_th(mrioc,
2453c1af985dSSreekanth Reddy 		    "event ack in the top half for event(0x%02x), event_ctx(0x%08x) is postponed\n",
2454c1af985dSSreekanth Reddy 		    event, event_ctx);
2455c1af985dSSreekanth Reddy 		return;
2456c1af985dSSreekanth Reddy 	}
2457c1af985dSSreekanth Reddy 	drv_cmd = &mrioc->evtack_cmds[cmd_idx];
2458c1af985dSSreekanth Reddy 
2459c1af985dSSreekanth Reddy issue_cmd:
2460c1af985dSSreekanth Reddy 	cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
2461c1af985dSSreekanth Reddy 
2462c1af985dSSreekanth Reddy 	memset(&evtack_req, 0, sizeof(evtack_req));
2463c1af985dSSreekanth Reddy 	if (drv_cmd->state & MPI3MR_CMD_PENDING) {
2464c1af985dSSreekanth Reddy 		dprint_event_th(mrioc,
2465c1af985dSSreekanth Reddy 		    "sending event ack failed due to command in use\n");
2466c1af985dSSreekanth Reddy 		goto out;
2467c1af985dSSreekanth Reddy 	}
2468c1af985dSSreekanth Reddy 	drv_cmd->state = MPI3MR_CMD_PENDING;
2469c1af985dSSreekanth Reddy 	drv_cmd->is_waiting = 0;
2470c1af985dSSreekanth Reddy 	drv_cmd->callback = mpi3mr_complete_evt_ack;
2471c1af985dSSreekanth Reddy 	evtack_req.host_tag = cpu_to_le16(drv_cmd->host_tag);
2472c1af985dSSreekanth Reddy 	evtack_req.function = MPI3_FUNCTION_EVENT_ACK;
2473c1af985dSSreekanth Reddy 	evtack_req.event = event;
2474c1af985dSSreekanth Reddy 	evtack_req.event_context = cpu_to_le32(event_ctx);
2475c1af985dSSreekanth Reddy 	retval = mpi3mr_admin_request_post(mrioc, &evtack_req,
2476c1af985dSSreekanth Reddy 	    sizeof(evtack_req), 1);
2477c1af985dSSreekanth Reddy 	if (retval) {
2478c1af985dSSreekanth Reddy 		dprint_event_th(mrioc,
2479c1af985dSSreekanth Reddy 		    "posting event ack request is failed\n");
2480c1af985dSSreekanth Reddy 		goto out_failed;
2481c1af985dSSreekanth Reddy 	}
2482c1af985dSSreekanth Reddy 
2483c1af985dSSreekanth Reddy 	dprint_event_th(mrioc,
2484c1af985dSSreekanth Reddy 	    "event ack in the top half for event(0x%02x), event_ctx(0x%08x) is posted\n",
2485c1af985dSSreekanth Reddy 	    event, event_ctx);
2486c1af985dSSreekanth Reddy out:
2487c1af985dSSreekanth Reddy 	return;
2488c1af985dSSreekanth Reddy out_failed:
2489c1af985dSSreekanth Reddy 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
2490c1af985dSSreekanth Reddy 	drv_cmd->callback = NULL;
2491c1af985dSSreekanth Reddy 	clear_bit(cmd_idx, mrioc->evtack_cmds_bitmap);
2492c1af985dSSreekanth Reddy }
2493c1af985dSSreekanth Reddy 
2494c1af985dSSreekanth Reddy /**
24958e653455SKashyap Desai  * mpi3mr_pcietopochg_evt_th - PCIETopologyChange evt tophalf
24968e653455SKashyap Desai  * @mrioc: Adapter instance reference
24978e653455SKashyap Desai  * @event_reply: event data
24988e653455SKashyap Desai  *
24998e653455SKashyap Desai  * Checks for the reason code and based on that either block I/O
25008e653455SKashyap Desai  * to device, or unblock I/O to the device, or start the device
25018e653455SKashyap Desai  * removal handshake with reason as remove with the firmware for
25028e653455SKashyap Desai  * PCIe devices.
25038e653455SKashyap Desai  *
25048e653455SKashyap Desai  * Return: Nothing
25058e653455SKashyap Desai  */
mpi3mr_pcietopochg_evt_th(struct mpi3mr_ioc * mrioc,struct mpi3_event_notification_reply * event_reply)25068e653455SKashyap Desai static void mpi3mr_pcietopochg_evt_th(struct mpi3mr_ioc *mrioc,
25078e653455SKashyap Desai 	struct mpi3_event_notification_reply *event_reply)
25088e653455SKashyap Desai {
25098e653455SKashyap Desai 	struct mpi3_event_data_pcie_topology_change_list *topo_evt =
25108e653455SKashyap Desai 	    (struct mpi3_event_data_pcie_topology_change_list *)event_reply->event_data;
25118e653455SKashyap Desai 	int i;
25128e653455SKashyap Desai 	u16 handle;
25138e653455SKashyap Desai 	u8 reason_code;
25148e653455SKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev = NULL;
25158e653455SKashyap Desai 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
25168e653455SKashyap Desai 
25178e653455SKashyap Desai 	for (i = 0; i < topo_evt->num_entries; i++) {
25188e653455SKashyap Desai 		handle = le16_to_cpu(topo_evt->port_entry[i].attached_dev_handle);
25198e653455SKashyap Desai 		if (!handle)
25208e653455SKashyap Desai 			continue;
25218e653455SKashyap Desai 		reason_code = topo_evt->port_entry[i].port_status;
25228e653455SKashyap Desai 		scsi_tgt_priv_data =  NULL;
25238e653455SKashyap Desai 		tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
25248e653455SKashyap Desai 		if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata)
25258e653455SKashyap Desai 			scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
25268e653455SKashyap Desai 			    tgtdev->starget->hostdata;
25278e653455SKashyap Desai 		switch (reason_code) {
25288e653455SKashyap Desai 		case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
25298e653455SKashyap Desai 			if (scsi_tgt_priv_data) {
25308e653455SKashyap Desai 				scsi_tgt_priv_data->dev_removed = 1;
25318e653455SKashyap Desai 				scsi_tgt_priv_data->dev_removedelay = 0;
25328e653455SKashyap Desai 				atomic_set(&scsi_tgt_priv_data->block_io, 0);
25338e653455SKashyap Desai 			}
25348e653455SKashyap Desai 			mpi3mr_dev_rmhs_send_tm(mrioc, handle, NULL,
25358e653455SKashyap Desai 			    MPI3_CTRL_OP_REMOVE_DEVICE);
25368e653455SKashyap Desai 			break;
25378e653455SKashyap Desai 		case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING:
25388e653455SKashyap Desai 			if (scsi_tgt_priv_data) {
25398e653455SKashyap Desai 				scsi_tgt_priv_data->dev_removedelay = 1;
25408e653455SKashyap Desai 				atomic_inc(&scsi_tgt_priv_data->block_io);
25418e653455SKashyap Desai 			}
25428e653455SKashyap Desai 			break;
25438e653455SKashyap Desai 		case MPI3_EVENT_PCIE_TOPO_PS_RESPONDING:
25448e653455SKashyap Desai 			if (scsi_tgt_priv_data &&
25458e653455SKashyap Desai 			    scsi_tgt_priv_data->dev_removedelay) {
25468e653455SKashyap Desai 				scsi_tgt_priv_data->dev_removedelay = 0;
25478e653455SKashyap Desai 				atomic_dec_if_positive
25488e653455SKashyap Desai 				    (&scsi_tgt_priv_data->block_io);
25498e653455SKashyap Desai 			}
25508e653455SKashyap Desai 			break;
25518e653455SKashyap Desai 		case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
25528e653455SKashyap Desai 		default:
25538e653455SKashyap Desai 			break;
25548e653455SKashyap Desai 		}
25558e653455SKashyap Desai 		if (tgtdev)
25568e653455SKashyap Desai 			mpi3mr_tgtdev_put(tgtdev);
25578e653455SKashyap Desai 	}
25588e653455SKashyap Desai }
25598e653455SKashyap Desai 
25608e653455SKashyap Desai /**
256113ef29eaSKashyap Desai  * mpi3mr_sastopochg_evt_th - SASTopologyChange evt tophalf
256213ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
256313ef29eaSKashyap Desai  * @event_reply: event data
256413ef29eaSKashyap Desai  *
256513ef29eaSKashyap Desai  * Checks for the reason code and based on that either block I/O
256613ef29eaSKashyap Desai  * to device, or unblock I/O to the device, or start the device
256713ef29eaSKashyap Desai  * removal handshake with reason as remove with the firmware for
256813ef29eaSKashyap Desai  * SAS/SATA devices.
256913ef29eaSKashyap Desai  *
257013ef29eaSKashyap Desai  * Return: Nothing
257113ef29eaSKashyap Desai  */
mpi3mr_sastopochg_evt_th(struct mpi3mr_ioc * mrioc,struct mpi3_event_notification_reply * event_reply)257213ef29eaSKashyap Desai static void mpi3mr_sastopochg_evt_th(struct mpi3mr_ioc *mrioc,
257313ef29eaSKashyap Desai 	struct mpi3_event_notification_reply *event_reply)
257413ef29eaSKashyap Desai {
257513ef29eaSKashyap Desai 	struct mpi3_event_data_sas_topology_change_list *topo_evt =
257613ef29eaSKashyap Desai 	    (struct mpi3_event_data_sas_topology_change_list *)event_reply->event_data;
257713ef29eaSKashyap Desai 	int i;
257813ef29eaSKashyap Desai 	u16 handle;
257913ef29eaSKashyap Desai 	u8 reason_code;
258013ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev = NULL;
258113ef29eaSKashyap Desai 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
258213ef29eaSKashyap Desai 
258313ef29eaSKashyap Desai 	for (i = 0; i < topo_evt->num_entries; i++) {
258413ef29eaSKashyap Desai 		handle = le16_to_cpu(topo_evt->phy_entry[i].attached_dev_handle);
258513ef29eaSKashyap Desai 		if (!handle)
258613ef29eaSKashyap Desai 			continue;
258713ef29eaSKashyap Desai 		reason_code = topo_evt->phy_entry[i].status &
258813ef29eaSKashyap Desai 		    MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
258913ef29eaSKashyap Desai 		scsi_tgt_priv_data =  NULL;
259013ef29eaSKashyap Desai 		tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
259113ef29eaSKashyap Desai 		if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata)
259213ef29eaSKashyap Desai 			scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
259313ef29eaSKashyap Desai 			    tgtdev->starget->hostdata;
259413ef29eaSKashyap Desai 		switch (reason_code) {
259513ef29eaSKashyap Desai 		case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
259613ef29eaSKashyap Desai 			if (scsi_tgt_priv_data) {
259713ef29eaSKashyap Desai 				scsi_tgt_priv_data->dev_removed = 1;
259813ef29eaSKashyap Desai 				scsi_tgt_priv_data->dev_removedelay = 0;
259913ef29eaSKashyap Desai 				atomic_set(&scsi_tgt_priv_data->block_io, 0);
260013ef29eaSKashyap Desai 			}
260113ef29eaSKashyap Desai 			mpi3mr_dev_rmhs_send_tm(mrioc, handle, NULL,
260213ef29eaSKashyap Desai 			    MPI3_CTRL_OP_REMOVE_DEVICE);
260313ef29eaSKashyap Desai 			break;
260413ef29eaSKashyap Desai 		case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING:
260513ef29eaSKashyap Desai 			if (scsi_tgt_priv_data) {
260613ef29eaSKashyap Desai 				scsi_tgt_priv_data->dev_removedelay = 1;
260713ef29eaSKashyap Desai 				atomic_inc(&scsi_tgt_priv_data->block_io);
260813ef29eaSKashyap Desai 			}
260913ef29eaSKashyap Desai 			break;
261013ef29eaSKashyap Desai 		case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING:
261113ef29eaSKashyap Desai 			if (scsi_tgt_priv_data &&
261213ef29eaSKashyap Desai 			    scsi_tgt_priv_data->dev_removedelay) {
261313ef29eaSKashyap Desai 				scsi_tgt_priv_data->dev_removedelay = 0;
261413ef29eaSKashyap Desai 				atomic_dec_if_positive
261513ef29eaSKashyap Desai 				    (&scsi_tgt_priv_data->block_io);
261613ef29eaSKashyap Desai 			}
26177b8a4988SGustavo A. R. Silva 			break;
261813ef29eaSKashyap Desai 		case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
261913ef29eaSKashyap Desai 		default:
262013ef29eaSKashyap Desai 			break;
262113ef29eaSKashyap Desai 		}
262213ef29eaSKashyap Desai 		if (tgtdev)
262313ef29eaSKashyap Desai 			mpi3mr_tgtdev_put(tgtdev);
262413ef29eaSKashyap Desai 	}
262513ef29eaSKashyap Desai }
262613ef29eaSKashyap Desai 
262713ef29eaSKashyap Desai /**
262813ef29eaSKashyap Desai  * mpi3mr_devstatuschg_evt_th - DeviceStatusChange evt tophalf
262913ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
263013ef29eaSKashyap Desai  * @event_reply: event data
263113ef29eaSKashyap Desai  *
263213ef29eaSKashyap Desai  * Checks for the reason code and based on that either block I/O
263313ef29eaSKashyap Desai  * to device, or unblock I/O to the device, or start the device
263413ef29eaSKashyap Desai  * removal handshake with reason as remove/hide acknowledgment
263513ef29eaSKashyap Desai  * with the firmware.
263613ef29eaSKashyap Desai  *
263713ef29eaSKashyap Desai  * Return: Nothing
263813ef29eaSKashyap Desai  */
mpi3mr_devstatuschg_evt_th(struct mpi3mr_ioc * mrioc,struct mpi3_event_notification_reply * event_reply)263913ef29eaSKashyap Desai static void mpi3mr_devstatuschg_evt_th(struct mpi3mr_ioc *mrioc,
264013ef29eaSKashyap Desai 	struct mpi3_event_notification_reply *event_reply)
264113ef29eaSKashyap Desai {
264213ef29eaSKashyap Desai 	u16 dev_handle = 0;
264313ef29eaSKashyap Desai 	u8 ublock = 0, block = 0, hide = 0, delete = 0, remove = 0;
264413ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev = NULL;
264513ef29eaSKashyap Desai 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
264613ef29eaSKashyap Desai 	struct mpi3_event_data_device_status_change *evtdata =
264713ef29eaSKashyap Desai 	    (struct mpi3_event_data_device_status_change *)event_reply->event_data;
264813ef29eaSKashyap Desai 
264913ef29eaSKashyap Desai 	if (mrioc->stop_drv_processing)
265013ef29eaSKashyap Desai 		goto out;
265113ef29eaSKashyap Desai 
265213ef29eaSKashyap Desai 	dev_handle = le16_to_cpu(evtdata->dev_handle);
265313ef29eaSKashyap Desai 
265413ef29eaSKashyap Desai 	switch (evtdata->reason_code) {
265513ef29eaSKashyap Desai 	case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT:
265613ef29eaSKashyap Desai 	case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_STRT:
265713ef29eaSKashyap Desai 		block = 1;
265813ef29eaSKashyap Desai 		break;
265913ef29eaSKashyap Desai 	case MPI3_EVENT_DEV_STAT_RC_HIDDEN:
266013ef29eaSKashyap Desai 		delete = 1;
266113ef29eaSKashyap Desai 		hide = 1;
266213ef29eaSKashyap Desai 		break;
266313ef29eaSKashyap Desai 	case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING:
266413ef29eaSKashyap Desai 		delete = 1;
266513ef29eaSKashyap Desai 		remove = 1;
266613ef29eaSKashyap Desai 		break;
266713ef29eaSKashyap Desai 	case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_CMP:
266813ef29eaSKashyap Desai 	case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_CMP:
266913ef29eaSKashyap Desai 		ublock = 1;
267013ef29eaSKashyap Desai 		break;
267113ef29eaSKashyap Desai 	default:
267213ef29eaSKashyap Desai 		break;
267313ef29eaSKashyap Desai 	}
267413ef29eaSKashyap Desai 
267513ef29eaSKashyap Desai 	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
267613ef29eaSKashyap Desai 	if (!tgtdev)
267713ef29eaSKashyap Desai 		goto out;
267813ef29eaSKashyap Desai 	if (hide)
267913ef29eaSKashyap Desai 		tgtdev->is_hidden = hide;
268013ef29eaSKashyap Desai 	if (tgtdev->starget && tgtdev->starget->hostdata) {
268113ef29eaSKashyap Desai 		scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
268213ef29eaSKashyap Desai 		    tgtdev->starget->hostdata;
268313ef29eaSKashyap Desai 		if (block)
268413ef29eaSKashyap Desai 			atomic_inc(&scsi_tgt_priv_data->block_io);
268513ef29eaSKashyap Desai 		if (delete)
268613ef29eaSKashyap Desai 			scsi_tgt_priv_data->dev_removed = 1;
268713ef29eaSKashyap Desai 		if (ublock)
268813ef29eaSKashyap Desai 			atomic_dec_if_positive(&scsi_tgt_priv_data->block_io);
268913ef29eaSKashyap Desai 	}
269013ef29eaSKashyap Desai 	if (remove)
269113ef29eaSKashyap Desai 		mpi3mr_dev_rmhs_send_tm(mrioc, dev_handle, NULL,
269213ef29eaSKashyap Desai 		    MPI3_CTRL_OP_REMOVE_DEVICE);
269313ef29eaSKashyap Desai 	if (hide)
269413ef29eaSKashyap Desai 		mpi3mr_dev_rmhs_send_tm(mrioc, dev_handle, NULL,
269513ef29eaSKashyap Desai 		    MPI3_CTRL_OP_HIDDEN_ACK);
269613ef29eaSKashyap Desai 
269713ef29eaSKashyap Desai out:
269813ef29eaSKashyap Desai 	if (tgtdev)
269913ef29eaSKashyap Desai 		mpi3mr_tgtdev_put(tgtdev);
270013ef29eaSKashyap Desai }
270113ef29eaSKashyap Desai 
270213ef29eaSKashyap Desai /**
270378b76a07SSreekanth Reddy  * mpi3mr_preparereset_evt_th - Prepare for reset event tophalf
270478b76a07SSreekanth Reddy  * @mrioc: Adapter instance reference
270578b76a07SSreekanth Reddy  * @event_reply: event data
270678b76a07SSreekanth Reddy  *
270778b76a07SSreekanth Reddy  * Blocks and unblocks host level I/O based on the reason code
270878b76a07SSreekanth Reddy  *
270978b76a07SSreekanth Reddy  * Return: Nothing
271078b76a07SSreekanth Reddy  */
mpi3mr_preparereset_evt_th(struct mpi3mr_ioc * mrioc,struct mpi3_event_notification_reply * event_reply)271178b76a07SSreekanth Reddy static void mpi3mr_preparereset_evt_th(struct mpi3mr_ioc *mrioc,
271278b76a07SSreekanth Reddy 	struct mpi3_event_notification_reply *event_reply)
271378b76a07SSreekanth Reddy {
271478b76a07SSreekanth Reddy 	struct mpi3_event_data_prepare_for_reset *evtdata =
271578b76a07SSreekanth Reddy 	    (struct mpi3_event_data_prepare_for_reset *)event_reply->event_data;
271678b76a07SSreekanth Reddy 
271778b76a07SSreekanth Reddy 	if (evtdata->reason_code == MPI3_EVENT_PREPARE_RESET_RC_START) {
271878b76a07SSreekanth Reddy 		dprint_event_th(mrioc,
271978b76a07SSreekanth Reddy 		    "prepare for reset event top half with rc=start\n");
272078b76a07SSreekanth Reddy 		if (mrioc->prepare_for_reset)
272178b76a07SSreekanth Reddy 			return;
272278b76a07SSreekanth Reddy 		mrioc->prepare_for_reset = 1;
272378b76a07SSreekanth Reddy 		mrioc->prepare_for_reset_timeout_counter = 0;
272478b76a07SSreekanth Reddy 	} else if (evtdata->reason_code == MPI3_EVENT_PREPARE_RESET_RC_ABORT) {
272578b76a07SSreekanth Reddy 		dprint_event_th(mrioc,
272678b76a07SSreekanth Reddy 		    "prepare for reset top half with rc=abort\n");
272778b76a07SSreekanth Reddy 		mrioc->prepare_for_reset = 0;
272878b76a07SSreekanth Reddy 		mrioc->prepare_for_reset_timeout_counter = 0;
272978b76a07SSreekanth Reddy 	}
273078b76a07SSreekanth Reddy 	if ((event_reply->msg_flags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK)
273178b76a07SSreekanth Reddy 	    == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED)
273278b76a07SSreekanth Reddy 		mpi3mr_send_event_ack(mrioc, event_reply->event, NULL,
273378b76a07SSreekanth Reddy 		    le32_to_cpu(event_reply->event_context));
273478b76a07SSreekanth Reddy }
273578b76a07SSreekanth Reddy 
273678b76a07SSreekanth Reddy /**
2737e36710dcSKashyap Desai  * mpi3mr_energypackchg_evt_th - Energy pack change evt tophalf
2738e36710dcSKashyap Desai  * @mrioc: Adapter instance reference
2739e36710dcSKashyap Desai  * @event_reply: event data
2740e36710dcSKashyap Desai  *
2741e36710dcSKashyap Desai  * Identifies the new shutdown timeout value and update.
2742e36710dcSKashyap Desai  *
2743e36710dcSKashyap Desai  * Return: Nothing
2744e36710dcSKashyap Desai  */
mpi3mr_energypackchg_evt_th(struct mpi3mr_ioc * mrioc,struct mpi3_event_notification_reply * event_reply)2745e36710dcSKashyap Desai static void mpi3mr_energypackchg_evt_th(struct mpi3mr_ioc *mrioc,
2746e36710dcSKashyap Desai 	struct mpi3_event_notification_reply *event_reply)
2747e36710dcSKashyap Desai {
2748e36710dcSKashyap Desai 	struct mpi3_event_data_energy_pack_change *evtdata =
2749e36710dcSKashyap Desai 	    (struct mpi3_event_data_energy_pack_change *)event_reply->event_data;
2750e36710dcSKashyap Desai 	u16 shutdown_timeout = le16_to_cpu(evtdata->shutdown_timeout);
2751e36710dcSKashyap Desai 
2752e36710dcSKashyap Desai 	if (shutdown_timeout <= 0) {
2753e36710dcSKashyap Desai 		ioc_warn(mrioc,
2754e36710dcSKashyap Desai 		    "%s :Invalid Shutdown Timeout received = %d\n",
2755e36710dcSKashyap Desai 		    __func__, shutdown_timeout);
2756e36710dcSKashyap Desai 		return;
2757e36710dcSKashyap Desai 	}
2758e36710dcSKashyap Desai 
2759e36710dcSKashyap Desai 	ioc_info(mrioc,
2760e36710dcSKashyap Desai 	    "%s :Previous Shutdown Timeout Value = %d New Shutdown Timeout Value = %d\n",
2761e36710dcSKashyap Desai 	    __func__, mrioc->facts.shutdown_timeout, shutdown_timeout);
2762e36710dcSKashyap Desai 	mrioc->facts.shutdown_timeout = shutdown_timeout;
2763e36710dcSKashyap Desai }
2764e36710dcSKashyap Desai 
2765e36710dcSKashyap Desai /**
276695cca8d5SSreekanth Reddy  * mpi3mr_cablemgmt_evt_th - Cable management event tophalf
276795cca8d5SSreekanth Reddy  * @mrioc: Adapter instance reference
276895cca8d5SSreekanth Reddy  * @event_reply: event data
276995cca8d5SSreekanth Reddy  *
277095cca8d5SSreekanth Reddy  * Displays Cable manegemt event details.
277195cca8d5SSreekanth Reddy  *
277295cca8d5SSreekanth Reddy  * Return: Nothing
277395cca8d5SSreekanth Reddy  */
mpi3mr_cablemgmt_evt_th(struct mpi3mr_ioc * mrioc,struct mpi3_event_notification_reply * event_reply)277495cca8d5SSreekanth Reddy static void mpi3mr_cablemgmt_evt_th(struct mpi3mr_ioc *mrioc,
277595cca8d5SSreekanth Reddy 	struct mpi3_event_notification_reply *event_reply)
277695cca8d5SSreekanth Reddy {
277795cca8d5SSreekanth Reddy 	struct mpi3_event_data_cable_management *evtdata =
277895cca8d5SSreekanth Reddy 	    (struct mpi3_event_data_cable_management *)event_reply->event_data;
277995cca8d5SSreekanth Reddy 
278095cca8d5SSreekanth Reddy 	switch (evtdata->status) {
278195cca8d5SSreekanth Reddy 	case MPI3_EVENT_CABLE_MGMT_STATUS_INSUFFICIENT_POWER:
278295cca8d5SSreekanth Reddy 	{
278395cca8d5SSreekanth Reddy 		ioc_info(mrioc, "An active cable with receptacle_id %d cannot be powered.\n"
278495cca8d5SSreekanth Reddy 		    "Devices connected to this cable are not detected.\n"
278595cca8d5SSreekanth Reddy 		    "This cable requires %d mW of power.\n",
278695cca8d5SSreekanth Reddy 		    evtdata->receptacle_id,
278795cca8d5SSreekanth Reddy 		    le32_to_cpu(evtdata->active_cable_power_requirement));
278895cca8d5SSreekanth Reddy 		break;
278995cca8d5SSreekanth Reddy 	}
279095cca8d5SSreekanth Reddy 	case MPI3_EVENT_CABLE_MGMT_STATUS_DEGRADED:
279195cca8d5SSreekanth Reddy 	{
279295cca8d5SSreekanth Reddy 		ioc_info(mrioc, "A cable with receptacle_id %d is not running at optimal speed\n",
279395cca8d5SSreekanth Reddy 		    evtdata->receptacle_id);
279495cca8d5SSreekanth Reddy 		break;
279595cca8d5SSreekanth Reddy 	}
279695cca8d5SSreekanth Reddy 	default:
279795cca8d5SSreekanth Reddy 		break;
279895cca8d5SSreekanth Reddy 	}
279995cca8d5SSreekanth Reddy }
280095cca8d5SSreekanth Reddy 
280195cca8d5SSreekanth Reddy /**
28022745ce0eSSreekanth Reddy  * mpi3mr_add_event_wait_for_device_refresh - Add Wait for Device Refresh Event
28032745ce0eSSreekanth Reddy  * @mrioc: Adapter instance reference
28042745ce0eSSreekanth Reddy  *
28052745ce0eSSreekanth Reddy  * Add driver specific event to make sure that the driver won't process the
28062745ce0eSSreekanth Reddy  * events until all the devices are refreshed during soft reset.
28072745ce0eSSreekanth Reddy  *
28082745ce0eSSreekanth Reddy  * Return: Nothing
28092745ce0eSSreekanth Reddy  */
mpi3mr_add_event_wait_for_device_refresh(struct mpi3mr_ioc * mrioc)28102745ce0eSSreekanth Reddy void mpi3mr_add_event_wait_for_device_refresh(struct mpi3mr_ioc *mrioc)
28112745ce0eSSreekanth Reddy {
28122745ce0eSSreekanth Reddy 	struct mpi3mr_fwevt *fwevt = NULL;
28132745ce0eSSreekanth Reddy 
28142745ce0eSSreekanth Reddy 	fwevt = mpi3mr_alloc_fwevt(0);
28152745ce0eSSreekanth Reddy 	if (!fwevt) {
28162745ce0eSSreekanth Reddy 		dprint_event_th(mrioc,
28172745ce0eSSreekanth Reddy 		    "failed to schedule bottom half handler for event(0x%02x)\n",
28182745ce0eSSreekanth Reddy 		    MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH);
28192745ce0eSSreekanth Reddy 		return;
28202745ce0eSSreekanth Reddy 	}
28212745ce0eSSreekanth Reddy 	fwevt->mrioc = mrioc;
28222745ce0eSSreekanth Reddy 	fwevt->event_id = MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH;
28232745ce0eSSreekanth Reddy 	fwevt->send_ack = 0;
28242745ce0eSSreekanth Reddy 	fwevt->process_evt = 1;
28252745ce0eSSreekanth Reddy 	fwevt->evt_ctx = 0;
28262745ce0eSSreekanth Reddy 	fwevt->event_data_size = 0;
28272745ce0eSSreekanth Reddy 	mpi3mr_fwevt_add_to_list(mrioc, fwevt);
28282745ce0eSSreekanth Reddy }
28292745ce0eSSreekanth Reddy 
28302745ce0eSSreekanth Reddy /**
283113ef29eaSKashyap Desai  * mpi3mr_os_handle_events - Firmware event handler
283213ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
283313ef29eaSKashyap Desai  * @event_reply: event data
283413ef29eaSKashyap Desai  *
283513ef29eaSKashyap Desai  * Identify whteher the event has to handled and acknowledged
283613ef29eaSKashyap Desai  * and either process the event in the tophalf and/or schedule a
283713ef29eaSKashyap Desai  * bottom half through mpi3mr_fwevt_worker.
283813ef29eaSKashyap Desai  *
283913ef29eaSKashyap Desai  * Return: Nothing
284013ef29eaSKashyap Desai  */
mpi3mr_os_handle_events(struct mpi3mr_ioc * mrioc,struct mpi3_event_notification_reply * event_reply)284113ef29eaSKashyap Desai void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
284213ef29eaSKashyap Desai 	struct mpi3_event_notification_reply *event_reply)
284313ef29eaSKashyap Desai {
284413ef29eaSKashyap Desai 	u16 evt_type, sz;
284513ef29eaSKashyap Desai 	struct mpi3mr_fwevt *fwevt = NULL;
284613ef29eaSKashyap Desai 	bool ack_req = 0, process_evt_bh = 0;
284713ef29eaSKashyap Desai 
284813ef29eaSKashyap Desai 	if (mrioc->stop_drv_processing)
284913ef29eaSKashyap Desai 		return;
285013ef29eaSKashyap Desai 
285113ef29eaSKashyap Desai 	if ((event_reply->msg_flags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK)
285213ef29eaSKashyap Desai 	    == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED)
285313ef29eaSKashyap Desai 		ack_req = 1;
285413ef29eaSKashyap Desai 
285513ef29eaSKashyap Desai 	evt_type = event_reply->event;
285613ef29eaSKashyap Desai 
285713ef29eaSKashyap Desai 	switch (evt_type) {
285813ef29eaSKashyap Desai 	case MPI3_EVENT_DEVICE_ADDED:
285913ef29eaSKashyap Desai 	{
286013ef29eaSKashyap Desai 		struct mpi3_device_page0 *dev_pg0 =
286113ef29eaSKashyap Desai 		    (struct mpi3_device_page0 *)event_reply->event_data;
286213ef29eaSKashyap Desai 		if (mpi3mr_create_tgtdev(mrioc, dev_pg0))
286313ef29eaSKashyap Desai 			ioc_err(mrioc,
286413ef29eaSKashyap Desai 			    "%s :Failed to add device in the device add event\n",
286513ef29eaSKashyap Desai 			    __func__);
286613ef29eaSKashyap Desai 		else
286713ef29eaSKashyap Desai 			process_evt_bh = 1;
286813ef29eaSKashyap Desai 		break;
286913ef29eaSKashyap Desai 	}
287013ef29eaSKashyap Desai 	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
287113ef29eaSKashyap Desai 	{
287213ef29eaSKashyap Desai 		process_evt_bh = 1;
287313ef29eaSKashyap Desai 		mpi3mr_devstatuschg_evt_th(mrioc, event_reply);
287413ef29eaSKashyap Desai 		break;
287513ef29eaSKashyap Desai 	}
287613ef29eaSKashyap Desai 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
287713ef29eaSKashyap Desai 	{
287813ef29eaSKashyap Desai 		process_evt_bh = 1;
287913ef29eaSKashyap Desai 		mpi3mr_sastopochg_evt_th(mrioc, event_reply);
288013ef29eaSKashyap Desai 		break;
288113ef29eaSKashyap Desai 	}
28828e653455SKashyap Desai 	case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
28838e653455SKashyap Desai 	{
28848e653455SKashyap Desai 		process_evt_bh = 1;
28858e653455SKashyap Desai 		mpi3mr_pcietopochg_evt_th(mrioc, event_reply);
28868e653455SKashyap Desai 		break;
28878e653455SKashyap Desai 	}
288878b76a07SSreekanth Reddy 	case MPI3_EVENT_PREPARE_FOR_RESET:
288978b76a07SSreekanth Reddy 	{
289078b76a07SSreekanth Reddy 		mpi3mr_preparereset_evt_th(mrioc, event_reply);
289178b76a07SSreekanth Reddy 		ack_req = 0;
289278b76a07SSreekanth Reddy 		break;
289378b76a07SSreekanth Reddy 	}
289413ef29eaSKashyap Desai 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
289543ca1100SSumit Saxena 	case MPI3_EVENT_LOG_DATA:
28967188c03fSSreekanth Reddy 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
28977188c03fSSreekanth Reddy 	case MPI3_EVENT_ENCL_DEVICE_ADDED:
289813ef29eaSKashyap Desai 	{
289913ef29eaSKashyap Desai 		process_evt_bh = 1;
290013ef29eaSKashyap Desai 		break;
290113ef29eaSKashyap Desai 	}
2902e36710dcSKashyap Desai 	case MPI3_EVENT_ENERGY_PACK_CHANGE:
2903e36710dcSKashyap Desai 	{
2904e36710dcSKashyap Desai 		mpi3mr_energypackchg_evt_th(mrioc, event_reply);
2905e36710dcSKashyap Desai 		break;
2906e36710dcSKashyap Desai 	}
290795cca8d5SSreekanth Reddy 	case MPI3_EVENT_CABLE_MGMT:
290895cca8d5SSreekanth Reddy 	{
290995cca8d5SSreekanth Reddy 		mpi3mr_cablemgmt_evt_th(mrioc, event_reply);
291095cca8d5SSreekanth Reddy 		break;
291195cca8d5SSreekanth Reddy 	}
291213ef29eaSKashyap Desai 	case MPI3_EVENT_SAS_DISCOVERY:
291313ef29eaSKashyap Desai 	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
2914e36710dcSKashyap Desai 	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
29158e653455SKashyap Desai 	case MPI3_EVENT_PCIE_ENUMERATION:
291613ef29eaSKashyap Desai 		break;
291713ef29eaSKashyap Desai 	default:
291813ef29eaSKashyap Desai 		ioc_info(mrioc, "%s :event 0x%02x is not handled\n",
291913ef29eaSKashyap Desai 		    __func__, evt_type);
292013ef29eaSKashyap Desai 		break;
292113ef29eaSKashyap Desai 	}
292213ef29eaSKashyap Desai 	if (process_evt_bh || ack_req) {
292313ef29eaSKashyap Desai 		sz = event_reply->event_data_length * 4;
292413ef29eaSKashyap Desai 		fwevt = mpi3mr_alloc_fwevt(sz);
292513ef29eaSKashyap Desai 		if (!fwevt) {
292613ef29eaSKashyap Desai 			ioc_info(mrioc, "%s :failure at %s:%d/%s()!\n",
292713ef29eaSKashyap Desai 			    __func__, __FILE__, __LINE__, __func__);
292813ef29eaSKashyap Desai 			return;
292913ef29eaSKashyap Desai 		}
293013ef29eaSKashyap Desai 
293113ef29eaSKashyap Desai 		memcpy(fwevt->event_data, event_reply->event_data, sz);
293213ef29eaSKashyap Desai 		fwevt->mrioc = mrioc;
293313ef29eaSKashyap Desai 		fwevt->event_id = evt_type;
293413ef29eaSKashyap Desai 		fwevt->send_ack = ack_req;
293513ef29eaSKashyap Desai 		fwevt->process_evt = process_evt_bh;
293613ef29eaSKashyap Desai 		fwevt->evt_ctx = le32_to_cpu(event_reply->event_context);
293713ef29eaSKashyap Desai 		mpi3mr_fwevt_add_to_list(mrioc, fwevt);
293813ef29eaSKashyap Desai 	}
293913ef29eaSKashyap Desai }
294013ef29eaSKashyap Desai 
2941023ab2a9SKashyap Desai /**
294274e1f30aSKashyap Desai  * mpi3mr_setup_eedp - Setup EEDP information in MPI3 SCSI IO
294374e1f30aSKashyap Desai  * @mrioc: Adapter instance reference
294474e1f30aSKashyap Desai  * @scmd: SCSI command reference
294574e1f30aSKashyap Desai  * @scsiio_req: MPI3 SCSI IO request
294674e1f30aSKashyap Desai  *
294774e1f30aSKashyap Desai  * Identifies the protection information flags from the SCSI
294874e1f30aSKashyap Desai  * command and set appropriate flags in the MPI3 SCSI IO
294974e1f30aSKashyap Desai  * request.
295074e1f30aSKashyap Desai  *
295174e1f30aSKashyap Desai  * Return: Nothing
295274e1f30aSKashyap Desai  */
mpi3mr_setup_eedp(struct mpi3mr_ioc * mrioc,struct scsi_cmnd * scmd,struct mpi3_scsi_io_request * scsiio_req)295374e1f30aSKashyap Desai static void mpi3mr_setup_eedp(struct mpi3mr_ioc *mrioc,
295474e1f30aSKashyap Desai 	struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req)
295574e1f30aSKashyap Desai {
295674e1f30aSKashyap Desai 	u16 eedp_flags = 0;
295774e1f30aSKashyap Desai 	unsigned char prot_op = scsi_get_prot_op(scmd);
295874e1f30aSKashyap Desai 
295974e1f30aSKashyap Desai 	switch (prot_op) {
296074e1f30aSKashyap Desai 	case SCSI_PROT_NORMAL:
296174e1f30aSKashyap Desai 		return;
296274e1f30aSKashyap Desai 	case SCSI_PROT_READ_STRIP:
296374e1f30aSKashyap Desai 		eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE;
296474e1f30aSKashyap Desai 		break;
296574e1f30aSKashyap Desai 	case SCSI_PROT_WRITE_INSERT:
296674e1f30aSKashyap Desai 		eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_INSERT;
296774e1f30aSKashyap Desai 		break;
296874e1f30aSKashyap Desai 	case SCSI_PROT_READ_INSERT:
296974e1f30aSKashyap Desai 		eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_INSERT;
297074e1f30aSKashyap Desai 		scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID;
297174e1f30aSKashyap Desai 		break;
297274e1f30aSKashyap Desai 	case SCSI_PROT_WRITE_STRIP:
297374e1f30aSKashyap Desai 		eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE;
297474e1f30aSKashyap Desai 		scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID;
297574e1f30aSKashyap Desai 		break;
297674e1f30aSKashyap Desai 	case SCSI_PROT_READ_PASS:
297792cc94adSMartin K. Petersen 		eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK;
297874e1f30aSKashyap Desai 		scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID;
297974e1f30aSKashyap Desai 		break;
298074e1f30aSKashyap Desai 	case SCSI_PROT_WRITE_PASS:
298192cc94adSMartin K. Petersen 		if (scmd->prot_flags & SCSI_PROT_IP_CHECKSUM) {
298292cc94adSMartin K. Petersen 			eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REGEN;
298374e1f30aSKashyap Desai 			scsiio_req->sgl[0].eedp.application_tag_translation_mask =
298474e1f30aSKashyap Desai 			    0xffff;
298592cc94adSMartin K. Petersen 		} else
298692cc94adSMartin K. Petersen 			eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK;
298792cc94adSMartin K. Petersen 
298874e1f30aSKashyap Desai 		scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID;
298974e1f30aSKashyap Desai 		break;
299074e1f30aSKashyap Desai 	default:
299174e1f30aSKashyap Desai 		return;
299274e1f30aSKashyap Desai 	}
299374e1f30aSKashyap Desai 
299492cc94adSMartin K. Petersen 	if (scmd->prot_flags & SCSI_PROT_GUARD_CHECK)
299592cc94adSMartin K. Petersen 		eedp_flags |= MPI3_EEDPFLAGS_CHK_GUARD;
299692cc94adSMartin K. Petersen 
299792cc94adSMartin K. Petersen 	if (scmd->prot_flags & SCSI_PROT_IP_CHECKSUM)
299874e1f30aSKashyap Desai 		eedp_flags |= MPI3_EEDPFLAGS_HOST_GUARD_IP_CHKSUM;
299974e1f30aSKashyap Desai 
300092cc94adSMartin K. Petersen 	if (scmd->prot_flags & SCSI_PROT_REF_CHECK) {
300192cc94adSMartin K. Petersen 		eedp_flags |= MPI3_EEDPFLAGS_CHK_REF_TAG |
300292cc94adSMartin K. Petersen 			MPI3_EEDPFLAGS_INCR_PRI_REF_TAG;
300374e1f30aSKashyap Desai 		scsiio_req->cdb.eedp32.primary_reference_tag =
300492cc94adSMartin K. Petersen 			cpu_to_be32(scsi_prot_ref_tag(scmd));
300574e1f30aSKashyap Desai 	}
300674e1f30aSKashyap Desai 
300792cc94adSMartin K. Petersen 	if (scmd->prot_flags & SCSI_PROT_REF_INCREMENT)
300892cc94adSMartin K. Petersen 		eedp_flags |= MPI3_EEDPFLAGS_INCR_PRI_REF_TAG;
300992cc94adSMartin K. Petersen 
301092cc94adSMartin K. Petersen 	eedp_flags |= MPI3_EEDPFLAGS_ESC_MODE_APPTAG_DISABLE;
301192cc94adSMartin K. Petersen 
301292cc94adSMartin K. Petersen 	switch (scsi_prot_interval(scmd)) {
301374e1f30aSKashyap Desai 	case 512:
301474e1f30aSKashyap Desai 		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_512;
301574e1f30aSKashyap Desai 		break;
301674e1f30aSKashyap Desai 	case 520:
301774e1f30aSKashyap Desai 		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_520;
301874e1f30aSKashyap Desai 		break;
301974e1f30aSKashyap Desai 	case 4080:
302074e1f30aSKashyap Desai 		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4080;
302174e1f30aSKashyap Desai 		break;
302274e1f30aSKashyap Desai 	case 4088:
302374e1f30aSKashyap Desai 		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4088;
302474e1f30aSKashyap Desai 		break;
302574e1f30aSKashyap Desai 	case 4096:
302674e1f30aSKashyap Desai 		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4096;
302774e1f30aSKashyap Desai 		break;
302874e1f30aSKashyap Desai 	case 4104:
302974e1f30aSKashyap Desai 		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4104;
303074e1f30aSKashyap Desai 		break;
303174e1f30aSKashyap Desai 	case 4160:
303274e1f30aSKashyap Desai 		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4160;
303374e1f30aSKashyap Desai 		break;
303474e1f30aSKashyap Desai 	default:
303574e1f30aSKashyap Desai 		break;
303674e1f30aSKashyap Desai 	}
303774e1f30aSKashyap Desai 
303874e1f30aSKashyap Desai 	scsiio_req->sgl[0].eedp.eedp_flags = cpu_to_le16(eedp_flags);
303974e1f30aSKashyap Desai 	scsiio_req->sgl[0].eedp.flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_EXTENDED;
304074e1f30aSKashyap Desai }
304174e1f30aSKashyap Desai 
304274e1f30aSKashyap Desai /**
304374e1f30aSKashyap Desai  * mpi3mr_build_sense_buffer - Map sense information
304474e1f30aSKashyap Desai  * @desc: Sense type
304574e1f30aSKashyap Desai  * @buf: Sense buffer to populate
304674e1f30aSKashyap Desai  * @key: Sense key
304774e1f30aSKashyap Desai  * @asc: Additional sense code
304874e1f30aSKashyap Desai  * @ascq: Additional sense code qualifier
304974e1f30aSKashyap Desai  *
305074e1f30aSKashyap Desai  * Maps the given sense information into either descriptor or
305174e1f30aSKashyap Desai  * fixed format sense data.
305274e1f30aSKashyap Desai  *
305374e1f30aSKashyap Desai  * Return: Nothing
305474e1f30aSKashyap Desai  */
mpi3mr_build_sense_buffer(int desc,u8 * buf,u8 key,u8 asc,u8 ascq)305574e1f30aSKashyap Desai static inline void mpi3mr_build_sense_buffer(int desc, u8 *buf, u8 key,
305674e1f30aSKashyap Desai 	u8 asc, u8 ascq)
305774e1f30aSKashyap Desai {
305874e1f30aSKashyap Desai 	if (desc) {
305974e1f30aSKashyap Desai 		buf[0] = 0x72;	/* descriptor, current */
306074e1f30aSKashyap Desai 		buf[1] = key;
306174e1f30aSKashyap Desai 		buf[2] = asc;
306274e1f30aSKashyap Desai 		buf[3] = ascq;
306374e1f30aSKashyap Desai 		buf[7] = 0;
306474e1f30aSKashyap Desai 	} else {
306574e1f30aSKashyap Desai 		buf[0] = 0x70;	/* fixed, current */
306674e1f30aSKashyap Desai 		buf[2] = key;
306774e1f30aSKashyap Desai 		buf[7] = 0xa;
306874e1f30aSKashyap Desai 		buf[12] = asc;
306974e1f30aSKashyap Desai 		buf[13] = ascq;
307074e1f30aSKashyap Desai 	}
307174e1f30aSKashyap Desai }
307274e1f30aSKashyap Desai 
307374e1f30aSKashyap Desai /**
307474e1f30aSKashyap Desai  * mpi3mr_map_eedp_error - Map EEDP errors from IOC status
307574e1f30aSKashyap Desai  * @scmd: SCSI command reference
307674e1f30aSKashyap Desai  * @ioc_status: status of MPI3 request
307774e1f30aSKashyap Desai  *
307874e1f30aSKashyap Desai  * Maps the EEDP error status of the SCSI IO request to sense
307974e1f30aSKashyap Desai  * data.
308074e1f30aSKashyap Desai  *
308174e1f30aSKashyap Desai  * Return: Nothing
308274e1f30aSKashyap Desai  */
mpi3mr_map_eedp_error(struct scsi_cmnd * scmd,u16 ioc_status)308374e1f30aSKashyap Desai static void mpi3mr_map_eedp_error(struct scsi_cmnd *scmd,
308474e1f30aSKashyap Desai 	u16 ioc_status)
308574e1f30aSKashyap Desai {
308674e1f30aSKashyap Desai 	u8 ascq = 0;
308774e1f30aSKashyap Desai 
308874e1f30aSKashyap Desai 	switch (ioc_status) {
308974e1f30aSKashyap Desai 	case MPI3_IOCSTATUS_EEDP_GUARD_ERROR:
309074e1f30aSKashyap Desai 		ascq = 0x01;
309174e1f30aSKashyap Desai 		break;
309274e1f30aSKashyap Desai 	case MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR:
309374e1f30aSKashyap Desai 		ascq = 0x02;
309474e1f30aSKashyap Desai 		break;
309574e1f30aSKashyap Desai 	case MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR:
309674e1f30aSKashyap Desai 		ascq = 0x03;
309774e1f30aSKashyap Desai 		break;
309874e1f30aSKashyap Desai 	default:
309974e1f30aSKashyap Desai 		ascq = 0x00;
310074e1f30aSKashyap Desai 		break;
310174e1f30aSKashyap Desai 	}
310274e1f30aSKashyap Desai 
310374e1f30aSKashyap Desai 	mpi3mr_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
310474e1f30aSKashyap Desai 	    0x10, ascq);
31051ff28f22SMartin K. Petersen 	scmd->result = (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
310674e1f30aSKashyap Desai }
310774e1f30aSKashyap Desai 
310874e1f30aSKashyap Desai /**
3109023ab2a9SKashyap Desai  * mpi3mr_process_op_reply_desc - reply descriptor handler
3110023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
3111023ab2a9SKashyap Desai  * @reply_desc: Operational reply descriptor
3112023ab2a9SKashyap Desai  * @reply_dma: place holder for reply DMA address
3113023ab2a9SKashyap Desai  * @qidx: Operational queue index
3114023ab2a9SKashyap Desai  *
3115023ab2a9SKashyap Desai  * Process the operational reply descriptor and identifies the
3116023ab2a9SKashyap Desai  * descriptor type. Based on the descriptor map the MPI3 request
3117023ab2a9SKashyap Desai  * status to a SCSI command status and calls scsi_done call
3118023ab2a9SKashyap Desai  * back.
3119023ab2a9SKashyap Desai  *
3120023ab2a9SKashyap Desai  * Return: Nothing
3121023ab2a9SKashyap Desai  */
mpi3mr_process_op_reply_desc(struct mpi3mr_ioc * mrioc,struct mpi3_default_reply_descriptor * reply_desc,u64 * reply_dma,u16 qidx)3122023ab2a9SKashyap Desai void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc,
3123023ab2a9SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma, u16 qidx)
3124023ab2a9SKashyap Desai {
3125023ab2a9SKashyap Desai 	u16 reply_desc_type, host_tag = 0;
3126023ab2a9SKashyap Desai 	u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
3127023ab2a9SKashyap Desai 	u32 ioc_loginfo = 0;
3128023ab2a9SKashyap Desai 	struct mpi3_status_reply_descriptor *status_desc = NULL;
3129023ab2a9SKashyap Desai 	struct mpi3_address_reply_descriptor *addr_desc = NULL;
3130023ab2a9SKashyap Desai 	struct mpi3_success_reply_descriptor *success_desc = NULL;
3131023ab2a9SKashyap Desai 	struct mpi3_scsi_io_reply *scsi_reply = NULL;
3132023ab2a9SKashyap Desai 	struct scsi_cmnd *scmd = NULL;
3133023ab2a9SKashyap Desai 	struct scmd_priv *priv = NULL;
3134023ab2a9SKashyap Desai 	u8 *sense_buf = NULL;
3135023ab2a9SKashyap Desai 	u8 scsi_state = 0, scsi_status = 0, sense_state = 0;
3136023ab2a9SKashyap Desai 	u32 xfer_count = 0, sense_count = 0, resp_data = 0;
3137023ab2a9SKashyap Desai 	u16 dev_handle = 0xFFFF;
3138023ab2a9SKashyap Desai 	struct scsi_sense_hdr sshdr;
3139f10af057SSreekanth Reddy 	struct mpi3mr_stgt_priv_data *stgt_priv_data = NULL;
3140f10af057SSreekanth Reddy 	struct mpi3mr_sdev_priv_data *sdev_priv_data = NULL;
3141f10af057SSreekanth Reddy 	u32 ioc_pend_data_len = 0, tg_pend_data_len = 0, data_len_blks = 0;
3142f10af057SSreekanth Reddy 	struct mpi3mr_throttle_group_info *tg = NULL;
3143f10af057SSreekanth Reddy 	u8 throttle_enabled_dev = 0;
3144023ab2a9SKashyap Desai 
3145023ab2a9SKashyap Desai 	*reply_dma = 0;
3146023ab2a9SKashyap Desai 	reply_desc_type = le16_to_cpu(reply_desc->reply_flags) &
3147023ab2a9SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
3148023ab2a9SKashyap Desai 	switch (reply_desc_type) {
3149023ab2a9SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
3150023ab2a9SKashyap Desai 		status_desc = (struct mpi3_status_reply_descriptor *)reply_desc;
3151023ab2a9SKashyap Desai 		host_tag = le16_to_cpu(status_desc->host_tag);
3152023ab2a9SKashyap Desai 		ioc_status = le16_to_cpu(status_desc->ioc_status);
3153023ab2a9SKashyap Desai 		if (ioc_status &
3154023ab2a9SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
3155023ab2a9SKashyap Desai 			ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
3156023ab2a9SKashyap Desai 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
3157023ab2a9SKashyap Desai 		break;
3158023ab2a9SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
3159023ab2a9SKashyap Desai 		addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
3160023ab2a9SKashyap Desai 		*reply_dma = le64_to_cpu(addr_desc->reply_frame_address);
3161023ab2a9SKashyap Desai 		scsi_reply = mpi3mr_get_reply_virt_addr(mrioc,
3162023ab2a9SKashyap Desai 		    *reply_dma);
3163023ab2a9SKashyap Desai 		if (!scsi_reply) {
3164023ab2a9SKashyap Desai 			panic("%s: scsi_reply is NULL, this shouldn't happen\n",
3165023ab2a9SKashyap Desai 			    mrioc->name);
3166023ab2a9SKashyap Desai 			goto out;
3167023ab2a9SKashyap Desai 		}
3168023ab2a9SKashyap Desai 		host_tag = le16_to_cpu(scsi_reply->host_tag);
3169023ab2a9SKashyap Desai 		ioc_status = le16_to_cpu(scsi_reply->ioc_status);
3170023ab2a9SKashyap Desai 		scsi_status = scsi_reply->scsi_status;
3171023ab2a9SKashyap Desai 		scsi_state = scsi_reply->scsi_state;
3172023ab2a9SKashyap Desai 		dev_handle = le16_to_cpu(scsi_reply->dev_handle);
3173023ab2a9SKashyap Desai 		sense_state = (scsi_state & MPI3_SCSI_STATE_SENSE_MASK);
3174023ab2a9SKashyap Desai 		xfer_count = le32_to_cpu(scsi_reply->transfer_count);
3175023ab2a9SKashyap Desai 		sense_count = le32_to_cpu(scsi_reply->sense_count);
3176023ab2a9SKashyap Desai 		resp_data = le32_to_cpu(scsi_reply->response_data);
3177023ab2a9SKashyap Desai 		sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
3178023ab2a9SKashyap Desai 		    le64_to_cpu(scsi_reply->sense_data_buffer_address));
3179023ab2a9SKashyap Desai 		if (ioc_status &
3180023ab2a9SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
3181023ab2a9SKashyap Desai 			ioc_loginfo = le32_to_cpu(scsi_reply->ioc_log_info);
3182023ab2a9SKashyap Desai 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
3183023ab2a9SKashyap Desai 		if (sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY)
3184023ab2a9SKashyap Desai 			panic("%s: Ran out of sense buffers\n", mrioc->name);
3185023ab2a9SKashyap Desai 		break;
3186023ab2a9SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
3187023ab2a9SKashyap Desai 		success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
3188023ab2a9SKashyap Desai 		host_tag = le16_to_cpu(success_desc->host_tag);
3189023ab2a9SKashyap Desai 		break;
3190023ab2a9SKashyap Desai 	default:
3191023ab2a9SKashyap Desai 		break;
3192023ab2a9SKashyap Desai 	}
3193023ab2a9SKashyap Desai 	scmd = mpi3mr_scmd_from_host_tag(mrioc, host_tag, qidx);
3194023ab2a9SKashyap Desai 	if (!scmd) {
3195023ab2a9SKashyap Desai 		panic("%s: Cannot Identify scmd for host_tag 0x%x\n",
3196023ab2a9SKashyap Desai 		    mrioc->name, host_tag);
3197023ab2a9SKashyap Desai 		goto out;
3198023ab2a9SKashyap Desai 	}
3199023ab2a9SKashyap Desai 	priv = scsi_cmd_priv(scmd);
3200f10af057SSreekanth Reddy 
3201f10af057SSreekanth Reddy 	data_len_blks = scsi_bufflen(scmd) >> 9;
3202f10af057SSreekanth Reddy 	sdev_priv_data = scmd->device->hostdata;
3203f10af057SSreekanth Reddy 	if (sdev_priv_data) {
3204f10af057SSreekanth Reddy 		stgt_priv_data = sdev_priv_data->tgt_priv_data;
3205f10af057SSreekanth Reddy 		if (stgt_priv_data) {
3206f10af057SSreekanth Reddy 			tg = stgt_priv_data->throttle_group;
3207f10af057SSreekanth Reddy 			throttle_enabled_dev =
3208f10af057SSreekanth Reddy 			    stgt_priv_data->io_throttle_enabled;
3209f10af057SSreekanth Reddy 		}
3210f10af057SSreekanth Reddy 	}
3211f10af057SSreekanth Reddy 	if (unlikely((data_len_blks >= mrioc->io_throttle_data_length) &&
3212f10af057SSreekanth Reddy 	    throttle_enabled_dev)) {
3213f10af057SSreekanth Reddy 		ioc_pend_data_len = atomic_sub_return(data_len_blks,
3214f10af057SSreekanth Reddy 		    &mrioc->pend_large_data_sz);
3215f10af057SSreekanth Reddy 		if (tg) {
3216f10af057SSreekanth Reddy 			tg_pend_data_len = atomic_sub_return(data_len_blks,
3217f10af057SSreekanth Reddy 			    &tg->pend_large_data_sz);
3218f10af057SSreekanth Reddy 			if (tg->io_divert  && ((ioc_pend_data_len <=
3219f10af057SSreekanth Reddy 			    mrioc->io_throttle_low) &&
3220f10af057SSreekanth Reddy 			    (tg_pend_data_len <= tg->low))) {
3221f10af057SSreekanth Reddy 				tg->io_divert = 0;
3222f10af057SSreekanth Reddy 				mpi3mr_set_io_divert_for_all_vd_in_tg(
3223f10af057SSreekanth Reddy 				    mrioc, tg, 0);
3224f10af057SSreekanth Reddy 			}
3225f10af057SSreekanth Reddy 		} else {
3226f10af057SSreekanth Reddy 			if (ioc_pend_data_len <= mrioc->io_throttle_low)
3227f10af057SSreekanth Reddy 				stgt_priv_data->io_divert = 0;
3228f10af057SSreekanth Reddy 		}
3229f10af057SSreekanth Reddy 	} else if (unlikely((stgt_priv_data && stgt_priv_data->io_divert))) {
3230f10af057SSreekanth Reddy 		ioc_pend_data_len = atomic_read(&mrioc->pend_large_data_sz);
3231f10af057SSreekanth Reddy 		if (!tg) {
3232f10af057SSreekanth Reddy 			if (ioc_pend_data_len <= mrioc->io_throttle_low)
3233f10af057SSreekanth Reddy 				stgt_priv_data->io_divert = 0;
3234f10af057SSreekanth Reddy 
3235f10af057SSreekanth Reddy 		} else if (ioc_pend_data_len <= mrioc->io_throttle_low) {
3236f10af057SSreekanth Reddy 			tg_pend_data_len = atomic_read(&tg->pend_large_data_sz);
3237f10af057SSreekanth Reddy 			if (tg->io_divert  && (tg_pend_data_len <= tg->low)) {
3238f10af057SSreekanth Reddy 				tg->io_divert = 0;
3239f10af057SSreekanth Reddy 				mpi3mr_set_io_divert_for_all_vd_in_tg(
3240f10af057SSreekanth Reddy 				    mrioc, tg, 0);
3241f10af057SSreekanth Reddy 			}
3242f10af057SSreekanth Reddy 		}
3243f10af057SSreekanth Reddy 	}
3244f10af057SSreekanth Reddy 
3245023ab2a9SKashyap Desai 	if (success_desc) {
3246023ab2a9SKashyap Desai 		scmd->result = DID_OK << 16;
3247023ab2a9SKashyap Desai 		goto out_success;
3248023ab2a9SKashyap Desai 	}
324999922461SSreekanth Reddy 
325099922461SSreekanth Reddy 	scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_count);
3251023ab2a9SKashyap Desai 	if (ioc_status == MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN &&
3252023ab2a9SKashyap Desai 	    xfer_count == 0 && (scsi_status == MPI3_SCSI_STATUS_BUSY ||
3253023ab2a9SKashyap Desai 	    scsi_status == MPI3_SCSI_STATUS_RESERVATION_CONFLICT ||
3254023ab2a9SKashyap Desai 	    scsi_status == MPI3_SCSI_STATUS_TASK_SET_FULL))
3255023ab2a9SKashyap Desai 		ioc_status = MPI3_IOCSTATUS_SUCCESS;
3256023ab2a9SKashyap Desai 
3257023ab2a9SKashyap Desai 	if ((sense_state == MPI3_SCSI_STATE_SENSE_VALID) && sense_count &&
3258023ab2a9SKashyap Desai 	    sense_buf) {
3259023ab2a9SKashyap Desai 		u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, sense_count);
3260023ab2a9SKashyap Desai 
3261023ab2a9SKashyap Desai 		memcpy(scmd->sense_buffer, sense_buf, sz);
3262023ab2a9SKashyap Desai 	}
3263023ab2a9SKashyap Desai 
3264023ab2a9SKashyap Desai 	switch (ioc_status) {
3265023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_BUSY:
3266023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_INSUFFICIENT_RESOURCES:
3267023ab2a9SKashyap Desai 		scmd->result = SAM_STAT_BUSY;
3268023ab2a9SKashyap Desai 		break;
3269023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3270023ab2a9SKashyap Desai 		scmd->result = DID_NO_CONNECT << 16;
3271023ab2a9SKashyap Desai 		break;
3272023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED:
3273023ab2a9SKashyap Desai 		scmd->result = DID_SOFT_ERROR << 16;
3274023ab2a9SKashyap Desai 		break;
3275023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_SCSI_TASK_TERMINATED:
3276023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_SCSI_EXT_TERMINATED:
3277023ab2a9SKashyap Desai 		scmd->result = DID_RESET << 16;
3278023ab2a9SKashyap Desai 		break;
3279023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3280023ab2a9SKashyap Desai 		if ((xfer_count == 0) || (scmd->underflow > xfer_count))
3281023ab2a9SKashyap Desai 			scmd->result = DID_SOFT_ERROR << 16;
3282023ab2a9SKashyap Desai 		else
3283023ab2a9SKashyap Desai 			scmd->result = (DID_OK << 16) | scsi_status;
3284023ab2a9SKashyap Desai 		break;
3285023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN:
3286023ab2a9SKashyap Desai 		scmd->result = (DID_OK << 16) | scsi_status;
3287023ab2a9SKashyap Desai 		if (sense_state == MPI3_SCSI_STATE_SENSE_VALID)
3288023ab2a9SKashyap Desai 			break;
3289023ab2a9SKashyap Desai 		if (xfer_count < scmd->underflow) {
3290023ab2a9SKashyap Desai 			if (scsi_status == SAM_STAT_BUSY)
3291023ab2a9SKashyap Desai 				scmd->result = SAM_STAT_BUSY;
3292023ab2a9SKashyap Desai 			else
3293023ab2a9SKashyap Desai 				scmd->result = DID_SOFT_ERROR << 16;
3294023ab2a9SKashyap Desai 		} else if ((scsi_state & (MPI3_SCSI_STATE_NO_SCSI_STATUS)) ||
3295023ab2a9SKashyap Desai 		    (sense_state != MPI3_SCSI_STATE_SENSE_NOT_AVAILABLE))
3296023ab2a9SKashyap Desai 			scmd->result = DID_SOFT_ERROR << 16;
3297023ab2a9SKashyap Desai 		else if (scsi_state & MPI3_SCSI_STATE_TERMINATED)
3298023ab2a9SKashyap Desai 			scmd->result = DID_RESET << 16;
3299023ab2a9SKashyap Desai 		break;
3300023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_SCSI_DATA_OVERRUN:
3301023ab2a9SKashyap Desai 		scsi_set_resid(scmd, 0);
3302023ab2a9SKashyap Desai 		fallthrough;
3303023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR:
3304023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_SUCCESS:
3305023ab2a9SKashyap Desai 		scmd->result = (DID_OK << 16) | scsi_status;
3306023ab2a9SKashyap Desai 		if ((scsi_state & (MPI3_SCSI_STATE_NO_SCSI_STATUS)) ||
3307023ab2a9SKashyap Desai 		    (sense_state == MPI3_SCSI_STATE_SENSE_FAILED) ||
3308023ab2a9SKashyap Desai 			(sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY))
3309023ab2a9SKashyap Desai 			scmd->result = DID_SOFT_ERROR << 16;
3310023ab2a9SKashyap Desai 		else if (scsi_state & MPI3_SCSI_STATE_TERMINATED)
3311023ab2a9SKashyap Desai 			scmd->result = DID_RESET << 16;
3312023ab2a9SKashyap Desai 		break;
331374e1f30aSKashyap Desai 	case MPI3_IOCSTATUS_EEDP_GUARD_ERROR:
331474e1f30aSKashyap Desai 	case MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR:
331574e1f30aSKashyap Desai 	case MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR:
331674e1f30aSKashyap Desai 		mpi3mr_map_eedp_error(scmd, ioc_status);
331774e1f30aSKashyap Desai 		break;
3318023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3319023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_INVALID_FUNCTION:
3320023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_INVALID_SGL:
3321023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_INTERNAL_ERROR:
3322023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_INVALID_FIELD:
3323023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_INVALID_STATE:
3324023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_SCSI_IO_DATA_ERROR:
3325023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3326023ab2a9SKashyap Desai 	case MPI3_IOCSTATUS_INSUFFICIENT_POWER:
3327023ab2a9SKashyap Desai 	default:
3328023ab2a9SKashyap Desai 		scmd->result = DID_SOFT_ERROR << 16;
3329023ab2a9SKashyap Desai 		break;
3330023ab2a9SKashyap Desai 	}
3331023ab2a9SKashyap Desai 
3332023ab2a9SKashyap Desai 	if (scmd->result != (DID_OK << 16) && (scmd->cmnd[0] != ATA_12) &&
33337d21fcfbSShin'ichiro Kawasaki 	    (scmd->cmnd[0] != ATA_16) &&
33347d21fcfbSShin'ichiro Kawasaki 	    mrioc->logging_level & MPI3_DEBUG_SCSI_ERROR) {
3335023ab2a9SKashyap Desai 		ioc_info(mrioc, "%s :scmd->result 0x%x\n", __func__,
3336023ab2a9SKashyap Desai 		    scmd->result);
3337023ab2a9SKashyap Desai 		scsi_print_command(scmd);
3338023ab2a9SKashyap Desai 		ioc_info(mrioc,
3339023ab2a9SKashyap Desai 		    "%s :Command issued to handle 0x%02x returned with error 0x%04x loginfo 0x%08x, qid %d\n",
3340023ab2a9SKashyap Desai 		    __func__, dev_handle, ioc_status, ioc_loginfo,
3341023ab2a9SKashyap Desai 		    priv->req_q_idx + 1);
3342023ab2a9SKashyap Desai 		ioc_info(mrioc,
3343023ab2a9SKashyap Desai 		    " host_tag %d scsi_state 0x%02x scsi_status 0x%02x, xfer_cnt %d resp_data 0x%x\n",
3344023ab2a9SKashyap Desai 		    host_tag, scsi_state, scsi_status, xfer_count, resp_data);
3345023ab2a9SKashyap Desai 		if (sense_buf) {
3346023ab2a9SKashyap Desai 			scsi_normalize_sense(sense_buf, sense_count, &sshdr);
3347023ab2a9SKashyap Desai 			ioc_info(mrioc,
3348023ab2a9SKashyap Desai 			    "%s :sense_count 0x%x, sense_key 0x%x ASC 0x%x, ASCQ 0x%x\n",
3349023ab2a9SKashyap Desai 			    __func__, sense_count, sshdr.sense_key,
3350023ab2a9SKashyap Desai 			    sshdr.asc, sshdr.ascq);
3351023ab2a9SKashyap Desai 		}
3352023ab2a9SKashyap Desai 	}
3353023ab2a9SKashyap Desai out_success:
335474e1f30aSKashyap Desai 	if (priv->meta_sg_valid) {
335574e1f30aSKashyap Desai 		dma_unmap_sg(&mrioc->pdev->dev, scsi_prot_sglist(scmd),
335674e1f30aSKashyap Desai 		    scsi_prot_sg_count(scmd), scmd->sc_data_direction);
335774e1f30aSKashyap Desai 	}
3358023ab2a9SKashyap Desai 	mpi3mr_clear_scmd_priv(mrioc, scmd);
3359023ab2a9SKashyap Desai 	scsi_dma_unmap(scmd);
33601a30fd18SBart Van Assche 	scsi_done(scmd);
3361023ab2a9SKashyap Desai out:
3362023ab2a9SKashyap Desai 	if (sense_buf)
3363023ab2a9SKashyap Desai 		mpi3mr_repost_sense_buf(mrioc,
3364023ab2a9SKashyap Desai 		    le64_to_cpu(scsi_reply->sense_data_buffer_address));
3365023ab2a9SKashyap Desai }
3366023ab2a9SKashyap Desai 
3367023ab2a9SKashyap Desai /**
3368023ab2a9SKashyap Desai  * mpi3mr_get_chain_idx - get free chain buffer index
3369023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
3370023ab2a9SKashyap Desai  *
3371023ab2a9SKashyap Desai  * Try to get a free chain buffer index from the free pool.
3372023ab2a9SKashyap Desai  *
3373023ab2a9SKashyap Desai  * Return: -1 on failure or the free chain buffer index
3374023ab2a9SKashyap Desai  */
mpi3mr_get_chain_idx(struct mpi3mr_ioc * mrioc)3375023ab2a9SKashyap Desai static int mpi3mr_get_chain_idx(struct mpi3mr_ioc *mrioc)
3376023ab2a9SKashyap Desai {
3377023ab2a9SKashyap Desai 	u8 retry_count = 5;
3378023ab2a9SKashyap Desai 	int cmd_idx = -1;
33792acc635aSRanjan Kumar 	unsigned long flags;
3380023ab2a9SKashyap Desai 
33812acc635aSRanjan Kumar 	spin_lock_irqsave(&mrioc->chain_buf_lock, flags);
3382023ab2a9SKashyap Desai 	do {
3383023ab2a9SKashyap Desai 		cmd_idx = find_first_zero_bit(mrioc->chain_bitmap,
3384023ab2a9SKashyap Desai 		    mrioc->chain_buf_count);
3385023ab2a9SKashyap Desai 		if (cmd_idx < mrioc->chain_buf_count) {
3386023ab2a9SKashyap Desai 			set_bit(cmd_idx, mrioc->chain_bitmap);
3387023ab2a9SKashyap Desai 			break;
3388023ab2a9SKashyap Desai 		}
3389023ab2a9SKashyap Desai 		cmd_idx = -1;
3390023ab2a9SKashyap Desai 	} while (retry_count--);
33912acc635aSRanjan Kumar 	spin_unlock_irqrestore(&mrioc->chain_buf_lock, flags);
3392023ab2a9SKashyap Desai 	return cmd_idx;
3393023ab2a9SKashyap Desai }
3394023ab2a9SKashyap Desai 
3395023ab2a9SKashyap Desai /**
3396023ab2a9SKashyap Desai  * mpi3mr_prepare_sg_scmd - build scatter gather list
3397023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
3398023ab2a9SKashyap Desai  * @scmd: SCSI command reference
3399023ab2a9SKashyap Desai  * @scsiio_req: MPI3 SCSI IO request
3400023ab2a9SKashyap Desai  *
3401023ab2a9SKashyap Desai  * This function maps SCSI command's data and protection SGEs to
3402023ab2a9SKashyap Desai  * MPI request SGEs. If required additional 4K chain buffer is
3403023ab2a9SKashyap Desai  * used to send the SGEs.
3404023ab2a9SKashyap Desai  *
3405023ab2a9SKashyap Desai  * Return: 0 on success, -ENOMEM on dma_map_sg failure
3406023ab2a9SKashyap Desai  */
mpi3mr_prepare_sg_scmd(struct mpi3mr_ioc * mrioc,struct scsi_cmnd * scmd,struct mpi3_scsi_io_request * scsiio_req)3407023ab2a9SKashyap Desai static int mpi3mr_prepare_sg_scmd(struct mpi3mr_ioc *mrioc,
3408023ab2a9SKashyap Desai 	struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req)
3409023ab2a9SKashyap Desai {
3410023ab2a9SKashyap Desai 	dma_addr_t chain_dma;
3411023ab2a9SKashyap Desai 	struct scatterlist *sg_scmd;
3412023ab2a9SKashyap Desai 	void *sg_local, *chain;
3413023ab2a9SKashyap Desai 	u32 chain_length;
3414023ab2a9SKashyap Desai 	int sges_left, chain_idx;
3415023ab2a9SKashyap Desai 	u32 sges_in_segment;
3416023ab2a9SKashyap Desai 	u8 simple_sgl_flags;
3417023ab2a9SKashyap Desai 	u8 simple_sgl_flags_last;
3418023ab2a9SKashyap Desai 	u8 last_chain_sgl_flags;
3419023ab2a9SKashyap Desai 	struct chain_element *chain_req;
3420023ab2a9SKashyap Desai 	struct scmd_priv *priv = NULL;
342174e1f30aSKashyap Desai 	u32 meta_sg = le32_to_cpu(scsiio_req->flags) &
342274e1f30aSKashyap Desai 	    MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI;
3423023ab2a9SKashyap Desai 
3424023ab2a9SKashyap Desai 	priv = scsi_cmd_priv(scmd);
3425023ab2a9SKashyap Desai 
3426023ab2a9SKashyap Desai 	simple_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE |
3427023ab2a9SKashyap Desai 	    MPI3_SGE_FLAGS_DLAS_SYSTEM;
3428023ab2a9SKashyap Desai 	simple_sgl_flags_last = simple_sgl_flags |
3429023ab2a9SKashyap Desai 	    MPI3_SGE_FLAGS_END_OF_LIST;
3430023ab2a9SKashyap Desai 	last_chain_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN |
3431023ab2a9SKashyap Desai 	    MPI3_SGE_FLAGS_DLAS_SYSTEM;
3432023ab2a9SKashyap Desai 
343374e1f30aSKashyap Desai 	if (meta_sg)
343474e1f30aSKashyap Desai 		sg_local = &scsiio_req->sgl[MPI3_SCSIIO_METASGL_INDEX];
343574e1f30aSKashyap Desai 	else
3436023ab2a9SKashyap Desai 		sg_local = &scsiio_req->sgl;
3437023ab2a9SKashyap Desai 
343874e1f30aSKashyap Desai 	if (!scsiio_req->data_length && !meta_sg) {
3439023ab2a9SKashyap Desai 		mpi3mr_build_zero_len_sge(sg_local);
3440023ab2a9SKashyap Desai 		return 0;
3441023ab2a9SKashyap Desai 	}
3442023ab2a9SKashyap Desai 
344374e1f30aSKashyap Desai 	if (meta_sg) {
344474e1f30aSKashyap Desai 		sg_scmd = scsi_prot_sglist(scmd);
344574e1f30aSKashyap Desai 		sges_left = dma_map_sg(&mrioc->pdev->dev,
344674e1f30aSKashyap Desai 		    scsi_prot_sglist(scmd),
344774e1f30aSKashyap Desai 		    scsi_prot_sg_count(scmd),
344874e1f30aSKashyap Desai 		    scmd->sc_data_direction);
344974e1f30aSKashyap Desai 		priv->meta_sg_valid = 1; /* To unmap meta sg DMA */
345074e1f30aSKashyap Desai 	} else {
345180d0624dSDamien Le Moal 		/*
345280d0624dSDamien Le Moal 		 * Some firmware versions byte-swap the REPORT ZONES command
345380d0624dSDamien Le Moal 		 * reply from ATA-ZAC devices by directly accessing in the host
345480d0624dSDamien Le Moal 		 * buffer. This does not respect the default command DMA
345580d0624dSDamien Le Moal 		 * direction and causes IOMMU page faults on some architectures
345680d0624dSDamien Le Moal 		 * with an IOMMU enforcing write mappings (e.g. AMD hosts).
345780d0624dSDamien Le Moal 		 * Avoid such issue by making the REPORT ZONES buffer mapping
345880d0624dSDamien Le Moal 		 * bi-directional.
345980d0624dSDamien Le Moal 		 */
346080d0624dSDamien Le Moal 		if (scmd->cmnd[0] == ZBC_IN && scmd->cmnd[1] == ZI_REPORT_ZONES)
346180d0624dSDamien Le Moal 			scmd->sc_data_direction = DMA_BIDIRECTIONAL;
3462023ab2a9SKashyap Desai 		sg_scmd = scsi_sglist(scmd);
3463023ab2a9SKashyap Desai 		sges_left = scsi_dma_map(scmd);
346474e1f30aSKashyap Desai 	}
3465023ab2a9SKashyap Desai 
3466023ab2a9SKashyap Desai 	if (sges_left < 0) {
3467023ab2a9SKashyap Desai 		sdev_printk(KERN_ERR, scmd->device,
3468023ab2a9SKashyap Desai 		    "scsi_dma_map failed: request for %d bytes!\n",
3469023ab2a9SKashyap Desai 		    scsi_bufflen(scmd));
3470023ab2a9SKashyap Desai 		return -ENOMEM;
3471023ab2a9SKashyap Desai 	}
3472d9adb81eSRanjan Kumar 	if (sges_left > mrioc->max_sgl_entries) {
3473023ab2a9SKashyap Desai 		sdev_printk(KERN_ERR, scmd->device,
3474023ab2a9SKashyap Desai 		    "scsi_dma_map returned unsupported sge count %d!\n",
3475023ab2a9SKashyap Desai 		    sges_left);
3476023ab2a9SKashyap Desai 		return -ENOMEM;
3477023ab2a9SKashyap Desai 	}
3478023ab2a9SKashyap Desai 
3479023ab2a9SKashyap Desai 	sges_in_segment = (mrioc->facts.op_req_sz -
3480023ab2a9SKashyap Desai 	    offsetof(struct mpi3_scsi_io_request, sgl)) / sizeof(struct mpi3_sge_common);
3481023ab2a9SKashyap Desai 
348274e1f30aSKashyap Desai 	if (scsiio_req->sgl[0].eedp.flags ==
348374e1f30aSKashyap Desai 	    MPI3_SGE_FLAGS_ELEMENT_TYPE_EXTENDED && !meta_sg) {
348474e1f30aSKashyap Desai 		sg_local += sizeof(struct mpi3_sge_common);
348574e1f30aSKashyap Desai 		sges_in_segment--;
348674e1f30aSKashyap Desai 		/* Reserve 1st segment (scsiio_req->sgl[0]) for eedp */
348774e1f30aSKashyap Desai 	}
348874e1f30aSKashyap Desai 
348974e1f30aSKashyap Desai 	if (scsiio_req->msg_flags ==
349074e1f30aSKashyap Desai 	    MPI3_SCSIIO_MSGFLAGS_METASGL_VALID && !meta_sg) {
349174e1f30aSKashyap Desai 		sges_in_segment--;
349274e1f30aSKashyap Desai 		/* Reserve last segment (scsiio_req->sgl[3]) for meta sg */
349374e1f30aSKashyap Desai 	}
349474e1f30aSKashyap Desai 
349574e1f30aSKashyap Desai 	if (meta_sg)
349674e1f30aSKashyap Desai 		sges_in_segment = 1;
349774e1f30aSKashyap Desai 
3498023ab2a9SKashyap Desai 	if (sges_left <= sges_in_segment)
3499023ab2a9SKashyap Desai 		goto fill_in_last_segment;
3500023ab2a9SKashyap Desai 
3501023ab2a9SKashyap Desai 	/* fill in main message segment when there is a chain following */
3502023ab2a9SKashyap Desai 	while (sges_in_segment > 1) {
3503023ab2a9SKashyap Desai 		mpi3mr_add_sg_single(sg_local, simple_sgl_flags,
3504023ab2a9SKashyap Desai 		    sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
3505023ab2a9SKashyap Desai 		sg_scmd = sg_next(sg_scmd);
3506023ab2a9SKashyap Desai 		sg_local += sizeof(struct mpi3_sge_common);
3507023ab2a9SKashyap Desai 		sges_left--;
3508023ab2a9SKashyap Desai 		sges_in_segment--;
3509023ab2a9SKashyap Desai 	}
3510023ab2a9SKashyap Desai 
3511023ab2a9SKashyap Desai 	chain_idx = mpi3mr_get_chain_idx(mrioc);
3512023ab2a9SKashyap Desai 	if (chain_idx < 0)
3513023ab2a9SKashyap Desai 		return -1;
3514023ab2a9SKashyap Desai 	chain_req = &mrioc->chain_sgl_list[chain_idx];
351574e1f30aSKashyap Desai 	if (meta_sg)
351674e1f30aSKashyap Desai 		priv->meta_chain_idx = chain_idx;
351774e1f30aSKashyap Desai 	else
3518023ab2a9SKashyap Desai 		priv->chain_idx = chain_idx;
3519023ab2a9SKashyap Desai 
3520023ab2a9SKashyap Desai 	chain = chain_req->addr;
3521023ab2a9SKashyap Desai 	chain_dma = chain_req->dma_addr;
3522023ab2a9SKashyap Desai 	sges_in_segment = sges_left;
3523023ab2a9SKashyap Desai 	chain_length = sges_in_segment * sizeof(struct mpi3_sge_common);
3524023ab2a9SKashyap Desai 
3525023ab2a9SKashyap Desai 	mpi3mr_add_sg_single(sg_local, last_chain_sgl_flags,
3526023ab2a9SKashyap Desai 	    chain_length, chain_dma);
3527023ab2a9SKashyap Desai 
3528023ab2a9SKashyap Desai 	sg_local = chain;
3529023ab2a9SKashyap Desai 
3530023ab2a9SKashyap Desai fill_in_last_segment:
3531023ab2a9SKashyap Desai 	while (sges_left > 0) {
3532023ab2a9SKashyap Desai 		if (sges_left == 1)
3533023ab2a9SKashyap Desai 			mpi3mr_add_sg_single(sg_local,
3534023ab2a9SKashyap Desai 			    simple_sgl_flags_last, sg_dma_len(sg_scmd),
3535023ab2a9SKashyap Desai 			    sg_dma_address(sg_scmd));
3536023ab2a9SKashyap Desai 		else
3537023ab2a9SKashyap Desai 			mpi3mr_add_sg_single(sg_local, simple_sgl_flags,
3538023ab2a9SKashyap Desai 			    sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
3539023ab2a9SKashyap Desai 		sg_scmd = sg_next(sg_scmd);
3540023ab2a9SKashyap Desai 		sg_local += sizeof(struct mpi3_sge_common);
3541023ab2a9SKashyap Desai 		sges_left--;
3542023ab2a9SKashyap Desai 	}
3543023ab2a9SKashyap Desai 
3544023ab2a9SKashyap Desai 	return 0;
3545023ab2a9SKashyap Desai }
3546023ab2a9SKashyap Desai 
3547023ab2a9SKashyap Desai /**
3548023ab2a9SKashyap Desai  * mpi3mr_build_sg_scmd - build scatter gather list for SCSI IO
3549023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
3550023ab2a9SKashyap Desai  * @scmd: SCSI command reference
3551023ab2a9SKashyap Desai  * @scsiio_req: MPI3 SCSI IO request
3552023ab2a9SKashyap Desai  *
3553023ab2a9SKashyap Desai  * This function calls mpi3mr_prepare_sg_scmd for constructing
3554023ab2a9SKashyap Desai  * both data SGEs and protection information SGEs in the MPI
3555023ab2a9SKashyap Desai  * format from the SCSI Command as appropriate .
3556023ab2a9SKashyap Desai  *
3557023ab2a9SKashyap Desai  * Return: return value of mpi3mr_prepare_sg_scmd.
3558023ab2a9SKashyap Desai  */
mpi3mr_build_sg_scmd(struct mpi3mr_ioc * mrioc,struct scsi_cmnd * scmd,struct mpi3_scsi_io_request * scsiio_req)3559023ab2a9SKashyap Desai static int mpi3mr_build_sg_scmd(struct mpi3mr_ioc *mrioc,
3560023ab2a9SKashyap Desai 	struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req)
3561023ab2a9SKashyap Desai {
3562023ab2a9SKashyap Desai 	int ret;
3563023ab2a9SKashyap Desai 
3564023ab2a9SKashyap Desai 	ret = mpi3mr_prepare_sg_scmd(mrioc, scmd, scsiio_req);
3565023ab2a9SKashyap Desai 	if (ret)
3566023ab2a9SKashyap Desai 		return ret;
3567023ab2a9SKashyap Desai 
356874e1f30aSKashyap Desai 	if (scsiio_req->msg_flags == MPI3_SCSIIO_MSGFLAGS_METASGL_VALID) {
356974e1f30aSKashyap Desai 		/* There is a valid meta sg */
357074e1f30aSKashyap Desai 		scsiio_req->flags |=
357174e1f30aSKashyap Desai 		    cpu_to_le32(MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI);
357274e1f30aSKashyap Desai 		ret = mpi3mr_prepare_sg_scmd(mrioc, scmd, scsiio_req);
357374e1f30aSKashyap Desai 	}
357474e1f30aSKashyap Desai 
3575023ab2a9SKashyap Desai 	return ret;
3576023ab2a9SKashyap Desai }
3577023ab2a9SKashyap Desai 
3578824a1566SKashyap Desai /**
3579c8665134SSreekanth Reddy  * mpi3mr_tm_response_name -  get TM response as a string
3580e844adb1SKashyap Desai  * @resp_code: TM response code
3581e844adb1SKashyap Desai  *
3582c8665134SSreekanth Reddy  * Convert known task management response code as a readable
3583c8665134SSreekanth Reddy  * string.
3584e844adb1SKashyap Desai  *
3585c8665134SSreekanth Reddy  * Return: response code string.
3586e844adb1SKashyap Desai  */
mpi3mr_tm_response_name(u8 resp_code)3587c8665134SSreekanth Reddy static const char *mpi3mr_tm_response_name(u8 resp_code)
3588e844adb1SKashyap Desai {
3589e844adb1SKashyap Desai 	char *desc;
3590e844adb1SKashyap Desai 
3591e844adb1SKashyap Desai 	switch (resp_code) {
3592c8665134SSreekanth Reddy 	case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE:
3593e844adb1SKashyap Desai 		desc = "task management request completed";
3594e844adb1SKashyap Desai 		break;
3595c8665134SSreekanth Reddy 	case MPI3_SCSITASKMGMT_RSPCODE_INVALID_FRAME:
3596e844adb1SKashyap Desai 		desc = "invalid frame";
3597e844adb1SKashyap Desai 		break;
3598c8665134SSreekanth Reddy 	case MPI3_SCSITASKMGMT_RSPCODE_TM_FUNCTION_NOT_SUPPORTED:
3599e844adb1SKashyap Desai 		desc = "task management request not supported";
3600e844adb1SKashyap Desai 		break;
3601c8665134SSreekanth Reddy 	case MPI3_SCSITASKMGMT_RSPCODE_TM_FAILED:
3602e844adb1SKashyap Desai 		desc = "task management request failed";
3603e844adb1SKashyap Desai 		break;
3604c8665134SSreekanth Reddy 	case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED:
3605e844adb1SKashyap Desai 		desc = "task management request succeeded";
3606e844adb1SKashyap Desai 		break;
3607c8665134SSreekanth Reddy 	case MPI3_SCSITASKMGMT_RSPCODE_TM_INVALID_LUN:
3608c8665134SSreekanth Reddy 		desc = "invalid LUN";
3609e844adb1SKashyap Desai 		break;
3610c8665134SSreekanth Reddy 	case MPI3_SCSITASKMGMT_RSPCODE_TM_OVERLAPPED_TAG:
3611e844adb1SKashyap Desai 		desc = "overlapped tag attempted";
3612e844adb1SKashyap Desai 		break;
3613c8665134SSreekanth Reddy 	case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC:
3614e844adb1SKashyap Desai 		desc = "task queued, however not sent to target";
3615e844adb1SKashyap Desai 		break;
3616c8665134SSreekanth Reddy 	case MPI3_SCSITASKMGMT_RSPCODE_TM_NVME_DENIED:
3617c8665134SSreekanth Reddy 		desc = "task management request denied by NVMe device";
3618c8665134SSreekanth Reddy 		break;
3619e844adb1SKashyap Desai 	default:
3620e844adb1SKashyap Desai 		desc = "unknown";
3621e844adb1SKashyap Desai 		break;
3622e844adb1SKashyap Desai 	}
3623c8665134SSreekanth Reddy 
3624c8665134SSreekanth Reddy 	return desc;
3625e844adb1SKashyap Desai }
3626e844adb1SKashyap Desai 
mpi3mr_poll_pend_io_completions(struct mpi3mr_ioc * mrioc)3627a91603a5SSreekanth Reddy inline void mpi3mr_poll_pend_io_completions(struct mpi3mr_ioc *mrioc)
3628a91603a5SSreekanth Reddy {
3629a91603a5SSreekanth Reddy 	int i;
3630a91603a5SSreekanth Reddy 	int num_of_reply_queues =
3631a91603a5SSreekanth Reddy 	    mrioc->num_op_reply_q + mrioc->op_reply_q_offset;
3632a91603a5SSreekanth Reddy 
3633a91603a5SSreekanth Reddy 	for (i = mrioc->op_reply_q_offset; i < num_of_reply_queues; i++)
3634a91603a5SSreekanth Reddy 		mpi3mr_process_op_reply_q(mrioc,
3635a91603a5SSreekanth Reddy 		    mrioc->intr_info[i].op_reply_q);
3636a91603a5SSreekanth Reddy }
3637a91603a5SSreekanth Reddy 
3638e844adb1SKashyap Desai /**
3639e844adb1SKashyap Desai  * mpi3mr_issue_tm - Issue Task Management request
3640e844adb1SKashyap Desai  * @mrioc: Adapter instance reference
3641e844adb1SKashyap Desai  * @tm_type: Task Management type
3642e844adb1SKashyap Desai  * @handle: Device handle
3643e844adb1SKashyap Desai  * @lun: lun ID
3644e844adb1SKashyap Desai  * @htag: Host tag of the TM request
3645a91603a5SSreekanth Reddy  * @timeout: TM timeout value
3646e844adb1SKashyap Desai  * @drv_cmd: Internal command tracker
3647e844adb1SKashyap Desai  * @resp_code: Response code place holder
3648a91603a5SSreekanth Reddy  * @scmd: SCSI command
3649e844adb1SKashyap Desai  *
3650e844adb1SKashyap Desai  * Issues a Task Management Request to the controller for a
3651e844adb1SKashyap Desai  * specified target, lun and command and wait for its completion
3652e844adb1SKashyap Desai  * and check TM response. Recover the TM if it timed out by
3653e844adb1SKashyap Desai  * issuing controller reset.
3654e844adb1SKashyap Desai  *
3655e844adb1SKashyap Desai  * Return: 0 on success, non-zero on errors
3656e844adb1SKashyap Desai  */
mpi3mr_issue_tm(struct mpi3mr_ioc * mrioc,u8 tm_type,u16 handle,uint lun,u16 htag,ulong timeout,struct mpi3mr_drv_cmd * drv_cmd,u8 * resp_code,struct scsi_cmnd * scmd)3657506bc1a0SSumit Saxena int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
3658e844adb1SKashyap Desai 	u16 handle, uint lun, u16 htag, ulong timeout,
3659e844adb1SKashyap Desai 	struct mpi3mr_drv_cmd *drv_cmd,
3660a91603a5SSreekanth Reddy 	u8 *resp_code, struct scsi_cmnd *scmd)
3661e844adb1SKashyap Desai {
3662e844adb1SKashyap Desai 	struct mpi3_scsi_task_mgmt_request tm_req;
3663e844adb1SKashyap Desai 	struct mpi3_scsi_task_mgmt_reply *tm_reply = NULL;
3664e844adb1SKashyap Desai 	int retval = 0;
3665e844adb1SKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev = NULL;
3666e844adb1SKashyap Desai 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
3667a91603a5SSreekanth Reddy 	struct scmd_priv *cmd_priv = NULL;
3668a91603a5SSreekanth Reddy 	struct scsi_device *sdev = NULL;
3669a91603a5SSreekanth Reddy 	struct mpi3mr_sdev_priv_data *sdev_priv_data = NULL;
3670e844adb1SKashyap Desai 
3671e844adb1SKashyap Desai 	ioc_info(mrioc, "%s :Issue TM: TM type (0x%x) for devhandle 0x%04x\n",
3672e844adb1SKashyap Desai 	     __func__, tm_type, handle);
3673e844adb1SKashyap Desai 	if (mrioc->unrecoverable) {
3674e844adb1SKashyap Desai 		retval = -1;
3675e844adb1SKashyap Desai 		ioc_err(mrioc, "%s :Issue TM: Unrecoverable controller\n",
3676e844adb1SKashyap Desai 		    __func__);
3677e844adb1SKashyap Desai 		goto out;
3678e844adb1SKashyap Desai 	}
3679e844adb1SKashyap Desai 
3680e844adb1SKashyap Desai 	memset(&tm_req, 0, sizeof(tm_req));
3681e844adb1SKashyap Desai 	mutex_lock(&drv_cmd->mutex);
3682e844adb1SKashyap Desai 	if (drv_cmd->state & MPI3MR_CMD_PENDING) {
3683e844adb1SKashyap Desai 		retval = -1;
3684e844adb1SKashyap Desai 		ioc_err(mrioc, "%s :Issue TM: Command is in use\n", __func__);
3685e844adb1SKashyap Desai 		mutex_unlock(&drv_cmd->mutex);
3686e844adb1SKashyap Desai 		goto out;
3687e844adb1SKashyap Desai 	}
3688e844adb1SKashyap Desai 	if (mrioc->reset_in_progress) {
3689e844adb1SKashyap Desai 		retval = -1;
3690e844adb1SKashyap Desai 		ioc_err(mrioc, "%s :Issue TM: Reset in progress\n", __func__);
3691e844adb1SKashyap Desai 		mutex_unlock(&drv_cmd->mutex);
3692e844adb1SKashyap Desai 		goto out;
3693e844adb1SKashyap Desai 	}
3694e844adb1SKashyap Desai 
3695e844adb1SKashyap Desai 	drv_cmd->state = MPI3MR_CMD_PENDING;
3696e844adb1SKashyap Desai 	drv_cmd->is_waiting = 1;
3697e844adb1SKashyap Desai 	drv_cmd->callback = NULL;
3698e844adb1SKashyap Desai 	tm_req.dev_handle = cpu_to_le16(handle);
3699e844adb1SKashyap Desai 	tm_req.task_type = tm_type;
3700e844adb1SKashyap Desai 	tm_req.host_tag = cpu_to_le16(htag);
3701e844adb1SKashyap Desai 
3702e844adb1SKashyap Desai 	int_to_scsilun(lun, (struct scsi_lun *)tm_req.lun);
3703e844adb1SKashyap Desai 	tm_req.function = MPI3_FUNCTION_SCSI_TASK_MGMT;
3704e844adb1SKashyap Desai 
3705e844adb1SKashyap Desai 	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
3706a91603a5SSreekanth Reddy 
3707a91603a5SSreekanth Reddy 	if (scmd) {
3708a91603a5SSreekanth Reddy 		sdev = scmd->device;
3709a91603a5SSreekanth Reddy 		sdev_priv_data = sdev->hostdata;
3710a91603a5SSreekanth Reddy 		scsi_tgt_priv_data = ((sdev_priv_data) ?
3711a91603a5SSreekanth Reddy 		    sdev_priv_data->tgt_priv_data : NULL);
3712a91603a5SSreekanth Reddy 	} else {
3713a91603a5SSreekanth Reddy 		if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata)
3714e844adb1SKashyap Desai 			scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
3715e844adb1SKashyap Desai 			    tgtdev->starget->hostdata;
3716a91603a5SSreekanth Reddy 	}
3717a91603a5SSreekanth Reddy 
3718a91603a5SSreekanth Reddy 	if (scsi_tgt_priv_data)
3719e844adb1SKashyap Desai 		atomic_inc(&scsi_tgt_priv_data->block_io);
3720a91603a5SSreekanth Reddy 
3721e844adb1SKashyap Desai 	if (tgtdev && (tgtdev->dev_type == MPI3_DEVICE_DEVFORM_PCIE)) {
3722e844adb1SKashyap Desai 		if (cmd_priv && tgtdev->dev_spec.pcie_inf.abort_to)
3723e844adb1SKashyap Desai 			timeout = tgtdev->dev_spec.pcie_inf.abort_to;
3724e844adb1SKashyap Desai 		else if (!cmd_priv && tgtdev->dev_spec.pcie_inf.reset_to)
3725e844adb1SKashyap Desai 			timeout = tgtdev->dev_spec.pcie_inf.reset_to;
3726e844adb1SKashyap Desai 	}
3727e844adb1SKashyap Desai 
3728e844adb1SKashyap Desai 	init_completion(&drv_cmd->done);
3729e844adb1SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &tm_req, sizeof(tm_req), 1);
3730e844adb1SKashyap Desai 	if (retval) {
3731e844adb1SKashyap Desai 		ioc_err(mrioc, "%s :Issue TM: Admin Post failed\n", __func__);
3732e844adb1SKashyap Desai 		goto out_unlock;
3733e844adb1SKashyap Desai 	}
3734e844adb1SKashyap Desai 	wait_for_completion_timeout(&drv_cmd->done, (timeout * HZ));
3735e844adb1SKashyap Desai 
3736e844adb1SKashyap Desai 	if (!(drv_cmd->state & MPI3MR_CMD_COMPLETE)) {
3737e844adb1SKashyap Desai 		drv_cmd->is_waiting = 0;
3738e844adb1SKashyap Desai 		retval = -1;
3739a91603a5SSreekanth Reddy 		if (!(drv_cmd->state & MPI3MR_CMD_RESET)) {
3740a91603a5SSreekanth Reddy 			dprint_tm(mrioc,
3741a91603a5SSreekanth Reddy 			    "task management request timed out after %ld seconds\n",
3742a91603a5SSreekanth Reddy 			    timeout);
3743a91603a5SSreekanth Reddy 			if (mrioc->logging_level & MPI3_DEBUG_TM)
3744a91603a5SSreekanth Reddy 				dprint_dump_req(&tm_req, sizeof(tm_req)/4);
3745e844adb1SKashyap Desai 			mpi3mr_soft_reset_handler(mrioc,
3746e844adb1SKashyap Desai 			    MPI3MR_RESET_FROM_TM_TIMEOUT, 1);
3747a91603a5SSreekanth Reddy 		}
3748e844adb1SKashyap Desai 		goto out_unlock;
3749e844adb1SKashyap Desai 	}
3750e844adb1SKashyap Desai 
3751a91603a5SSreekanth Reddy 	if (!(drv_cmd->state & MPI3MR_CMD_REPLY_VALID)) {
3752a91603a5SSreekanth Reddy 		dprint_tm(mrioc, "invalid task management reply message\n");
3753a91603a5SSreekanth Reddy 		retval = -1;
3754a91603a5SSreekanth Reddy 		goto out_unlock;
3755a91603a5SSreekanth Reddy 	}
3756a91603a5SSreekanth Reddy 
3757e844adb1SKashyap Desai 	tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply;
3758e844adb1SKashyap Desai 
3759a91603a5SSreekanth Reddy 	switch (drv_cmd->ioc_status) {
3760a91603a5SSreekanth Reddy 	case MPI3_IOCSTATUS_SUCCESS:
3761e844adb1SKashyap Desai 		*resp_code = le32_to_cpu(tm_reply->response_data) &
3762e844adb1SKashyap Desai 			MPI3MR_RI_MASK_RESPCODE;
3763a91603a5SSreekanth Reddy 		break;
3764a91603a5SSreekanth Reddy 	case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED:
3765a91603a5SSreekanth Reddy 		*resp_code = MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE;
3766a91603a5SSreekanth Reddy 		break;
3767a91603a5SSreekanth Reddy 	default:
3768a91603a5SSreekanth Reddy 		dprint_tm(mrioc,
3769a91603a5SSreekanth Reddy 		    "task management request to handle(0x%04x) is failed with ioc_status(0x%04x) log_info(0x%08x)\n",
3770a91603a5SSreekanth Reddy 		    handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo);
3771a91603a5SSreekanth Reddy 		retval = -1;
3772a91603a5SSreekanth Reddy 		goto out_unlock;
3773a91603a5SSreekanth Reddy 	}
3774a91603a5SSreekanth Reddy 
3775e844adb1SKashyap Desai 	switch (*resp_code) {
3776c8665134SSreekanth Reddy 	case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED:
3777c8665134SSreekanth Reddy 	case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE:
3778e844adb1SKashyap Desai 		break;
3779c8665134SSreekanth Reddy 	case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC:
3780e844adb1SKashyap Desai 		if (tm_type != MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK)
3781e844adb1SKashyap Desai 			retval = -1;
3782e844adb1SKashyap Desai 		break;
3783e844adb1SKashyap Desai 	default:
3784e844adb1SKashyap Desai 		retval = -1;
3785e844adb1SKashyap Desai 		break;
3786e844adb1SKashyap Desai 	}
3787e844adb1SKashyap Desai 
3788c8665134SSreekanth Reddy 	dprint_tm(mrioc,
3789c8665134SSreekanth Reddy 	    "task management request type(%d) completed for handle(0x%04x) with ioc_status(0x%04x), log_info(0x%08x), termination_count(%d), response:%s(0x%x)\n",
3790c8665134SSreekanth Reddy 	    tm_type, handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo,
3791c8665134SSreekanth Reddy 	    le32_to_cpu(tm_reply->termination_count),
3792c8665134SSreekanth Reddy 	    mpi3mr_tm_response_name(*resp_code), *resp_code);
3793e844adb1SKashyap Desai 
3794a91603a5SSreekanth Reddy 	if (!retval) {
3795a91603a5SSreekanth Reddy 		mpi3mr_ioc_disable_intr(mrioc);
3796a91603a5SSreekanth Reddy 		mpi3mr_poll_pend_io_completions(mrioc);
3797a91603a5SSreekanth Reddy 		mpi3mr_ioc_enable_intr(mrioc);
3798a91603a5SSreekanth Reddy 		mpi3mr_poll_pend_io_completions(mrioc);
379902ca7da2SRanjan Kumar 		mpi3mr_process_admin_reply_q(mrioc);
3800a91603a5SSreekanth Reddy 	}
3801a91603a5SSreekanth Reddy 	switch (tm_type) {
3802a91603a5SSreekanth Reddy 	case MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
3803a91603a5SSreekanth Reddy 		if (!scsi_tgt_priv_data)
3804a91603a5SSreekanth Reddy 			break;
3805a91603a5SSreekanth Reddy 		scsi_tgt_priv_data->pend_count = 0;
3806a91603a5SSreekanth Reddy 		blk_mq_tagset_busy_iter(&mrioc->shost->tag_set,
3807a91603a5SSreekanth Reddy 		    mpi3mr_count_tgt_pending,
3808a91603a5SSreekanth Reddy 		    (void *)scsi_tgt_priv_data->starget);
3809a91603a5SSreekanth Reddy 		break;
3810a91603a5SSreekanth Reddy 	case MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
3811a91603a5SSreekanth Reddy 		if (!sdev_priv_data)
3812a91603a5SSreekanth Reddy 			break;
3813a91603a5SSreekanth Reddy 		sdev_priv_data->pend_count = 0;
3814a91603a5SSreekanth Reddy 		blk_mq_tagset_busy_iter(&mrioc->shost->tag_set,
3815a91603a5SSreekanth Reddy 		    mpi3mr_count_dev_pending, (void *)sdev);
3816a91603a5SSreekanth Reddy 		break;
3817a91603a5SSreekanth Reddy 	default:
3818a91603a5SSreekanth Reddy 		break;
3819a91603a5SSreekanth Reddy 	}
3820a91603a5SSreekanth Reddy 
3821e844adb1SKashyap Desai out_unlock:
3822e844adb1SKashyap Desai 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
3823e844adb1SKashyap Desai 	mutex_unlock(&drv_cmd->mutex);
3824e844adb1SKashyap Desai 	if (scsi_tgt_priv_data)
3825e844adb1SKashyap Desai 		atomic_dec_if_positive(&scsi_tgt_priv_data->block_io);
3826e844adb1SKashyap Desai 	if (tgtdev)
3827e844adb1SKashyap Desai 		mpi3mr_tgtdev_put(tgtdev);
3828e844adb1SKashyap Desai out:
3829e844adb1SKashyap Desai 	return retval;
3830e844adb1SKashyap Desai }
3831e844adb1SKashyap Desai 
3832e844adb1SKashyap Desai /**
38338f9c6173SKashyap Desai  * mpi3mr_bios_param - BIOS param callback
38348f9c6173SKashyap Desai  * @sdev: SCSI device reference
38358f9c6173SKashyap Desai  * @bdev: Block device reference
38368f9c6173SKashyap Desai  * @capacity: Capacity in logical sectors
38378f9c6173SKashyap Desai  * @params: Parameter array
38388f9c6173SKashyap Desai  *
38398f9c6173SKashyap Desai  * Just the parameters with heads/secots/cylinders.
38408f9c6173SKashyap Desai  *
38418f9c6173SKashyap Desai  * Return: 0 always
38428f9c6173SKashyap Desai  */
mpi3mr_bios_param(struct scsi_device * sdev,struct block_device * bdev,sector_t capacity,int params[])38438f9c6173SKashyap Desai static int mpi3mr_bios_param(struct scsi_device *sdev,
38448f9c6173SKashyap Desai 	struct block_device *bdev, sector_t capacity, int params[])
38458f9c6173SKashyap Desai {
38468f9c6173SKashyap Desai 	int heads;
38478f9c6173SKashyap Desai 	int sectors;
38488f9c6173SKashyap Desai 	sector_t cylinders;
38498f9c6173SKashyap Desai 	ulong dummy;
38508f9c6173SKashyap Desai 
38518f9c6173SKashyap Desai 	heads = 64;
38528f9c6173SKashyap Desai 	sectors = 32;
38538f9c6173SKashyap Desai 
38548f9c6173SKashyap Desai 	dummy = heads * sectors;
38558f9c6173SKashyap Desai 	cylinders = capacity;
38568f9c6173SKashyap Desai 	sector_div(cylinders, dummy);
38578f9c6173SKashyap Desai 
38588f9c6173SKashyap Desai 	if ((ulong)capacity >= 0x200000) {
38598f9c6173SKashyap Desai 		heads = 255;
38608f9c6173SKashyap Desai 		sectors = 63;
38618f9c6173SKashyap Desai 		dummy = heads * sectors;
38628f9c6173SKashyap Desai 		cylinders = capacity;
38638f9c6173SKashyap Desai 		sector_div(cylinders, dummy);
38648f9c6173SKashyap Desai 	}
38658f9c6173SKashyap Desai 
38668f9c6173SKashyap Desai 	params[0] = heads;
38678f9c6173SKashyap Desai 	params[1] = sectors;
38688f9c6173SKashyap Desai 	params[2] = cylinders;
38698f9c6173SKashyap Desai 	return 0;
38708f9c6173SKashyap Desai }
38718f9c6173SKashyap Desai 
38728f9c6173SKashyap Desai /**
3873824a1566SKashyap Desai  * mpi3mr_map_queues - Map queues callback handler
3874824a1566SKashyap Desai  * @shost: SCSI host reference
3875824a1566SKashyap Desai  *
3876afd3a579SSreekanth Reddy  * Maps default and poll queues.
3877824a1566SKashyap Desai  *
3878afd3a579SSreekanth Reddy  * Return: return zero.
3879824a1566SKashyap Desai  */
mpi3mr_map_queues(struct Scsi_Host * shost)3880a4e1d0b7SBart Van Assche static void mpi3mr_map_queues(struct Scsi_Host *shost)
3881824a1566SKashyap Desai {
3882824a1566SKashyap Desai 	struct mpi3mr_ioc *mrioc = shost_priv(shost);
3883afd3a579SSreekanth Reddy 	int i, qoff, offset;
3884afd3a579SSreekanth Reddy 	struct blk_mq_queue_map *map = NULL;
3885824a1566SKashyap Desai 
3886afd3a579SSreekanth Reddy 	offset = mrioc->op_reply_q_offset;
3887afd3a579SSreekanth Reddy 
3888afd3a579SSreekanth Reddy 	for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
3889afd3a579SSreekanth Reddy 		map = &shost->tag_set.map[i];
3890afd3a579SSreekanth Reddy 
3891afd3a579SSreekanth Reddy 		map->nr_queues  = 0;
3892afd3a579SSreekanth Reddy 
3893afd3a579SSreekanth Reddy 		if (i == HCTX_TYPE_DEFAULT)
3894afd3a579SSreekanth Reddy 			map->nr_queues = mrioc->default_qcount;
3895afd3a579SSreekanth Reddy 		else if (i == HCTX_TYPE_POLL)
3896afd3a579SSreekanth Reddy 			map->nr_queues = mrioc->active_poll_qcount;
3897afd3a579SSreekanth Reddy 
3898afd3a579SSreekanth Reddy 		if (!map->nr_queues) {
3899afd3a579SSreekanth Reddy 			BUG_ON(i == HCTX_TYPE_DEFAULT);
3900afd3a579SSreekanth Reddy 			continue;
3901afd3a579SSreekanth Reddy 		}
3902afd3a579SSreekanth Reddy 
3903afd3a579SSreekanth Reddy 		/*
3904afd3a579SSreekanth Reddy 		 * The poll queue(s) doesn't have an IRQ (and hence IRQ
3905afd3a579SSreekanth Reddy 		 * affinity), so use the regular blk-mq cpu mapping
3906afd3a579SSreekanth Reddy 		 */
3907afd3a579SSreekanth Reddy 		map->queue_offset = qoff;
3908afd3a579SSreekanth Reddy 		if (i != HCTX_TYPE_POLL)
3909afd3a579SSreekanth Reddy 			blk_mq_pci_map_queues(map, mrioc->pdev, offset);
3910afd3a579SSreekanth Reddy 		else
3911afd3a579SSreekanth Reddy 			blk_mq_map_queues(map);
3912afd3a579SSreekanth Reddy 
3913afd3a579SSreekanth Reddy 		qoff += map->nr_queues;
3914afd3a579SSreekanth Reddy 		offset += map->nr_queues;
3915afd3a579SSreekanth Reddy 	}
3916824a1566SKashyap Desai }
3917824a1566SKashyap Desai 
3918824a1566SKashyap Desai /**
391971e80106SKashyap Desai  * mpi3mr_get_fw_pending_ios - Calculate pending I/O count
392071e80106SKashyap Desai  * @mrioc: Adapter instance reference
392171e80106SKashyap Desai  *
392271e80106SKashyap Desai  * Calculate the pending I/Os for the controller and return.
392371e80106SKashyap Desai  *
392471e80106SKashyap Desai  * Return: Number of pending I/Os
392571e80106SKashyap Desai  */
mpi3mr_get_fw_pending_ios(struct mpi3mr_ioc * mrioc)392671e80106SKashyap Desai static inline int mpi3mr_get_fw_pending_ios(struct mpi3mr_ioc *mrioc)
392771e80106SKashyap Desai {
392871e80106SKashyap Desai 	u16 i;
392971e80106SKashyap Desai 	uint pend_ios = 0;
393071e80106SKashyap Desai 
393171e80106SKashyap Desai 	for (i = 0; i < mrioc->num_op_reply_q; i++)
393271e80106SKashyap Desai 		pend_ios += atomic_read(&mrioc->op_reply_qinfo[i].pend_ios);
393371e80106SKashyap Desai 	return pend_ios;
393471e80106SKashyap Desai }
393571e80106SKashyap Desai 
393671e80106SKashyap Desai /**
393771e80106SKashyap Desai  * mpi3mr_print_pending_host_io - print pending I/Os
393871e80106SKashyap Desai  * @mrioc: Adapter instance reference
393971e80106SKashyap Desai  *
394071e80106SKashyap Desai  * Print number of pending I/Os and each I/O details prior to
394171e80106SKashyap Desai  * reset for debug purpose.
394271e80106SKashyap Desai  *
394371e80106SKashyap Desai  * Return: Nothing
394471e80106SKashyap Desai  */
mpi3mr_print_pending_host_io(struct mpi3mr_ioc * mrioc)394571e80106SKashyap Desai static void mpi3mr_print_pending_host_io(struct mpi3mr_ioc *mrioc)
394671e80106SKashyap Desai {
394771e80106SKashyap Desai 	struct Scsi_Host *shost = mrioc->shost;
394871e80106SKashyap Desai 
394971e80106SKashyap Desai 	ioc_info(mrioc, "%s :Pending commands prior to reset: %d\n",
395071e80106SKashyap Desai 	    __func__, mpi3mr_get_fw_pending_ios(mrioc));
395171e80106SKashyap Desai 	blk_mq_tagset_busy_iter(&shost->tag_set,
395271e80106SKashyap Desai 	    mpi3mr_print_scmd, (void *)mrioc);
395371e80106SKashyap Desai }
395471e80106SKashyap Desai 
395571e80106SKashyap Desai /**
395644dc724fSKashyap Desai  * mpi3mr_wait_for_host_io - block for I/Os to complete
395744dc724fSKashyap Desai  * @mrioc: Adapter instance reference
395844dc724fSKashyap Desai  * @timeout: time out in seconds
395944dc724fSKashyap Desai  * Waits for pending I/Os for the given adapter to complete or
396044dc724fSKashyap Desai  * to hit the timeout.
396144dc724fSKashyap Desai  *
396244dc724fSKashyap Desai  * Return: Nothing
396344dc724fSKashyap Desai  */
mpi3mr_wait_for_host_io(struct mpi3mr_ioc * mrioc,u32 timeout)396444dc724fSKashyap Desai void mpi3mr_wait_for_host_io(struct mpi3mr_ioc *mrioc, u32 timeout)
396544dc724fSKashyap Desai {
396644dc724fSKashyap Desai 	enum mpi3mr_iocstate iocstate;
396744dc724fSKashyap Desai 	int i = 0;
396844dc724fSKashyap Desai 
396944dc724fSKashyap Desai 	iocstate = mpi3mr_get_iocstate(mrioc);
397044dc724fSKashyap Desai 	if (iocstate != MRIOC_STATE_READY)
397144dc724fSKashyap Desai 		return;
397244dc724fSKashyap Desai 
397344dc724fSKashyap Desai 	if (!mpi3mr_get_fw_pending_ios(mrioc))
397444dc724fSKashyap Desai 		return;
397544dc724fSKashyap Desai 	ioc_info(mrioc,
397644dc724fSKashyap Desai 	    "%s :Waiting for %d seconds prior to reset for %d I/O\n",
397744dc724fSKashyap Desai 	    __func__, timeout, mpi3mr_get_fw_pending_ios(mrioc));
397844dc724fSKashyap Desai 
397944dc724fSKashyap Desai 	for (i = 0; i < timeout; i++) {
398044dc724fSKashyap Desai 		if (!mpi3mr_get_fw_pending_ios(mrioc))
398144dc724fSKashyap Desai 			break;
398244dc724fSKashyap Desai 		iocstate = mpi3mr_get_iocstate(mrioc);
398344dc724fSKashyap Desai 		if (iocstate != MRIOC_STATE_READY)
398444dc724fSKashyap Desai 			break;
398544dc724fSKashyap Desai 		msleep(1000);
398644dc724fSKashyap Desai 	}
398744dc724fSKashyap Desai 
398844dc724fSKashyap Desai 	ioc_info(mrioc, "%s :Pending I/Os after wait is: %d\n", __func__,
398944dc724fSKashyap Desai 	    mpi3mr_get_fw_pending_ios(mrioc));
399044dc724fSKashyap Desai }
399144dc724fSKashyap Desai 
399244dc724fSKashyap Desai /**
3993e7a8648eSRanjan Kumar  * mpi3mr_setup_divert_ws - Setup Divert IO flag for write same
3994e7a8648eSRanjan Kumar  * @mrioc: Adapter instance reference
3995e7a8648eSRanjan Kumar  * @scmd: SCSI command reference
3996e7a8648eSRanjan Kumar  * @scsiio_req: MPI3 SCSI IO request
3997e7a8648eSRanjan Kumar  * @scsiio_flags: Pointer to MPI3 SCSI IO Flags
3998e7a8648eSRanjan Kumar  * @wslen: write same max length
3999e7a8648eSRanjan Kumar  *
4000e7a8648eSRanjan Kumar  * Gets values of unmap, ndob and number of blocks from write
4001e7a8648eSRanjan Kumar  * same scsi io and based on these values it sets divert IO flag
4002e7a8648eSRanjan Kumar  * and reason for diverting IO to firmware.
4003e7a8648eSRanjan Kumar  *
4004e7a8648eSRanjan Kumar  * Return: Nothing
4005e7a8648eSRanjan Kumar  */
mpi3mr_setup_divert_ws(struct mpi3mr_ioc * mrioc,struct scsi_cmnd * scmd,struct mpi3_scsi_io_request * scsiio_req,u32 * scsiio_flags,u16 wslen)4006e7a8648eSRanjan Kumar static inline void mpi3mr_setup_divert_ws(struct mpi3mr_ioc *mrioc,
4007e7a8648eSRanjan Kumar 	struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req,
4008e7a8648eSRanjan Kumar 	u32 *scsiio_flags, u16 wslen)
4009e7a8648eSRanjan Kumar {
4010e7a8648eSRanjan Kumar 	u8 unmap = 0, ndob = 0;
4011e7a8648eSRanjan Kumar 	u8 opcode = scmd->cmnd[0];
4012e7a8648eSRanjan Kumar 	u32 num_blocks = 0;
4013e7a8648eSRanjan Kumar 	u16 sa = (scmd->cmnd[8] << 8) | (scmd->cmnd[9]);
4014e7a8648eSRanjan Kumar 
4015e7a8648eSRanjan Kumar 	if (opcode == WRITE_SAME_16) {
4016e7a8648eSRanjan Kumar 		unmap = scmd->cmnd[1] & 0x08;
4017e7a8648eSRanjan Kumar 		ndob = scmd->cmnd[1] & 0x01;
4018e7a8648eSRanjan Kumar 		num_blocks = get_unaligned_be32(scmd->cmnd + 10);
4019e7a8648eSRanjan Kumar 	} else if ((opcode == VARIABLE_LENGTH_CMD) && (sa == WRITE_SAME_32)) {
4020e7a8648eSRanjan Kumar 		unmap = scmd->cmnd[10] & 0x08;
4021e7a8648eSRanjan Kumar 		ndob = scmd->cmnd[10] & 0x01;
4022e7a8648eSRanjan Kumar 		num_blocks = get_unaligned_be32(scmd->cmnd + 28);
4023e7a8648eSRanjan Kumar 	} else
4024e7a8648eSRanjan Kumar 		return;
4025e7a8648eSRanjan Kumar 
4026e7a8648eSRanjan Kumar 	if ((unmap) && (ndob) && (num_blocks > wslen)) {
4027e7a8648eSRanjan Kumar 		scsiio_req->msg_flags |=
4028e7a8648eSRanjan Kumar 		    MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE;
4029e7a8648eSRanjan Kumar 		*scsiio_flags |=
4030e7a8648eSRanjan Kumar 			MPI3_SCSIIO_FLAGS_DIVERT_REASON_WRITE_SAME_TOO_LARGE;
4031e7a8648eSRanjan Kumar 	}
4032e7a8648eSRanjan Kumar }
4033e7a8648eSRanjan Kumar 
4034e7a8648eSRanjan Kumar /**
4035e844adb1SKashyap Desai  * mpi3mr_eh_host_reset - Host reset error handling callback
4036e844adb1SKashyap Desai  * @scmd: SCSI command reference
4037e844adb1SKashyap Desai  *
4038e844adb1SKashyap Desai  * Issue controller reset if the scmd is for a Physical Device,
4039e844adb1SKashyap Desai  * if the scmd is for RAID volume, then wait for
4040e844adb1SKashyap Desai  * MPI3MR_RAID_ERRREC_RESET_TIMEOUT and checke whether any
4041e844adb1SKashyap Desai  * pending I/Os prior to issuing reset to the controller.
4042e844adb1SKashyap Desai  *
4043e844adb1SKashyap Desai  * Return: SUCCESS of successful reset else FAILED
4044e844adb1SKashyap Desai  */
mpi3mr_eh_host_reset(struct scsi_cmnd * scmd)4045e844adb1SKashyap Desai static int mpi3mr_eh_host_reset(struct scsi_cmnd *scmd)
4046e844adb1SKashyap Desai {
4047e844adb1SKashyap Desai 	struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host);
404844dc724fSKashyap Desai 	struct mpi3mr_stgt_priv_data *stgt_priv_data;
404944dc724fSKashyap Desai 	struct mpi3mr_sdev_priv_data *sdev_priv_data;
405044dc724fSKashyap Desai 	u8 dev_type = MPI3_DEVICE_DEVFORM_VD;
4051e844adb1SKashyap Desai 	int retval = FAILED, ret;
4052e844adb1SKashyap Desai 
405344dc724fSKashyap Desai 	sdev_priv_data = scmd->device->hostdata;
405444dc724fSKashyap Desai 	if (sdev_priv_data && sdev_priv_data->tgt_priv_data) {
405544dc724fSKashyap Desai 		stgt_priv_data = sdev_priv_data->tgt_priv_data;
405644dc724fSKashyap Desai 		dev_type = stgt_priv_data->dev_type;
405744dc724fSKashyap Desai 	}
405844dc724fSKashyap Desai 
405944dc724fSKashyap Desai 	if (dev_type == MPI3_DEVICE_DEVFORM_VD) {
406044dc724fSKashyap Desai 		mpi3mr_wait_for_host_io(mrioc,
406144dc724fSKashyap Desai 		    MPI3MR_RAID_ERRREC_RESET_TIMEOUT);
406244dc724fSKashyap Desai 		if (!mpi3mr_get_fw_pending_ios(mrioc)) {
406344dc724fSKashyap Desai 			retval = SUCCESS;
406444dc724fSKashyap Desai 			goto out;
406544dc724fSKashyap Desai 		}
406644dc724fSKashyap Desai 	}
406744dc724fSKashyap Desai 
406871e80106SKashyap Desai 	mpi3mr_print_pending_host_io(mrioc);
4069e844adb1SKashyap Desai 	ret = mpi3mr_soft_reset_handler(mrioc,
4070e844adb1SKashyap Desai 	    MPI3MR_RESET_FROM_EH_HOS, 1);
4071e844adb1SKashyap Desai 	if (ret)
4072e844adb1SKashyap Desai 		goto out;
4073e844adb1SKashyap Desai 
4074e844adb1SKashyap Desai 	retval = SUCCESS;
4075e844adb1SKashyap Desai out:
4076e844adb1SKashyap Desai 	sdev_printk(KERN_INFO, scmd->device,
4077e844adb1SKashyap Desai 	    "Host reset is %s for scmd(%p)\n",
4078e844adb1SKashyap Desai 	    ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
4079e844adb1SKashyap Desai 
4080e844adb1SKashyap Desai 	return retval;
4081e844adb1SKashyap Desai }
4082e844adb1SKashyap Desai 
4083e844adb1SKashyap Desai /**
4084e844adb1SKashyap Desai  * mpi3mr_eh_target_reset - Target reset error handling callback
4085e844adb1SKashyap Desai  * @scmd: SCSI command reference
4086e844adb1SKashyap Desai  *
4087e844adb1SKashyap Desai  * Issue Target reset Task Management and verify the scmd is
4088e844adb1SKashyap Desai  * terminated successfully and return status accordingly.
4089e844adb1SKashyap Desai  *
4090e844adb1SKashyap Desai  * Return: SUCCESS of successful termination of the scmd else
4091e844adb1SKashyap Desai  *         FAILED
4092e844adb1SKashyap Desai  */
mpi3mr_eh_target_reset(struct scsi_cmnd * scmd)4093e844adb1SKashyap Desai static int mpi3mr_eh_target_reset(struct scsi_cmnd *scmd)
4094e844adb1SKashyap Desai {
4095e844adb1SKashyap Desai 	struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host);
4096e844adb1SKashyap Desai 	struct mpi3mr_stgt_priv_data *stgt_priv_data;
4097e844adb1SKashyap Desai 	struct mpi3mr_sdev_priv_data *sdev_priv_data;
4098e844adb1SKashyap Desai 	u16 dev_handle;
4099e844adb1SKashyap Desai 	u8 resp_code = 0;
4100e844adb1SKashyap Desai 	int retval = FAILED, ret = 0;
4101e844adb1SKashyap Desai 
4102e844adb1SKashyap Desai 	sdev_printk(KERN_INFO, scmd->device,
4103e844adb1SKashyap Desai 	    "Attempting Target Reset! scmd(%p)\n", scmd);
4104e844adb1SKashyap Desai 	scsi_print_command(scmd);
4105e844adb1SKashyap Desai 
4106e844adb1SKashyap Desai 	sdev_priv_data = scmd->device->hostdata;
4107e844adb1SKashyap Desai 	if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) {
4108e844adb1SKashyap Desai 		sdev_printk(KERN_INFO, scmd->device,
4109e844adb1SKashyap Desai 		    "SCSI device is not available\n");
4110e844adb1SKashyap Desai 		retval = SUCCESS;
4111e844adb1SKashyap Desai 		goto out;
4112e844adb1SKashyap Desai 	}
4113e844adb1SKashyap Desai 
4114e844adb1SKashyap Desai 	stgt_priv_data = sdev_priv_data->tgt_priv_data;
4115e844adb1SKashyap Desai 	dev_handle = stgt_priv_data->dev_handle;
4116a91603a5SSreekanth Reddy 	if (stgt_priv_data->dev_removed) {
4117f1dec6b1SRanjan Kumar 		struct scmd_priv *cmd_priv = scsi_cmd_priv(scmd);
4118a91603a5SSreekanth Reddy 		sdev_printk(KERN_INFO, scmd->device,
4119a91603a5SSreekanth Reddy 		    "%s:target(handle = 0x%04x) is removed, target reset is not issued\n",
4120a91603a5SSreekanth Reddy 		    mrioc->name, dev_handle);
4121f1dec6b1SRanjan Kumar 		if (!cmd_priv->in_lld_scope || cmd_priv->host_tag == MPI3MR_HOSTTAG_INVALID)
4122f1dec6b1SRanjan Kumar 			retval = SUCCESS;
4123f1dec6b1SRanjan Kumar 		else
4124a91603a5SSreekanth Reddy 			retval = FAILED;
4125a91603a5SSreekanth Reddy 		goto out;
4126a91603a5SSreekanth Reddy 	}
4127e844adb1SKashyap Desai 	sdev_printk(KERN_INFO, scmd->device,
4128e844adb1SKashyap Desai 	    "Target Reset is issued to handle(0x%04x)\n",
4129e844adb1SKashyap Desai 	    dev_handle);
4130e844adb1SKashyap Desai 
4131e844adb1SKashyap Desai 	ret = mpi3mr_issue_tm(mrioc,
4132e844adb1SKashyap Desai 	    MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET, dev_handle,
4133e844adb1SKashyap Desai 	    sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS,
4134a91603a5SSreekanth Reddy 	    MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, scmd);
4135e844adb1SKashyap Desai 
4136e844adb1SKashyap Desai 	if (ret)
4137e844adb1SKashyap Desai 		goto out;
4138e844adb1SKashyap Desai 
4139a91603a5SSreekanth Reddy 	if (stgt_priv_data->pend_count) {
4140a91603a5SSreekanth Reddy 		sdev_printk(KERN_INFO, scmd->device,
4141a91603a5SSreekanth Reddy 		    "%s: target has %d pending commands, target reset is failed\n",
41426d211f1dSSreekanth Reddy 		    mrioc->name, stgt_priv_data->pend_count);
4143a91603a5SSreekanth Reddy 		goto out;
4144a91603a5SSreekanth Reddy 	}
4145a91603a5SSreekanth Reddy 
4146e844adb1SKashyap Desai 	retval = SUCCESS;
4147e844adb1SKashyap Desai out:
4148e844adb1SKashyap Desai 	sdev_printk(KERN_INFO, scmd->device,
4149a91603a5SSreekanth Reddy 	    "%s: target reset is %s for scmd(%p)\n", mrioc->name,
4150e844adb1SKashyap Desai 	    ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
4151e844adb1SKashyap Desai 
4152e844adb1SKashyap Desai 	return retval;
4153e844adb1SKashyap Desai }
4154e844adb1SKashyap Desai 
4155e844adb1SKashyap Desai /**
4156e844adb1SKashyap Desai  * mpi3mr_eh_dev_reset- Device reset error handling callback
4157e844adb1SKashyap Desai  * @scmd: SCSI command reference
4158e844adb1SKashyap Desai  *
4159e844adb1SKashyap Desai  * Issue lun reset Task Management and verify the scmd is
4160e844adb1SKashyap Desai  * terminated successfully and return status accordingly.
4161e844adb1SKashyap Desai  *
4162e844adb1SKashyap Desai  * Return: SUCCESS of successful termination of the scmd else
4163e844adb1SKashyap Desai  *         FAILED
4164e844adb1SKashyap Desai  */
mpi3mr_eh_dev_reset(struct scsi_cmnd * scmd)4165e844adb1SKashyap Desai static int mpi3mr_eh_dev_reset(struct scsi_cmnd *scmd)
4166e844adb1SKashyap Desai {
4167e844adb1SKashyap Desai 	struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host);
4168e844adb1SKashyap Desai 	struct mpi3mr_stgt_priv_data *stgt_priv_data;
4169e844adb1SKashyap Desai 	struct mpi3mr_sdev_priv_data *sdev_priv_data;
4170e844adb1SKashyap Desai 	u16 dev_handle;
4171e844adb1SKashyap Desai 	u8 resp_code = 0;
4172e844adb1SKashyap Desai 	int retval = FAILED, ret = 0;
4173e844adb1SKashyap Desai 
4174e844adb1SKashyap Desai 	sdev_printk(KERN_INFO, scmd->device,
4175e844adb1SKashyap Desai 	    "Attempting Device(lun) Reset! scmd(%p)\n", scmd);
4176e844adb1SKashyap Desai 	scsi_print_command(scmd);
4177e844adb1SKashyap Desai 
4178e844adb1SKashyap Desai 	sdev_priv_data = scmd->device->hostdata;
4179e844adb1SKashyap Desai 	if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) {
4180e844adb1SKashyap Desai 		sdev_printk(KERN_INFO, scmd->device,
4181e844adb1SKashyap Desai 		    "SCSI device is not available\n");
4182e844adb1SKashyap Desai 		retval = SUCCESS;
4183e844adb1SKashyap Desai 		goto out;
4184e844adb1SKashyap Desai 	}
4185e844adb1SKashyap Desai 
4186e844adb1SKashyap Desai 	stgt_priv_data = sdev_priv_data->tgt_priv_data;
4187e844adb1SKashyap Desai 	dev_handle = stgt_priv_data->dev_handle;
4188a91603a5SSreekanth Reddy 	if (stgt_priv_data->dev_removed) {
4189f1dec6b1SRanjan Kumar 		struct scmd_priv *cmd_priv = scsi_cmd_priv(scmd);
4190a91603a5SSreekanth Reddy 		sdev_printk(KERN_INFO, scmd->device,
4191a91603a5SSreekanth Reddy 		    "%s: device(handle = 0x%04x) is removed, device(LUN) reset is not issued\n",
4192a91603a5SSreekanth Reddy 		    mrioc->name, dev_handle);
4193f1dec6b1SRanjan Kumar 		if (!cmd_priv->in_lld_scope || cmd_priv->host_tag == MPI3MR_HOSTTAG_INVALID)
4194f1dec6b1SRanjan Kumar 			retval = SUCCESS;
4195f1dec6b1SRanjan Kumar 		else
4196a91603a5SSreekanth Reddy 			retval = FAILED;
4197a91603a5SSreekanth Reddy 		goto out;
4198a91603a5SSreekanth Reddy 	}
4199e844adb1SKashyap Desai 	sdev_printk(KERN_INFO, scmd->device,
4200e844adb1SKashyap Desai 	    "Device(lun) Reset is issued to handle(0x%04x)\n", dev_handle);
4201e844adb1SKashyap Desai 
4202e844adb1SKashyap Desai 	ret = mpi3mr_issue_tm(mrioc,
4203e844adb1SKashyap Desai 	    MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, dev_handle,
4204e844adb1SKashyap Desai 	    sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS,
4205a91603a5SSreekanth Reddy 	    MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, scmd);
4206e844adb1SKashyap Desai 
4207e844adb1SKashyap Desai 	if (ret)
4208e844adb1SKashyap Desai 		goto out;
4209e844adb1SKashyap Desai 
4210a91603a5SSreekanth Reddy 	if (sdev_priv_data->pend_count) {
4211a91603a5SSreekanth Reddy 		sdev_printk(KERN_INFO, scmd->device,
4212a91603a5SSreekanth Reddy 		    "%s: device has %d pending commands, device(LUN) reset is failed\n",
4213a91603a5SSreekanth Reddy 		    mrioc->name, sdev_priv_data->pend_count);
4214a91603a5SSreekanth Reddy 		goto out;
4215a91603a5SSreekanth Reddy 	}
4216e844adb1SKashyap Desai 	retval = SUCCESS;
4217e844adb1SKashyap Desai out:
4218e844adb1SKashyap Desai 	sdev_printk(KERN_INFO, scmd->device,
4219a91603a5SSreekanth Reddy 	    "%s: device(LUN) reset is %s for scmd(%p)\n", mrioc->name,
4220e844adb1SKashyap Desai 	    ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
4221e844adb1SKashyap Desai 
4222e844adb1SKashyap Desai 	return retval;
4223e844adb1SKashyap Desai }
4224e844adb1SKashyap Desai 
4225e844adb1SKashyap Desai /**
4226023ab2a9SKashyap Desai  * mpi3mr_scan_start - Scan start callback handler
4227023ab2a9SKashyap Desai  * @shost: SCSI host reference
4228023ab2a9SKashyap Desai  *
4229023ab2a9SKashyap Desai  * Issue port enable request asynchronously.
4230023ab2a9SKashyap Desai  *
4231023ab2a9SKashyap Desai  * Return: Nothing
4232023ab2a9SKashyap Desai  */
mpi3mr_scan_start(struct Scsi_Host * shost)4233023ab2a9SKashyap Desai static void mpi3mr_scan_start(struct Scsi_Host *shost)
4234023ab2a9SKashyap Desai {
4235023ab2a9SKashyap Desai 	struct mpi3mr_ioc *mrioc = shost_priv(shost);
4236023ab2a9SKashyap Desai 
4237023ab2a9SKashyap Desai 	mrioc->scan_started = 1;
4238023ab2a9SKashyap Desai 	ioc_info(mrioc, "%s :Issuing Port Enable\n", __func__);
4239023ab2a9SKashyap Desai 	if (mpi3mr_issue_port_enable(mrioc, 1)) {
4240023ab2a9SKashyap Desai 		ioc_err(mrioc, "%s :Issuing port enable failed\n", __func__);
4241023ab2a9SKashyap Desai 		mrioc->scan_started = 0;
4242023ab2a9SKashyap Desai 		mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR;
4243023ab2a9SKashyap Desai 	}
4244023ab2a9SKashyap Desai }
4245023ab2a9SKashyap Desai 
4246023ab2a9SKashyap Desai /**
4247023ab2a9SKashyap Desai  * mpi3mr_scan_finished - Scan finished callback handler
4248023ab2a9SKashyap Desai  * @shost: SCSI host reference
4249023ab2a9SKashyap Desai  * @time: Jiffies from the scan start
4250023ab2a9SKashyap Desai  *
4251023ab2a9SKashyap Desai  * Checks whether the port enable is completed or timedout or
4252023ab2a9SKashyap Desai  * failed and set the scan status accordingly after taking any
4253023ab2a9SKashyap Desai  * recovery if required.
4254023ab2a9SKashyap Desai  *
4255023ab2a9SKashyap Desai  * Return: 1 on scan finished or timed out, 0 for in progress
4256023ab2a9SKashyap Desai  */
mpi3mr_scan_finished(struct Scsi_Host * shost,unsigned long time)4257023ab2a9SKashyap Desai static int mpi3mr_scan_finished(struct Scsi_Host *shost,
4258023ab2a9SKashyap Desai 	unsigned long time)
4259023ab2a9SKashyap Desai {
4260023ab2a9SKashyap Desai 	struct mpi3mr_ioc *mrioc = shost_priv(shost);
4261023ab2a9SKashyap Desai 	u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT;
4262b64845a7SSreekanth Reddy 	u32 ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4263023ab2a9SKashyap Desai 
4264b64845a7SSreekanth Reddy 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
4265b64845a7SSreekanth Reddy 	    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
4266b64845a7SSreekanth Reddy 		ioc_err(mrioc, "port enable failed due to fault or reset\n");
4267b64845a7SSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
4268b64845a7SSreekanth Reddy 		mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR;
4269b64845a7SSreekanth Reddy 		mrioc->scan_started = 0;
4270023ab2a9SKashyap Desai 		mrioc->init_cmds.is_waiting = 0;
4271023ab2a9SKashyap Desai 		mrioc->init_cmds.callback = NULL;
4272023ab2a9SKashyap Desai 		mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
4273023ab2a9SKashyap Desai 	}
4274023ab2a9SKashyap Desai 
4275b64845a7SSreekanth Reddy 	if (time >= (pe_timeout * HZ)) {
4276b64845a7SSreekanth Reddy 		ioc_err(mrioc, "port enable failed due to time out\n");
4277b64845a7SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
4278b64845a7SSreekanth Reddy 		    MPI3MR_RESET_FROM_PE_TIMEOUT);
4279b64845a7SSreekanth Reddy 		mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR;
4280b64845a7SSreekanth Reddy 		mrioc->scan_started = 0;
4281b64845a7SSreekanth Reddy 		mrioc->init_cmds.is_waiting = 0;
4282b64845a7SSreekanth Reddy 		mrioc->init_cmds.callback = NULL;
4283b64845a7SSreekanth Reddy 		mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
4284023ab2a9SKashyap Desai 	}
4285023ab2a9SKashyap Desai 
4286023ab2a9SKashyap Desai 	if (mrioc->scan_started)
4287023ab2a9SKashyap Desai 		return 0;
4288b64845a7SSreekanth Reddy 
4289b64845a7SSreekanth Reddy 	if (mrioc->scan_failed) {
4290b64845a7SSreekanth Reddy 		ioc_err(mrioc,
4291b64845a7SSreekanth Reddy 		    "port enable failed with status=0x%04x\n",
4292b64845a7SSreekanth Reddy 		    mrioc->scan_failed);
4293b64845a7SSreekanth Reddy 	} else
4294b64845a7SSreekanth Reddy 		ioc_info(mrioc, "port enable is successfully completed\n");
4295b64845a7SSreekanth Reddy 
4296672ae26cSKashyap Desai 	mpi3mr_start_watchdog(mrioc);
4297023ab2a9SKashyap Desai 	mrioc->is_driver_loading = 0;
4298f5e6d5a3SSumit Saxena 	mrioc->stop_bsgs = 0;
4299023ab2a9SKashyap Desai 	return 1;
4300023ab2a9SKashyap Desai }
4301023ab2a9SKashyap Desai 
4302023ab2a9SKashyap Desai /**
4303824a1566SKashyap Desai  * mpi3mr_slave_destroy - Slave destroy callback handler
4304824a1566SKashyap Desai  * @sdev: SCSI device reference
4305824a1566SKashyap Desai  *
4306824a1566SKashyap Desai  * Cleanup and free per device(lun) private data.
4307824a1566SKashyap Desai  *
4308824a1566SKashyap Desai  * Return: Nothing.
4309824a1566SKashyap Desai  */
mpi3mr_slave_destroy(struct scsi_device * sdev)4310824a1566SKashyap Desai static void mpi3mr_slave_destroy(struct scsi_device *sdev)
4311824a1566SKashyap Desai {
431213ef29eaSKashyap Desai 	struct Scsi_Host *shost;
431313ef29eaSKashyap Desai 	struct mpi3mr_ioc *mrioc;
431413ef29eaSKashyap Desai 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
4315626665e9SSreekanth Reddy 	struct mpi3mr_tgt_dev *tgt_dev = NULL;
431613ef29eaSKashyap Desai 	unsigned long flags;
431713ef29eaSKashyap Desai 	struct scsi_target *starget;
4318626665e9SSreekanth Reddy 	struct sas_rphy *rphy = NULL;
431913ef29eaSKashyap Desai 
432013ef29eaSKashyap Desai 	if (!sdev->hostdata)
432113ef29eaSKashyap Desai 		return;
432213ef29eaSKashyap Desai 
432313ef29eaSKashyap Desai 	starget = scsi_target(sdev);
432413ef29eaSKashyap Desai 	shost = dev_to_shost(&starget->dev);
432513ef29eaSKashyap Desai 	mrioc = shost_priv(shost);
432613ef29eaSKashyap Desai 	scsi_tgt_priv_data = starget->hostdata;
432713ef29eaSKashyap Desai 
432813ef29eaSKashyap Desai 	scsi_tgt_priv_data->num_luns--;
432913ef29eaSKashyap Desai 
433013ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
4331626665e9SSreekanth Reddy 	if (starget->channel == mrioc->scsi_device_channel)
433213ef29eaSKashyap Desai 		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
4333626665e9SSreekanth Reddy 	else if (mrioc->sas_transport_enabled && !starget->channel) {
4334626665e9SSreekanth Reddy 		rphy = dev_to_rphy(starget->dev.parent);
4335626665e9SSreekanth Reddy 		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
4336626665e9SSreekanth Reddy 		    rphy->identify.sas_address, rphy);
4337626665e9SSreekanth Reddy 	}
4338626665e9SSreekanth Reddy 
433913ef29eaSKashyap Desai 	if (tgt_dev && (!scsi_tgt_priv_data->num_luns))
434013ef29eaSKashyap Desai 		tgt_dev->starget = NULL;
434113ef29eaSKashyap Desai 	if (tgt_dev)
434213ef29eaSKashyap Desai 		mpi3mr_tgtdev_put(tgt_dev);
434313ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
434413ef29eaSKashyap Desai 
434513ef29eaSKashyap Desai 	kfree(sdev->hostdata);
434613ef29eaSKashyap Desai 	sdev->hostdata = NULL;
4347824a1566SKashyap Desai }
4348824a1566SKashyap Desai 
4349824a1566SKashyap Desai /**
4350824a1566SKashyap Desai  * mpi3mr_target_destroy - Target destroy callback handler
4351824a1566SKashyap Desai  * @starget: SCSI target reference
4352824a1566SKashyap Desai  *
4353824a1566SKashyap Desai  * Cleanup and free per target private data.
4354824a1566SKashyap Desai  *
4355824a1566SKashyap Desai  * Return: Nothing.
4356824a1566SKashyap Desai  */
mpi3mr_target_destroy(struct scsi_target * starget)4357824a1566SKashyap Desai static void mpi3mr_target_destroy(struct scsi_target *starget)
4358824a1566SKashyap Desai {
435913ef29eaSKashyap Desai 	struct Scsi_Host *shost;
436013ef29eaSKashyap Desai 	struct mpi3mr_ioc *mrioc;
436113ef29eaSKashyap Desai 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
436213ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgt_dev;
436313ef29eaSKashyap Desai 	unsigned long flags;
436413ef29eaSKashyap Desai 
436513ef29eaSKashyap Desai 	if (!starget->hostdata)
436613ef29eaSKashyap Desai 		return;
436713ef29eaSKashyap Desai 
436813ef29eaSKashyap Desai 	shost = dev_to_shost(&starget->dev);
436913ef29eaSKashyap Desai 	mrioc = shost_priv(shost);
437013ef29eaSKashyap Desai 	scsi_tgt_priv_data = starget->hostdata;
437113ef29eaSKashyap Desai 
437213ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
437313ef29eaSKashyap Desai 	tgt_dev = __mpi3mr_get_tgtdev_from_tgtpriv(mrioc, scsi_tgt_priv_data);
437413ef29eaSKashyap Desai 	if (tgt_dev && (tgt_dev->starget == starget) &&
437513ef29eaSKashyap Desai 	    (tgt_dev->perst_id == starget->id))
437613ef29eaSKashyap Desai 		tgt_dev->starget = NULL;
437713ef29eaSKashyap Desai 	if (tgt_dev) {
437813ef29eaSKashyap Desai 		scsi_tgt_priv_data->tgt_dev = NULL;
437913ef29eaSKashyap Desai 		scsi_tgt_priv_data->perst_id = 0;
438013ef29eaSKashyap Desai 		mpi3mr_tgtdev_put(tgt_dev);
438113ef29eaSKashyap Desai 		mpi3mr_tgtdev_put(tgt_dev);
438213ef29eaSKashyap Desai 	}
438313ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
438413ef29eaSKashyap Desai 
438513ef29eaSKashyap Desai 	kfree(starget->hostdata);
438613ef29eaSKashyap Desai 	starget->hostdata = NULL;
4387824a1566SKashyap Desai }
4388824a1566SKashyap Desai 
4389824a1566SKashyap Desai /**
4390824a1566SKashyap Desai  * mpi3mr_slave_configure - Slave configure callback handler
4391824a1566SKashyap Desai  * @sdev: SCSI device reference
4392824a1566SKashyap Desai  *
4393824a1566SKashyap Desai  * Configure queue depth, max hardware sectors and virt boundary
4394824a1566SKashyap Desai  * as required
4395824a1566SKashyap Desai  *
4396824a1566SKashyap Desai  * Return: 0 always.
4397824a1566SKashyap Desai  */
mpi3mr_slave_configure(struct scsi_device * sdev)4398824a1566SKashyap Desai static int mpi3mr_slave_configure(struct scsi_device *sdev)
4399824a1566SKashyap Desai {
440013ef29eaSKashyap Desai 	struct scsi_target *starget;
440113ef29eaSKashyap Desai 	struct Scsi_Host *shost;
440213ef29eaSKashyap Desai 	struct mpi3mr_ioc *mrioc;
4403626665e9SSreekanth Reddy 	struct mpi3mr_tgt_dev *tgt_dev = NULL;
440413ef29eaSKashyap Desai 	unsigned long flags;
4405824a1566SKashyap Desai 	int retval = 0;
4406626665e9SSreekanth Reddy 	struct sas_rphy *rphy = NULL;
440713ef29eaSKashyap Desai 
440813ef29eaSKashyap Desai 	starget = scsi_target(sdev);
440913ef29eaSKashyap Desai 	shost = dev_to_shost(&starget->dev);
441013ef29eaSKashyap Desai 	mrioc = shost_priv(shost);
441113ef29eaSKashyap Desai 
441213ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
4413626665e9SSreekanth Reddy 	if (starget->channel == mrioc->scsi_device_channel)
441413ef29eaSKashyap Desai 		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
4415626665e9SSreekanth Reddy 	else if (mrioc->sas_transport_enabled && !starget->channel) {
4416626665e9SSreekanth Reddy 		rphy = dev_to_rphy(starget->dev.parent);
4417626665e9SSreekanth Reddy 		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
4418626665e9SSreekanth Reddy 		    rphy->identify.sas_address, rphy);
4419626665e9SSreekanth Reddy 	}
442013ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
442113ef29eaSKashyap Desai 	if (!tgt_dev)
442213ef29eaSKashyap Desai 		return -ENXIO;
442313ef29eaSKashyap Desai 
44240ea17734SKashyap Desai 	mpi3mr_change_queue_depth(sdev, tgt_dev->q_depth);
44251aa529d4SSreekanth Reddy 
44261aa529d4SSreekanth Reddy 	sdev->eh_timeout = MPI3MR_EH_SCMD_TIMEOUT;
44271aa529d4SSreekanth Reddy 	blk_queue_rq_timeout(sdev->request_queue, MPI3MR_SCMD_TIMEOUT);
44281aa529d4SSreekanth Reddy 
44298e653455SKashyap Desai 	switch (tgt_dev->dev_type) {
44308e653455SKashyap Desai 	case MPI3_DEVICE_DEVFORM_PCIE:
44318e653455SKashyap Desai 		/*The block layer hw sector size = 512*/
443217d6b9cfSSreekanth Reddy 		if ((tgt_dev->dev_spec.pcie_inf.dev_info &
443317d6b9cfSSreekanth Reddy 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) ==
443417d6b9cfSSreekanth Reddy 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) {
44358e653455SKashyap Desai 			blk_queue_max_hw_sectors(sdev->request_queue,
44368e653455SKashyap Desai 			    tgt_dev->dev_spec.pcie_inf.mdts / 512);
443717d6b9cfSSreekanth Reddy 			if (tgt_dev->dev_spec.pcie_inf.pgsz == 0)
443817d6b9cfSSreekanth Reddy 				blk_queue_virt_boundary(sdev->request_queue,
443917d6b9cfSSreekanth Reddy 				    ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1));
444017d6b9cfSSreekanth Reddy 			else
44418e653455SKashyap Desai 				blk_queue_virt_boundary(sdev->request_queue,
44428e653455SKashyap Desai 				    ((1 << tgt_dev->dev_spec.pcie_inf.pgsz) - 1));
444317d6b9cfSSreekanth Reddy 		}
44448e653455SKashyap Desai 		break;
44458e653455SKashyap Desai 	default:
44468e653455SKashyap Desai 		break;
44478e653455SKashyap Desai 	}
44488e653455SKashyap Desai 
444913ef29eaSKashyap Desai 	mpi3mr_tgtdev_put(tgt_dev);
445013ef29eaSKashyap Desai 
4451824a1566SKashyap Desai 	return retval;
4452824a1566SKashyap Desai }
4453824a1566SKashyap Desai 
4454824a1566SKashyap Desai /**
4455824a1566SKashyap Desai  * mpi3mr_slave_alloc -Slave alloc callback handler
4456824a1566SKashyap Desai  * @sdev: SCSI device reference
4457824a1566SKashyap Desai  *
4458824a1566SKashyap Desai  * Allocate per device(lun) private data and initialize it.
4459824a1566SKashyap Desai  *
4460824a1566SKashyap Desai  * Return: 0 on success -ENOMEM on memory allocation failure.
4461824a1566SKashyap Desai  */
mpi3mr_slave_alloc(struct scsi_device * sdev)4462824a1566SKashyap Desai static int mpi3mr_slave_alloc(struct scsi_device *sdev)
4463824a1566SKashyap Desai {
446413ef29eaSKashyap Desai 	struct Scsi_Host *shost;
446513ef29eaSKashyap Desai 	struct mpi3mr_ioc *mrioc;
446613ef29eaSKashyap Desai 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
4467626665e9SSreekanth Reddy 	struct mpi3mr_tgt_dev *tgt_dev = NULL;
446813ef29eaSKashyap Desai 	struct mpi3mr_sdev_priv_data *scsi_dev_priv_data;
446913ef29eaSKashyap Desai 	unsigned long flags;
447013ef29eaSKashyap Desai 	struct scsi_target *starget;
4471824a1566SKashyap Desai 	int retval = 0;
4472626665e9SSreekanth Reddy 	struct sas_rphy *rphy = NULL;
447313ef29eaSKashyap Desai 
447413ef29eaSKashyap Desai 	starget = scsi_target(sdev);
447513ef29eaSKashyap Desai 	shost = dev_to_shost(&starget->dev);
447613ef29eaSKashyap Desai 	mrioc = shost_priv(shost);
447713ef29eaSKashyap Desai 	scsi_tgt_priv_data = starget->hostdata;
447813ef29eaSKashyap Desai 
447913ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
4480626665e9SSreekanth Reddy 
4481626665e9SSreekanth Reddy 	if (starget->channel == mrioc->scsi_device_channel)
448213ef29eaSKashyap Desai 		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
4483626665e9SSreekanth Reddy 	else if (mrioc->sas_transport_enabled && !starget->channel) {
4484626665e9SSreekanth Reddy 		rphy = dev_to_rphy(starget->dev.parent);
4485626665e9SSreekanth Reddy 		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
4486626665e9SSreekanth Reddy 		    rphy->identify.sas_address, rphy);
4487626665e9SSreekanth Reddy 	}
448813ef29eaSKashyap Desai 
448913ef29eaSKashyap Desai 	if (tgt_dev) {
449013ef29eaSKashyap Desai 		if (tgt_dev->starget == NULL)
449113ef29eaSKashyap Desai 			tgt_dev->starget = starget;
449213ef29eaSKashyap Desai 		mpi3mr_tgtdev_put(tgt_dev);
449313ef29eaSKashyap Desai 		retval = 0;
449413ef29eaSKashyap Desai 	} else {
449513ef29eaSKashyap Desai 		spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
449613ef29eaSKashyap Desai 		return -ENXIO;
449713ef29eaSKashyap Desai 	}
449813ef29eaSKashyap Desai 
449913ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
450013ef29eaSKashyap Desai 
450113ef29eaSKashyap Desai 	scsi_dev_priv_data = kzalloc(sizeof(*scsi_dev_priv_data), GFP_KERNEL);
450213ef29eaSKashyap Desai 	if (!scsi_dev_priv_data)
450313ef29eaSKashyap Desai 		return -ENOMEM;
450413ef29eaSKashyap Desai 
450513ef29eaSKashyap Desai 	scsi_dev_priv_data->lun_id = sdev->lun;
450613ef29eaSKashyap Desai 	scsi_dev_priv_data->tgt_priv_data = scsi_tgt_priv_data;
450713ef29eaSKashyap Desai 	sdev->hostdata = scsi_dev_priv_data;
450813ef29eaSKashyap Desai 
450913ef29eaSKashyap Desai 	scsi_tgt_priv_data->num_luns++;
451013ef29eaSKashyap Desai 
4511824a1566SKashyap Desai 	return retval;
4512824a1566SKashyap Desai }
4513824a1566SKashyap Desai 
4514824a1566SKashyap Desai /**
4515824a1566SKashyap Desai  * mpi3mr_target_alloc - Target alloc callback handler
4516824a1566SKashyap Desai  * @starget: SCSI target reference
4517824a1566SKashyap Desai  *
4518824a1566SKashyap Desai  * Allocate per target private data and initialize it.
4519824a1566SKashyap Desai  *
4520824a1566SKashyap Desai  * Return: 0 on success -ENOMEM on memory allocation failure.
4521824a1566SKashyap Desai  */
mpi3mr_target_alloc(struct scsi_target * starget)4522824a1566SKashyap Desai static int mpi3mr_target_alloc(struct scsi_target *starget)
4523824a1566SKashyap Desai {
452413ef29eaSKashyap Desai 	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
452513ef29eaSKashyap Desai 	struct mpi3mr_ioc *mrioc = shost_priv(shost);
452613ef29eaSKashyap Desai 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
452713ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgt_dev;
452813ef29eaSKashyap Desai 	unsigned long flags;
452913ef29eaSKashyap Desai 	int retval = 0;
4530626665e9SSreekanth Reddy 	struct sas_rphy *rphy = NULL;
453113ef29eaSKashyap Desai 
453213ef29eaSKashyap Desai 	scsi_tgt_priv_data = kzalloc(sizeof(*scsi_tgt_priv_data), GFP_KERNEL);
453313ef29eaSKashyap Desai 	if (!scsi_tgt_priv_data)
453413ef29eaSKashyap Desai 		return -ENOMEM;
453513ef29eaSKashyap Desai 
453613ef29eaSKashyap Desai 	starget->hostdata = scsi_tgt_priv_data;
453713ef29eaSKashyap Desai 
453813ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
4539626665e9SSreekanth Reddy 	if (starget->channel == mrioc->scsi_device_channel) {
454013ef29eaSKashyap Desai 		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
4541e7a8648eSRanjan Kumar 		if (tgt_dev && !tgt_dev->is_hidden) {
454213ef29eaSKashyap Desai 			scsi_tgt_priv_data->starget = starget;
454313ef29eaSKashyap Desai 			scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle;
454413ef29eaSKashyap Desai 			scsi_tgt_priv_data->perst_id = tgt_dev->perst_id;
454513ef29eaSKashyap Desai 			scsi_tgt_priv_data->dev_type = tgt_dev->dev_type;
454613ef29eaSKashyap Desai 			scsi_tgt_priv_data->tgt_dev = tgt_dev;
454713ef29eaSKashyap Desai 			tgt_dev->starget = starget;
454813ef29eaSKashyap Desai 			atomic_set(&scsi_tgt_priv_data->block_io, 0);
454913ef29eaSKashyap Desai 			retval = 0;
4550e7a8648eSRanjan Kumar 			if ((tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_PCIE) &&
4551e7a8648eSRanjan Kumar 			    ((tgt_dev->dev_spec.pcie_inf.dev_info &
4552e7a8648eSRanjan Kumar 			    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) ==
4553e7a8648eSRanjan Kumar 			    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) &&
4554e7a8648eSRanjan Kumar 			    ((tgt_dev->dev_spec.pcie_inf.dev_info &
4555e7a8648eSRanjan Kumar 			    MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_MASK) !=
4556e7a8648eSRanjan Kumar 			    MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_0))
4557e7a8648eSRanjan Kumar 				scsi_tgt_priv_data->dev_nvme_dif = 1;
4558e7a8648eSRanjan Kumar 			scsi_tgt_priv_data->io_throttle_enabled = tgt_dev->io_throttle_enabled;
4559e7a8648eSRanjan Kumar 			scsi_tgt_priv_data->wslen = tgt_dev->wslen;
4560f10af057SSreekanth Reddy 			if (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_VD)
4561e7a8648eSRanjan Kumar 				scsi_tgt_priv_data->throttle_group = tgt_dev->dev_spec.vd_inf.tg;
4562e7a8648eSRanjan Kumar 		} else
4563e7a8648eSRanjan Kumar 			retval = -ENXIO;
4564e7a8648eSRanjan Kumar 	} else if (mrioc->sas_transport_enabled && !starget->channel) {
4565e7a8648eSRanjan Kumar 		rphy = dev_to_rphy(starget->dev.parent);
4566e7a8648eSRanjan Kumar 		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
4567e7a8648eSRanjan Kumar 		    rphy->identify.sas_address, rphy);
4568e7a8648eSRanjan Kumar 		if (tgt_dev && !tgt_dev->is_hidden && !tgt_dev->non_stl &&
4569e7a8648eSRanjan Kumar 		    (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA)) {
4570e7a8648eSRanjan Kumar 			scsi_tgt_priv_data->starget = starget;
4571e7a8648eSRanjan Kumar 			scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle;
4572e7a8648eSRanjan Kumar 			scsi_tgt_priv_data->perst_id = tgt_dev->perst_id;
4573e7a8648eSRanjan Kumar 			scsi_tgt_priv_data->dev_type = tgt_dev->dev_type;
4574e7a8648eSRanjan Kumar 			scsi_tgt_priv_data->tgt_dev = tgt_dev;
4575e7a8648eSRanjan Kumar 			scsi_tgt_priv_data->io_throttle_enabled = tgt_dev->io_throttle_enabled;
4576e7a8648eSRanjan Kumar 			scsi_tgt_priv_data->wslen = tgt_dev->wslen;
4577e7a8648eSRanjan Kumar 			tgt_dev->starget = starget;
4578e7a8648eSRanjan Kumar 			atomic_set(&scsi_tgt_priv_data->block_io, 0);
4579e7a8648eSRanjan Kumar 			retval = 0;
4580e7a8648eSRanjan Kumar 		} else
4581e7a8648eSRanjan Kumar 			retval = -ENXIO;
4582626665e9SSreekanth Reddy 	}
458313ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
458413ef29eaSKashyap Desai 
4585824a1566SKashyap Desai 	return retval;
4586824a1566SKashyap Desai }
4587824a1566SKashyap Desai 
4588824a1566SKashyap Desai /**
4589392bbeb8SKashyap Desai  * mpi3mr_check_return_unmap - Whether an unmap is allowed
4590392bbeb8SKashyap Desai  * @mrioc: Adapter instance reference
4591392bbeb8SKashyap Desai  * @scmd: SCSI Command reference
4592392bbeb8SKashyap Desai  *
4593392bbeb8SKashyap Desai  * The controller hardware cannot handle certain unmap commands
4594392bbeb8SKashyap Desai  * for NVMe drives, this routine checks those and return true
4595392bbeb8SKashyap Desai  * and completes the SCSI command with proper status and sense
4596392bbeb8SKashyap Desai  * data.
4597392bbeb8SKashyap Desai  *
4598392bbeb8SKashyap Desai  * Return: TRUE for not  allowed unmap, FALSE otherwise.
4599392bbeb8SKashyap Desai  */
mpi3mr_check_return_unmap(struct mpi3mr_ioc * mrioc,struct scsi_cmnd * scmd)4600392bbeb8SKashyap Desai static bool mpi3mr_check_return_unmap(struct mpi3mr_ioc *mrioc,
4601392bbeb8SKashyap Desai 	struct scsi_cmnd *scmd)
4602392bbeb8SKashyap Desai {
4603392bbeb8SKashyap Desai 	unsigned char *buf;
460413fd7b15SSreekanth Reddy 	u16 param_len, desc_len, trunc_param_len;
4605392bbeb8SKashyap Desai 
460613fd7b15SSreekanth Reddy 	trunc_param_len = param_len = get_unaligned_be16(scmd->cmnd + 7);
460713fd7b15SSreekanth Reddy 
460813fd7b15SSreekanth Reddy 	if (mrioc->pdev->revision) {
460913fd7b15SSreekanth Reddy 		if ((param_len > 24) && ((param_len - 8) & 0xF)) {
461013fd7b15SSreekanth Reddy 			trunc_param_len -= (param_len - 8) & 0xF;
461113fd7b15SSreekanth Reddy 			dprint_scsi_command(mrioc, scmd, MPI3_DEBUG_SCSI_ERROR);
461213fd7b15SSreekanth Reddy 			dprint_scsi_err(mrioc,
461313fd7b15SSreekanth Reddy 			    "truncating param_len from (%d) to (%d)\n",
461413fd7b15SSreekanth Reddy 			    param_len, trunc_param_len);
461513fd7b15SSreekanth Reddy 			put_unaligned_be16(trunc_param_len, scmd->cmnd + 7);
461613fd7b15SSreekanth Reddy 			dprint_scsi_command(mrioc, scmd, MPI3_DEBUG_SCSI_ERROR);
461713fd7b15SSreekanth Reddy 		}
461813fd7b15SSreekanth Reddy 		return false;
461913fd7b15SSreekanth Reddy 	}
4620392bbeb8SKashyap Desai 
4621392bbeb8SKashyap Desai 	if (!param_len) {
4622392bbeb8SKashyap Desai 		ioc_warn(mrioc,
4623392bbeb8SKashyap Desai 		    "%s: cdb received with zero parameter length\n",
4624392bbeb8SKashyap Desai 		    __func__);
4625392bbeb8SKashyap Desai 		scsi_print_command(scmd);
4626392bbeb8SKashyap Desai 		scmd->result = DID_OK << 16;
46271a30fd18SBart Van Assche 		scsi_done(scmd);
4628392bbeb8SKashyap Desai 		return true;
4629392bbeb8SKashyap Desai 	}
4630392bbeb8SKashyap Desai 
4631392bbeb8SKashyap Desai 	if (param_len < 24) {
4632392bbeb8SKashyap Desai 		ioc_warn(mrioc,
4633392bbeb8SKashyap Desai 		    "%s: cdb received with invalid param_len: %d\n",
4634392bbeb8SKashyap Desai 		    __func__, param_len);
4635392bbeb8SKashyap Desai 		scsi_print_command(scmd);
46361ff28f22SMartin K. Petersen 		scmd->result = SAM_STAT_CHECK_CONDITION;
4637392bbeb8SKashyap Desai 		scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
4638392bbeb8SKashyap Desai 		    0x1A, 0);
46391a30fd18SBart Van Assche 		scsi_done(scmd);
4640392bbeb8SKashyap Desai 		return true;
4641392bbeb8SKashyap Desai 	}
4642392bbeb8SKashyap Desai 	if (param_len != scsi_bufflen(scmd)) {
4643392bbeb8SKashyap Desai 		ioc_warn(mrioc,
4644392bbeb8SKashyap Desai 		    "%s: cdb received with param_len: %d bufflen: %d\n",
4645392bbeb8SKashyap Desai 		    __func__, param_len, scsi_bufflen(scmd));
4646392bbeb8SKashyap Desai 		scsi_print_command(scmd);
46471ff28f22SMartin K. Petersen 		scmd->result = SAM_STAT_CHECK_CONDITION;
4648392bbeb8SKashyap Desai 		scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
4649392bbeb8SKashyap Desai 		    0x1A, 0);
46501a30fd18SBart Van Assche 		scsi_done(scmd);
4651392bbeb8SKashyap Desai 		return true;
4652392bbeb8SKashyap Desai 	}
4653392bbeb8SKashyap Desai 	buf = kzalloc(scsi_bufflen(scmd), GFP_ATOMIC);
4654392bbeb8SKashyap Desai 	if (!buf) {
4655392bbeb8SKashyap Desai 		scsi_print_command(scmd);
46561ff28f22SMartin K. Petersen 		scmd->result = SAM_STAT_CHECK_CONDITION;
4657392bbeb8SKashyap Desai 		scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
4658392bbeb8SKashyap Desai 		    0x55, 0x03);
46591a30fd18SBart Van Assche 		scsi_done(scmd);
4660392bbeb8SKashyap Desai 		return true;
4661392bbeb8SKashyap Desai 	}
4662392bbeb8SKashyap Desai 	scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
4663392bbeb8SKashyap Desai 	desc_len = get_unaligned_be16(&buf[2]);
4664392bbeb8SKashyap Desai 
4665392bbeb8SKashyap Desai 	if (desc_len < 16) {
4666392bbeb8SKashyap Desai 		ioc_warn(mrioc,
4667392bbeb8SKashyap Desai 		    "%s: Invalid descriptor length in param list: %d\n",
4668392bbeb8SKashyap Desai 		    __func__, desc_len);
4669392bbeb8SKashyap Desai 		scsi_print_command(scmd);
46701ff28f22SMartin K. Petersen 		scmd->result = SAM_STAT_CHECK_CONDITION;
4671392bbeb8SKashyap Desai 		scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
4672392bbeb8SKashyap Desai 		    0x26, 0);
46731a30fd18SBart Van Assche 		scsi_done(scmd);
4674392bbeb8SKashyap Desai 		kfree(buf);
4675392bbeb8SKashyap Desai 		return true;
4676392bbeb8SKashyap Desai 	}
4677392bbeb8SKashyap Desai 
4678392bbeb8SKashyap Desai 	if (param_len > (desc_len + 8)) {
467913fd7b15SSreekanth Reddy 		trunc_param_len = desc_len + 8;
4680392bbeb8SKashyap Desai 		scsi_print_command(scmd);
468113fd7b15SSreekanth Reddy 		dprint_scsi_err(mrioc,
468213fd7b15SSreekanth Reddy 		    "truncating param_len(%d) to desc_len+8(%d)\n",
468313fd7b15SSreekanth Reddy 		    param_len, trunc_param_len);
468413fd7b15SSreekanth Reddy 		put_unaligned_be16(trunc_param_len, scmd->cmnd + 7);
4685392bbeb8SKashyap Desai 		scsi_print_command(scmd);
4686392bbeb8SKashyap Desai 	}
4687392bbeb8SKashyap Desai 
4688392bbeb8SKashyap Desai 	kfree(buf);
4689392bbeb8SKashyap Desai 	return false;
4690392bbeb8SKashyap Desai }
4691392bbeb8SKashyap Desai 
4692392bbeb8SKashyap Desai /**
469382141ddbSKashyap Desai  * mpi3mr_allow_scmd_to_fw - Command is allowed during shutdown
469482141ddbSKashyap Desai  * @scmd: SCSI Command reference
469582141ddbSKashyap Desai  *
469682141ddbSKashyap Desai  * Checks whether a cdb is allowed during shutdown or not.
469782141ddbSKashyap Desai  *
469882141ddbSKashyap Desai  * Return: TRUE for allowed commands, FALSE otherwise.
469982141ddbSKashyap Desai  */
470082141ddbSKashyap Desai 
mpi3mr_allow_scmd_to_fw(struct scsi_cmnd * scmd)470182141ddbSKashyap Desai inline bool mpi3mr_allow_scmd_to_fw(struct scsi_cmnd *scmd)
470282141ddbSKashyap Desai {
470382141ddbSKashyap Desai 	switch (scmd->cmnd[0]) {
470482141ddbSKashyap Desai 	case SYNCHRONIZE_CACHE:
470582141ddbSKashyap Desai 	case START_STOP:
470682141ddbSKashyap Desai 		return true;
470782141ddbSKashyap Desai 	default:
470882141ddbSKashyap Desai 		return false;
470982141ddbSKashyap Desai 	}
471082141ddbSKashyap Desai }
471182141ddbSKashyap Desai 
471282141ddbSKashyap Desai /**
4713824a1566SKashyap Desai  * mpi3mr_qcmd - I/O request despatcher
4714824a1566SKashyap Desai  * @shost: SCSI Host reference
4715824a1566SKashyap Desai  * @scmd: SCSI Command reference
4716824a1566SKashyap Desai  *
4717824a1566SKashyap Desai  * Issues the SCSI Command as an MPI3 request.
4718824a1566SKashyap Desai  *
4719824a1566SKashyap Desai  * Return: 0 on successful queueing of the request or if the
4720824a1566SKashyap Desai  *         request is completed with failure.
4721824a1566SKashyap Desai  *         SCSI_MLQUEUE_DEVICE_BUSY when the device is busy.
4722824a1566SKashyap Desai  *         SCSI_MLQUEUE_HOST_BUSY when the host queue is full.
4723824a1566SKashyap Desai  */
mpi3mr_qcmd(struct Scsi_Host * shost,struct scsi_cmnd * scmd)4724824a1566SKashyap Desai static int mpi3mr_qcmd(struct Scsi_Host *shost,
4725824a1566SKashyap Desai 	struct scsi_cmnd *scmd)
4726824a1566SKashyap Desai {
4727023ab2a9SKashyap Desai 	struct mpi3mr_ioc *mrioc = shost_priv(shost);
4728023ab2a9SKashyap Desai 	struct mpi3mr_stgt_priv_data *stgt_priv_data;
4729023ab2a9SKashyap Desai 	struct mpi3mr_sdev_priv_data *sdev_priv_data;
4730023ab2a9SKashyap Desai 	struct scmd_priv *scmd_priv_data = NULL;
4731023ab2a9SKashyap Desai 	struct mpi3_scsi_io_request *scsiio_req = NULL;
4732023ab2a9SKashyap Desai 	struct op_req_qinfo *op_req_q = NULL;
4733824a1566SKashyap Desai 	int retval = 0;
4734023ab2a9SKashyap Desai 	u16 dev_handle;
4735023ab2a9SKashyap Desai 	u16 host_tag;
4736f10af057SSreekanth Reddy 	u32 scsiio_flags = 0, data_len_blks = 0;
473769868c3bSBart Van Assche 	struct request *rq = scsi_cmd_to_rq(scmd);
4738023ab2a9SKashyap Desai 	int iprio_class;
473913fd7b15SSreekanth Reddy 	u8 is_pcie_dev = 0;
4740f10af057SSreekanth Reddy 	u32 tracked_io_sz = 0;
4741f10af057SSreekanth Reddy 	u32 ioc_pend_data_len = 0, tg_pend_data_len = 0;
4742f10af057SSreekanth Reddy 	struct mpi3mr_throttle_group_info *tg = NULL;
4743824a1566SKashyap Desai 
4744256bd4f2SSreekanth Reddy 	if (mrioc->unrecoverable) {
4745256bd4f2SSreekanth Reddy 		scmd->result = DID_ERROR << 16;
4746256bd4f2SSreekanth Reddy 		scsi_done(scmd);
4747256bd4f2SSreekanth Reddy 		goto out;
4748256bd4f2SSreekanth Reddy 	}
4749256bd4f2SSreekanth Reddy 
4750023ab2a9SKashyap Desai 	sdev_priv_data = scmd->device->hostdata;
4751023ab2a9SKashyap Desai 	if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) {
4752824a1566SKashyap Desai 		scmd->result = DID_NO_CONNECT << 16;
47531a30fd18SBart Van Assche 		scsi_done(scmd);
4754023ab2a9SKashyap Desai 		goto out;
4755023ab2a9SKashyap Desai 	}
4756023ab2a9SKashyap Desai 
475782141ddbSKashyap Desai 	if (mrioc->stop_drv_processing &&
475882141ddbSKashyap Desai 	    !(mpi3mr_allow_scmd_to_fw(scmd))) {
4759023ab2a9SKashyap Desai 		scmd->result = DID_NO_CONNECT << 16;
47601a30fd18SBart Van Assche 		scsi_done(scmd);
4761023ab2a9SKashyap Desai 		goto out;
4762023ab2a9SKashyap Desai 	}
4763023ab2a9SKashyap Desai 
4764f1dec6b1SRanjan Kumar 	stgt_priv_data = sdev_priv_data->tgt_priv_data;
4765f1dec6b1SRanjan Kumar 	dev_handle = stgt_priv_data->dev_handle;
4766f1dec6b1SRanjan Kumar 
4767f1dec6b1SRanjan Kumar 	/* Avoid error handling escalation when device is removed or blocked */
4768f1dec6b1SRanjan Kumar 
4769f1dec6b1SRanjan Kumar 	if (scmd->device->host->shost_state == SHOST_RECOVERY &&
4770f1dec6b1SRanjan Kumar 		scmd->cmnd[0] == TEST_UNIT_READY &&
4771f1dec6b1SRanjan Kumar 		(stgt_priv_data->dev_removed || (dev_handle == MPI3MR_INVALID_DEV_HANDLE))) {
4772f1dec6b1SRanjan Kumar 		scsi_build_sense(scmd, 0, UNIT_ATTENTION, 0x29, 0x07);
4773f1dec6b1SRanjan Kumar 		scsi_done(scmd);
4774f1dec6b1SRanjan Kumar 		goto out;
4775f1dec6b1SRanjan Kumar 	}
4776f1dec6b1SRanjan Kumar 
4777023ab2a9SKashyap Desai 	if (mrioc->reset_in_progress) {
4778023ab2a9SKashyap Desai 		retval = SCSI_MLQUEUE_HOST_BUSY;
4779023ab2a9SKashyap Desai 		goto out;
4780023ab2a9SKashyap Desai 	}
4781023ab2a9SKashyap Desai 
47827f90bc70SSreekanth Reddy 	if (atomic_read(&stgt_priv_data->block_io)) {
47837f90bc70SSreekanth Reddy 		if (mrioc->stop_drv_processing) {
47847f90bc70SSreekanth Reddy 			scmd->result = DID_NO_CONNECT << 16;
47857f90bc70SSreekanth Reddy 			scsi_done(scmd);
47867f90bc70SSreekanth Reddy 			goto out;
47877f90bc70SSreekanth Reddy 		}
47887f90bc70SSreekanth Reddy 		retval = SCSI_MLQUEUE_DEVICE_BUSY;
47897f90bc70SSreekanth Reddy 		goto out;
47907f90bc70SSreekanth Reddy 	}
47917f90bc70SSreekanth Reddy 
4792023ab2a9SKashyap Desai 	if (dev_handle == MPI3MR_INVALID_DEV_HANDLE) {
4793023ab2a9SKashyap Desai 		scmd->result = DID_NO_CONNECT << 16;
47941a30fd18SBart Van Assche 		scsi_done(scmd);
4795023ab2a9SKashyap Desai 		goto out;
4796023ab2a9SKashyap Desai 	}
4797023ab2a9SKashyap Desai 	if (stgt_priv_data->dev_removed) {
4798023ab2a9SKashyap Desai 		scmd->result = DID_NO_CONNECT << 16;
47991a30fd18SBart Van Assche 		scsi_done(scmd);
4800023ab2a9SKashyap Desai 		goto out;
4801023ab2a9SKashyap Desai 	}
4802023ab2a9SKashyap Desai 
480313fd7b15SSreekanth Reddy 	if (stgt_priv_data->dev_type == MPI3_DEVICE_DEVFORM_PCIE)
480413fd7b15SSreekanth Reddy 		is_pcie_dev = 1;
480513fd7b15SSreekanth Reddy 	if ((scmd->cmnd[0] == UNMAP) && is_pcie_dev &&
480613fd7b15SSreekanth Reddy 	    (mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) &&
4807392bbeb8SKashyap Desai 	    mpi3mr_check_return_unmap(mrioc, scmd))
4808392bbeb8SKashyap Desai 		goto out;
4809392bbeb8SKashyap Desai 
4810023ab2a9SKashyap Desai 	host_tag = mpi3mr_host_tag_for_scmd(mrioc, scmd);
4811023ab2a9SKashyap Desai 	if (host_tag == MPI3MR_HOSTTAG_INVALID) {
4812023ab2a9SKashyap Desai 		scmd->result = DID_ERROR << 16;
48131a30fd18SBart Van Assche 		scsi_done(scmd);
4814023ab2a9SKashyap Desai 		goto out;
4815023ab2a9SKashyap Desai 	}
4816023ab2a9SKashyap Desai 
4817023ab2a9SKashyap Desai 	if (scmd->sc_data_direction == DMA_FROM_DEVICE)
4818023ab2a9SKashyap Desai 		scsiio_flags = MPI3_SCSIIO_FLAGS_DATADIRECTION_READ;
4819023ab2a9SKashyap Desai 	else if (scmd->sc_data_direction == DMA_TO_DEVICE)
4820023ab2a9SKashyap Desai 		scsiio_flags = MPI3_SCSIIO_FLAGS_DATADIRECTION_WRITE;
4821023ab2a9SKashyap Desai 	else
4822023ab2a9SKashyap Desai 		scsiio_flags = MPI3_SCSIIO_FLAGS_DATADIRECTION_NO_DATA_TRANSFER;
4823023ab2a9SKashyap Desai 
4824023ab2a9SKashyap Desai 	scsiio_flags |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SIMPLEQ;
4825023ab2a9SKashyap Desai 
4826023ab2a9SKashyap Desai 	if (sdev_priv_data->ncq_prio_enable) {
4827023ab2a9SKashyap Desai 		iprio_class = IOPRIO_PRIO_CLASS(req_get_ioprio(rq));
4828023ab2a9SKashyap Desai 		if (iprio_class == IOPRIO_CLASS_RT)
4829023ab2a9SKashyap Desai 			scsiio_flags |= 1 << MPI3_SCSIIO_FLAGS_CMDPRI_SHIFT;
4830023ab2a9SKashyap Desai 	}
4831023ab2a9SKashyap Desai 
4832023ab2a9SKashyap Desai 	if (scmd->cmd_len > 16)
4833023ab2a9SKashyap Desai 		scsiio_flags |= MPI3_SCSIIO_FLAGS_CDB_GREATER_THAN_16;
4834023ab2a9SKashyap Desai 
4835023ab2a9SKashyap Desai 	scmd_priv_data = scsi_cmd_priv(scmd);
4836023ab2a9SKashyap Desai 	memset(scmd_priv_data->mpi3mr_scsiio_req, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
4837023ab2a9SKashyap Desai 	scsiio_req = (struct mpi3_scsi_io_request *)scmd_priv_data->mpi3mr_scsiio_req;
4838023ab2a9SKashyap Desai 	scsiio_req->function = MPI3_FUNCTION_SCSI_IO;
4839023ab2a9SKashyap Desai 	scsiio_req->host_tag = cpu_to_le16(host_tag);
4840023ab2a9SKashyap Desai 
484174e1f30aSKashyap Desai 	mpi3mr_setup_eedp(mrioc, scmd, scsiio_req);
484274e1f30aSKashyap Desai 
4843e7a8648eSRanjan Kumar 	if (stgt_priv_data->wslen)
4844e7a8648eSRanjan Kumar 		mpi3mr_setup_divert_ws(mrioc, scmd, scsiio_req, &scsiio_flags,
4845e7a8648eSRanjan Kumar 		    stgt_priv_data->wslen);
4846e7a8648eSRanjan Kumar 
4847023ab2a9SKashyap Desai 	memcpy(scsiio_req->cdb.cdb32, scmd->cmnd, scmd->cmd_len);
4848023ab2a9SKashyap Desai 	scsiio_req->data_length = cpu_to_le32(scsi_bufflen(scmd));
4849023ab2a9SKashyap Desai 	scsiio_req->dev_handle = cpu_to_le16(dev_handle);
4850023ab2a9SKashyap Desai 	scsiio_req->flags = cpu_to_le32(scsiio_flags);
4851023ab2a9SKashyap Desai 	int_to_scsilun(sdev_priv_data->lun_id,
4852023ab2a9SKashyap Desai 	    (struct scsi_lun *)scsiio_req->lun);
4853023ab2a9SKashyap Desai 
4854023ab2a9SKashyap Desai 	if (mpi3mr_build_sg_scmd(mrioc, scmd, scsiio_req)) {
4855023ab2a9SKashyap Desai 		mpi3mr_clear_scmd_priv(mrioc, scmd);
4856023ab2a9SKashyap Desai 		retval = SCSI_MLQUEUE_HOST_BUSY;
4857023ab2a9SKashyap Desai 		goto out;
4858023ab2a9SKashyap Desai 	}
4859023ab2a9SKashyap Desai 	op_req_q = &mrioc->req_qinfo[scmd_priv_data->req_q_idx];
4860f10af057SSreekanth Reddy 	data_len_blks = scsi_bufflen(scmd) >> 9;
4861f10af057SSreekanth Reddy 	if ((data_len_blks >= mrioc->io_throttle_data_length) &&
4862f10af057SSreekanth Reddy 	    stgt_priv_data->io_throttle_enabled) {
4863f10af057SSreekanth Reddy 		tracked_io_sz = data_len_blks;
4864f10af057SSreekanth Reddy 		tg = stgt_priv_data->throttle_group;
4865f10af057SSreekanth Reddy 		if (tg) {
4866f10af057SSreekanth Reddy 			ioc_pend_data_len = atomic_add_return(data_len_blks,
4867f10af057SSreekanth Reddy 			    &mrioc->pend_large_data_sz);
4868f10af057SSreekanth Reddy 			tg_pend_data_len = atomic_add_return(data_len_blks,
4869f10af057SSreekanth Reddy 			    &tg->pend_large_data_sz);
4870f10af057SSreekanth Reddy 			if (!tg->io_divert  && ((ioc_pend_data_len >=
4871f10af057SSreekanth Reddy 			    mrioc->io_throttle_high) ||
4872f10af057SSreekanth Reddy 			    (tg_pend_data_len >= tg->high))) {
4873f10af057SSreekanth Reddy 				tg->io_divert = 1;
4874cf1ce8b7SSreekanth Reddy 				tg->need_qd_reduction = 1;
4875f10af057SSreekanth Reddy 				mpi3mr_set_io_divert_for_all_vd_in_tg(mrioc,
4876f10af057SSreekanth Reddy 				    tg, 1);
4877cf1ce8b7SSreekanth Reddy 				mpi3mr_queue_qd_reduction_event(mrioc, tg);
4878f10af057SSreekanth Reddy 			}
4879f10af057SSreekanth Reddy 		} else {
4880f10af057SSreekanth Reddy 			ioc_pend_data_len = atomic_add_return(data_len_blks,
4881f10af057SSreekanth Reddy 			    &mrioc->pend_large_data_sz);
4882f10af057SSreekanth Reddy 			if (ioc_pend_data_len >= mrioc->io_throttle_high)
4883f10af057SSreekanth Reddy 				stgt_priv_data->io_divert = 1;
4884f10af057SSreekanth Reddy 		}
4885f10af057SSreekanth Reddy 	}
4886f10af057SSreekanth Reddy 
4887f10af057SSreekanth Reddy 	if (stgt_priv_data->io_divert) {
4888f10af057SSreekanth Reddy 		scsiio_req->msg_flags |=
4889f10af057SSreekanth Reddy 		    MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE;
4890f10af057SSreekanth Reddy 		scsiio_flags |= MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING;
4891f10af057SSreekanth Reddy 	}
4892f10af057SSreekanth Reddy 	scsiio_req->flags = cpu_to_le32(scsiio_flags);
4893023ab2a9SKashyap Desai 
4894023ab2a9SKashyap Desai 	if (mpi3mr_op_request_post(mrioc, op_req_q,
4895023ab2a9SKashyap Desai 	    scmd_priv_data->mpi3mr_scsiio_req)) {
4896023ab2a9SKashyap Desai 		mpi3mr_clear_scmd_priv(mrioc, scmd);
4897023ab2a9SKashyap Desai 		retval = SCSI_MLQUEUE_HOST_BUSY;
4898f10af057SSreekanth Reddy 		if (tracked_io_sz) {
4899f10af057SSreekanth Reddy 			atomic_sub(tracked_io_sz, &mrioc->pend_large_data_sz);
4900f10af057SSreekanth Reddy 			if (tg)
4901f10af057SSreekanth Reddy 				atomic_sub(tracked_io_sz,
4902f10af057SSreekanth Reddy 				    &tg->pend_large_data_sz);
4903f10af057SSreekanth Reddy 		}
4904023ab2a9SKashyap Desai 		goto out;
4905023ab2a9SKashyap Desai 	}
4906023ab2a9SKashyap Desai 
4907023ab2a9SKashyap Desai out:
4908824a1566SKashyap Desai 	return retval;
4909824a1566SKashyap Desai }
4910824a1566SKashyap Desai 
4911b85f82f3SBart Van Assche static const struct scsi_host_template mpi3mr_driver_template = {
4912824a1566SKashyap Desai 	.module				= THIS_MODULE,
4913824a1566SKashyap Desai 	.name				= "MPI3 Storage Controller",
4914824a1566SKashyap Desai 	.proc_name			= MPI3MR_DRIVER_NAME,
4915824a1566SKashyap Desai 	.queuecommand			= mpi3mr_qcmd,
4916824a1566SKashyap Desai 	.target_alloc			= mpi3mr_target_alloc,
4917824a1566SKashyap Desai 	.slave_alloc			= mpi3mr_slave_alloc,
4918824a1566SKashyap Desai 	.slave_configure		= mpi3mr_slave_configure,
4919824a1566SKashyap Desai 	.target_destroy			= mpi3mr_target_destroy,
4920824a1566SKashyap Desai 	.slave_destroy			= mpi3mr_slave_destroy,
4921023ab2a9SKashyap Desai 	.scan_finished			= mpi3mr_scan_finished,
4922023ab2a9SKashyap Desai 	.scan_start			= mpi3mr_scan_start,
49230ea17734SKashyap Desai 	.change_queue_depth		= mpi3mr_change_queue_depth,
4924e844adb1SKashyap Desai 	.eh_device_reset_handler	= mpi3mr_eh_dev_reset,
4925e844adb1SKashyap Desai 	.eh_target_reset_handler	= mpi3mr_eh_target_reset,
4926e844adb1SKashyap Desai 	.eh_host_reset_handler		= mpi3mr_eh_host_reset,
49278f9c6173SKashyap Desai 	.bios_param			= mpi3mr_bios_param,
4928824a1566SKashyap Desai 	.map_queues			= mpi3mr_map_queues,
4929afd3a579SSreekanth Reddy 	.mq_poll                        = mpi3mr_blk_mq_poll,
4930824a1566SKashyap Desai 	.no_write_same			= 1,
4931824a1566SKashyap Desai 	.can_queue			= 1,
4932824a1566SKashyap Desai 	.this_id			= -1,
4933d9adb81eSRanjan Kumar 	.sg_tablesize			= MPI3MR_DEFAULT_SGL_ENTRIES,
4934824a1566SKashyap Desai 	/* max xfer supported is 1M (2K in 512 byte sized sectors)
4935824a1566SKashyap Desai 	 */
4936d9adb81eSRanjan Kumar 	.max_sectors			= (MPI3MR_DEFAULT_MAX_IO_SIZE / 512),
4937824a1566SKashyap Desai 	.cmd_per_lun			= MPI3MR_MAX_CMDS_LUN,
49384f08b963SSreekanth Reddy 	.max_segment_size		= 0xffffffff,
4939824a1566SKashyap Desai 	.track_queue_depth		= 1,
4940824a1566SKashyap Desai 	.cmd_size			= sizeof(struct scmd_priv),
4941986d6badSSumit Saxena 	.shost_groups			= mpi3mr_host_groups,
49429feb5c4cSSreekanth Reddy 	.sdev_groups			= mpi3mr_dev_groups,
4943824a1566SKashyap Desai };
4944824a1566SKashyap Desai 
4945824a1566SKashyap Desai /**
4946824a1566SKashyap Desai  * mpi3mr_init_drv_cmd - Initialize internal command tracker
4947824a1566SKashyap Desai  * @cmdptr: Internal command tracker
4948824a1566SKashyap Desai  * @host_tag: Host tag used for the specific command
4949824a1566SKashyap Desai  *
4950824a1566SKashyap Desai  * Initialize the internal command tracker structure with
4951824a1566SKashyap Desai  * specified host tag.
4952824a1566SKashyap Desai  *
4953824a1566SKashyap Desai  * Return: Nothing.
4954824a1566SKashyap Desai  */
mpi3mr_init_drv_cmd(struct mpi3mr_drv_cmd * cmdptr,u16 host_tag)4955824a1566SKashyap Desai static inline void mpi3mr_init_drv_cmd(struct mpi3mr_drv_cmd *cmdptr,
4956824a1566SKashyap Desai 	u16 host_tag)
4957824a1566SKashyap Desai {
4958824a1566SKashyap Desai 	mutex_init(&cmdptr->mutex);
4959824a1566SKashyap Desai 	cmdptr->reply = NULL;
4960824a1566SKashyap Desai 	cmdptr->state = MPI3MR_CMD_NOTUSED;
4961824a1566SKashyap Desai 	cmdptr->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
4962824a1566SKashyap Desai 	cmdptr->host_tag = host_tag;
4963824a1566SKashyap Desai }
4964824a1566SKashyap Desai 
4965824a1566SKashyap Desai /**
496628cbe2f4SKashyap Desai  * osintfc_mrioc_security_status -Check controller secure status
496728cbe2f4SKashyap Desai  * @pdev: PCI device instance
496828cbe2f4SKashyap Desai  *
496928cbe2f4SKashyap Desai  * Read the Device Serial Number capability from PCI config
497028cbe2f4SKashyap Desai  * space and decide whether the controller is secure or not.
497128cbe2f4SKashyap Desai  *
497228cbe2f4SKashyap Desai  * Return: 0 on success, non-zero on failure.
497328cbe2f4SKashyap Desai  */
497428cbe2f4SKashyap Desai static int
osintfc_mrioc_security_status(struct pci_dev * pdev)497528cbe2f4SKashyap Desai osintfc_mrioc_security_status(struct pci_dev *pdev)
497628cbe2f4SKashyap Desai {
497728cbe2f4SKashyap Desai 	u32 cap_data;
497828cbe2f4SKashyap Desai 	int base;
497928cbe2f4SKashyap Desai 	u32 ctlr_status;
498028cbe2f4SKashyap Desai 	u32 debug_status;
498128cbe2f4SKashyap Desai 	int retval = 0;
498228cbe2f4SKashyap Desai 
498328cbe2f4SKashyap Desai 	base = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DSN);
498428cbe2f4SKashyap Desai 	if (!base) {
498528cbe2f4SKashyap Desai 		dev_err(&pdev->dev,
498628cbe2f4SKashyap Desai 		    "%s: PCI_EXT_CAP_ID_DSN is not supported\n", __func__);
498728cbe2f4SKashyap Desai 		return -1;
498828cbe2f4SKashyap Desai 	}
498928cbe2f4SKashyap Desai 
499028cbe2f4SKashyap Desai 	pci_read_config_dword(pdev, base + 4, &cap_data);
499128cbe2f4SKashyap Desai 
499228cbe2f4SKashyap Desai 	debug_status = cap_data & MPI3MR_CTLR_SECURE_DBG_STATUS_MASK;
499328cbe2f4SKashyap Desai 	ctlr_status = cap_data & MPI3MR_CTLR_SECURITY_STATUS_MASK;
499428cbe2f4SKashyap Desai 
499528cbe2f4SKashyap Desai 	switch (ctlr_status) {
499628cbe2f4SKashyap Desai 	case MPI3MR_INVALID_DEVICE:
499728cbe2f4SKashyap Desai 		dev_err(&pdev->dev,
499828cbe2f4SKashyap Desai 		    "%s: Non secure ctlr (Invalid) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
499928cbe2f4SKashyap Desai 		    __func__, pdev->device, pdev->subsystem_vendor,
500028cbe2f4SKashyap Desai 		    pdev->subsystem_device);
500128cbe2f4SKashyap Desai 		retval = -1;
500228cbe2f4SKashyap Desai 		break;
500328cbe2f4SKashyap Desai 	case MPI3MR_CONFIG_SECURE_DEVICE:
500428cbe2f4SKashyap Desai 		if (!debug_status)
500528cbe2f4SKashyap Desai 			dev_info(&pdev->dev,
500628cbe2f4SKashyap Desai 			    "%s: Config secure ctlr is detected\n",
500728cbe2f4SKashyap Desai 			    __func__);
500828cbe2f4SKashyap Desai 		break;
500928cbe2f4SKashyap Desai 	case MPI3MR_HARD_SECURE_DEVICE:
501028cbe2f4SKashyap Desai 		break;
501128cbe2f4SKashyap Desai 	case MPI3MR_TAMPERED_DEVICE:
501228cbe2f4SKashyap Desai 		dev_err(&pdev->dev,
501328cbe2f4SKashyap Desai 		    "%s: Non secure ctlr (Tampered) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
501428cbe2f4SKashyap Desai 		    __func__, pdev->device, pdev->subsystem_vendor,
501528cbe2f4SKashyap Desai 		    pdev->subsystem_device);
501628cbe2f4SKashyap Desai 		retval = -1;
501728cbe2f4SKashyap Desai 		break;
501828cbe2f4SKashyap Desai 	default:
501928cbe2f4SKashyap Desai 		retval = -1;
502028cbe2f4SKashyap Desai 			break;
502128cbe2f4SKashyap Desai 	}
502228cbe2f4SKashyap Desai 
502328cbe2f4SKashyap Desai 	if (!retval && debug_status) {
502428cbe2f4SKashyap Desai 		dev_err(&pdev->dev,
502528cbe2f4SKashyap Desai 		    "%s: Non secure ctlr (Secure Dbg) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
502628cbe2f4SKashyap Desai 		    __func__, pdev->device, pdev->subsystem_vendor,
502728cbe2f4SKashyap Desai 		    pdev->subsystem_device);
502828cbe2f4SKashyap Desai 		retval = -1;
502928cbe2f4SKashyap Desai 	}
503028cbe2f4SKashyap Desai 
503128cbe2f4SKashyap Desai 	return retval;
503228cbe2f4SKashyap Desai }
503328cbe2f4SKashyap Desai 
503428cbe2f4SKashyap Desai /**
5035824a1566SKashyap Desai  * mpi3mr_probe - PCI probe callback
5036824a1566SKashyap Desai  * @pdev: PCI device instance
5037824a1566SKashyap Desai  * @id: PCI device ID details
5038824a1566SKashyap Desai  *
5039824a1566SKashyap Desai  * controller initialization routine. Checks the security status
5040824a1566SKashyap Desai  * of the controller and if it is invalid or tampered return the
5041824a1566SKashyap Desai  * probe without initializing the controller. Otherwise,
5042824a1566SKashyap Desai  * allocate per adapter instance through shost_priv and
5043824a1566SKashyap Desai  * initialize controller specific data structures, initializae
5044824a1566SKashyap Desai  * the controller hardware, add shost to the SCSI subsystem.
5045824a1566SKashyap Desai  *
5046824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
5047824a1566SKashyap Desai  */
5048824a1566SKashyap Desai 
5049824a1566SKashyap Desai static int
mpi3mr_probe(struct pci_dev * pdev,const struct pci_device_id * id)5050824a1566SKashyap Desai mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
5051824a1566SKashyap Desai {
5052824a1566SKashyap Desai 	struct mpi3mr_ioc *mrioc = NULL;
5053824a1566SKashyap Desai 	struct Scsi_Host *shost = NULL;
505413ef29eaSKashyap Desai 	int retval = 0, i;
5055824a1566SKashyap Desai 
505628cbe2f4SKashyap Desai 	if (osintfc_mrioc_security_status(pdev)) {
505728cbe2f4SKashyap Desai 		warn_non_secure_ctlr = 1;
505828cbe2f4SKashyap Desai 		return 1; /* For Invalid and Tampered device */
505928cbe2f4SKashyap Desai 	}
506028cbe2f4SKashyap Desai 
5061824a1566SKashyap Desai 	shost = scsi_host_alloc(&mpi3mr_driver_template,
5062824a1566SKashyap Desai 	    sizeof(struct mpi3mr_ioc));
5063824a1566SKashyap Desai 	if (!shost) {
5064824a1566SKashyap Desai 		retval = -ENODEV;
5065824a1566SKashyap Desai 		goto shost_failed;
5066824a1566SKashyap Desai 	}
5067824a1566SKashyap Desai 
5068824a1566SKashyap Desai 	mrioc = shost_priv(shost);
5069*f5a20424SRanjan Kumar 	retval = ida_alloc_range(&mrioc_ida, 0, U8_MAX, GFP_KERNEL);
5070d424303dSGuixin Liu 	if (retval < 0)
5071d424303dSGuixin Liu 		goto id_alloc_failed;
5072d424303dSGuixin Liu 	mrioc->id = (u8)retval;
5073824a1566SKashyap Desai 	sprintf(mrioc->driver_name, "%s", MPI3MR_DRIVER_NAME);
5074824a1566SKashyap Desai 	sprintf(mrioc->name, "%s%d", mrioc->driver_name, mrioc->id);
5075824a1566SKashyap Desai 	INIT_LIST_HEAD(&mrioc->list);
5076824a1566SKashyap Desai 	spin_lock(&mrioc_list_lock);
5077824a1566SKashyap Desai 	list_add_tail(&mrioc->list, &mrioc_list);
5078824a1566SKashyap Desai 	spin_unlock(&mrioc_list_lock);
5079824a1566SKashyap Desai 
5080824a1566SKashyap Desai 	spin_lock_init(&mrioc->admin_req_lock);
5081824a1566SKashyap Desai 	spin_lock_init(&mrioc->reply_free_queue_lock);
5082824a1566SKashyap Desai 	spin_lock_init(&mrioc->sbq_lock);
508313ef29eaSKashyap Desai 	spin_lock_init(&mrioc->fwevt_lock);
508413ef29eaSKashyap Desai 	spin_lock_init(&mrioc->tgtdev_lock);
5085672ae26cSKashyap Desai 	spin_lock_init(&mrioc->watchdog_lock);
5086023ab2a9SKashyap Desai 	spin_lock_init(&mrioc->chain_buf_lock);
5087125ad1e6SSreekanth Reddy 	spin_lock_init(&mrioc->sas_node_lock);
5088824a1566SKashyap Desai 
508913ef29eaSKashyap Desai 	INIT_LIST_HEAD(&mrioc->fwevt_list);
509013ef29eaSKashyap Desai 	INIT_LIST_HEAD(&mrioc->tgtdev_list);
509113ef29eaSKashyap Desai 	INIT_LIST_HEAD(&mrioc->delayed_rmhs_list);
5092c1af985dSSreekanth Reddy 	INIT_LIST_HEAD(&mrioc->delayed_evtack_cmds_list);
5093125ad1e6SSreekanth Reddy 	INIT_LIST_HEAD(&mrioc->sas_expander_list);
5094125ad1e6SSreekanth Reddy 	INIT_LIST_HEAD(&mrioc->hba_port_table_list);
50957188c03fSSreekanth Reddy 	INIT_LIST_HEAD(&mrioc->enclosure_list);
509613ef29eaSKashyap Desai 
5097fb9b0457SKashyap Desai 	mutex_init(&mrioc->reset_mutex);
5098824a1566SKashyap Desai 	mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
5099e844adb1SKashyap Desai 	mpi3mr_init_drv_cmd(&mrioc->host_tm_cmds, MPI3MR_HOSTTAG_BLK_TMS);
5100f5e6d5a3SSumit Saxena 	mpi3mr_init_drv_cmd(&mrioc->bsg_cmds, MPI3MR_HOSTTAG_BSG_CMDS);
510132d457d5SSreekanth Reddy 	mpi3mr_init_drv_cmd(&mrioc->cfg_cmds, MPI3MR_HOSTTAG_CFG_CMDS);
51022bd37e28SSreekanth Reddy 	mpi3mr_init_drv_cmd(&mrioc->transport_cmds,
51032bd37e28SSreekanth Reddy 	    MPI3MR_HOSTTAG_TRANSPORT_CMDS);
5104672ae26cSKashyap Desai 
510513ef29eaSKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
510613ef29eaSKashyap Desai 		mpi3mr_init_drv_cmd(&mrioc->dev_rmhs_cmds[i],
510713ef29eaSKashyap Desai 		    MPI3MR_HOSTTAG_DEVRMCMD_MIN + i);
510813ef29eaSKashyap Desai 
5109e39ea831SShin'ichiro Kawasaki 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++)
5110e39ea831SShin'ichiro Kawasaki 		mpi3mr_init_drv_cmd(&mrioc->evtack_cmds[i],
5111e39ea831SShin'ichiro Kawasaki 				    MPI3MR_HOSTTAG_EVTACKCMD_MIN + i);
5112e39ea831SShin'ichiro Kawasaki 
51136e1613daSSumit Saxena 	if ((pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) &&
51146e1613daSSumit Saxena 		!pdev->revision)
51156e1613daSSumit Saxena 		mrioc->enable_segqueue = false;
51166e1613daSSumit Saxena 	else
5117c9566231SKashyap Desai 		mrioc->enable_segqueue = true;
5118824a1566SKashyap Desai 
5119fb9b0457SKashyap Desai 	init_waitqueue_head(&mrioc->reset_waitq);
5120824a1566SKashyap Desai 	mrioc->logging_level = logging_level;
5121824a1566SKashyap Desai 	mrioc->shost = shost;
5122824a1566SKashyap Desai 	mrioc->pdev = pdev;
5123f5e6d5a3SSumit Saxena 	mrioc->stop_bsgs = 1;
5124824a1566SKashyap Desai 
5125d9adb81eSRanjan Kumar 	mrioc->max_sgl_entries = max_sgl_entries;
5126d9adb81eSRanjan Kumar 	if (max_sgl_entries > MPI3MR_MAX_SGL_ENTRIES)
5127d9adb81eSRanjan Kumar 		mrioc->max_sgl_entries = MPI3MR_MAX_SGL_ENTRIES;
5128d9adb81eSRanjan Kumar 	else if (max_sgl_entries < MPI3MR_DEFAULT_SGL_ENTRIES)
5129d9adb81eSRanjan Kumar 		mrioc->max_sgl_entries = MPI3MR_DEFAULT_SGL_ENTRIES;
5130d9adb81eSRanjan Kumar 	else {
5131d9adb81eSRanjan Kumar 		mrioc->max_sgl_entries /= MPI3MR_DEFAULT_SGL_ENTRIES;
5132d9adb81eSRanjan Kumar 		mrioc->max_sgl_entries *= MPI3MR_DEFAULT_SGL_ENTRIES;
5133d9adb81eSRanjan Kumar 	}
5134d9adb81eSRanjan Kumar 
5135824a1566SKashyap Desai 	/* init shost parameters */
5136824a1566SKashyap Desai 	shost->max_cmd_len = MPI3MR_MAX_CDB_LENGTH;
5137824a1566SKashyap Desai 	shost->max_lun = -1;
5138824a1566SKashyap Desai 	shost->unique_id = mrioc->id;
5139824a1566SKashyap Desai 
514097e6ea6dSSreekanth Reddy 	shost->max_channel = 0;
5141824a1566SKashyap Desai 	shost->max_id = 0xFFFFFFFF;
5142824a1566SKashyap Desai 
5143465191d6SSreekanth Reddy 	shost->host_tagset = 1;
5144465191d6SSreekanth Reddy 
514574e1f30aSKashyap Desai 	if (prot_mask >= 0)
514674e1f30aSKashyap Desai 		scsi_host_set_prot(shost, prot_mask);
514774e1f30aSKashyap Desai 	else {
514874e1f30aSKashyap Desai 		prot_mask = SHOST_DIF_TYPE1_PROTECTION
514974e1f30aSKashyap Desai 		    | SHOST_DIF_TYPE2_PROTECTION
515074e1f30aSKashyap Desai 		    | SHOST_DIF_TYPE3_PROTECTION;
515174e1f30aSKashyap Desai 		scsi_host_set_prot(shost, prot_mask);
515274e1f30aSKashyap Desai 	}
515374e1f30aSKashyap Desai 
515474e1f30aSKashyap Desai 	ioc_info(mrioc,
515574e1f30aSKashyap Desai 	    "%s :host protection capabilities enabled %s%s%s%s%s%s%s\n",
515674e1f30aSKashyap Desai 	    __func__,
515774e1f30aSKashyap Desai 	    (prot_mask & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
515874e1f30aSKashyap Desai 	    (prot_mask & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
515974e1f30aSKashyap Desai 	    (prot_mask & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
516074e1f30aSKashyap Desai 	    (prot_mask & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
516174e1f30aSKashyap Desai 	    (prot_mask & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
516274e1f30aSKashyap Desai 	    (prot_mask & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
516374e1f30aSKashyap Desai 	    (prot_mask & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
516474e1f30aSKashyap Desai 
516574e1f30aSKashyap Desai 	if (prot_guard_mask)
516674e1f30aSKashyap Desai 		scsi_host_set_guard(shost, (prot_guard_mask & 3));
516774e1f30aSKashyap Desai 	else
516874e1f30aSKashyap Desai 		scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
516974e1f30aSKashyap Desai 
517013ef29eaSKashyap Desai 	snprintf(mrioc->fwevt_worker_name, sizeof(mrioc->fwevt_worker_name),
517113ef29eaSKashyap Desai 	    "%s%d_fwevt_wrkr", mrioc->driver_name, mrioc->id);
517213ef29eaSKashyap Desai 	mrioc->fwevt_worker_thread = alloc_ordered_workqueue(
5173334ae645SSreekanth Reddy 	    mrioc->fwevt_worker_name, 0);
517413ef29eaSKashyap Desai 	if (!mrioc->fwevt_worker_thread) {
517513ef29eaSKashyap Desai 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
517613ef29eaSKashyap Desai 		    __FILE__, __LINE__, __func__);
517713ef29eaSKashyap Desai 		retval = -ENODEV;
5178fe6db615SSreekanth Reddy 		goto fwevtthread_failed;
517913ef29eaSKashyap Desai 	}
518013ef29eaSKashyap Desai 
5181824a1566SKashyap Desai 	mrioc->is_driver_loading = 1;
5182fe6db615SSreekanth Reddy 	mrioc->cpu_count = num_online_cpus();
5183fe6db615SSreekanth Reddy 	if (mpi3mr_setup_resources(mrioc)) {
5184fe6db615SSreekanth Reddy 		ioc_err(mrioc, "setup resources failed\n");
5185824a1566SKashyap Desai 		retval = -ENODEV;
5186fe6db615SSreekanth Reddy 		goto resource_alloc_failed;
5187fe6db615SSreekanth Reddy 	}
5188fe6db615SSreekanth Reddy 	if (mpi3mr_init_ioc(mrioc)) {
5189fe6db615SSreekanth Reddy 		ioc_err(mrioc, "initializing IOC failed\n");
5190fe6db615SSreekanth Reddy 		retval = -ENODEV;
5191fe6db615SSreekanth Reddy 		goto init_ioc_failed;
5192824a1566SKashyap Desai 	}
5193824a1566SKashyap Desai 
5194824a1566SKashyap Desai 	shost->nr_hw_queues = mrioc->num_op_reply_q;
5195afd3a579SSreekanth Reddy 	if (mrioc->active_poll_qcount)
5196afd3a579SSreekanth Reddy 		shost->nr_maps = 3;
5197afd3a579SSreekanth Reddy 
5198824a1566SKashyap Desai 	shost->can_queue = mrioc->max_host_ios;
5199d9adb81eSRanjan Kumar 	shost->sg_tablesize = mrioc->max_sgl_entries;
5200fe6db615SSreekanth Reddy 	shost->max_id = mrioc->facts.max_perids + 1;
5201824a1566SKashyap Desai 
5202824a1566SKashyap Desai 	retval = scsi_add_host(shost, &pdev->dev);
5203824a1566SKashyap Desai 	if (retval) {
5204824a1566SKashyap Desai 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
5205824a1566SKashyap Desai 		    __FILE__, __LINE__, __func__);
5206824a1566SKashyap Desai 		goto addhost_failed;
5207824a1566SKashyap Desai 	}
5208824a1566SKashyap Desai 
5209824a1566SKashyap Desai 	scsi_scan_host(shost);
52104268fa75SSumit Saxena 	mpi3mr_bsg_init(mrioc);
5211824a1566SKashyap Desai 	return retval;
5212824a1566SKashyap Desai 
5213824a1566SKashyap Desai addhost_failed:
5214fe6db615SSreekanth Reddy 	mpi3mr_stop_watchdog(mrioc);
5215fe6db615SSreekanth Reddy 	mpi3mr_cleanup_ioc(mrioc);
5216fe6db615SSreekanth Reddy init_ioc_failed:
5217fe6db615SSreekanth Reddy 	mpi3mr_free_mem(mrioc);
5218fe6db615SSreekanth Reddy 	mpi3mr_cleanup_resources(mrioc);
5219fe6db615SSreekanth Reddy resource_alloc_failed:
522013ef29eaSKashyap Desai 	destroy_workqueue(mrioc->fwevt_worker_thread);
5221fe6db615SSreekanth Reddy fwevtthread_failed:
5222d424303dSGuixin Liu 	ida_free(&mrioc_ida, mrioc->id);
5223824a1566SKashyap Desai 	spin_lock(&mrioc_list_lock);
5224824a1566SKashyap Desai 	list_del(&mrioc->list);
5225824a1566SKashyap Desai 	spin_unlock(&mrioc_list_lock);
5226d424303dSGuixin Liu id_alloc_failed:
5227824a1566SKashyap Desai 	scsi_host_put(shost);
5228824a1566SKashyap Desai shost_failed:
5229824a1566SKashyap Desai 	return retval;
5230824a1566SKashyap Desai }
5231824a1566SKashyap Desai 
5232824a1566SKashyap Desai /**
5233824a1566SKashyap Desai  * mpi3mr_remove - PCI remove callback
5234824a1566SKashyap Desai  * @pdev: PCI device instance
5235824a1566SKashyap Desai  *
5236fe6db615SSreekanth Reddy  * Cleanup the IOC by issuing MUR and shutdown notification.
5237824a1566SKashyap Desai  * Free up all memory and resources associated with the
5238824a1566SKashyap Desai  * controllerand target devices, unregister the shost.
5239824a1566SKashyap Desai  *
5240824a1566SKashyap Desai  * Return: Nothing.
5241824a1566SKashyap Desai  */
mpi3mr_remove(struct pci_dev * pdev)5242824a1566SKashyap Desai static void mpi3mr_remove(struct pci_dev *pdev)
5243824a1566SKashyap Desai {
5244824a1566SKashyap Desai 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
5245824a1566SKashyap Desai 	struct mpi3mr_ioc *mrioc;
524613ef29eaSKashyap Desai 	struct workqueue_struct	*wq;
524713ef29eaSKashyap Desai 	unsigned long flags;
524813ef29eaSKashyap Desai 	struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next;
5249d0f3c372STomas Henzl 	struct mpi3mr_hba_port *port, *hba_port_next;
5250ce756daaSTomas Henzl 	struct mpi3mr_sas_node *sas_expander, *sas_expander_next;
5251824a1566SKashyap Desai 
525228cbe2f4SKashyap Desai 	if (!shost)
525328cbe2f4SKashyap Desai 		return;
525428cbe2f4SKashyap Desai 
5255824a1566SKashyap Desai 	mrioc = shost_priv(shost);
5256824a1566SKashyap Desai 	while (mrioc->reset_in_progress || mrioc->is_driver_loading)
5257824a1566SKashyap Desai 		ssleep(1);
5258824a1566SKashyap Desai 
5259f2a79d20SSreekanth Reddy 	if (!pci_device_is_present(mrioc->pdev)) {
5260f2a79d20SSreekanth Reddy 		mrioc->unrecoverable = 1;
5261f2a79d20SSreekanth Reddy 		mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
5262f2a79d20SSreekanth Reddy 	}
5263f2a79d20SSreekanth Reddy 
52644268fa75SSumit Saxena 	mpi3mr_bsg_exit(mrioc);
5265023ab2a9SKashyap Desai 	mrioc->stop_drv_processing = 1;
526613ef29eaSKashyap Desai 	mpi3mr_cleanup_fwevt_list(mrioc);
526713ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->fwevt_lock, flags);
526813ef29eaSKashyap Desai 	wq = mrioc->fwevt_worker_thread;
526913ef29eaSKashyap Desai 	mrioc->fwevt_worker_thread = NULL;
527013ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
527113ef29eaSKashyap Desai 	if (wq)
527213ef29eaSKashyap Desai 		destroy_workqueue(wq);
5273c4723e68SSreekanth Reddy 
5274c4723e68SSreekanth Reddy 	if (mrioc->sas_transport_enabled)
5275c4723e68SSreekanth Reddy 		sas_remove_host(shost);
5276c4723e68SSreekanth Reddy 	else
5277824a1566SKashyap Desai 		scsi_remove_host(shost);
5278824a1566SKashyap Desai 
527913ef29eaSKashyap Desai 	list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
528013ef29eaSKashyap Desai 	    list) {
528113ef29eaSKashyap Desai 		mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
52823f1254edSRanjan Kumar 		mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, true);
528313ef29eaSKashyap Desai 		mpi3mr_tgtdev_put(tgtdev);
528413ef29eaSKashyap Desai 	}
5285fe6db615SSreekanth Reddy 	mpi3mr_stop_watchdog(mrioc);
5286fe6db615SSreekanth Reddy 	mpi3mr_cleanup_ioc(mrioc);
5287fe6db615SSreekanth Reddy 	mpi3mr_free_mem(mrioc);
5288fe6db615SSreekanth Reddy 	mpi3mr_cleanup_resources(mrioc);
5289824a1566SKashyap Desai 
5290d0f3c372STomas Henzl 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
5291ce756daaSTomas Henzl 	list_for_each_entry_safe_reverse(sas_expander, sas_expander_next,
5292ce756daaSTomas Henzl 	    &mrioc->sas_expander_list, list) {
5293ce756daaSTomas Henzl 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
5294ce756daaSTomas Henzl 		mpi3mr_expander_node_remove(mrioc, sas_expander);
5295ce756daaSTomas Henzl 		spin_lock_irqsave(&mrioc->sas_node_lock, flags);
5296ce756daaSTomas Henzl 	}
5297d0f3c372STomas Henzl 	list_for_each_entry_safe(port, hba_port_next, &mrioc->hba_port_table_list, list) {
5298d0f3c372STomas Henzl 		ioc_info(mrioc,
5299d0f3c372STomas Henzl 		    "removing hba_port entry: %p port: %d from hba_port list\n",
5300d0f3c372STomas Henzl 		    port, port->port_id);
5301d0f3c372STomas Henzl 		list_del(&port->list);
5302d0f3c372STomas Henzl 		kfree(port);
5303d0f3c372STomas Henzl 	}
5304d0f3c372STomas Henzl 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
5305d0f3c372STomas Henzl 
5306d4caa1a4STomas Henzl 	if (mrioc->sas_hba.num_phys) {
5307d4caa1a4STomas Henzl 		kfree(mrioc->sas_hba.phy);
5308d4caa1a4STomas Henzl 		mrioc->sas_hba.phy = NULL;
5309d4caa1a4STomas Henzl 		mrioc->sas_hba.num_phys = 0;
5310d4caa1a4STomas Henzl 	}
5311d4caa1a4STomas Henzl 
5312d424303dSGuixin Liu 	ida_free(&mrioc_ida, mrioc->id);
5313824a1566SKashyap Desai 	spin_lock(&mrioc_list_lock);
5314824a1566SKashyap Desai 	list_del(&mrioc->list);
5315824a1566SKashyap Desai 	spin_unlock(&mrioc_list_lock);
5316824a1566SKashyap Desai 
5317824a1566SKashyap Desai 	scsi_host_put(shost);
5318824a1566SKashyap Desai }
5319824a1566SKashyap Desai 
5320824a1566SKashyap Desai /**
5321824a1566SKashyap Desai  * mpi3mr_shutdown - PCI shutdown callback
5322824a1566SKashyap Desai  * @pdev: PCI device instance
5323824a1566SKashyap Desai  *
5324824a1566SKashyap Desai  * Free up all memory and resources associated with the
5325824a1566SKashyap Desai  * controller
5326824a1566SKashyap Desai  *
5327824a1566SKashyap Desai  * Return: Nothing.
5328824a1566SKashyap Desai  */
mpi3mr_shutdown(struct pci_dev * pdev)5329824a1566SKashyap Desai static void mpi3mr_shutdown(struct pci_dev *pdev)
5330824a1566SKashyap Desai {
5331824a1566SKashyap Desai 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
5332824a1566SKashyap Desai 	struct mpi3mr_ioc *mrioc;
533313ef29eaSKashyap Desai 	struct workqueue_struct	*wq;
533413ef29eaSKashyap Desai 	unsigned long flags;
5335824a1566SKashyap Desai 
5336824a1566SKashyap Desai 	if (!shost)
5337824a1566SKashyap Desai 		return;
5338824a1566SKashyap Desai 
5339824a1566SKashyap Desai 	mrioc = shost_priv(shost);
5340824a1566SKashyap Desai 	while (mrioc->reset_in_progress || mrioc->is_driver_loading)
5341824a1566SKashyap Desai 		ssleep(1);
5342824a1566SKashyap Desai 
5343023ab2a9SKashyap Desai 	mrioc->stop_drv_processing = 1;
534413ef29eaSKashyap Desai 	mpi3mr_cleanup_fwevt_list(mrioc);
534513ef29eaSKashyap Desai 	spin_lock_irqsave(&mrioc->fwevt_lock, flags);
534613ef29eaSKashyap Desai 	wq = mrioc->fwevt_worker_thread;
534713ef29eaSKashyap Desai 	mrioc->fwevt_worker_thread = NULL;
534813ef29eaSKashyap Desai 	spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
534913ef29eaSKashyap Desai 	if (wq)
535013ef29eaSKashyap Desai 		destroy_workqueue(wq);
5351fe6db615SSreekanth Reddy 
5352fe6db615SSreekanth Reddy 	mpi3mr_stop_watchdog(mrioc);
5353fe6db615SSreekanth Reddy 	mpi3mr_cleanup_ioc(mrioc);
5354fe6db615SSreekanth Reddy 	mpi3mr_cleanup_resources(mrioc);
5355824a1566SKashyap Desai }
5356824a1566SKashyap Desai 
53572f9c4d52SKashyap Desai /**
53582f9c4d52SKashyap Desai  * mpi3mr_suspend - PCI power management suspend callback
535947cd930eSSreekanth Reddy  * @dev: Device struct
53602f9c4d52SKashyap Desai  *
53612f9c4d52SKashyap Desai  * Change the power state to the given value and cleanup the IOC
53622f9c4d52SKashyap Desai  * by issuing MUR and shutdown notification
53632f9c4d52SKashyap Desai  *
53642f9c4d52SKashyap Desai  * Return: 0 always.
53652f9c4d52SKashyap Desai  */
536647cd930eSSreekanth Reddy static int __maybe_unused
mpi3mr_suspend(struct device * dev)536747cd930eSSreekanth Reddy mpi3mr_suspend(struct device *dev)
53682f9c4d52SKashyap Desai {
536947cd930eSSreekanth Reddy 	struct pci_dev *pdev = to_pci_dev(dev);
53702f9c4d52SKashyap Desai 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
53712f9c4d52SKashyap Desai 	struct mpi3mr_ioc *mrioc;
53722f9c4d52SKashyap Desai 
53732f9c4d52SKashyap Desai 	if (!shost)
53742f9c4d52SKashyap Desai 		return 0;
53752f9c4d52SKashyap Desai 
53762f9c4d52SKashyap Desai 	mrioc = shost_priv(shost);
53772f9c4d52SKashyap Desai 	while (mrioc->reset_in_progress || mrioc->is_driver_loading)
53782f9c4d52SKashyap Desai 		ssleep(1);
53792f9c4d52SKashyap Desai 	mrioc->stop_drv_processing = 1;
53802f9c4d52SKashyap Desai 	mpi3mr_cleanup_fwevt_list(mrioc);
53812f9c4d52SKashyap Desai 	scsi_block_requests(shost);
53822f9c4d52SKashyap Desai 	mpi3mr_stop_watchdog(mrioc);
5383fe6db615SSreekanth Reddy 	mpi3mr_cleanup_ioc(mrioc);
53842f9c4d52SKashyap Desai 
538547cd930eSSreekanth Reddy 	ioc_info(mrioc, "pdev=0x%p, slot=%s, entering operating state\n",
538647cd930eSSreekanth Reddy 	    pdev, pci_name(pdev));
53872f9c4d52SKashyap Desai 	mpi3mr_cleanup_resources(mrioc);
53882f9c4d52SKashyap Desai 
53892f9c4d52SKashyap Desai 	return 0;
53902f9c4d52SKashyap Desai }
53912f9c4d52SKashyap Desai 
53922f9c4d52SKashyap Desai /**
53932f9c4d52SKashyap Desai  * mpi3mr_resume - PCI power management resume callback
539447cd930eSSreekanth Reddy  * @dev: Device struct
53952f9c4d52SKashyap Desai  *
53962f9c4d52SKashyap Desai  * Restore the power state to D0 and reinitialize the controller
53972f9c4d52SKashyap Desai  * and resume I/O operations to the target devices
53982f9c4d52SKashyap Desai  *
53992f9c4d52SKashyap Desai  * Return: 0 on success, non-zero on failure
54002f9c4d52SKashyap Desai  */
540147cd930eSSreekanth Reddy static int __maybe_unused
mpi3mr_resume(struct device * dev)540247cd930eSSreekanth Reddy mpi3mr_resume(struct device *dev)
54032f9c4d52SKashyap Desai {
540447cd930eSSreekanth Reddy 	struct pci_dev *pdev = to_pci_dev(dev);
54052f9c4d52SKashyap Desai 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
54062f9c4d52SKashyap Desai 	struct mpi3mr_ioc *mrioc;
54072f9c4d52SKashyap Desai 	pci_power_t device_state = pdev->current_state;
54082f9c4d52SKashyap Desai 	int r;
54092f9c4d52SKashyap Desai 
541028cbe2f4SKashyap Desai 	if (!shost)
541128cbe2f4SKashyap Desai 		return 0;
541228cbe2f4SKashyap Desai 
54132f9c4d52SKashyap Desai 	mrioc = shost_priv(shost);
54142f9c4d52SKashyap Desai 
54152f9c4d52SKashyap Desai 	ioc_info(mrioc, "pdev=0x%p, slot=%s, previous operating state [D%d]\n",
54162f9c4d52SKashyap Desai 	    pdev, pci_name(pdev), device_state);
54172f9c4d52SKashyap Desai 	mrioc->pdev = pdev;
54182f9c4d52SKashyap Desai 	mrioc->cpu_count = num_online_cpus();
54192f9c4d52SKashyap Desai 	r = mpi3mr_setup_resources(mrioc);
54202f9c4d52SKashyap Desai 	if (r) {
54212f9c4d52SKashyap Desai 		ioc_info(mrioc, "%s: Setup resources failed[%d]\n",
54222f9c4d52SKashyap Desai 		    __func__, r);
54232f9c4d52SKashyap Desai 		return r;
54242f9c4d52SKashyap Desai 	}
54252f9c4d52SKashyap Desai 
54262f9c4d52SKashyap Desai 	mrioc->stop_drv_processing = 0;
5427f84e8b5bSSreekanth Reddy 	mpi3mr_invalidate_devhandles(mrioc);
5428f84e8b5bSSreekanth Reddy 	mpi3mr_free_enclosure_list(mrioc);
54290da66348SKashyap Desai 	mpi3mr_memset_buffers(mrioc);
5430fe6db615SSreekanth Reddy 	r = mpi3mr_reinit_ioc(mrioc, 1);
5431fe6db615SSreekanth Reddy 	if (r) {
5432fe6db615SSreekanth Reddy 		ioc_err(mrioc, "resuming controller failed[%d]\n", r);
5433fe6db615SSreekanth Reddy 		return r;
5434fe6db615SSreekanth Reddy 	}
5435f84e8b5bSSreekanth Reddy 	ssleep(MPI3MR_RESET_TOPOLOGY_SETTLE_TIME);
54362f9c4d52SKashyap Desai 	scsi_unblock_requests(shost);
5437f84e8b5bSSreekanth Reddy 	mrioc->device_refresh_on = 0;
54382f9c4d52SKashyap Desai 	mpi3mr_start_watchdog(mrioc);
54392f9c4d52SKashyap Desai 
54402f9c4d52SKashyap Desai 	return 0;
54412f9c4d52SKashyap Desai }
54422f9c4d52SKashyap Desai 
5443824a1566SKashyap Desai static const struct pci_device_id mpi3mr_pci_id_table[] = {
5444824a1566SKashyap Desai 	{
544595cca8d5SSreekanth Reddy 		PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM,
544695cca8d5SSreekanth Reddy 		    MPI3_MFGPAGE_DEVID_SAS4116, PCI_ANY_ID, PCI_ANY_ID)
5447824a1566SKashyap Desai 	},
5448177fe2a7SSumit Saxena 	{
5449177fe2a7SSumit Saxena 		PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM,
5450177fe2a7SSumit Saxena 		    MPI3_MFGPAGE_DEVID_SAS5116_MPI, PCI_ANY_ID, PCI_ANY_ID)
5451177fe2a7SSumit Saxena 	},
5452177fe2a7SSumit Saxena 	{
5453177fe2a7SSumit Saxena 		PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM,
5454177fe2a7SSumit Saxena 		    MPI3_MFGPAGE_DEVID_SAS5116_MPI_MGMT, PCI_ANY_ID, PCI_ANY_ID)
5455177fe2a7SSumit Saxena 	},
5456824a1566SKashyap Desai 	{ 0 }
5457824a1566SKashyap Desai };
5458824a1566SKashyap Desai MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table);
5459824a1566SKashyap Desai 
546047cd930eSSreekanth Reddy static SIMPLE_DEV_PM_OPS(mpi3mr_pm_ops, mpi3mr_suspend, mpi3mr_resume);
546147cd930eSSreekanth Reddy 
5462824a1566SKashyap Desai static struct pci_driver mpi3mr_pci_driver = {
5463824a1566SKashyap Desai 	.name = MPI3MR_DRIVER_NAME,
5464824a1566SKashyap Desai 	.id_table = mpi3mr_pci_id_table,
5465824a1566SKashyap Desai 	.probe = mpi3mr_probe,
5466824a1566SKashyap Desai 	.remove = mpi3mr_remove,
5467824a1566SKashyap Desai 	.shutdown = mpi3mr_shutdown,
546847cd930eSSreekanth Reddy 	.driver.pm = &mpi3mr_pm_ops,
5469824a1566SKashyap Desai };
5470824a1566SKashyap Desai 
event_counter_show(struct device_driver * dd,char * buf)547143ca1100SSumit Saxena static ssize_t event_counter_show(struct device_driver *dd, char *buf)
547243ca1100SSumit Saxena {
547343ca1100SSumit Saxena 	return sprintf(buf, "%llu\n", atomic64_read(&event_counter));
547443ca1100SSumit Saxena }
547543ca1100SSumit Saxena static DRIVER_ATTR_RO(event_counter);
547643ca1100SSumit Saxena 
mpi3mr_init(void)5477824a1566SKashyap Desai static int __init mpi3mr_init(void)
5478824a1566SKashyap Desai {
5479824a1566SKashyap Desai 	int ret_val;
5480824a1566SKashyap Desai 
5481824a1566SKashyap Desai 	pr_info("Loading %s version %s\n", MPI3MR_DRIVER_NAME,
5482824a1566SKashyap Desai 	    MPI3MR_DRIVER_VERSION);
5483824a1566SKashyap Desai 
5484176d4aa6SSreekanth Reddy 	mpi3mr_transport_template =
5485176d4aa6SSreekanth Reddy 	    sas_attach_transport(&mpi3mr_transport_functions);
5486176d4aa6SSreekanth Reddy 	if (!mpi3mr_transport_template) {
5487176d4aa6SSreekanth Reddy 		pr_err("%s failed to load due to sas transport attach failure\n",
5488176d4aa6SSreekanth Reddy 		    MPI3MR_DRIVER_NAME);
5489176d4aa6SSreekanth Reddy 		return -ENODEV;
5490176d4aa6SSreekanth Reddy 	}
5491176d4aa6SSreekanth Reddy 
5492824a1566SKashyap Desai 	ret_val = pci_register_driver(&mpi3mr_pci_driver);
549343ca1100SSumit Saxena 	if (ret_val) {
549443ca1100SSumit Saxena 		pr_err("%s failed to load due to pci register driver failure\n",
549543ca1100SSumit Saxena 		    MPI3MR_DRIVER_NAME);
5496176d4aa6SSreekanth Reddy 		goto err_pci_reg_fail;
549743ca1100SSumit Saxena 	}
549843ca1100SSumit Saxena 
549943ca1100SSumit Saxena 	ret_val = driver_create_file(&mpi3mr_pci_driver.driver,
550043ca1100SSumit Saxena 				     &driver_attr_event_counter);
550143ca1100SSumit Saxena 	if (ret_val)
5502176d4aa6SSreekanth Reddy 		goto err_event_counter;
5503176d4aa6SSreekanth Reddy 
5504176d4aa6SSreekanth Reddy 	return ret_val;
5505176d4aa6SSreekanth Reddy 
5506176d4aa6SSreekanth Reddy err_event_counter:
550743ca1100SSumit Saxena 	pci_unregister_driver(&mpi3mr_pci_driver);
5508824a1566SKashyap Desai 
5509176d4aa6SSreekanth Reddy err_pci_reg_fail:
5510176d4aa6SSreekanth Reddy 	sas_release_transport(mpi3mr_transport_template);
5511824a1566SKashyap Desai 	return ret_val;
5512824a1566SKashyap Desai }
5513824a1566SKashyap Desai 
mpi3mr_exit(void)5514824a1566SKashyap Desai static void __exit mpi3mr_exit(void)
5515824a1566SKashyap Desai {
5516824a1566SKashyap Desai 	if (warn_non_secure_ctlr)
5517824a1566SKashyap Desai 		pr_warn(
5518824a1566SKashyap Desai 		    "Unloading %s version %s while managing a non secure controller\n",
5519824a1566SKashyap Desai 		    MPI3MR_DRIVER_NAME, MPI3MR_DRIVER_VERSION);
5520824a1566SKashyap Desai 	else
5521824a1566SKashyap Desai 		pr_info("Unloading %s version %s\n", MPI3MR_DRIVER_NAME,
5522824a1566SKashyap Desai 		    MPI3MR_DRIVER_VERSION);
5523824a1566SKashyap Desai 
552443ca1100SSumit Saxena 	driver_remove_file(&mpi3mr_pci_driver.driver,
552543ca1100SSumit Saxena 			   &driver_attr_event_counter);
5526824a1566SKashyap Desai 	pci_unregister_driver(&mpi3mr_pci_driver);
5527176d4aa6SSreekanth Reddy 	sas_release_transport(mpi3mr_transport_template);
5528d424303dSGuixin Liu 	ida_destroy(&mrioc_ida);
5529824a1566SKashyap Desai }
5530824a1566SKashyap Desai 
5531824a1566SKashyap Desai module_init(mpi3mr_init);
5532824a1566SKashyap Desai module_exit(mpi3mr_exit);
5533