162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for Broadcom MPI3 Storage Controllers
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2017-2023 Broadcom Inc.
662306a36Sopenharmony_ci *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "mpi3mr.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/* global driver scop variables */
1362306a36Sopenharmony_ciLIST_HEAD(mrioc_list);
1462306a36Sopenharmony_ciDEFINE_SPINLOCK(mrioc_list_lock);
1562306a36Sopenharmony_cistatic int mrioc_ids;
1662306a36Sopenharmony_cistatic int warn_non_secure_ctlr;
1762306a36Sopenharmony_ciatomic64_t event_counter;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ciMODULE_AUTHOR(MPI3MR_DRIVER_AUTHOR);
2062306a36Sopenharmony_ciMODULE_DESCRIPTION(MPI3MR_DRIVER_DESC);
2162306a36Sopenharmony_ciMODULE_LICENSE(MPI3MR_DRIVER_LICENSE);
2262306a36Sopenharmony_ciMODULE_VERSION(MPI3MR_DRIVER_VERSION);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* Module parameters*/
2562306a36Sopenharmony_ciint prot_mask = -1;
2662306a36Sopenharmony_cimodule_param(prot_mask, int, 0);
2762306a36Sopenharmony_ciMODULE_PARM_DESC(prot_mask, "Host protection capabilities mask, def=0x07");
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic int prot_guard_mask = 3;
3062306a36Sopenharmony_cimodule_param(prot_guard_mask, int, 0);
3162306a36Sopenharmony_ciMODULE_PARM_DESC(prot_guard_mask, " Host protection guard mask, def=3");
3262306a36Sopenharmony_cistatic int logging_level;
3362306a36Sopenharmony_cimodule_param(logging_level, int, 0);
3462306a36Sopenharmony_ciMODULE_PARM_DESC(logging_level,
3562306a36Sopenharmony_ci	" bits for enabling additional logging info (default=0)");
3662306a36Sopenharmony_cistatic int max_sgl_entries = MPI3MR_DEFAULT_SGL_ENTRIES;
3762306a36Sopenharmony_cimodule_param(max_sgl_entries, int, 0444);
3862306a36Sopenharmony_ciMODULE_PARM_DESC(max_sgl_entries,
3962306a36Sopenharmony_ci	"Preferred max number of SG entries to be used for a single I/O\n"
4062306a36Sopenharmony_ci	"The actual value will be determined by the driver\n"
4162306a36Sopenharmony_ci	"(Minimum=256, Maximum=2048, default=256)");
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* Forward declarations*/
4462306a36Sopenharmony_cistatic void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
4562306a36Sopenharmony_ci	struct mpi3mr_drv_cmd *cmdparam, u32 event_ctx);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION	(0xFFFF)
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH	(0xFFFE)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/**
5262306a36Sopenharmony_ci * mpi3mr_host_tag_for_scmd - Get host tag for a scmd
5362306a36Sopenharmony_ci * @mrioc: Adapter instance reference
5462306a36Sopenharmony_ci * @scmd: SCSI command reference
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci * Calculate the host tag based on block tag for a given scmd.
5762306a36Sopenharmony_ci *
5862306a36Sopenharmony_ci * Return: Valid host tag or MPI3MR_HOSTTAG_INVALID.
5962306a36Sopenharmony_ci */
6062306a36Sopenharmony_cistatic u16 mpi3mr_host_tag_for_scmd(struct mpi3mr_ioc *mrioc,
6162306a36Sopenharmony_ci	struct scsi_cmnd *scmd)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	struct scmd_priv *priv = NULL;
6462306a36Sopenharmony_ci	u32 unique_tag;
6562306a36Sopenharmony_ci	u16 host_tag, hw_queue;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	unique_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	hw_queue = blk_mq_unique_tag_to_hwq(unique_tag);
7062306a36Sopenharmony_ci	if (hw_queue >= mrioc->num_op_reply_q)
7162306a36Sopenharmony_ci		return MPI3MR_HOSTTAG_INVALID;
7262306a36Sopenharmony_ci	host_tag = blk_mq_unique_tag_to_tag(unique_tag);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (WARN_ON(host_tag >= mrioc->max_host_ios))
7562306a36Sopenharmony_ci		return MPI3MR_HOSTTAG_INVALID;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	priv = scsi_cmd_priv(scmd);
7862306a36Sopenharmony_ci	/*host_tag 0 is invalid hence incrementing by 1*/
7962306a36Sopenharmony_ci	priv->host_tag = host_tag + 1;
8062306a36Sopenharmony_ci	priv->scmd = scmd;
8162306a36Sopenharmony_ci	priv->in_lld_scope = 1;
8262306a36Sopenharmony_ci	priv->req_q_idx = hw_queue;
8362306a36Sopenharmony_ci	priv->meta_chain_idx = -1;
8462306a36Sopenharmony_ci	priv->chain_idx = -1;
8562306a36Sopenharmony_ci	priv->meta_sg_valid = 0;
8662306a36Sopenharmony_ci	return priv->host_tag;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/**
9062306a36Sopenharmony_ci * mpi3mr_scmd_from_host_tag - Get SCSI command from host tag
9162306a36Sopenharmony_ci * @mrioc: Adapter instance reference
9262306a36Sopenharmony_ci * @host_tag: Host tag
9362306a36Sopenharmony_ci * @qidx: Operational queue index
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * Identify the block tag from the host tag and queue index and
9662306a36Sopenharmony_ci * retrieve associated scsi command using scsi_host_find_tag().
9762306a36Sopenharmony_ci *
9862306a36Sopenharmony_ci * Return: SCSI command reference or NULL.
9962306a36Sopenharmony_ci */
10062306a36Sopenharmony_cistatic struct scsi_cmnd *mpi3mr_scmd_from_host_tag(
10162306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc, u16 host_tag, u16 qidx)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	struct scsi_cmnd *scmd = NULL;
10462306a36Sopenharmony_ci	struct scmd_priv *priv = NULL;
10562306a36Sopenharmony_ci	u32 unique_tag = host_tag - 1;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (WARN_ON(host_tag > mrioc->max_host_ios))
10862306a36Sopenharmony_ci		goto out;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	unique_tag |= (qidx << BLK_MQ_UNIQUE_TAG_BITS);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	scmd = scsi_host_find_tag(mrioc->shost, unique_tag);
11362306a36Sopenharmony_ci	if (scmd) {
11462306a36Sopenharmony_ci		priv = scsi_cmd_priv(scmd);
11562306a36Sopenharmony_ci		if (!priv->in_lld_scope)
11662306a36Sopenharmony_ci			scmd = NULL;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ciout:
11962306a36Sopenharmony_ci	return scmd;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/**
12362306a36Sopenharmony_ci * mpi3mr_clear_scmd_priv - Cleanup SCSI command private date
12462306a36Sopenharmony_ci * @mrioc: Adapter instance reference
12562306a36Sopenharmony_ci * @scmd: SCSI command reference
12662306a36Sopenharmony_ci *
12762306a36Sopenharmony_ci * Invalidate the SCSI command private data to mark the command
12862306a36Sopenharmony_ci * is not in LLD scope anymore.
12962306a36Sopenharmony_ci *
13062306a36Sopenharmony_ci * Return: Nothing.
13162306a36Sopenharmony_ci */
13262306a36Sopenharmony_cistatic void mpi3mr_clear_scmd_priv(struct mpi3mr_ioc *mrioc,
13362306a36Sopenharmony_ci	struct scsi_cmnd *scmd)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	struct scmd_priv *priv = NULL;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	priv = scsi_cmd_priv(scmd);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (WARN_ON(priv->in_lld_scope == 0))
14062306a36Sopenharmony_ci		return;
14162306a36Sopenharmony_ci	priv->host_tag = MPI3MR_HOSTTAG_INVALID;
14262306a36Sopenharmony_ci	priv->req_q_idx = 0xFFFF;
14362306a36Sopenharmony_ci	priv->scmd = NULL;
14462306a36Sopenharmony_ci	priv->in_lld_scope = 0;
14562306a36Sopenharmony_ci	priv->meta_sg_valid = 0;
14662306a36Sopenharmony_ci	if (priv->chain_idx >= 0) {
14762306a36Sopenharmony_ci		clear_bit(priv->chain_idx, mrioc->chain_bitmap);
14862306a36Sopenharmony_ci		priv->chain_idx = -1;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci	if (priv->meta_chain_idx >= 0) {
15162306a36Sopenharmony_ci		clear_bit(priv->meta_chain_idx, mrioc->chain_bitmap);
15262306a36Sopenharmony_ci		priv->meta_chain_idx = -1;
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_ioc *mrioc, u16 handle,
15762306a36Sopenharmony_ci	struct mpi3mr_drv_cmd *cmdparam, u8 iou_rc);
15862306a36Sopenharmony_cistatic void mpi3mr_fwevt_worker(struct work_struct *work);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/**
16162306a36Sopenharmony_ci * mpi3mr_fwevt_free - firmware event memory dealloctor
16262306a36Sopenharmony_ci * @r: k reference pointer of the firmware event
16362306a36Sopenharmony_ci *
16462306a36Sopenharmony_ci * Free firmware event memory when no reference.
16562306a36Sopenharmony_ci */
16662306a36Sopenharmony_cistatic void mpi3mr_fwevt_free(struct kref *r)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	kfree(container_of(r, struct mpi3mr_fwevt, ref_count));
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/**
17262306a36Sopenharmony_ci * mpi3mr_fwevt_get - k reference incrementor
17362306a36Sopenharmony_ci * @fwevt: Firmware event reference
17462306a36Sopenharmony_ci *
17562306a36Sopenharmony_ci * Increment firmware event reference count.
17662306a36Sopenharmony_ci */
17762306a36Sopenharmony_cistatic void mpi3mr_fwevt_get(struct mpi3mr_fwevt *fwevt)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	kref_get(&fwevt->ref_count);
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/**
18362306a36Sopenharmony_ci * mpi3mr_fwevt_put - k reference decrementor
18462306a36Sopenharmony_ci * @fwevt: Firmware event reference
18562306a36Sopenharmony_ci *
18662306a36Sopenharmony_ci * decrement firmware event reference count.
18762306a36Sopenharmony_ci */
18862306a36Sopenharmony_cistatic void mpi3mr_fwevt_put(struct mpi3mr_fwevt *fwevt)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	kref_put(&fwevt->ref_count, mpi3mr_fwevt_free);
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/**
19462306a36Sopenharmony_ci * mpi3mr_alloc_fwevt - Allocate firmware event
19562306a36Sopenharmony_ci * @len: length of firmware event data to allocate
19662306a36Sopenharmony_ci *
19762306a36Sopenharmony_ci * Allocate firmware event with required length and initialize
19862306a36Sopenharmony_ci * the reference counter.
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci * Return: firmware event reference.
20162306a36Sopenharmony_ci */
20262306a36Sopenharmony_cistatic struct mpi3mr_fwevt *mpi3mr_alloc_fwevt(int len)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	fwevt = kzalloc(sizeof(*fwevt) + len, GFP_ATOMIC);
20762306a36Sopenharmony_ci	if (!fwevt)
20862306a36Sopenharmony_ci		return NULL;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	kref_init(&fwevt->ref_count);
21162306a36Sopenharmony_ci	return fwevt;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/**
21562306a36Sopenharmony_ci * mpi3mr_fwevt_add_to_list - Add firmware event to the list
21662306a36Sopenharmony_ci * @mrioc: Adapter instance reference
21762306a36Sopenharmony_ci * @fwevt: Firmware event reference
21862306a36Sopenharmony_ci *
21962306a36Sopenharmony_ci * Add the given firmware event to the firmware event list.
22062306a36Sopenharmony_ci *
22162306a36Sopenharmony_ci * Return: Nothing.
22262306a36Sopenharmony_ci */
22362306a36Sopenharmony_cistatic void mpi3mr_fwevt_add_to_list(struct mpi3mr_ioc *mrioc,
22462306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	unsigned long flags;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (!mrioc->fwevt_worker_thread)
22962306a36Sopenharmony_ci		return;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->fwevt_lock, flags);
23262306a36Sopenharmony_ci	/* get fwevt reference count while adding it to fwevt_list */
23362306a36Sopenharmony_ci	mpi3mr_fwevt_get(fwevt);
23462306a36Sopenharmony_ci	INIT_LIST_HEAD(&fwevt->list);
23562306a36Sopenharmony_ci	list_add_tail(&fwevt->list, &mrioc->fwevt_list);
23662306a36Sopenharmony_ci	INIT_WORK(&fwevt->work, mpi3mr_fwevt_worker);
23762306a36Sopenharmony_ci	/* get fwevt reference count while enqueueing it to worker queue */
23862306a36Sopenharmony_ci	mpi3mr_fwevt_get(fwevt);
23962306a36Sopenharmony_ci	queue_work(mrioc->fwevt_worker_thread, &fwevt->work);
24062306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci/**
24462306a36Sopenharmony_ci * mpi3mr_fwevt_del_from_list - Delete firmware event from list
24562306a36Sopenharmony_ci * @mrioc: Adapter instance reference
24662306a36Sopenharmony_ci * @fwevt: Firmware event reference
24762306a36Sopenharmony_ci *
24862306a36Sopenharmony_ci * Delete the given firmware event from the firmware event list.
24962306a36Sopenharmony_ci *
25062306a36Sopenharmony_ci * Return: Nothing.
25162306a36Sopenharmony_ci */
25262306a36Sopenharmony_cistatic void mpi3mr_fwevt_del_from_list(struct mpi3mr_ioc *mrioc,
25362306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	unsigned long flags;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->fwevt_lock, flags);
25862306a36Sopenharmony_ci	if (!list_empty(&fwevt->list)) {
25962306a36Sopenharmony_ci		list_del_init(&fwevt->list);
26062306a36Sopenharmony_ci		/*
26162306a36Sopenharmony_ci		 * Put fwevt reference count after
26262306a36Sopenharmony_ci		 * removing it from fwevt_list
26362306a36Sopenharmony_ci		 */
26462306a36Sopenharmony_ci		mpi3mr_fwevt_put(fwevt);
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/**
27062306a36Sopenharmony_ci * mpi3mr_dequeue_fwevt - Dequeue firmware event from the list
27162306a36Sopenharmony_ci * @mrioc: Adapter instance reference
27262306a36Sopenharmony_ci *
27362306a36Sopenharmony_ci * Dequeue a firmware event from the firmware event list.
27462306a36Sopenharmony_ci *
27562306a36Sopenharmony_ci * Return: firmware event.
27662306a36Sopenharmony_ci */
27762306a36Sopenharmony_cistatic struct mpi3mr_fwevt *mpi3mr_dequeue_fwevt(
27862306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	unsigned long flags;
28162306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt = NULL;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->fwevt_lock, flags);
28462306a36Sopenharmony_ci	if (!list_empty(&mrioc->fwevt_list)) {
28562306a36Sopenharmony_ci		fwevt = list_first_entry(&mrioc->fwevt_list,
28662306a36Sopenharmony_ci		    struct mpi3mr_fwevt, list);
28762306a36Sopenharmony_ci		list_del_init(&fwevt->list);
28862306a36Sopenharmony_ci		/*
28962306a36Sopenharmony_ci		 * Put fwevt reference count after
29062306a36Sopenharmony_ci		 * removing it from fwevt_list
29162306a36Sopenharmony_ci		 */
29262306a36Sopenharmony_ci		mpi3mr_fwevt_put(fwevt);
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	return fwevt;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci/**
30062306a36Sopenharmony_ci * mpi3mr_cancel_work - cancel firmware event
30162306a36Sopenharmony_ci * @fwevt: fwevt object which needs to be canceled
30262306a36Sopenharmony_ci *
30362306a36Sopenharmony_ci * Return: Nothing.
30462306a36Sopenharmony_ci */
30562306a36Sopenharmony_cistatic void mpi3mr_cancel_work(struct mpi3mr_fwevt *fwevt)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	/*
30862306a36Sopenharmony_ci	 * Wait on the fwevt to complete. If this returns 1, then
30962306a36Sopenharmony_ci	 * the event was never executed.
31062306a36Sopenharmony_ci	 *
31162306a36Sopenharmony_ci	 * If it did execute, we wait for it to finish, and the put will
31262306a36Sopenharmony_ci	 * happen from mpi3mr_process_fwevt()
31362306a36Sopenharmony_ci	 */
31462306a36Sopenharmony_ci	if (cancel_work_sync(&fwevt->work)) {
31562306a36Sopenharmony_ci		/*
31662306a36Sopenharmony_ci		 * Put fwevt reference count after
31762306a36Sopenharmony_ci		 * dequeuing it from worker queue
31862306a36Sopenharmony_ci		 */
31962306a36Sopenharmony_ci		mpi3mr_fwevt_put(fwevt);
32062306a36Sopenharmony_ci		/*
32162306a36Sopenharmony_ci		 * Put fwevt reference count to neutralize
32262306a36Sopenharmony_ci		 * kref_init increment
32362306a36Sopenharmony_ci		 */
32462306a36Sopenharmony_ci		mpi3mr_fwevt_put(fwevt);
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci/**
32962306a36Sopenharmony_ci * mpi3mr_cleanup_fwevt_list - Cleanup firmware event list
33062306a36Sopenharmony_ci * @mrioc: Adapter instance reference
33162306a36Sopenharmony_ci *
33262306a36Sopenharmony_ci * Flush all pending firmware events from the firmware event
33362306a36Sopenharmony_ci * list.
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * Return: Nothing.
33662306a36Sopenharmony_ci */
33762306a36Sopenharmony_civoid mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt = NULL;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if ((list_empty(&mrioc->fwevt_list) && !mrioc->current_event) ||
34262306a36Sopenharmony_ci	    !mrioc->fwevt_worker_thread)
34362306a36Sopenharmony_ci		return;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	while ((fwevt = mpi3mr_dequeue_fwevt(mrioc)))
34662306a36Sopenharmony_ci		mpi3mr_cancel_work(fwevt);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (mrioc->current_event) {
34962306a36Sopenharmony_ci		fwevt = mrioc->current_event;
35062306a36Sopenharmony_ci		/*
35162306a36Sopenharmony_ci		 * Don't call cancel_work_sync() API for the
35262306a36Sopenharmony_ci		 * fwevt work if the controller reset is
35362306a36Sopenharmony_ci		 * get called as part of processing the
35462306a36Sopenharmony_ci		 * same fwevt work (or) when worker thread is
35562306a36Sopenharmony_ci		 * waiting for device add/remove APIs to complete.
35662306a36Sopenharmony_ci		 * Otherwise we will see deadlock.
35762306a36Sopenharmony_ci		 */
35862306a36Sopenharmony_ci		if (current_work() == &fwevt->work || fwevt->pending_at_sml) {
35962306a36Sopenharmony_ci			fwevt->discard = 1;
36062306a36Sopenharmony_ci			return;
36162306a36Sopenharmony_ci		}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		mpi3mr_cancel_work(fwevt);
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci/**
36862306a36Sopenharmony_ci * mpi3mr_queue_qd_reduction_event - Queue TG QD reduction event
36962306a36Sopenharmony_ci * @mrioc: Adapter instance reference
37062306a36Sopenharmony_ci * @tg: Throttle group information pointer
37162306a36Sopenharmony_ci *
37262306a36Sopenharmony_ci * Accessor to queue on synthetically generated driver event to
37362306a36Sopenharmony_ci * the event worker thread, the driver event will be used to
37462306a36Sopenharmony_ci * reduce the QD of all VDs in the TG from the worker thread.
37562306a36Sopenharmony_ci *
37662306a36Sopenharmony_ci * Return: None.
37762306a36Sopenharmony_ci */
37862306a36Sopenharmony_cistatic void mpi3mr_queue_qd_reduction_event(struct mpi3mr_ioc *mrioc,
37962306a36Sopenharmony_ci	struct mpi3mr_throttle_group_info *tg)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt;
38262306a36Sopenharmony_ci	u16 sz = sizeof(struct mpi3mr_throttle_group_info *);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	/*
38562306a36Sopenharmony_ci	 * If the QD reduction event is already queued due to throttle and if
38662306a36Sopenharmony_ci	 * the QD is not restored through device info change event
38762306a36Sopenharmony_ci	 * then dont queue further reduction events
38862306a36Sopenharmony_ci	 */
38962306a36Sopenharmony_ci	if (tg->fw_qd != tg->modified_qd)
39062306a36Sopenharmony_ci		return;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	fwevt = mpi3mr_alloc_fwevt(sz);
39362306a36Sopenharmony_ci	if (!fwevt) {
39462306a36Sopenharmony_ci		ioc_warn(mrioc, "failed to queue TG QD reduction event\n");
39562306a36Sopenharmony_ci		return;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci	*(struct mpi3mr_throttle_group_info **)fwevt->event_data = tg;
39862306a36Sopenharmony_ci	fwevt->mrioc = mrioc;
39962306a36Sopenharmony_ci	fwevt->event_id = MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION;
40062306a36Sopenharmony_ci	fwevt->send_ack = 0;
40162306a36Sopenharmony_ci	fwevt->process_evt = 1;
40262306a36Sopenharmony_ci	fwevt->evt_ctx = 0;
40362306a36Sopenharmony_ci	fwevt->event_data_size = sz;
40462306a36Sopenharmony_ci	tg->modified_qd = max_t(u16, (tg->fw_qd * tg->qd_reduction) / 10, 8);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	dprint_event_bh(mrioc, "qd reduction event queued for tg_id(%d)\n",
40762306a36Sopenharmony_ci	    tg->id);
40862306a36Sopenharmony_ci	mpi3mr_fwevt_add_to_list(mrioc, fwevt);
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci/**
41262306a36Sopenharmony_ci * mpi3mr_invalidate_devhandles -Invalidate device handles
41362306a36Sopenharmony_ci * @mrioc: Adapter instance reference
41462306a36Sopenharmony_ci *
41562306a36Sopenharmony_ci * Invalidate the device handles in the target device structures
41662306a36Sopenharmony_ci * . Called post reset prior to reinitializing the controller.
41762306a36Sopenharmony_ci *
41862306a36Sopenharmony_ci * Return: Nothing.
41962306a36Sopenharmony_ci */
42062306a36Sopenharmony_civoid mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev;
42362306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *tgt_priv;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
42662306a36Sopenharmony_ci		tgtdev->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
42762306a36Sopenharmony_ci		if (tgtdev->starget && tgtdev->starget->hostdata) {
42862306a36Sopenharmony_ci			tgt_priv = tgtdev->starget->hostdata;
42962306a36Sopenharmony_ci			tgt_priv->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
43062306a36Sopenharmony_ci			tgt_priv->io_throttle_enabled = 0;
43162306a36Sopenharmony_ci			tgt_priv->io_divert = 0;
43262306a36Sopenharmony_ci			tgt_priv->throttle_group = NULL;
43362306a36Sopenharmony_ci			tgt_priv->wslen = 0;
43462306a36Sopenharmony_ci			if (tgtdev->host_exposed)
43562306a36Sopenharmony_ci				atomic_set(&tgt_priv->block_io, 1);
43662306a36Sopenharmony_ci		}
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci/**
44162306a36Sopenharmony_ci * mpi3mr_print_scmd - print individual SCSI command
44262306a36Sopenharmony_ci * @rq: Block request
44362306a36Sopenharmony_ci * @data: Adapter instance reference
44462306a36Sopenharmony_ci *
44562306a36Sopenharmony_ci * Print the SCSI command details if it is in LLD scope.
44662306a36Sopenharmony_ci *
44762306a36Sopenharmony_ci * Return: true always.
44862306a36Sopenharmony_ci */
44962306a36Sopenharmony_cistatic bool mpi3mr_print_scmd(struct request *rq, void *data)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc = (struct mpi3mr_ioc *)data;
45262306a36Sopenharmony_ci	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
45362306a36Sopenharmony_ci	struct scmd_priv *priv = NULL;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (scmd) {
45662306a36Sopenharmony_ci		priv = scsi_cmd_priv(scmd);
45762306a36Sopenharmony_ci		if (!priv->in_lld_scope)
45862306a36Sopenharmony_ci			goto out;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci		ioc_info(mrioc, "%s :Host Tag = %d, qid = %d\n",
46162306a36Sopenharmony_ci		    __func__, priv->host_tag, priv->req_q_idx + 1);
46262306a36Sopenharmony_ci		scsi_print_command(scmd);
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ciout:
46662306a36Sopenharmony_ci	return(true);
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci/**
47062306a36Sopenharmony_ci * mpi3mr_flush_scmd - Flush individual SCSI command
47162306a36Sopenharmony_ci * @rq: Block request
47262306a36Sopenharmony_ci * @data: Adapter instance reference
47362306a36Sopenharmony_ci *
47462306a36Sopenharmony_ci * Return the SCSI command to the upper layers if it is in LLD
47562306a36Sopenharmony_ci * scope.
47662306a36Sopenharmony_ci *
47762306a36Sopenharmony_ci * Return: true always.
47862306a36Sopenharmony_ci */
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic bool mpi3mr_flush_scmd(struct request *rq, void *data)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc = (struct mpi3mr_ioc *)data;
48362306a36Sopenharmony_ci	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
48462306a36Sopenharmony_ci	struct scmd_priv *priv = NULL;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (scmd) {
48762306a36Sopenharmony_ci		priv = scsi_cmd_priv(scmd);
48862306a36Sopenharmony_ci		if (!priv->in_lld_scope)
48962306a36Sopenharmony_ci			goto out;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci		if (priv->meta_sg_valid)
49262306a36Sopenharmony_ci			dma_unmap_sg(&mrioc->pdev->dev, scsi_prot_sglist(scmd),
49362306a36Sopenharmony_ci			    scsi_prot_sg_count(scmd), scmd->sc_data_direction);
49462306a36Sopenharmony_ci		mpi3mr_clear_scmd_priv(mrioc, scmd);
49562306a36Sopenharmony_ci		scsi_dma_unmap(scmd);
49662306a36Sopenharmony_ci		scmd->result = DID_RESET << 16;
49762306a36Sopenharmony_ci		scsi_print_command(scmd);
49862306a36Sopenharmony_ci		scsi_done(scmd);
49962306a36Sopenharmony_ci		mrioc->flush_io_count++;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ciout:
50362306a36Sopenharmony_ci	return(true);
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci/**
50762306a36Sopenharmony_ci * mpi3mr_count_dev_pending - Count commands pending for a lun
50862306a36Sopenharmony_ci * @rq: Block request
50962306a36Sopenharmony_ci * @data: SCSI device reference
51062306a36Sopenharmony_ci *
51162306a36Sopenharmony_ci * This is an iterator function called for each SCSI command in
51262306a36Sopenharmony_ci * a host and if the command is pending in the LLD for the
51362306a36Sopenharmony_ci * specific device(lun) then device specific pending I/O counter
51462306a36Sopenharmony_ci * is updated in the device structure.
51562306a36Sopenharmony_ci *
51662306a36Sopenharmony_ci * Return: true always.
51762306a36Sopenharmony_ci */
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic bool mpi3mr_count_dev_pending(struct request *rq, void *data)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	struct scsi_device *sdev = (struct scsi_device *)data;
52262306a36Sopenharmony_ci	struct mpi3mr_sdev_priv_data *sdev_priv_data = sdev->hostdata;
52362306a36Sopenharmony_ci	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
52462306a36Sopenharmony_ci	struct scmd_priv *priv;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if (scmd) {
52762306a36Sopenharmony_ci		priv = scsi_cmd_priv(scmd);
52862306a36Sopenharmony_ci		if (!priv->in_lld_scope)
52962306a36Sopenharmony_ci			goto out;
53062306a36Sopenharmony_ci		if (scmd->device == sdev)
53162306a36Sopenharmony_ci			sdev_priv_data->pend_count++;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ciout:
53562306a36Sopenharmony_ci	return true;
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci/**
53962306a36Sopenharmony_ci * mpi3mr_count_tgt_pending - Count commands pending for target
54062306a36Sopenharmony_ci * @rq: Block request
54162306a36Sopenharmony_ci * @data: SCSI target reference
54262306a36Sopenharmony_ci *
54362306a36Sopenharmony_ci * This is an iterator function called for each SCSI command in
54462306a36Sopenharmony_ci * a host and if the command is pending in the LLD for the
54562306a36Sopenharmony_ci * specific target then target specific pending I/O counter is
54662306a36Sopenharmony_ci * updated in the target structure.
54762306a36Sopenharmony_ci *
54862306a36Sopenharmony_ci * Return: true always.
54962306a36Sopenharmony_ci */
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic bool mpi3mr_count_tgt_pending(struct request *rq, void *data)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	struct scsi_target *starget = (struct scsi_target *)data;
55462306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *stgt_priv_data = starget->hostdata;
55562306a36Sopenharmony_ci	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
55662306a36Sopenharmony_ci	struct scmd_priv *priv;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	if (scmd) {
55962306a36Sopenharmony_ci		priv = scsi_cmd_priv(scmd);
56062306a36Sopenharmony_ci		if (!priv->in_lld_scope)
56162306a36Sopenharmony_ci			goto out;
56262306a36Sopenharmony_ci		if (scmd->device && (scsi_target(scmd->device) == starget))
56362306a36Sopenharmony_ci			stgt_priv_data->pend_count++;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ciout:
56762306a36Sopenharmony_ci	return true;
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci/**
57162306a36Sopenharmony_ci * mpi3mr_flush_host_io -  Flush host I/Os
57262306a36Sopenharmony_ci * @mrioc: Adapter instance reference
57362306a36Sopenharmony_ci *
57462306a36Sopenharmony_ci * Flush all of the pending I/Os by calling
57562306a36Sopenharmony_ci * blk_mq_tagset_busy_iter() for each possible tag. This is
57662306a36Sopenharmony_ci * executed post controller reset
57762306a36Sopenharmony_ci *
57862306a36Sopenharmony_ci * Return: Nothing.
57962306a36Sopenharmony_ci */
58062306a36Sopenharmony_civoid mpi3mr_flush_host_io(struct mpi3mr_ioc *mrioc)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	struct Scsi_Host *shost = mrioc->shost;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	mrioc->flush_io_count = 0;
58562306a36Sopenharmony_ci	ioc_info(mrioc, "%s :Flushing Host I/O cmds post reset\n", __func__);
58662306a36Sopenharmony_ci	blk_mq_tagset_busy_iter(&shost->tag_set,
58762306a36Sopenharmony_ci	    mpi3mr_flush_scmd, (void *)mrioc);
58862306a36Sopenharmony_ci	ioc_info(mrioc, "%s :Flushed %d Host I/O cmds\n", __func__,
58962306a36Sopenharmony_ci	    mrioc->flush_io_count);
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci/**
59362306a36Sopenharmony_ci * mpi3mr_flush_cmds_for_unrecovered_controller - Flush all pending cmds
59462306a36Sopenharmony_ci * @mrioc: Adapter instance reference
59562306a36Sopenharmony_ci *
59662306a36Sopenharmony_ci * This function waits for currently running IO poll threads to
59762306a36Sopenharmony_ci * exit and then flushes all host I/Os and any internal pending
59862306a36Sopenharmony_ci * cmds. This is executed after controller is marked as
59962306a36Sopenharmony_ci * unrecoverable.
60062306a36Sopenharmony_ci *
60162306a36Sopenharmony_ci * Return: Nothing.
60262306a36Sopenharmony_ci */
60362306a36Sopenharmony_civoid mpi3mr_flush_cmds_for_unrecovered_controller(struct mpi3mr_ioc *mrioc)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct Scsi_Host *shost = mrioc->shost;
60662306a36Sopenharmony_ci	int i;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	if (!mrioc->unrecoverable)
60962306a36Sopenharmony_ci		return;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	if (mrioc->op_reply_qinfo) {
61262306a36Sopenharmony_ci		for (i = 0; i < mrioc->num_queues; i++) {
61362306a36Sopenharmony_ci			while (atomic_read(&mrioc->op_reply_qinfo[i].in_use))
61462306a36Sopenharmony_ci				udelay(500);
61562306a36Sopenharmony_ci			atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0);
61662306a36Sopenharmony_ci		}
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci	mrioc->flush_io_count = 0;
61962306a36Sopenharmony_ci	blk_mq_tagset_busy_iter(&shost->tag_set,
62062306a36Sopenharmony_ci	    mpi3mr_flush_scmd, (void *)mrioc);
62162306a36Sopenharmony_ci	mpi3mr_flush_delayed_cmd_lists(mrioc);
62262306a36Sopenharmony_ci	mpi3mr_flush_drv_cmds(mrioc);
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci/**
62662306a36Sopenharmony_ci * mpi3mr_alloc_tgtdev - target device allocator
62762306a36Sopenharmony_ci *
62862306a36Sopenharmony_ci * Allocate target device instance and initialize the reference
62962306a36Sopenharmony_ci * count
63062306a36Sopenharmony_ci *
63162306a36Sopenharmony_ci * Return: target device instance.
63262306a36Sopenharmony_ci */
63362306a36Sopenharmony_cistatic struct mpi3mr_tgt_dev *mpi3mr_alloc_tgtdev(void)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	tgtdev = kzalloc(sizeof(*tgtdev), GFP_ATOMIC);
63862306a36Sopenharmony_ci	if (!tgtdev)
63962306a36Sopenharmony_ci		return NULL;
64062306a36Sopenharmony_ci	kref_init(&tgtdev->ref_count);
64162306a36Sopenharmony_ci	return tgtdev;
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci/**
64562306a36Sopenharmony_ci * mpi3mr_tgtdev_add_to_list -Add tgtdevice to the list
64662306a36Sopenharmony_ci * @mrioc: Adapter instance reference
64762306a36Sopenharmony_ci * @tgtdev: Target device
64862306a36Sopenharmony_ci *
64962306a36Sopenharmony_ci * Add the target device to the target device list
65062306a36Sopenharmony_ci *
65162306a36Sopenharmony_ci * Return: Nothing.
65262306a36Sopenharmony_ci */
65362306a36Sopenharmony_cistatic void mpi3mr_tgtdev_add_to_list(struct mpi3mr_ioc *mrioc,
65462306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	unsigned long flags;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
65962306a36Sopenharmony_ci	mpi3mr_tgtdev_get(tgtdev);
66062306a36Sopenharmony_ci	INIT_LIST_HEAD(&tgtdev->list);
66162306a36Sopenharmony_ci	list_add_tail(&tgtdev->list, &mrioc->tgtdev_list);
66262306a36Sopenharmony_ci	tgtdev->state = MPI3MR_DEV_CREATED;
66362306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci/**
66762306a36Sopenharmony_ci * mpi3mr_tgtdev_del_from_list -Delete tgtdevice from the list
66862306a36Sopenharmony_ci * @mrioc: Adapter instance reference
66962306a36Sopenharmony_ci * @tgtdev: Target device
67062306a36Sopenharmony_ci * @must_delete: Must delete the target device from the list irrespective
67162306a36Sopenharmony_ci * of the device state.
67262306a36Sopenharmony_ci *
67362306a36Sopenharmony_ci * Remove the target device from the target device list
67462306a36Sopenharmony_ci *
67562306a36Sopenharmony_ci * Return: Nothing.
67662306a36Sopenharmony_ci */
67762306a36Sopenharmony_cistatic void mpi3mr_tgtdev_del_from_list(struct mpi3mr_ioc *mrioc,
67862306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev, bool must_delete)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	unsigned long flags;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
68362306a36Sopenharmony_ci	if ((tgtdev->state == MPI3MR_DEV_REMOVE_HS_STARTED) || (must_delete == true)) {
68462306a36Sopenharmony_ci		if (!list_empty(&tgtdev->list)) {
68562306a36Sopenharmony_ci			list_del_init(&tgtdev->list);
68662306a36Sopenharmony_ci			tgtdev->state = MPI3MR_DEV_DELETED;
68762306a36Sopenharmony_ci			mpi3mr_tgtdev_put(tgtdev);
68862306a36Sopenharmony_ci		}
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci/**
69462306a36Sopenharmony_ci * __mpi3mr_get_tgtdev_by_handle -Get tgtdev from device handle
69562306a36Sopenharmony_ci * @mrioc: Adapter instance reference
69662306a36Sopenharmony_ci * @handle: Device handle
69762306a36Sopenharmony_ci *
69862306a36Sopenharmony_ci * Accessor to retrieve target device from the device handle.
69962306a36Sopenharmony_ci * Non Lock version
70062306a36Sopenharmony_ci *
70162306a36Sopenharmony_ci * Return: Target device reference.
70262306a36Sopenharmony_ci */
70362306a36Sopenharmony_cistatic struct mpi3mr_tgt_dev  *__mpi3mr_get_tgtdev_by_handle(
70462306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc, u16 handle)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	assert_spin_locked(&mrioc->tgtdev_lock);
70962306a36Sopenharmony_ci	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
71062306a36Sopenharmony_ci		if (tgtdev->dev_handle == handle)
71162306a36Sopenharmony_ci			goto found_tgtdev;
71262306a36Sopenharmony_ci	return NULL;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_cifound_tgtdev:
71562306a36Sopenharmony_ci	mpi3mr_tgtdev_get(tgtdev);
71662306a36Sopenharmony_ci	return tgtdev;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci/**
72062306a36Sopenharmony_ci * mpi3mr_get_tgtdev_by_handle -Get tgtdev from device handle
72162306a36Sopenharmony_ci * @mrioc: Adapter instance reference
72262306a36Sopenharmony_ci * @handle: Device handle
72362306a36Sopenharmony_ci *
72462306a36Sopenharmony_ci * Accessor to retrieve target device from the device handle.
72562306a36Sopenharmony_ci * Lock version
72662306a36Sopenharmony_ci *
72762306a36Sopenharmony_ci * Return: Target device reference.
72862306a36Sopenharmony_ci */
72962306a36Sopenharmony_cistruct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_handle(
73062306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc, u16 handle)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev;
73362306a36Sopenharmony_ci	unsigned long flags;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
73662306a36Sopenharmony_ci	tgtdev = __mpi3mr_get_tgtdev_by_handle(mrioc, handle);
73762306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
73862306a36Sopenharmony_ci	return tgtdev;
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci/**
74262306a36Sopenharmony_ci * __mpi3mr_get_tgtdev_by_perst_id -Get tgtdev from persist ID
74362306a36Sopenharmony_ci * @mrioc: Adapter instance reference
74462306a36Sopenharmony_ci * @persist_id: Persistent ID
74562306a36Sopenharmony_ci *
74662306a36Sopenharmony_ci * Accessor to retrieve target device from the Persistent ID.
74762306a36Sopenharmony_ci * Non Lock version
74862306a36Sopenharmony_ci *
74962306a36Sopenharmony_ci * Return: Target device reference.
75062306a36Sopenharmony_ci */
75162306a36Sopenharmony_cistatic struct mpi3mr_tgt_dev  *__mpi3mr_get_tgtdev_by_perst_id(
75262306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc, u16 persist_id)
75362306a36Sopenharmony_ci{
75462306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	assert_spin_locked(&mrioc->tgtdev_lock);
75762306a36Sopenharmony_ci	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
75862306a36Sopenharmony_ci		if (tgtdev->perst_id == persist_id)
75962306a36Sopenharmony_ci			goto found_tgtdev;
76062306a36Sopenharmony_ci	return NULL;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cifound_tgtdev:
76362306a36Sopenharmony_ci	mpi3mr_tgtdev_get(tgtdev);
76462306a36Sopenharmony_ci	return tgtdev;
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci/**
76862306a36Sopenharmony_ci * mpi3mr_get_tgtdev_by_perst_id -Get tgtdev from persistent ID
76962306a36Sopenharmony_ci * @mrioc: Adapter instance reference
77062306a36Sopenharmony_ci * @persist_id: Persistent ID
77162306a36Sopenharmony_ci *
77262306a36Sopenharmony_ci * Accessor to retrieve target device from the Persistent ID.
77362306a36Sopenharmony_ci * Lock version
77462306a36Sopenharmony_ci *
77562306a36Sopenharmony_ci * Return: Target device reference.
77662306a36Sopenharmony_ci */
77762306a36Sopenharmony_cistatic struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_perst_id(
77862306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc, u16 persist_id)
77962306a36Sopenharmony_ci{
78062306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev;
78162306a36Sopenharmony_ci	unsigned long flags;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
78462306a36Sopenharmony_ci	tgtdev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, persist_id);
78562306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
78662306a36Sopenharmony_ci	return tgtdev;
78762306a36Sopenharmony_ci}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci/**
79062306a36Sopenharmony_ci * __mpi3mr_get_tgtdev_from_tgtpriv -Get tgtdev from tgt private
79162306a36Sopenharmony_ci * @mrioc: Adapter instance reference
79262306a36Sopenharmony_ci * @tgt_priv: Target private data
79362306a36Sopenharmony_ci *
79462306a36Sopenharmony_ci * Accessor to return target device from the target private
79562306a36Sopenharmony_ci * data. Non Lock version
79662306a36Sopenharmony_ci *
79762306a36Sopenharmony_ci * Return: Target device reference.
79862306a36Sopenharmony_ci */
79962306a36Sopenharmony_cistatic struct mpi3mr_tgt_dev  *__mpi3mr_get_tgtdev_from_tgtpriv(
80062306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc, struct mpi3mr_stgt_priv_data *tgt_priv)
80162306a36Sopenharmony_ci{
80262306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	assert_spin_locked(&mrioc->tgtdev_lock);
80562306a36Sopenharmony_ci	tgtdev = tgt_priv->tgt_dev;
80662306a36Sopenharmony_ci	if (tgtdev)
80762306a36Sopenharmony_ci		mpi3mr_tgtdev_get(tgtdev);
80862306a36Sopenharmony_ci	return tgtdev;
80962306a36Sopenharmony_ci}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci/**
81262306a36Sopenharmony_ci * mpi3mr_set_io_divert_for_all_vd_in_tg -set divert for TG VDs
81362306a36Sopenharmony_ci * @mrioc: Adapter instance reference
81462306a36Sopenharmony_ci * @tg: Throttle group information pointer
81562306a36Sopenharmony_ci * @divert_value: 1 or 0
81662306a36Sopenharmony_ci *
81762306a36Sopenharmony_ci * Accessor to set io_divert flag for each device associated
81862306a36Sopenharmony_ci * with the given throttle group with the given value.
81962306a36Sopenharmony_ci *
82062306a36Sopenharmony_ci * Return: None.
82162306a36Sopenharmony_ci */
82262306a36Sopenharmony_cistatic void mpi3mr_set_io_divert_for_all_vd_in_tg(struct mpi3mr_ioc *mrioc,
82362306a36Sopenharmony_ci	struct mpi3mr_throttle_group_info *tg, u8 divert_value)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	unsigned long flags;
82662306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev;
82762306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *tgt_priv;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
83062306a36Sopenharmony_ci	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
83162306a36Sopenharmony_ci		if (tgtdev->starget && tgtdev->starget->hostdata) {
83262306a36Sopenharmony_ci			tgt_priv = tgtdev->starget->hostdata;
83362306a36Sopenharmony_ci			if (tgt_priv->throttle_group == tg)
83462306a36Sopenharmony_ci				tgt_priv->io_divert = divert_value;
83562306a36Sopenharmony_ci		}
83662306a36Sopenharmony_ci	}
83762306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci/**
84162306a36Sopenharmony_ci * mpi3mr_print_device_event_notice - print notice related to post processing of
84262306a36Sopenharmony_ci *					device event after controller reset.
84362306a36Sopenharmony_ci *
84462306a36Sopenharmony_ci * @mrioc: Adapter instance reference
84562306a36Sopenharmony_ci * @device_add: true for device add event and false for device removal event
84662306a36Sopenharmony_ci *
84762306a36Sopenharmony_ci * Return: None.
84862306a36Sopenharmony_ci */
84962306a36Sopenharmony_civoid mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc,
85062306a36Sopenharmony_ci	bool device_add)
85162306a36Sopenharmony_ci{
85262306a36Sopenharmony_ci	ioc_notice(mrioc, "Device %s was in progress before the reset and\n",
85362306a36Sopenharmony_ci	    (device_add ? "addition" : "removal"));
85462306a36Sopenharmony_ci	ioc_notice(mrioc, "completed after reset, verify whether the exposed devices\n");
85562306a36Sopenharmony_ci	ioc_notice(mrioc, "are matched with attached devices for correctness\n");
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci/**
85962306a36Sopenharmony_ci * mpi3mr_remove_tgtdev_from_host - Remove dev from upper layers
86062306a36Sopenharmony_ci * @mrioc: Adapter instance reference
86162306a36Sopenharmony_ci * @tgtdev: Target device structure
86262306a36Sopenharmony_ci *
86362306a36Sopenharmony_ci * Checks whether the device is exposed to upper layers and if it
86462306a36Sopenharmony_ci * is then remove the device from upper layers by calling
86562306a36Sopenharmony_ci * scsi_remove_target().
86662306a36Sopenharmony_ci *
86762306a36Sopenharmony_ci * Return: 0 on success, non zero on failure.
86862306a36Sopenharmony_ci */
86962306a36Sopenharmony_civoid mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc,
87062306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *tgt_priv;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	ioc_info(mrioc, "%s :Removing handle(0x%04x), wwid(0x%016llx)\n",
87562306a36Sopenharmony_ci	    __func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid);
87662306a36Sopenharmony_ci	if (tgtdev->starget && tgtdev->starget->hostdata) {
87762306a36Sopenharmony_ci		tgt_priv = tgtdev->starget->hostdata;
87862306a36Sopenharmony_ci		atomic_set(&tgt_priv->block_io, 0);
87962306a36Sopenharmony_ci		tgt_priv->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
88062306a36Sopenharmony_ci	}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	if (!mrioc->sas_transport_enabled || (tgtdev->dev_type !=
88362306a36Sopenharmony_ci	    MPI3_DEVICE_DEVFORM_SAS_SATA) || tgtdev->non_stl) {
88462306a36Sopenharmony_ci		if (tgtdev->starget) {
88562306a36Sopenharmony_ci			if (mrioc->current_event)
88662306a36Sopenharmony_ci				mrioc->current_event->pending_at_sml = 1;
88762306a36Sopenharmony_ci			scsi_remove_target(&tgtdev->starget->dev);
88862306a36Sopenharmony_ci			tgtdev->host_exposed = 0;
88962306a36Sopenharmony_ci			if (mrioc->current_event) {
89062306a36Sopenharmony_ci				mrioc->current_event->pending_at_sml = 0;
89162306a36Sopenharmony_ci				if (mrioc->current_event->discard) {
89262306a36Sopenharmony_ci					mpi3mr_print_device_event_notice(mrioc,
89362306a36Sopenharmony_ci					    false);
89462306a36Sopenharmony_ci					return;
89562306a36Sopenharmony_ci				}
89662306a36Sopenharmony_ci			}
89762306a36Sopenharmony_ci		}
89862306a36Sopenharmony_ci	} else
89962306a36Sopenharmony_ci		mpi3mr_remove_tgtdev_from_sas_transport(mrioc, tgtdev);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	ioc_info(mrioc, "%s :Removed handle(0x%04x), wwid(0x%016llx)\n",
90262306a36Sopenharmony_ci	    __func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid);
90362306a36Sopenharmony_ci}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci/**
90662306a36Sopenharmony_ci * mpi3mr_report_tgtdev_to_host - Expose device to upper layers
90762306a36Sopenharmony_ci * @mrioc: Adapter instance reference
90862306a36Sopenharmony_ci * @perst_id: Persistent ID of the device
90962306a36Sopenharmony_ci *
91062306a36Sopenharmony_ci * Checks whether the device can be exposed to upper layers and
91162306a36Sopenharmony_ci * if it is not then expose the device to upper layers by
91262306a36Sopenharmony_ci * calling scsi_scan_target().
91362306a36Sopenharmony_ci *
91462306a36Sopenharmony_ci * Return: 0 on success, non zero on failure.
91562306a36Sopenharmony_ci */
91662306a36Sopenharmony_cistatic int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc,
91762306a36Sopenharmony_ci	u16 perst_id)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	int retval = 0;
92062306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	if (mrioc->reset_in_progress)
92362306a36Sopenharmony_ci		return -1;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	tgtdev = mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id);
92662306a36Sopenharmony_ci	if (!tgtdev) {
92762306a36Sopenharmony_ci		retval = -1;
92862306a36Sopenharmony_ci		goto out;
92962306a36Sopenharmony_ci	}
93062306a36Sopenharmony_ci	if (tgtdev->is_hidden || tgtdev->host_exposed) {
93162306a36Sopenharmony_ci		retval = -1;
93262306a36Sopenharmony_ci		goto out;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci	if (!mrioc->sas_transport_enabled || (tgtdev->dev_type !=
93562306a36Sopenharmony_ci	    MPI3_DEVICE_DEVFORM_SAS_SATA) || tgtdev->non_stl){
93662306a36Sopenharmony_ci		tgtdev->host_exposed = 1;
93762306a36Sopenharmony_ci		if (mrioc->current_event)
93862306a36Sopenharmony_ci			mrioc->current_event->pending_at_sml = 1;
93962306a36Sopenharmony_ci		scsi_scan_target(&mrioc->shost->shost_gendev,
94062306a36Sopenharmony_ci		    mrioc->scsi_device_channel, tgtdev->perst_id,
94162306a36Sopenharmony_ci		    SCAN_WILD_CARD, SCSI_SCAN_INITIAL);
94262306a36Sopenharmony_ci		if (!tgtdev->starget)
94362306a36Sopenharmony_ci			tgtdev->host_exposed = 0;
94462306a36Sopenharmony_ci		if (mrioc->current_event) {
94562306a36Sopenharmony_ci			mrioc->current_event->pending_at_sml = 0;
94662306a36Sopenharmony_ci			if (mrioc->current_event->discard) {
94762306a36Sopenharmony_ci				mpi3mr_print_device_event_notice(mrioc, true);
94862306a36Sopenharmony_ci				goto out;
94962306a36Sopenharmony_ci			}
95062306a36Sopenharmony_ci		}
95162306a36Sopenharmony_ci	} else
95262306a36Sopenharmony_ci		mpi3mr_report_tgtdev_to_sas_transport(mrioc, tgtdev);
95362306a36Sopenharmony_ciout:
95462306a36Sopenharmony_ci	if (tgtdev)
95562306a36Sopenharmony_ci		mpi3mr_tgtdev_put(tgtdev);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	return retval;
95862306a36Sopenharmony_ci}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci/**
96162306a36Sopenharmony_ci * mpi3mr_change_queue_depth- Change QD callback handler
96262306a36Sopenharmony_ci * @sdev: SCSI device reference
96362306a36Sopenharmony_ci * @q_depth: Queue depth
96462306a36Sopenharmony_ci *
96562306a36Sopenharmony_ci * Validate and limit QD and call scsi_change_queue_depth.
96662306a36Sopenharmony_ci *
96762306a36Sopenharmony_ci * Return: return value of scsi_change_queue_depth
96862306a36Sopenharmony_ci */
96962306a36Sopenharmony_cistatic int mpi3mr_change_queue_depth(struct scsi_device *sdev,
97062306a36Sopenharmony_ci	int q_depth)
97162306a36Sopenharmony_ci{
97262306a36Sopenharmony_ci	struct scsi_target *starget = scsi_target(sdev);
97362306a36Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
97462306a36Sopenharmony_ci	int retval = 0;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	if (!sdev->tagged_supported)
97762306a36Sopenharmony_ci		q_depth = 1;
97862306a36Sopenharmony_ci	if (q_depth > shost->can_queue)
97962306a36Sopenharmony_ci		q_depth = shost->can_queue;
98062306a36Sopenharmony_ci	else if (!q_depth)
98162306a36Sopenharmony_ci		q_depth = MPI3MR_DEFAULT_SDEV_QD;
98262306a36Sopenharmony_ci	retval = scsi_change_queue_depth(sdev, q_depth);
98362306a36Sopenharmony_ci	sdev->max_queue_depth = sdev->queue_depth;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	return retval;
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci/**
98962306a36Sopenharmony_ci * mpi3mr_update_sdev - Update SCSI device information
99062306a36Sopenharmony_ci * @sdev: SCSI device reference
99162306a36Sopenharmony_ci * @data: target device reference
99262306a36Sopenharmony_ci *
99362306a36Sopenharmony_ci * This is an iterator function called for each SCSI device in a
99462306a36Sopenharmony_ci * target to update the target specific information into each
99562306a36Sopenharmony_ci * SCSI device.
99662306a36Sopenharmony_ci *
99762306a36Sopenharmony_ci * Return: Nothing.
99862306a36Sopenharmony_ci */
99962306a36Sopenharmony_cistatic void
100062306a36Sopenharmony_cimpi3mr_update_sdev(struct scsi_device *sdev, void *data)
100162306a36Sopenharmony_ci{
100262306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	tgtdev = (struct mpi3mr_tgt_dev *)data;
100562306a36Sopenharmony_ci	if (!tgtdev)
100662306a36Sopenharmony_ci		return;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	mpi3mr_change_queue_depth(sdev, tgtdev->q_depth);
100962306a36Sopenharmony_ci	switch (tgtdev->dev_type) {
101062306a36Sopenharmony_ci	case MPI3_DEVICE_DEVFORM_PCIE:
101162306a36Sopenharmony_ci		/*The block layer hw sector size = 512*/
101262306a36Sopenharmony_ci		if ((tgtdev->dev_spec.pcie_inf.dev_info &
101362306a36Sopenharmony_ci		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) ==
101462306a36Sopenharmony_ci		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) {
101562306a36Sopenharmony_ci			blk_queue_max_hw_sectors(sdev->request_queue,
101662306a36Sopenharmony_ci			    tgtdev->dev_spec.pcie_inf.mdts / 512);
101762306a36Sopenharmony_ci			if (tgtdev->dev_spec.pcie_inf.pgsz == 0)
101862306a36Sopenharmony_ci				blk_queue_virt_boundary(sdev->request_queue,
101962306a36Sopenharmony_ci				    ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1));
102062306a36Sopenharmony_ci			else
102162306a36Sopenharmony_ci				blk_queue_virt_boundary(sdev->request_queue,
102262306a36Sopenharmony_ci				    ((1 << tgtdev->dev_spec.pcie_inf.pgsz) - 1));
102362306a36Sopenharmony_ci		}
102462306a36Sopenharmony_ci		break;
102562306a36Sopenharmony_ci	default:
102662306a36Sopenharmony_ci		break;
102762306a36Sopenharmony_ci	}
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci/**
103162306a36Sopenharmony_ci * mpi3mr_rfresh_tgtdevs - Refresh target device exposure
103262306a36Sopenharmony_ci * @mrioc: Adapter instance reference
103362306a36Sopenharmony_ci *
103462306a36Sopenharmony_ci * This is executed post controller reset to identify any
103562306a36Sopenharmony_ci * missing devices during reset and remove from the upper layers
103662306a36Sopenharmony_ci * or expose any newly detected device to the upper layers.
103762306a36Sopenharmony_ci *
103862306a36Sopenharmony_ci * Return: Nothing.
103962306a36Sopenharmony_ci */
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_civoid mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next;
104462306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *tgt_priv;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	dprint_reset(mrioc, "refresh target devices: check for removals\n");
104762306a36Sopenharmony_ci	list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
104862306a36Sopenharmony_ci	    list) {
104962306a36Sopenharmony_ci		if ((tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) &&
105062306a36Sopenharmony_ci		     tgtdev->is_hidden &&
105162306a36Sopenharmony_ci		     tgtdev->host_exposed && tgtdev->starget &&
105262306a36Sopenharmony_ci		     tgtdev->starget->hostdata) {
105362306a36Sopenharmony_ci			tgt_priv = tgtdev->starget->hostdata;
105462306a36Sopenharmony_ci			tgt_priv->dev_removed = 1;
105562306a36Sopenharmony_ci			atomic_set(&tgt_priv->block_io, 0);
105662306a36Sopenharmony_ci		}
105762306a36Sopenharmony_ci	}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
106062306a36Sopenharmony_ci	    list) {
106162306a36Sopenharmony_ci		if (tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) {
106262306a36Sopenharmony_ci			dprint_reset(mrioc, "removing target device with perst_id(%d)\n",
106362306a36Sopenharmony_ci			    tgtdev->perst_id);
106462306a36Sopenharmony_ci			if (tgtdev->host_exposed)
106562306a36Sopenharmony_ci				mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
106662306a36Sopenharmony_ci			mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, true);
106762306a36Sopenharmony_ci			mpi3mr_tgtdev_put(tgtdev);
106862306a36Sopenharmony_ci		} else if (tgtdev->is_hidden & tgtdev->host_exposed) {
106962306a36Sopenharmony_ci			dprint_reset(mrioc, "hiding target device with perst_id(%d)\n",
107062306a36Sopenharmony_ci				     tgtdev->perst_id);
107162306a36Sopenharmony_ci			mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
107262306a36Sopenharmony_ci		}
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	tgtdev = NULL;
107662306a36Sopenharmony_ci	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
107762306a36Sopenharmony_ci		if ((tgtdev->dev_handle != MPI3MR_INVALID_DEV_HANDLE) &&
107862306a36Sopenharmony_ci		    !tgtdev->is_hidden) {
107962306a36Sopenharmony_ci			if (!tgtdev->host_exposed)
108062306a36Sopenharmony_ci				mpi3mr_report_tgtdev_to_host(mrioc,
108162306a36Sopenharmony_ci							     tgtdev->perst_id);
108262306a36Sopenharmony_ci			else if (tgtdev->starget)
108362306a36Sopenharmony_ci				starget_for_each_device(tgtdev->starget,
108462306a36Sopenharmony_ci							(void *)tgtdev, mpi3mr_update_sdev);
108562306a36Sopenharmony_ci	}
108662306a36Sopenharmony_ci	}
108762306a36Sopenharmony_ci}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci/**
109062306a36Sopenharmony_ci * mpi3mr_update_tgtdev - DevStatusChange evt bottomhalf
109162306a36Sopenharmony_ci * @mrioc: Adapter instance reference
109262306a36Sopenharmony_ci * @tgtdev: Target device internal structure
109362306a36Sopenharmony_ci * @dev_pg0: New device page0
109462306a36Sopenharmony_ci * @is_added: Flag to indicate the device is just added
109562306a36Sopenharmony_ci *
109662306a36Sopenharmony_ci * Update the information from the device page0 into the driver
109762306a36Sopenharmony_ci * cached target device structure.
109862306a36Sopenharmony_ci *
109962306a36Sopenharmony_ci * Return: Nothing.
110062306a36Sopenharmony_ci */
110162306a36Sopenharmony_cistatic void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
110262306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev, struct mpi3_device_page0 *dev_pg0,
110362306a36Sopenharmony_ci	bool is_added)
110462306a36Sopenharmony_ci{
110562306a36Sopenharmony_ci	u16 flags = 0;
110662306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
110762306a36Sopenharmony_ci	struct mpi3mr_enclosure_node *enclosure_dev = NULL;
110862306a36Sopenharmony_ci	u8 prot_mask = 0;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	tgtdev->perst_id = le16_to_cpu(dev_pg0->persistent_id);
111162306a36Sopenharmony_ci	tgtdev->dev_handle = le16_to_cpu(dev_pg0->dev_handle);
111262306a36Sopenharmony_ci	tgtdev->dev_type = dev_pg0->device_form;
111362306a36Sopenharmony_ci	tgtdev->io_unit_port = dev_pg0->io_unit_port;
111462306a36Sopenharmony_ci	tgtdev->encl_handle = le16_to_cpu(dev_pg0->enclosure_handle);
111562306a36Sopenharmony_ci	tgtdev->parent_handle = le16_to_cpu(dev_pg0->parent_dev_handle);
111662306a36Sopenharmony_ci	tgtdev->slot = le16_to_cpu(dev_pg0->slot);
111762306a36Sopenharmony_ci	tgtdev->q_depth = le16_to_cpu(dev_pg0->queue_depth);
111862306a36Sopenharmony_ci	tgtdev->wwid = le64_to_cpu(dev_pg0->wwid);
111962306a36Sopenharmony_ci	tgtdev->devpg0_flag = le16_to_cpu(dev_pg0->flags);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	if (tgtdev->encl_handle)
112262306a36Sopenharmony_ci		enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc,
112362306a36Sopenharmony_ci		    tgtdev->encl_handle);
112462306a36Sopenharmony_ci	if (enclosure_dev)
112562306a36Sopenharmony_ci		tgtdev->enclosure_logical_id = le64_to_cpu(
112662306a36Sopenharmony_ci		    enclosure_dev->pg0.enclosure_logical_id);
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	flags = tgtdev->devpg0_flag;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	tgtdev->is_hidden = (flags & MPI3_DEVICE0_FLAGS_HIDDEN);
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	if (is_added == true)
113362306a36Sopenharmony_ci		tgtdev->io_throttle_enabled =
113462306a36Sopenharmony_ci		    (flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	switch (flags & MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_MASK) {
113762306a36Sopenharmony_ci	case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_256_LB:
113862306a36Sopenharmony_ci		tgtdev->wslen = MPI3MR_WRITE_SAME_MAX_LEN_256_BLKS;
113962306a36Sopenharmony_ci		break;
114062306a36Sopenharmony_ci	case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_2048_LB:
114162306a36Sopenharmony_ci		tgtdev->wslen = MPI3MR_WRITE_SAME_MAX_LEN_2048_BLKS;
114262306a36Sopenharmony_ci		break;
114362306a36Sopenharmony_ci	case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_NO_LIMIT:
114462306a36Sopenharmony_ci	default:
114562306a36Sopenharmony_ci		tgtdev->wslen = 0;
114662306a36Sopenharmony_ci		break;
114762306a36Sopenharmony_ci	}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	if (tgtdev->starget && tgtdev->starget->hostdata) {
115062306a36Sopenharmony_ci		scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
115162306a36Sopenharmony_ci		    tgtdev->starget->hostdata;
115262306a36Sopenharmony_ci		scsi_tgt_priv_data->perst_id = tgtdev->perst_id;
115362306a36Sopenharmony_ci		scsi_tgt_priv_data->dev_handle = tgtdev->dev_handle;
115462306a36Sopenharmony_ci		scsi_tgt_priv_data->dev_type = tgtdev->dev_type;
115562306a36Sopenharmony_ci		scsi_tgt_priv_data->io_throttle_enabled =
115662306a36Sopenharmony_ci		    tgtdev->io_throttle_enabled;
115762306a36Sopenharmony_ci		if (is_added == true)
115862306a36Sopenharmony_ci			atomic_set(&scsi_tgt_priv_data->block_io, 0);
115962306a36Sopenharmony_ci		scsi_tgt_priv_data->wslen = tgtdev->wslen;
116062306a36Sopenharmony_ci	}
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	switch (dev_pg0->access_status) {
116362306a36Sopenharmony_ci	case MPI3_DEVICE0_ASTATUS_NO_ERRORS:
116462306a36Sopenharmony_ci	case MPI3_DEVICE0_ASTATUS_PREPARE:
116562306a36Sopenharmony_ci	case MPI3_DEVICE0_ASTATUS_NEEDS_INITIALIZATION:
116662306a36Sopenharmony_ci	case MPI3_DEVICE0_ASTATUS_DEVICE_MISSING_DELAY:
116762306a36Sopenharmony_ci		break;
116862306a36Sopenharmony_ci	default:
116962306a36Sopenharmony_ci		tgtdev->is_hidden = 1;
117062306a36Sopenharmony_ci		break;
117162306a36Sopenharmony_ci	}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	switch (tgtdev->dev_type) {
117462306a36Sopenharmony_ci	case MPI3_DEVICE_DEVFORM_SAS_SATA:
117562306a36Sopenharmony_ci	{
117662306a36Sopenharmony_ci		struct mpi3_device0_sas_sata_format *sasinf =
117762306a36Sopenharmony_ci		    &dev_pg0->device_specific.sas_sata_format;
117862306a36Sopenharmony_ci		u16 dev_info = le16_to_cpu(sasinf->device_info);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci		tgtdev->dev_spec.sas_sata_inf.dev_info = dev_info;
118162306a36Sopenharmony_ci		tgtdev->dev_spec.sas_sata_inf.sas_address =
118262306a36Sopenharmony_ci		    le64_to_cpu(sasinf->sas_address);
118362306a36Sopenharmony_ci		tgtdev->dev_spec.sas_sata_inf.phy_id = sasinf->phy_num;
118462306a36Sopenharmony_ci		tgtdev->dev_spec.sas_sata_inf.attached_phy_id =
118562306a36Sopenharmony_ci		    sasinf->attached_phy_identifier;
118662306a36Sopenharmony_ci		if ((dev_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) !=
118762306a36Sopenharmony_ci		    MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE)
118862306a36Sopenharmony_ci			tgtdev->is_hidden = 1;
118962306a36Sopenharmony_ci		else if (!(dev_info & (MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET |
119062306a36Sopenharmony_ci		    MPI3_SAS_DEVICE_INFO_SSP_TARGET)))
119162306a36Sopenharmony_ci			tgtdev->is_hidden = 1;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci		if (((tgtdev->devpg0_flag &
119462306a36Sopenharmony_ci		    MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)
119562306a36Sopenharmony_ci		    && (tgtdev->devpg0_flag &
119662306a36Sopenharmony_ci		    MPI3_DEVICE0_FLAGS_ATT_METHOD_VIRTUAL)) ||
119762306a36Sopenharmony_ci		    (tgtdev->parent_handle == 0xFFFF))
119862306a36Sopenharmony_ci			tgtdev->non_stl = 1;
119962306a36Sopenharmony_ci		if (tgtdev->dev_spec.sas_sata_inf.hba_port)
120062306a36Sopenharmony_ci			tgtdev->dev_spec.sas_sata_inf.hba_port->port_id =
120162306a36Sopenharmony_ci			    dev_pg0->io_unit_port;
120262306a36Sopenharmony_ci		break;
120362306a36Sopenharmony_ci	}
120462306a36Sopenharmony_ci	case MPI3_DEVICE_DEVFORM_PCIE:
120562306a36Sopenharmony_ci	{
120662306a36Sopenharmony_ci		struct mpi3_device0_pcie_format *pcieinf =
120762306a36Sopenharmony_ci		    &dev_pg0->device_specific.pcie_format;
120862306a36Sopenharmony_ci		u16 dev_info = le16_to_cpu(pcieinf->device_info);
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci		tgtdev->dev_spec.pcie_inf.dev_info = dev_info;
121162306a36Sopenharmony_ci		tgtdev->dev_spec.pcie_inf.capb =
121262306a36Sopenharmony_ci		    le32_to_cpu(pcieinf->capabilities);
121362306a36Sopenharmony_ci		tgtdev->dev_spec.pcie_inf.mdts = MPI3MR_DEFAULT_MDTS;
121462306a36Sopenharmony_ci		/* 2^12 = 4096 */
121562306a36Sopenharmony_ci		tgtdev->dev_spec.pcie_inf.pgsz = 12;
121662306a36Sopenharmony_ci		if (dev_pg0->access_status == MPI3_DEVICE0_ASTATUS_NO_ERRORS) {
121762306a36Sopenharmony_ci			tgtdev->dev_spec.pcie_inf.mdts =
121862306a36Sopenharmony_ci			    le32_to_cpu(pcieinf->maximum_data_transfer_size);
121962306a36Sopenharmony_ci			tgtdev->dev_spec.pcie_inf.pgsz = pcieinf->page_size;
122062306a36Sopenharmony_ci			tgtdev->dev_spec.pcie_inf.reset_to =
122162306a36Sopenharmony_ci			    max_t(u8, pcieinf->controller_reset_to,
122262306a36Sopenharmony_ci			     MPI3MR_INTADMCMD_TIMEOUT);
122362306a36Sopenharmony_ci			tgtdev->dev_spec.pcie_inf.abort_to =
122462306a36Sopenharmony_ci			    max_t(u8, pcieinf->nvme_abort_to,
122562306a36Sopenharmony_ci			    MPI3MR_INTADMCMD_TIMEOUT);
122662306a36Sopenharmony_ci		}
122762306a36Sopenharmony_ci		if (tgtdev->dev_spec.pcie_inf.mdts > (1024 * 1024))
122862306a36Sopenharmony_ci			tgtdev->dev_spec.pcie_inf.mdts = (1024 * 1024);
122962306a36Sopenharmony_ci		if (((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) !=
123062306a36Sopenharmony_ci		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) &&
123162306a36Sopenharmony_ci		    ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) !=
123262306a36Sopenharmony_ci		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE))
123362306a36Sopenharmony_ci			tgtdev->is_hidden = 1;
123462306a36Sopenharmony_ci		tgtdev->non_stl = 1;
123562306a36Sopenharmony_ci		if (!mrioc->shost)
123662306a36Sopenharmony_ci			break;
123762306a36Sopenharmony_ci		prot_mask = scsi_host_get_prot(mrioc->shost);
123862306a36Sopenharmony_ci		if (prot_mask & SHOST_DIX_TYPE0_PROTECTION) {
123962306a36Sopenharmony_ci			scsi_host_set_prot(mrioc->shost, prot_mask & 0x77);
124062306a36Sopenharmony_ci			ioc_info(mrioc,
124162306a36Sopenharmony_ci			    "%s : Disabling DIX0 prot capability\n", __func__);
124262306a36Sopenharmony_ci			ioc_info(mrioc,
124362306a36Sopenharmony_ci			    "because HBA does not support DIX0 operation on NVME drives\n");
124462306a36Sopenharmony_ci		}
124562306a36Sopenharmony_ci		break;
124662306a36Sopenharmony_ci	}
124762306a36Sopenharmony_ci	case MPI3_DEVICE_DEVFORM_VD:
124862306a36Sopenharmony_ci	{
124962306a36Sopenharmony_ci		struct mpi3_device0_vd_format *vdinf =
125062306a36Sopenharmony_ci		    &dev_pg0->device_specific.vd_format;
125162306a36Sopenharmony_ci		struct mpi3mr_throttle_group_info *tg = NULL;
125262306a36Sopenharmony_ci		u16 vdinf_io_throttle_group =
125362306a36Sopenharmony_ci		    le16_to_cpu(vdinf->io_throttle_group);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci		tgtdev->dev_spec.vd_inf.state = vdinf->vd_state;
125662306a36Sopenharmony_ci		if (vdinf->vd_state == MPI3_DEVICE0_VD_STATE_OFFLINE)
125762306a36Sopenharmony_ci			tgtdev->is_hidden = 1;
125862306a36Sopenharmony_ci		tgtdev->non_stl = 1;
125962306a36Sopenharmony_ci		tgtdev->dev_spec.vd_inf.tg_id = vdinf_io_throttle_group;
126062306a36Sopenharmony_ci		tgtdev->dev_spec.vd_inf.tg_high =
126162306a36Sopenharmony_ci		    le16_to_cpu(vdinf->io_throttle_group_high) * 2048;
126262306a36Sopenharmony_ci		tgtdev->dev_spec.vd_inf.tg_low =
126362306a36Sopenharmony_ci		    le16_to_cpu(vdinf->io_throttle_group_low) * 2048;
126462306a36Sopenharmony_ci		if (vdinf_io_throttle_group < mrioc->num_io_throttle_group) {
126562306a36Sopenharmony_ci			tg = mrioc->throttle_groups + vdinf_io_throttle_group;
126662306a36Sopenharmony_ci			tg->id = vdinf_io_throttle_group;
126762306a36Sopenharmony_ci			tg->high = tgtdev->dev_spec.vd_inf.tg_high;
126862306a36Sopenharmony_ci			tg->low = tgtdev->dev_spec.vd_inf.tg_low;
126962306a36Sopenharmony_ci			tg->qd_reduction =
127062306a36Sopenharmony_ci			    tgtdev->dev_spec.vd_inf.tg_qd_reduction;
127162306a36Sopenharmony_ci			if (is_added == true)
127262306a36Sopenharmony_ci				tg->fw_qd = tgtdev->q_depth;
127362306a36Sopenharmony_ci			tg->modified_qd = tgtdev->q_depth;
127462306a36Sopenharmony_ci		}
127562306a36Sopenharmony_ci		tgtdev->dev_spec.vd_inf.tg = tg;
127662306a36Sopenharmony_ci		if (scsi_tgt_priv_data)
127762306a36Sopenharmony_ci			scsi_tgt_priv_data->throttle_group = tg;
127862306a36Sopenharmony_ci		break;
127962306a36Sopenharmony_ci	}
128062306a36Sopenharmony_ci	default:
128162306a36Sopenharmony_ci		break;
128262306a36Sopenharmony_ci	}
128362306a36Sopenharmony_ci}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci/**
128662306a36Sopenharmony_ci * mpi3mr_devstatuschg_evt_bh - DevStatusChange evt bottomhalf
128762306a36Sopenharmony_ci * @mrioc: Adapter instance reference
128862306a36Sopenharmony_ci * @fwevt: Firmware event information.
128962306a36Sopenharmony_ci *
129062306a36Sopenharmony_ci * Process Device status Change event and based on device's new
129162306a36Sopenharmony_ci * information, either expose the device to the upper layers, or
129262306a36Sopenharmony_ci * remove the device from upper layers.
129362306a36Sopenharmony_ci *
129462306a36Sopenharmony_ci * Return: Nothing.
129562306a36Sopenharmony_ci */
129662306a36Sopenharmony_cistatic void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_ioc *mrioc,
129762306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt)
129862306a36Sopenharmony_ci{
129962306a36Sopenharmony_ci	u16 dev_handle = 0;
130062306a36Sopenharmony_ci	u8 uhide = 0, delete = 0, cleanup = 0;
130162306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev = NULL;
130262306a36Sopenharmony_ci	struct mpi3_event_data_device_status_change *evtdata =
130362306a36Sopenharmony_ci	    (struct mpi3_event_data_device_status_change *)fwevt->event_data;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	dev_handle = le16_to_cpu(evtdata->dev_handle);
130662306a36Sopenharmony_ci	ioc_info(mrioc,
130762306a36Sopenharmony_ci	    "%s :device status change: handle(0x%04x): reason code(0x%x)\n",
130862306a36Sopenharmony_ci	    __func__, dev_handle, evtdata->reason_code);
130962306a36Sopenharmony_ci	switch (evtdata->reason_code) {
131062306a36Sopenharmony_ci	case MPI3_EVENT_DEV_STAT_RC_HIDDEN:
131162306a36Sopenharmony_ci		delete = 1;
131262306a36Sopenharmony_ci		break;
131362306a36Sopenharmony_ci	case MPI3_EVENT_DEV_STAT_RC_NOT_HIDDEN:
131462306a36Sopenharmony_ci		uhide = 1;
131562306a36Sopenharmony_ci		break;
131662306a36Sopenharmony_ci	case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING:
131762306a36Sopenharmony_ci		delete = 1;
131862306a36Sopenharmony_ci		cleanup = 1;
131962306a36Sopenharmony_ci		break;
132062306a36Sopenharmony_ci	default:
132162306a36Sopenharmony_ci		ioc_info(mrioc, "%s :Unhandled reason code(0x%x)\n", __func__,
132262306a36Sopenharmony_ci		    evtdata->reason_code);
132362306a36Sopenharmony_ci		break;
132462306a36Sopenharmony_ci	}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
132762306a36Sopenharmony_ci	if (!tgtdev)
132862306a36Sopenharmony_ci		goto out;
132962306a36Sopenharmony_ci	if (uhide) {
133062306a36Sopenharmony_ci		tgtdev->is_hidden = 0;
133162306a36Sopenharmony_ci		if (!tgtdev->host_exposed)
133262306a36Sopenharmony_ci			mpi3mr_report_tgtdev_to_host(mrioc, tgtdev->perst_id);
133362306a36Sopenharmony_ci	}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	if (delete)
133662306a36Sopenharmony_ci		mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	if (cleanup) {
133962306a36Sopenharmony_ci		mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, false);
134062306a36Sopenharmony_ci		mpi3mr_tgtdev_put(tgtdev);
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ciout:
134462306a36Sopenharmony_ci	if (tgtdev)
134562306a36Sopenharmony_ci		mpi3mr_tgtdev_put(tgtdev);
134662306a36Sopenharmony_ci}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci/**
134962306a36Sopenharmony_ci * mpi3mr_devinfochg_evt_bh - DeviceInfoChange evt bottomhalf
135062306a36Sopenharmony_ci * @mrioc: Adapter instance reference
135162306a36Sopenharmony_ci * @dev_pg0: New device page0
135262306a36Sopenharmony_ci *
135362306a36Sopenharmony_ci * Process Device Info Change event and based on device's new
135462306a36Sopenharmony_ci * information, either expose the device to the upper layers, or
135562306a36Sopenharmony_ci * remove the device from upper layers or update the details of
135662306a36Sopenharmony_ci * the device.
135762306a36Sopenharmony_ci *
135862306a36Sopenharmony_ci * Return: Nothing.
135962306a36Sopenharmony_ci */
136062306a36Sopenharmony_cistatic void mpi3mr_devinfochg_evt_bh(struct mpi3mr_ioc *mrioc,
136162306a36Sopenharmony_ci	struct mpi3_device_page0 *dev_pg0)
136262306a36Sopenharmony_ci{
136362306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev = NULL;
136462306a36Sopenharmony_ci	u16 dev_handle = 0, perst_id = 0;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	perst_id = le16_to_cpu(dev_pg0->persistent_id);
136762306a36Sopenharmony_ci	dev_handle = le16_to_cpu(dev_pg0->dev_handle);
136862306a36Sopenharmony_ci	ioc_info(mrioc,
136962306a36Sopenharmony_ci	    "%s :Device info change: handle(0x%04x): persist_id(0x%x)\n",
137062306a36Sopenharmony_ci	    __func__, dev_handle, perst_id);
137162306a36Sopenharmony_ci	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
137262306a36Sopenharmony_ci	if (!tgtdev)
137362306a36Sopenharmony_ci		goto out;
137462306a36Sopenharmony_ci	mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, false);
137562306a36Sopenharmony_ci	if (!tgtdev->is_hidden && !tgtdev->host_exposed)
137662306a36Sopenharmony_ci		mpi3mr_report_tgtdev_to_host(mrioc, perst_id);
137762306a36Sopenharmony_ci	if (tgtdev->is_hidden && tgtdev->host_exposed)
137862306a36Sopenharmony_ci		mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
137962306a36Sopenharmony_ci	if (!tgtdev->is_hidden && tgtdev->host_exposed && tgtdev->starget)
138062306a36Sopenharmony_ci		starget_for_each_device(tgtdev->starget, (void *)tgtdev,
138162306a36Sopenharmony_ci		    mpi3mr_update_sdev);
138262306a36Sopenharmony_ciout:
138362306a36Sopenharmony_ci	if (tgtdev)
138462306a36Sopenharmony_ci		mpi3mr_tgtdev_put(tgtdev);
138562306a36Sopenharmony_ci}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci/**
138862306a36Sopenharmony_ci * mpi3mr_free_enclosure_list - release enclosures
138962306a36Sopenharmony_ci * @mrioc: Adapter instance reference
139062306a36Sopenharmony_ci *
139162306a36Sopenharmony_ci * Free memory allocated during encloure add.
139262306a36Sopenharmony_ci *
139362306a36Sopenharmony_ci * Return nothing.
139462306a36Sopenharmony_ci */
139562306a36Sopenharmony_civoid mpi3mr_free_enclosure_list(struct mpi3mr_ioc *mrioc)
139662306a36Sopenharmony_ci{
139762306a36Sopenharmony_ci	struct mpi3mr_enclosure_node *enclosure_dev, *enclosure_dev_next;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	list_for_each_entry_safe(enclosure_dev,
140062306a36Sopenharmony_ci	    enclosure_dev_next, &mrioc->enclosure_list, list) {
140162306a36Sopenharmony_ci		list_del(&enclosure_dev->list);
140262306a36Sopenharmony_ci		kfree(enclosure_dev);
140362306a36Sopenharmony_ci	}
140462306a36Sopenharmony_ci}
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci/**
140762306a36Sopenharmony_ci * mpi3mr_enclosure_find_by_handle - enclosure search by handle
140862306a36Sopenharmony_ci * @mrioc: Adapter instance reference
140962306a36Sopenharmony_ci * @handle: Firmware device handle of the enclosure
141062306a36Sopenharmony_ci *
141162306a36Sopenharmony_ci * This searches for enclosure device based on handle, then returns the
141262306a36Sopenharmony_ci * enclosure object.
141362306a36Sopenharmony_ci *
141462306a36Sopenharmony_ci * Return: Enclosure object reference or NULL
141562306a36Sopenharmony_ci */
141662306a36Sopenharmony_cistruct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle(
141762306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc, u16 handle)
141862306a36Sopenharmony_ci{
141962306a36Sopenharmony_ci	struct mpi3mr_enclosure_node *enclosure_dev, *r = NULL;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	list_for_each_entry(enclosure_dev, &mrioc->enclosure_list, list) {
142262306a36Sopenharmony_ci		if (le16_to_cpu(enclosure_dev->pg0.enclosure_handle) != handle)
142362306a36Sopenharmony_ci			continue;
142462306a36Sopenharmony_ci		r = enclosure_dev;
142562306a36Sopenharmony_ci		goto out;
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ciout:
142862306a36Sopenharmony_ci	return r;
142962306a36Sopenharmony_ci}
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci/**
143262306a36Sopenharmony_ci * mpi3mr_encldev_add_chg_evt_debug - debug for enclosure event
143362306a36Sopenharmony_ci * @mrioc: Adapter instance reference
143462306a36Sopenharmony_ci * @encl_pg0: Enclosure page 0.
143562306a36Sopenharmony_ci * @is_added: Added event or not
143662306a36Sopenharmony_ci *
143762306a36Sopenharmony_ci * Return nothing.
143862306a36Sopenharmony_ci */
143962306a36Sopenharmony_cistatic void mpi3mr_encldev_add_chg_evt_debug(struct mpi3mr_ioc *mrioc,
144062306a36Sopenharmony_ci	struct mpi3_enclosure_page0 *encl_pg0, u8 is_added)
144162306a36Sopenharmony_ci{
144262306a36Sopenharmony_ci	char *reason_str = NULL;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	if (!(mrioc->logging_level & MPI3_DEBUG_EVENT_WORK_TASK))
144562306a36Sopenharmony_ci		return;
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	if (is_added)
144862306a36Sopenharmony_ci		reason_str = "enclosure added";
144962306a36Sopenharmony_ci	else
145062306a36Sopenharmony_ci		reason_str = "enclosure dev status changed";
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	ioc_info(mrioc,
145362306a36Sopenharmony_ci	    "%s: handle(0x%04x), enclosure logical id(0x%016llx)\n",
145462306a36Sopenharmony_ci	    reason_str, le16_to_cpu(encl_pg0->enclosure_handle),
145562306a36Sopenharmony_ci	    (unsigned long long)le64_to_cpu(encl_pg0->enclosure_logical_id));
145662306a36Sopenharmony_ci	ioc_info(mrioc,
145762306a36Sopenharmony_ci	    "number of slots(%d), port(%d), flags(0x%04x), present(%d)\n",
145862306a36Sopenharmony_ci	    le16_to_cpu(encl_pg0->num_slots), encl_pg0->io_unit_port,
145962306a36Sopenharmony_ci	    le16_to_cpu(encl_pg0->flags),
146062306a36Sopenharmony_ci	    ((le16_to_cpu(encl_pg0->flags) &
146162306a36Sopenharmony_ci	      MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4));
146262306a36Sopenharmony_ci}
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci/**
146562306a36Sopenharmony_ci * mpi3mr_encldev_add_chg_evt_bh - Enclosure evt bottomhalf
146662306a36Sopenharmony_ci * @mrioc: Adapter instance reference
146762306a36Sopenharmony_ci * @fwevt: Firmware event reference
146862306a36Sopenharmony_ci *
146962306a36Sopenharmony_ci * Prints information about the Enclosure device status or
147062306a36Sopenharmony_ci * Enclosure add events if logging is enabled and add or remove
147162306a36Sopenharmony_ci * the enclosure from the controller's internal list of
147262306a36Sopenharmony_ci * enclosures.
147362306a36Sopenharmony_ci *
147462306a36Sopenharmony_ci * Return: Nothing.
147562306a36Sopenharmony_ci */
147662306a36Sopenharmony_cistatic void mpi3mr_encldev_add_chg_evt_bh(struct mpi3mr_ioc *mrioc,
147762306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt)
147862306a36Sopenharmony_ci{
147962306a36Sopenharmony_ci	struct mpi3mr_enclosure_node *enclosure_dev = NULL;
148062306a36Sopenharmony_ci	struct mpi3_enclosure_page0 *encl_pg0;
148162306a36Sopenharmony_ci	u16 encl_handle;
148262306a36Sopenharmony_ci	u8 added, present;
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	encl_pg0 = (struct mpi3_enclosure_page0 *) fwevt->event_data;
148562306a36Sopenharmony_ci	added = (fwevt->event_id == MPI3_EVENT_ENCL_DEVICE_ADDED) ? 1 : 0;
148662306a36Sopenharmony_ci	mpi3mr_encldev_add_chg_evt_debug(mrioc, encl_pg0, added);
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	encl_handle = le16_to_cpu(encl_pg0->enclosure_handle);
149062306a36Sopenharmony_ci	present = ((le16_to_cpu(encl_pg0->flags) &
149162306a36Sopenharmony_ci	      MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4);
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	if (encl_handle)
149462306a36Sopenharmony_ci		enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc,
149562306a36Sopenharmony_ci		    encl_handle);
149662306a36Sopenharmony_ci	if (!enclosure_dev && present) {
149762306a36Sopenharmony_ci		enclosure_dev =
149862306a36Sopenharmony_ci			kzalloc(sizeof(struct mpi3mr_enclosure_node),
149962306a36Sopenharmony_ci			    GFP_KERNEL);
150062306a36Sopenharmony_ci		if (!enclosure_dev)
150162306a36Sopenharmony_ci			return;
150262306a36Sopenharmony_ci		list_add_tail(&enclosure_dev->list,
150362306a36Sopenharmony_ci		    &mrioc->enclosure_list);
150462306a36Sopenharmony_ci	}
150562306a36Sopenharmony_ci	if (enclosure_dev) {
150662306a36Sopenharmony_ci		if (!present) {
150762306a36Sopenharmony_ci			list_del(&enclosure_dev->list);
150862306a36Sopenharmony_ci			kfree(enclosure_dev);
150962306a36Sopenharmony_ci		} else
151062306a36Sopenharmony_ci			memcpy(&enclosure_dev->pg0, encl_pg0,
151162306a36Sopenharmony_ci			    sizeof(enclosure_dev->pg0));
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	}
151462306a36Sopenharmony_ci}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci/**
151762306a36Sopenharmony_ci * mpi3mr_sastopochg_evt_debug - SASTopoChange details
151862306a36Sopenharmony_ci * @mrioc: Adapter instance reference
151962306a36Sopenharmony_ci * @event_data: SAS topology change list event data
152062306a36Sopenharmony_ci *
152162306a36Sopenharmony_ci * Prints information about the SAS topology change event.
152262306a36Sopenharmony_ci *
152362306a36Sopenharmony_ci * Return: Nothing.
152462306a36Sopenharmony_ci */
152562306a36Sopenharmony_cistatic void
152662306a36Sopenharmony_cimpi3mr_sastopochg_evt_debug(struct mpi3mr_ioc *mrioc,
152762306a36Sopenharmony_ci	struct mpi3_event_data_sas_topology_change_list *event_data)
152862306a36Sopenharmony_ci{
152962306a36Sopenharmony_ci	int i;
153062306a36Sopenharmony_ci	u16 handle;
153162306a36Sopenharmony_ci	u8 reason_code, phy_number;
153262306a36Sopenharmony_ci	char *status_str = NULL;
153362306a36Sopenharmony_ci	u8 link_rate, prev_link_rate;
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	switch (event_data->exp_status) {
153662306a36Sopenharmony_ci	case MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
153762306a36Sopenharmony_ci		status_str = "remove";
153862306a36Sopenharmony_ci		break;
153962306a36Sopenharmony_ci	case MPI3_EVENT_SAS_TOPO_ES_RESPONDING:
154062306a36Sopenharmony_ci		status_str =  "responding";
154162306a36Sopenharmony_ci		break;
154262306a36Sopenharmony_ci	case MPI3_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
154362306a36Sopenharmony_ci		status_str = "remove delay";
154462306a36Sopenharmony_ci		break;
154562306a36Sopenharmony_ci	case MPI3_EVENT_SAS_TOPO_ES_NO_EXPANDER:
154662306a36Sopenharmony_ci		status_str = "direct attached";
154762306a36Sopenharmony_ci		break;
154862306a36Sopenharmony_ci	default:
154962306a36Sopenharmony_ci		status_str = "unknown status";
155062306a36Sopenharmony_ci		break;
155162306a36Sopenharmony_ci	}
155262306a36Sopenharmony_ci	ioc_info(mrioc, "%s :sas topology change: (%s)\n",
155362306a36Sopenharmony_ci	    __func__, status_str);
155462306a36Sopenharmony_ci	ioc_info(mrioc,
155562306a36Sopenharmony_ci	    "%s :\texpander_handle(0x%04x), port(%d), enclosure_handle(0x%04x) start_phy(%02d), num_entries(%d)\n",
155662306a36Sopenharmony_ci	    __func__, le16_to_cpu(event_data->expander_dev_handle),
155762306a36Sopenharmony_ci	    event_data->io_unit_port,
155862306a36Sopenharmony_ci	    le16_to_cpu(event_data->enclosure_handle),
155962306a36Sopenharmony_ci	    event_data->start_phy_num, event_data->num_entries);
156062306a36Sopenharmony_ci	for (i = 0; i < event_data->num_entries; i++) {
156162306a36Sopenharmony_ci		handle = le16_to_cpu(event_data->phy_entry[i].attached_dev_handle);
156262306a36Sopenharmony_ci		if (!handle)
156362306a36Sopenharmony_ci			continue;
156462306a36Sopenharmony_ci		phy_number = event_data->start_phy_num + i;
156562306a36Sopenharmony_ci		reason_code = event_data->phy_entry[i].status &
156662306a36Sopenharmony_ci		    MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
156762306a36Sopenharmony_ci		switch (reason_code) {
156862306a36Sopenharmony_ci		case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
156962306a36Sopenharmony_ci			status_str = "target remove";
157062306a36Sopenharmony_ci			break;
157162306a36Sopenharmony_ci		case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING:
157262306a36Sopenharmony_ci			status_str = "delay target remove";
157362306a36Sopenharmony_ci			break;
157462306a36Sopenharmony_ci		case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
157562306a36Sopenharmony_ci			status_str = "link status change";
157662306a36Sopenharmony_ci			break;
157762306a36Sopenharmony_ci		case MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE:
157862306a36Sopenharmony_ci			status_str = "link status no change";
157962306a36Sopenharmony_ci			break;
158062306a36Sopenharmony_ci		case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING:
158162306a36Sopenharmony_ci			status_str = "target responding";
158262306a36Sopenharmony_ci			break;
158362306a36Sopenharmony_ci		default:
158462306a36Sopenharmony_ci			status_str = "unknown";
158562306a36Sopenharmony_ci			break;
158662306a36Sopenharmony_ci		}
158762306a36Sopenharmony_ci		link_rate = event_data->phy_entry[i].link_rate >> 4;
158862306a36Sopenharmony_ci		prev_link_rate = event_data->phy_entry[i].link_rate & 0xF;
158962306a36Sopenharmony_ci		ioc_info(mrioc,
159062306a36Sopenharmony_ci		    "%s :\tphy(%02d), attached_handle(0x%04x): %s: link rate: new(0x%02x), old(0x%02x)\n",
159162306a36Sopenharmony_ci		    __func__, phy_number, handle, status_str, link_rate,
159262306a36Sopenharmony_ci		    prev_link_rate);
159362306a36Sopenharmony_ci	}
159462306a36Sopenharmony_ci}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci/**
159762306a36Sopenharmony_ci * mpi3mr_sastopochg_evt_bh - SASTopologyChange evt bottomhalf
159862306a36Sopenharmony_ci * @mrioc: Adapter instance reference
159962306a36Sopenharmony_ci * @fwevt: Firmware event reference
160062306a36Sopenharmony_ci *
160162306a36Sopenharmony_ci * Prints information about the SAS topology change event and
160262306a36Sopenharmony_ci * for "not responding" event code, removes the device from the
160362306a36Sopenharmony_ci * upper layers.
160462306a36Sopenharmony_ci *
160562306a36Sopenharmony_ci * Return: Nothing.
160662306a36Sopenharmony_ci */
160762306a36Sopenharmony_cistatic void mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc *mrioc,
160862306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt)
160962306a36Sopenharmony_ci{
161062306a36Sopenharmony_ci	struct mpi3_event_data_sas_topology_change_list *event_data =
161162306a36Sopenharmony_ci	    (struct mpi3_event_data_sas_topology_change_list *)fwevt->event_data;
161262306a36Sopenharmony_ci	int i;
161362306a36Sopenharmony_ci	u16 handle;
161462306a36Sopenharmony_ci	u8 reason_code;
161562306a36Sopenharmony_ci	u64 exp_sas_address = 0, parent_sas_address = 0;
161662306a36Sopenharmony_ci	struct mpi3mr_hba_port *hba_port = NULL;
161762306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev = NULL;
161862306a36Sopenharmony_ci	struct mpi3mr_sas_node *sas_expander = NULL;
161962306a36Sopenharmony_ci	unsigned long flags;
162062306a36Sopenharmony_ci	u8 link_rate, prev_link_rate, parent_phy_number;
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	mpi3mr_sastopochg_evt_debug(mrioc, event_data);
162362306a36Sopenharmony_ci	if (mrioc->sas_transport_enabled) {
162462306a36Sopenharmony_ci		hba_port = mpi3mr_get_hba_port_by_id(mrioc,
162562306a36Sopenharmony_ci		    event_data->io_unit_port);
162662306a36Sopenharmony_ci		if (le16_to_cpu(event_data->expander_dev_handle)) {
162762306a36Sopenharmony_ci			spin_lock_irqsave(&mrioc->sas_node_lock, flags);
162862306a36Sopenharmony_ci			sas_expander = __mpi3mr_expander_find_by_handle(mrioc,
162962306a36Sopenharmony_ci			    le16_to_cpu(event_data->expander_dev_handle));
163062306a36Sopenharmony_ci			if (sas_expander) {
163162306a36Sopenharmony_ci				exp_sas_address = sas_expander->sas_address;
163262306a36Sopenharmony_ci				hba_port = sas_expander->hba_port;
163362306a36Sopenharmony_ci			}
163462306a36Sopenharmony_ci			spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
163562306a36Sopenharmony_ci			parent_sas_address = exp_sas_address;
163662306a36Sopenharmony_ci		} else
163762306a36Sopenharmony_ci			parent_sas_address = mrioc->sas_hba.sas_address;
163862306a36Sopenharmony_ci	}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	for (i = 0; i < event_data->num_entries; i++) {
164162306a36Sopenharmony_ci		if (fwevt->discard)
164262306a36Sopenharmony_ci			return;
164362306a36Sopenharmony_ci		handle = le16_to_cpu(event_data->phy_entry[i].attached_dev_handle);
164462306a36Sopenharmony_ci		if (!handle)
164562306a36Sopenharmony_ci			continue;
164662306a36Sopenharmony_ci		tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
164762306a36Sopenharmony_ci		if (!tgtdev)
164862306a36Sopenharmony_ci			continue;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci		reason_code = event_data->phy_entry[i].status &
165162306a36Sopenharmony_ci		    MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci		switch (reason_code) {
165462306a36Sopenharmony_ci		case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
165562306a36Sopenharmony_ci			if (tgtdev->host_exposed)
165662306a36Sopenharmony_ci				mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
165762306a36Sopenharmony_ci			mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, false);
165862306a36Sopenharmony_ci			mpi3mr_tgtdev_put(tgtdev);
165962306a36Sopenharmony_ci			break;
166062306a36Sopenharmony_ci		case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING:
166162306a36Sopenharmony_ci		case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
166262306a36Sopenharmony_ci		case MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE:
166362306a36Sopenharmony_ci		{
166462306a36Sopenharmony_ci			if (!mrioc->sas_transport_enabled || tgtdev->non_stl
166562306a36Sopenharmony_ci			    || tgtdev->is_hidden)
166662306a36Sopenharmony_ci				break;
166762306a36Sopenharmony_ci			link_rate = event_data->phy_entry[i].link_rate >> 4;
166862306a36Sopenharmony_ci			prev_link_rate = event_data->phy_entry[i].link_rate & 0xF;
166962306a36Sopenharmony_ci			if (link_rate == prev_link_rate)
167062306a36Sopenharmony_ci				break;
167162306a36Sopenharmony_ci			if (!parent_sas_address)
167262306a36Sopenharmony_ci				break;
167362306a36Sopenharmony_ci			parent_phy_number = event_data->start_phy_num + i;
167462306a36Sopenharmony_ci			mpi3mr_update_links(mrioc, parent_sas_address, handle,
167562306a36Sopenharmony_ci			    parent_phy_number, link_rate, hba_port);
167662306a36Sopenharmony_ci			break;
167762306a36Sopenharmony_ci		}
167862306a36Sopenharmony_ci		default:
167962306a36Sopenharmony_ci			break;
168062306a36Sopenharmony_ci		}
168162306a36Sopenharmony_ci		if (tgtdev)
168262306a36Sopenharmony_ci			mpi3mr_tgtdev_put(tgtdev);
168362306a36Sopenharmony_ci	}
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	if (mrioc->sas_transport_enabled && (event_data->exp_status ==
168662306a36Sopenharmony_ci	    MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING)) {
168762306a36Sopenharmony_ci		if (sas_expander)
168862306a36Sopenharmony_ci			mpi3mr_expander_remove(mrioc, exp_sas_address,
168962306a36Sopenharmony_ci			    hba_port);
169062306a36Sopenharmony_ci	}
169162306a36Sopenharmony_ci}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci/**
169462306a36Sopenharmony_ci * mpi3mr_pcietopochg_evt_debug - PCIeTopoChange details
169562306a36Sopenharmony_ci * @mrioc: Adapter instance reference
169662306a36Sopenharmony_ci * @event_data: PCIe topology change list event data
169762306a36Sopenharmony_ci *
169862306a36Sopenharmony_ci * Prints information about the PCIe topology change event.
169962306a36Sopenharmony_ci *
170062306a36Sopenharmony_ci * Return: Nothing.
170162306a36Sopenharmony_ci */
170262306a36Sopenharmony_cistatic void
170362306a36Sopenharmony_cimpi3mr_pcietopochg_evt_debug(struct mpi3mr_ioc *mrioc,
170462306a36Sopenharmony_ci	struct mpi3_event_data_pcie_topology_change_list *event_data)
170562306a36Sopenharmony_ci{
170662306a36Sopenharmony_ci	int i;
170762306a36Sopenharmony_ci	u16 handle;
170862306a36Sopenharmony_ci	u16 reason_code;
170962306a36Sopenharmony_ci	u8 port_number;
171062306a36Sopenharmony_ci	char *status_str = NULL;
171162306a36Sopenharmony_ci	u8 link_rate, prev_link_rate;
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	switch (event_data->switch_status) {
171462306a36Sopenharmony_ci	case MPI3_EVENT_PCIE_TOPO_SS_NOT_RESPONDING:
171562306a36Sopenharmony_ci		status_str = "remove";
171662306a36Sopenharmony_ci		break;
171762306a36Sopenharmony_ci	case MPI3_EVENT_PCIE_TOPO_SS_RESPONDING:
171862306a36Sopenharmony_ci		status_str =  "responding";
171962306a36Sopenharmony_ci		break;
172062306a36Sopenharmony_ci	case MPI3_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING:
172162306a36Sopenharmony_ci		status_str = "remove delay";
172262306a36Sopenharmony_ci		break;
172362306a36Sopenharmony_ci	case MPI3_EVENT_PCIE_TOPO_SS_NO_PCIE_SWITCH:
172462306a36Sopenharmony_ci		status_str = "direct attached";
172562306a36Sopenharmony_ci		break;
172662306a36Sopenharmony_ci	default:
172762306a36Sopenharmony_ci		status_str = "unknown status";
172862306a36Sopenharmony_ci		break;
172962306a36Sopenharmony_ci	}
173062306a36Sopenharmony_ci	ioc_info(mrioc, "%s :pcie topology change: (%s)\n",
173162306a36Sopenharmony_ci	    __func__, status_str);
173262306a36Sopenharmony_ci	ioc_info(mrioc,
173362306a36Sopenharmony_ci	    "%s :\tswitch_handle(0x%04x), enclosure_handle(0x%04x) start_port(%02d), num_entries(%d)\n",
173462306a36Sopenharmony_ci	    __func__, le16_to_cpu(event_data->switch_dev_handle),
173562306a36Sopenharmony_ci	    le16_to_cpu(event_data->enclosure_handle),
173662306a36Sopenharmony_ci	    event_data->start_port_num, event_data->num_entries);
173762306a36Sopenharmony_ci	for (i = 0; i < event_data->num_entries; i++) {
173862306a36Sopenharmony_ci		handle =
173962306a36Sopenharmony_ci		    le16_to_cpu(event_data->port_entry[i].attached_dev_handle);
174062306a36Sopenharmony_ci		if (!handle)
174162306a36Sopenharmony_ci			continue;
174262306a36Sopenharmony_ci		port_number = event_data->start_port_num + i;
174362306a36Sopenharmony_ci		reason_code = event_data->port_entry[i].port_status;
174462306a36Sopenharmony_ci		switch (reason_code) {
174562306a36Sopenharmony_ci		case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
174662306a36Sopenharmony_ci			status_str = "target remove";
174762306a36Sopenharmony_ci			break;
174862306a36Sopenharmony_ci		case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING:
174962306a36Sopenharmony_ci			status_str = "delay target remove";
175062306a36Sopenharmony_ci			break;
175162306a36Sopenharmony_ci		case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
175262306a36Sopenharmony_ci			status_str = "link status change";
175362306a36Sopenharmony_ci			break;
175462306a36Sopenharmony_ci		case MPI3_EVENT_PCIE_TOPO_PS_NO_CHANGE:
175562306a36Sopenharmony_ci			status_str = "link status no change";
175662306a36Sopenharmony_ci			break;
175762306a36Sopenharmony_ci		case MPI3_EVENT_PCIE_TOPO_PS_RESPONDING:
175862306a36Sopenharmony_ci			status_str = "target responding";
175962306a36Sopenharmony_ci			break;
176062306a36Sopenharmony_ci		default:
176162306a36Sopenharmony_ci			status_str = "unknown";
176262306a36Sopenharmony_ci			break;
176362306a36Sopenharmony_ci		}
176462306a36Sopenharmony_ci		link_rate = event_data->port_entry[i].current_port_info &
176562306a36Sopenharmony_ci		    MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK;
176662306a36Sopenharmony_ci		prev_link_rate = event_data->port_entry[i].previous_port_info &
176762306a36Sopenharmony_ci		    MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK;
176862306a36Sopenharmony_ci		ioc_info(mrioc,
176962306a36Sopenharmony_ci		    "%s :\tport(%02d), attached_handle(0x%04x): %s: link rate: new(0x%02x), old(0x%02x)\n",
177062306a36Sopenharmony_ci		    __func__, port_number, handle, status_str, link_rate,
177162306a36Sopenharmony_ci		    prev_link_rate);
177262306a36Sopenharmony_ci	}
177362306a36Sopenharmony_ci}
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci/**
177662306a36Sopenharmony_ci * mpi3mr_pcietopochg_evt_bh - PCIeTopologyChange evt bottomhalf
177762306a36Sopenharmony_ci * @mrioc: Adapter instance reference
177862306a36Sopenharmony_ci * @fwevt: Firmware event reference
177962306a36Sopenharmony_ci *
178062306a36Sopenharmony_ci * Prints information about the PCIe topology change event and
178162306a36Sopenharmony_ci * for "not responding" event code, removes the device from the
178262306a36Sopenharmony_ci * upper layers.
178362306a36Sopenharmony_ci *
178462306a36Sopenharmony_ci * Return: Nothing.
178562306a36Sopenharmony_ci */
178662306a36Sopenharmony_cistatic void mpi3mr_pcietopochg_evt_bh(struct mpi3mr_ioc *mrioc,
178762306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt)
178862306a36Sopenharmony_ci{
178962306a36Sopenharmony_ci	struct mpi3_event_data_pcie_topology_change_list *event_data =
179062306a36Sopenharmony_ci	    (struct mpi3_event_data_pcie_topology_change_list *)fwevt->event_data;
179162306a36Sopenharmony_ci	int i;
179262306a36Sopenharmony_ci	u16 handle;
179362306a36Sopenharmony_ci	u8 reason_code;
179462306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev = NULL;
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	mpi3mr_pcietopochg_evt_debug(mrioc, event_data);
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	for (i = 0; i < event_data->num_entries; i++) {
179962306a36Sopenharmony_ci		if (fwevt->discard)
180062306a36Sopenharmony_ci			return;
180162306a36Sopenharmony_ci		handle =
180262306a36Sopenharmony_ci		    le16_to_cpu(event_data->port_entry[i].attached_dev_handle);
180362306a36Sopenharmony_ci		if (!handle)
180462306a36Sopenharmony_ci			continue;
180562306a36Sopenharmony_ci		tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
180662306a36Sopenharmony_ci		if (!tgtdev)
180762306a36Sopenharmony_ci			continue;
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci		reason_code = event_data->port_entry[i].port_status;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci		switch (reason_code) {
181262306a36Sopenharmony_ci		case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
181362306a36Sopenharmony_ci			if (tgtdev->host_exposed)
181462306a36Sopenharmony_ci				mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
181562306a36Sopenharmony_ci			mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, false);
181662306a36Sopenharmony_ci			mpi3mr_tgtdev_put(tgtdev);
181762306a36Sopenharmony_ci			break;
181862306a36Sopenharmony_ci		default:
181962306a36Sopenharmony_ci			break;
182062306a36Sopenharmony_ci		}
182162306a36Sopenharmony_ci		if (tgtdev)
182262306a36Sopenharmony_ci			mpi3mr_tgtdev_put(tgtdev);
182362306a36Sopenharmony_ci	}
182462306a36Sopenharmony_ci}
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci/**
182762306a36Sopenharmony_ci * mpi3mr_logdata_evt_bh -  Log data event bottomhalf
182862306a36Sopenharmony_ci * @mrioc: Adapter instance reference
182962306a36Sopenharmony_ci * @fwevt: Firmware event reference
183062306a36Sopenharmony_ci *
183162306a36Sopenharmony_ci * Extracts the event data and calls application interfacing
183262306a36Sopenharmony_ci * function to process the event further.
183362306a36Sopenharmony_ci *
183462306a36Sopenharmony_ci * Return: Nothing.
183562306a36Sopenharmony_ci */
183662306a36Sopenharmony_cistatic void mpi3mr_logdata_evt_bh(struct mpi3mr_ioc *mrioc,
183762306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt)
183862306a36Sopenharmony_ci{
183962306a36Sopenharmony_ci	mpi3mr_app_save_logdata(mrioc, fwevt->event_data,
184062306a36Sopenharmony_ci	    fwevt->event_data_size);
184162306a36Sopenharmony_ci}
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci/**
184462306a36Sopenharmony_ci * mpi3mr_update_sdev_qd - Update SCSI device queue depath
184562306a36Sopenharmony_ci * @sdev: SCSI device reference
184662306a36Sopenharmony_ci * @data: Queue depth reference
184762306a36Sopenharmony_ci *
184862306a36Sopenharmony_ci * This is an iterator function called for each SCSI device in a
184962306a36Sopenharmony_ci * target to update the QD of each SCSI device.
185062306a36Sopenharmony_ci *
185162306a36Sopenharmony_ci * Return: Nothing.
185262306a36Sopenharmony_ci */
185362306a36Sopenharmony_cistatic void mpi3mr_update_sdev_qd(struct scsi_device *sdev, void *data)
185462306a36Sopenharmony_ci{
185562306a36Sopenharmony_ci	u16 *q_depth = (u16 *)data;
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	scsi_change_queue_depth(sdev, (int)*q_depth);
185862306a36Sopenharmony_ci	sdev->max_queue_depth = sdev->queue_depth;
185962306a36Sopenharmony_ci}
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci/**
186262306a36Sopenharmony_ci * mpi3mr_set_qd_for_all_vd_in_tg -set QD for TG VDs
186362306a36Sopenharmony_ci * @mrioc: Adapter instance reference
186462306a36Sopenharmony_ci * @tg: Throttle group information pointer
186562306a36Sopenharmony_ci *
186662306a36Sopenharmony_ci * Accessor to reduce QD for each device associated with the
186762306a36Sopenharmony_ci * given throttle group.
186862306a36Sopenharmony_ci *
186962306a36Sopenharmony_ci * Return: None.
187062306a36Sopenharmony_ci */
187162306a36Sopenharmony_cistatic void mpi3mr_set_qd_for_all_vd_in_tg(struct mpi3mr_ioc *mrioc,
187262306a36Sopenharmony_ci	struct mpi3mr_throttle_group_info *tg)
187362306a36Sopenharmony_ci{
187462306a36Sopenharmony_ci	unsigned long flags;
187562306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev;
187662306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *tgt_priv;
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
188062306a36Sopenharmony_ci	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
188162306a36Sopenharmony_ci		if (tgtdev->starget && tgtdev->starget->hostdata) {
188262306a36Sopenharmony_ci			tgt_priv = tgtdev->starget->hostdata;
188362306a36Sopenharmony_ci			if (tgt_priv->throttle_group == tg) {
188462306a36Sopenharmony_ci				dprint_event_bh(mrioc,
188562306a36Sopenharmony_ci				    "updating qd due to throttling for persist_id(%d) original_qd(%d), reduced_qd (%d)\n",
188662306a36Sopenharmony_ci				    tgt_priv->perst_id, tgtdev->q_depth,
188762306a36Sopenharmony_ci				    tg->modified_qd);
188862306a36Sopenharmony_ci				starget_for_each_device(tgtdev->starget,
188962306a36Sopenharmony_ci				    (void *)&tg->modified_qd,
189062306a36Sopenharmony_ci				    mpi3mr_update_sdev_qd);
189162306a36Sopenharmony_ci			}
189262306a36Sopenharmony_ci		}
189362306a36Sopenharmony_ci	}
189462306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
189562306a36Sopenharmony_ci}
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci/**
189862306a36Sopenharmony_ci * mpi3mr_fwevt_bh - Firmware event bottomhalf handler
189962306a36Sopenharmony_ci * @mrioc: Adapter instance reference
190062306a36Sopenharmony_ci * @fwevt: Firmware event reference
190162306a36Sopenharmony_ci *
190262306a36Sopenharmony_ci * Identifies the firmware event and calls corresponding bottomg
190362306a36Sopenharmony_ci * half handler and sends event acknowledgment if required.
190462306a36Sopenharmony_ci *
190562306a36Sopenharmony_ci * Return: Nothing.
190662306a36Sopenharmony_ci */
190762306a36Sopenharmony_cistatic void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
190862306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt)
190962306a36Sopenharmony_ci{
191062306a36Sopenharmony_ci	struct mpi3_device_page0 *dev_pg0 = NULL;
191162306a36Sopenharmony_ci	u16 perst_id, handle, dev_info;
191262306a36Sopenharmony_ci	struct mpi3_device0_sas_sata_format *sasinf = NULL;
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci	mpi3mr_fwevt_del_from_list(mrioc, fwevt);
191562306a36Sopenharmony_ci	mrioc->current_event = fwevt;
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	if (mrioc->stop_drv_processing)
191862306a36Sopenharmony_ci		goto out;
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	if (mrioc->unrecoverable) {
192162306a36Sopenharmony_ci		dprint_event_bh(mrioc,
192262306a36Sopenharmony_ci		    "ignoring event(0x%02x) in bottom half handler due to unrecoverable controller\n",
192362306a36Sopenharmony_ci		    fwevt->event_id);
192462306a36Sopenharmony_ci		goto out;
192562306a36Sopenharmony_ci	}
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	if (!fwevt->process_evt)
192862306a36Sopenharmony_ci		goto evt_ack;
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	switch (fwevt->event_id) {
193162306a36Sopenharmony_ci	case MPI3_EVENT_DEVICE_ADDED:
193262306a36Sopenharmony_ci	{
193362306a36Sopenharmony_ci		dev_pg0 = (struct mpi3_device_page0 *)fwevt->event_data;
193462306a36Sopenharmony_ci		perst_id = le16_to_cpu(dev_pg0->persistent_id);
193562306a36Sopenharmony_ci		handle = le16_to_cpu(dev_pg0->dev_handle);
193662306a36Sopenharmony_ci		if (perst_id != MPI3_DEVICE0_PERSISTENTID_INVALID)
193762306a36Sopenharmony_ci			mpi3mr_report_tgtdev_to_host(mrioc, perst_id);
193862306a36Sopenharmony_ci		else if (mrioc->sas_transport_enabled &&
193962306a36Sopenharmony_ci		    (dev_pg0->device_form == MPI3_DEVICE_DEVFORM_SAS_SATA)) {
194062306a36Sopenharmony_ci			sasinf = &dev_pg0->device_specific.sas_sata_format;
194162306a36Sopenharmony_ci			dev_info = le16_to_cpu(sasinf->device_info);
194262306a36Sopenharmony_ci			if (!mrioc->sas_hba.num_phys)
194362306a36Sopenharmony_ci				mpi3mr_sas_host_add(mrioc);
194462306a36Sopenharmony_ci			else
194562306a36Sopenharmony_ci				mpi3mr_sas_host_refresh(mrioc);
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci			if (mpi3mr_is_expander_device(dev_info))
194862306a36Sopenharmony_ci				mpi3mr_expander_add(mrioc, handle);
194962306a36Sopenharmony_ci		}
195062306a36Sopenharmony_ci		break;
195162306a36Sopenharmony_ci	}
195262306a36Sopenharmony_ci	case MPI3_EVENT_DEVICE_INFO_CHANGED:
195362306a36Sopenharmony_ci	{
195462306a36Sopenharmony_ci		dev_pg0 = (struct mpi3_device_page0 *)fwevt->event_data;
195562306a36Sopenharmony_ci		perst_id = le16_to_cpu(dev_pg0->persistent_id);
195662306a36Sopenharmony_ci		if (perst_id != MPI3_DEVICE0_PERSISTENTID_INVALID)
195762306a36Sopenharmony_ci			mpi3mr_devinfochg_evt_bh(mrioc, dev_pg0);
195862306a36Sopenharmony_ci		break;
195962306a36Sopenharmony_ci	}
196062306a36Sopenharmony_ci	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
196162306a36Sopenharmony_ci	{
196262306a36Sopenharmony_ci		mpi3mr_devstatuschg_evt_bh(mrioc, fwevt);
196362306a36Sopenharmony_ci		break;
196462306a36Sopenharmony_ci	}
196562306a36Sopenharmony_ci	case MPI3_EVENT_ENCL_DEVICE_ADDED:
196662306a36Sopenharmony_ci	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
196762306a36Sopenharmony_ci	{
196862306a36Sopenharmony_ci		mpi3mr_encldev_add_chg_evt_bh(mrioc, fwevt);
196962306a36Sopenharmony_ci		break;
197062306a36Sopenharmony_ci	}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
197362306a36Sopenharmony_ci	{
197462306a36Sopenharmony_ci		mpi3mr_sastopochg_evt_bh(mrioc, fwevt);
197562306a36Sopenharmony_ci		break;
197662306a36Sopenharmony_ci	}
197762306a36Sopenharmony_ci	case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
197862306a36Sopenharmony_ci	{
197962306a36Sopenharmony_ci		mpi3mr_pcietopochg_evt_bh(mrioc, fwevt);
198062306a36Sopenharmony_ci		break;
198162306a36Sopenharmony_ci	}
198262306a36Sopenharmony_ci	case MPI3_EVENT_LOG_DATA:
198362306a36Sopenharmony_ci	{
198462306a36Sopenharmony_ci		mpi3mr_logdata_evt_bh(mrioc, fwevt);
198562306a36Sopenharmony_ci		break;
198662306a36Sopenharmony_ci	}
198762306a36Sopenharmony_ci	case MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION:
198862306a36Sopenharmony_ci	{
198962306a36Sopenharmony_ci		struct mpi3mr_throttle_group_info *tg;
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci		tg = *(struct mpi3mr_throttle_group_info **)fwevt->event_data;
199262306a36Sopenharmony_ci		dprint_event_bh(mrioc,
199362306a36Sopenharmony_ci		    "qd reduction event processed for tg_id(%d) reduction_needed(%d)\n",
199462306a36Sopenharmony_ci		    tg->id, tg->need_qd_reduction);
199562306a36Sopenharmony_ci		if (tg->need_qd_reduction) {
199662306a36Sopenharmony_ci			mpi3mr_set_qd_for_all_vd_in_tg(mrioc, tg);
199762306a36Sopenharmony_ci			tg->need_qd_reduction = 0;
199862306a36Sopenharmony_ci		}
199962306a36Sopenharmony_ci		break;
200062306a36Sopenharmony_ci	}
200162306a36Sopenharmony_ci	case MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH:
200262306a36Sopenharmony_ci	{
200362306a36Sopenharmony_ci		while (mrioc->device_refresh_on)
200462306a36Sopenharmony_ci			msleep(500);
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci		dprint_event_bh(mrioc,
200762306a36Sopenharmony_ci		    "scan for non responding and newly added devices after soft reset started\n");
200862306a36Sopenharmony_ci		if (mrioc->sas_transport_enabled) {
200962306a36Sopenharmony_ci			mpi3mr_refresh_sas_ports(mrioc);
201062306a36Sopenharmony_ci			mpi3mr_refresh_expanders(mrioc);
201162306a36Sopenharmony_ci		}
201262306a36Sopenharmony_ci		mpi3mr_rfresh_tgtdevs(mrioc);
201362306a36Sopenharmony_ci		ioc_info(mrioc,
201462306a36Sopenharmony_ci		    "scan for non responding and newly added devices after soft reset completed\n");
201562306a36Sopenharmony_ci		break;
201662306a36Sopenharmony_ci	}
201762306a36Sopenharmony_ci	default:
201862306a36Sopenharmony_ci		break;
201962306a36Sopenharmony_ci	}
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_cievt_ack:
202262306a36Sopenharmony_ci	if (fwevt->send_ack)
202362306a36Sopenharmony_ci		mpi3mr_process_event_ack(mrioc, fwevt->event_id,
202462306a36Sopenharmony_ci		    fwevt->evt_ctx);
202562306a36Sopenharmony_ciout:
202662306a36Sopenharmony_ci	/* Put fwevt reference count to neutralize kref_init increment */
202762306a36Sopenharmony_ci	mpi3mr_fwevt_put(fwevt);
202862306a36Sopenharmony_ci	mrioc->current_event = NULL;
202962306a36Sopenharmony_ci}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci/**
203262306a36Sopenharmony_ci * mpi3mr_fwevt_worker - Firmware event worker
203362306a36Sopenharmony_ci * @work: Work struct containing firmware event
203462306a36Sopenharmony_ci *
203562306a36Sopenharmony_ci * Extracts the firmware event and calls mpi3mr_fwevt_bh.
203662306a36Sopenharmony_ci *
203762306a36Sopenharmony_ci * Return: Nothing.
203862306a36Sopenharmony_ci */
203962306a36Sopenharmony_cistatic void mpi3mr_fwevt_worker(struct work_struct *work)
204062306a36Sopenharmony_ci{
204162306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt = container_of(work, struct mpi3mr_fwevt,
204262306a36Sopenharmony_ci	    work);
204362306a36Sopenharmony_ci	mpi3mr_fwevt_bh(fwevt->mrioc, fwevt);
204462306a36Sopenharmony_ci	/*
204562306a36Sopenharmony_ci	 * Put fwevt reference count after
204662306a36Sopenharmony_ci	 * dequeuing it from worker queue
204762306a36Sopenharmony_ci	 */
204862306a36Sopenharmony_ci	mpi3mr_fwevt_put(fwevt);
204962306a36Sopenharmony_ci}
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci/**
205262306a36Sopenharmony_ci * mpi3mr_create_tgtdev - Create and add a target device
205362306a36Sopenharmony_ci * @mrioc: Adapter instance reference
205462306a36Sopenharmony_ci * @dev_pg0: Device Page 0 data
205562306a36Sopenharmony_ci *
205662306a36Sopenharmony_ci * If the device specified by the device page 0 data is not
205762306a36Sopenharmony_ci * present in the driver's internal list, allocate the memory
205862306a36Sopenharmony_ci * for the device, populate the data and add to the list, else
205962306a36Sopenharmony_ci * update the device data.  The key is persistent ID.
206062306a36Sopenharmony_ci *
206162306a36Sopenharmony_ci * Return: 0 on success, -ENOMEM on memory allocation failure
206262306a36Sopenharmony_ci */
206362306a36Sopenharmony_cistatic int mpi3mr_create_tgtdev(struct mpi3mr_ioc *mrioc,
206462306a36Sopenharmony_ci	struct mpi3_device_page0 *dev_pg0)
206562306a36Sopenharmony_ci{
206662306a36Sopenharmony_ci	int retval = 0;
206762306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev = NULL;
206862306a36Sopenharmony_ci	u16 perst_id = 0;
206962306a36Sopenharmony_ci	unsigned long flags;
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	perst_id = le16_to_cpu(dev_pg0->persistent_id);
207262306a36Sopenharmony_ci	if (perst_id == MPI3_DEVICE0_PERSISTENTID_INVALID)
207362306a36Sopenharmony_ci		return retval;
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
207662306a36Sopenharmony_ci	tgtdev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id);
207762306a36Sopenharmony_ci	if (tgtdev)
207862306a36Sopenharmony_ci		tgtdev->state = MPI3MR_DEV_CREATED;
207962306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	if (tgtdev) {
208262306a36Sopenharmony_ci		mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, true);
208362306a36Sopenharmony_ci		mpi3mr_tgtdev_put(tgtdev);
208462306a36Sopenharmony_ci	} else {
208562306a36Sopenharmony_ci		tgtdev = mpi3mr_alloc_tgtdev();
208662306a36Sopenharmony_ci		if (!tgtdev)
208762306a36Sopenharmony_ci			return -ENOMEM;
208862306a36Sopenharmony_ci		mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, true);
208962306a36Sopenharmony_ci		mpi3mr_tgtdev_add_to_list(mrioc, tgtdev);
209062306a36Sopenharmony_ci	}
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	return retval;
209362306a36Sopenharmony_ci}
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci/**
209662306a36Sopenharmony_ci * mpi3mr_flush_delayed_cmd_lists - Flush pending commands
209762306a36Sopenharmony_ci * @mrioc: Adapter instance reference
209862306a36Sopenharmony_ci *
209962306a36Sopenharmony_ci * Flush pending commands in the delayed lists due to a
210062306a36Sopenharmony_ci * controller reset or driver removal as a cleanup.
210162306a36Sopenharmony_ci *
210262306a36Sopenharmony_ci * Return: Nothing
210362306a36Sopenharmony_ci */
210462306a36Sopenharmony_civoid mpi3mr_flush_delayed_cmd_lists(struct mpi3mr_ioc *mrioc)
210562306a36Sopenharmony_ci{
210662306a36Sopenharmony_ci	struct delayed_dev_rmhs_node *_rmhs_node;
210762306a36Sopenharmony_ci	struct delayed_evt_ack_node *_evtack_node;
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci	dprint_reset(mrioc, "flushing delayed dev_remove_hs commands\n");
211062306a36Sopenharmony_ci	while (!list_empty(&mrioc->delayed_rmhs_list)) {
211162306a36Sopenharmony_ci		_rmhs_node = list_entry(mrioc->delayed_rmhs_list.next,
211262306a36Sopenharmony_ci		    struct delayed_dev_rmhs_node, list);
211362306a36Sopenharmony_ci		list_del(&_rmhs_node->list);
211462306a36Sopenharmony_ci		kfree(_rmhs_node);
211562306a36Sopenharmony_ci	}
211662306a36Sopenharmony_ci	dprint_reset(mrioc, "flushing delayed event ack commands\n");
211762306a36Sopenharmony_ci	while (!list_empty(&mrioc->delayed_evtack_cmds_list)) {
211862306a36Sopenharmony_ci		_evtack_node = list_entry(mrioc->delayed_evtack_cmds_list.next,
211962306a36Sopenharmony_ci		    struct delayed_evt_ack_node, list);
212062306a36Sopenharmony_ci		list_del(&_evtack_node->list);
212162306a36Sopenharmony_ci		kfree(_evtack_node);
212262306a36Sopenharmony_ci	}
212362306a36Sopenharmony_ci}
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci/**
212662306a36Sopenharmony_ci * mpi3mr_dev_rmhs_complete_iou - Device removal IOUC completion
212762306a36Sopenharmony_ci * @mrioc: Adapter instance reference
212862306a36Sopenharmony_ci * @drv_cmd: Internal command tracker
212962306a36Sopenharmony_ci *
213062306a36Sopenharmony_ci * Issues a target reset TM to the firmware from the device
213162306a36Sopenharmony_ci * removal TM pend list or retry the removal handshake sequence
213262306a36Sopenharmony_ci * based on the IOU control request IOC status.
213362306a36Sopenharmony_ci *
213462306a36Sopenharmony_ci * Return: Nothing
213562306a36Sopenharmony_ci */
213662306a36Sopenharmony_cistatic void mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_ioc *mrioc,
213762306a36Sopenharmony_ci	struct mpi3mr_drv_cmd *drv_cmd)
213862306a36Sopenharmony_ci{
213962306a36Sopenharmony_ci	u16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
214062306a36Sopenharmony_ci	struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL;
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci	if (drv_cmd->state & MPI3MR_CMD_RESET)
214362306a36Sopenharmony_ci		goto clear_drv_cmd;
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	ioc_info(mrioc,
214662306a36Sopenharmony_ci	    "%s :dev_rmhs_iouctrl_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x)\n",
214762306a36Sopenharmony_ci	    __func__, drv_cmd->dev_handle, drv_cmd->ioc_status,
214862306a36Sopenharmony_ci	    drv_cmd->ioc_loginfo);
214962306a36Sopenharmony_ci	if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) {
215062306a36Sopenharmony_ci		if (drv_cmd->retry_count < MPI3MR_DEV_RMHS_RETRY_COUNT) {
215162306a36Sopenharmony_ci			drv_cmd->retry_count++;
215262306a36Sopenharmony_ci			ioc_info(mrioc,
215362306a36Sopenharmony_ci			    "%s :dev_rmhs_iouctrl_complete: handle(0x%04x)retrying handshake retry=%d\n",
215462306a36Sopenharmony_ci			    __func__, drv_cmd->dev_handle,
215562306a36Sopenharmony_ci			    drv_cmd->retry_count);
215662306a36Sopenharmony_ci			mpi3mr_dev_rmhs_send_tm(mrioc, drv_cmd->dev_handle,
215762306a36Sopenharmony_ci			    drv_cmd, drv_cmd->iou_rc);
215862306a36Sopenharmony_ci			return;
215962306a36Sopenharmony_ci		}
216062306a36Sopenharmony_ci		ioc_err(mrioc,
216162306a36Sopenharmony_ci		    "%s :dev removal handshake failed after all retries: handle(0x%04x)\n",
216262306a36Sopenharmony_ci		    __func__, drv_cmd->dev_handle);
216362306a36Sopenharmony_ci	} else {
216462306a36Sopenharmony_ci		ioc_info(mrioc,
216562306a36Sopenharmony_ci		    "%s :dev removal handshake completed successfully: handle(0x%04x)\n",
216662306a36Sopenharmony_ci		    __func__, drv_cmd->dev_handle);
216762306a36Sopenharmony_ci		clear_bit(drv_cmd->dev_handle, mrioc->removepend_bitmap);
216862306a36Sopenharmony_ci	}
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	if (!list_empty(&mrioc->delayed_rmhs_list)) {
217162306a36Sopenharmony_ci		delayed_dev_rmhs = list_entry(mrioc->delayed_rmhs_list.next,
217262306a36Sopenharmony_ci		    struct delayed_dev_rmhs_node, list);
217362306a36Sopenharmony_ci		drv_cmd->dev_handle = delayed_dev_rmhs->handle;
217462306a36Sopenharmony_ci		drv_cmd->retry_count = 0;
217562306a36Sopenharmony_ci		drv_cmd->iou_rc = delayed_dev_rmhs->iou_rc;
217662306a36Sopenharmony_ci		ioc_info(mrioc,
217762306a36Sopenharmony_ci		    "%s :dev_rmhs_iouctrl_complete: processing delayed TM: handle(0x%04x)\n",
217862306a36Sopenharmony_ci		    __func__, drv_cmd->dev_handle);
217962306a36Sopenharmony_ci		mpi3mr_dev_rmhs_send_tm(mrioc, drv_cmd->dev_handle, drv_cmd,
218062306a36Sopenharmony_ci		    drv_cmd->iou_rc);
218162306a36Sopenharmony_ci		list_del(&delayed_dev_rmhs->list);
218262306a36Sopenharmony_ci		kfree(delayed_dev_rmhs);
218362306a36Sopenharmony_ci		return;
218462306a36Sopenharmony_ci	}
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ciclear_drv_cmd:
218762306a36Sopenharmony_ci	drv_cmd->state = MPI3MR_CMD_NOTUSED;
218862306a36Sopenharmony_ci	drv_cmd->callback = NULL;
218962306a36Sopenharmony_ci	drv_cmd->retry_count = 0;
219062306a36Sopenharmony_ci	drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
219162306a36Sopenharmony_ci	clear_bit(cmd_idx, mrioc->devrem_bitmap);
219262306a36Sopenharmony_ci}
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci/**
219562306a36Sopenharmony_ci * mpi3mr_dev_rmhs_complete_tm - Device removal TM completion
219662306a36Sopenharmony_ci * @mrioc: Adapter instance reference
219762306a36Sopenharmony_ci * @drv_cmd: Internal command tracker
219862306a36Sopenharmony_ci *
219962306a36Sopenharmony_ci * Issues a target reset TM to the firmware from the device
220062306a36Sopenharmony_ci * removal TM pend list or issue IO unit control request as
220162306a36Sopenharmony_ci * part of device removal or hidden acknowledgment handshake.
220262306a36Sopenharmony_ci *
220362306a36Sopenharmony_ci * Return: Nothing
220462306a36Sopenharmony_ci */
220562306a36Sopenharmony_cistatic void mpi3mr_dev_rmhs_complete_tm(struct mpi3mr_ioc *mrioc,
220662306a36Sopenharmony_ci	struct mpi3mr_drv_cmd *drv_cmd)
220762306a36Sopenharmony_ci{
220862306a36Sopenharmony_ci	struct mpi3_iounit_control_request iou_ctrl;
220962306a36Sopenharmony_ci	u16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
221062306a36Sopenharmony_ci	struct mpi3_scsi_task_mgmt_reply *tm_reply = NULL;
221162306a36Sopenharmony_ci	int retval;
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	if (drv_cmd->state & MPI3MR_CMD_RESET)
221462306a36Sopenharmony_ci		goto clear_drv_cmd;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID)
221762306a36Sopenharmony_ci		tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply;
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	if (tm_reply)
222062306a36Sopenharmony_ci		pr_info(IOCNAME
222162306a36Sopenharmony_ci		    "dev_rmhs_tr_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x), term_count(%d)\n",
222262306a36Sopenharmony_ci		    mrioc->name, drv_cmd->dev_handle, drv_cmd->ioc_status,
222362306a36Sopenharmony_ci		    drv_cmd->ioc_loginfo,
222462306a36Sopenharmony_ci		    le32_to_cpu(tm_reply->termination_count));
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	pr_info(IOCNAME "Issuing IOU CTL: handle(0x%04x) dev_rmhs idx(%d)\n",
222762306a36Sopenharmony_ci	    mrioc->name, drv_cmd->dev_handle, cmd_idx);
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci	memset(&iou_ctrl, 0, sizeof(iou_ctrl));
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	drv_cmd->state = MPI3MR_CMD_PENDING;
223262306a36Sopenharmony_ci	drv_cmd->is_waiting = 0;
223362306a36Sopenharmony_ci	drv_cmd->callback = mpi3mr_dev_rmhs_complete_iou;
223462306a36Sopenharmony_ci	iou_ctrl.operation = drv_cmd->iou_rc;
223562306a36Sopenharmony_ci	iou_ctrl.param16[0] = cpu_to_le16(drv_cmd->dev_handle);
223662306a36Sopenharmony_ci	iou_ctrl.host_tag = cpu_to_le16(drv_cmd->host_tag);
223762306a36Sopenharmony_ci	iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci	retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl, sizeof(iou_ctrl),
224062306a36Sopenharmony_ci	    1);
224162306a36Sopenharmony_ci	if (retval) {
224262306a36Sopenharmony_ci		pr_err(IOCNAME "Issue DevRmHsTMIOUCTL: Admin post failed\n",
224362306a36Sopenharmony_ci		    mrioc->name);
224462306a36Sopenharmony_ci		goto clear_drv_cmd;
224562306a36Sopenharmony_ci	}
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	return;
224862306a36Sopenharmony_ciclear_drv_cmd:
224962306a36Sopenharmony_ci	drv_cmd->state = MPI3MR_CMD_NOTUSED;
225062306a36Sopenharmony_ci	drv_cmd->callback = NULL;
225162306a36Sopenharmony_ci	drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
225262306a36Sopenharmony_ci	drv_cmd->retry_count = 0;
225362306a36Sopenharmony_ci	clear_bit(cmd_idx, mrioc->devrem_bitmap);
225462306a36Sopenharmony_ci}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci/**
225762306a36Sopenharmony_ci * mpi3mr_dev_rmhs_send_tm - Issue TM for device removal
225862306a36Sopenharmony_ci * @mrioc: Adapter instance reference
225962306a36Sopenharmony_ci * @handle: Device handle
226062306a36Sopenharmony_ci * @cmdparam: Internal command tracker
226162306a36Sopenharmony_ci * @iou_rc: IO unit reason code
226262306a36Sopenharmony_ci *
226362306a36Sopenharmony_ci * Issues a target reset TM to the firmware or add it to a pend
226462306a36Sopenharmony_ci * list as part of device removal or hidden acknowledgment
226562306a36Sopenharmony_ci * handshake.
226662306a36Sopenharmony_ci *
226762306a36Sopenharmony_ci * Return: Nothing
226862306a36Sopenharmony_ci */
226962306a36Sopenharmony_cistatic void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_ioc *mrioc, u16 handle,
227062306a36Sopenharmony_ci	struct mpi3mr_drv_cmd *cmdparam, u8 iou_rc)
227162306a36Sopenharmony_ci{
227262306a36Sopenharmony_ci	struct mpi3_scsi_task_mgmt_request tm_req;
227362306a36Sopenharmony_ci	int retval = 0;
227462306a36Sopenharmony_ci	u16 cmd_idx = MPI3MR_NUM_DEVRMCMD;
227562306a36Sopenharmony_ci	u8 retrycount = 5;
227662306a36Sopenharmony_ci	struct mpi3mr_drv_cmd *drv_cmd = cmdparam;
227762306a36Sopenharmony_ci	struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL;
227862306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev = NULL;
227962306a36Sopenharmony_ci	unsigned long flags;
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
228262306a36Sopenharmony_ci	tgtdev = __mpi3mr_get_tgtdev_by_handle(mrioc, handle);
228362306a36Sopenharmony_ci	if (tgtdev && (iou_rc == MPI3_CTRL_OP_REMOVE_DEVICE))
228462306a36Sopenharmony_ci		tgtdev->state = MPI3MR_DEV_REMOVE_HS_STARTED;
228562306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci	if (drv_cmd)
228862306a36Sopenharmony_ci		goto issue_cmd;
228962306a36Sopenharmony_ci	do {
229062306a36Sopenharmony_ci		cmd_idx = find_first_zero_bit(mrioc->devrem_bitmap,
229162306a36Sopenharmony_ci		    MPI3MR_NUM_DEVRMCMD);
229262306a36Sopenharmony_ci		if (cmd_idx < MPI3MR_NUM_DEVRMCMD) {
229362306a36Sopenharmony_ci			if (!test_and_set_bit(cmd_idx, mrioc->devrem_bitmap))
229462306a36Sopenharmony_ci				break;
229562306a36Sopenharmony_ci			cmd_idx = MPI3MR_NUM_DEVRMCMD;
229662306a36Sopenharmony_ci		}
229762306a36Sopenharmony_ci	} while (retrycount--);
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci	if (cmd_idx >= MPI3MR_NUM_DEVRMCMD) {
230062306a36Sopenharmony_ci		delayed_dev_rmhs = kzalloc(sizeof(*delayed_dev_rmhs),
230162306a36Sopenharmony_ci		    GFP_ATOMIC);
230262306a36Sopenharmony_ci		if (!delayed_dev_rmhs)
230362306a36Sopenharmony_ci			return;
230462306a36Sopenharmony_ci		INIT_LIST_HEAD(&delayed_dev_rmhs->list);
230562306a36Sopenharmony_ci		delayed_dev_rmhs->handle = handle;
230662306a36Sopenharmony_ci		delayed_dev_rmhs->iou_rc = iou_rc;
230762306a36Sopenharmony_ci		list_add_tail(&delayed_dev_rmhs->list,
230862306a36Sopenharmony_ci		    &mrioc->delayed_rmhs_list);
230962306a36Sopenharmony_ci		ioc_info(mrioc, "%s :DevRmHs: tr:handle(0x%04x) is postponed\n",
231062306a36Sopenharmony_ci		    __func__, handle);
231162306a36Sopenharmony_ci		return;
231262306a36Sopenharmony_ci	}
231362306a36Sopenharmony_ci	drv_cmd = &mrioc->dev_rmhs_cmds[cmd_idx];
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ciissue_cmd:
231662306a36Sopenharmony_ci	cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
231762306a36Sopenharmony_ci	ioc_info(mrioc,
231862306a36Sopenharmony_ci	    "%s :Issuing TR TM: for devhandle 0x%04x with dev_rmhs %d\n",
231962306a36Sopenharmony_ci	    __func__, handle, cmd_idx);
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	memset(&tm_req, 0, sizeof(tm_req));
232262306a36Sopenharmony_ci	if (drv_cmd->state & MPI3MR_CMD_PENDING) {
232362306a36Sopenharmony_ci		ioc_err(mrioc, "%s :Issue TM: Command is in use\n", __func__);
232462306a36Sopenharmony_ci		goto out;
232562306a36Sopenharmony_ci	}
232662306a36Sopenharmony_ci	drv_cmd->state = MPI3MR_CMD_PENDING;
232762306a36Sopenharmony_ci	drv_cmd->is_waiting = 0;
232862306a36Sopenharmony_ci	drv_cmd->callback = mpi3mr_dev_rmhs_complete_tm;
232962306a36Sopenharmony_ci	drv_cmd->dev_handle = handle;
233062306a36Sopenharmony_ci	drv_cmd->iou_rc = iou_rc;
233162306a36Sopenharmony_ci	tm_req.dev_handle = cpu_to_le16(handle);
233262306a36Sopenharmony_ci	tm_req.task_type = MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
233362306a36Sopenharmony_ci	tm_req.host_tag = cpu_to_le16(drv_cmd->host_tag);
233462306a36Sopenharmony_ci	tm_req.task_host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INVALID);
233562306a36Sopenharmony_ci	tm_req.function = MPI3_FUNCTION_SCSI_TASK_MGMT;
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	set_bit(handle, mrioc->removepend_bitmap);
233862306a36Sopenharmony_ci	retval = mpi3mr_admin_request_post(mrioc, &tm_req, sizeof(tm_req), 1);
233962306a36Sopenharmony_ci	if (retval) {
234062306a36Sopenharmony_ci		ioc_err(mrioc, "%s :Issue DevRmHsTM: Admin Post failed\n",
234162306a36Sopenharmony_ci		    __func__);
234262306a36Sopenharmony_ci		goto out_failed;
234362306a36Sopenharmony_ci	}
234462306a36Sopenharmony_ciout:
234562306a36Sopenharmony_ci	return;
234662306a36Sopenharmony_ciout_failed:
234762306a36Sopenharmony_ci	drv_cmd->state = MPI3MR_CMD_NOTUSED;
234862306a36Sopenharmony_ci	drv_cmd->callback = NULL;
234962306a36Sopenharmony_ci	drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
235062306a36Sopenharmony_ci	drv_cmd->retry_count = 0;
235162306a36Sopenharmony_ci	clear_bit(cmd_idx, mrioc->devrem_bitmap);
235262306a36Sopenharmony_ci}
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci/**
235562306a36Sopenharmony_ci * mpi3mr_complete_evt_ack - event ack request completion
235662306a36Sopenharmony_ci * @mrioc: Adapter instance reference
235762306a36Sopenharmony_ci * @drv_cmd: Internal command tracker
235862306a36Sopenharmony_ci *
235962306a36Sopenharmony_ci * This is the completion handler for non blocking event
236062306a36Sopenharmony_ci * acknowledgment sent to the firmware and this will issue any
236162306a36Sopenharmony_ci * pending event acknowledgment request.
236262306a36Sopenharmony_ci *
236362306a36Sopenharmony_ci * Return: Nothing
236462306a36Sopenharmony_ci */
236562306a36Sopenharmony_cistatic void mpi3mr_complete_evt_ack(struct mpi3mr_ioc *mrioc,
236662306a36Sopenharmony_ci	struct mpi3mr_drv_cmd *drv_cmd)
236762306a36Sopenharmony_ci{
236862306a36Sopenharmony_ci	u16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
236962306a36Sopenharmony_ci	struct delayed_evt_ack_node *delayed_evtack = NULL;
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	if (drv_cmd->state & MPI3MR_CMD_RESET)
237262306a36Sopenharmony_ci		goto clear_drv_cmd;
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) {
237562306a36Sopenharmony_ci		dprint_event_th(mrioc,
237662306a36Sopenharmony_ci		    "immediate event ack failed with ioc_status(0x%04x) log_info(0x%08x)\n",
237762306a36Sopenharmony_ci		    (drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
237862306a36Sopenharmony_ci		    drv_cmd->ioc_loginfo);
237962306a36Sopenharmony_ci	}
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	if (!list_empty(&mrioc->delayed_evtack_cmds_list)) {
238262306a36Sopenharmony_ci		delayed_evtack =
238362306a36Sopenharmony_ci			list_entry(mrioc->delayed_evtack_cmds_list.next,
238462306a36Sopenharmony_ci			    struct delayed_evt_ack_node, list);
238562306a36Sopenharmony_ci		mpi3mr_send_event_ack(mrioc, delayed_evtack->event, drv_cmd,
238662306a36Sopenharmony_ci		    delayed_evtack->event_ctx);
238762306a36Sopenharmony_ci		list_del(&delayed_evtack->list);
238862306a36Sopenharmony_ci		kfree(delayed_evtack);
238962306a36Sopenharmony_ci		return;
239062306a36Sopenharmony_ci	}
239162306a36Sopenharmony_ciclear_drv_cmd:
239262306a36Sopenharmony_ci	drv_cmd->state = MPI3MR_CMD_NOTUSED;
239362306a36Sopenharmony_ci	drv_cmd->callback = NULL;
239462306a36Sopenharmony_ci	clear_bit(cmd_idx, mrioc->evtack_cmds_bitmap);
239562306a36Sopenharmony_ci}
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci/**
239862306a36Sopenharmony_ci * mpi3mr_send_event_ack - Issue event acknwoledgment request
239962306a36Sopenharmony_ci * @mrioc: Adapter instance reference
240062306a36Sopenharmony_ci * @event: MPI3 event id
240162306a36Sopenharmony_ci * @cmdparam: Internal command tracker
240262306a36Sopenharmony_ci * @event_ctx: event context
240362306a36Sopenharmony_ci *
240462306a36Sopenharmony_ci * Issues event acknowledgment request to the firmware if there
240562306a36Sopenharmony_ci * is a free command to send the event ack else it to a pend
240662306a36Sopenharmony_ci * list so that it will be processed on a completion of a prior
240762306a36Sopenharmony_ci * event acknowledgment .
240862306a36Sopenharmony_ci *
240962306a36Sopenharmony_ci * Return: Nothing
241062306a36Sopenharmony_ci */
241162306a36Sopenharmony_cistatic void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
241262306a36Sopenharmony_ci	struct mpi3mr_drv_cmd *cmdparam, u32 event_ctx)
241362306a36Sopenharmony_ci{
241462306a36Sopenharmony_ci	struct mpi3_event_ack_request evtack_req;
241562306a36Sopenharmony_ci	int retval = 0;
241662306a36Sopenharmony_ci	u8 retrycount = 5;
241762306a36Sopenharmony_ci	u16 cmd_idx = MPI3MR_NUM_EVTACKCMD;
241862306a36Sopenharmony_ci	struct mpi3mr_drv_cmd *drv_cmd = cmdparam;
241962306a36Sopenharmony_ci	struct delayed_evt_ack_node *delayed_evtack = NULL;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	if (drv_cmd) {
242262306a36Sopenharmony_ci		dprint_event_th(mrioc,
242362306a36Sopenharmony_ci		    "sending delayed event ack in the top half for event(0x%02x), event_ctx(0x%08x)\n",
242462306a36Sopenharmony_ci		    event, event_ctx);
242562306a36Sopenharmony_ci		goto issue_cmd;
242662306a36Sopenharmony_ci	}
242762306a36Sopenharmony_ci	dprint_event_th(mrioc,
242862306a36Sopenharmony_ci	    "sending event ack in the top half for event(0x%02x), event_ctx(0x%08x)\n",
242962306a36Sopenharmony_ci	    event, event_ctx);
243062306a36Sopenharmony_ci	do {
243162306a36Sopenharmony_ci		cmd_idx = find_first_zero_bit(mrioc->evtack_cmds_bitmap,
243262306a36Sopenharmony_ci		    MPI3MR_NUM_EVTACKCMD);
243362306a36Sopenharmony_ci		if (cmd_idx < MPI3MR_NUM_EVTACKCMD) {
243462306a36Sopenharmony_ci			if (!test_and_set_bit(cmd_idx,
243562306a36Sopenharmony_ci			    mrioc->evtack_cmds_bitmap))
243662306a36Sopenharmony_ci				break;
243762306a36Sopenharmony_ci			cmd_idx = MPI3MR_NUM_EVTACKCMD;
243862306a36Sopenharmony_ci		}
243962306a36Sopenharmony_ci	} while (retrycount--);
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci	if (cmd_idx >= MPI3MR_NUM_EVTACKCMD) {
244262306a36Sopenharmony_ci		delayed_evtack = kzalloc(sizeof(*delayed_evtack),
244362306a36Sopenharmony_ci		    GFP_ATOMIC);
244462306a36Sopenharmony_ci		if (!delayed_evtack)
244562306a36Sopenharmony_ci			return;
244662306a36Sopenharmony_ci		INIT_LIST_HEAD(&delayed_evtack->list);
244762306a36Sopenharmony_ci		delayed_evtack->event = event;
244862306a36Sopenharmony_ci		delayed_evtack->event_ctx = event_ctx;
244962306a36Sopenharmony_ci		list_add_tail(&delayed_evtack->list,
245062306a36Sopenharmony_ci		    &mrioc->delayed_evtack_cmds_list);
245162306a36Sopenharmony_ci		dprint_event_th(mrioc,
245262306a36Sopenharmony_ci		    "event ack in the top half for event(0x%02x), event_ctx(0x%08x) is postponed\n",
245362306a36Sopenharmony_ci		    event, event_ctx);
245462306a36Sopenharmony_ci		return;
245562306a36Sopenharmony_ci	}
245662306a36Sopenharmony_ci	drv_cmd = &mrioc->evtack_cmds[cmd_idx];
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ciissue_cmd:
245962306a36Sopenharmony_ci	cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	memset(&evtack_req, 0, sizeof(evtack_req));
246262306a36Sopenharmony_ci	if (drv_cmd->state & MPI3MR_CMD_PENDING) {
246362306a36Sopenharmony_ci		dprint_event_th(mrioc,
246462306a36Sopenharmony_ci		    "sending event ack failed due to command in use\n");
246562306a36Sopenharmony_ci		goto out;
246662306a36Sopenharmony_ci	}
246762306a36Sopenharmony_ci	drv_cmd->state = MPI3MR_CMD_PENDING;
246862306a36Sopenharmony_ci	drv_cmd->is_waiting = 0;
246962306a36Sopenharmony_ci	drv_cmd->callback = mpi3mr_complete_evt_ack;
247062306a36Sopenharmony_ci	evtack_req.host_tag = cpu_to_le16(drv_cmd->host_tag);
247162306a36Sopenharmony_ci	evtack_req.function = MPI3_FUNCTION_EVENT_ACK;
247262306a36Sopenharmony_ci	evtack_req.event = event;
247362306a36Sopenharmony_ci	evtack_req.event_context = cpu_to_le32(event_ctx);
247462306a36Sopenharmony_ci	retval = mpi3mr_admin_request_post(mrioc, &evtack_req,
247562306a36Sopenharmony_ci	    sizeof(evtack_req), 1);
247662306a36Sopenharmony_ci	if (retval) {
247762306a36Sopenharmony_ci		dprint_event_th(mrioc,
247862306a36Sopenharmony_ci		    "posting event ack request is failed\n");
247962306a36Sopenharmony_ci		goto out_failed;
248062306a36Sopenharmony_ci	}
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	dprint_event_th(mrioc,
248362306a36Sopenharmony_ci	    "event ack in the top half for event(0x%02x), event_ctx(0x%08x) is posted\n",
248462306a36Sopenharmony_ci	    event, event_ctx);
248562306a36Sopenharmony_ciout:
248662306a36Sopenharmony_ci	return;
248762306a36Sopenharmony_ciout_failed:
248862306a36Sopenharmony_ci	drv_cmd->state = MPI3MR_CMD_NOTUSED;
248962306a36Sopenharmony_ci	drv_cmd->callback = NULL;
249062306a36Sopenharmony_ci	clear_bit(cmd_idx, mrioc->evtack_cmds_bitmap);
249162306a36Sopenharmony_ci}
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci/**
249462306a36Sopenharmony_ci * mpi3mr_pcietopochg_evt_th - PCIETopologyChange evt tophalf
249562306a36Sopenharmony_ci * @mrioc: Adapter instance reference
249662306a36Sopenharmony_ci * @event_reply: event data
249762306a36Sopenharmony_ci *
249862306a36Sopenharmony_ci * Checks for the reason code and based on that either block I/O
249962306a36Sopenharmony_ci * to device, or unblock I/O to the device, or start the device
250062306a36Sopenharmony_ci * removal handshake with reason as remove with the firmware for
250162306a36Sopenharmony_ci * PCIe devices.
250262306a36Sopenharmony_ci *
250362306a36Sopenharmony_ci * Return: Nothing
250462306a36Sopenharmony_ci */
250562306a36Sopenharmony_cistatic void mpi3mr_pcietopochg_evt_th(struct mpi3mr_ioc *mrioc,
250662306a36Sopenharmony_ci	struct mpi3_event_notification_reply *event_reply)
250762306a36Sopenharmony_ci{
250862306a36Sopenharmony_ci	struct mpi3_event_data_pcie_topology_change_list *topo_evt =
250962306a36Sopenharmony_ci	    (struct mpi3_event_data_pcie_topology_change_list *)event_reply->event_data;
251062306a36Sopenharmony_ci	int i;
251162306a36Sopenharmony_ci	u16 handle;
251262306a36Sopenharmony_ci	u8 reason_code;
251362306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev = NULL;
251462306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	for (i = 0; i < topo_evt->num_entries; i++) {
251762306a36Sopenharmony_ci		handle = le16_to_cpu(topo_evt->port_entry[i].attached_dev_handle);
251862306a36Sopenharmony_ci		if (!handle)
251962306a36Sopenharmony_ci			continue;
252062306a36Sopenharmony_ci		reason_code = topo_evt->port_entry[i].port_status;
252162306a36Sopenharmony_ci		scsi_tgt_priv_data =  NULL;
252262306a36Sopenharmony_ci		tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
252362306a36Sopenharmony_ci		if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata)
252462306a36Sopenharmony_ci			scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
252562306a36Sopenharmony_ci			    tgtdev->starget->hostdata;
252662306a36Sopenharmony_ci		switch (reason_code) {
252762306a36Sopenharmony_ci		case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
252862306a36Sopenharmony_ci			if (scsi_tgt_priv_data) {
252962306a36Sopenharmony_ci				scsi_tgt_priv_data->dev_removed = 1;
253062306a36Sopenharmony_ci				scsi_tgt_priv_data->dev_removedelay = 0;
253162306a36Sopenharmony_ci				atomic_set(&scsi_tgt_priv_data->block_io, 0);
253262306a36Sopenharmony_ci			}
253362306a36Sopenharmony_ci			mpi3mr_dev_rmhs_send_tm(mrioc, handle, NULL,
253462306a36Sopenharmony_ci			    MPI3_CTRL_OP_REMOVE_DEVICE);
253562306a36Sopenharmony_ci			break;
253662306a36Sopenharmony_ci		case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING:
253762306a36Sopenharmony_ci			if (scsi_tgt_priv_data) {
253862306a36Sopenharmony_ci				scsi_tgt_priv_data->dev_removedelay = 1;
253962306a36Sopenharmony_ci				atomic_inc(&scsi_tgt_priv_data->block_io);
254062306a36Sopenharmony_ci			}
254162306a36Sopenharmony_ci			break;
254262306a36Sopenharmony_ci		case MPI3_EVENT_PCIE_TOPO_PS_RESPONDING:
254362306a36Sopenharmony_ci			if (scsi_tgt_priv_data &&
254462306a36Sopenharmony_ci			    scsi_tgt_priv_data->dev_removedelay) {
254562306a36Sopenharmony_ci				scsi_tgt_priv_data->dev_removedelay = 0;
254662306a36Sopenharmony_ci				atomic_dec_if_positive
254762306a36Sopenharmony_ci				    (&scsi_tgt_priv_data->block_io);
254862306a36Sopenharmony_ci			}
254962306a36Sopenharmony_ci			break;
255062306a36Sopenharmony_ci		case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
255162306a36Sopenharmony_ci		default:
255262306a36Sopenharmony_ci			break;
255362306a36Sopenharmony_ci		}
255462306a36Sopenharmony_ci		if (tgtdev)
255562306a36Sopenharmony_ci			mpi3mr_tgtdev_put(tgtdev);
255662306a36Sopenharmony_ci	}
255762306a36Sopenharmony_ci}
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci/**
256062306a36Sopenharmony_ci * mpi3mr_sastopochg_evt_th - SASTopologyChange evt tophalf
256162306a36Sopenharmony_ci * @mrioc: Adapter instance reference
256262306a36Sopenharmony_ci * @event_reply: event data
256362306a36Sopenharmony_ci *
256462306a36Sopenharmony_ci * Checks for the reason code and based on that either block I/O
256562306a36Sopenharmony_ci * to device, or unblock I/O to the device, or start the device
256662306a36Sopenharmony_ci * removal handshake with reason as remove with the firmware for
256762306a36Sopenharmony_ci * SAS/SATA devices.
256862306a36Sopenharmony_ci *
256962306a36Sopenharmony_ci * Return: Nothing
257062306a36Sopenharmony_ci */
257162306a36Sopenharmony_cistatic void mpi3mr_sastopochg_evt_th(struct mpi3mr_ioc *mrioc,
257262306a36Sopenharmony_ci	struct mpi3_event_notification_reply *event_reply)
257362306a36Sopenharmony_ci{
257462306a36Sopenharmony_ci	struct mpi3_event_data_sas_topology_change_list *topo_evt =
257562306a36Sopenharmony_ci	    (struct mpi3_event_data_sas_topology_change_list *)event_reply->event_data;
257662306a36Sopenharmony_ci	int i;
257762306a36Sopenharmony_ci	u16 handle;
257862306a36Sopenharmony_ci	u8 reason_code;
257962306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev = NULL;
258062306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	for (i = 0; i < topo_evt->num_entries; i++) {
258362306a36Sopenharmony_ci		handle = le16_to_cpu(topo_evt->phy_entry[i].attached_dev_handle);
258462306a36Sopenharmony_ci		if (!handle)
258562306a36Sopenharmony_ci			continue;
258662306a36Sopenharmony_ci		reason_code = topo_evt->phy_entry[i].status &
258762306a36Sopenharmony_ci		    MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
258862306a36Sopenharmony_ci		scsi_tgt_priv_data =  NULL;
258962306a36Sopenharmony_ci		tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
259062306a36Sopenharmony_ci		if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata)
259162306a36Sopenharmony_ci			scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
259262306a36Sopenharmony_ci			    tgtdev->starget->hostdata;
259362306a36Sopenharmony_ci		switch (reason_code) {
259462306a36Sopenharmony_ci		case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
259562306a36Sopenharmony_ci			if (scsi_tgt_priv_data) {
259662306a36Sopenharmony_ci				scsi_tgt_priv_data->dev_removed = 1;
259762306a36Sopenharmony_ci				scsi_tgt_priv_data->dev_removedelay = 0;
259862306a36Sopenharmony_ci				atomic_set(&scsi_tgt_priv_data->block_io, 0);
259962306a36Sopenharmony_ci			}
260062306a36Sopenharmony_ci			mpi3mr_dev_rmhs_send_tm(mrioc, handle, NULL,
260162306a36Sopenharmony_ci			    MPI3_CTRL_OP_REMOVE_DEVICE);
260262306a36Sopenharmony_ci			break;
260362306a36Sopenharmony_ci		case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING:
260462306a36Sopenharmony_ci			if (scsi_tgt_priv_data) {
260562306a36Sopenharmony_ci				scsi_tgt_priv_data->dev_removedelay = 1;
260662306a36Sopenharmony_ci				atomic_inc(&scsi_tgt_priv_data->block_io);
260762306a36Sopenharmony_ci			}
260862306a36Sopenharmony_ci			break;
260962306a36Sopenharmony_ci		case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING:
261062306a36Sopenharmony_ci			if (scsi_tgt_priv_data &&
261162306a36Sopenharmony_ci			    scsi_tgt_priv_data->dev_removedelay) {
261262306a36Sopenharmony_ci				scsi_tgt_priv_data->dev_removedelay = 0;
261362306a36Sopenharmony_ci				atomic_dec_if_positive
261462306a36Sopenharmony_ci				    (&scsi_tgt_priv_data->block_io);
261562306a36Sopenharmony_ci			}
261662306a36Sopenharmony_ci			break;
261762306a36Sopenharmony_ci		case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
261862306a36Sopenharmony_ci		default:
261962306a36Sopenharmony_ci			break;
262062306a36Sopenharmony_ci		}
262162306a36Sopenharmony_ci		if (tgtdev)
262262306a36Sopenharmony_ci			mpi3mr_tgtdev_put(tgtdev);
262362306a36Sopenharmony_ci	}
262462306a36Sopenharmony_ci}
262562306a36Sopenharmony_ci
262662306a36Sopenharmony_ci/**
262762306a36Sopenharmony_ci * mpi3mr_devstatuschg_evt_th - DeviceStatusChange evt tophalf
262862306a36Sopenharmony_ci * @mrioc: Adapter instance reference
262962306a36Sopenharmony_ci * @event_reply: event data
263062306a36Sopenharmony_ci *
263162306a36Sopenharmony_ci * Checks for the reason code and based on that either block I/O
263262306a36Sopenharmony_ci * to device, or unblock I/O to the device, or start the device
263362306a36Sopenharmony_ci * removal handshake with reason as remove/hide acknowledgment
263462306a36Sopenharmony_ci * with the firmware.
263562306a36Sopenharmony_ci *
263662306a36Sopenharmony_ci * Return: Nothing
263762306a36Sopenharmony_ci */
263862306a36Sopenharmony_cistatic void mpi3mr_devstatuschg_evt_th(struct mpi3mr_ioc *mrioc,
263962306a36Sopenharmony_ci	struct mpi3_event_notification_reply *event_reply)
264062306a36Sopenharmony_ci{
264162306a36Sopenharmony_ci	u16 dev_handle = 0;
264262306a36Sopenharmony_ci	u8 ublock = 0, block = 0, hide = 0, delete = 0, remove = 0;
264362306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev = NULL;
264462306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
264562306a36Sopenharmony_ci	struct mpi3_event_data_device_status_change *evtdata =
264662306a36Sopenharmony_ci	    (struct mpi3_event_data_device_status_change *)event_reply->event_data;
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_ci	if (mrioc->stop_drv_processing)
264962306a36Sopenharmony_ci		goto out;
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	dev_handle = le16_to_cpu(evtdata->dev_handle);
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	switch (evtdata->reason_code) {
265462306a36Sopenharmony_ci	case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT:
265562306a36Sopenharmony_ci	case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_STRT:
265662306a36Sopenharmony_ci		block = 1;
265762306a36Sopenharmony_ci		break;
265862306a36Sopenharmony_ci	case MPI3_EVENT_DEV_STAT_RC_HIDDEN:
265962306a36Sopenharmony_ci		delete = 1;
266062306a36Sopenharmony_ci		hide = 1;
266162306a36Sopenharmony_ci		break;
266262306a36Sopenharmony_ci	case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING:
266362306a36Sopenharmony_ci		delete = 1;
266462306a36Sopenharmony_ci		remove = 1;
266562306a36Sopenharmony_ci		break;
266662306a36Sopenharmony_ci	case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_CMP:
266762306a36Sopenharmony_ci	case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_CMP:
266862306a36Sopenharmony_ci		ublock = 1;
266962306a36Sopenharmony_ci		break;
267062306a36Sopenharmony_ci	default:
267162306a36Sopenharmony_ci		break;
267262306a36Sopenharmony_ci	}
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
267562306a36Sopenharmony_ci	if (!tgtdev)
267662306a36Sopenharmony_ci		goto out;
267762306a36Sopenharmony_ci	if (hide)
267862306a36Sopenharmony_ci		tgtdev->is_hidden = hide;
267962306a36Sopenharmony_ci	if (tgtdev->starget && tgtdev->starget->hostdata) {
268062306a36Sopenharmony_ci		scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
268162306a36Sopenharmony_ci		    tgtdev->starget->hostdata;
268262306a36Sopenharmony_ci		if (block)
268362306a36Sopenharmony_ci			atomic_inc(&scsi_tgt_priv_data->block_io);
268462306a36Sopenharmony_ci		if (delete)
268562306a36Sopenharmony_ci			scsi_tgt_priv_data->dev_removed = 1;
268662306a36Sopenharmony_ci		if (ublock)
268762306a36Sopenharmony_ci			atomic_dec_if_positive(&scsi_tgt_priv_data->block_io);
268862306a36Sopenharmony_ci	}
268962306a36Sopenharmony_ci	if (remove)
269062306a36Sopenharmony_ci		mpi3mr_dev_rmhs_send_tm(mrioc, dev_handle, NULL,
269162306a36Sopenharmony_ci		    MPI3_CTRL_OP_REMOVE_DEVICE);
269262306a36Sopenharmony_ci	if (hide)
269362306a36Sopenharmony_ci		mpi3mr_dev_rmhs_send_tm(mrioc, dev_handle, NULL,
269462306a36Sopenharmony_ci		    MPI3_CTRL_OP_HIDDEN_ACK);
269562306a36Sopenharmony_ci
269662306a36Sopenharmony_ciout:
269762306a36Sopenharmony_ci	if (tgtdev)
269862306a36Sopenharmony_ci		mpi3mr_tgtdev_put(tgtdev);
269962306a36Sopenharmony_ci}
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci/**
270262306a36Sopenharmony_ci * mpi3mr_preparereset_evt_th - Prepare for reset event tophalf
270362306a36Sopenharmony_ci * @mrioc: Adapter instance reference
270462306a36Sopenharmony_ci * @event_reply: event data
270562306a36Sopenharmony_ci *
270662306a36Sopenharmony_ci * Blocks and unblocks host level I/O based on the reason code
270762306a36Sopenharmony_ci *
270862306a36Sopenharmony_ci * Return: Nothing
270962306a36Sopenharmony_ci */
271062306a36Sopenharmony_cistatic void mpi3mr_preparereset_evt_th(struct mpi3mr_ioc *mrioc,
271162306a36Sopenharmony_ci	struct mpi3_event_notification_reply *event_reply)
271262306a36Sopenharmony_ci{
271362306a36Sopenharmony_ci	struct mpi3_event_data_prepare_for_reset *evtdata =
271462306a36Sopenharmony_ci	    (struct mpi3_event_data_prepare_for_reset *)event_reply->event_data;
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci	if (evtdata->reason_code == MPI3_EVENT_PREPARE_RESET_RC_START) {
271762306a36Sopenharmony_ci		dprint_event_th(mrioc,
271862306a36Sopenharmony_ci		    "prepare for reset event top half with rc=start\n");
271962306a36Sopenharmony_ci		if (mrioc->prepare_for_reset)
272062306a36Sopenharmony_ci			return;
272162306a36Sopenharmony_ci		mrioc->prepare_for_reset = 1;
272262306a36Sopenharmony_ci		mrioc->prepare_for_reset_timeout_counter = 0;
272362306a36Sopenharmony_ci	} else if (evtdata->reason_code == MPI3_EVENT_PREPARE_RESET_RC_ABORT) {
272462306a36Sopenharmony_ci		dprint_event_th(mrioc,
272562306a36Sopenharmony_ci		    "prepare for reset top half with rc=abort\n");
272662306a36Sopenharmony_ci		mrioc->prepare_for_reset = 0;
272762306a36Sopenharmony_ci		mrioc->prepare_for_reset_timeout_counter = 0;
272862306a36Sopenharmony_ci	}
272962306a36Sopenharmony_ci	if ((event_reply->msg_flags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK)
273062306a36Sopenharmony_ci	    == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED)
273162306a36Sopenharmony_ci		mpi3mr_send_event_ack(mrioc, event_reply->event, NULL,
273262306a36Sopenharmony_ci		    le32_to_cpu(event_reply->event_context));
273362306a36Sopenharmony_ci}
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci/**
273662306a36Sopenharmony_ci * mpi3mr_energypackchg_evt_th - Energy pack change evt tophalf
273762306a36Sopenharmony_ci * @mrioc: Adapter instance reference
273862306a36Sopenharmony_ci * @event_reply: event data
273962306a36Sopenharmony_ci *
274062306a36Sopenharmony_ci * Identifies the new shutdown timeout value and update.
274162306a36Sopenharmony_ci *
274262306a36Sopenharmony_ci * Return: Nothing
274362306a36Sopenharmony_ci */
274462306a36Sopenharmony_cistatic void mpi3mr_energypackchg_evt_th(struct mpi3mr_ioc *mrioc,
274562306a36Sopenharmony_ci	struct mpi3_event_notification_reply *event_reply)
274662306a36Sopenharmony_ci{
274762306a36Sopenharmony_ci	struct mpi3_event_data_energy_pack_change *evtdata =
274862306a36Sopenharmony_ci	    (struct mpi3_event_data_energy_pack_change *)event_reply->event_data;
274962306a36Sopenharmony_ci	u16 shutdown_timeout = le16_to_cpu(evtdata->shutdown_timeout);
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	if (shutdown_timeout <= 0) {
275262306a36Sopenharmony_ci		ioc_warn(mrioc,
275362306a36Sopenharmony_ci		    "%s :Invalid Shutdown Timeout received = %d\n",
275462306a36Sopenharmony_ci		    __func__, shutdown_timeout);
275562306a36Sopenharmony_ci		return;
275662306a36Sopenharmony_ci	}
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	ioc_info(mrioc,
275962306a36Sopenharmony_ci	    "%s :Previous Shutdown Timeout Value = %d New Shutdown Timeout Value = %d\n",
276062306a36Sopenharmony_ci	    __func__, mrioc->facts.shutdown_timeout, shutdown_timeout);
276162306a36Sopenharmony_ci	mrioc->facts.shutdown_timeout = shutdown_timeout;
276262306a36Sopenharmony_ci}
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci/**
276562306a36Sopenharmony_ci * mpi3mr_cablemgmt_evt_th - Cable management event tophalf
276662306a36Sopenharmony_ci * @mrioc: Adapter instance reference
276762306a36Sopenharmony_ci * @event_reply: event data
276862306a36Sopenharmony_ci *
276962306a36Sopenharmony_ci * Displays Cable manegemt event details.
277062306a36Sopenharmony_ci *
277162306a36Sopenharmony_ci * Return: Nothing
277262306a36Sopenharmony_ci */
277362306a36Sopenharmony_cistatic void mpi3mr_cablemgmt_evt_th(struct mpi3mr_ioc *mrioc,
277462306a36Sopenharmony_ci	struct mpi3_event_notification_reply *event_reply)
277562306a36Sopenharmony_ci{
277662306a36Sopenharmony_ci	struct mpi3_event_data_cable_management *evtdata =
277762306a36Sopenharmony_ci	    (struct mpi3_event_data_cable_management *)event_reply->event_data;
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci	switch (evtdata->status) {
278062306a36Sopenharmony_ci	case MPI3_EVENT_CABLE_MGMT_STATUS_INSUFFICIENT_POWER:
278162306a36Sopenharmony_ci	{
278262306a36Sopenharmony_ci		ioc_info(mrioc, "An active cable with receptacle_id %d cannot be powered.\n"
278362306a36Sopenharmony_ci		    "Devices connected to this cable are not detected.\n"
278462306a36Sopenharmony_ci		    "This cable requires %d mW of power.\n",
278562306a36Sopenharmony_ci		    evtdata->receptacle_id,
278662306a36Sopenharmony_ci		    le32_to_cpu(evtdata->active_cable_power_requirement));
278762306a36Sopenharmony_ci		break;
278862306a36Sopenharmony_ci	}
278962306a36Sopenharmony_ci	case MPI3_EVENT_CABLE_MGMT_STATUS_DEGRADED:
279062306a36Sopenharmony_ci	{
279162306a36Sopenharmony_ci		ioc_info(mrioc, "A cable with receptacle_id %d is not running at optimal speed\n",
279262306a36Sopenharmony_ci		    evtdata->receptacle_id);
279362306a36Sopenharmony_ci		break;
279462306a36Sopenharmony_ci	}
279562306a36Sopenharmony_ci	default:
279662306a36Sopenharmony_ci		break;
279762306a36Sopenharmony_ci	}
279862306a36Sopenharmony_ci}
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci/**
280162306a36Sopenharmony_ci * mpi3mr_add_event_wait_for_device_refresh - Add Wait for Device Refresh Event
280262306a36Sopenharmony_ci * @mrioc: Adapter instance reference
280362306a36Sopenharmony_ci *
280462306a36Sopenharmony_ci * Add driver specific event to make sure that the driver won't process the
280562306a36Sopenharmony_ci * events until all the devices are refreshed during soft reset.
280662306a36Sopenharmony_ci *
280762306a36Sopenharmony_ci * Return: Nothing
280862306a36Sopenharmony_ci */
280962306a36Sopenharmony_civoid mpi3mr_add_event_wait_for_device_refresh(struct mpi3mr_ioc *mrioc)
281062306a36Sopenharmony_ci{
281162306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt = NULL;
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci	fwevt = mpi3mr_alloc_fwevt(0);
281462306a36Sopenharmony_ci	if (!fwevt) {
281562306a36Sopenharmony_ci		dprint_event_th(mrioc,
281662306a36Sopenharmony_ci		    "failed to schedule bottom half handler for event(0x%02x)\n",
281762306a36Sopenharmony_ci		    MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH);
281862306a36Sopenharmony_ci		return;
281962306a36Sopenharmony_ci	}
282062306a36Sopenharmony_ci	fwevt->mrioc = mrioc;
282162306a36Sopenharmony_ci	fwevt->event_id = MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH;
282262306a36Sopenharmony_ci	fwevt->send_ack = 0;
282362306a36Sopenharmony_ci	fwevt->process_evt = 1;
282462306a36Sopenharmony_ci	fwevt->evt_ctx = 0;
282562306a36Sopenharmony_ci	fwevt->event_data_size = 0;
282662306a36Sopenharmony_ci	mpi3mr_fwevt_add_to_list(mrioc, fwevt);
282762306a36Sopenharmony_ci}
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci/**
283062306a36Sopenharmony_ci * mpi3mr_os_handle_events - Firmware event handler
283162306a36Sopenharmony_ci * @mrioc: Adapter instance reference
283262306a36Sopenharmony_ci * @event_reply: event data
283362306a36Sopenharmony_ci *
283462306a36Sopenharmony_ci * Identify whteher the event has to handled and acknowledged
283562306a36Sopenharmony_ci * and either process the event in the tophalf and/or schedule a
283662306a36Sopenharmony_ci * bottom half through mpi3mr_fwevt_worker.
283762306a36Sopenharmony_ci *
283862306a36Sopenharmony_ci * Return: Nothing
283962306a36Sopenharmony_ci */
284062306a36Sopenharmony_civoid mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
284162306a36Sopenharmony_ci	struct mpi3_event_notification_reply *event_reply)
284262306a36Sopenharmony_ci{
284362306a36Sopenharmony_ci	u16 evt_type, sz;
284462306a36Sopenharmony_ci	struct mpi3mr_fwevt *fwevt = NULL;
284562306a36Sopenharmony_ci	bool ack_req = 0, process_evt_bh = 0;
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_ci	if (mrioc->stop_drv_processing)
284862306a36Sopenharmony_ci		return;
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	if ((event_reply->msg_flags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK)
285162306a36Sopenharmony_ci	    == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED)
285262306a36Sopenharmony_ci		ack_req = 1;
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci	evt_type = event_reply->event;
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci	switch (evt_type) {
285762306a36Sopenharmony_ci	case MPI3_EVENT_DEVICE_ADDED:
285862306a36Sopenharmony_ci	{
285962306a36Sopenharmony_ci		struct mpi3_device_page0 *dev_pg0 =
286062306a36Sopenharmony_ci		    (struct mpi3_device_page0 *)event_reply->event_data;
286162306a36Sopenharmony_ci		if (mpi3mr_create_tgtdev(mrioc, dev_pg0))
286262306a36Sopenharmony_ci			ioc_err(mrioc,
286362306a36Sopenharmony_ci			    "%s :Failed to add device in the device add event\n",
286462306a36Sopenharmony_ci			    __func__);
286562306a36Sopenharmony_ci		else
286662306a36Sopenharmony_ci			process_evt_bh = 1;
286762306a36Sopenharmony_ci		break;
286862306a36Sopenharmony_ci	}
286962306a36Sopenharmony_ci	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
287062306a36Sopenharmony_ci	{
287162306a36Sopenharmony_ci		process_evt_bh = 1;
287262306a36Sopenharmony_ci		mpi3mr_devstatuschg_evt_th(mrioc, event_reply);
287362306a36Sopenharmony_ci		break;
287462306a36Sopenharmony_ci	}
287562306a36Sopenharmony_ci	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
287662306a36Sopenharmony_ci	{
287762306a36Sopenharmony_ci		process_evt_bh = 1;
287862306a36Sopenharmony_ci		mpi3mr_sastopochg_evt_th(mrioc, event_reply);
287962306a36Sopenharmony_ci		break;
288062306a36Sopenharmony_ci	}
288162306a36Sopenharmony_ci	case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
288262306a36Sopenharmony_ci	{
288362306a36Sopenharmony_ci		process_evt_bh = 1;
288462306a36Sopenharmony_ci		mpi3mr_pcietopochg_evt_th(mrioc, event_reply);
288562306a36Sopenharmony_ci		break;
288662306a36Sopenharmony_ci	}
288762306a36Sopenharmony_ci	case MPI3_EVENT_PREPARE_FOR_RESET:
288862306a36Sopenharmony_ci	{
288962306a36Sopenharmony_ci		mpi3mr_preparereset_evt_th(mrioc, event_reply);
289062306a36Sopenharmony_ci		ack_req = 0;
289162306a36Sopenharmony_ci		break;
289262306a36Sopenharmony_ci	}
289362306a36Sopenharmony_ci	case MPI3_EVENT_DEVICE_INFO_CHANGED:
289462306a36Sopenharmony_ci	case MPI3_EVENT_LOG_DATA:
289562306a36Sopenharmony_ci	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
289662306a36Sopenharmony_ci	case MPI3_EVENT_ENCL_DEVICE_ADDED:
289762306a36Sopenharmony_ci	{
289862306a36Sopenharmony_ci		process_evt_bh = 1;
289962306a36Sopenharmony_ci		break;
290062306a36Sopenharmony_ci	}
290162306a36Sopenharmony_ci	case MPI3_EVENT_ENERGY_PACK_CHANGE:
290262306a36Sopenharmony_ci	{
290362306a36Sopenharmony_ci		mpi3mr_energypackchg_evt_th(mrioc, event_reply);
290462306a36Sopenharmony_ci		break;
290562306a36Sopenharmony_ci	}
290662306a36Sopenharmony_ci	case MPI3_EVENT_CABLE_MGMT:
290762306a36Sopenharmony_ci	{
290862306a36Sopenharmony_ci		mpi3mr_cablemgmt_evt_th(mrioc, event_reply);
290962306a36Sopenharmony_ci		break;
291062306a36Sopenharmony_ci	}
291162306a36Sopenharmony_ci	case MPI3_EVENT_SAS_DISCOVERY:
291262306a36Sopenharmony_ci	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
291362306a36Sopenharmony_ci	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
291462306a36Sopenharmony_ci	case MPI3_EVENT_PCIE_ENUMERATION:
291562306a36Sopenharmony_ci		break;
291662306a36Sopenharmony_ci	default:
291762306a36Sopenharmony_ci		ioc_info(mrioc, "%s :event 0x%02x is not handled\n",
291862306a36Sopenharmony_ci		    __func__, evt_type);
291962306a36Sopenharmony_ci		break;
292062306a36Sopenharmony_ci	}
292162306a36Sopenharmony_ci	if (process_evt_bh || ack_req) {
292262306a36Sopenharmony_ci		sz = event_reply->event_data_length * 4;
292362306a36Sopenharmony_ci		fwevt = mpi3mr_alloc_fwevt(sz);
292462306a36Sopenharmony_ci		if (!fwevt) {
292562306a36Sopenharmony_ci			ioc_info(mrioc, "%s :failure at %s:%d/%s()!\n",
292662306a36Sopenharmony_ci			    __func__, __FILE__, __LINE__, __func__);
292762306a36Sopenharmony_ci			return;
292862306a36Sopenharmony_ci		}
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci		memcpy(fwevt->event_data, event_reply->event_data, sz);
293162306a36Sopenharmony_ci		fwevt->mrioc = mrioc;
293262306a36Sopenharmony_ci		fwevt->event_id = evt_type;
293362306a36Sopenharmony_ci		fwevt->send_ack = ack_req;
293462306a36Sopenharmony_ci		fwevt->process_evt = process_evt_bh;
293562306a36Sopenharmony_ci		fwevt->evt_ctx = le32_to_cpu(event_reply->event_context);
293662306a36Sopenharmony_ci		mpi3mr_fwevt_add_to_list(mrioc, fwevt);
293762306a36Sopenharmony_ci	}
293862306a36Sopenharmony_ci}
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_ci/**
294162306a36Sopenharmony_ci * mpi3mr_setup_eedp - Setup EEDP information in MPI3 SCSI IO
294262306a36Sopenharmony_ci * @mrioc: Adapter instance reference
294362306a36Sopenharmony_ci * @scmd: SCSI command reference
294462306a36Sopenharmony_ci * @scsiio_req: MPI3 SCSI IO request
294562306a36Sopenharmony_ci *
294662306a36Sopenharmony_ci * Identifies the protection information flags from the SCSI
294762306a36Sopenharmony_ci * command and set appropriate flags in the MPI3 SCSI IO
294862306a36Sopenharmony_ci * request.
294962306a36Sopenharmony_ci *
295062306a36Sopenharmony_ci * Return: Nothing
295162306a36Sopenharmony_ci */
295262306a36Sopenharmony_cistatic void mpi3mr_setup_eedp(struct mpi3mr_ioc *mrioc,
295362306a36Sopenharmony_ci	struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req)
295462306a36Sopenharmony_ci{
295562306a36Sopenharmony_ci	u16 eedp_flags = 0;
295662306a36Sopenharmony_ci	unsigned char prot_op = scsi_get_prot_op(scmd);
295762306a36Sopenharmony_ci
295862306a36Sopenharmony_ci	switch (prot_op) {
295962306a36Sopenharmony_ci	case SCSI_PROT_NORMAL:
296062306a36Sopenharmony_ci		return;
296162306a36Sopenharmony_ci	case SCSI_PROT_READ_STRIP:
296262306a36Sopenharmony_ci		eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE;
296362306a36Sopenharmony_ci		break;
296462306a36Sopenharmony_ci	case SCSI_PROT_WRITE_INSERT:
296562306a36Sopenharmony_ci		eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_INSERT;
296662306a36Sopenharmony_ci		break;
296762306a36Sopenharmony_ci	case SCSI_PROT_READ_INSERT:
296862306a36Sopenharmony_ci		eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_INSERT;
296962306a36Sopenharmony_ci		scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID;
297062306a36Sopenharmony_ci		break;
297162306a36Sopenharmony_ci	case SCSI_PROT_WRITE_STRIP:
297262306a36Sopenharmony_ci		eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE;
297362306a36Sopenharmony_ci		scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID;
297462306a36Sopenharmony_ci		break;
297562306a36Sopenharmony_ci	case SCSI_PROT_READ_PASS:
297662306a36Sopenharmony_ci		eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK;
297762306a36Sopenharmony_ci		scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID;
297862306a36Sopenharmony_ci		break;
297962306a36Sopenharmony_ci	case SCSI_PROT_WRITE_PASS:
298062306a36Sopenharmony_ci		if (scmd->prot_flags & SCSI_PROT_IP_CHECKSUM) {
298162306a36Sopenharmony_ci			eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REGEN;
298262306a36Sopenharmony_ci			scsiio_req->sgl[0].eedp.application_tag_translation_mask =
298362306a36Sopenharmony_ci			    0xffff;
298462306a36Sopenharmony_ci		} else
298562306a36Sopenharmony_ci			eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK;
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci		scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID;
298862306a36Sopenharmony_ci		break;
298962306a36Sopenharmony_ci	default:
299062306a36Sopenharmony_ci		return;
299162306a36Sopenharmony_ci	}
299262306a36Sopenharmony_ci
299362306a36Sopenharmony_ci	if (scmd->prot_flags & SCSI_PROT_GUARD_CHECK)
299462306a36Sopenharmony_ci		eedp_flags |= MPI3_EEDPFLAGS_CHK_GUARD;
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci	if (scmd->prot_flags & SCSI_PROT_IP_CHECKSUM)
299762306a36Sopenharmony_ci		eedp_flags |= MPI3_EEDPFLAGS_HOST_GUARD_IP_CHKSUM;
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_ci	if (scmd->prot_flags & SCSI_PROT_REF_CHECK) {
300062306a36Sopenharmony_ci		eedp_flags |= MPI3_EEDPFLAGS_CHK_REF_TAG |
300162306a36Sopenharmony_ci			MPI3_EEDPFLAGS_INCR_PRI_REF_TAG;
300262306a36Sopenharmony_ci		scsiio_req->cdb.eedp32.primary_reference_tag =
300362306a36Sopenharmony_ci			cpu_to_be32(scsi_prot_ref_tag(scmd));
300462306a36Sopenharmony_ci	}
300562306a36Sopenharmony_ci
300662306a36Sopenharmony_ci	if (scmd->prot_flags & SCSI_PROT_REF_INCREMENT)
300762306a36Sopenharmony_ci		eedp_flags |= MPI3_EEDPFLAGS_INCR_PRI_REF_TAG;
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci	eedp_flags |= MPI3_EEDPFLAGS_ESC_MODE_APPTAG_DISABLE;
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci	switch (scsi_prot_interval(scmd)) {
301262306a36Sopenharmony_ci	case 512:
301362306a36Sopenharmony_ci		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_512;
301462306a36Sopenharmony_ci		break;
301562306a36Sopenharmony_ci	case 520:
301662306a36Sopenharmony_ci		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_520;
301762306a36Sopenharmony_ci		break;
301862306a36Sopenharmony_ci	case 4080:
301962306a36Sopenharmony_ci		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4080;
302062306a36Sopenharmony_ci		break;
302162306a36Sopenharmony_ci	case 4088:
302262306a36Sopenharmony_ci		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4088;
302362306a36Sopenharmony_ci		break;
302462306a36Sopenharmony_ci	case 4096:
302562306a36Sopenharmony_ci		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4096;
302662306a36Sopenharmony_ci		break;
302762306a36Sopenharmony_ci	case 4104:
302862306a36Sopenharmony_ci		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4104;
302962306a36Sopenharmony_ci		break;
303062306a36Sopenharmony_ci	case 4160:
303162306a36Sopenharmony_ci		scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4160;
303262306a36Sopenharmony_ci		break;
303362306a36Sopenharmony_ci	default:
303462306a36Sopenharmony_ci		break;
303562306a36Sopenharmony_ci	}
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci	scsiio_req->sgl[0].eedp.eedp_flags = cpu_to_le16(eedp_flags);
303862306a36Sopenharmony_ci	scsiio_req->sgl[0].eedp.flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_EXTENDED;
303962306a36Sopenharmony_ci}
304062306a36Sopenharmony_ci
304162306a36Sopenharmony_ci/**
304262306a36Sopenharmony_ci * mpi3mr_build_sense_buffer - Map sense information
304362306a36Sopenharmony_ci * @desc: Sense type
304462306a36Sopenharmony_ci * @buf: Sense buffer to populate
304562306a36Sopenharmony_ci * @key: Sense key
304662306a36Sopenharmony_ci * @asc: Additional sense code
304762306a36Sopenharmony_ci * @ascq: Additional sense code qualifier
304862306a36Sopenharmony_ci *
304962306a36Sopenharmony_ci * Maps the given sense information into either descriptor or
305062306a36Sopenharmony_ci * fixed format sense data.
305162306a36Sopenharmony_ci *
305262306a36Sopenharmony_ci * Return: Nothing
305362306a36Sopenharmony_ci */
305462306a36Sopenharmony_cistatic inline void mpi3mr_build_sense_buffer(int desc, u8 *buf, u8 key,
305562306a36Sopenharmony_ci	u8 asc, u8 ascq)
305662306a36Sopenharmony_ci{
305762306a36Sopenharmony_ci	if (desc) {
305862306a36Sopenharmony_ci		buf[0] = 0x72;	/* descriptor, current */
305962306a36Sopenharmony_ci		buf[1] = key;
306062306a36Sopenharmony_ci		buf[2] = asc;
306162306a36Sopenharmony_ci		buf[3] = ascq;
306262306a36Sopenharmony_ci		buf[7] = 0;
306362306a36Sopenharmony_ci	} else {
306462306a36Sopenharmony_ci		buf[0] = 0x70;	/* fixed, current */
306562306a36Sopenharmony_ci		buf[2] = key;
306662306a36Sopenharmony_ci		buf[7] = 0xa;
306762306a36Sopenharmony_ci		buf[12] = asc;
306862306a36Sopenharmony_ci		buf[13] = ascq;
306962306a36Sopenharmony_ci	}
307062306a36Sopenharmony_ci}
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ci/**
307362306a36Sopenharmony_ci * mpi3mr_map_eedp_error - Map EEDP errors from IOC status
307462306a36Sopenharmony_ci * @scmd: SCSI command reference
307562306a36Sopenharmony_ci * @ioc_status: status of MPI3 request
307662306a36Sopenharmony_ci *
307762306a36Sopenharmony_ci * Maps the EEDP error status of the SCSI IO request to sense
307862306a36Sopenharmony_ci * data.
307962306a36Sopenharmony_ci *
308062306a36Sopenharmony_ci * Return: Nothing
308162306a36Sopenharmony_ci */
308262306a36Sopenharmony_cistatic void mpi3mr_map_eedp_error(struct scsi_cmnd *scmd,
308362306a36Sopenharmony_ci	u16 ioc_status)
308462306a36Sopenharmony_ci{
308562306a36Sopenharmony_ci	u8 ascq = 0;
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci	switch (ioc_status) {
308862306a36Sopenharmony_ci	case MPI3_IOCSTATUS_EEDP_GUARD_ERROR:
308962306a36Sopenharmony_ci		ascq = 0x01;
309062306a36Sopenharmony_ci		break;
309162306a36Sopenharmony_ci	case MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR:
309262306a36Sopenharmony_ci		ascq = 0x02;
309362306a36Sopenharmony_ci		break;
309462306a36Sopenharmony_ci	case MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR:
309562306a36Sopenharmony_ci		ascq = 0x03;
309662306a36Sopenharmony_ci		break;
309762306a36Sopenharmony_ci	default:
309862306a36Sopenharmony_ci		ascq = 0x00;
309962306a36Sopenharmony_ci		break;
310062306a36Sopenharmony_ci	}
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	mpi3mr_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
310362306a36Sopenharmony_ci	    0x10, ascq);
310462306a36Sopenharmony_ci	scmd->result = (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
310562306a36Sopenharmony_ci}
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci/**
310862306a36Sopenharmony_ci * mpi3mr_process_op_reply_desc - reply descriptor handler
310962306a36Sopenharmony_ci * @mrioc: Adapter instance reference
311062306a36Sopenharmony_ci * @reply_desc: Operational reply descriptor
311162306a36Sopenharmony_ci * @reply_dma: place holder for reply DMA address
311262306a36Sopenharmony_ci * @qidx: Operational queue index
311362306a36Sopenharmony_ci *
311462306a36Sopenharmony_ci * Process the operational reply descriptor and identifies the
311562306a36Sopenharmony_ci * descriptor type. Based on the descriptor map the MPI3 request
311662306a36Sopenharmony_ci * status to a SCSI command status and calls scsi_done call
311762306a36Sopenharmony_ci * back.
311862306a36Sopenharmony_ci *
311962306a36Sopenharmony_ci * Return: Nothing
312062306a36Sopenharmony_ci */
312162306a36Sopenharmony_civoid mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc,
312262306a36Sopenharmony_ci	struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma, u16 qidx)
312362306a36Sopenharmony_ci{
312462306a36Sopenharmony_ci	u16 reply_desc_type, host_tag = 0;
312562306a36Sopenharmony_ci	u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
312662306a36Sopenharmony_ci	u32 ioc_loginfo = 0;
312762306a36Sopenharmony_ci	struct mpi3_status_reply_descriptor *status_desc = NULL;
312862306a36Sopenharmony_ci	struct mpi3_address_reply_descriptor *addr_desc = NULL;
312962306a36Sopenharmony_ci	struct mpi3_success_reply_descriptor *success_desc = NULL;
313062306a36Sopenharmony_ci	struct mpi3_scsi_io_reply *scsi_reply = NULL;
313162306a36Sopenharmony_ci	struct scsi_cmnd *scmd = NULL;
313262306a36Sopenharmony_ci	struct scmd_priv *priv = NULL;
313362306a36Sopenharmony_ci	u8 *sense_buf = NULL;
313462306a36Sopenharmony_ci	u8 scsi_state = 0, scsi_status = 0, sense_state = 0;
313562306a36Sopenharmony_ci	u32 xfer_count = 0, sense_count = 0, resp_data = 0;
313662306a36Sopenharmony_ci	u16 dev_handle = 0xFFFF;
313762306a36Sopenharmony_ci	struct scsi_sense_hdr sshdr;
313862306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *stgt_priv_data = NULL;
313962306a36Sopenharmony_ci	struct mpi3mr_sdev_priv_data *sdev_priv_data = NULL;
314062306a36Sopenharmony_ci	u32 ioc_pend_data_len = 0, tg_pend_data_len = 0, data_len_blks = 0;
314162306a36Sopenharmony_ci	struct mpi3mr_throttle_group_info *tg = NULL;
314262306a36Sopenharmony_ci	u8 throttle_enabled_dev = 0;
314362306a36Sopenharmony_ci
314462306a36Sopenharmony_ci	*reply_dma = 0;
314562306a36Sopenharmony_ci	reply_desc_type = le16_to_cpu(reply_desc->reply_flags) &
314662306a36Sopenharmony_ci	    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
314762306a36Sopenharmony_ci	switch (reply_desc_type) {
314862306a36Sopenharmony_ci	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
314962306a36Sopenharmony_ci		status_desc = (struct mpi3_status_reply_descriptor *)reply_desc;
315062306a36Sopenharmony_ci		host_tag = le16_to_cpu(status_desc->host_tag);
315162306a36Sopenharmony_ci		ioc_status = le16_to_cpu(status_desc->ioc_status);
315262306a36Sopenharmony_ci		if (ioc_status &
315362306a36Sopenharmony_ci		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
315462306a36Sopenharmony_ci			ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
315562306a36Sopenharmony_ci		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
315662306a36Sopenharmony_ci		break;
315762306a36Sopenharmony_ci	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
315862306a36Sopenharmony_ci		addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
315962306a36Sopenharmony_ci		*reply_dma = le64_to_cpu(addr_desc->reply_frame_address);
316062306a36Sopenharmony_ci		scsi_reply = mpi3mr_get_reply_virt_addr(mrioc,
316162306a36Sopenharmony_ci		    *reply_dma);
316262306a36Sopenharmony_ci		if (!scsi_reply) {
316362306a36Sopenharmony_ci			panic("%s: scsi_reply is NULL, this shouldn't happen\n",
316462306a36Sopenharmony_ci			    mrioc->name);
316562306a36Sopenharmony_ci			goto out;
316662306a36Sopenharmony_ci		}
316762306a36Sopenharmony_ci		host_tag = le16_to_cpu(scsi_reply->host_tag);
316862306a36Sopenharmony_ci		ioc_status = le16_to_cpu(scsi_reply->ioc_status);
316962306a36Sopenharmony_ci		scsi_status = scsi_reply->scsi_status;
317062306a36Sopenharmony_ci		scsi_state = scsi_reply->scsi_state;
317162306a36Sopenharmony_ci		dev_handle = le16_to_cpu(scsi_reply->dev_handle);
317262306a36Sopenharmony_ci		sense_state = (scsi_state & MPI3_SCSI_STATE_SENSE_MASK);
317362306a36Sopenharmony_ci		xfer_count = le32_to_cpu(scsi_reply->transfer_count);
317462306a36Sopenharmony_ci		sense_count = le32_to_cpu(scsi_reply->sense_count);
317562306a36Sopenharmony_ci		resp_data = le32_to_cpu(scsi_reply->response_data);
317662306a36Sopenharmony_ci		sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
317762306a36Sopenharmony_ci		    le64_to_cpu(scsi_reply->sense_data_buffer_address));
317862306a36Sopenharmony_ci		if (ioc_status &
317962306a36Sopenharmony_ci		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
318062306a36Sopenharmony_ci			ioc_loginfo = le32_to_cpu(scsi_reply->ioc_log_info);
318162306a36Sopenharmony_ci		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
318262306a36Sopenharmony_ci		if (sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY)
318362306a36Sopenharmony_ci			panic("%s: Ran out of sense buffers\n", mrioc->name);
318462306a36Sopenharmony_ci		break;
318562306a36Sopenharmony_ci	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
318662306a36Sopenharmony_ci		success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
318762306a36Sopenharmony_ci		host_tag = le16_to_cpu(success_desc->host_tag);
318862306a36Sopenharmony_ci		break;
318962306a36Sopenharmony_ci	default:
319062306a36Sopenharmony_ci		break;
319162306a36Sopenharmony_ci	}
319262306a36Sopenharmony_ci	scmd = mpi3mr_scmd_from_host_tag(mrioc, host_tag, qidx);
319362306a36Sopenharmony_ci	if (!scmd) {
319462306a36Sopenharmony_ci		panic("%s: Cannot Identify scmd for host_tag 0x%x\n",
319562306a36Sopenharmony_ci		    mrioc->name, host_tag);
319662306a36Sopenharmony_ci		goto out;
319762306a36Sopenharmony_ci	}
319862306a36Sopenharmony_ci	priv = scsi_cmd_priv(scmd);
319962306a36Sopenharmony_ci
320062306a36Sopenharmony_ci	data_len_blks = scsi_bufflen(scmd) >> 9;
320162306a36Sopenharmony_ci	sdev_priv_data = scmd->device->hostdata;
320262306a36Sopenharmony_ci	if (sdev_priv_data) {
320362306a36Sopenharmony_ci		stgt_priv_data = sdev_priv_data->tgt_priv_data;
320462306a36Sopenharmony_ci		if (stgt_priv_data) {
320562306a36Sopenharmony_ci			tg = stgt_priv_data->throttle_group;
320662306a36Sopenharmony_ci			throttle_enabled_dev =
320762306a36Sopenharmony_ci			    stgt_priv_data->io_throttle_enabled;
320862306a36Sopenharmony_ci		}
320962306a36Sopenharmony_ci	}
321062306a36Sopenharmony_ci	if (unlikely((data_len_blks >= mrioc->io_throttle_data_length) &&
321162306a36Sopenharmony_ci	    throttle_enabled_dev)) {
321262306a36Sopenharmony_ci		ioc_pend_data_len = atomic_sub_return(data_len_blks,
321362306a36Sopenharmony_ci		    &mrioc->pend_large_data_sz);
321462306a36Sopenharmony_ci		if (tg) {
321562306a36Sopenharmony_ci			tg_pend_data_len = atomic_sub_return(data_len_blks,
321662306a36Sopenharmony_ci			    &tg->pend_large_data_sz);
321762306a36Sopenharmony_ci			if (tg->io_divert  && ((ioc_pend_data_len <=
321862306a36Sopenharmony_ci			    mrioc->io_throttle_low) &&
321962306a36Sopenharmony_ci			    (tg_pend_data_len <= tg->low))) {
322062306a36Sopenharmony_ci				tg->io_divert = 0;
322162306a36Sopenharmony_ci				mpi3mr_set_io_divert_for_all_vd_in_tg(
322262306a36Sopenharmony_ci				    mrioc, tg, 0);
322362306a36Sopenharmony_ci			}
322462306a36Sopenharmony_ci		} else {
322562306a36Sopenharmony_ci			if (ioc_pend_data_len <= mrioc->io_throttle_low)
322662306a36Sopenharmony_ci				stgt_priv_data->io_divert = 0;
322762306a36Sopenharmony_ci		}
322862306a36Sopenharmony_ci	} else if (unlikely((stgt_priv_data && stgt_priv_data->io_divert))) {
322962306a36Sopenharmony_ci		ioc_pend_data_len = atomic_read(&mrioc->pend_large_data_sz);
323062306a36Sopenharmony_ci		if (!tg) {
323162306a36Sopenharmony_ci			if (ioc_pend_data_len <= mrioc->io_throttle_low)
323262306a36Sopenharmony_ci				stgt_priv_data->io_divert = 0;
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ci		} else if (ioc_pend_data_len <= mrioc->io_throttle_low) {
323562306a36Sopenharmony_ci			tg_pend_data_len = atomic_read(&tg->pend_large_data_sz);
323662306a36Sopenharmony_ci			if (tg->io_divert  && (tg_pend_data_len <= tg->low)) {
323762306a36Sopenharmony_ci				tg->io_divert = 0;
323862306a36Sopenharmony_ci				mpi3mr_set_io_divert_for_all_vd_in_tg(
323962306a36Sopenharmony_ci				    mrioc, tg, 0);
324062306a36Sopenharmony_ci			}
324162306a36Sopenharmony_ci		}
324262306a36Sopenharmony_ci	}
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci	if (success_desc) {
324562306a36Sopenharmony_ci		scmd->result = DID_OK << 16;
324662306a36Sopenharmony_ci		goto out_success;
324762306a36Sopenharmony_ci	}
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_ci	scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_count);
325062306a36Sopenharmony_ci	if (ioc_status == MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN &&
325162306a36Sopenharmony_ci	    xfer_count == 0 && (scsi_status == MPI3_SCSI_STATUS_BUSY ||
325262306a36Sopenharmony_ci	    scsi_status == MPI3_SCSI_STATUS_RESERVATION_CONFLICT ||
325362306a36Sopenharmony_ci	    scsi_status == MPI3_SCSI_STATUS_TASK_SET_FULL))
325462306a36Sopenharmony_ci		ioc_status = MPI3_IOCSTATUS_SUCCESS;
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_ci	if ((sense_state == MPI3_SCSI_STATE_SENSE_VALID) && sense_count &&
325762306a36Sopenharmony_ci	    sense_buf) {
325862306a36Sopenharmony_ci		u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, sense_count);
325962306a36Sopenharmony_ci
326062306a36Sopenharmony_ci		memcpy(scmd->sense_buffer, sense_buf, sz);
326162306a36Sopenharmony_ci	}
326262306a36Sopenharmony_ci
326362306a36Sopenharmony_ci	switch (ioc_status) {
326462306a36Sopenharmony_ci	case MPI3_IOCSTATUS_BUSY:
326562306a36Sopenharmony_ci	case MPI3_IOCSTATUS_INSUFFICIENT_RESOURCES:
326662306a36Sopenharmony_ci		scmd->result = SAM_STAT_BUSY;
326762306a36Sopenharmony_ci		break;
326862306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
326962306a36Sopenharmony_ci		scmd->result = DID_NO_CONNECT << 16;
327062306a36Sopenharmony_ci		break;
327162306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED:
327262306a36Sopenharmony_ci		scmd->result = DID_SOFT_ERROR << 16;
327362306a36Sopenharmony_ci		break;
327462306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SCSI_TASK_TERMINATED:
327562306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SCSI_EXT_TERMINATED:
327662306a36Sopenharmony_ci		scmd->result = DID_RESET << 16;
327762306a36Sopenharmony_ci		break;
327862306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
327962306a36Sopenharmony_ci		if ((xfer_count == 0) || (scmd->underflow > xfer_count))
328062306a36Sopenharmony_ci			scmd->result = DID_SOFT_ERROR << 16;
328162306a36Sopenharmony_ci		else
328262306a36Sopenharmony_ci			scmd->result = (DID_OK << 16) | scsi_status;
328362306a36Sopenharmony_ci		break;
328462306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN:
328562306a36Sopenharmony_ci		scmd->result = (DID_OK << 16) | scsi_status;
328662306a36Sopenharmony_ci		if (sense_state == MPI3_SCSI_STATE_SENSE_VALID)
328762306a36Sopenharmony_ci			break;
328862306a36Sopenharmony_ci		if (xfer_count < scmd->underflow) {
328962306a36Sopenharmony_ci			if (scsi_status == SAM_STAT_BUSY)
329062306a36Sopenharmony_ci				scmd->result = SAM_STAT_BUSY;
329162306a36Sopenharmony_ci			else
329262306a36Sopenharmony_ci				scmd->result = DID_SOFT_ERROR << 16;
329362306a36Sopenharmony_ci		} else if ((scsi_state & (MPI3_SCSI_STATE_NO_SCSI_STATUS)) ||
329462306a36Sopenharmony_ci		    (sense_state != MPI3_SCSI_STATE_SENSE_NOT_AVAILABLE))
329562306a36Sopenharmony_ci			scmd->result = DID_SOFT_ERROR << 16;
329662306a36Sopenharmony_ci		else if (scsi_state & MPI3_SCSI_STATE_TERMINATED)
329762306a36Sopenharmony_ci			scmd->result = DID_RESET << 16;
329862306a36Sopenharmony_ci		break;
329962306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SCSI_DATA_OVERRUN:
330062306a36Sopenharmony_ci		scsi_set_resid(scmd, 0);
330162306a36Sopenharmony_ci		fallthrough;
330262306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR:
330362306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SUCCESS:
330462306a36Sopenharmony_ci		scmd->result = (DID_OK << 16) | scsi_status;
330562306a36Sopenharmony_ci		if ((scsi_state & (MPI3_SCSI_STATE_NO_SCSI_STATUS)) ||
330662306a36Sopenharmony_ci		    (sense_state == MPI3_SCSI_STATE_SENSE_FAILED) ||
330762306a36Sopenharmony_ci			(sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY))
330862306a36Sopenharmony_ci			scmd->result = DID_SOFT_ERROR << 16;
330962306a36Sopenharmony_ci		else if (scsi_state & MPI3_SCSI_STATE_TERMINATED)
331062306a36Sopenharmony_ci			scmd->result = DID_RESET << 16;
331162306a36Sopenharmony_ci		break;
331262306a36Sopenharmony_ci	case MPI3_IOCSTATUS_EEDP_GUARD_ERROR:
331362306a36Sopenharmony_ci	case MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR:
331462306a36Sopenharmony_ci	case MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR:
331562306a36Sopenharmony_ci		mpi3mr_map_eedp_error(scmd, ioc_status);
331662306a36Sopenharmony_ci		break;
331762306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SCSI_PROTOCOL_ERROR:
331862306a36Sopenharmony_ci	case MPI3_IOCSTATUS_INVALID_FUNCTION:
331962306a36Sopenharmony_ci	case MPI3_IOCSTATUS_INVALID_SGL:
332062306a36Sopenharmony_ci	case MPI3_IOCSTATUS_INTERNAL_ERROR:
332162306a36Sopenharmony_ci	case MPI3_IOCSTATUS_INVALID_FIELD:
332262306a36Sopenharmony_ci	case MPI3_IOCSTATUS_INVALID_STATE:
332362306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SCSI_IO_DATA_ERROR:
332462306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
332562306a36Sopenharmony_ci	case MPI3_IOCSTATUS_INSUFFICIENT_POWER:
332662306a36Sopenharmony_ci	default:
332762306a36Sopenharmony_ci		scmd->result = DID_SOFT_ERROR << 16;
332862306a36Sopenharmony_ci		break;
332962306a36Sopenharmony_ci	}
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_ci	if (scmd->result != (DID_OK << 16) && (scmd->cmnd[0] != ATA_12) &&
333262306a36Sopenharmony_ci	    (scmd->cmnd[0] != ATA_16) &&
333362306a36Sopenharmony_ci	    mrioc->logging_level & MPI3_DEBUG_SCSI_ERROR) {
333462306a36Sopenharmony_ci		ioc_info(mrioc, "%s :scmd->result 0x%x\n", __func__,
333562306a36Sopenharmony_ci		    scmd->result);
333662306a36Sopenharmony_ci		scsi_print_command(scmd);
333762306a36Sopenharmony_ci		ioc_info(mrioc,
333862306a36Sopenharmony_ci		    "%s :Command issued to handle 0x%02x returned with error 0x%04x loginfo 0x%08x, qid %d\n",
333962306a36Sopenharmony_ci		    __func__, dev_handle, ioc_status, ioc_loginfo,
334062306a36Sopenharmony_ci		    priv->req_q_idx + 1);
334162306a36Sopenharmony_ci		ioc_info(mrioc,
334262306a36Sopenharmony_ci		    " host_tag %d scsi_state 0x%02x scsi_status 0x%02x, xfer_cnt %d resp_data 0x%x\n",
334362306a36Sopenharmony_ci		    host_tag, scsi_state, scsi_status, xfer_count, resp_data);
334462306a36Sopenharmony_ci		if (sense_buf) {
334562306a36Sopenharmony_ci			scsi_normalize_sense(sense_buf, sense_count, &sshdr);
334662306a36Sopenharmony_ci			ioc_info(mrioc,
334762306a36Sopenharmony_ci			    "%s :sense_count 0x%x, sense_key 0x%x ASC 0x%x, ASCQ 0x%x\n",
334862306a36Sopenharmony_ci			    __func__, sense_count, sshdr.sense_key,
334962306a36Sopenharmony_ci			    sshdr.asc, sshdr.ascq);
335062306a36Sopenharmony_ci		}
335162306a36Sopenharmony_ci	}
335262306a36Sopenharmony_ciout_success:
335362306a36Sopenharmony_ci	if (priv->meta_sg_valid) {
335462306a36Sopenharmony_ci		dma_unmap_sg(&mrioc->pdev->dev, scsi_prot_sglist(scmd),
335562306a36Sopenharmony_ci		    scsi_prot_sg_count(scmd), scmd->sc_data_direction);
335662306a36Sopenharmony_ci	}
335762306a36Sopenharmony_ci	mpi3mr_clear_scmd_priv(mrioc, scmd);
335862306a36Sopenharmony_ci	scsi_dma_unmap(scmd);
335962306a36Sopenharmony_ci	scsi_done(scmd);
336062306a36Sopenharmony_ciout:
336162306a36Sopenharmony_ci	if (sense_buf)
336262306a36Sopenharmony_ci		mpi3mr_repost_sense_buf(mrioc,
336362306a36Sopenharmony_ci		    le64_to_cpu(scsi_reply->sense_data_buffer_address));
336462306a36Sopenharmony_ci}
336562306a36Sopenharmony_ci
336662306a36Sopenharmony_ci/**
336762306a36Sopenharmony_ci * mpi3mr_get_chain_idx - get free chain buffer index
336862306a36Sopenharmony_ci * @mrioc: Adapter instance reference
336962306a36Sopenharmony_ci *
337062306a36Sopenharmony_ci * Try to get a free chain buffer index from the free pool.
337162306a36Sopenharmony_ci *
337262306a36Sopenharmony_ci * Return: -1 on failure or the free chain buffer index
337362306a36Sopenharmony_ci */
337462306a36Sopenharmony_cistatic int mpi3mr_get_chain_idx(struct mpi3mr_ioc *mrioc)
337562306a36Sopenharmony_ci{
337662306a36Sopenharmony_ci	u8 retry_count = 5;
337762306a36Sopenharmony_ci	int cmd_idx = -1;
337862306a36Sopenharmony_ci	unsigned long flags;
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->chain_buf_lock, flags);
338162306a36Sopenharmony_ci	do {
338262306a36Sopenharmony_ci		cmd_idx = find_first_zero_bit(mrioc->chain_bitmap,
338362306a36Sopenharmony_ci		    mrioc->chain_buf_count);
338462306a36Sopenharmony_ci		if (cmd_idx < mrioc->chain_buf_count) {
338562306a36Sopenharmony_ci			set_bit(cmd_idx, mrioc->chain_bitmap);
338662306a36Sopenharmony_ci			break;
338762306a36Sopenharmony_ci		}
338862306a36Sopenharmony_ci		cmd_idx = -1;
338962306a36Sopenharmony_ci	} while (retry_count--);
339062306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->chain_buf_lock, flags);
339162306a36Sopenharmony_ci	return cmd_idx;
339262306a36Sopenharmony_ci}
339362306a36Sopenharmony_ci
339462306a36Sopenharmony_ci/**
339562306a36Sopenharmony_ci * mpi3mr_prepare_sg_scmd - build scatter gather list
339662306a36Sopenharmony_ci * @mrioc: Adapter instance reference
339762306a36Sopenharmony_ci * @scmd: SCSI command reference
339862306a36Sopenharmony_ci * @scsiio_req: MPI3 SCSI IO request
339962306a36Sopenharmony_ci *
340062306a36Sopenharmony_ci * This function maps SCSI command's data and protection SGEs to
340162306a36Sopenharmony_ci * MPI request SGEs. If required additional 4K chain buffer is
340262306a36Sopenharmony_ci * used to send the SGEs.
340362306a36Sopenharmony_ci *
340462306a36Sopenharmony_ci * Return: 0 on success, -ENOMEM on dma_map_sg failure
340562306a36Sopenharmony_ci */
340662306a36Sopenharmony_cistatic int mpi3mr_prepare_sg_scmd(struct mpi3mr_ioc *mrioc,
340762306a36Sopenharmony_ci	struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req)
340862306a36Sopenharmony_ci{
340962306a36Sopenharmony_ci	dma_addr_t chain_dma;
341062306a36Sopenharmony_ci	struct scatterlist *sg_scmd;
341162306a36Sopenharmony_ci	void *sg_local, *chain;
341262306a36Sopenharmony_ci	u32 chain_length;
341362306a36Sopenharmony_ci	int sges_left, chain_idx;
341462306a36Sopenharmony_ci	u32 sges_in_segment;
341562306a36Sopenharmony_ci	u8 simple_sgl_flags;
341662306a36Sopenharmony_ci	u8 simple_sgl_flags_last;
341762306a36Sopenharmony_ci	u8 last_chain_sgl_flags;
341862306a36Sopenharmony_ci	struct chain_element *chain_req;
341962306a36Sopenharmony_ci	struct scmd_priv *priv = NULL;
342062306a36Sopenharmony_ci	u32 meta_sg = le32_to_cpu(scsiio_req->flags) &
342162306a36Sopenharmony_ci	    MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI;
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_ci	priv = scsi_cmd_priv(scmd);
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci	simple_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE |
342662306a36Sopenharmony_ci	    MPI3_SGE_FLAGS_DLAS_SYSTEM;
342762306a36Sopenharmony_ci	simple_sgl_flags_last = simple_sgl_flags |
342862306a36Sopenharmony_ci	    MPI3_SGE_FLAGS_END_OF_LIST;
342962306a36Sopenharmony_ci	last_chain_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN |
343062306a36Sopenharmony_ci	    MPI3_SGE_FLAGS_DLAS_SYSTEM;
343162306a36Sopenharmony_ci
343262306a36Sopenharmony_ci	if (meta_sg)
343362306a36Sopenharmony_ci		sg_local = &scsiio_req->sgl[MPI3_SCSIIO_METASGL_INDEX];
343462306a36Sopenharmony_ci	else
343562306a36Sopenharmony_ci		sg_local = &scsiio_req->sgl;
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci	if (!scsiio_req->data_length && !meta_sg) {
343862306a36Sopenharmony_ci		mpi3mr_build_zero_len_sge(sg_local);
343962306a36Sopenharmony_ci		return 0;
344062306a36Sopenharmony_ci	}
344162306a36Sopenharmony_ci
344262306a36Sopenharmony_ci	if (meta_sg) {
344362306a36Sopenharmony_ci		sg_scmd = scsi_prot_sglist(scmd);
344462306a36Sopenharmony_ci		sges_left = dma_map_sg(&mrioc->pdev->dev,
344562306a36Sopenharmony_ci		    scsi_prot_sglist(scmd),
344662306a36Sopenharmony_ci		    scsi_prot_sg_count(scmd),
344762306a36Sopenharmony_ci		    scmd->sc_data_direction);
344862306a36Sopenharmony_ci		priv->meta_sg_valid = 1; /* To unmap meta sg DMA */
344962306a36Sopenharmony_ci	} else {
345062306a36Sopenharmony_ci		sg_scmd = scsi_sglist(scmd);
345162306a36Sopenharmony_ci		sges_left = scsi_dma_map(scmd);
345262306a36Sopenharmony_ci	}
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ci	if (sges_left < 0) {
345562306a36Sopenharmony_ci		sdev_printk(KERN_ERR, scmd->device,
345662306a36Sopenharmony_ci		    "scsi_dma_map failed: request for %d bytes!\n",
345762306a36Sopenharmony_ci		    scsi_bufflen(scmd));
345862306a36Sopenharmony_ci		return -ENOMEM;
345962306a36Sopenharmony_ci	}
346062306a36Sopenharmony_ci	if (sges_left > mrioc->max_sgl_entries) {
346162306a36Sopenharmony_ci		sdev_printk(KERN_ERR, scmd->device,
346262306a36Sopenharmony_ci		    "scsi_dma_map returned unsupported sge count %d!\n",
346362306a36Sopenharmony_ci		    sges_left);
346462306a36Sopenharmony_ci		return -ENOMEM;
346562306a36Sopenharmony_ci	}
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ci	sges_in_segment = (mrioc->facts.op_req_sz -
346862306a36Sopenharmony_ci	    offsetof(struct mpi3_scsi_io_request, sgl)) / sizeof(struct mpi3_sge_common);
346962306a36Sopenharmony_ci
347062306a36Sopenharmony_ci	if (scsiio_req->sgl[0].eedp.flags ==
347162306a36Sopenharmony_ci	    MPI3_SGE_FLAGS_ELEMENT_TYPE_EXTENDED && !meta_sg) {
347262306a36Sopenharmony_ci		sg_local += sizeof(struct mpi3_sge_common);
347362306a36Sopenharmony_ci		sges_in_segment--;
347462306a36Sopenharmony_ci		/* Reserve 1st segment (scsiio_req->sgl[0]) for eedp */
347562306a36Sopenharmony_ci	}
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_ci	if (scsiio_req->msg_flags ==
347862306a36Sopenharmony_ci	    MPI3_SCSIIO_MSGFLAGS_METASGL_VALID && !meta_sg) {
347962306a36Sopenharmony_ci		sges_in_segment--;
348062306a36Sopenharmony_ci		/* Reserve last segment (scsiio_req->sgl[3]) for meta sg */
348162306a36Sopenharmony_ci	}
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ci	if (meta_sg)
348462306a36Sopenharmony_ci		sges_in_segment = 1;
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_ci	if (sges_left <= sges_in_segment)
348762306a36Sopenharmony_ci		goto fill_in_last_segment;
348862306a36Sopenharmony_ci
348962306a36Sopenharmony_ci	/* fill in main message segment when there is a chain following */
349062306a36Sopenharmony_ci	while (sges_in_segment > 1) {
349162306a36Sopenharmony_ci		mpi3mr_add_sg_single(sg_local, simple_sgl_flags,
349262306a36Sopenharmony_ci		    sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
349362306a36Sopenharmony_ci		sg_scmd = sg_next(sg_scmd);
349462306a36Sopenharmony_ci		sg_local += sizeof(struct mpi3_sge_common);
349562306a36Sopenharmony_ci		sges_left--;
349662306a36Sopenharmony_ci		sges_in_segment--;
349762306a36Sopenharmony_ci	}
349862306a36Sopenharmony_ci
349962306a36Sopenharmony_ci	chain_idx = mpi3mr_get_chain_idx(mrioc);
350062306a36Sopenharmony_ci	if (chain_idx < 0)
350162306a36Sopenharmony_ci		return -1;
350262306a36Sopenharmony_ci	chain_req = &mrioc->chain_sgl_list[chain_idx];
350362306a36Sopenharmony_ci	if (meta_sg)
350462306a36Sopenharmony_ci		priv->meta_chain_idx = chain_idx;
350562306a36Sopenharmony_ci	else
350662306a36Sopenharmony_ci		priv->chain_idx = chain_idx;
350762306a36Sopenharmony_ci
350862306a36Sopenharmony_ci	chain = chain_req->addr;
350962306a36Sopenharmony_ci	chain_dma = chain_req->dma_addr;
351062306a36Sopenharmony_ci	sges_in_segment = sges_left;
351162306a36Sopenharmony_ci	chain_length = sges_in_segment * sizeof(struct mpi3_sge_common);
351262306a36Sopenharmony_ci
351362306a36Sopenharmony_ci	mpi3mr_add_sg_single(sg_local, last_chain_sgl_flags,
351462306a36Sopenharmony_ci	    chain_length, chain_dma);
351562306a36Sopenharmony_ci
351662306a36Sopenharmony_ci	sg_local = chain;
351762306a36Sopenharmony_ci
351862306a36Sopenharmony_cifill_in_last_segment:
351962306a36Sopenharmony_ci	while (sges_left > 0) {
352062306a36Sopenharmony_ci		if (sges_left == 1)
352162306a36Sopenharmony_ci			mpi3mr_add_sg_single(sg_local,
352262306a36Sopenharmony_ci			    simple_sgl_flags_last, sg_dma_len(sg_scmd),
352362306a36Sopenharmony_ci			    sg_dma_address(sg_scmd));
352462306a36Sopenharmony_ci		else
352562306a36Sopenharmony_ci			mpi3mr_add_sg_single(sg_local, simple_sgl_flags,
352662306a36Sopenharmony_ci			    sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
352762306a36Sopenharmony_ci		sg_scmd = sg_next(sg_scmd);
352862306a36Sopenharmony_ci		sg_local += sizeof(struct mpi3_sge_common);
352962306a36Sopenharmony_ci		sges_left--;
353062306a36Sopenharmony_ci	}
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_ci	return 0;
353362306a36Sopenharmony_ci}
353462306a36Sopenharmony_ci
353562306a36Sopenharmony_ci/**
353662306a36Sopenharmony_ci * mpi3mr_build_sg_scmd - build scatter gather list for SCSI IO
353762306a36Sopenharmony_ci * @mrioc: Adapter instance reference
353862306a36Sopenharmony_ci * @scmd: SCSI command reference
353962306a36Sopenharmony_ci * @scsiio_req: MPI3 SCSI IO request
354062306a36Sopenharmony_ci *
354162306a36Sopenharmony_ci * This function calls mpi3mr_prepare_sg_scmd for constructing
354262306a36Sopenharmony_ci * both data SGEs and protection information SGEs in the MPI
354362306a36Sopenharmony_ci * format from the SCSI Command as appropriate .
354462306a36Sopenharmony_ci *
354562306a36Sopenharmony_ci * Return: return value of mpi3mr_prepare_sg_scmd.
354662306a36Sopenharmony_ci */
354762306a36Sopenharmony_cistatic int mpi3mr_build_sg_scmd(struct mpi3mr_ioc *mrioc,
354862306a36Sopenharmony_ci	struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req)
354962306a36Sopenharmony_ci{
355062306a36Sopenharmony_ci	int ret;
355162306a36Sopenharmony_ci
355262306a36Sopenharmony_ci	ret = mpi3mr_prepare_sg_scmd(mrioc, scmd, scsiio_req);
355362306a36Sopenharmony_ci	if (ret)
355462306a36Sopenharmony_ci		return ret;
355562306a36Sopenharmony_ci
355662306a36Sopenharmony_ci	if (scsiio_req->msg_flags == MPI3_SCSIIO_MSGFLAGS_METASGL_VALID) {
355762306a36Sopenharmony_ci		/* There is a valid meta sg */
355862306a36Sopenharmony_ci		scsiio_req->flags |=
355962306a36Sopenharmony_ci		    cpu_to_le32(MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI);
356062306a36Sopenharmony_ci		ret = mpi3mr_prepare_sg_scmd(mrioc, scmd, scsiio_req);
356162306a36Sopenharmony_ci	}
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci	return ret;
356462306a36Sopenharmony_ci}
356562306a36Sopenharmony_ci
356662306a36Sopenharmony_ci/**
356762306a36Sopenharmony_ci * mpi3mr_tm_response_name -  get TM response as a string
356862306a36Sopenharmony_ci * @resp_code: TM response code
356962306a36Sopenharmony_ci *
357062306a36Sopenharmony_ci * Convert known task management response code as a readable
357162306a36Sopenharmony_ci * string.
357262306a36Sopenharmony_ci *
357362306a36Sopenharmony_ci * Return: response code string.
357462306a36Sopenharmony_ci */
357562306a36Sopenharmony_cistatic const char *mpi3mr_tm_response_name(u8 resp_code)
357662306a36Sopenharmony_ci{
357762306a36Sopenharmony_ci	char *desc;
357862306a36Sopenharmony_ci
357962306a36Sopenharmony_ci	switch (resp_code) {
358062306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE:
358162306a36Sopenharmony_ci		desc = "task management request completed";
358262306a36Sopenharmony_ci		break;
358362306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_RSPCODE_INVALID_FRAME:
358462306a36Sopenharmony_ci		desc = "invalid frame";
358562306a36Sopenharmony_ci		break;
358662306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_RSPCODE_TM_FUNCTION_NOT_SUPPORTED:
358762306a36Sopenharmony_ci		desc = "task management request not supported";
358862306a36Sopenharmony_ci		break;
358962306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_RSPCODE_TM_FAILED:
359062306a36Sopenharmony_ci		desc = "task management request failed";
359162306a36Sopenharmony_ci		break;
359262306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED:
359362306a36Sopenharmony_ci		desc = "task management request succeeded";
359462306a36Sopenharmony_ci		break;
359562306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_RSPCODE_TM_INVALID_LUN:
359662306a36Sopenharmony_ci		desc = "invalid LUN";
359762306a36Sopenharmony_ci		break;
359862306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_RSPCODE_TM_OVERLAPPED_TAG:
359962306a36Sopenharmony_ci		desc = "overlapped tag attempted";
360062306a36Sopenharmony_ci		break;
360162306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC:
360262306a36Sopenharmony_ci		desc = "task queued, however not sent to target";
360362306a36Sopenharmony_ci		break;
360462306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_RSPCODE_TM_NVME_DENIED:
360562306a36Sopenharmony_ci		desc = "task management request denied by NVMe device";
360662306a36Sopenharmony_ci		break;
360762306a36Sopenharmony_ci	default:
360862306a36Sopenharmony_ci		desc = "unknown";
360962306a36Sopenharmony_ci		break;
361062306a36Sopenharmony_ci	}
361162306a36Sopenharmony_ci
361262306a36Sopenharmony_ci	return desc;
361362306a36Sopenharmony_ci}
361462306a36Sopenharmony_ci
361562306a36Sopenharmony_ciinline void mpi3mr_poll_pend_io_completions(struct mpi3mr_ioc *mrioc)
361662306a36Sopenharmony_ci{
361762306a36Sopenharmony_ci	int i;
361862306a36Sopenharmony_ci	int num_of_reply_queues =
361962306a36Sopenharmony_ci	    mrioc->num_op_reply_q + mrioc->op_reply_q_offset;
362062306a36Sopenharmony_ci
362162306a36Sopenharmony_ci	for (i = mrioc->op_reply_q_offset; i < num_of_reply_queues; i++)
362262306a36Sopenharmony_ci		mpi3mr_process_op_reply_q(mrioc,
362362306a36Sopenharmony_ci		    mrioc->intr_info[i].op_reply_q);
362462306a36Sopenharmony_ci}
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_ci/**
362762306a36Sopenharmony_ci * mpi3mr_issue_tm - Issue Task Management request
362862306a36Sopenharmony_ci * @mrioc: Adapter instance reference
362962306a36Sopenharmony_ci * @tm_type: Task Management type
363062306a36Sopenharmony_ci * @handle: Device handle
363162306a36Sopenharmony_ci * @lun: lun ID
363262306a36Sopenharmony_ci * @htag: Host tag of the TM request
363362306a36Sopenharmony_ci * @timeout: TM timeout value
363462306a36Sopenharmony_ci * @drv_cmd: Internal command tracker
363562306a36Sopenharmony_ci * @resp_code: Response code place holder
363662306a36Sopenharmony_ci * @scmd: SCSI command
363762306a36Sopenharmony_ci *
363862306a36Sopenharmony_ci * Issues a Task Management Request to the controller for a
363962306a36Sopenharmony_ci * specified target, lun and command and wait for its completion
364062306a36Sopenharmony_ci * and check TM response. Recover the TM if it timed out by
364162306a36Sopenharmony_ci * issuing controller reset.
364262306a36Sopenharmony_ci *
364362306a36Sopenharmony_ci * Return: 0 on success, non-zero on errors
364462306a36Sopenharmony_ci */
364562306a36Sopenharmony_ciint mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
364662306a36Sopenharmony_ci	u16 handle, uint lun, u16 htag, ulong timeout,
364762306a36Sopenharmony_ci	struct mpi3mr_drv_cmd *drv_cmd,
364862306a36Sopenharmony_ci	u8 *resp_code, struct scsi_cmnd *scmd)
364962306a36Sopenharmony_ci{
365062306a36Sopenharmony_ci	struct mpi3_scsi_task_mgmt_request tm_req;
365162306a36Sopenharmony_ci	struct mpi3_scsi_task_mgmt_reply *tm_reply = NULL;
365262306a36Sopenharmony_ci	int retval = 0;
365362306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev = NULL;
365462306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
365562306a36Sopenharmony_ci	struct scmd_priv *cmd_priv = NULL;
365662306a36Sopenharmony_ci	struct scsi_device *sdev = NULL;
365762306a36Sopenharmony_ci	struct mpi3mr_sdev_priv_data *sdev_priv_data = NULL;
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_ci	ioc_info(mrioc, "%s :Issue TM: TM type (0x%x) for devhandle 0x%04x\n",
366062306a36Sopenharmony_ci	     __func__, tm_type, handle);
366162306a36Sopenharmony_ci	if (mrioc->unrecoverable) {
366262306a36Sopenharmony_ci		retval = -1;
366362306a36Sopenharmony_ci		ioc_err(mrioc, "%s :Issue TM: Unrecoverable controller\n",
366462306a36Sopenharmony_ci		    __func__);
366562306a36Sopenharmony_ci		goto out;
366662306a36Sopenharmony_ci	}
366762306a36Sopenharmony_ci
366862306a36Sopenharmony_ci	memset(&tm_req, 0, sizeof(tm_req));
366962306a36Sopenharmony_ci	mutex_lock(&drv_cmd->mutex);
367062306a36Sopenharmony_ci	if (drv_cmd->state & MPI3MR_CMD_PENDING) {
367162306a36Sopenharmony_ci		retval = -1;
367262306a36Sopenharmony_ci		ioc_err(mrioc, "%s :Issue TM: Command is in use\n", __func__);
367362306a36Sopenharmony_ci		mutex_unlock(&drv_cmd->mutex);
367462306a36Sopenharmony_ci		goto out;
367562306a36Sopenharmony_ci	}
367662306a36Sopenharmony_ci	if (mrioc->reset_in_progress) {
367762306a36Sopenharmony_ci		retval = -1;
367862306a36Sopenharmony_ci		ioc_err(mrioc, "%s :Issue TM: Reset in progress\n", __func__);
367962306a36Sopenharmony_ci		mutex_unlock(&drv_cmd->mutex);
368062306a36Sopenharmony_ci		goto out;
368162306a36Sopenharmony_ci	}
368262306a36Sopenharmony_ci
368362306a36Sopenharmony_ci	drv_cmd->state = MPI3MR_CMD_PENDING;
368462306a36Sopenharmony_ci	drv_cmd->is_waiting = 1;
368562306a36Sopenharmony_ci	drv_cmd->callback = NULL;
368662306a36Sopenharmony_ci	tm_req.dev_handle = cpu_to_le16(handle);
368762306a36Sopenharmony_ci	tm_req.task_type = tm_type;
368862306a36Sopenharmony_ci	tm_req.host_tag = cpu_to_le16(htag);
368962306a36Sopenharmony_ci
369062306a36Sopenharmony_ci	int_to_scsilun(lun, (struct scsi_lun *)tm_req.lun);
369162306a36Sopenharmony_ci	tm_req.function = MPI3_FUNCTION_SCSI_TASK_MGMT;
369262306a36Sopenharmony_ci
369362306a36Sopenharmony_ci	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
369462306a36Sopenharmony_ci
369562306a36Sopenharmony_ci	if (scmd) {
369662306a36Sopenharmony_ci		sdev = scmd->device;
369762306a36Sopenharmony_ci		sdev_priv_data = sdev->hostdata;
369862306a36Sopenharmony_ci		scsi_tgt_priv_data = ((sdev_priv_data) ?
369962306a36Sopenharmony_ci		    sdev_priv_data->tgt_priv_data : NULL);
370062306a36Sopenharmony_ci	} else {
370162306a36Sopenharmony_ci		if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata)
370262306a36Sopenharmony_ci			scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
370362306a36Sopenharmony_ci			    tgtdev->starget->hostdata;
370462306a36Sopenharmony_ci	}
370562306a36Sopenharmony_ci
370662306a36Sopenharmony_ci	if (scsi_tgt_priv_data)
370762306a36Sopenharmony_ci		atomic_inc(&scsi_tgt_priv_data->block_io);
370862306a36Sopenharmony_ci
370962306a36Sopenharmony_ci	if (tgtdev && (tgtdev->dev_type == MPI3_DEVICE_DEVFORM_PCIE)) {
371062306a36Sopenharmony_ci		if (cmd_priv && tgtdev->dev_spec.pcie_inf.abort_to)
371162306a36Sopenharmony_ci			timeout = tgtdev->dev_spec.pcie_inf.abort_to;
371262306a36Sopenharmony_ci		else if (!cmd_priv && tgtdev->dev_spec.pcie_inf.reset_to)
371362306a36Sopenharmony_ci			timeout = tgtdev->dev_spec.pcie_inf.reset_to;
371462306a36Sopenharmony_ci	}
371562306a36Sopenharmony_ci
371662306a36Sopenharmony_ci	init_completion(&drv_cmd->done);
371762306a36Sopenharmony_ci	retval = mpi3mr_admin_request_post(mrioc, &tm_req, sizeof(tm_req), 1);
371862306a36Sopenharmony_ci	if (retval) {
371962306a36Sopenharmony_ci		ioc_err(mrioc, "%s :Issue TM: Admin Post failed\n", __func__);
372062306a36Sopenharmony_ci		goto out_unlock;
372162306a36Sopenharmony_ci	}
372262306a36Sopenharmony_ci	wait_for_completion_timeout(&drv_cmd->done, (timeout * HZ));
372362306a36Sopenharmony_ci
372462306a36Sopenharmony_ci	if (!(drv_cmd->state & MPI3MR_CMD_COMPLETE)) {
372562306a36Sopenharmony_ci		drv_cmd->is_waiting = 0;
372662306a36Sopenharmony_ci		retval = -1;
372762306a36Sopenharmony_ci		if (!(drv_cmd->state & MPI3MR_CMD_RESET)) {
372862306a36Sopenharmony_ci			dprint_tm(mrioc,
372962306a36Sopenharmony_ci			    "task management request timed out after %ld seconds\n",
373062306a36Sopenharmony_ci			    timeout);
373162306a36Sopenharmony_ci			if (mrioc->logging_level & MPI3_DEBUG_TM)
373262306a36Sopenharmony_ci				dprint_dump_req(&tm_req, sizeof(tm_req)/4);
373362306a36Sopenharmony_ci			mpi3mr_soft_reset_handler(mrioc,
373462306a36Sopenharmony_ci			    MPI3MR_RESET_FROM_TM_TIMEOUT, 1);
373562306a36Sopenharmony_ci		}
373662306a36Sopenharmony_ci		goto out_unlock;
373762306a36Sopenharmony_ci	}
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_ci	if (!(drv_cmd->state & MPI3MR_CMD_REPLY_VALID)) {
374062306a36Sopenharmony_ci		dprint_tm(mrioc, "invalid task management reply message\n");
374162306a36Sopenharmony_ci		retval = -1;
374262306a36Sopenharmony_ci		goto out_unlock;
374362306a36Sopenharmony_ci	}
374462306a36Sopenharmony_ci
374562306a36Sopenharmony_ci	tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply;
374662306a36Sopenharmony_ci
374762306a36Sopenharmony_ci	switch (drv_cmd->ioc_status) {
374862306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SUCCESS:
374962306a36Sopenharmony_ci		*resp_code = le32_to_cpu(tm_reply->response_data) &
375062306a36Sopenharmony_ci			MPI3MR_RI_MASK_RESPCODE;
375162306a36Sopenharmony_ci		break;
375262306a36Sopenharmony_ci	case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED:
375362306a36Sopenharmony_ci		*resp_code = MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE;
375462306a36Sopenharmony_ci		break;
375562306a36Sopenharmony_ci	default:
375662306a36Sopenharmony_ci		dprint_tm(mrioc,
375762306a36Sopenharmony_ci		    "task management request to handle(0x%04x) is failed with ioc_status(0x%04x) log_info(0x%08x)\n",
375862306a36Sopenharmony_ci		    handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo);
375962306a36Sopenharmony_ci		retval = -1;
376062306a36Sopenharmony_ci		goto out_unlock;
376162306a36Sopenharmony_ci	}
376262306a36Sopenharmony_ci
376362306a36Sopenharmony_ci	switch (*resp_code) {
376462306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED:
376562306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE:
376662306a36Sopenharmony_ci		break;
376762306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC:
376862306a36Sopenharmony_ci		if (tm_type != MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK)
376962306a36Sopenharmony_ci			retval = -1;
377062306a36Sopenharmony_ci		break;
377162306a36Sopenharmony_ci	default:
377262306a36Sopenharmony_ci		retval = -1;
377362306a36Sopenharmony_ci		break;
377462306a36Sopenharmony_ci	}
377562306a36Sopenharmony_ci
377662306a36Sopenharmony_ci	dprint_tm(mrioc,
377762306a36Sopenharmony_ci	    "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",
377862306a36Sopenharmony_ci	    tm_type, handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo,
377962306a36Sopenharmony_ci	    le32_to_cpu(tm_reply->termination_count),
378062306a36Sopenharmony_ci	    mpi3mr_tm_response_name(*resp_code), *resp_code);
378162306a36Sopenharmony_ci
378262306a36Sopenharmony_ci	if (!retval) {
378362306a36Sopenharmony_ci		mpi3mr_ioc_disable_intr(mrioc);
378462306a36Sopenharmony_ci		mpi3mr_poll_pend_io_completions(mrioc);
378562306a36Sopenharmony_ci		mpi3mr_ioc_enable_intr(mrioc);
378662306a36Sopenharmony_ci		mpi3mr_poll_pend_io_completions(mrioc);
378762306a36Sopenharmony_ci		mpi3mr_process_admin_reply_q(mrioc);
378862306a36Sopenharmony_ci	}
378962306a36Sopenharmony_ci	switch (tm_type) {
379062306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
379162306a36Sopenharmony_ci		if (!scsi_tgt_priv_data)
379262306a36Sopenharmony_ci			break;
379362306a36Sopenharmony_ci		scsi_tgt_priv_data->pend_count = 0;
379462306a36Sopenharmony_ci		blk_mq_tagset_busy_iter(&mrioc->shost->tag_set,
379562306a36Sopenharmony_ci		    mpi3mr_count_tgt_pending,
379662306a36Sopenharmony_ci		    (void *)scsi_tgt_priv_data->starget);
379762306a36Sopenharmony_ci		break;
379862306a36Sopenharmony_ci	case MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
379962306a36Sopenharmony_ci		if (!sdev_priv_data)
380062306a36Sopenharmony_ci			break;
380162306a36Sopenharmony_ci		sdev_priv_data->pend_count = 0;
380262306a36Sopenharmony_ci		blk_mq_tagset_busy_iter(&mrioc->shost->tag_set,
380362306a36Sopenharmony_ci		    mpi3mr_count_dev_pending, (void *)sdev);
380462306a36Sopenharmony_ci		break;
380562306a36Sopenharmony_ci	default:
380662306a36Sopenharmony_ci		break;
380762306a36Sopenharmony_ci	}
380862306a36Sopenharmony_ci
380962306a36Sopenharmony_ciout_unlock:
381062306a36Sopenharmony_ci	drv_cmd->state = MPI3MR_CMD_NOTUSED;
381162306a36Sopenharmony_ci	mutex_unlock(&drv_cmd->mutex);
381262306a36Sopenharmony_ci	if (scsi_tgt_priv_data)
381362306a36Sopenharmony_ci		atomic_dec_if_positive(&scsi_tgt_priv_data->block_io);
381462306a36Sopenharmony_ci	if (tgtdev)
381562306a36Sopenharmony_ci		mpi3mr_tgtdev_put(tgtdev);
381662306a36Sopenharmony_ciout:
381762306a36Sopenharmony_ci	return retval;
381862306a36Sopenharmony_ci}
381962306a36Sopenharmony_ci
382062306a36Sopenharmony_ci/**
382162306a36Sopenharmony_ci * mpi3mr_bios_param - BIOS param callback
382262306a36Sopenharmony_ci * @sdev: SCSI device reference
382362306a36Sopenharmony_ci * @bdev: Block device reference
382462306a36Sopenharmony_ci * @capacity: Capacity in logical sectors
382562306a36Sopenharmony_ci * @params: Parameter array
382662306a36Sopenharmony_ci *
382762306a36Sopenharmony_ci * Just the parameters with heads/secots/cylinders.
382862306a36Sopenharmony_ci *
382962306a36Sopenharmony_ci * Return: 0 always
383062306a36Sopenharmony_ci */
383162306a36Sopenharmony_cistatic int mpi3mr_bios_param(struct scsi_device *sdev,
383262306a36Sopenharmony_ci	struct block_device *bdev, sector_t capacity, int params[])
383362306a36Sopenharmony_ci{
383462306a36Sopenharmony_ci	int heads;
383562306a36Sopenharmony_ci	int sectors;
383662306a36Sopenharmony_ci	sector_t cylinders;
383762306a36Sopenharmony_ci	ulong dummy;
383862306a36Sopenharmony_ci
383962306a36Sopenharmony_ci	heads = 64;
384062306a36Sopenharmony_ci	sectors = 32;
384162306a36Sopenharmony_ci
384262306a36Sopenharmony_ci	dummy = heads * sectors;
384362306a36Sopenharmony_ci	cylinders = capacity;
384462306a36Sopenharmony_ci	sector_div(cylinders, dummy);
384562306a36Sopenharmony_ci
384662306a36Sopenharmony_ci	if ((ulong)capacity >= 0x200000) {
384762306a36Sopenharmony_ci		heads = 255;
384862306a36Sopenharmony_ci		sectors = 63;
384962306a36Sopenharmony_ci		dummy = heads * sectors;
385062306a36Sopenharmony_ci		cylinders = capacity;
385162306a36Sopenharmony_ci		sector_div(cylinders, dummy);
385262306a36Sopenharmony_ci	}
385362306a36Sopenharmony_ci
385462306a36Sopenharmony_ci	params[0] = heads;
385562306a36Sopenharmony_ci	params[1] = sectors;
385662306a36Sopenharmony_ci	params[2] = cylinders;
385762306a36Sopenharmony_ci	return 0;
385862306a36Sopenharmony_ci}
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci/**
386162306a36Sopenharmony_ci * mpi3mr_map_queues - Map queues callback handler
386262306a36Sopenharmony_ci * @shost: SCSI host reference
386362306a36Sopenharmony_ci *
386462306a36Sopenharmony_ci * Maps default and poll queues.
386562306a36Sopenharmony_ci *
386662306a36Sopenharmony_ci * Return: return zero.
386762306a36Sopenharmony_ci */
386862306a36Sopenharmony_cistatic void mpi3mr_map_queues(struct Scsi_Host *shost)
386962306a36Sopenharmony_ci{
387062306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc = shost_priv(shost);
387162306a36Sopenharmony_ci	int i, qoff, offset;
387262306a36Sopenharmony_ci	struct blk_mq_queue_map *map = NULL;
387362306a36Sopenharmony_ci
387462306a36Sopenharmony_ci	offset = mrioc->op_reply_q_offset;
387562306a36Sopenharmony_ci
387662306a36Sopenharmony_ci	for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
387762306a36Sopenharmony_ci		map = &shost->tag_set.map[i];
387862306a36Sopenharmony_ci
387962306a36Sopenharmony_ci		map->nr_queues  = 0;
388062306a36Sopenharmony_ci
388162306a36Sopenharmony_ci		if (i == HCTX_TYPE_DEFAULT)
388262306a36Sopenharmony_ci			map->nr_queues = mrioc->default_qcount;
388362306a36Sopenharmony_ci		else if (i == HCTX_TYPE_POLL)
388462306a36Sopenharmony_ci			map->nr_queues = mrioc->active_poll_qcount;
388562306a36Sopenharmony_ci
388662306a36Sopenharmony_ci		if (!map->nr_queues) {
388762306a36Sopenharmony_ci			BUG_ON(i == HCTX_TYPE_DEFAULT);
388862306a36Sopenharmony_ci			continue;
388962306a36Sopenharmony_ci		}
389062306a36Sopenharmony_ci
389162306a36Sopenharmony_ci		/*
389262306a36Sopenharmony_ci		 * The poll queue(s) doesn't have an IRQ (and hence IRQ
389362306a36Sopenharmony_ci		 * affinity), so use the regular blk-mq cpu mapping
389462306a36Sopenharmony_ci		 */
389562306a36Sopenharmony_ci		map->queue_offset = qoff;
389662306a36Sopenharmony_ci		if (i != HCTX_TYPE_POLL)
389762306a36Sopenharmony_ci			blk_mq_pci_map_queues(map, mrioc->pdev, offset);
389862306a36Sopenharmony_ci		else
389962306a36Sopenharmony_ci			blk_mq_map_queues(map);
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_ci		qoff += map->nr_queues;
390262306a36Sopenharmony_ci		offset += map->nr_queues;
390362306a36Sopenharmony_ci	}
390462306a36Sopenharmony_ci}
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ci/**
390762306a36Sopenharmony_ci * mpi3mr_get_fw_pending_ios - Calculate pending I/O count
390862306a36Sopenharmony_ci * @mrioc: Adapter instance reference
390962306a36Sopenharmony_ci *
391062306a36Sopenharmony_ci * Calculate the pending I/Os for the controller and return.
391162306a36Sopenharmony_ci *
391262306a36Sopenharmony_ci * Return: Number of pending I/Os
391362306a36Sopenharmony_ci */
391462306a36Sopenharmony_cistatic inline int mpi3mr_get_fw_pending_ios(struct mpi3mr_ioc *mrioc)
391562306a36Sopenharmony_ci{
391662306a36Sopenharmony_ci	u16 i;
391762306a36Sopenharmony_ci	uint pend_ios = 0;
391862306a36Sopenharmony_ci
391962306a36Sopenharmony_ci	for (i = 0; i < mrioc->num_op_reply_q; i++)
392062306a36Sopenharmony_ci		pend_ios += atomic_read(&mrioc->op_reply_qinfo[i].pend_ios);
392162306a36Sopenharmony_ci	return pend_ios;
392262306a36Sopenharmony_ci}
392362306a36Sopenharmony_ci
392462306a36Sopenharmony_ci/**
392562306a36Sopenharmony_ci * mpi3mr_print_pending_host_io - print pending I/Os
392662306a36Sopenharmony_ci * @mrioc: Adapter instance reference
392762306a36Sopenharmony_ci *
392862306a36Sopenharmony_ci * Print number of pending I/Os and each I/O details prior to
392962306a36Sopenharmony_ci * reset for debug purpose.
393062306a36Sopenharmony_ci *
393162306a36Sopenharmony_ci * Return: Nothing
393262306a36Sopenharmony_ci */
393362306a36Sopenharmony_cistatic void mpi3mr_print_pending_host_io(struct mpi3mr_ioc *mrioc)
393462306a36Sopenharmony_ci{
393562306a36Sopenharmony_ci	struct Scsi_Host *shost = mrioc->shost;
393662306a36Sopenharmony_ci
393762306a36Sopenharmony_ci	ioc_info(mrioc, "%s :Pending commands prior to reset: %d\n",
393862306a36Sopenharmony_ci	    __func__, mpi3mr_get_fw_pending_ios(mrioc));
393962306a36Sopenharmony_ci	blk_mq_tagset_busy_iter(&shost->tag_set,
394062306a36Sopenharmony_ci	    mpi3mr_print_scmd, (void *)mrioc);
394162306a36Sopenharmony_ci}
394262306a36Sopenharmony_ci
394362306a36Sopenharmony_ci/**
394462306a36Sopenharmony_ci * mpi3mr_wait_for_host_io - block for I/Os to complete
394562306a36Sopenharmony_ci * @mrioc: Adapter instance reference
394662306a36Sopenharmony_ci * @timeout: time out in seconds
394762306a36Sopenharmony_ci * Waits for pending I/Os for the given adapter to complete or
394862306a36Sopenharmony_ci * to hit the timeout.
394962306a36Sopenharmony_ci *
395062306a36Sopenharmony_ci * Return: Nothing
395162306a36Sopenharmony_ci */
395262306a36Sopenharmony_civoid mpi3mr_wait_for_host_io(struct mpi3mr_ioc *mrioc, u32 timeout)
395362306a36Sopenharmony_ci{
395462306a36Sopenharmony_ci	enum mpi3mr_iocstate iocstate;
395562306a36Sopenharmony_ci	int i = 0;
395662306a36Sopenharmony_ci
395762306a36Sopenharmony_ci	iocstate = mpi3mr_get_iocstate(mrioc);
395862306a36Sopenharmony_ci	if (iocstate != MRIOC_STATE_READY)
395962306a36Sopenharmony_ci		return;
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci	if (!mpi3mr_get_fw_pending_ios(mrioc))
396262306a36Sopenharmony_ci		return;
396362306a36Sopenharmony_ci	ioc_info(mrioc,
396462306a36Sopenharmony_ci	    "%s :Waiting for %d seconds prior to reset for %d I/O\n",
396562306a36Sopenharmony_ci	    __func__, timeout, mpi3mr_get_fw_pending_ios(mrioc));
396662306a36Sopenharmony_ci
396762306a36Sopenharmony_ci	for (i = 0; i < timeout; i++) {
396862306a36Sopenharmony_ci		if (!mpi3mr_get_fw_pending_ios(mrioc))
396962306a36Sopenharmony_ci			break;
397062306a36Sopenharmony_ci		iocstate = mpi3mr_get_iocstate(mrioc);
397162306a36Sopenharmony_ci		if (iocstate != MRIOC_STATE_READY)
397262306a36Sopenharmony_ci			break;
397362306a36Sopenharmony_ci		msleep(1000);
397462306a36Sopenharmony_ci	}
397562306a36Sopenharmony_ci
397662306a36Sopenharmony_ci	ioc_info(mrioc, "%s :Pending I/Os after wait is: %d\n", __func__,
397762306a36Sopenharmony_ci	    mpi3mr_get_fw_pending_ios(mrioc));
397862306a36Sopenharmony_ci}
397962306a36Sopenharmony_ci
398062306a36Sopenharmony_ci/**
398162306a36Sopenharmony_ci * mpi3mr_setup_divert_ws - Setup Divert IO flag for write same
398262306a36Sopenharmony_ci * @mrioc: Adapter instance reference
398362306a36Sopenharmony_ci * @scmd: SCSI command reference
398462306a36Sopenharmony_ci * @scsiio_req: MPI3 SCSI IO request
398562306a36Sopenharmony_ci * @scsiio_flags: Pointer to MPI3 SCSI IO Flags
398662306a36Sopenharmony_ci * @wslen: write same max length
398762306a36Sopenharmony_ci *
398862306a36Sopenharmony_ci * Gets values of unmap, ndob and number of blocks from write
398962306a36Sopenharmony_ci * same scsi io and based on these values it sets divert IO flag
399062306a36Sopenharmony_ci * and reason for diverting IO to firmware.
399162306a36Sopenharmony_ci *
399262306a36Sopenharmony_ci * Return: Nothing
399362306a36Sopenharmony_ci */
399462306a36Sopenharmony_cistatic inline void mpi3mr_setup_divert_ws(struct mpi3mr_ioc *mrioc,
399562306a36Sopenharmony_ci	struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req,
399662306a36Sopenharmony_ci	u32 *scsiio_flags, u16 wslen)
399762306a36Sopenharmony_ci{
399862306a36Sopenharmony_ci	u8 unmap = 0, ndob = 0;
399962306a36Sopenharmony_ci	u8 opcode = scmd->cmnd[0];
400062306a36Sopenharmony_ci	u32 num_blocks = 0;
400162306a36Sopenharmony_ci	u16 sa = (scmd->cmnd[8] << 8) | (scmd->cmnd[9]);
400262306a36Sopenharmony_ci
400362306a36Sopenharmony_ci	if (opcode == WRITE_SAME_16) {
400462306a36Sopenharmony_ci		unmap = scmd->cmnd[1] & 0x08;
400562306a36Sopenharmony_ci		ndob = scmd->cmnd[1] & 0x01;
400662306a36Sopenharmony_ci		num_blocks = get_unaligned_be32(scmd->cmnd + 10);
400762306a36Sopenharmony_ci	} else if ((opcode == VARIABLE_LENGTH_CMD) && (sa == WRITE_SAME_32)) {
400862306a36Sopenharmony_ci		unmap = scmd->cmnd[10] & 0x08;
400962306a36Sopenharmony_ci		ndob = scmd->cmnd[10] & 0x01;
401062306a36Sopenharmony_ci		num_blocks = get_unaligned_be32(scmd->cmnd + 28);
401162306a36Sopenharmony_ci	} else
401262306a36Sopenharmony_ci		return;
401362306a36Sopenharmony_ci
401462306a36Sopenharmony_ci	if ((unmap) && (ndob) && (num_blocks > wslen)) {
401562306a36Sopenharmony_ci		scsiio_req->msg_flags |=
401662306a36Sopenharmony_ci		    MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE;
401762306a36Sopenharmony_ci		*scsiio_flags |=
401862306a36Sopenharmony_ci			MPI3_SCSIIO_FLAGS_DIVERT_REASON_WRITE_SAME_TOO_LARGE;
401962306a36Sopenharmony_ci	}
402062306a36Sopenharmony_ci}
402162306a36Sopenharmony_ci
402262306a36Sopenharmony_ci/**
402362306a36Sopenharmony_ci * mpi3mr_eh_host_reset - Host reset error handling callback
402462306a36Sopenharmony_ci * @scmd: SCSI command reference
402562306a36Sopenharmony_ci *
402662306a36Sopenharmony_ci * Issue controller reset if the scmd is for a Physical Device,
402762306a36Sopenharmony_ci * if the scmd is for RAID volume, then wait for
402862306a36Sopenharmony_ci * MPI3MR_RAID_ERRREC_RESET_TIMEOUT and checke whether any
402962306a36Sopenharmony_ci * pending I/Os prior to issuing reset to the controller.
403062306a36Sopenharmony_ci *
403162306a36Sopenharmony_ci * Return: SUCCESS of successful reset else FAILED
403262306a36Sopenharmony_ci */
403362306a36Sopenharmony_cistatic int mpi3mr_eh_host_reset(struct scsi_cmnd *scmd)
403462306a36Sopenharmony_ci{
403562306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host);
403662306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *stgt_priv_data;
403762306a36Sopenharmony_ci	struct mpi3mr_sdev_priv_data *sdev_priv_data;
403862306a36Sopenharmony_ci	u8 dev_type = MPI3_DEVICE_DEVFORM_VD;
403962306a36Sopenharmony_ci	int retval = FAILED, ret;
404062306a36Sopenharmony_ci
404162306a36Sopenharmony_ci	sdev_priv_data = scmd->device->hostdata;
404262306a36Sopenharmony_ci	if (sdev_priv_data && sdev_priv_data->tgt_priv_data) {
404362306a36Sopenharmony_ci		stgt_priv_data = sdev_priv_data->tgt_priv_data;
404462306a36Sopenharmony_ci		dev_type = stgt_priv_data->dev_type;
404562306a36Sopenharmony_ci	}
404662306a36Sopenharmony_ci
404762306a36Sopenharmony_ci	if (dev_type == MPI3_DEVICE_DEVFORM_VD) {
404862306a36Sopenharmony_ci		mpi3mr_wait_for_host_io(mrioc,
404962306a36Sopenharmony_ci		    MPI3MR_RAID_ERRREC_RESET_TIMEOUT);
405062306a36Sopenharmony_ci		if (!mpi3mr_get_fw_pending_ios(mrioc)) {
405162306a36Sopenharmony_ci			retval = SUCCESS;
405262306a36Sopenharmony_ci			goto out;
405362306a36Sopenharmony_ci		}
405462306a36Sopenharmony_ci	}
405562306a36Sopenharmony_ci
405662306a36Sopenharmony_ci	mpi3mr_print_pending_host_io(mrioc);
405762306a36Sopenharmony_ci	ret = mpi3mr_soft_reset_handler(mrioc,
405862306a36Sopenharmony_ci	    MPI3MR_RESET_FROM_EH_HOS, 1);
405962306a36Sopenharmony_ci	if (ret)
406062306a36Sopenharmony_ci		goto out;
406162306a36Sopenharmony_ci
406262306a36Sopenharmony_ci	retval = SUCCESS;
406362306a36Sopenharmony_ciout:
406462306a36Sopenharmony_ci	sdev_printk(KERN_INFO, scmd->device,
406562306a36Sopenharmony_ci	    "Host reset is %s for scmd(%p)\n",
406662306a36Sopenharmony_ci	    ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
406762306a36Sopenharmony_ci
406862306a36Sopenharmony_ci	return retval;
406962306a36Sopenharmony_ci}
407062306a36Sopenharmony_ci
407162306a36Sopenharmony_ci/**
407262306a36Sopenharmony_ci * mpi3mr_eh_target_reset - Target reset error handling callback
407362306a36Sopenharmony_ci * @scmd: SCSI command reference
407462306a36Sopenharmony_ci *
407562306a36Sopenharmony_ci * Issue Target reset Task Management and verify the scmd is
407662306a36Sopenharmony_ci * terminated successfully and return status accordingly.
407762306a36Sopenharmony_ci *
407862306a36Sopenharmony_ci * Return: SUCCESS of successful termination of the scmd else
407962306a36Sopenharmony_ci *         FAILED
408062306a36Sopenharmony_ci */
408162306a36Sopenharmony_cistatic int mpi3mr_eh_target_reset(struct scsi_cmnd *scmd)
408262306a36Sopenharmony_ci{
408362306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host);
408462306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *stgt_priv_data;
408562306a36Sopenharmony_ci	struct mpi3mr_sdev_priv_data *sdev_priv_data;
408662306a36Sopenharmony_ci	u16 dev_handle;
408762306a36Sopenharmony_ci	u8 resp_code = 0;
408862306a36Sopenharmony_ci	int retval = FAILED, ret = 0;
408962306a36Sopenharmony_ci
409062306a36Sopenharmony_ci	sdev_printk(KERN_INFO, scmd->device,
409162306a36Sopenharmony_ci	    "Attempting Target Reset! scmd(%p)\n", scmd);
409262306a36Sopenharmony_ci	scsi_print_command(scmd);
409362306a36Sopenharmony_ci
409462306a36Sopenharmony_ci	sdev_priv_data = scmd->device->hostdata;
409562306a36Sopenharmony_ci	if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) {
409662306a36Sopenharmony_ci		sdev_printk(KERN_INFO, scmd->device,
409762306a36Sopenharmony_ci		    "SCSI device is not available\n");
409862306a36Sopenharmony_ci		retval = SUCCESS;
409962306a36Sopenharmony_ci		goto out;
410062306a36Sopenharmony_ci	}
410162306a36Sopenharmony_ci
410262306a36Sopenharmony_ci	stgt_priv_data = sdev_priv_data->tgt_priv_data;
410362306a36Sopenharmony_ci	dev_handle = stgt_priv_data->dev_handle;
410462306a36Sopenharmony_ci	if (stgt_priv_data->dev_removed) {
410562306a36Sopenharmony_ci		struct scmd_priv *cmd_priv = scsi_cmd_priv(scmd);
410662306a36Sopenharmony_ci		sdev_printk(KERN_INFO, scmd->device,
410762306a36Sopenharmony_ci		    "%s:target(handle = 0x%04x) is removed, target reset is not issued\n",
410862306a36Sopenharmony_ci		    mrioc->name, dev_handle);
410962306a36Sopenharmony_ci		if (!cmd_priv->in_lld_scope || cmd_priv->host_tag == MPI3MR_HOSTTAG_INVALID)
411062306a36Sopenharmony_ci			retval = SUCCESS;
411162306a36Sopenharmony_ci		else
411262306a36Sopenharmony_ci			retval = FAILED;
411362306a36Sopenharmony_ci		goto out;
411462306a36Sopenharmony_ci	}
411562306a36Sopenharmony_ci	sdev_printk(KERN_INFO, scmd->device,
411662306a36Sopenharmony_ci	    "Target Reset is issued to handle(0x%04x)\n",
411762306a36Sopenharmony_ci	    dev_handle);
411862306a36Sopenharmony_ci
411962306a36Sopenharmony_ci	ret = mpi3mr_issue_tm(mrioc,
412062306a36Sopenharmony_ci	    MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET, dev_handle,
412162306a36Sopenharmony_ci	    sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS,
412262306a36Sopenharmony_ci	    MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, scmd);
412362306a36Sopenharmony_ci
412462306a36Sopenharmony_ci	if (ret)
412562306a36Sopenharmony_ci		goto out;
412662306a36Sopenharmony_ci
412762306a36Sopenharmony_ci	if (stgt_priv_data->pend_count) {
412862306a36Sopenharmony_ci		sdev_printk(KERN_INFO, scmd->device,
412962306a36Sopenharmony_ci		    "%s: target has %d pending commands, target reset is failed\n",
413062306a36Sopenharmony_ci		    mrioc->name, stgt_priv_data->pend_count);
413162306a36Sopenharmony_ci		goto out;
413262306a36Sopenharmony_ci	}
413362306a36Sopenharmony_ci
413462306a36Sopenharmony_ci	retval = SUCCESS;
413562306a36Sopenharmony_ciout:
413662306a36Sopenharmony_ci	sdev_printk(KERN_INFO, scmd->device,
413762306a36Sopenharmony_ci	    "%s: target reset is %s for scmd(%p)\n", mrioc->name,
413862306a36Sopenharmony_ci	    ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
413962306a36Sopenharmony_ci
414062306a36Sopenharmony_ci	return retval;
414162306a36Sopenharmony_ci}
414262306a36Sopenharmony_ci
414362306a36Sopenharmony_ci/**
414462306a36Sopenharmony_ci * mpi3mr_eh_dev_reset- Device reset error handling callback
414562306a36Sopenharmony_ci * @scmd: SCSI command reference
414662306a36Sopenharmony_ci *
414762306a36Sopenharmony_ci * Issue lun reset Task Management and verify the scmd is
414862306a36Sopenharmony_ci * terminated successfully and return status accordingly.
414962306a36Sopenharmony_ci *
415062306a36Sopenharmony_ci * Return: SUCCESS of successful termination of the scmd else
415162306a36Sopenharmony_ci *         FAILED
415262306a36Sopenharmony_ci */
415362306a36Sopenharmony_cistatic int mpi3mr_eh_dev_reset(struct scsi_cmnd *scmd)
415462306a36Sopenharmony_ci{
415562306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host);
415662306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *stgt_priv_data;
415762306a36Sopenharmony_ci	struct mpi3mr_sdev_priv_data *sdev_priv_data;
415862306a36Sopenharmony_ci	u16 dev_handle;
415962306a36Sopenharmony_ci	u8 resp_code = 0;
416062306a36Sopenharmony_ci	int retval = FAILED, ret = 0;
416162306a36Sopenharmony_ci
416262306a36Sopenharmony_ci	sdev_printk(KERN_INFO, scmd->device,
416362306a36Sopenharmony_ci	    "Attempting Device(lun) Reset! scmd(%p)\n", scmd);
416462306a36Sopenharmony_ci	scsi_print_command(scmd);
416562306a36Sopenharmony_ci
416662306a36Sopenharmony_ci	sdev_priv_data = scmd->device->hostdata;
416762306a36Sopenharmony_ci	if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) {
416862306a36Sopenharmony_ci		sdev_printk(KERN_INFO, scmd->device,
416962306a36Sopenharmony_ci		    "SCSI device is not available\n");
417062306a36Sopenharmony_ci		retval = SUCCESS;
417162306a36Sopenharmony_ci		goto out;
417262306a36Sopenharmony_ci	}
417362306a36Sopenharmony_ci
417462306a36Sopenharmony_ci	stgt_priv_data = sdev_priv_data->tgt_priv_data;
417562306a36Sopenharmony_ci	dev_handle = stgt_priv_data->dev_handle;
417662306a36Sopenharmony_ci	if (stgt_priv_data->dev_removed) {
417762306a36Sopenharmony_ci		struct scmd_priv *cmd_priv = scsi_cmd_priv(scmd);
417862306a36Sopenharmony_ci		sdev_printk(KERN_INFO, scmd->device,
417962306a36Sopenharmony_ci		    "%s: device(handle = 0x%04x) is removed, device(LUN) reset is not issued\n",
418062306a36Sopenharmony_ci		    mrioc->name, dev_handle);
418162306a36Sopenharmony_ci		if (!cmd_priv->in_lld_scope || cmd_priv->host_tag == MPI3MR_HOSTTAG_INVALID)
418262306a36Sopenharmony_ci			retval = SUCCESS;
418362306a36Sopenharmony_ci		else
418462306a36Sopenharmony_ci			retval = FAILED;
418562306a36Sopenharmony_ci		goto out;
418662306a36Sopenharmony_ci	}
418762306a36Sopenharmony_ci	sdev_printk(KERN_INFO, scmd->device,
418862306a36Sopenharmony_ci	    "Device(lun) Reset is issued to handle(0x%04x)\n", dev_handle);
418962306a36Sopenharmony_ci
419062306a36Sopenharmony_ci	ret = mpi3mr_issue_tm(mrioc,
419162306a36Sopenharmony_ci	    MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, dev_handle,
419262306a36Sopenharmony_ci	    sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS,
419362306a36Sopenharmony_ci	    MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, scmd);
419462306a36Sopenharmony_ci
419562306a36Sopenharmony_ci	if (ret)
419662306a36Sopenharmony_ci		goto out;
419762306a36Sopenharmony_ci
419862306a36Sopenharmony_ci	if (sdev_priv_data->pend_count) {
419962306a36Sopenharmony_ci		sdev_printk(KERN_INFO, scmd->device,
420062306a36Sopenharmony_ci		    "%s: device has %d pending commands, device(LUN) reset is failed\n",
420162306a36Sopenharmony_ci		    mrioc->name, sdev_priv_data->pend_count);
420262306a36Sopenharmony_ci		goto out;
420362306a36Sopenharmony_ci	}
420462306a36Sopenharmony_ci	retval = SUCCESS;
420562306a36Sopenharmony_ciout:
420662306a36Sopenharmony_ci	sdev_printk(KERN_INFO, scmd->device,
420762306a36Sopenharmony_ci	    "%s: device(LUN) reset is %s for scmd(%p)\n", mrioc->name,
420862306a36Sopenharmony_ci	    ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
420962306a36Sopenharmony_ci
421062306a36Sopenharmony_ci	return retval;
421162306a36Sopenharmony_ci}
421262306a36Sopenharmony_ci
421362306a36Sopenharmony_ci/**
421462306a36Sopenharmony_ci * mpi3mr_scan_start - Scan start callback handler
421562306a36Sopenharmony_ci * @shost: SCSI host reference
421662306a36Sopenharmony_ci *
421762306a36Sopenharmony_ci * Issue port enable request asynchronously.
421862306a36Sopenharmony_ci *
421962306a36Sopenharmony_ci * Return: Nothing
422062306a36Sopenharmony_ci */
422162306a36Sopenharmony_cistatic void mpi3mr_scan_start(struct Scsi_Host *shost)
422262306a36Sopenharmony_ci{
422362306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc = shost_priv(shost);
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_ci	mrioc->scan_started = 1;
422662306a36Sopenharmony_ci	ioc_info(mrioc, "%s :Issuing Port Enable\n", __func__);
422762306a36Sopenharmony_ci	if (mpi3mr_issue_port_enable(mrioc, 1)) {
422862306a36Sopenharmony_ci		ioc_err(mrioc, "%s :Issuing port enable failed\n", __func__);
422962306a36Sopenharmony_ci		mrioc->scan_started = 0;
423062306a36Sopenharmony_ci		mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR;
423162306a36Sopenharmony_ci	}
423262306a36Sopenharmony_ci}
423362306a36Sopenharmony_ci
423462306a36Sopenharmony_ci/**
423562306a36Sopenharmony_ci * mpi3mr_scan_finished - Scan finished callback handler
423662306a36Sopenharmony_ci * @shost: SCSI host reference
423762306a36Sopenharmony_ci * @time: Jiffies from the scan start
423862306a36Sopenharmony_ci *
423962306a36Sopenharmony_ci * Checks whether the port enable is completed or timedout or
424062306a36Sopenharmony_ci * failed and set the scan status accordingly after taking any
424162306a36Sopenharmony_ci * recovery if required.
424262306a36Sopenharmony_ci *
424362306a36Sopenharmony_ci * Return: 1 on scan finished or timed out, 0 for in progress
424462306a36Sopenharmony_ci */
424562306a36Sopenharmony_cistatic int mpi3mr_scan_finished(struct Scsi_Host *shost,
424662306a36Sopenharmony_ci	unsigned long time)
424762306a36Sopenharmony_ci{
424862306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc = shost_priv(shost);
424962306a36Sopenharmony_ci	u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT;
425062306a36Sopenharmony_ci	u32 ioc_status = readl(&mrioc->sysif_regs->ioc_status);
425162306a36Sopenharmony_ci
425262306a36Sopenharmony_ci	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
425362306a36Sopenharmony_ci	    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
425462306a36Sopenharmony_ci		ioc_err(mrioc, "port enable failed due to fault or reset\n");
425562306a36Sopenharmony_ci		mpi3mr_print_fault_info(mrioc);
425662306a36Sopenharmony_ci		mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR;
425762306a36Sopenharmony_ci		mrioc->scan_started = 0;
425862306a36Sopenharmony_ci		mrioc->init_cmds.is_waiting = 0;
425962306a36Sopenharmony_ci		mrioc->init_cmds.callback = NULL;
426062306a36Sopenharmony_ci		mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
426162306a36Sopenharmony_ci	}
426262306a36Sopenharmony_ci
426362306a36Sopenharmony_ci	if (time >= (pe_timeout * HZ)) {
426462306a36Sopenharmony_ci		ioc_err(mrioc, "port enable failed due to time out\n");
426562306a36Sopenharmony_ci		mpi3mr_check_rh_fault_ioc(mrioc,
426662306a36Sopenharmony_ci		    MPI3MR_RESET_FROM_PE_TIMEOUT);
426762306a36Sopenharmony_ci		mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR;
426862306a36Sopenharmony_ci		mrioc->scan_started = 0;
426962306a36Sopenharmony_ci		mrioc->init_cmds.is_waiting = 0;
427062306a36Sopenharmony_ci		mrioc->init_cmds.callback = NULL;
427162306a36Sopenharmony_ci		mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
427262306a36Sopenharmony_ci	}
427362306a36Sopenharmony_ci
427462306a36Sopenharmony_ci	if (mrioc->scan_started)
427562306a36Sopenharmony_ci		return 0;
427662306a36Sopenharmony_ci
427762306a36Sopenharmony_ci	if (mrioc->scan_failed) {
427862306a36Sopenharmony_ci		ioc_err(mrioc,
427962306a36Sopenharmony_ci		    "port enable failed with status=0x%04x\n",
428062306a36Sopenharmony_ci		    mrioc->scan_failed);
428162306a36Sopenharmony_ci	} else
428262306a36Sopenharmony_ci		ioc_info(mrioc, "port enable is successfully completed\n");
428362306a36Sopenharmony_ci
428462306a36Sopenharmony_ci	mpi3mr_start_watchdog(mrioc);
428562306a36Sopenharmony_ci	mrioc->is_driver_loading = 0;
428662306a36Sopenharmony_ci	mrioc->stop_bsgs = 0;
428762306a36Sopenharmony_ci	return 1;
428862306a36Sopenharmony_ci}
428962306a36Sopenharmony_ci
429062306a36Sopenharmony_ci/**
429162306a36Sopenharmony_ci * mpi3mr_slave_destroy - Slave destroy callback handler
429262306a36Sopenharmony_ci * @sdev: SCSI device reference
429362306a36Sopenharmony_ci *
429462306a36Sopenharmony_ci * Cleanup and free per device(lun) private data.
429562306a36Sopenharmony_ci *
429662306a36Sopenharmony_ci * Return: Nothing.
429762306a36Sopenharmony_ci */
429862306a36Sopenharmony_cistatic void mpi3mr_slave_destroy(struct scsi_device *sdev)
429962306a36Sopenharmony_ci{
430062306a36Sopenharmony_ci	struct Scsi_Host *shost;
430162306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc;
430262306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
430362306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgt_dev = NULL;
430462306a36Sopenharmony_ci	unsigned long flags;
430562306a36Sopenharmony_ci	struct scsi_target *starget;
430662306a36Sopenharmony_ci	struct sas_rphy *rphy = NULL;
430762306a36Sopenharmony_ci
430862306a36Sopenharmony_ci	if (!sdev->hostdata)
430962306a36Sopenharmony_ci		return;
431062306a36Sopenharmony_ci
431162306a36Sopenharmony_ci	starget = scsi_target(sdev);
431262306a36Sopenharmony_ci	shost = dev_to_shost(&starget->dev);
431362306a36Sopenharmony_ci	mrioc = shost_priv(shost);
431462306a36Sopenharmony_ci	scsi_tgt_priv_data = starget->hostdata;
431562306a36Sopenharmony_ci
431662306a36Sopenharmony_ci	scsi_tgt_priv_data->num_luns--;
431762306a36Sopenharmony_ci
431862306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
431962306a36Sopenharmony_ci	if (starget->channel == mrioc->scsi_device_channel)
432062306a36Sopenharmony_ci		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
432162306a36Sopenharmony_ci	else if (mrioc->sas_transport_enabled && !starget->channel) {
432262306a36Sopenharmony_ci		rphy = dev_to_rphy(starget->dev.parent);
432362306a36Sopenharmony_ci		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
432462306a36Sopenharmony_ci		    rphy->identify.sas_address, rphy);
432562306a36Sopenharmony_ci	}
432662306a36Sopenharmony_ci
432762306a36Sopenharmony_ci	if (tgt_dev && (!scsi_tgt_priv_data->num_luns))
432862306a36Sopenharmony_ci		tgt_dev->starget = NULL;
432962306a36Sopenharmony_ci	if (tgt_dev)
433062306a36Sopenharmony_ci		mpi3mr_tgtdev_put(tgt_dev);
433162306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
433262306a36Sopenharmony_ci
433362306a36Sopenharmony_ci	kfree(sdev->hostdata);
433462306a36Sopenharmony_ci	sdev->hostdata = NULL;
433562306a36Sopenharmony_ci}
433662306a36Sopenharmony_ci
433762306a36Sopenharmony_ci/**
433862306a36Sopenharmony_ci * mpi3mr_target_destroy - Target destroy callback handler
433962306a36Sopenharmony_ci * @starget: SCSI target reference
434062306a36Sopenharmony_ci *
434162306a36Sopenharmony_ci * Cleanup and free per target private data.
434262306a36Sopenharmony_ci *
434362306a36Sopenharmony_ci * Return: Nothing.
434462306a36Sopenharmony_ci */
434562306a36Sopenharmony_cistatic void mpi3mr_target_destroy(struct scsi_target *starget)
434662306a36Sopenharmony_ci{
434762306a36Sopenharmony_ci	struct Scsi_Host *shost;
434862306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc;
434962306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
435062306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgt_dev;
435162306a36Sopenharmony_ci	unsigned long flags;
435262306a36Sopenharmony_ci
435362306a36Sopenharmony_ci	if (!starget->hostdata)
435462306a36Sopenharmony_ci		return;
435562306a36Sopenharmony_ci
435662306a36Sopenharmony_ci	shost = dev_to_shost(&starget->dev);
435762306a36Sopenharmony_ci	mrioc = shost_priv(shost);
435862306a36Sopenharmony_ci	scsi_tgt_priv_data = starget->hostdata;
435962306a36Sopenharmony_ci
436062306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
436162306a36Sopenharmony_ci	tgt_dev = __mpi3mr_get_tgtdev_from_tgtpriv(mrioc, scsi_tgt_priv_data);
436262306a36Sopenharmony_ci	if (tgt_dev && (tgt_dev->starget == starget) &&
436362306a36Sopenharmony_ci	    (tgt_dev->perst_id == starget->id))
436462306a36Sopenharmony_ci		tgt_dev->starget = NULL;
436562306a36Sopenharmony_ci	if (tgt_dev) {
436662306a36Sopenharmony_ci		scsi_tgt_priv_data->tgt_dev = NULL;
436762306a36Sopenharmony_ci		scsi_tgt_priv_data->perst_id = 0;
436862306a36Sopenharmony_ci		mpi3mr_tgtdev_put(tgt_dev);
436962306a36Sopenharmony_ci		mpi3mr_tgtdev_put(tgt_dev);
437062306a36Sopenharmony_ci	}
437162306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
437262306a36Sopenharmony_ci
437362306a36Sopenharmony_ci	kfree(starget->hostdata);
437462306a36Sopenharmony_ci	starget->hostdata = NULL;
437562306a36Sopenharmony_ci}
437662306a36Sopenharmony_ci
437762306a36Sopenharmony_ci/**
437862306a36Sopenharmony_ci * mpi3mr_slave_configure - Slave configure callback handler
437962306a36Sopenharmony_ci * @sdev: SCSI device reference
438062306a36Sopenharmony_ci *
438162306a36Sopenharmony_ci * Configure queue depth, max hardware sectors and virt boundary
438262306a36Sopenharmony_ci * as required
438362306a36Sopenharmony_ci *
438462306a36Sopenharmony_ci * Return: 0 always.
438562306a36Sopenharmony_ci */
438662306a36Sopenharmony_cistatic int mpi3mr_slave_configure(struct scsi_device *sdev)
438762306a36Sopenharmony_ci{
438862306a36Sopenharmony_ci	struct scsi_target *starget;
438962306a36Sopenharmony_ci	struct Scsi_Host *shost;
439062306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc;
439162306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgt_dev = NULL;
439262306a36Sopenharmony_ci	unsigned long flags;
439362306a36Sopenharmony_ci	int retval = 0;
439462306a36Sopenharmony_ci	struct sas_rphy *rphy = NULL;
439562306a36Sopenharmony_ci
439662306a36Sopenharmony_ci	starget = scsi_target(sdev);
439762306a36Sopenharmony_ci	shost = dev_to_shost(&starget->dev);
439862306a36Sopenharmony_ci	mrioc = shost_priv(shost);
439962306a36Sopenharmony_ci
440062306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
440162306a36Sopenharmony_ci	if (starget->channel == mrioc->scsi_device_channel)
440262306a36Sopenharmony_ci		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
440362306a36Sopenharmony_ci	else if (mrioc->sas_transport_enabled && !starget->channel) {
440462306a36Sopenharmony_ci		rphy = dev_to_rphy(starget->dev.parent);
440562306a36Sopenharmony_ci		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
440662306a36Sopenharmony_ci		    rphy->identify.sas_address, rphy);
440762306a36Sopenharmony_ci	}
440862306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
440962306a36Sopenharmony_ci	if (!tgt_dev)
441062306a36Sopenharmony_ci		return -ENXIO;
441162306a36Sopenharmony_ci
441262306a36Sopenharmony_ci	mpi3mr_change_queue_depth(sdev, tgt_dev->q_depth);
441362306a36Sopenharmony_ci
441462306a36Sopenharmony_ci	sdev->eh_timeout = MPI3MR_EH_SCMD_TIMEOUT;
441562306a36Sopenharmony_ci	blk_queue_rq_timeout(sdev->request_queue, MPI3MR_SCMD_TIMEOUT);
441662306a36Sopenharmony_ci
441762306a36Sopenharmony_ci	switch (tgt_dev->dev_type) {
441862306a36Sopenharmony_ci	case MPI3_DEVICE_DEVFORM_PCIE:
441962306a36Sopenharmony_ci		/*The block layer hw sector size = 512*/
442062306a36Sopenharmony_ci		if ((tgt_dev->dev_spec.pcie_inf.dev_info &
442162306a36Sopenharmony_ci		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) ==
442262306a36Sopenharmony_ci		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) {
442362306a36Sopenharmony_ci			blk_queue_max_hw_sectors(sdev->request_queue,
442462306a36Sopenharmony_ci			    tgt_dev->dev_spec.pcie_inf.mdts / 512);
442562306a36Sopenharmony_ci			if (tgt_dev->dev_spec.pcie_inf.pgsz == 0)
442662306a36Sopenharmony_ci				blk_queue_virt_boundary(sdev->request_queue,
442762306a36Sopenharmony_ci				    ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1));
442862306a36Sopenharmony_ci			else
442962306a36Sopenharmony_ci				blk_queue_virt_boundary(sdev->request_queue,
443062306a36Sopenharmony_ci				    ((1 << tgt_dev->dev_spec.pcie_inf.pgsz) - 1));
443162306a36Sopenharmony_ci		}
443262306a36Sopenharmony_ci		break;
443362306a36Sopenharmony_ci	default:
443462306a36Sopenharmony_ci		break;
443562306a36Sopenharmony_ci	}
443662306a36Sopenharmony_ci
443762306a36Sopenharmony_ci	mpi3mr_tgtdev_put(tgt_dev);
443862306a36Sopenharmony_ci
443962306a36Sopenharmony_ci	return retval;
444062306a36Sopenharmony_ci}
444162306a36Sopenharmony_ci
444262306a36Sopenharmony_ci/**
444362306a36Sopenharmony_ci * mpi3mr_slave_alloc -Slave alloc callback handler
444462306a36Sopenharmony_ci * @sdev: SCSI device reference
444562306a36Sopenharmony_ci *
444662306a36Sopenharmony_ci * Allocate per device(lun) private data and initialize it.
444762306a36Sopenharmony_ci *
444862306a36Sopenharmony_ci * Return: 0 on success -ENOMEM on memory allocation failure.
444962306a36Sopenharmony_ci */
445062306a36Sopenharmony_cistatic int mpi3mr_slave_alloc(struct scsi_device *sdev)
445162306a36Sopenharmony_ci{
445262306a36Sopenharmony_ci	struct Scsi_Host *shost;
445362306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc;
445462306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
445562306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgt_dev = NULL;
445662306a36Sopenharmony_ci	struct mpi3mr_sdev_priv_data *scsi_dev_priv_data;
445762306a36Sopenharmony_ci	unsigned long flags;
445862306a36Sopenharmony_ci	struct scsi_target *starget;
445962306a36Sopenharmony_ci	int retval = 0;
446062306a36Sopenharmony_ci	struct sas_rphy *rphy = NULL;
446162306a36Sopenharmony_ci
446262306a36Sopenharmony_ci	starget = scsi_target(sdev);
446362306a36Sopenharmony_ci	shost = dev_to_shost(&starget->dev);
446462306a36Sopenharmony_ci	mrioc = shost_priv(shost);
446562306a36Sopenharmony_ci	scsi_tgt_priv_data = starget->hostdata;
446662306a36Sopenharmony_ci
446762306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
446862306a36Sopenharmony_ci
446962306a36Sopenharmony_ci	if (starget->channel == mrioc->scsi_device_channel)
447062306a36Sopenharmony_ci		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
447162306a36Sopenharmony_ci	else if (mrioc->sas_transport_enabled && !starget->channel) {
447262306a36Sopenharmony_ci		rphy = dev_to_rphy(starget->dev.parent);
447362306a36Sopenharmony_ci		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
447462306a36Sopenharmony_ci		    rphy->identify.sas_address, rphy);
447562306a36Sopenharmony_ci	}
447662306a36Sopenharmony_ci
447762306a36Sopenharmony_ci	if (tgt_dev) {
447862306a36Sopenharmony_ci		if (tgt_dev->starget == NULL)
447962306a36Sopenharmony_ci			tgt_dev->starget = starget;
448062306a36Sopenharmony_ci		mpi3mr_tgtdev_put(tgt_dev);
448162306a36Sopenharmony_ci		retval = 0;
448262306a36Sopenharmony_ci	} else {
448362306a36Sopenharmony_ci		spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
448462306a36Sopenharmony_ci		return -ENXIO;
448562306a36Sopenharmony_ci	}
448662306a36Sopenharmony_ci
448762306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
448862306a36Sopenharmony_ci
448962306a36Sopenharmony_ci	scsi_dev_priv_data = kzalloc(sizeof(*scsi_dev_priv_data), GFP_KERNEL);
449062306a36Sopenharmony_ci	if (!scsi_dev_priv_data)
449162306a36Sopenharmony_ci		return -ENOMEM;
449262306a36Sopenharmony_ci
449362306a36Sopenharmony_ci	scsi_dev_priv_data->lun_id = sdev->lun;
449462306a36Sopenharmony_ci	scsi_dev_priv_data->tgt_priv_data = scsi_tgt_priv_data;
449562306a36Sopenharmony_ci	sdev->hostdata = scsi_dev_priv_data;
449662306a36Sopenharmony_ci
449762306a36Sopenharmony_ci	scsi_tgt_priv_data->num_luns++;
449862306a36Sopenharmony_ci
449962306a36Sopenharmony_ci	return retval;
450062306a36Sopenharmony_ci}
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci/**
450362306a36Sopenharmony_ci * mpi3mr_target_alloc - Target alloc callback handler
450462306a36Sopenharmony_ci * @starget: SCSI target reference
450562306a36Sopenharmony_ci *
450662306a36Sopenharmony_ci * Allocate per target private data and initialize it.
450762306a36Sopenharmony_ci *
450862306a36Sopenharmony_ci * Return: 0 on success -ENOMEM on memory allocation failure.
450962306a36Sopenharmony_ci */
451062306a36Sopenharmony_cistatic int mpi3mr_target_alloc(struct scsi_target *starget)
451162306a36Sopenharmony_ci{
451262306a36Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
451362306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc = shost_priv(shost);
451462306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
451562306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgt_dev;
451662306a36Sopenharmony_ci	unsigned long flags;
451762306a36Sopenharmony_ci	int retval = 0;
451862306a36Sopenharmony_ci	struct sas_rphy *rphy = NULL;
451962306a36Sopenharmony_ci
452062306a36Sopenharmony_ci	scsi_tgt_priv_data = kzalloc(sizeof(*scsi_tgt_priv_data), GFP_KERNEL);
452162306a36Sopenharmony_ci	if (!scsi_tgt_priv_data)
452262306a36Sopenharmony_ci		return -ENOMEM;
452362306a36Sopenharmony_ci
452462306a36Sopenharmony_ci	starget->hostdata = scsi_tgt_priv_data;
452562306a36Sopenharmony_ci
452662306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
452762306a36Sopenharmony_ci	if (starget->channel == mrioc->scsi_device_channel) {
452862306a36Sopenharmony_ci		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
452962306a36Sopenharmony_ci		if (tgt_dev && !tgt_dev->is_hidden) {
453062306a36Sopenharmony_ci			scsi_tgt_priv_data->starget = starget;
453162306a36Sopenharmony_ci			scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle;
453262306a36Sopenharmony_ci			scsi_tgt_priv_data->perst_id = tgt_dev->perst_id;
453362306a36Sopenharmony_ci			scsi_tgt_priv_data->dev_type = tgt_dev->dev_type;
453462306a36Sopenharmony_ci			scsi_tgt_priv_data->tgt_dev = tgt_dev;
453562306a36Sopenharmony_ci			tgt_dev->starget = starget;
453662306a36Sopenharmony_ci			atomic_set(&scsi_tgt_priv_data->block_io, 0);
453762306a36Sopenharmony_ci			retval = 0;
453862306a36Sopenharmony_ci			if ((tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_PCIE) &&
453962306a36Sopenharmony_ci			    ((tgt_dev->dev_spec.pcie_inf.dev_info &
454062306a36Sopenharmony_ci			    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) ==
454162306a36Sopenharmony_ci			    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) &&
454262306a36Sopenharmony_ci			    ((tgt_dev->dev_spec.pcie_inf.dev_info &
454362306a36Sopenharmony_ci			    MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_MASK) !=
454462306a36Sopenharmony_ci			    MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_0))
454562306a36Sopenharmony_ci				scsi_tgt_priv_data->dev_nvme_dif = 1;
454662306a36Sopenharmony_ci			scsi_tgt_priv_data->io_throttle_enabled = tgt_dev->io_throttle_enabled;
454762306a36Sopenharmony_ci			scsi_tgt_priv_data->wslen = tgt_dev->wslen;
454862306a36Sopenharmony_ci			if (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_VD)
454962306a36Sopenharmony_ci				scsi_tgt_priv_data->throttle_group = tgt_dev->dev_spec.vd_inf.tg;
455062306a36Sopenharmony_ci		} else
455162306a36Sopenharmony_ci			retval = -ENXIO;
455262306a36Sopenharmony_ci	} else if (mrioc->sas_transport_enabled && !starget->channel) {
455362306a36Sopenharmony_ci		rphy = dev_to_rphy(starget->dev.parent);
455462306a36Sopenharmony_ci		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
455562306a36Sopenharmony_ci		    rphy->identify.sas_address, rphy);
455662306a36Sopenharmony_ci		if (tgt_dev && !tgt_dev->is_hidden && !tgt_dev->non_stl &&
455762306a36Sopenharmony_ci		    (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA)) {
455862306a36Sopenharmony_ci			scsi_tgt_priv_data->starget = starget;
455962306a36Sopenharmony_ci			scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle;
456062306a36Sopenharmony_ci			scsi_tgt_priv_data->perst_id = tgt_dev->perst_id;
456162306a36Sopenharmony_ci			scsi_tgt_priv_data->dev_type = tgt_dev->dev_type;
456262306a36Sopenharmony_ci			scsi_tgt_priv_data->tgt_dev = tgt_dev;
456362306a36Sopenharmony_ci			scsi_tgt_priv_data->io_throttle_enabled = tgt_dev->io_throttle_enabled;
456462306a36Sopenharmony_ci			scsi_tgt_priv_data->wslen = tgt_dev->wslen;
456562306a36Sopenharmony_ci			tgt_dev->starget = starget;
456662306a36Sopenharmony_ci			atomic_set(&scsi_tgt_priv_data->block_io, 0);
456762306a36Sopenharmony_ci			retval = 0;
456862306a36Sopenharmony_ci		} else
456962306a36Sopenharmony_ci			retval = -ENXIO;
457062306a36Sopenharmony_ci	}
457162306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
457262306a36Sopenharmony_ci
457362306a36Sopenharmony_ci	return retval;
457462306a36Sopenharmony_ci}
457562306a36Sopenharmony_ci
457662306a36Sopenharmony_ci/**
457762306a36Sopenharmony_ci * mpi3mr_check_return_unmap - Whether an unmap is allowed
457862306a36Sopenharmony_ci * @mrioc: Adapter instance reference
457962306a36Sopenharmony_ci * @scmd: SCSI Command reference
458062306a36Sopenharmony_ci *
458162306a36Sopenharmony_ci * The controller hardware cannot handle certain unmap commands
458262306a36Sopenharmony_ci * for NVMe drives, this routine checks those and return true
458362306a36Sopenharmony_ci * and completes the SCSI command with proper status and sense
458462306a36Sopenharmony_ci * data.
458562306a36Sopenharmony_ci *
458662306a36Sopenharmony_ci * Return: TRUE for not  allowed unmap, FALSE otherwise.
458762306a36Sopenharmony_ci */
458862306a36Sopenharmony_cistatic bool mpi3mr_check_return_unmap(struct mpi3mr_ioc *mrioc,
458962306a36Sopenharmony_ci	struct scsi_cmnd *scmd)
459062306a36Sopenharmony_ci{
459162306a36Sopenharmony_ci	unsigned char *buf;
459262306a36Sopenharmony_ci	u16 param_len, desc_len, trunc_param_len;
459362306a36Sopenharmony_ci
459462306a36Sopenharmony_ci	trunc_param_len = param_len = get_unaligned_be16(scmd->cmnd + 7);
459562306a36Sopenharmony_ci
459662306a36Sopenharmony_ci	if (mrioc->pdev->revision) {
459762306a36Sopenharmony_ci		if ((param_len > 24) && ((param_len - 8) & 0xF)) {
459862306a36Sopenharmony_ci			trunc_param_len -= (param_len - 8) & 0xF;
459962306a36Sopenharmony_ci			dprint_scsi_command(mrioc, scmd, MPI3_DEBUG_SCSI_ERROR);
460062306a36Sopenharmony_ci			dprint_scsi_err(mrioc,
460162306a36Sopenharmony_ci			    "truncating param_len from (%d) to (%d)\n",
460262306a36Sopenharmony_ci			    param_len, trunc_param_len);
460362306a36Sopenharmony_ci			put_unaligned_be16(trunc_param_len, scmd->cmnd + 7);
460462306a36Sopenharmony_ci			dprint_scsi_command(mrioc, scmd, MPI3_DEBUG_SCSI_ERROR);
460562306a36Sopenharmony_ci		}
460662306a36Sopenharmony_ci		return false;
460762306a36Sopenharmony_ci	}
460862306a36Sopenharmony_ci
460962306a36Sopenharmony_ci	if (!param_len) {
461062306a36Sopenharmony_ci		ioc_warn(mrioc,
461162306a36Sopenharmony_ci		    "%s: cdb received with zero parameter length\n",
461262306a36Sopenharmony_ci		    __func__);
461362306a36Sopenharmony_ci		scsi_print_command(scmd);
461462306a36Sopenharmony_ci		scmd->result = DID_OK << 16;
461562306a36Sopenharmony_ci		scsi_done(scmd);
461662306a36Sopenharmony_ci		return true;
461762306a36Sopenharmony_ci	}
461862306a36Sopenharmony_ci
461962306a36Sopenharmony_ci	if (param_len < 24) {
462062306a36Sopenharmony_ci		ioc_warn(mrioc,
462162306a36Sopenharmony_ci		    "%s: cdb received with invalid param_len: %d\n",
462262306a36Sopenharmony_ci		    __func__, param_len);
462362306a36Sopenharmony_ci		scsi_print_command(scmd);
462462306a36Sopenharmony_ci		scmd->result = SAM_STAT_CHECK_CONDITION;
462562306a36Sopenharmony_ci		scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
462662306a36Sopenharmony_ci		    0x1A, 0);
462762306a36Sopenharmony_ci		scsi_done(scmd);
462862306a36Sopenharmony_ci		return true;
462962306a36Sopenharmony_ci	}
463062306a36Sopenharmony_ci	if (param_len != scsi_bufflen(scmd)) {
463162306a36Sopenharmony_ci		ioc_warn(mrioc,
463262306a36Sopenharmony_ci		    "%s: cdb received with param_len: %d bufflen: %d\n",
463362306a36Sopenharmony_ci		    __func__, param_len, scsi_bufflen(scmd));
463462306a36Sopenharmony_ci		scsi_print_command(scmd);
463562306a36Sopenharmony_ci		scmd->result = SAM_STAT_CHECK_CONDITION;
463662306a36Sopenharmony_ci		scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
463762306a36Sopenharmony_ci		    0x1A, 0);
463862306a36Sopenharmony_ci		scsi_done(scmd);
463962306a36Sopenharmony_ci		return true;
464062306a36Sopenharmony_ci	}
464162306a36Sopenharmony_ci	buf = kzalloc(scsi_bufflen(scmd), GFP_ATOMIC);
464262306a36Sopenharmony_ci	if (!buf) {
464362306a36Sopenharmony_ci		scsi_print_command(scmd);
464462306a36Sopenharmony_ci		scmd->result = SAM_STAT_CHECK_CONDITION;
464562306a36Sopenharmony_ci		scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
464662306a36Sopenharmony_ci		    0x55, 0x03);
464762306a36Sopenharmony_ci		scsi_done(scmd);
464862306a36Sopenharmony_ci		return true;
464962306a36Sopenharmony_ci	}
465062306a36Sopenharmony_ci	scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
465162306a36Sopenharmony_ci	desc_len = get_unaligned_be16(&buf[2]);
465262306a36Sopenharmony_ci
465362306a36Sopenharmony_ci	if (desc_len < 16) {
465462306a36Sopenharmony_ci		ioc_warn(mrioc,
465562306a36Sopenharmony_ci		    "%s: Invalid descriptor length in param list: %d\n",
465662306a36Sopenharmony_ci		    __func__, desc_len);
465762306a36Sopenharmony_ci		scsi_print_command(scmd);
465862306a36Sopenharmony_ci		scmd->result = SAM_STAT_CHECK_CONDITION;
465962306a36Sopenharmony_ci		scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
466062306a36Sopenharmony_ci		    0x26, 0);
466162306a36Sopenharmony_ci		scsi_done(scmd);
466262306a36Sopenharmony_ci		kfree(buf);
466362306a36Sopenharmony_ci		return true;
466462306a36Sopenharmony_ci	}
466562306a36Sopenharmony_ci
466662306a36Sopenharmony_ci	if (param_len > (desc_len + 8)) {
466762306a36Sopenharmony_ci		trunc_param_len = desc_len + 8;
466862306a36Sopenharmony_ci		scsi_print_command(scmd);
466962306a36Sopenharmony_ci		dprint_scsi_err(mrioc,
467062306a36Sopenharmony_ci		    "truncating param_len(%d) to desc_len+8(%d)\n",
467162306a36Sopenharmony_ci		    param_len, trunc_param_len);
467262306a36Sopenharmony_ci		put_unaligned_be16(trunc_param_len, scmd->cmnd + 7);
467362306a36Sopenharmony_ci		scsi_print_command(scmd);
467462306a36Sopenharmony_ci	}
467562306a36Sopenharmony_ci
467662306a36Sopenharmony_ci	kfree(buf);
467762306a36Sopenharmony_ci	return false;
467862306a36Sopenharmony_ci}
467962306a36Sopenharmony_ci
468062306a36Sopenharmony_ci/**
468162306a36Sopenharmony_ci * mpi3mr_allow_scmd_to_fw - Command is allowed during shutdown
468262306a36Sopenharmony_ci * @scmd: SCSI Command reference
468362306a36Sopenharmony_ci *
468462306a36Sopenharmony_ci * Checks whether a cdb is allowed during shutdown or not.
468562306a36Sopenharmony_ci *
468662306a36Sopenharmony_ci * Return: TRUE for allowed commands, FALSE otherwise.
468762306a36Sopenharmony_ci */
468862306a36Sopenharmony_ci
468962306a36Sopenharmony_ciinline bool mpi3mr_allow_scmd_to_fw(struct scsi_cmnd *scmd)
469062306a36Sopenharmony_ci{
469162306a36Sopenharmony_ci	switch (scmd->cmnd[0]) {
469262306a36Sopenharmony_ci	case SYNCHRONIZE_CACHE:
469362306a36Sopenharmony_ci	case START_STOP:
469462306a36Sopenharmony_ci		return true;
469562306a36Sopenharmony_ci	default:
469662306a36Sopenharmony_ci		return false;
469762306a36Sopenharmony_ci	}
469862306a36Sopenharmony_ci}
469962306a36Sopenharmony_ci
470062306a36Sopenharmony_ci/**
470162306a36Sopenharmony_ci * mpi3mr_qcmd - I/O request despatcher
470262306a36Sopenharmony_ci * @shost: SCSI Host reference
470362306a36Sopenharmony_ci * @scmd: SCSI Command reference
470462306a36Sopenharmony_ci *
470562306a36Sopenharmony_ci * Issues the SCSI Command as an MPI3 request.
470662306a36Sopenharmony_ci *
470762306a36Sopenharmony_ci * Return: 0 on successful queueing of the request or if the
470862306a36Sopenharmony_ci *         request is completed with failure.
470962306a36Sopenharmony_ci *         SCSI_MLQUEUE_DEVICE_BUSY when the device is busy.
471062306a36Sopenharmony_ci *         SCSI_MLQUEUE_HOST_BUSY when the host queue is full.
471162306a36Sopenharmony_ci */
471262306a36Sopenharmony_cistatic int mpi3mr_qcmd(struct Scsi_Host *shost,
471362306a36Sopenharmony_ci	struct scsi_cmnd *scmd)
471462306a36Sopenharmony_ci{
471562306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc = shost_priv(shost);
471662306a36Sopenharmony_ci	struct mpi3mr_stgt_priv_data *stgt_priv_data;
471762306a36Sopenharmony_ci	struct mpi3mr_sdev_priv_data *sdev_priv_data;
471862306a36Sopenharmony_ci	struct scmd_priv *scmd_priv_data = NULL;
471962306a36Sopenharmony_ci	struct mpi3_scsi_io_request *scsiio_req = NULL;
472062306a36Sopenharmony_ci	struct op_req_qinfo *op_req_q = NULL;
472162306a36Sopenharmony_ci	int retval = 0;
472262306a36Sopenharmony_ci	u16 dev_handle;
472362306a36Sopenharmony_ci	u16 host_tag;
472462306a36Sopenharmony_ci	u32 scsiio_flags = 0, data_len_blks = 0;
472562306a36Sopenharmony_ci	struct request *rq = scsi_cmd_to_rq(scmd);
472662306a36Sopenharmony_ci	int iprio_class;
472762306a36Sopenharmony_ci	u8 is_pcie_dev = 0;
472862306a36Sopenharmony_ci	u32 tracked_io_sz = 0;
472962306a36Sopenharmony_ci	u32 ioc_pend_data_len = 0, tg_pend_data_len = 0;
473062306a36Sopenharmony_ci	struct mpi3mr_throttle_group_info *tg = NULL;
473162306a36Sopenharmony_ci
473262306a36Sopenharmony_ci	if (mrioc->unrecoverable) {
473362306a36Sopenharmony_ci		scmd->result = DID_ERROR << 16;
473462306a36Sopenharmony_ci		scsi_done(scmd);
473562306a36Sopenharmony_ci		goto out;
473662306a36Sopenharmony_ci	}
473762306a36Sopenharmony_ci
473862306a36Sopenharmony_ci	sdev_priv_data = scmd->device->hostdata;
473962306a36Sopenharmony_ci	if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) {
474062306a36Sopenharmony_ci		scmd->result = DID_NO_CONNECT << 16;
474162306a36Sopenharmony_ci		scsi_done(scmd);
474262306a36Sopenharmony_ci		goto out;
474362306a36Sopenharmony_ci	}
474462306a36Sopenharmony_ci
474562306a36Sopenharmony_ci	if (mrioc->stop_drv_processing &&
474662306a36Sopenharmony_ci	    !(mpi3mr_allow_scmd_to_fw(scmd))) {
474762306a36Sopenharmony_ci		scmd->result = DID_NO_CONNECT << 16;
474862306a36Sopenharmony_ci		scsi_done(scmd);
474962306a36Sopenharmony_ci		goto out;
475062306a36Sopenharmony_ci	}
475162306a36Sopenharmony_ci
475262306a36Sopenharmony_ci	stgt_priv_data = sdev_priv_data->tgt_priv_data;
475362306a36Sopenharmony_ci	dev_handle = stgt_priv_data->dev_handle;
475462306a36Sopenharmony_ci
475562306a36Sopenharmony_ci	/* Avoid error handling escalation when device is removed or blocked */
475662306a36Sopenharmony_ci
475762306a36Sopenharmony_ci	if (scmd->device->host->shost_state == SHOST_RECOVERY &&
475862306a36Sopenharmony_ci		scmd->cmnd[0] == TEST_UNIT_READY &&
475962306a36Sopenharmony_ci		(stgt_priv_data->dev_removed || (dev_handle == MPI3MR_INVALID_DEV_HANDLE))) {
476062306a36Sopenharmony_ci		scsi_build_sense(scmd, 0, UNIT_ATTENTION, 0x29, 0x07);
476162306a36Sopenharmony_ci		scsi_done(scmd);
476262306a36Sopenharmony_ci		goto out;
476362306a36Sopenharmony_ci	}
476462306a36Sopenharmony_ci
476562306a36Sopenharmony_ci	if (mrioc->reset_in_progress) {
476662306a36Sopenharmony_ci		retval = SCSI_MLQUEUE_HOST_BUSY;
476762306a36Sopenharmony_ci		goto out;
476862306a36Sopenharmony_ci	}
476962306a36Sopenharmony_ci
477062306a36Sopenharmony_ci	if (atomic_read(&stgt_priv_data->block_io)) {
477162306a36Sopenharmony_ci		if (mrioc->stop_drv_processing) {
477262306a36Sopenharmony_ci			scmd->result = DID_NO_CONNECT << 16;
477362306a36Sopenharmony_ci			scsi_done(scmd);
477462306a36Sopenharmony_ci			goto out;
477562306a36Sopenharmony_ci		}
477662306a36Sopenharmony_ci		retval = SCSI_MLQUEUE_DEVICE_BUSY;
477762306a36Sopenharmony_ci		goto out;
477862306a36Sopenharmony_ci	}
477962306a36Sopenharmony_ci
478062306a36Sopenharmony_ci	if (dev_handle == MPI3MR_INVALID_DEV_HANDLE) {
478162306a36Sopenharmony_ci		scmd->result = DID_NO_CONNECT << 16;
478262306a36Sopenharmony_ci		scsi_done(scmd);
478362306a36Sopenharmony_ci		goto out;
478462306a36Sopenharmony_ci	}
478562306a36Sopenharmony_ci	if (stgt_priv_data->dev_removed) {
478662306a36Sopenharmony_ci		scmd->result = DID_NO_CONNECT << 16;
478762306a36Sopenharmony_ci		scsi_done(scmd);
478862306a36Sopenharmony_ci		goto out;
478962306a36Sopenharmony_ci	}
479062306a36Sopenharmony_ci
479162306a36Sopenharmony_ci	if (stgt_priv_data->dev_type == MPI3_DEVICE_DEVFORM_PCIE)
479262306a36Sopenharmony_ci		is_pcie_dev = 1;
479362306a36Sopenharmony_ci	if ((scmd->cmnd[0] == UNMAP) && is_pcie_dev &&
479462306a36Sopenharmony_ci	    (mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) &&
479562306a36Sopenharmony_ci	    mpi3mr_check_return_unmap(mrioc, scmd))
479662306a36Sopenharmony_ci		goto out;
479762306a36Sopenharmony_ci
479862306a36Sopenharmony_ci	host_tag = mpi3mr_host_tag_for_scmd(mrioc, scmd);
479962306a36Sopenharmony_ci	if (host_tag == MPI3MR_HOSTTAG_INVALID) {
480062306a36Sopenharmony_ci		scmd->result = DID_ERROR << 16;
480162306a36Sopenharmony_ci		scsi_done(scmd);
480262306a36Sopenharmony_ci		goto out;
480362306a36Sopenharmony_ci	}
480462306a36Sopenharmony_ci
480562306a36Sopenharmony_ci	if (scmd->sc_data_direction == DMA_FROM_DEVICE)
480662306a36Sopenharmony_ci		scsiio_flags = MPI3_SCSIIO_FLAGS_DATADIRECTION_READ;
480762306a36Sopenharmony_ci	else if (scmd->sc_data_direction == DMA_TO_DEVICE)
480862306a36Sopenharmony_ci		scsiio_flags = MPI3_SCSIIO_FLAGS_DATADIRECTION_WRITE;
480962306a36Sopenharmony_ci	else
481062306a36Sopenharmony_ci		scsiio_flags = MPI3_SCSIIO_FLAGS_DATADIRECTION_NO_DATA_TRANSFER;
481162306a36Sopenharmony_ci
481262306a36Sopenharmony_ci	scsiio_flags |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SIMPLEQ;
481362306a36Sopenharmony_ci
481462306a36Sopenharmony_ci	if (sdev_priv_data->ncq_prio_enable) {
481562306a36Sopenharmony_ci		iprio_class = IOPRIO_PRIO_CLASS(req_get_ioprio(rq));
481662306a36Sopenharmony_ci		if (iprio_class == IOPRIO_CLASS_RT)
481762306a36Sopenharmony_ci			scsiio_flags |= 1 << MPI3_SCSIIO_FLAGS_CMDPRI_SHIFT;
481862306a36Sopenharmony_ci	}
481962306a36Sopenharmony_ci
482062306a36Sopenharmony_ci	if (scmd->cmd_len > 16)
482162306a36Sopenharmony_ci		scsiio_flags |= MPI3_SCSIIO_FLAGS_CDB_GREATER_THAN_16;
482262306a36Sopenharmony_ci
482362306a36Sopenharmony_ci	scmd_priv_data = scsi_cmd_priv(scmd);
482462306a36Sopenharmony_ci	memset(scmd_priv_data->mpi3mr_scsiio_req, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
482562306a36Sopenharmony_ci	scsiio_req = (struct mpi3_scsi_io_request *)scmd_priv_data->mpi3mr_scsiio_req;
482662306a36Sopenharmony_ci	scsiio_req->function = MPI3_FUNCTION_SCSI_IO;
482762306a36Sopenharmony_ci	scsiio_req->host_tag = cpu_to_le16(host_tag);
482862306a36Sopenharmony_ci
482962306a36Sopenharmony_ci	mpi3mr_setup_eedp(mrioc, scmd, scsiio_req);
483062306a36Sopenharmony_ci
483162306a36Sopenharmony_ci	if (stgt_priv_data->wslen)
483262306a36Sopenharmony_ci		mpi3mr_setup_divert_ws(mrioc, scmd, scsiio_req, &scsiio_flags,
483362306a36Sopenharmony_ci		    stgt_priv_data->wslen);
483462306a36Sopenharmony_ci
483562306a36Sopenharmony_ci	memcpy(scsiio_req->cdb.cdb32, scmd->cmnd, scmd->cmd_len);
483662306a36Sopenharmony_ci	scsiio_req->data_length = cpu_to_le32(scsi_bufflen(scmd));
483762306a36Sopenharmony_ci	scsiio_req->dev_handle = cpu_to_le16(dev_handle);
483862306a36Sopenharmony_ci	scsiio_req->flags = cpu_to_le32(scsiio_flags);
483962306a36Sopenharmony_ci	int_to_scsilun(sdev_priv_data->lun_id,
484062306a36Sopenharmony_ci	    (struct scsi_lun *)scsiio_req->lun);
484162306a36Sopenharmony_ci
484262306a36Sopenharmony_ci	if (mpi3mr_build_sg_scmd(mrioc, scmd, scsiio_req)) {
484362306a36Sopenharmony_ci		mpi3mr_clear_scmd_priv(mrioc, scmd);
484462306a36Sopenharmony_ci		retval = SCSI_MLQUEUE_HOST_BUSY;
484562306a36Sopenharmony_ci		goto out;
484662306a36Sopenharmony_ci	}
484762306a36Sopenharmony_ci	op_req_q = &mrioc->req_qinfo[scmd_priv_data->req_q_idx];
484862306a36Sopenharmony_ci	data_len_blks = scsi_bufflen(scmd) >> 9;
484962306a36Sopenharmony_ci	if ((data_len_blks >= mrioc->io_throttle_data_length) &&
485062306a36Sopenharmony_ci	    stgt_priv_data->io_throttle_enabled) {
485162306a36Sopenharmony_ci		tracked_io_sz = data_len_blks;
485262306a36Sopenharmony_ci		tg = stgt_priv_data->throttle_group;
485362306a36Sopenharmony_ci		if (tg) {
485462306a36Sopenharmony_ci			ioc_pend_data_len = atomic_add_return(data_len_blks,
485562306a36Sopenharmony_ci			    &mrioc->pend_large_data_sz);
485662306a36Sopenharmony_ci			tg_pend_data_len = atomic_add_return(data_len_blks,
485762306a36Sopenharmony_ci			    &tg->pend_large_data_sz);
485862306a36Sopenharmony_ci			if (!tg->io_divert  && ((ioc_pend_data_len >=
485962306a36Sopenharmony_ci			    mrioc->io_throttle_high) ||
486062306a36Sopenharmony_ci			    (tg_pend_data_len >= tg->high))) {
486162306a36Sopenharmony_ci				tg->io_divert = 1;
486262306a36Sopenharmony_ci				tg->need_qd_reduction = 1;
486362306a36Sopenharmony_ci				mpi3mr_set_io_divert_for_all_vd_in_tg(mrioc,
486462306a36Sopenharmony_ci				    tg, 1);
486562306a36Sopenharmony_ci				mpi3mr_queue_qd_reduction_event(mrioc, tg);
486662306a36Sopenharmony_ci			}
486762306a36Sopenharmony_ci		} else {
486862306a36Sopenharmony_ci			ioc_pend_data_len = atomic_add_return(data_len_blks,
486962306a36Sopenharmony_ci			    &mrioc->pend_large_data_sz);
487062306a36Sopenharmony_ci			if (ioc_pend_data_len >= mrioc->io_throttle_high)
487162306a36Sopenharmony_ci				stgt_priv_data->io_divert = 1;
487262306a36Sopenharmony_ci		}
487362306a36Sopenharmony_ci	}
487462306a36Sopenharmony_ci
487562306a36Sopenharmony_ci	if (stgt_priv_data->io_divert) {
487662306a36Sopenharmony_ci		scsiio_req->msg_flags |=
487762306a36Sopenharmony_ci		    MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE;
487862306a36Sopenharmony_ci		scsiio_flags |= MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING;
487962306a36Sopenharmony_ci	}
488062306a36Sopenharmony_ci	scsiio_req->flags = cpu_to_le32(scsiio_flags);
488162306a36Sopenharmony_ci
488262306a36Sopenharmony_ci	if (mpi3mr_op_request_post(mrioc, op_req_q,
488362306a36Sopenharmony_ci	    scmd_priv_data->mpi3mr_scsiio_req)) {
488462306a36Sopenharmony_ci		mpi3mr_clear_scmd_priv(mrioc, scmd);
488562306a36Sopenharmony_ci		retval = SCSI_MLQUEUE_HOST_BUSY;
488662306a36Sopenharmony_ci		if (tracked_io_sz) {
488762306a36Sopenharmony_ci			atomic_sub(tracked_io_sz, &mrioc->pend_large_data_sz);
488862306a36Sopenharmony_ci			if (tg)
488962306a36Sopenharmony_ci				atomic_sub(tracked_io_sz,
489062306a36Sopenharmony_ci				    &tg->pend_large_data_sz);
489162306a36Sopenharmony_ci		}
489262306a36Sopenharmony_ci		goto out;
489362306a36Sopenharmony_ci	}
489462306a36Sopenharmony_ci
489562306a36Sopenharmony_ciout:
489662306a36Sopenharmony_ci	return retval;
489762306a36Sopenharmony_ci}
489862306a36Sopenharmony_ci
489962306a36Sopenharmony_cistatic const struct scsi_host_template mpi3mr_driver_template = {
490062306a36Sopenharmony_ci	.module				= THIS_MODULE,
490162306a36Sopenharmony_ci	.name				= "MPI3 Storage Controller",
490262306a36Sopenharmony_ci	.proc_name			= MPI3MR_DRIVER_NAME,
490362306a36Sopenharmony_ci	.queuecommand			= mpi3mr_qcmd,
490462306a36Sopenharmony_ci	.target_alloc			= mpi3mr_target_alloc,
490562306a36Sopenharmony_ci	.slave_alloc			= mpi3mr_slave_alloc,
490662306a36Sopenharmony_ci	.slave_configure		= mpi3mr_slave_configure,
490762306a36Sopenharmony_ci	.target_destroy			= mpi3mr_target_destroy,
490862306a36Sopenharmony_ci	.slave_destroy			= mpi3mr_slave_destroy,
490962306a36Sopenharmony_ci	.scan_finished			= mpi3mr_scan_finished,
491062306a36Sopenharmony_ci	.scan_start			= mpi3mr_scan_start,
491162306a36Sopenharmony_ci	.change_queue_depth		= mpi3mr_change_queue_depth,
491262306a36Sopenharmony_ci	.eh_device_reset_handler	= mpi3mr_eh_dev_reset,
491362306a36Sopenharmony_ci	.eh_target_reset_handler	= mpi3mr_eh_target_reset,
491462306a36Sopenharmony_ci	.eh_host_reset_handler		= mpi3mr_eh_host_reset,
491562306a36Sopenharmony_ci	.bios_param			= mpi3mr_bios_param,
491662306a36Sopenharmony_ci	.map_queues			= mpi3mr_map_queues,
491762306a36Sopenharmony_ci	.mq_poll                        = mpi3mr_blk_mq_poll,
491862306a36Sopenharmony_ci	.no_write_same			= 1,
491962306a36Sopenharmony_ci	.can_queue			= 1,
492062306a36Sopenharmony_ci	.this_id			= -1,
492162306a36Sopenharmony_ci	.sg_tablesize			= MPI3MR_DEFAULT_SGL_ENTRIES,
492262306a36Sopenharmony_ci	/* max xfer supported is 1M (2K in 512 byte sized sectors)
492362306a36Sopenharmony_ci	 */
492462306a36Sopenharmony_ci	.max_sectors			= (MPI3MR_DEFAULT_MAX_IO_SIZE / 512),
492562306a36Sopenharmony_ci	.cmd_per_lun			= MPI3MR_MAX_CMDS_LUN,
492662306a36Sopenharmony_ci	.max_segment_size		= 0xffffffff,
492762306a36Sopenharmony_ci	.track_queue_depth		= 1,
492862306a36Sopenharmony_ci	.cmd_size			= sizeof(struct scmd_priv),
492962306a36Sopenharmony_ci	.shost_groups			= mpi3mr_host_groups,
493062306a36Sopenharmony_ci	.sdev_groups			= mpi3mr_dev_groups,
493162306a36Sopenharmony_ci};
493262306a36Sopenharmony_ci
493362306a36Sopenharmony_ci/**
493462306a36Sopenharmony_ci * mpi3mr_init_drv_cmd - Initialize internal command tracker
493562306a36Sopenharmony_ci * @cmdptr: Internal command tracker
493662306a36Sopenharmony_ci * @host_tag: Host tag used for the specific command
493762306a36Sopenharmony_ci *
493862306a36Sopenharmony_ci * Initialize the internal command tracker structure with
493962306a36Sopenharmony_ci * specified host tag.
494062306a36Sopenharmony_ci *
494162306a36Sopenharmony_ci * Return: Nothing.
494262306a36Sopenharmony_ci */
494362306a36Sopenharmony_cistatic inline void mpi3mr_init_drv_cmd(struct mpi3mr_drv_cmd *cmdptr,
494462306a36Sopenharmony_ci	u16 host_tag)
494562306a36Sopenharmony_ci{
494662306a36Sopenharmony_ci	mutex_init(&cmdptr->mutex);
494762306a36Sopenharmony_ci	cmdptr->reply = NULL;
494862306a36Sopenharmony_ci	cmdptr->state = MPI3MR_CMD_NOTUSED;
494962306a36Sopenharmony_ci	cmdptr->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
495062306a36Sopenharmony_ci	cmdptr->host_tag = host_tag;
495162306a36Sopenharmony_ci}
495262306a36Sopenharmony_ci
495362306a36Sopenharmony_ci/**
495462306a36Sopenharmony_ci * osintfc_mrioc_security_status -Check controller secure status
495562306a36Sopenharmony_ci * @pdev: PCI device instance
495662306a36Sopenharmony_ci *
495762306a36Sopenharmony_ci * Read the Device Serial Number capability from PCI config
495862306a36Sopenharmony_ci * space and decide whether the controller is secure or not.
495962306a36Sopenharmony_ci *
496062306a36Sopenharmony_ci * Return: 0 on success, non-zero on failure.
496162306a36Sopenharmony_ci */
496262306a36Sopenharmony_cistatic int
496362306a36Sopenharmony_ciosintfc_mrioc_security_status(struct pci_dev *pdev)
496462306a36Sopenharmony_ci{
496562306a36Sopenharmony_ci	u32 cap_data;
496662306a36Sopenharmony_ci	int base;
496762306a36Sopenharmony_ci	u32 ctlr_status;
496862306a36Sopenharmony_ci	u32 debug_status;
496962306a36Sopenharmony_ci	int retval = 0;
497062306a36Sopenharmony_ci
497162306a36Sopenharmony_ci	base = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DSN);
497262306a36Sopenharmony_ci	if (!base) {
497362306a36Sopenharmony_ci		dev_err(&pdev->dev,
497462306a36Sopenharmony_ci		    "%s: PCI_EXT_CAP_ID_DSN is not supported\n", __func__);
497562306a36Sopenharmony_ci		return -1;
497662306a36Sopenharmony_ci	}
497762306a36Sopenharmony_ci
497862306a36Sopenharmony_ci	pci_read_config_dword(pdev, base + 4, &cap_data);
497962306a36Sopenharmony_ci
498062306a36Sopenharmony_ci	debug_status = cap_data & MPI3MR_CTLR_SECURE_DBG_STATUS_MASK;
498162306a36Sopenharmony_ci	ctlr_status = cap_data & MPI3MR_CTLR_SECURITY_STATUS_MASK;
498262306a36Sopenharmony_ci
498362306a36Sopenharmony_ci	switch (ctlr_status) {
498462306a36Sopenharmony_ci	case MPI3MR_INVALID_DEVICE:
498562306a36Sopenharmony_ci		dev_err(&pdev->dev,
498662306a36Sopenharmony_ci		    "%s: Non secure ctlr (Invalid) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
498762306a36Sopenharmony_ci		    __func__, pdev->device, pdev->subsystem_vendor,
498862306a36Sopenharmony_ci		    pdev->subsystem_device);
498962306a36Sopenharmony_ci		retval = -1;
499062306a36Sopenharmony_ci		break;
499162306a36Sopenharmony_ci	case MPI3MR_CONFIG_SECURE_DEVICE:
499262306a36Sopenharmony_ci		if (!debug_status)
499362306a36Sopenharmony_ci			dev_info(&pdev->dev,
499462306a36Sopenharmony_ci			    "%s: Config secure ctlr is detected\n",
499562306a36Sopenharmony_ci			    __func__);
499662306a36Sopenharmony_ci		break;
499762306a36Sopenharmony_ci	case MPI3MR_HARD_SECURE_DEVICE:
499862306a36Sopenharmony_ci		break;
499962306a36Sopenharmony_ci	case MPI3MR_TAMPERED_DEVICE:
500062306a36Sopenharmony_ci		dev_err(&pdev->dev,
500162306a36Sopenharmony_ci		    "%s: Non secure ctlr (Tampered) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
500262306a36Sopenharmony_ci		    __func__, pdev->device, pdev->subsystem_vendor,
500362306a36Sopenharmony_ci		    pdev->subsystem_device);
500462306a36Sopenharmony_ci		retval = -1;
500562306a36Sopenharmony_ci		break;
500662306a36Sopenharmony_ci	default:
500762306a36Sopenharmony_ci		retval = -1;
500862306a36Sopenharmony_ci			break;
500962306a36Sopenharmony_ci	}
501062306a36Sopenharmony_ci
501162306a36Sopenharmony_ci	if (!retval && debug_status) {
501262306a36Sopenharmony_ci		dev_err(&pdev->dev,
501362306a36Sopenharmony_ci		    "%s: Non secure ctlr (Secure Dbg) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
501462306a36Sopenharmony_ci		    __func__, pdev->device, pdev->subsystem_vendor,
501562306a36Sopenharmony_ci		    pdev->subsystem_device);
501662306a36Sopenharmony_ci		retval = -1;
501762306a36Sopenharmony_ci	}
501862306a36Sopenharmony_ci
501962306a36Sopenharmony_ci	return retval;
502062306a36Sopenharmony_ci}
502162306a36Sopenharmony_ci
502262306a36Sopenharmony_ci/**
502362306a36Sopenharmony_ci * mpi3mr_probe - PCI probe callback
502462306a36Sopenharmony_ci * @pdev: PCI device instance
502562306a36Sopenharmony_ci * @id: PCI device ID details
502662306a36Sopenharmony_ci *
502762306a36Sopenharmony_ci * controller initialization routine. Checks the security status
502862306a36Sopenharmony_ci * of the controller and if it is invalid or tampered return the
502962306a36Sopenharmony_ci * probe without initializing the controller. Otherwise,
503062306a36Sopenharmony_ci * allocate per adapter instance through shost_priv and
503162306a36Sopenharmony_ci * initialize controller specific data structures, initializae
503262306a36Sopenharmony_ci * the controller hardware, add shost to the SCSI subsystem.
503362306a36Sopenharmony_ci *
503462306a36Sopenharmony_ci * Return: 0 on success, non-zero on failure.
503562306a36Sopenharmony_ci */
503662306a36Sopenharmony_ci
503762306a36Sopenharmony_cistatic int
503862306a36Sopenharmony_cimpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
503962306a36Sopenharmony_ci{
504062306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc = NULL;
504162306a36Sopenharmony_ci	struct Scsi_Host *shost = NULL;
504262306a36Sopenharmony_ci	int retval = 0, i;
504362306a36Sopenharmony_ci
504462306a36Sopenharmony_ci	if (osintfc_mrioc_security_status(pdev)) {
504562306a36Sopenharmony_ci		warn_non_secure_ctlr = 1;
504662306a36Sopenharmony_ci		return 1; /* For Invalid and Tampered device */
504762306a36Sopenharmony_ci	}
504862306a36Sopenharmony_ci
504962306a36Sopenharmony_ci	shost = scsi_host_alloc(&mpi3mr_driver_template,
505062306a36Sopenharmony_ci	    sizeof(struct mpi3mr_ioc));
505162306a36Sopenharmony_ci	if (!shost) {
505262306a36Sopenharmony_ci		retval = -ENODEV;
505362306a36Sopenharmony_ci		goto shost_failed;
505462306a36Sopenharmony_ci	}
505562306a36Sopenharmony_ci
505662306a36Sopenharmony_ci	mrioc = shost_priv(shost);
505762306a36Sopenharmony_ci	mrioc->id = mrioc_ids++;
505862306a36Sopenharmony_ci	sprintf(mrioc->driver_name, "%s", MPI3MR_DRIVER_NAME);
505962306a36Sopenharmony_ci	sprintf(mrioc->name, "%s%d", mrioc->driver_name, mrioc->id);
506062306a36Sopenharmony_ci	INIT_LIST_HEAD(&mrioc->list);
506162306a36Sopenharmony_ci	spin_lock(&mrioc_list_lock);
506262306a36Sopenharmony_ci	list_add_tail(&mrioc->list, &mrioc_list);
506362306a36Sopenharmony_ci	spin_unlock(&mrioc_list_lock);
506462306a36Sopenharmony_ci
506562306a36Sopenharmony_ci	spin_lock_init(&mrioc->admin_req_lock);
506662306a36Sopenharmony_ci	spin_lock_init(&mrioc->reply_free_queue_lock);
506762306a36Sopenharmony_ci	spin_lock_init(&mrioc->sbq_lock);
506862306a36Sopenharmony_ci	spin_lock_init(&mrioc->fwevt_lock);
506962306a36Sopenharmony_ci	spin_lock_init(&mrioc->tgtdev_lock);
507062306a36Sopenharmony_ci	spin_lock_init(&mrioc->watchdog_lock);
507162306a36Sopenharmony_ci	spin_lock_init(&mrioc->chain_buf_lock);
507262306a36Sopenharmony_ci	spin_lock_init(&mrioc->sas_node_lock);
507362306a36Sopenharmony_ci
507462306a36Sopenharmony_ci	INIT_LIST_HEAD(&mrioc->fwevt_list);
507562306a36Sopenharmony_ci	INIT_LIST_HEAD(&mrioc->tgtdev_list);
507662306a36Sopenharmony_ci	INIT_LIST_HEAD(&mrioc->delayed_rmhs_list);
507762306a36Sopenharmony_ci	INIT_LIST_HEAD(&mrioc->delayed_evtack_cmds_list);
507862306a36Sopenharmony_ci	INIT_LIST_HEAD(&mrioc->sas_expander_list);
507962306a36Sopenharmony_ci	INIT_LIST_HEAD(&mrioc->hba_port_table_list);
508062306a36Sopenharmony_ci	INIT_LIST_HEAD(&mrioc->enclosure_list);
508162306a36Sopenharmony_ci
508262306a36Sopenharmony_ci	mutex_init(&mrioc->reset_mutex);
508362306a36Sopenharmony_ci	mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
508462306a36Sopenharmony_ci	mpi3mr_init_drv_cmd(&mrioc->host_tm_cmds, MPI3MR_HOSTTAG_BLK_TMS);
508562306a36Sopenharmony_ci	mpi3mr_init_drv_cmd(&mrioc->bsg_cmds, MPI3MR_HOSTTAG_BSG_CMDS);
508662306a36Sopenharmony_ci	mpi3mr_init_drv_cmd(&mrioc->cfg_cmds, MPI3MR_HOSTTAG_CFG_CMDS);
508762306a36Sopenharmony_ci	mpi3mr_init_drv_cmd(&mrioc->transport_cmds,
508862306a36Sopenharmony_ci	    MPI3MR_HOSTTAG_TRANSPORT_CMDS);
508962306a36Sopenharmony_ci
509062306a36Sopenharmony_ci	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
509162306a36Sopenharmony_ci		mpi3mr_init_drv_cmd(&mrioc->dev_rmhs_cmds[i],
509262306a36Sopenharmony_ci		    MPI3MR_HOSTTAG_DEVRMCMD_MIN + i);
509362306a36Sopenharmony_ci
509462306a36Sopenharmony_ci	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++)
509562306a36Sopenharmony_ci		mpi3mr_init_drv_cmd(&mrioc->evtack_cmds[i],
509662306a36Sopenharmony_ci				    MPI3MR_HOSTTAG_EVTACKCMD_MIN + i);
509762306a36Sopenharmony_ci
509862306a36Sopenharmony_ci	if ((pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) &&
509962306a36Sopenharmony_ci		!pdev->revision)
510062306a36Sopenharmony_ci		mrioc->enable_segqueue = false;
510162306a36Sopenharmony_ci	else
510262306a36Sopenharmony_ci		mrioc->enable_segqueue = true;
510362306a36Sopenharmony_ci
510462306a36Sopenharmony_ci	init_waitqueue_head(&mrioc->reset_waitq);
510562306a36Sopenharmony_ci	mrioc->logging_level = logging_level;
510662306a36Sopenharmony_ci	mrioc->shost = shost;
510762306a36Sopenharmony_ci	mrioc->pdev = pdev;
510862306a36Sopenharmony_ci	mrioc->stop_bsgs = 1;
510962306a36Sopenharmony_ci
511062306a36Sopenharmony_ci	mrioc->max_sgl_entries = max_sgl_entries;
511162306a36Sopenharmony_ci	if (max_sgl_entries > MPI3MR_MAX_SGL_ENTRIES)
511262306a36Sopenharmony_ci		mrioc->max_sgl_entries = MPI3MR_MAX_SGL_ENTRIES;
511362306a36Sopenharmony_ci	else if (max_sgl_entries < MPI3MR_DEFAULT_SGL_ENTRIES)
511462306a36Sopenharmony_ci		mrioc->max_sgl_entries = MPI3MR_DEFAULT_SGL_ENTRIES;
511562306a36Sopenharmony_ci	else {
511662306a36Sopenharmony_ci		mrioc->max_sgl_entries /= MPI3MR_DEFAULT_SGL_ENTRIES;
511762306a36Sopenharmony_ci		mrioc->max_sgl_entries *= MPI3MR_DEFAULT_SGL_ENTRIES;
511862306a36Sopenharmony_ci	}
511962306a36Sopenharmony_ci
512062306a36Sopenharmony_ci	/* init shost parameters */
512162306a36Sopenharmony_ci	shost->max_cmd_len = MPI3MR_MAX_CDB_LENGTH;
512262306a36Sopenharmony_ci	shost->max_lun = -1;
512362306a36Sopenharmony_ci	shost->unique_id = mrioc->id;
512462306a36Sopenharmony_ci
512562306a36Sopenharmony_ci	shost->max_channel = 0;
512662306a36Sopenharmony_ci	shost->max_id = 0xFFFFFFFF;
512762306a36Sopenharmony_ci
512862306a36Sopenharmony_ci	shost->host_tagset = 1;
512962306a36Sopenharmony_ci
513062306a36Sopenharmony_ci	if (prot_mask >= 0)
513162306a36Sopenharmony_ci		scsi_host_set_prot(shost, prot_mask);
513262306a36Sopenharmony_ci	else {
513362306a36Sopenharmony_ci		prot_mask = SHOST_DIF_TYPE1_PROTECTION
513462306a36Sopenharmony_ci		    | SHOST_DIF_TYPE2_PROTECTION
513562306a36Sopenharmony_ci		    | SHOST_DIF_TYPE3_PROTECTION;
513662306a36Sopenharmony_ci		scsi_host_set_prot(shost, prot_mask);
513762306a36Sopenharmony_ci	}
513862306a36Sopenharmony_ci
513962306a36Sopenharmony_ci	ioc_info(mrioc,
514062306a36Sopenharmony_ci	    "%s :host protection capabilities enabled %s%s%s%s%s%s%s\n",
514162306a36Sopenharmony_ci	    __func__,
514262306a36Sopenharmony_ci	    (prot_mask & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
514362306a36Sopenharmony_ci	    (prot_mask & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
514462306a36Sopenharmony_ci	    (prot_mask & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
514562306a36Sopenharmony_ci	    (prot_mask & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
514662306a36Sopenharmony_ci	    (prot_mask & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
514762306a36Sopenharmony_ci	    (prot_mask & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
514862306a36Sopenharmony_ci	    (prot_mask & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
514962306a36Sopenharmony_ci
515062306a36Sopenharmony_ci	if (prot_guard_mask)
515162306a36Sopenharmony_ci		scsi_host_set_guard(shost, (prot_guard_mask & 3));
515262306a36Sopenharmony_ci	else
515362306a36Sopenharmony_ci		scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
515462306a36Sopenharmony_ci
515562306a36Sopenharmony_ci	snprintf(mrioc->fwevt_worker_name, sizeof(mrioc->fwevt_worker_name),
515662306a36Sopenharmony_ci	    "%s%d_fwevt_wrkr", mrioc->driver_name, mrioc->id);
515762306a36Sopenharmony_ci	mrioc->fwevt_worker_thread = alloc_ordered_workqueue(
515862306a36Sopenharmony_ci	    mrioc->fwevt_worker_name, 0);
515962306a36Sopenharmony_ci	if (!mrioc->fwevt_worker_thread) {
516062306a36Sopenharmony_ci		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
516162306a36Sopenharmony_ci		    __FILE__, __LINE__, __func__);
516262306a36Sopenharmony_ci		retval = -ENODEV;
516362306a36Sopenharmony_ci		goto fwevtthread_failed;
516462306a36Sopenharmony_ci	}
516562306a36Sopenharmony_ci
516662306a36Sopenharmony_ci	mrioc->is_driver_loading = 1;
516762306a36Sopenharmony_ci	mrioc->cpu_count = num_online_cpus();
516862306a36Sopenharmony_ci	if (mpi3mr_setup_resources(mrioc)) {
516962306a36Sopenharmony_ci		ioc_err(mrioc, "setup resources failed\n");
517062306a36Sopenharmony_ci		retval = -ENODEV;
517162306a36Sopenharmony_ci		goto resource_alloc_failed;
517262306a36Sopenharmony_ci	}
517362306a36Sopenharmony_ci	if (mpi3mr_init_ioc(mrioc)) {
517462306a36Sopenharmony_ci		ioc_err(mrioc, "initializing IOC failed\n");
517562306a36Sopenharmony_ci		retval = -ENODEV;
517662306a36Sopenharmony_ci		goto init_ioc_failed;
517762306a36Sopenharmony_ci	}
517862306a36Sopenharmony_ci
517962306a36Sopenharmony_ci	shost->nr_hw_queues = mrioc->num_op_reply_q;
518062306a36Sopenharmony_ci	if (mrioc->active_poll_qcount)
518162306a36Sopenharmony_ci		shost->nr_maps = 3;
518262306a36Sopenharmony_ci
518362306a36Sopenharmony_ci	shost->can_queue = mrioc->max_host_ios;
518462306a36Sopenharmony_ci	shost->sg_tablesize = mrioc->max_sgl_entries;
518562306a36Sopenharmony_ci	shost->max_id = mrioc->facts.max_perids + 1;
518662306a36Sopenharmony_ci
518762306a36Sopenharmony_ci	retval = scsi_add_host(shost, &pdev->dev);
518862306a36Sopenharmony_ci	if (retval) {
518962306a36Sopenharmony_ci		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
519062306a36Sopenharmony_ci		    __FILE__, __LINE__, __func__);
519162306a36Sopenharmony_ci		goto addhost_failed;
519262306a36Sopenharmony_ci	}
519362306a36Sopenharmony_ci
519462306a36Sopenharmony_ci	scsi_scan_host(shost);
519562306a36Sopenharmony_ci	mpi3mr_bsg_init(mrioc);
519662306a36Sopenharmony_ci	return retval;
519762306a36Sopenharmony_ci
519862306a36Sopenharmony_ciaddhost_failed:
519962306a36Sopenharmony_ci	mpi3mr_stop_watchdog(mrioc);
520062306a36Sopenharmony_ci	mpi3mr_cleanup_ioc(mrioc);
520162306a36Sopenharmony_ciinit_ioc_failed:
520262306a36Sopenharmony_ci	mpi3mr_free_mem(mrioc);
520362306a36Sopenharmony_ci	mpi3mr_cleanup_resources(mrioc);
520462306a36Sopenharmony_ciresource_alloc_failed:
520562306a36Sopenharmony_ci	destroy_workqueue(mrioc->fwevt_worker_thread);
520662306a36Sopenharmony_cifwevtthread_failed:
520762306a36Sopenharmony_ci	spin_lock(&mrioc_list_lock);
520862306a36Sopenharmony_ci	list_del(&mrioc->list);
520962306a36Sopenharmony_ci	spin_unlock(&mrioc_list_lock);
521062306a36Sopenharmony_ci	scsi_host_put(shost);
521162306a36Sopenharmony_cishost_failed:
521262306a36Sopenharmony_ci	return retval;
521362306a36Sopenharmony_ci}
521462306a36Sopenharmony_ci
521562306a36Sopenharmony_ci/**
521662306a36Sopenharmony_ci * mpi3mr_remove - PCI remove callback
521762306a36Sopenharmony_ci * @pdev: PCI device instance
521862306a36Sopenharmony_ci *
521962306a36Sopenharmony_ci * Cleanup the IOC by issuing MUR and shutdown notification.
522062306a36Sopenharmony_ci * Free up all memory and resources associated with the
522162306a36Sopenharmony_ci * controllerand target devices, unregister the shost.
522262306a36Sopenharmony_ci *
522362306a36Sopenharmony_ci * Return: Nothing.
522462306a36Sopenharmony_ci */
522562306a36Sopenharmony_cistatic void mpi3mr_remove(struct pci_dev *pdev)
522662306a36Sopenharmony_ci{
522762306a36Sopenharmony_ci	struct Scsi_Host *shost = pci_get_drvdata(pdev);
522862306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc;
522962306a36Sopenharmony_ci	struct workqueue_struct	*wq;
523062306a36Sopenharmony_ci	unsigned long flags;
523162306a36Sopenharmony_ci	struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next;
523262306a36Sopenharmony_ci	struct mpi3mr_hba_port *port, *hba_port_next;
523362306a36Sopenharmony_ci	struct mpi3mr_sas_node *sas_expander, *sas_expander_next;
523462306a36Sopenharmony_ci
523562306a36Sopenharmony_ci	if (!shost)
523662306a36Sopenharmony_ci		return;
523762306a36Sopenharmony_ci
523862306a36Sopenharmony_ci	mrioc = shost_priv(shost);
523962306a36Sopenharmony_ci	while (mrioc->reset_in_progress || mrioc->is_driver_loading)
524062306a36Sopenharmony_ci		ssleep(1);
524162306a36Sopenharmony_ci
524262306a36Sopenharmony_ci	if (!pci_device_is_present(mrioc->pdev)) {
524362306a36Sopenharmony_ci		mrioc->unrecoverable = 1;
524462306a36Sopenharmony_ci		mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
524562306a36Sopenharmony_ci	}
524662306a36Sopenharmony_ci
524762306a36Sopenharmony_ci	mpi3mr_bsg_exit(mrioc);
524862306a36Sopenharmony_ci	mrioc->stop_drv_processing = 1;
524962306a36Sopenharmony_ci	mpi3mr_cleanup_fwevt_list(mrioc);
525062306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->fwevt_lock, flags);
525162306a36Sopenharmony_ci	wq = mrioc->fwevt_worker_thread;
525262306a36Sopenharmony_ci	mrioc->fwevt_worker_thread = NULL;
525362306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
525462306a36Sopenharmony_ci	if (wq)
525562306a36Sopenharmony_ci		destroy_workqueue(wq);
525662306a36Sopenharmony_ci
525762306a36Sopenharmony_ci	if (mrioc->sas_transport_enabled)
525862306a36Sopenharmony_ci		sas_remove_host(shost);
525962306a36Sopenharmony_ci	else
526062306a36Sopenharmony_ci		scsi_remove_host(shost);
526162306a36Sopenharmony_ci
526262306a36Sopenharmony_ci	list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
526362306a36Sopenharmony_ci	    list) {
526462306a36Sopenharmony_ci		mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
526562306a36Sopenharmony_ci		mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, true);
526662306a36Sopenharmony_ci		mpi3mr_tgtdev_put(tgtdev);
526762306a36Sopenharmony_ci	}
526862306a36Sopenharmony_ci	mpi3mr_stop_watchdog(mrioc);
526962306a36Sopenharmony_ci	mpi3mr_cleanup_ioc(mrioc);
527062306a36Sopenharmony_ci	mpi3mr_free_mem(mrioc);
527162306a36Sopenharmony_ci	mpi3mr_cleanup_resources(mrioc);
527262306a36Sopenharmony_ci
527362306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
527462306a36Sopenharmony_ci	list_for_each_entry_safe_reverse(sas_expander, sas_expander_next,
527562306a36Sopenharmony_ci	    &mrioc->sas_expander_list, list) {
527662306a36Sopenharmony_ci		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
527762306a36Sopenharmony_ci		mpi3mr_expander_node_remove(mrioc, sas_expander);
527862306a36Sopenharmony_ci		spin_lock_irqsave(&mrioc->sas_node_lock, flags);
527962306a36Sopenharmony_ci	}
528062306a36Sopenharmony_ci	list_for_each_entry_safe(port, hba_port_next, &mrioc->hba_port_table_list, list) {
528162306a36Sopenharmony_ci		ioc_info(mrioc,
528262306a36Sopenharmony_ci		    "removing hba_port entry: %p port: %d from hba_port list\n",
528362306a36Sopenharmony_ci		    port, port->port_id);
528462306a36Sopenharmony_ci		list_del(&port->list);
528562306a36Sopenharmony_ci		kfree(port);
528662306a36Sopenharmony_ci	}
528762306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
528862306a36Sopenharmony_ci
528962306a36Sopenharmony_ci	if (mrioc->sas_hba.num_phys) {
529062306a36Sopenharmony_ci		kfree(mrioc->sas_hba.phy);
529162306a36Sopenharmony_ci		mrioc->sas_hba.phy = NULL;
529262306a36Sopenharmony_ci		mrioc->sas_hba.num_phys = 0;
529362306a36Sopenharmony_ci	}
529462306a36Sopenharmony_ci
529562306a36Sopenharmony_ci	spin_lock(&mrioc_list_lock);
529662306a36Sopenharmony_ci	list_del(&mrioc->list);
529762306a36Sopenharmony_ci	spin_unlock(&mrioc_list_lock);
529862306a36Sopenharmony_ci
529962306a36Sopenharmony_ci	scsi_host_put(shost);
530062306a36Sopenharmony_ci}
530162306a36Sopenharmony_ci
530262306a36Sopenharmony_ci/**
530362306a36Sopenharmony_ci * mpi3mr_shutdown - PCI shutdown callback
530462306a36Sopenharmony_ci * @pdev: PCI device instance
530562306a36Sopenharmony_ci *
530662306a36Sopenharmony_ci * Free up all memory and resources associated with the
530762306a36Sopenharmony_ci * controller
530862306a36Sopenharmony_ci *
530962306a36Sopenharmony_ci * Return: Nothing.
531062306a36Sopenharmony_ci */
531162306a36Sopenharmony_cistatic void mpi3mr_shutdown(struct pci_dev *pdev)
531262306a36Sopenharmony_ci{
531362306a36Sopenharmony_ci	struct Scsi_Host *shost = pci_get_drvdata(pdev);
531462306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc;
531562306a36Sopenharmony_ci	struct workqueue_struct	*wq;
531662306a36Sopenharmony_ci	unsigned long flags;
531762306a36Sopenharmony_ci
531862306a36Sopenharmony_ci	if (!shost)
531962306a36Sopenharmony_ci		return;
532062306a36Sopenharmony_ci
532162306a36Sopenharmony_ci	mrioc = shost_priv(shost);
532262306a36Sopenharmony_ci	while (mrioc->reset_in_progress || mrioc->is_driver_loading)
532362306a36Sopenharmony_ci		ssleep(1);
532462306a36Sopenharmony_ci
532562306a36Sopenharmony_ci	mrioc->stop_drv_processing = 1;
532662306a36Sopenharmony_ci	mpi3mr_cleanup_fwevt_list(mrioc);
532762306a36Sopenharmony_ci	spin_lock_irqsave(&mrioc->fwevt_lock, flags);
532862306a36Sopenharmony_ci	wq = mrioc->fwevt_worker_thread;
532962306a36Sopenharmony_ci	mrioc->fwevt_worker_thread = NULL;
533062306a36Sopenharmony_ci	spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
533162306a36Sopenharmony_ci	if (wq)
533262306a36Sopenharmony_ci		destroy_workqueue(wq);
533362306a36Sopenharmony_ci
533462306a36Sopenharmony_ci	mpi3mr_stop_watchdog(mrioc);
533562306a36Sopenharmony_ci	mpi3mr_cleanup_ioc(mrioc);
533662306a36Sopenharmony_ci	mpi3mr_cleanup_resources(mrioc);
533762306a36Sopenharmony_ci}
533862306a36Sopenharmony_ci
533962306a36Sopenharmony_ci/**
534062306a36Sopenharmony_ci * mpi3mr_suspend - PCI power management suspend callback
534162306a36Sopenharmony_ci * @dev: Device struct
534262306a36Sopenharmony_ci *
534362306a36Sopenharmony_ci * Change the power state to the given value and cleanup the IOC
534462306a36Sopenharmony_ci * by issuing MUR and shutdown notification
534562306a36Sopenharmony_ci *
534662306a36Sopenharmony_ci * Return: 0 always.
534762306a36Sopenharmony_ci */
534862306a36Sopenharmony_cistatic int __maybe_unused
534962306a36Sopenharmony_cimpi3mr_suspend(struct device *dev)
535062306a36Sopenharmony_ci{
535162306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
535262306a36Sopenharmony_ci	struct Scsi_Host *shost = pci_get_drvdata(pdev);
535362306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc;
535462306a36Sopenharmony_ci
535562306a36Sopenharmony_ci	if (!shost)
535662306a36Sopenharmony_ci		return 0;
535762306a36Sopenharmony_ci
535862306a36Sopenharmony_ci	mrioc = shost_priv(shost);
535962306a36Sopenharmony_ci	while (mrioc->reset_in_progress || mrioc->is_driver_loading)
536062306a36Sopenharmony_ci		ssleep(1);
536162306a36Sopenharmony_ci	mrioc->stop_drv_processing = 1;
536262306a36Sopenharmony_ci	mpi3mr_cleanup_fwevt_list(mrioc);
536362306a36Sopenharmony_ci	scsi_block_requests(shost);
536462306a36Sopenharmony_ci	mpi3mr_stop_watchdog(mrioc);
536562306a36Sopenharmony_ci	mpi3mr_cleanup_ioc(mrioc);
536662306a36Sopenharmony_ci
536762306a36Sopenharmony_ci	ioc_info(mrioc, "pdev=0x%p, slot=%s, entering operating state\n",
536862306a36Sopenharmony_ci	    pdev, pci_name(pdev));
536962306a36Sopenharmony_ci	mpi3mr_cleanup_resources(mrioc);
537062306a36Sopenharmony_ci
537162306a36Sopenharmony_ci	return 0;
537262306a36Sopenharmony_ci}
537362306a36Sopenharmony_ci
537462306a36Sopenharmony_ci/**
537562306a36Sopenharmony_ci * mpi3mr_resume - PCI power management resume callback
537662306a36Sopenharmony_ci * @dev: Device struct
537762306a36Sopenharmony_ci *
537862306a36Sopenharmony_ci * Restore the power state to D0 and reinitialize the controller
537962306a36Sopenharmony_ci * and resume I/O operations to the target devices
538062306a36Sopenharmony_ci *
538162306a36Sopenharmony_ci * Return: 0 on success, non-zero on failure
538262306a36Sopenharmony_ci */
538362306a36Sopenharmony_cistatic int __maybe_unused
538462306a36Sopenharmony_cimpi3mr_resume(struct device *dev)
538562306a36Sopenharmony_ci{
538662306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
538762306a36Sopenharmony_ci	struct Scsi_Host *shost = pci_get_drvdata(pdev);
538862306a36Sopenharmony_ci	struct mpi3mr_ioc *mrioc;
538962306a36Sopenharmony_ci	pci_power_t device_state = pdev->current_state;
539062306a36Sopenharmony_ci	int r;
539162306a36Sopenharmony_ci
539262306a36Sopenharmony_ci	if (!shost)
539362306a36Sopenharmony_ci		return 0;
539462306a36Sopenharmony_ci
539562306a36Sopenharmony_ci	mrioc = shost_priv(shost);
539662306a36Sopenharmony_ci
539762306a36Sopenharmony_ci	ioc_info(mrioc, "pdev=0x%p, slot=%s, previous operating state [D%d]\n",
539862306a36Sopenharmony_ci	    pdev, pci_name(pdev), device_state);
539962306a36Sopenharmony_ci	mrioc->pdev = pdev;
540062306a36Sopenharmony_ci	mrioc->cpu_count = num_online_cpus();
540162306a36Sopenharmony_ci	r = mpi3mr_setup_resources(mrioc);
540262306a36Sopenharmony_ci	if (r) {
540362306a36Sopenharmony_ci		ioc_info(mrioc, "%s: Setup resources failed[%d]\n",
540462306a36Sopenharmony_ci		    __func__, r);
540562306a36Sopenharmony_ci		return r;
540662306a36Sopenharmony_ci	}
540762306a36Sopenharmony_ci
540862306a36Sopenharmony_ci	mrioc->stop_drv_processing = 0;
540962306a36Sopenharmony_ci	mpi3mr_invalidate_devhandles(mrioc);
541062306a36Sopenharmony_ci	mpi3mr_free_enclosure_list(mrioc);
541162306a36Sopenharmony_ci	mpi3mr_memset_buffers(mrioc);
541262306a36Sopenharmony_ci	r = mpi3mr_reinit_ioc(mrioc, 1);
541362306a36Sopenharmony_ci	if (r) {
541462306a36Sopenharmony_ci		ioc_err(mrioc, "resuming controller failed[%d]\n", r);
541562306a36Sopenharmony_ci		return r;
541662306a36Sopenharmony_ci	}
541762306a36Sopenharmony_ci	ssleep(MPI3MR_RESET_TOPOLOGY_SETTLE_TIME);
541862306a36Sopenharmony_ci	scsi_unblock_requests(shost);
541962306a36Sopenharmony_ci	mrioc->device_refresh_on = 0;
542062306a36Sopenharmony_ci	mpi3mr_start_watchdog(mrioc);
542162306a36Sopenharmony_ci
542262306a36Sopenharmony_ci	return 0;
542362306a36Sopenharmony_ci}
542462306a36Sopenharmony_ci
542562306a36Sopenharmony_cistatic const struct pci_device_id mpi3mr_pci_id_table[] = {
542662306a36Sopenharmony_ci	{
542762306a36Sopenharmony_ci		PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM,
542862306a36Sopenharmony_ci		    MPI3_MFGPAGE_DEVID_SAS4116, PCI_ANY_ID, PCI_ANY_ID)
542962306a36Sopenharmony_ci	},
543062306a36Sopenharmony_ci	{
543162306a36Sopenharmony_ci		PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM,
543262306a36Sopenharmony_ci		    MPI3_MFGPAGE_DEVID_SAS5116_MPI, PCI_ANY_ID, PCI_ANY_ID)
543362306a36Sopenharmony_ci	},
543462306a36Sopenharmony_ci	{
543562306a36Sopenharmony_ci		PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM,
543662306a36Sopenharmony_ci		    MPI3_MFGPAGE_DEVID_SAS5116_MPI_MGMT, PCI_ANY_ID, PCI_ANY_ID)
543762306a36Sopenharmony_ci	},
543862306a36Sopenharmony_ci	{ 0 }
543962306a36Sopenharmony_ci};
544062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table);
544162306a36Sopenharmony_ci
544262306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(mpi3mr_pm_ops, mpi3mr_suspend, mpi3mr_resume);
544362306a36Sopenharmony_ci
544462306a36Sopenharmony_cistatic struct pci_driver mpi3mr_pci_driver = {
544562306a36Sopenharmony_ci	.name = MPI3MR_DRIVER_NAME,
544662306a36Sopenharmony_ci	.id_table = mpi3mr_pci_id_table,
544762306a36Sopenharmony_ci	.probe = mpi3mr_probe,
544862306a36Sopenharmony_ci	.remove = mpi3mr_remove,
544962306a36Sopenharmony_ci	.shutdown = mpi3mr_shutdown,
545062306a36Sopenharmony_ci	.driver.pm = &mpi3mr_pm_ops,
545162306a36Sopenharmony_ci};
545262306a36Sopenharmony_ci
545362306a36Sopenharmony_cistatic ssize_t event_counter_show(struct device_driver *dd, char *buf)
545462306a36Sopenharmony_ci{
545562306a36Sopenharmony_ci	return sprintf(buf, "%llu\n", atomic64_read(&event_counter));
545662306a36Sopenharmony_ci}
545762306a36Sopenharmony_cistatic DRIVER_ATTR_RO(event_counter);
545862306a36Sopenharmony_ci
545962306a36Sopenharmony_cistatic int __init mpi3mr_init(void)
546062306a36Sopenharmony_ci{
546162306a36Sopenharmony_ci	int ret_val;
546262306a36Sopenharmony_ci
546362306a36Sopenharmony_ci	pr_info("Loading %s version %s\n", MPI3MR_DRIVER_NAME,
546462306a36Sopenharmony_ci	    MPI3MR_DRIVER_VERSION);
546562306a36Sopenharmony_ci
546662306a36Sopenharmony_ci	mpi3mr_transport_template =
546762306a36Sopenharmony_ci	    sas_attach_transport(&mpi3mr_transport_functions);
546862306a36Sopenharmony_ci	if (!mpi3mr_transport_template) {
546962306a36Sopenharmony_ci		pr_err("%s failed to load due to sas transport attach failure\n",
547062306a36Sopenharmony_ci		    MPI3MR_DRIVER_NAME);
547162306a36Sopenharmony_ci		return -ENODEV;
547262306a36Sopenharmony_ci	}
547362306a36Sopenharmony_ci
547462306a36Sopenharmony_ci	ret_val = pci_register_driver(&mpi3mr_pci_driver);
547562306a36Sopenharmony_ci	if (ret_val) {
547662306a36Sopenharmony_ci		pr_err("%s failed to load due to pci register driver failure\n",
547762306a36Sopenharmony_ci		    MPI3MR_DRIVER_NAME);
547862306a36Sopenharmony_ci		goto err_pci_reg_fail;
547962306a36Sopenharmony_ci	}
548062306a36Sopenharmony_ci
548162306a36Sopenharmony_ci	ret_val = driver_create_file(&mpi3mr_pci_driver.driver,
548262306a36Sopenharmony_ci				     &driver_attr_event_counter);
548362306a36Sopenharmony_ci	if (ret_val)
548462306a36Sopenharmony_ci		goto err_event_counter;
548562306a36Sopenharmony_ci
548662306a36Sopenharmony_ci	return ret_val;
548762306a36Sopenharmony_ci
548862306a36Sopenharmony_cierr_event_counter:
548962306a36Sopenharmony_ci	pci_unregister_driver(&mpi3mr_pci_driver);
549062306a36Sopenharmony_ci
549162306a36Sopenharmony_cierr_pci_reg_fail:
549262306a36Sopenharmony_ci	sas_release_transport(mpi3mr_transport_template);
549362306a36Sopenharmony_ci	return ret_val;
549462306a36Sopenharmony_ci}
549562306a36Sopenharmony_ci
549662306a36Sopenharmony_cistatic void __exit mpi3mr_exit(void)
549762306a36Sopenharmony_ci{
549862306a36Sopenharmony_ci	if (warn_non_secure_ctlr)
549962306a36Sopenharmony_ci		pr_warn(
550062306a36Sopenharmony_ci		    "Unloading %s version %s while managing a non secure controller\n",
550162306a36Sopenharmony_ci		    MPI3MR_DRIVER_NAME, MPI3MR_DRIVER_VERSION);
550262306a36Sopenharmony_ci	else
550362306a36Sopenharmony_ci		pr_info("Unloading %s version %s\n", MPI3MR_DRIVER_NAME,
550462306a36Sopenharmony_ci		    MPI3MR_DRIVER_VERSION);
550562306a36Sopenharmony_ci
550662306a36Sopenharmony_ci	driver_remove_file(&mpi3mr_pci_driver.driver,
550762306a36Sopenharmony_ci			   &driver_attr_event_counter);
550862306a36Sopenharmony_ci	pci_unregister_driver(&mpi3mr_pci_driver);
550962306a36Sopenharmony_ci	sas_release_transport(mpi3mr_transport_template);
551062306a36Sopenharmony_ci}
551162306a36Sopenharmony_ci
551262306a36Sopenharmony_cimodule_init(mpi3mr_init);
551362306a36Sopenharmony_cimodule_exit(mpi3mr_exit);
5514