18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2014 Cisco Systems, Inc.  All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This program is free software; you may redistribute it and/or modify
58c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by
68c2ecf20Sopenharmony_ci * the Free Software Foundation; version 2 of the License.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
98c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
108c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
118c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
128c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
148c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
158c2ecf20Sopenharmony_ci * SOFTWARE.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/mempool.h>
198c2ecf20Sopenharmony_ci#include <linux/errno.h>
208c2ecf20Sopenharmony_ci#include <linux/init.h>
218c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
228c2ecf20Sopenharmony_ci#include <linux/pci.h>
238c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
248c2ecf20Sopenharmony_ci#include <linux/delay.h>
258c2ecf20Sopenharmony_ci#include <linux/gfp.h>
268c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
278c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
288c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
298c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
308c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h>
318c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include "snic_io.h"
348c2ecf20Sopenharmony_ci#include "snic.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define snic_cmd_tag(sc)	(((struct scsi_cmnd *) sc)->request->tag)
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ciconst char *snic_state_str[] = {
398c2ecf20Sopenharmony_ci	[SNIC_INIT]	= "SNIC_INIT",
408c2ecf20Sopenharmony_ci	[SNIC_ERROR]	= "SNIC_ERROR",
418c2ecf20Sopenharmony_ci	[SNIC_ONLINE]	= "SNIC_ONLINE",
428c2ecf20Sopenharmony_ci	[SNIC_OFFLINE]	= "SNIC_OFFLINE",
438c2ecf20Sopenharmony_ci	[SNIC_FWRESET]	= "SNIC_FWRESET",
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic const char * const snic_req_state_str[] = {
478c2ecf20Sopenharmony_ci	[SNIC_IOREQ_NOT_INITED]	= "SNIC_IOREQ_NOT_INITED",
488c2ecf20Sopenharmony_ci	[SNIC_IOREQ_PENDING]	= "SNIC_IOREQ_PENDING",
498c2ecf20Sopenharmony_ci	[SNIC_IOREQ_ABTS_PENDING] = "SNIC_IOREQ_ABTS_PENDING",
508c2ecf20Sopenharmony_ci	[SNIC_IOREQ_ABTS_COMPLETE] = "SNIC_IOREQ_ABTS_COMPLETE",
518c2ecf20Sopenharmony_ci	[SNIC_IOREQ_LR_PENDING]	= "SNIC_IOREQ_LR_PENDING",
528c2ecf20Sopenharmony_ci	[SNIC_IOREQ_LR_COMPLETE] = "SNIC_IOREQ_LR_COMPLETE",
538c2ecf20Sopenharmony_ci	[SNIC_IOREQ_COMPLETE]	= "SNIC_IOREQ_CMD_COMPLETE",
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/* snic cmd status strings */
578c2ecf20Sopenharmony_cistatic const char * const snic_io_status_str[] = {
588c2ecf20Sopenharmony_ci	[SNIC_STAT_IO_SUCCESS]	= "SNIC_STAT_IO_SUCCESS", /* 0x0 */
598c2ecf20Sopenharmony_ci	[SNIC_STAT_INVALID_HDR] = "SNIC_STAT_INVALID_HDR",
608c2ecf20Sopenharmony_ci	[SNIC_STAT_OUT_OF_RES]	= "SNIC_STAT_OUT_OF_RES",
618c2ecf20Sopenharmony_ci	[SNIC_STAT_INVALID_PARM] = "SNIC_STAT_INVALID_PARM",
628c2ecf20Sopenharmony_ci	[SNIC_STAT_REQ_NOT_SUP]	= "SNIC_STAT_REQ_NOT_SUP",
638c2ecf20Sopenharmony_ci	[SNIC_STAT_IO_NOT_FOUND] = "SNIC_STAT_IO_NOT_FOUND",
648c2ecf20Sopenharmony_ci	[SNIC_STAT_ABORTED]	= "SNIC_STAT_ABORTED",
658c2ecf20Sopenharmony_ci	[SNIC_STAT_TIMEOUT]	= "SNIC_STAT_TIMEOUT",
668c2ecf20Sopenharmony_ci	[SNIC_STAT_SGL_INVALID] = "SNIC_STAT_SGL_INVALID",
678c2ecf20Sopenharmony_ci	[SNIC_STAT_DATA_CNT_MISMATCH] = "SNIC_STAT_DATA_CNT_MISMATCH",
688c2ecf20Sopenharmony_ci	[SNIC_STAT_FW_ERR]	= "SNIC_STAT_FW_ERR",
698c2ecf20Sopenharmony_ci	[SNIC_STAT_ITMF_REJECT] = "SNIC_STAT_ITMF_REJECT",
708c2ecf20Sopenharmony_ci	[SNIC_STAT_ITMF_FAIL]	= "SNIC_STAT_ITMF_FAIL",
718c2ecf20Sopenharmony_ci	[SNIC_STAT_ITMF_INCORRECT_LUN] = "SNIC_STAT_ITMF_INCORRECT_LUN",
728c2ecf20Sopenharmony_ci	[SNIC_STAT_CMND_REJECT] = "SNIC_STAT_CMND_REJECT",
738c2ecf20Sopenharmony_ci	[SNIC_STAT_DEV_OFFLINE] = "SNIC_STAT_DEV_OFFLINE",
748c2ecf20Sopenharmony_ci	[SNIC_STAT_NO_BOOTLUN]	= "SNIC_STAT_NO_BOOTLUN",
758c2ecf20Sopenharmony_ci	[SNIC_STAT_SCSI_ERR]	= "SNIC_STAT_SCSI_ERR",
768c2ecf20Sopenharmony_ci	[SNIC_STAT_NOT_READY]	= "SNIC_STAT_NOT_READY",
778c2ecf20Sopenharmony_ci	[SNIC_STAT_FATAL_ERROR]	= "SNIC_STAT_FATAL_ERROR",
788c2ecf20Sopenharmony_ci};
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic void snic_scsi_cleanup(struct snic *, int);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ciconst char *
838c2ecf20Sopenharmony_cisnic_state_to_str(unsigned int state)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	if (state >= ARRAY_SIZE(snic_state_str) || !snic_state_str[state])
868c2ecf20Sopenharmony_ci		return "Unknown";
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return snic_state_str[state];
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic const char *
928c2ecf20Sopenharmony_cisnic_io_status_to_str(unsigned int state)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	if ((state >= ARRAY_SIZE(snic_io_status_str)) ||
958c2ecf20Sopenharmony_ci	     (!snic_io_status_str[state]))
968c2ecf20Sopenharmony_ci		return "Unknown";
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return snic_io_status_str[state];
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic const char *
1028c2ecf20Sopenharmony_cisnic_ioreq_state_to_str(unsigned int state)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	if (state >= ARRAY_SIZE(snic_req_state_str) ||
1058c2ecf20Sopenharmony_ci			!snic_req_state_str[state])
1068c2ecf20Sopenharmony_ci		return "Unknown";
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	return snic_req_state_str[state];
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic inline spinlock_t *
1128c2ecf20Sopenharmony_cisnic_io_lock_hash(struct snic *snic, struct scsi_cmnd *sc)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	u32 hash = snic_cmd_tag(sc) & (SNIC_IO_LOCKS - 1);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	return &snic->io_req_lock[hash];
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic inline spinlock_t *
1208c2ecf20Sopenharmony_cisnic_io_lock_tag(struct snic *snic, int tag)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	return &snic->io_req_lock[tag & (SNIC_IO_LOCKS - 1)];
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci/* snic_release_req_buf : Releases snic_req_info */
1268c2ecf20Sopenharmony_cistatic void
1278c2ecf20Sopenharmony_cisnic_release_req_buf(struct snic *snic,
1288c2ecf20Sopenharmony_ci		   struct snic_req_info *rqi,
1298c2ecf20Sopenharmony_ci		   struct scsi_cmnd *sc)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	struct snic_host_req *req = rqi_to_req(rqi);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	/* Freeing cmd without marking completion, not okay */
1348c2ecf20Sopenharmony_ci	SNIC_BUG_ON(!((CMD_STATE(sc) == SNIC_IOREQ_COMPLETE) ||
1358c2ecf20Sopenharmony_ci		      (CMD_STATE(sc) == SNIC_IOREQ_ABTS_COMPLETE) ||
1368c2ecf20Sopenharmony_ci		      (CMD_FLAGS(sc) & SNIC_DEV_RST_NOTSUP) ||
1378c2ecf20Sopenharmony_ci		      (CMD_FLAGS(sc) & SNIC_IO_INTERNAL_TERM_ISSUED) ||
1388c2ecf20Sopenharmony_ci		      (CMD_FLAGS(sc) & SNIC_DEV_RST_TERM_ISSUED) ||
1398c2ecf20Sopenharmony_ci		      (CMD_FLAGS(sc) & SNIC_SCSI_CLEANUP) ||
1408c2ecf20Sopenharmony_ci		      (CMD_STATE(sc) == SNIC_IOREQ_LR_COMPLETE)));
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
1438c2ecf20Sopenharmony_ci		      "Rel_req:sc %p:tag %x:rqi %p:ioreq %p:abt %p:dr %p: state %s:flags 0x%llx\n",
1448c2ecf20Sopenharmony_ci		      sc, snic_cmd_tag(sc), rqi, rqi->req, rqi->abort_req,
1458c2ecf20Sopenharmony_ci		      rqi->dr_req, snic_ioreq_state_to_str(CMD_STATE(sc)),
1468c2ecf20Sopenharmony_ci		      CMD_FLAGS(sc));
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (req->u.icmnd.sense_addr)
1498c2ecf20Sopenharmony_ci		dma_unmap_single(&snic->pdev->dev,
1508c2ecf20Sopenharmony_ci				 le64_to_cpu(req->u.icmnd.sense_addr),
1518c2ecf20Sopenharmony_ci				 SCSI_SENSE_BUFFERSIZE,
1528c2ecf20Sopenharmony_ci				 DMA_FROM_DEVICE);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	scsi_dma_unmap(sc);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	snic_req_free(snic, rqi);
1578c2ecf20Sopenharmony_ci} /* end of snic_release_req_buf */
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci/*
1608c2ecf20Sopenharmony_ci * snic_queue_icmnd_req : Queues snic_icmnd request
1618c2ecf20Sopenharmony_ci */
1628c2ecf20Sopenharmony_cistatic int
1638c2ecf20Sopenharmony_cisnic_queue_icmnd_req(struct snic *snic,
1648c2ecf20Sopenharmony_ci		     struct snic_req_info *rqi,
1658c2ecf20Sopenharmony_ci		     struct scsi_cmnd *sc,
1668c2ecf20Sopenharmony_ci		     int sg_cnt)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct scatterlist *sg;
1698c2ecf20Sopenharmony_ci	struct snic_sg_desc *sgd;
1708c2ecf20Sopenharmony_ci	dma_addr_t pa = 0;
1718c2ecf20Sopenharmony_ci	struct scsi_lun lun;
1728c2ecf20Sopenharmony_ci	u16 flags = 0;
1738c2ecf20Sopenharmony_ci	int ret = 0;
1748c2ecf20Sopenharmony_ci	unsigned int i;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (sg_cnt) {
1778c2ecf20Sopenharmony_ci		flags = SNIC_ICMND_ESGL;
1788c2ecf20Sopenharmony_ci		sgd = (struct snic_sg_desc *) req_to_sgl(rqi->req);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci		for_each_sg(scsi_sglist(sc), sg, sg_cnt, i) {
1818c2ecf20Sopenharmony_ci			sgd->addr = cpu_to_le64(sg_dma_address(sg));
1828c2ecf20Sopenharmony_ci			sgd->len = cpu_to_le32(sg_dma_len(sg));
1838c2ecf20Sopenharmony_ci			sgd->_resvd = 0;
1848c2ecf20Sopenharmony_ci			sgd++;
1858c2ecf20Sopenharmony_ci		}
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	pa = dma_map_single(&snic->pdev->dev,
1898c2ecf20Sopenharmony_ci			    sc->sense_buffer,
1908c2ecf20Sopenharmony_ci			    SCSI_SENSE_BUFFERSIZE,
1918c2ecf20Sopenharmony_ci			    DMA_FROM_DEVICE);
1928c2ecf20Sopenharmony_ci	if (dma_mapping_error(&snic->pdev->dev, pa)) {
1938c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
1948c2ecf20Sopenharmony_ci			      "QIcmnd:PCI Map Failed for sns buf %p tag %x\n",
1958c2ecf20Sopenharmony_ci			      sc->sense_buffer, snic_cmd_tag(sc));
1968c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		return ret;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	int_to_scsilun(sc->device->lun, &lun);
2028c2ecf20Sopenharmony_ci	if (sc->sc_data_direction == DMA_FROM_DEVICE)
2038c2ecf20Sopenharmony_ci		flags |= SNIC_ICMND_RD;
2048c2ecf20Sopenharmony_ci	if (sc->sc_data_direction == DMA_TO_DEVICE)
2058c2ecf20Sopenharmony_ci		flags |= SNIC_ICMND_WR;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/* Initialize icmnd */
2088c2ecf20Sopenharmony_ci	snic_icmnd_init(rqi->req,
2098c2ecf20Sopenharmony_ci			snic_cmd_tag(sc),
2108c2ecf20Sopenharmony_ci			snic->config.hid, /* hid */
2118c2ecf20Sopenharmony_ci			(ulong) rqi,
2128c2ecf20Sopenharmony_ci			flags, /* command flags */
2138c2ecf20Sopenharmony_ci			rqi->tgt_id,
2148c2ecf20Sopenharmony_ci			lun.scsi_lun,
2158c2ecf20Sopenharmony_ci			sc->cmnd,
2168c2ecf20Sopenharmony_ci			sc->cmd_len,
2178c2ecf20Sopenharmony_ci			scsi_bufflen(sc),
2188c2ecf20Sopenharmony_ci			sg_cnt,
2198c2ecf20Sopenharmony_ci			(ulong) req_to_sgl(rqi->req),
2208c2ecf20Sopenharmony_ci			pa, /* sense buffer pa */
2218c2ecf20Sopenharmony_ci			SCSI_SENSE_BUFFERSIZE);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	atomic64_inc(&snic->s_stats.io.active);
2248c2ecf20Sopenharmony_ci	ret = snic_queue_wq_desc(snic, rqi->req, rqi->req_len);
2258c2ecf20Sopenharmony_ci	if (ret) {
2268c2ecf20Sopenharmony_ci		atomic64_dec(&snic->s_stats.io.active);
2278c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
2288c2ecf20Sopenharmony_ci			      "QIcmnd: Queuing Icmnd Failed. ret = %d\n",
2298c2ecf20Sopenharmony_ci			      ret);
2308c2ecf20Sopenharmony_ci	} else
2318c2ecf20Sopenharmony_ci		snic_stats_update_active_ios(&snic->s_stats);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	return ret;
2348c2ecf20Sopenharmony_ci} /* end of snic_queue_icmnd_req */
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci/*
2378c2ecf20Sopenharmony_ci * snic_issue_scsi_req : Prepares IO request and Issues to FW.
2388c2ecf20Sopenharmony_ci */
2398c2ecf20Sopenharmony_cistatic int
2408c2ecf20Sopenharmony_cisnic_issue_scsi_req(struct snic *snic,
2418c2ecf20Sopenharmony_ci		      struct snic_tgt *tgt,
2428c2ecf20Sopenharmony_ci		      struct scsi_cmnd *sc)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
2458c2ecf20Sopenharmony_ci	int sg_cnt = 0;
2468c2ecf20Sopenharmony_ci	int ret = 0;
2478c2ecf20Sopenharmony_ci	u32 tag = snic_cmd_tag(sc);
2488c2ecf20Sopenharmony_ci	u64 cmd_trc = 0, cmd_st_flags = 0;
2498c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
2508c2ecf20Sopenharmony_ci	unsigned long flags;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	CMD_STATE(sc) = SNIC_IOREQ_NOT_INITED;
2538c2ecf20Sopenharmony_ci	CMD_FLAGS(sc) = SNIC_NO_FLAGS;
2548c2ecf20Sopenharmony_ci	sg_cnt = scsi_dma_map(sc);
2558c2ecf20Sopenharmony_ci	if (sg_cnt < 0) {
2568c2ecf20Sopenharmony_ci		SNIC_TRC((u16)snic->shost->host_no, tag, (ulong) sc, 0,
2578c2ecf20Sopenharmony_ci			 sc->cmnd[0], sg_cnt, CMD_STATE(sc));
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost, "issue_sc:Failed to map SG List.\n");
2608c2ecf20Sopenharmony_ci		ret = -ENOMEM;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		goto issue_sc_end;
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	rqi = snic_req_init(snic, sg_cnt);
2668c2ecf20Sopenharmony_ci	if (!rqi) {
2678c2ecf20Sopenharmony_ci		scsi_dma_unmap(sc);
2688c2ecf20Sopenharmony_ci		ret = -ENOMEM;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci		goto issue_sc_end;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	rqi->tgt_id = tgt->id;
2748c2ecf20Sopenharmony_ci	rqi->sc = sc;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	CMD_STATE(sc) = SNIC_IOREQ_PENDING;
2778c2ecf20Sopenharmony_ci	CMD_SP(sc) = (char *) rqi;
2788c2ecf20Sopenharmony_ci	cmd_trc = SNIC_TRC_CMD(sc);
2798c2ecf20Sopenharmony_ci	CMD_FLAGS(sc) |= (SNIC_IO_INITIALIZED | SNIC_IO_ISSUED);
2808c2ecf20Sopenharmony_ci	cmd_st_flags = SNIC_TRC_CMD_STATE_FLAGS(sc);
2818c2ecf20Sopenharmony_ci	io_lock = snic_io_lock_hash(snic, sc);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	/* create wq desc and enqueue it */
2848c2ecf20Sopenharmony_ci	ret = snic_queue_icmnd_req(snic, rqi, sc, sg_cnt);
2858c2ecf20Sopenharmony_ci	if (ret) {
2868c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
2878c2ecf20Sopenharmony_ci			      "issue_sc: icmnd qing Failed for sc %p, err %d\n",
2888c2ecf20Sopenharmony_ci			      sc, ret);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci		spin_lock_irqsave(io_lock, flags);
2918c2ecf20Sopenharmony_ci		rqi = (struct snic_req_info *) CMD_SP(sc);
2928c2ecf20Sopenharmony_ci		CMD_SP(sc) = NULL;
2938c2ecf20Sopenharmony_ci		CMD_STATE(sc) = SNIC_IOREQ_COMPLETE;
2948c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) &= ~SNIC_IO_ISSUED; /* turn off the flag */
2958c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		if (rqi)
2988c2ecf20Sopenharmony_ci			snic_release_req_buf(snic, rqi, sc);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		SNIC_TRC(snic->shost->host_no, tag, (ulong) sc, 0, 0, 0,
3018c2ecf20Sopenharmony_ci			 SNIC_TRC_CMD_STATE_FLAGS(sc));
3028c2ecf20Sopenharmony_ci	} else {
3038c2ecf20Sopenharmony_ci		u32 io_sz = scsi_bufflen(sc) >> 9;
3048c2ecf20Sopenharmony_ci		u32 qtime = jiffies - rqi->start_time;
3058c2ecf20Sopenharmony_ci		struct snic_io_stats *iostats = &snic->s_stats.io;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		if (io_sz > atomic64_read(&iostats->max_io_sz))
3088c2ecf20Sopenharmony_ci			atomic64_set(&iostats->max_io_sz, io_sz);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci		if (qtime > atomic64_read(&iostats->max_qtime))
3118c2ecf20Sopenharmony_ci			atomic64_set(&iostats->max_qtime, qtime);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
3148c2ecf20Sopenharmony_ci			      "issue_sc:sc %p, tag %d queued to WQ.\n",
3158c2ecf20Sopenharmony_ci			      sc, tag);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		SNIC_TRC(snic->shost->host_no, tag, (ulong) sc, (ulong) rqi,
3188c2ecf20Sopenharmony_ci			 sg_cnt, cmd_trc, cmd_st_flags);
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ciissue_sc_end:
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	return ret;
3248c2ecf20Sopenharmony_ci} /* end of snic_issue_scsi_req */
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci/*
3288c2ecf20Sopenharmony_ci * snic_queuecommand
3298c2ecf20Sopenharmony_ci * Routine to send a scsi cdb to LLD
3308c2ecf20Sopenharmony_ci * Called with host_lock held and interrupts disabled
3318c2ecf20Sopenharmony_ci */
3328c2ecf20Sopenharmony_ciint
3338c2ecf20Sopenharmony_cisnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	struct snic_tgt *tgt = NULL;
3368c2ecf20Sopenharmony_ci	struct snic *snic = shost_priv(shost);
3378c2ecf20Sopenharmony_ci	int ret;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	tgt = starget_to_tgt(scsi_target(sc->device));
3408c2ecf20Sopenharmony_ci	ret = snic_tgt_chkready(tgt);
3418c2ecf20Sopenharmony_ci	if (ret) {
3428c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(shost, "Tgt %p id %d Not Ready.\n", tgt, tgt->id);
3438c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.misc.tgt_not_rdy);
3448c2ecf20Sopenharmony_ci		sc->result = ret;
3458c2ecf20Sopenharmony_ci		sc->scsi_done(sc);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci		return 0;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (snic_get_state(snic) != SNIC_ONLINE) {
3518c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(shost, "snic state is %s\n",
3528c2ecf20Sopenharmony_ci			      snic_state_str[snic_get_state(snic)]);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci	atomic_inc(&snic->ios_inflight);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(shost, "sc %p Tag %d (sc %0x) lun %lld in snic_qcmd\n",
3598c2ecf20Sopenharmony_ci		      sc, snic_cmd_tag(sc), sc->cmnd[0], sc->device->lun);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	ret = snic_issue_scsi_req(snic, tgt, sc);
3628c2ecf20Sopenharmony_ci	if (ret) {
3638c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(shost, "Failed to Q, Scsi Req w/ err %d.\n", ret);
3648c2ecf20Sopenharmony_ci		ret = SCSI_MLQUEUE_HOST_BUSY;
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	atomic_dec(&snic->ios_inflight);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	return ret;
3708c2ecf20Sopenharmony_ci} /* end of snic_queuecommand */
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci/*
3738c2ecf20Sopenharmony_ci * snic_process_abts_pending_state:
3748c2ecf20Sopenharmony_ci * caller should hold IO lock
3758c2ecf20Sopenharmony_ci */
3768c2ecf20Sopenharmony_cistatic void
3778c2ecf20Sopenharmony_cisnic_proc_tmreq_pending_state(struct snic *snic,
3788c2ecf20Sopenharmony_ci			      struct scsi_cmnd *sc,
3798c2ecf20Sopenharmony_ci			      u8 cmpl_status)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	int state = CMD_STATE(sc);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	if (state == SNIC_IOREQ_ABTS_PENDING)
3848c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_ABTS_PENDING;
3858c2ecf20Sopenharmony_ci	else if (state == SNIC_IOREQ_LR_PENDING)
3868c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_DEV_RST_PENDING;
3878c2ecf20Sopenharmony_ci	else
3888c2ecf20Sopenharmony_ci		SNIC_BUG_ON(1);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	switch (cmpl_status) {
3918c2ecf20Sopenharmony_ci	case SNIC_STAT_IO_SUCCESS:
3928c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_DONE;
3938c2ecf20Sopenharmony_ci		break;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	case SNIC_STAT_ABORTED:
3968c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_ABORTED;
3978c2ecf20Sopenharmony_ci		break;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	default:
4008c2ecf20Sopenharmony_ci		SNIC_BUG_ON(1);
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci/*
4058c2ecf20Sopenharmony_ci * snic_process_io_failed_state:
4068c2ecf20Sopenharmony_ci * Processes IO's error states
4078c2ecf20Sopenharmony_ci */
4088c2ecf20Sopenharmony_cistatic void
4098c2ecf20Sopenharmony_cisnic_process_io_failed_state(struct snic *snic,
4108c2ecf20Sopenharmony_ci			     struct snic_icmnd_cmpl *icmnd_cmpl,
4118c2ecf20Sopenharmony_ci			     struct scsi_cmnd *sc,
4128c2ecf20Sopenharmony_ci			     u8 cmpl_stat)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	int res = 0;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	switch (cmpl_stat) {
4178c2ecf20Sopenharmony_ci	case SNIC_STAT_TIMEOUT:		/* Req was timedout */
4188c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.misc.io_tmo);
4198c2ecf20Sopenharmony_ci		res = DID_TIME_OUT;
4208c2ecf20Sopenharmony_ci		break;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	case SNIC_STAT_ABORTED:		/* Req was aborted */
4238c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.misc.io_aborted);
4248c2ecf20Sopenharmony_ci		res = DID_ABORT;
4258c2ecf20Sopenharmony_ci		break;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	case SNIC_STAT_DATA_CNT_MISMATCH:/* Recv/Sent more/less data than exp */
4288c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.misc.data_cnt_mismat);
4298c2ecf20Sopenharmony_ci		scsi_set_resid(sc, le32_to_cpu(icmnd_cmpl->resid));
4308c2ecf20Sopenharmony_ci		res = DID_ERROR;
4318c2ecf20Sopenharmony_ci		break;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	case SNIC_STAT_OUT_OF_RES: /* Out of resources to complete request */
4348c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.fw.out_of_res);
4358c2ecf20Sopenharmony_ci		res = DID_REQUEUE;
4368c2ecf20Sopenharmony_ci		break;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	case SNIC_STAT_IO_NOT_FOUND:	/* Requested I/O was not found */
4398c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.io.io_not_found);
4408c2ecf20Sopenharmony_ci		res = DID_ERROR;
4418c2ecf20Sopenharmony_ci		break;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	case SNIC_STAT_SGL_INVALID:	/* Req was aborted to due to sgl error*/
4448c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.misc.sgl_inval);
4458c2ecf20Sopenharmony_ci		res = DID_ERROR;
4468c2ecf20Sopenharmony_ci		break;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	case SNIC_STAT_FW_ERR:		/* Req terminated due to FW Error */
4498c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.fw.io_errs);
4508c2ecf20Sopenharmony_ci		res = DID_ERROR;
4518c2ecf20Sopenharmony_ci		break;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	case SNIC_STAT_SCSI_ERR:	/* FW hits SCSI Error */
4548c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.fw.scsi_errs);
4558c2ecf20Sopenharmony_ci		break;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	case SNIC_STAT_NOT_READY:	/* XPT yet to initialize */
4588c2ecf20Sopenharmony_ci	case SNIC_STAT_DEV_OFFLINE:	/* Device offline */
4598c2ecf20Sopenharmony_ci		res = DID_NO_CONNECT;
4608c2ecf20Sopenharmony_ci		break;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	case SNIC_STAT_INVALID_HDR:	/* Hdr contains invalid data */
4638c2ecf20Sopenharmony_ci	case SNIC_STAT_INVALID_PARM:	/* Some param in req is invalid */
4648c2ecf20Sopenharmony_ci	case SNIC_STAT_REQ_NOT_SUP:	/* Req type is not supported */
4658c2ecf20Sopenharmony_ci	case SNIC_STAT_CMND_REJECT:	/* Req rejected */
4668c2ecf20Sopenharmony_ci	case SNIC_STAT_FATAL_ERROR:	/* XPT Error */
4678c2ecf20Sopenharmony_ci	default:
4688c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
4698c2ecf20Sopenharmony_ci			      "Invalid Hdr/Param or Req Not Supported or Cmnd Rejected or Device Offline. or Unknown\n");
4708c2ecf20Sopenharmony_ci		res = DID_ERROR;
4718c2ecf20Sopenharmony_ci		break;
4728c2ecf20Sopenharmony_ci	}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	SNIC_HOST_ERR(snic->shost, "fw returns failed status %s flags 0x%llx\n",
4758c2ecf20Sopenharmony_ci		      snic_io_status_to_str(cmpl_stat), CMD_FLAGS(sc));
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	/* Set sc->result */
4788c2ecf20Sopenharmony_ci	sc->result = (res << 16) | icmnd_cmpl->scsi_status;
4798c2ecf20Sopenharmony_ci} /* end of snic_process_io_failed_state */
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci/*
4828c2ecf20Sopenharmony_ci * snic_tmreq_pending : is task management in progress.
4838c2ecf20Sopenharmony_ci */
4848c2ecf20Sopenharmony_cistatic int
4858c2ecf20Sopenharmony_cisnic_tmreq_pending(struct scsi_cmnd *sc)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	int state = CMD_STATE(sc);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	return ((state == SNIC_IOREQ_ABTS_PENDING) ||
4908c2ecf20Sopenharmony_ci			(state == SNIC_IOREQ_LR_PENDING));
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci/*
4948c2ecf20Sopenharmony_ci * snic_process_icmnd_cmpl_status:
4958c2ecf20Sopenharmony_ci * Caller should hold io_lock
4968c2ecf20Sopenharmony_ci */
4978c2ecf20Sopenharmony_cistatic int
4988c2ecf20Sopenharmony_cisnic_process_icmnd_cmpl_status(struct snic *snic,
4998c2ecf20Sopenharmony_ci			       struct snic_icmnd_cmpl *icmnd_cmpl,
5008c2ecf20Sopenharmony_ci			       u8 cmpl_stat,
5018c2ecf20Sopenharmony_ci			       struct scsi_cmnd *sc)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	u8 scsi_stat = icmnd_cmpl->scsi_status;
5048c2ecf20Sopenharmony_ci	u64 xfer_len = 0;
5058c2ecf20Sopenharmony_ci	int ret = 0;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	/* Mark the IO as complete */
5088c2ecf20Sopenharmony_ci	CMD_STATE(sc) = SNIC_IOREQ_COMPLETE;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	if (likely(cmpl_stat == SNIC_STAT_IO_SUCCESS)) {
5118c2ecf20Sopenharmony_ci		sc->result = (DID_OK << 16) | scsi_stat;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		xfer_len = scsi_bufflen(sc);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci		/* Update SCSI Cmd with resid value */
5168c2ecf20Sopenharmony_ci		scsi_set_resid(sc, le32_to_cpu(icmnd_cmpl->resid));
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci		if (icmnd_cmpl->flags & SNIC_ICMND_CMPL_UNDR_RUN) {
5198c2ecf20Sopenharmony_ci			xfer_len -= le32_to_cpu(icmnd_cmpl->resid);
5208c2ecf20Sopenharmony_ci			atomic64_inc(&snic->s_stats.misc.io_under_run);
5218c2ecf20Sopenharmony_ci		}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci		if (icmnd_cmpl->scsi_status == SAM_STAT_TASK_SET_FULL)
5248c2ecf20Sopenharmony_ci			atomic64_inc(&snic->s_stats.misc.qfull);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci		ret = 0;
5278c2ecf20Sopenharmony_ci	} else {
5288c2ecf20Sopenharmony_ci		snic_process_io_failed_state(snic, icmnd_cmpl, sc, cmpl_stat);
5298c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.io.fail);
5308c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
5318c2ecf20Sopenharmony_ci			      "icmnd_cmpl: IO Failed : Hdr Status %s flags 0x%llx\n",
5328c2ecf20Sopenharmony_ci			      snic_io_status_to_str(cmpl_stat), CMD_FLAGS(sc));
5338c2ecf20Sopenharmony_ci		ret = 1;
5348c2ecf20Sopenharmony_ci	}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	return ret;
5378c2ecf20Sopenharmony_ci} /* end of snic_process_icmnd_cmpl_status */
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci/*
5418c2ecf20Sopenharmony_ci * snic_icmnd_cmpl_handler
5428c2ecf20Sopenharmony_ci * Routine to handle icmnd completions
5438c2ecf20Sopenharmony_ci */
5448c2ecf20Sopenharmony_cistatic void
5458c2ecf20Sopenharmony_cisnic_icmnd_cmpl_handler(struct snic *snic, struct snic_fw_req *fwreq)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	u8 typ, hdr_stat;
5488c2ecf20Sopenharmony_ci	u32 cmnd_id, hid;
5498c2ecf20Sopenharmony_ci	ulong ctx;
5508c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc = NULL;
5518c2ecf20Sopenharmony_ci	struct snic_icmnd_cmpl *icmnd_cmpl = NULL;
5528c2ecf20Sopenharmony_ci	struct snic_host_req *req = NULL;
5538c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
5548c2ecf20Sopenharmony_ci	unsigned long flags, start_time;
5558c2ecf20Sopenharmony_ci	spinlock_t *io_lock;
5568c2ecf20Sopenharmony_ci	u8 sc_stat = 0;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	snic_io_hdr_dec(&fwreq->hdr, &typ, &hdr_stat, &cmnd_id, &hid, &ctx);
5598c2ecf20Sopenharmony_ci	icmnd_cmpl = &fwreq->u.icmnd_cmpl;
5608c2ecf20Sopenharmony_ci	sc_stat = icmnd_cmpl->scsi_status;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
5638c2ecf20Sopenharmony_ci		      "Icmnd_cmpl: type = %x, hdr_stat = %x, cmnd_id = %x, hid = %x,i ctx = %lx\n",
5648c2ecf20Sopenharmony_ci		      typ, hdr_stat, cmnd_id, hid, ctx);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	if (cmnd_id >= snic->max_tag_id) {
5678c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
5688c2ecf20Sopenharmony_ci			      "Icmnd_cmpl:Tag Error:Out of Range Tag %d, hdr status = %s\n",
5698c2ecf20Sopenharmony_ci			      cmnd_id, snic_io_status_to_str(hdr_stat));
5708c2ecf20Sopenharmony_ci		return;
5718c2ecf20Sopenharmony_ci	}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	sc = scsi_host_find_tag(snic->shost, cmnd_id);
5748c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!sc);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (!sc) {
5778c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.io.sc_null);
5788c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
5798c2ecf20Sopenharmony_ci			      "Icmnd_cmpl: Scsi Cmnd Not found, sc = NULL Hdr Status = %s tag = 0x%x fwreq = 0x%p\n",
5808c2ecf20Sopenharmony_ci			      snic_io_status_to_str(hdr_stat),
5818c2ecf20Sopenharmony_ci			      cmnd_id,
5828c2ecf20Sopenharmony_ci			      fwreq);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci		SNIC_TRC(snic->shost->host_no, cmnd_id, 0,
5858c2ecf20Sopenharmony_ci			 ((u64)hdr_stat << 16 |
5868c2ecf20Sopenharmony_ci			  (u64)sc_stat << 8 | (u64)icmnd_cmpl->flags),
5878c2ecf20Sopenharmony_ci			 (ulong) fwreq, le32_to_cpu(icmnd_cmpl->resid), ctx);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci		return;
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	io_lock = snic_io_lock_hash(snic, sc);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
5958c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
5968c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
5978c2ecf20Sopenharmony_ci		      "Icmnd_cmpl:lun %lld sc %p cmd %xtag %d flags 0x%llx rqi %p\n",
5988c2ecf20Sopenharmony_ci		      sc->device->lun, sc, sc->cmnd[0], snic_cmd_tag(sc),
5998c2ecf20Sopenharmony_ci		      CMD_FLAGS(sc), rqi);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	if (CMD_FLAGS(sc) & SNIC_HOST_RESET_CMD_TERM) {
6028c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci		return;
6058c2ecf20Sopenharmony_ci	}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	SNIC_BUG_ON(rqi != (struct snic_req_info *)ctx);
6088c2ecf20Sopenharmony_ci	WARN_ON_ONCE(req);
6098c2ecf20Sopenharmony_ci	if (!rqi) {
6108c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.io.req_null);
6118c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_REQ_NULL;
6128c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
6158c2ecf20Sopenharmony_ci			      "Icmnd_cmpl:Host Req Not Found(null), Hdr Status %s, Tag 0x%x, sc 0x%p flags 0x%llx\n",
6168c2ecf20Sopenharmony_ci			      snic_io_status_to_str(hdr_stat),
6178c2ecf20Sopenharmony_ci			      cmnd_id, sc, CMD_FLAGS(sc));
6188c2ecf20Sopenharmony_ci		return;
6198c2ecf20Sopenharmony_ci	}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) ctx;
6228c2ecf20Sopenharmony_ci	start_time = rqi->start_time;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	/* firmware completed the io */
6258c2ecf20Sopenharmony_ci	rqi->io_cmpl = 1;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	/*
6288c2ecf20Sopenharmony_ci	 * if SCSI-ML has already issued abort on this command,
6298c2ecf20Sopenharmony_ci	 * ignore completion of the IO. The abts path will clean it up
6308c2ecf20Sopenharmony_ci	 */
6318c2ecf20Sopenharmony_ci	if (unlikely(snic_tmreq_pending(sc))) {
6328c2ecf20Sopenharmony_ci		snic_proc_tmreq_pending_state(snic, sc, hdr_stat);
6338c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci		snic_stats_update_io_cmpl(&snic->s_stats);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci		/* Expected value is SNIC_STAT_ABORTED */
6388c2ecf20Sopenharmony_ci		if (likely(hdr_stat == SNIC_STAT_ABORTED))
6398c2ecf20Sopenharmony_ci			return;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
6428c2ecf20Sopenharmony_ci			      "icmnd_cmpl:TM Req Pending(%s), Hdr Status %s sc 0x%p scsi status %x resid %d flags 0x%llx\n",
6438c2ecf20Sopenharmony_ci			      snic_ioreq_state_to_str(CMD_STATE(sc)),
6448c2ecf20Sopenharmony_ci			      snic_io_status_to_str(hdr_stat),
6458c2ecf20Sopenharmony_ci			      sc, sc_stat, le32_to_cpu(icmnd_cmpl->resid),
6468c2ecf20Sopenharmony_ci			      CMD_FLAGS(sc));
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci		SNIC_TRC(snic->shost->host_no, cmnd_id, (ulong) sc,
6498c2ecf20Sopenharmony_ci			 jiffies_to_msecs(jiffies - start_time), (ulong) fwreq,
6508c2ecf20Sopenharmony_ci			 SNIC_TRC_CMD(sc), SNIC_TRC_CMD_STATE_FLAGS(sc));
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci		return;
6538c2ecf20Sopenharmony_ci	}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	if (snic_process_icmnd_cmpl_status(snic, icmnd_cmpl, hdr_stat, sc)) {
6568c2ecf20Sopenharmony_ci		scsi_print_command(sc);
6578c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
6588c2ecf20Sopenharmony_ci			      "icmnd_cmpl:IO Failed, sc 0x%p Tag %d Cmd %x Hdr Status %s flags 0x%llx\n",
6598c2ecf20Sopenharmony_ci			      sc, sc->cmnd[0], cmnd_id,
6608c2ecf20Sopenharmony_ci			      snic_io_status_to_str(hdr_stat), CMD_FLAGS(sc));
6618c2ecf20Sopenharmony_ci	}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	/* Break link with the SCSI Command */
6648c2ecf20Sopenharmony_ci	CMD_SP(sc) = NULL;
6658c2ecf20Sopenharmony_ci	CMD_FLAGS(sc) |= SNIC_IO_DONE;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	/* For now, consider only successful IO. */
6708c2ecf20Sopenharmony_ci	snic_calc_io_process_time(snic, rqi);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	snic_release_req_buf(snic, rqi, sc);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	SNIC_TRC(snic->shost->host_no, cmnd_id, (ulong) sc,
6758c2ecf20Sopenharmony_ci		 jiffies_to_msecs(jiffies - start_time), (ulong) fwreq,
6768c2ecf20Sopenharmony_ci		 SNIC_TRC_CMD(sc), SNIC_TRC_CMD_STATE_FLAGS(sc));
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	if (sc->scsi_done)
6808c2ecf20Sopenharmony_ci		sc->scsi_done(sc);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	snic_stats_update_io_cmpl(&snic->s_stats);
6838c2ecf20Sopenharmony_ci} /* end of snic_icmnd_cmpl_handler */
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_cistatic void
6868c2ecf20Sopenharmony_cisnic_proc_dr_cmpl_locked(struct snic *snic,
6878c2ecf20Sopenharmony_ci			 struct snic_fw_req *fwreq,
6888c2ecf20Sopenharmony_ci			 u8 cmpl_stat,
6898c2ecf20Sopenharmony_ci			 u32 cmnd_id,
6908c2ecf20Sopenharmony_ci			 struct scsi_cmnd *sc)
6918c2ecf20Sopenharmony_ci{
6928c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = (struct snic_req_info *) CMD_SP(sc);
6938c2ecf20Sopenharmony_ci	u32 start_time = rqi->start_time;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	CMD_LR_STATUS(sc) = cmpl_stat;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost, "itmf_cmpl: Cmd State = %s\n",
6988c2ecf20Sopenharmony_ci		      snic_ioreq_state_to_str(CMD_STATE(sc)));
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING) {
7018c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_DEV_RST_ABTS_PENDING;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		SNIC_TRC(snic->shost->host_no, cmnd_id, (ulong) sc,
7048c2ecf20Sopenharmony_ci			 jiffies_to_msecs(jiffies - start_time),
7058c2ecf20Sopenharmony_ci			 (ulong) fwreq, 0, SNIC_TRC_CMD_STATE_FLAGS(sc));
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
7088c2ecf20Sopenharmony_ci			      "itmf_cmpl: Terminate Pending Dev Reset Cmpl Recvd.id %x, status %s flags 0x%llx\n",
7098c2ecf20Sopenharmony_ci			      (int)(cmnd_id & SNIC_TAG_MASK),
7108c2ecf20Sopenharmony_ci			      snic_io_status_to_str(cmpl_stat),
7118c2ecf20Sopenharmony_ci			      CMD_FLAGS(sc));
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci		return;
7148c2ecf20Sopenharmony_ci	}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	if (CMD_FLAGS(sc) & SNIC_DEV_RST_TIMEDOUT) {
7188c2ecf20Sopenharmony_ci		SNIC_TRC(snic->shost->host_no, cmnd_id, (ulong) sc,
7198c2ecf20Sopenharmony_ci			 jiffies_to_msecs(jiffies - start_time),
7208c2ecf20Sopenharmony_ci			 (ulong) fwreq, 0, SNIC_TRC_CMD_STATE_FLAGS(sc));
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
7238c2ecf20Sopenharmony_ci			      "itmf_cmpl:Dev Reset Completion Received after timeout. id %d cmpl status %s flags 0x%llx\n",
7248c2ecf20Sopenharmony_ci			      (int)(cmnd_id & SNIC_TAG_MASK),
7258c2ecf20Sopenharmony_ci			      snic_io_status_to_str(cmpl_stat),
7268c2ecf20Sopenharmony_ci			      CMD_FLAGS(sc));
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci		return;
7298c2ecf20Sopenharmony_ci	}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	CMD_STATE(sc) = SNIC_IOREQ_LR_COMPLETE;
7328c2ecf20Sopenharmony_ci	CMD_FLAGS(sc) |= SNIC_DEV_RST_DONE;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
7358c2ecf20Sopenharmony_ci		      "itmf_cmpl:Dev Reset Cmpl Recvd id %d cmpl status %s flags 0x%llx\n",
7368c2ecf20Sopenharmony_ci		      (int)(cmnd_id & SNIC_TAG_MASK),
7378c2ecf20Sopenharmony_ci		      snic_io_status_to_str(cmpl_stat),
7388c2ecf20Sopenharmony_ci		      CMD_FLAGS(sc));
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	if (rqi->dr_done)
7418c2ecf20Sopenharmony_ci		complete(rqi->dr_done);
7428c2ecf20Sopenharmony_ci} /* end of snic_proc_dr_cmpl_locked */
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci/*
7458c2ecf20Sopenharmony_ci * snic_update_abort_stats : Updates abort stats based on completion status.
7468c2ecf20Sopenharmony_ci */
7478c2ecf20Sopenharmony_cistatic void
7488c2ecf20Sopenharmony_cisnic_update_abort_stats(struct snic *snic, u8 cmpl_stat)
7498c2ecf20Sopenharmony_ci{
7508c2ecf20Sopenharmony_ci	struct snic_abort_stats *abt_stats = &snic->s_stats.abts;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost, "Updating Abort stats.\n");
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	switch (cmpl_stat) {
7558c2ecf20Sopenharmony_ci	case  SNIC_STAT_IO_SUCCESS:
7568c2ecf20Sopenharmony_ci		break;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	case SNIC_STAT_TIMEOUT:
7598c2ecf20Sopenharmony_ci		atomic64_inc(&abt_stats->fw_tmo);
7608c2ecf20Sopenharmony_ci		break;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	case SNIC_STAT_IO_NOT_FOUND:
7638c2ecf20Sopenharmony_ci		atomic64_inc(&abt_stats->io_not_found);
7648c2ecf20Sopenharmony_ci		break;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	default:
7678c2ecf20Sopenharmony_ci		atomic64_inc(&abt_stats->fail);
7688c2ecf20Sopenharmony_ci		break;
7698c2ecf20Sopenharmony_ci	}
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_cistatic int
7738c2ecf20Sopenharmony_cisnic_process_itmf_cmpl(struct snic *snic,
7748c2ecf20Sopenharmony_ci		       struct snic_fw_req *fwreq,
7758c2ecf20Sopenharmony_ci		       u32 cmnd_id,
7768c2ecf20Sopenharmony_ci		       u8 cmpl_stat,
7778c2ecf20Sopenharmony_ci		       struct scsi_cmnd *sc)
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
7808c2ecf20Sopenharmony_ci	u32 tm_tags = 0;
7818c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
7828c2ecf20Sopenharmony_ci	unsigned long flags;
7838c2ecf20Sopenharmony_ci	u32 start_time = 0;
7848c2ecf20Sopenharmony_ci	int ret = 0;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	io_lock = snic_io_lock_hash(snic, sc);
7878c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
7888c2ecf20Sopenharmony_ci	if (CMD_FLAGS(sc) & SNIC_HOST_RESET_CMD_TERM) {
7898c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci		return ret;
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
7948c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!rqi);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	if (!rqi) {
7978c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.io.req_null);
7988c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
7998c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_ABTS_TERM_REQ_NULL;
8008c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
8018c2ecf20Sopenharmony_ci			      "itmf_cmpl: rqi is null,Hdr stat = %s Tag = 0x%x sc = 0x%p flags 0x%llx\n",
8028c2ecf20Sopenharmony_ci			      snic_io_status_to_str(cmpl_stat), cmnd_id, sc,
8038c2ecf20Sopenharmony_ci			      CMD_FLAGS(sc));
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci		return ret;
8068c2ecf20Sopenharmony_ci	}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	/* Extract task management flags */
8098c2ecf20Sopenharmony_ci	tm_tags = cmnd_id & ~(SNIC_TAG_MASK);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	start_time = rqi->start_time;
8128c2ecf20Sopenharmony_ci	cmnd_id &= (SNIC_TAG_MASK);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	switch (tm_tags) {
8158c2ecf20Sopenharmony_ci	case SNIC_TAG_ABORT:
8168c2ecf20Sopenharmony_ci		/* Abort only issued on cmd */
8178c2ecf20Sopenharmony_ci		snic_update_abort_stats(snic, cmpl_stat);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci		if (CMD_STATE(sc) != SNIC_IOREQ_ABTS_PENDING) {
8208c2ecf20Sopenharmony_ci			/* This is a late completion. Ignore it. */
8218c2ecf20Sopenharmony_ci			ret = -1;
8228c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(io_lock, flags);
8238c2ecf20Sopenharmony_ci			break;
8248c2ecf20Sopenharmony_ci		}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci		CMD_STATE(sc) = SNIC_IOREQ_ABTS_COMPLETE;
8278c2ecf20Sopenharmony_ci		CMD_ABTS_STATUS(sc) = cmpl_stat;
8288c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_ABTS_TERM_DONE;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
8318c2ecf20Sopenharmony_ci			      "itmf_cmpl:Abort Cmpl Recvd.Tag 0x%x Status %s flags 0x%llx\n",
8328c2ecf20Sopenharmony_ci			      cmnd_id,
8338c2ecf20Sopenharmony_ci			      snic_io_status_to_str(cmpl_stat),
8348c2ecf20Sopenharmony_ci			      CMD_FLAGS(sc));
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci		/*
8378c2ecf20Sopenharmony_ci		 * If scsi_eh thread is blocked waiting for abts complete,
8388c2ecf20Sopenharmony_ci		 * signal completion to it. IO will be cleaned in the thread,
8398c2ecf20Sopenharmony_ci		 * else clean it in this context.
8408c2ecf20Sopenharmony_ci		 */
8418c2ecf20Sopenharmony_ci		if (rqi->abts_done) {
8428c2ecf20Sopenharmony_ci			complete(rqi->abts_done);
8438c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(io_lock, flags);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci			break; /* jump out */
8468c2ecf20Sopenharmony_ci		}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci		CMD_SP(sc) = NULL;
8498c2ecf20Sopenharmony_ci		sc->result = (DID_ERROR << 16);
8508c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
8518c2ecf20Sopenharmony_ci			      "itmf_cmpl: Completing IO. sc %p flags 0x%llx\n",
8528c2ecf20Sopenharmony_ci			      sc, CMD_FLAGS(sc));
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci		snic_release_req_buf(snic, rqi, sc);
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci		if (sc->scsi_done) {
8598c2ecf20Sopenharmony_ci			SNIC_TRC(snic->shost->host_no, cmnd_id, (ulong) sc,
8608c2ecf20Sopenharmony_ci				 jiffies_to_msecs(jiffies - start_time),
8618c2ecf20Sopenharmony_ci				 (ulong) fwreq, SNIC_TRC_CMD(sc),
8628c2ecf20Sopenharmony_ci				 SNIC_TRC_CMD_STATE_FLAGS(sc));
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci			sc->scsi_done(sc);
8658c2ecf20Sopenharmony_ci		}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci		break;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	case SNIC_TAG_DEV_RST:
8708c2ecf20Sopenharmony_ci	case SNIC_TAG_DEV_RST | SNIC_TAG_IOCTL_DEV_RST:
8718c2ecf20Sopenharmony_ci		snic_proc_dr_cmpl_locked(snic, fwreq, cmpl_stat, cmnd_id, sc);
8728c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
8738c2ecf20Sopenharmony_ci		ret = 0;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci		break;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	case SNIC_TAG_ABORT | SNIC_TAG_DEV_RST:
8788c2ecf20Sopenharmony_ci		/* Abort and terminate completion of device reset req */
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci		CMD_STATE(sc) = SNIC_IOREQ_ABTS_COMPLETE;
8818c2ecf20Sopenharmony_ci		CMD_ABTS_STATUS(sc) = cmpl_stat;
8828c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_DEV_RST_DONE;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
8858c2ecf20Sopenharmony_ci			      "itmf_cmpl:dev reset abts cmpl recvd. id %d status %s flags 0x%llx\n",
8868c2ecf20Sopenharmony_ci			      cmnd_id, snic_io_status_to_str(cmpl_stat),
8878c2ecf20Sopenharmony_ci			      CMD_FLAGS(sc));
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci		if (rqi->abts_done)
8908c2ecf20Sopenharmony_ci			complete(rqi->abts_done);
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci		break;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	default:
8978c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
8988c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
8998c2ecf20Sopenharmony_ci			      "itmf_cmpl: Unknown TM tag bit 0x%x\n", tm_tags);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
9028c2ecf20Sopenharmony_ci			      "itmf_cmpl:Unexpected itmf io stat %s Tag = 0x%x flags 0x%llx\n",
9038c2ecf20Sopenharmony_ci			      snic_ioreq_state_to_str(CMD_STATE(sc)),
9048c2ecf20Sopenharmony_ci			      cmnd_id,
9058c2ecf20Sopenharmony_ci			      CMD_FLAGS(sc));
9068c2ecf20Sopenharmony_ci		ret = -1;
9078c2ecf20Sopenharmony_ci		SNIC_BUG_ON(1);
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci		break;
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	return ret;
9138c2ecf20Sopenharmony_ci} /* end of snic_process_itmf_cmpl_status */
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci/*
9168c2ecf20Sopenharmony_ci * snic_itmf_cmpl_handler.
9178c2ecf20Sopenharmony_ci * Routine to handle itmf completions.
9188c2ecf20Sopenharmony_ci */
9198c2ecf20Sopenharmony_cistatic void
9208c2ecf20Sopenharmony_cisnic_itmf_cmpl_handler(struct snic *snic, struct snic_fw_req *fwreq)
9218c2ecf20Sopenharmony_ci{
9228c2ecf20Sopenharmony_ci	struct scsi_cmnd  *sc = NULL;
9238c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
9248c2ecf20Sopenharmony_ci	struct snic_itmf_cmpl *itmf_cmpl = NULL;
9258c2ecf20Sopenharmony_ci	ulong ctx;
9268c2ecf20Sopenharmony_ci	u32 cmnd_id;
9278c2ecf20Sopenharmony_ci	u32 hid;
9288c2ecf20Sopenharmony_ci	u8 typ;
9298c2ecf20Sopenharmony_ci	u8 hdr_stat;
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	snic_io_hdr_dec(&fwreq->hdr, &typ, &hdr_stat, &cmnd_id, &hid, &ctx);
9328c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
9338c2ecf20Sopenharmony_ci		      "Itmf_cmpl: %s: type = %x, hdr_stat = %x, cmnd_id = %x, hid = %x,ctx = %lx\n",
9348c2ecf20Sopenharmony_ci		      __func__, typ, hdr_stat, cmnd_id, hid, ctx);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	itmf_cmpl = &fwreq->u.itmf_cmpl;
9378c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
9388c2ecf20Sopenharmony_ci		      "Itmf_cmpl: nterm %u , flags 0x%x\n",
9398c2ecf20Sopenharmony_ci		      le32_to_cpu(itmf_cmpl->nterminated), itmf_cmpl->flags);
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	/* spl case, dev reset issued through ioctl */
9428c2ecf20Sopenharmony_ci	if (cmnd_id & SNIC_TAG_IOCTL_DEV_RST) {
9438c2ecf20Sopenharmony_ci		rqi = (struct snic_req_info *) ctx;
9448c2ecf20Sopenharmony_ci		sc = rqi->sc;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci		goto ioctl_dev_rst;
9478c2ecf20Sopenharmony_ci	}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	if ((cmnd_id & SNIC_TAG_MASK) >= snic->max_tag_id) {
9508c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
9518c2ecf20Sopenharmony_ci			      "Itmf_cmpl: Tag 0x%x out of Range,HdrStat %s\n",
9528c2ecf20Sopenharmony_ci			      cmnd_id, snic_io_status_to_str(hdr_stat));
9538c2ecf20Sopenharmony_ci		SNIC_BUG_ON(1);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci		return;
9568c2ecf20Sopenharmony_ci	}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	sc = scsi_host_find_tag(snic->shost, cmnd_id & SNIC_TAG_MASK);
9598c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!sc);
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ciioctl_dev_rst:
9628c2ecf20Sopenharmony_ci	if (!sc) {
9638c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.io.sc_null);
9648c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
9658c2ecf20Sopenharmony_ci			      "Itmf_cmpl: sc is NULL - Hdr Stat %s Tag 0x%x\n",
9668c2ecf20Sopenharmony_ci			      snic_io_status_to_str(hdr_stat), cmnd_id);
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci		return;
9698c2ecf20Sopenharmony_ci	}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	snic_process_itmf_cmpl(snic, fwreq, cmnd_id, hdr_stat, sc);
9728c2ecf20Sopenharmony_ci} /* end of snic_itmf_cmpl_handler */
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_cistatic void
9778c2ecf20Sopenharmony_cisnic_hba_reset_scsi_cleanup(struct snic *snic, struct scsi_cmnd *sc)
9788c2ecf20Sopenharmony_ci{
9798c2ecf20Sopenharmony_ci	struct snic_stats *st = &snic->s_stats;
9808c2ecf20Sopenharmony_ci	long act_ios = 0, act_fwreqs = 0;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost, "HBA Reset scsi cleanup.\n");
9838c2ecf20Sopenharmony_ci	snic_scsi_cleanup(snic, snic_cmd_tag(sc));
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	/* Update stats on pending IOs */
9868c2ecf20Sopenharmony_ci	act_ios = atomic64_read(&st->io.active);
9878c2ecf20Sopenharmony_ci	atomic64_add(act_ios, &st->io.compl);
9888c2ecf20Sopenharmony_ci	atomic64_sub(act_ios, &st->io.active);
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	act_fwreqs = atomic64_read(&st->fw.actv_reqs);
9918c2ecf20Sopenharmony_ci	atomic64_sub(act_fwreqs, &st->fw.actv_reqs);
9928c2ecf20Sopenharmony_ci}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci/*
9958c2ecf20Sopenharmony_ci * snic_hba_reset_cmpl_handler :
9968c2ecf20Sopenharmony_ci *
9978c2ecf20Sopenharmony_ci * Notes :
9988c2ecf20Sopenharmony_ci * 1. Cleanup all the scsi cmds, release all snic specific cmds
9998c2ecf20Sopenharmony_ci * 2. Issue Report Targets in case of SAN targets
10008c2ecf20Sopenharmony_ci */
10018c2ecf20Sopenharmony_cistatic int
10028c2ecf20Sopenharmony_cisnic_hba_reset_cmpl_handler(struct snic *snic, struct snic_fw_req *fwreq)
10038c2ecf20Sopenharmony_ci{
10048c2ecf20Sopenharmony_ci	ulong ctx;
10058c2ecf20Sopenharmony_ci	u32 cmnd_id;
10068c2ecf20Sopenharmony_ci	u32 hid;
10078c2ecf20Sopenharmony_ci	u8 typ;
10088c2ecf20Sopenharmony_ci	u8 hdr_stat;
10098c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc = NULL;
10108c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
10118c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
10128c2ecf20Sopenharmony_ci	unsigned long flags, gflags;
10138c2ecf20Sopenharmony_ci	int ret = 0;
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	snic_io_hdr_dec(&fwreq->hdr, &typ, &hdr_stat, &cmnd_id, &hid, &ctx);
10168c2ecf20Sopenharmony_ci	SNIC_HOST_INFO(snic->shost,
10178c2ecf20Sopenharmony_ci		       "reset_cmpl:Tag %d ctx %lx cmpl status %s HBA Reset Completion received.\n",
10188c2ecf20Sopenharmony_ci		       cmnd_id, ctx, snic_io_status_to_str(hdr_stat));
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
10218c2ecf20Sopenharmony_ci		      "reset_cmpl: type = %x, hdr_stat = %x, cmnd_id = %x, hid = %x, ctx = %lx\n",
10228c2ecf20Sopenharmony_ci		      typ, hdr_stat, cmnd_id, hid, ctx);
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	/* spl case, host reset issued through ioctl */
10258c2ecf20Sopenharmony_ci	if (cmnd_id == SCSI_NO_TAG) {
10268c2ecf20Sopenharmony_ci		rqi = (struct snic_req_info *) ctx;
10278c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost,
10288c2ecf20Sopenharmony_ci			       "reset_cmpl:Tag %d ctx %lx cmpl stat %s\n",
10298c2ecf20Sopenharmony_ci			       cmnd_id, ctx, snic_io_status_to_str(hdr_stat));
10308c2ecf20Sopenharmony_ci		sc = rqi->sc;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci		goto ioctl_hba_rst;
10338c2ecf20Sopenharmony_ci	}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	if (cmnd_id >= snic->max_tag_id) {
10368c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
10378c2ecf20Sopenharmony_ci			      "reset_cmpl: Tag 0x%x out of Range,HdrStat %s\n",
10388c2ecf20Sopenharmony_ci			      cmnd_id, snic_io_status_to_str(hdr_stat));
10398c2ecf20Sopenharmony_ci		SNIC_BUG_ON(1);
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci		return 1;
10428c2ecf20Sopenharmony_ci	}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	sc = scsi_host_find_tag(snic->shost, cmnd_id);
10458c2ecf20Sopenharmony_ciioctl_hba_rst:
10468c2ecf20Sopenharmony_ci	if (!sc) {
10478c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.io.sc_null);
10488c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
10498c2ecf20Sopenharmony_ci			      "reset_cmpl: sc is NULL - Hdr Stat %s Tag 0x%x\n",
10508c2ecf20Sopenharmony_ci			      snic_io_status_to_str(hdr_stat), cmnd_id);
10518c2ecf20Sopenharmony_ci		ret = 1;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci		return ret;
10548c2ecf20Sopenharmony_ci	}
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	SNIC_HOST_INFO(snic->shost,
10578c2ecf20Sopenharmony_ci		       "reset_cmpl: sc %p rqi %p Tag %d flags 0x%llx\n",
10588c2ecf20Sopenharmony_ci		       sc, rqi, cmnd_id, CMD_FLAGS(sc));
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	io_lock = snic_io_lock_hash(snic, sc);
10618c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	if (!snic->remove_wait) {
10648c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
10658c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
10668c2ecf20Sopenharmony_ci			      "reset_cmpl:host reset completed after timeout\n");
10678c2ecf20Sopenharmony_ci		ret = 1;
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci		return ret;
10708c2ecf20Sopenharmony_ci	}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
10738c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!rqi);
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	if (!rqi) {
10768c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.io.req_null);
10778c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
10788c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_ABTS_TERM_REQ_NULL;
10798c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
10808c2ecf20Sopenharmony_ci			      "reset_cmpl: rqi is null,Hdr stat %s Tag 0x%x sc 0x%p flags 0x%llx\n",
10818c2ecf20Sopenharmony_ci			      snic_io_status_to_str(hdr_stat), cmnd_id, sc,
10828c2ecf20Sopenharmony_ci			      CMD_FLAGS(sc));
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci		ret = 1;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci		return ret;
10878c2ecf20Sopenharmony_ci	}
10888c2ecf20Sopenharmony_ci	/* stats */
10898c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	/* scsi cleanup */
10928c2ecf20Sopenharmony_ci	snic_hba_reset_scsi_cleanup(snic, sc);
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	SNIC_BUG_ON(snic_get_state(snic) != SNIC_OFFLINE &&
10958c2ecf20Sopenharmony_ci		    snic_get_state(snic) != SNIC_FWRESET);
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	/* Careful locking between snic_lock and io lock */
10988c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
10998c2ecf20Sopenharmony_ci	spin_lock_irqsave(&snic->snic_lock, gflags);
11008c2ecf20Sopenharmony_ci	if (snic_get_state(snic) == SNIC_FWRESET)
11018c2ecf20Sopenharmony_ci		snic_set_state(snic, SNIC_ONLINE);
11028c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&snic->snic_lock, gflags);
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	if (snic->remove_wait)
11058c2ecf20Sopenharmony_ci		complete(snic->remove_wait);
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
11088c2ecf20Sopenharmony_ci	atomic64_inc(&snic->s_stats.reset.hba_reset_cmpl);
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	ret = 0;
11118c2ecf20Sopenharmony_ci	/* Rediscovery is for SAN */
11128c2ecf20Sopenharmony_ci	if (snic->config.xpt_type == SNIC_DAS)
11138c2ecf20Sopenharmony_ci			return ret;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost, "reset_cmpl: Queuing discovery work.\n");
11168c2ecf20Sopenharmony_ci	queue_work(snic_glob->event_q, &snic->disc_work);
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	return ret;
11198c2ecf20Sopenharmony_ci}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_cistatic void
11228c2ecf20Sopenharmony_cisnic_msg_ack_handler(struct snic *snic, struct snic_fw_req *fwreq)
11238c2ecf20Sopenharmony_ci{
11248c2ecf20Sopenharmony_ci	SNIC_HOST_INFO(snic->shost, "Message Ack Received.\n");
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	SNIC_ASSERT_NOT_IMPL(1);
11278c2ecf20Sopenharmony_ci}
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_cistatic void
11308c2ecf20Sopenharmony_cisnic_aen_handler(struct snic *snic, struct snic_fw_req *fwreq)
11318c2ecf20Sopenharmony_ci{
11328c2ecf20Sopenharmony_ci	u8 typ, hdr_stat;
11338c2ecf20Sopenharmony_ci	u32 cmnd_id, hid;
11348c2ecf20Sopenharmony_ci	ulong ctx;
11358c2ecf20Sopenharmony_ci	struct snic_async_evnotify *aen = &fwreq->u.async_ev;
11368c2ecf20Sopenharmony_ci	u32 event_id = 0;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	snic_io_hdr_dec(&fwreq->hdr, &typ, &hdr_stat, &cmnd_id, &hid, &ctx);
11398c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
11408c2ecf20Sopenharmony_ci		      "aen: type = %x, hdr_stat = %x, cmnd_id = %x, hid = %x, ctx = %lx\n",
11418c2ecf20Sopenharmony_ci		      typ, hdr_stat, cmnd_id, hid, ctx);
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	event_id = le32_to_cpu(aen->ev_id);
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	switch (event_id) {
11468c2ecf20Sopenharmony_ci	case SNIC_EV_TGT_OFFLINE:
11478c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost, "aen:TGT_OFFLINE Event Recvd.\n");
11488c2ecf20Sopenharmony_ci		break;
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	case SNIC_EV_TGT_ONLINE:
11518c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost, "aen:TGT_ONLINE Event Recvd.\n");
11528c2ecf20Sopenharmony_ci		break;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	case SNIC_EV_LUN_OFFLINE:
11558c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost, "aen:LUN_OFFLINE Event Recvd.\n");
11568c2ecf20Sopenharmony_ci		break;
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	case SNIC_EV_LUN_ONLINE:
11598c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost, "aen:LUN_ONLINE Event Recvd.\n");
11608c2ecf20Sopenharmony_ci		break;
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	case SNIC_EV_CONF_CHG:
11638c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost, "aen:Config Change Event Recvd.\n");
11648c2ecf20Sopenharmony_ci		break;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	case SNIC_EV_TGT_ADDED:
11678c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost, "aen:TGT_ADD Event Recvd.\n");
11688c2ecf20Sopenharmony_ci		break;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	case SNIC_EV_TGT_DELTD:
11718c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost, "aen:TGT_DEL Event Recvd.\n");
11728c2ecf20Sopenharmony_ci		break;
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	case SNIC_EV_LUN_ADDED:
11758c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost, "aen:LUN_ADD Event Recvd.\n");
11768c2ecf20Sopenharmony_ci		break;
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	case SNIC_EV_LUN_DELTD:
11798c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost, "aen:LUN_DEL Event Recvd.\n");
11808c2ecf20Sopenharmony_ci		break;
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	case SNIC_EV_DISC_CMPL:
11838c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost, "aen:DISC_CMPL Event Recvd.\n");
11848c2ecf20Sopenharmony_ci		break;
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	default:
11878c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost, "aen:Unknown Event Recvd.\n");
11888c2ecf20Sopenharmony_ci		SNIC_BUG_ON(1);
11898c2ecf20Sopenharmony_ci		break;
11908c2ecf20Sopenharmony_ci	}
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	SNIC_ASSERT_NOT_IMPL(1);
11938c2ecf20Sopenharmony_ci} /* end of snic_aen_handler */
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci/*
11968c2ecf20Sopenharmony_ci * snic_io_cmpl_handler
11978c2ecf20Sopenharmony_ci * Routine to process CQ entries(IO Completions) posted by fw.
11988c2ecf20Sopenharmony_ci */
11998c2ecf20Sopenharmony_cistatic int
12008c2ecf20Sopenharmony_cisnic_io_cmpl_handler(struct vnic_dev *vdev,
12018c2ecf20Sopenharmony_ci		     unsigned int cq_idx,
12028c2ecf20Sopenharmony_ci		     struct snic_fw_req *fwreq)
12038c2ecf20Sopenharmony_ci{
12048c2ecf20Sopenharmony_ci	struct snic *snic = svnic_dev_priv(vdev);
12058c2ecf20Sopenharmony_ci	u64 start = jiffies, cmpl_time;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	snic_print_desc(__func__, (char *)fwreq, sizeof(*fwreq));
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	/* Update FW Stats */
12108c2ecf20Sopenharmony_ci	if ((fwreq->hdr.type >= SNIC_RSP_REPORT_TGTS_CMPL) &&
12118c2ecf20Sopenharmony_ci		(fwreq->hdr.type <= SNIC_RSP_BOOT_LUNS_CMPL))
12128c2ecf20Sopenharmony_ci		atomic64_dec(&snic->s_stats.fw.actv_reqs);
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	SNIC_BUG_ON((fwreq->hdr.type > SNIC_RSP_BOOT_LUNS_CMPL) &&
12158c2ecf20Sopenharmony_ci		    (fwreq->hdr.type < SNIC_MSG_ASYNC_EVNOTIFY));
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	/* Check for snic subsys errors */
12188c2ecf20Sopenharmony_ci	switch (fwreq->hdr.status) {
12198c2ecf20Sopenharmony_ci	case SNIC_STAT_NOT_READY:	/* XPT yet to initialize */
12208c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
12218c2ecf20Sopenharmony_ci			      "sNIC SubSystem is NOT Ready.\n");
12228c2ecf20Sopenharmony_ci		break;
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	case SNIC_STAT_FATAL_ERROR:	/* XPT Error */
12258c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
12268c2ecf20Sopenharmony_ci			      "sNIC SubSystem in Unrecoverable State.\n");
12278c2ecf20Sopenharmony_ci		break;
12288c2ecf20Sopenharmony_ci	}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	switch (fwreq->hdr.type) {
12318c2ecf20Sopenharmony_ci	case SNIC_RSP_EXCH_VER_CMPL:
12328c2ecf20Sopenharmony_ci		snic_io_exch_ver_cmpl_handler(snic, fwreq);
12338c2ecf20Sopenharmony_ci		break;
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	case SNIC_RSP_REPORT_TGTS_CMPL:
12368c2ecf20Sopenharmony_ci		snic_report_tgt_cmpl_handler(snic, fwreq);
12378c2ecf20Sopenharmony_ci		break;
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	case SNIC_RSP_ICMND_CMPL:
12408c2ecf20Sopenharmony_ci		snic_icmnd_cmpl_handler(snic, fwreq);
12418c2ecf20Sopenharmony_ci		break;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	case SNIC_RSP_ITMF_CMPL:
12448c2ecf20Sopenharmony_ci		snic_itmf_cmpl_handler(snic, fwreq);
12458c2ecf20Sopenharmony_ci		break;
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	case SNIC_RSP_HBA_RESET_CMPL:
12488c2ecf20Sopenharmony_ci		snic_hba_reset_cmpl_handler(snic, fwreq);
12498c2ecf20Sopenharmony_ci		break;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	case SNIC_MSG_ACK:
12528c2ecf20Sopenharmony_ci		snic_msg_ack_handler(snic, fwreq);
12538c2ecf20Sopenharmony_ci		break;
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	case SNIC_MSG_ASYNC_EVNOTIFY:
12568c2ecf20Sopenharmony_ci		snic_aen_handler(snic, fwreq);
12578c2ecf20Sopenharmony_ci		break;
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	default:
12608c2ecf20Sopenharmony_ci		SNIC_BUG_ON(1);
12618c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
12628c2ecf20Sopenharmony_ci			      "Unknown Firmware completion request type %d\n",
12638c2ecf20Sopenharmony_ci			      fwreq->hdr.type);
12648c2ecf20Sopenharmony_ci		break;
12658c2ecf20Sopenharmony_ci	}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	/* Update Stats */
12688c2ecf20Sopenharmony_ci	cmpl_time = jiffies - start;
12698c2ecf20Sopenharmony_ci	if (cmpl_time > atomic64_read(&snic->s_stats.io.max_cmpl_time))
12708c2ecf20Sopenharmony_ci		atomic64_set(&snic->s_stats.io.max_cmpl_time, cmpl_time);
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	return 0;
12738c2ecf20Sopenharmony_ci} /* end of snic_io_cmpl_handler */
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci/*
12768c2ecf20Sopenharmony_ci * snic_fwcq_cmpl_handler
12778c2ecf20Sopenharmony_ci * Routine to process fwCQ
12788c2ecf20Sopenharmony_ci * This CQ is independent, and not associated with wq/rq/wq_copy queues
12798c2ecf20Sopenharmony_ci */
12808c2ecf20Sopenharmony_ciint
12818c2ecf20Sopenharmony_cisnic_fwcq_cmpl_handler(struct snic *snic, int io_cmpl_work)
12828c2ecf20Sopenharmony_ci{
12838c2ecf20Sopenharmony_ci	unsigned int num_ent = 0;	/* number cq entries processed */
12848c2ecf20Sopenharmony_ci	unsigned int cq_idx;
12858c2ecf20Sopenharmony_ci	unsigned int nent_per_cq;
12868c2ecf20Sopenharmony_ci	struct snic_misc_stats *misc_stats = &snic->s_stats.misc;
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	for (cq_idx = snic->wq_count; cq_idx < snic->cq_count; cq_idx++) {
12898c2ecf20Sopenharmony_ci		nent_per_cq = vnic_cq_fw_service(&snic->cq[cq_idx],
12908c2ecf20Sopenharmony_ci						 snic_io_cmpl_handler,
12918c2ecf20Sopenharmony_ci						 io_cmpl_work);
12928c2ecf20Sopenharmony_ci		num_ent += nent_per_cq;
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci		if (nent_per_cq > atomic64_read(&misc_stats->max_cq_ents))
12958c2ecf20Sopenharmony_ci			atomic64_set(&misc_stats->max_cq_ents, nent_per_cq);
12968c2ecf20Sopenharmony_ci	}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	return num_ent;
12998c2ecf20Sopenharmony_ci} /* end of snic_fwcq_cmpl_handler */
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci/*
13028c2ecf20Sopenharmony_ci * snic_queue_itmf_req: Common API to queue Task Management requests.
13038c2ecf20Sopenharmony_ci * Use rqi->tm_tag for passing special tags.
13048c2ecf20Sopenharmony_ci * @req_id : aborted request's tag, -1 for lun reset.
13058c2ecf20Sopenharmony_ci */
13068c2ecf20Sopenharmony_cistatic int
13078c2ecf20Sopenharmony_cisnic_queue_itmf_req(struct snic *snic,
13088c2ecf20Sopenharmony_ci		    struct snic_host_req *tmreq,
13098c2ecf20Sopenharmony_ci		    struct scsi_cmnd *sc,
13108c2ecf20Sopenharmony_ci		    u32 tmf,
13118c2ecf20Sopenharmony_ci		    u32 req_id)
13128c2ecf20Sopenharmony_ci{
13138c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = req_to_rqi(tmreq);
13148c2ecf20Sopenharmony_ci	struct scsi_lun lun;
13158c2ecf20Sopenharmony_ci	int tm_tag = snic_cmd_tag(sc) | rqi->tm_tag;
13168c2ecf20Sopenharmony_ci	int ret = 0;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	SNIC_BUG_ON(!rqi);
13198c2ecf20Sopenharmony_ci	SNIC_BUG_ON(!rqi->tm_tag);
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	/* fill in lun info */
13228c2ecf20Sopenharmony_ci	int_to_scsilun(sc->device->lun, &lun);
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	/* Initialize snic_host_req: itmf */
13258c2ecf20Sopenharmony_ci	snic_itmf_init(tmreq,
13268c2ecf20Sopenharmony_ci		       tm_tag,
13278c2ecf20Sopenharmony_ci		       snic->config.hid,
13288c2ecf20Sopenharmony_ci		       (ulong) rqi,
13298c2ecf20Sopenharmony_ci		       0 /* flags */,
13308c2ecf20Sopenharmony_ci		       req_id, /* Command to be aborted. */
13318c2ecf20Sopenharmony_ci		       rqi->tgt_id,
13328c2ecf20Sopenharmony_ci		       lun.scsi_lun,
13338c2ecf20Sopenharmony_ci		       tmf);
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	/*
13368c2ecf20Sopenharmony_ci	 * In case of multiple aborts on same cmd,
13378c2ecf20Sopenharmony_ci	 * use try_wait_for_completion and completion_done() to check
13388c2ecf20Sopenharmony_ci	 * whether it queues aborts even after completion of abort issued
13398c2ecf20Sopenharmony_ci	 * prior.SNIC_BUG_ON(completion_done(&rqi->done));
13408c2ecf20Sopenharmony_ci	 */
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	ret = snic_queue_wq_desc(snic, tmreq, sizeof(*tmreq));
13438c2ecf20Sopenharmony_ci	if (ret)
13448c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
13458c2ecf20Sopenharmony_ci			      "qitmf:Queuing ITMF(%d) Req sc %p, rqi %p, req_id %d tag %d Failed, ret = %d\n",
13468c2ecf20Sopenharmony_ci			      tmf, sc, rqi, req_id, snic_cmd_tag(sc), ret);
13478c2ecf20Sopenharmony_ci	else
13488c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
13498c2ecf20Sopenharmony_ci			      "qitmf:Queuing ITMF(%d) Req sc %p, rqi %p, req_id %d, tag %d (req_id)- Success.",
13508c2ecf20Sopenharmony_ci			      tmf, sc, rqi, req_id, snic_cmd_tag(sc));
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	return ret;
13538c2ecf20Sopenharmony_ci} /* end of snic_queue_itmf_req */
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_cistatic int
13568c2ecf20Sopenharmony_cisnic_issue_tm_req(struct snic *snic,
13578c2ecf20Sopenharmony_ci		    struct snic_req_info *rqi,
13588c2ecf20Sopenharmony_ci		    struct scsi_cmnd *sc,
13598c2ecf20Sopenharmony_ci		    int tmf)
13608c2ecf20Sopenharmony_ci{
13618c2ecf20Sopenharmony_ci	struct snic_host_req *tmreq = NULL;
13628c2ecf20Sopenharmony_ci	int req_id = 0, tag = snic_cmd_tag(sc);
13638c2ecf20Sopenharmony_ci	int ret = 0;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	if (snic_get_state(snic) == SNIC_FWRESET)
13668c2ecf20Sopenharmony_ci		return -EBUSY;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	atomic_inc(&snic->ios_inflight);
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
13718c2ecf20Sopenharmony_ci		      "issu_tmreq: Task mgmt req %d. rqi %p w/ tag %x\n",
13728c2ecf20Sopenharmony_ci		      tmf, rqi, tag);
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	if (tmf == SNIC_ITMF_LUN_RESET) {
13768c2ecf20Sopenharmony_ci		tmreq = snic_dr_req_init(snic, rqi);
13778c2ecf20Sopenharmony_ci		req_id = SCSI_NO_TAG;
13788c2ecf20Sopenharmony_ci	} else {
13798c2ecf20Sopenharmony_ci		tmreq = snic_abort_req_init(snic, rqi);
13808c2ecf20Sopenharmony_ci		req_id = tag;
13818c2ecf20Sopenharmony_ci	}
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	if (!tmreq) {
13848c2ecf20Sopenharmony_ci		ret = -ENOMEM;
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci		goto tmreq_err;
13878c2ecf20Sopenharmony_ci	}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	ret = snic_queue_itmf_req(snic, tmreq, sc, tmf, req_id);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_citmreq_err:
13928c2ecf20Sopenharmony_ci	if (ret) {
13938c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
13948c2ecf20Sopenharmony_ci			      "issu_tmreq: Queueing ITMF(%d) Req, sc %p rqi %p req_id %d tag %x fails err = %d\n",
13958c2ecf20Sopenharmony_ci			      tmf, sc, rqi, req_id, tag, ret);
13968c2ecf20Sopenharmony_ci	} else {
13978c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
13988c2ecf20Sopenharmony_ci			      "issu_tmreq: Queueing ITMF(%d) Req, sc %p, rqi %p, req_id %d tag %x - Success.\n",
13998c2ecf20Sopenharmony_ci			      tmf, sc, rqi, req_id, tag);
14008c2ecf20Sopenharmony_ci	}
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	atomic_dec(&snic->ios_inflight);
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	return ret;
14058c2ecf20Sopenharmony_ci}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci/*
14088c2ecf20Sopenharmony_ci * snic_queue_abort_req : Queues abort req to WQ
14098c2ecf20Sopenharmony_ci */
14108c2ecf20Sopenharmony_cistatic int
14118c2ecf20Sopenharmony_cisnic_queue_abort_req(struct snic *snic,
14128c2ecf20Sopenharmony_ci		     struct snic_req_info *rqi,
14138c2ecf20Sopenharmony_ci		     struct scsi_cmnd *sc,
14148c2ecf20Sopenharmony_ci		     int tmf)
14158c2ecf20Sopenharmony_ci{
14168c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost, "q_abtreq: sc %p, rqi %p, tag %x, tmf %d\n",
14178c2ecf20Sopenharmony_ci		      sc, rqi, snic_cmd_tag(sc), tmf);
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	/* Add special tag for abort */
14208c2ecf20Sopenharmony_ci	rqi->tm_tag |= SNIC_TAG_ABORT;
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci	return snic_issue_tm_req(snic, rqi, sc, tmf);
14238c2ecf20Sopenharmony_ci}
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci/*
14268c2ecf20Sopenharmony_ci * snic_abort_finish : called by snic_abort_cmd on queuing abort successfully.
14278c2ecf20Sopenharmony_ci */
14288c2ecf20Sopenharmony_cistatic int
14298c2ecf20Sopenharmony_cisnic_abort_finish(struct snic *snic, struct scsi_cmnd *sc)
14308c2ecf20Sopenharmony_ci{
14318c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
14328c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
14338c2ecf20Sopenharmony_ci	unsigned long flags;
14348c2ecf20Sopenharmony_ci	int ret = 0, tag = snic_cmd_tag(sc);
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	io_lock = snic_io_lock_hash(snic, sc);
14378c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
14388c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
14398c2ecf20Sopenharmony_ci	if (!rqi) {
14408c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.io.req_null);
14418c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_ABTS_TERM_REQ_NULL;
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
14448c2ecf20Sopenharmony_ci			      "abt_fini:req info is null tag 0x%x, sc 0x%p flags 0x%llx\n",
14458c2ecf20Sopenharmony_ci			      tag, sc, CMD_FLAGS(sc));
14468c2ecf20Sopenharmony_ci		ret = FAILED;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci		goto abort_fail;
14498c2ecf20Sopenharmony_ci	}
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	rqi->abts_done = NULL;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	ret = FAILED;
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	/* Check the abort status. */
14568c2ecf20Sopenharmony_ci	switch (CMD_ABTS_STATUS(sc)) {
14578c2ecf20Sopenharmony_ci	case SNIC_INVALID_CODE:
14588c2ecf20Sopenharmony_ci		/* Firmware didn't complete abort req, timedout */
14598c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_ABTS_TIMEDOUT;
14608c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.abts.drv_tmo);
14618c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
14628c2ecf20Sopenharmony_ci			      "abt_fini:sc %p Tag %x Driver Timeout.flags 0x%llx\n",
14638c2ecf20Sopenharmony_ci			      sc, snic_cmd_tag(sc), CMD_FLAGS(sc));
14648c2ecf20Sopenharmony_ci		/* do not release snic request in timedout case */
14658c2ecf20Sopenharmony_ci		rqi = NULL;
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci		goto abort_fail;
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci	case SNIC_STAT_IO_SUCCESS:
14708c2ecf20Sopenharmony_ci	case SNIC_STAT_IO_NOT_FOUND:
14718c2ecf20Sopenharmony_ci		ret = SUCCESS;
14728c2ecf20Sopenharmony_ci		/*
14738c2ecf20Sopenharmony_ci		 * If abort path doesn't call scsi_done(),
14748c2ecf20Sopenharmony_ci		 * the # IO timeouts == 2, will cause the LUN offline.
14758c2ecf20Sopenharmony_ci		 * Call scsi_done to complete the IO.
14768c2ecf20Sopenharmony_ci		 */
14778c2ecf20Sopenharmony_ci		sc->result = (DID_ERROR << 16);
14788c2ecf20Sopenharmony_ci		sc->scsi_done(sc);
14798c2ecf20Sopenharmony_ci		break;
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	default:
14828c2ecf20Sopenharmony_ci		/* Firmware completed abort with error */
14838c2ecf20Sopenharmony_ci		ret = FAILED;
14848c2ecf20Sopenharmony_ci		rqi = NULL;
14858c2ecf20Sopenharmony_ci		break;
14868c2ecf20Sopenharmony_ci	}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	CMD_SP(sc) = NULL;
14898c2ecf20Sopenharmony_ci	SNIC_HOST_INFO(snic->shost,
14908c2ecf20Sopenharmony_ci		       "abt_fini: Tag %x, Cmpl Status %s flags 0x%llx\n",
14918c2ecf20Sopenharmony_ci		       tag, snic_io_status_to_str(CMD_ABTS_STATUS(sc)),
14928c2ecf20Sopenharmony_ci		       CMD_FLAGS(sc));
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ciabort_fail:
14958c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
14968c2ecf20Sopenharmony_ci	if (rqi)
14978c2ecf20Sopenharmony_ci		snic_release_req_buf(snic, rqi, sc);
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	return ret;
15008c2ecf20Sopenharmony_ci} /* end of snic_abort_finish */
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci/*
15038c2ecf20Sopenharmony_ci * snic_send_abort_and_wait : Issues Abort, and Waits
15048c2ecf20Sopenharmony_ci */
15058c2ecf20Sopenharmony_cistatic int
15068c2ecf20Sopenharmony_cisnic_send_abort_and_wait(struct snic *snic, struct scsi_cmnd *sc)
15078c2ecf20Sopenharmony_ci{
15088c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
15098c2ecf20Sopenharmony_ci	enum snic_ioreq_state sv_state;
15108c2ecf20Sopenharmony_ci	struct snic_tgt *tgt = NULL;
15118c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
15128c2ecf20Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(tm_done);
15138c2ecf20Sopenharmony_ci	unsigned long flags;
15148c2ecf20Sopenharmony_ci	int ret = 0, tmf = 0, tag = snic_cmd_tag(sc);
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	tgt = starget_to_tgt(scsi_target(sc->device));
15178c2ecf20Sopenharmony_ci	if ((snic_tgt_chkready(tgt) != 0) && (tgt->tdata.typ == SNIC_TGT_SAN))
15188c2ecf20Sopenharmony_ci		tmf = SNIC_ITMF_ABTS_TASK_TERM;
15198c2ecf20Sopenharmony_ci	else
15208c2ecf20Sopenharmony_ci		tmf = SNIC_ITMF_ABTS_TASK;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	/* stats */
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	io_lock = snic_io_lock_hash(snic, sc);
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	/*
15278c2ecf20Sopenharmony_ci	 * Avoid a race between SCSI issuing the abort and the device
15288c2ecf20Sopenharmony_ci	 * completing the command.
15298c2ecf20Sopenharmony_ci	 *
15308c2ecf20Sopenharmony_ci	 * If the command is already completed by fw_cmpl code,
15318c2ecf20Sopenharmony_ci	 * we just return SUCCESS from here. This means that the abort
15328c2ecf20Sopenharmony_ci	 * succeeded. In the SCSI ML, since the timeout for command has
15338c2ecf20Sopenharmony_ci	 * happend, the completion wont actually complete the command
15348c2ecf20Sopenharmony_ci	 * and it will be considered as an aborted command
15358c2ecf20Sopenharmony_ci	 *
15368c2ecf20Sopenharmony_ci	 * The CMD_SP will not be cleared except while holding io_lock
15378c2ecf20Sopenharmony_ci	 */
15388c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
15398c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
15408c2ecf20Sopenharmony_ci	if (!rqi) {
15418c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
15448c2ecf20Sopenharmony_ci			      "abt_cmd: rqi is null. Tag %d flags 0x%llx\n",
15458c2ecf20Sopenharmony_ci			      tag, CMD_FLAGS(sc));
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci		ret = SUCCESS;
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci		goto send_abts_end;
15508c2ecf20Sopenharmony_ci	}
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	rqi->abts_done = &tm_done;
15538c2ecf20Sopenharmony_ci	if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING) {
15548c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci		ret = 0;
15578c2ecf20Sopenharmony_ci		goto abts_pending;
15588c2ecf20Sopenharmony_ci	}
15598c2ecf20Sopenharmony_ci	SNIC_BUG_ON(!rqi->abts_done);
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	/* Save Command State, should be restored on failed to Queue. */
15628c2ecf20Sopenharmony_ci	sv_state = CMD_STATE(sc);
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci	/*
15658c2ecf20Sopenharmony_ci	 * Command is still pending, need to abort it
15668c2ecf20Sopenharmony_ci	 * If the fw completes the command after this point,
15678c2ecf20Sopenharmony_ci	 * the completion won't be done till mid-layer, since abot
15688c2ecf20Sopenharmony_ci	 * has already started.
15698c2ecf20Sopenharmony_ci	 */
15708c2ecf20Sopenharmony_ci	CMD_STATE(sc) = SNIC_IOREQ_ABTS_PENDING;
15718c2ecf20Sopenharmony_ci	CMD_ABTS_STATUS(sc) = SNIC_INVALID_CODE;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost, "send_abt_cmd: TAG 0x%x\n", tag);
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci	/* Now Queue the abort command to firmware */
15788c2ecf20Sopenharmony_ci	ret = snic_queue_abort_req(snic, rqi, sc, tmf);
15798c2ecf20Sopenharmony_ci	if (ret) {
15808c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.abts.q_fail);
15818c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
15828c2ecf20Sopenharmony_ci			      "send_abt_cmd: IO w/ Tag 0x%x fail w/ err %d flags 0x%llx\n",
15838c2ecf20Sopenharmony_ci			      tag, ret, CMD_FLAGS(sc));
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci		spin_lock_irqsave(io_lock, flags);
15868c2ecf20Sopenharmony_ci		/* Restore Command's previous state */
15878c2ecf20Sopenharmony_ci		CMD_STATE(sc) = sv_state;
15888c2ecf20Sopenharmony_ci		rqi = (struct snic_req_info *) CMD_SP(sc);
15898c2ecf20Sopenharmony_ci		if (rqi)
15908c2ecf20Sopenharmony_ci			rqi->abts_done = NULL;
15918c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
15928c2ecf20Sopenharmony_ci		ret = FAILED;
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci		goto send_abts_end;
15958c2ecf20Sopenharmony_ci	}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
15988c2ecf20Sopenharmony_ci	if (tmf == SNIC_ITMF_ABTS_TASK) {
15998c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_ABTS_ISSUED;
16008c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.abts.num);
16018c2ecf20Sopenharmony_ci	} else {
16028c2ecf20Sopenharmony_ci		/* term stats */
16038c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_TERM_ISSUED;
16048c2ecf20Sopenharmony_ci	}
16058c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
16088c2ecf20Sopenharmony_ci		      "send_abt_cmd: sc %p Tag %x flags 0x%llx\n",
16098c2ecf20Sopenharmony_ci		      sc, tag, CMD_FLAGS(sc));
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	ret = 0;
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ciabts_pending:
16158c2ecf20Sopenharmony_ci	/*
16168c2ecf20Sopenharmony_ci	 * Queued an abort IO, wait for its completion.
16178c2ecf20Sopenharmony_ci	 * Once the fw completes the abort command, it will
16188c2ecf20Sopenharmony_ci	 * wakeup this thread.
16198c2ecf20Sopenharmony_ci	 */
16208c2ecf20Sopenharmony_ci	wait_for_completion_timeout(&tm_done, SNIC_ABTS_TIMEOUT);
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_cisend_abts_end:
16238c2ecf20Sopenharmony_ci	return ret;
16248c2ecf20Sopenharmony_ci} /* end of snic_send_abort_and_wait */
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci/*
16278c2ecf20Sopenharmony_ci * This function is exported to SCSI for sending abort cmnds.
16288c2ecf20Sopenharmony_ci * A SCSI IO is represent by snic_ioreq in the driver.
16298c2ecf20Sopenharmony_ci * The snic_ioreq is linked to the SCSI Cmd, thus a link with the ULP'S IO
16308c2ecf20Sopenharmony_ci */
16318c2ecf20Sopenharmony_ciint
16328c2ecf20Sopenharmony_cisnic_abort_cmd(struct scsi_cmnd *sc)
16338c2ecf20Sopenharmony_ci{
16348c2ecf20Sopenharmony_ci	struct snic *snic = shost_priv(sc->device->host);
16358c2ecf20Sopenharmony_ci	int ret = SUCCESS, tag = snic_cmd_tag(sc);
16368c2ecf20Sopenharmony_ci	u32 start_time = jiffies;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost, "abt_cmd:sc %p :0x%x :req = %p :tag = %d\n",
16398c2ecf20Sopenharmony_ci		       sc, sc->cmnd[0], sc->request, tag);
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	if (unlikely(snic_get_state(snic) != SNIC_ONLINE)) {
16428c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
16438c2ecf20Sopenharmony_ci			      "abt_cmd: tag %x Parent Devs are not rdy\n",
16448c2ecf20Sopenharmony_ci			      tag);
16458c2ecf20Sopenharmony_ci		ret = FAST_IO_FAIL;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci		goto abort_end;
16488c2ecf20Sopenharmony_ci	}
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	ret = snic_send_abort_and_wait(snic, sc);
16528c2ecf20Sopenharmony_ci	if (ret)
16538c2ecf20Sopenharmony_ci		goto abort_end;
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	ret = snic_abort_finish(snic, sc);
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ciabort_end:
16588c2ecf20Sopenharmony_ci	SNIC_TRC(snic->shost->host_no, tag, (ulong) sc,
16598c2ecf20Sopenharmony_ci		 jiffies_to_msecs(jiffies - start_time), 0,
16608c2ecf20Sopenharmony_ci		 SNIC_TRC_CMD(sc), SNIC_TRC_CMD_STATE_FLAGS(sc));
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
16638c2ecf20Sopenharmony_ci		      "abts: Abort Req Status = %s\n",
16648c2ecf20Sopenharmony_ci		      (ret == SUCCESS) ? "SUCCESS" :
16658c2ecf20Sopenharmony_ci		       ((ret == FAST_IO_FAIL) ? "FAST_IO_FAIL" : "FAILED"));
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	return ret;
16688c2ecf20Sopenharmony_ci}
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_cistatic int
16738c2ecf20Sopenharmony_cisnic_is_abts_pending(struct snic *snic, struct scsi_cmnd *lr_sc)
16748c2ecf20Sopenharmony_ci{
16758c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
16768c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc = NULL;
16778c2ecf20Sopenharmony_ci	struct scsi_device *lr_sdev = NULL;
16788c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
16798c2ecf20Sopenharmony_ci	u32 tag;
16808c2ecf20Sopenharmony_ci	unsigned long flags;
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	if (lr_sc)
16838c2ecf20Sopenharmony_ci		lr_sdev = lr_sc->device;
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	/* walk through the tag map, an dcheck if IOs are still pending in fw*/
16868c2ecf20Sopenharmony_ci	for (tag = 0; tag < snic->max_tag_id; tag++) {
16878c2ecf20Sopenharmony_ci		io_lock = snic_io_lock_tag(snic, tag);
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci		spin_lock_irqsave(io_lock, flags);
16908c2ecf20Sopenharmony_ci		sc = scsi_host_find_tag(snic->shost, tag);
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci		if (!sc || (lr_sc && (sc->device != lr_sdev || sc == lr_sc))) {
16938c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(io_lock, flags);
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci			continue;
16968c2ecf20Sopenharmony_ci		}
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci		rqi = (struct snic_req_info *) CMD_SP(sc);
16998c2ecf20Sopenharmony_ci		if (!rqi) {
17008c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(io_lock, flags);
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci			continue;
17038c2ecf20Sopenharmony_ci		}
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci		/*
17068c2ecf20Sopenharmony_ci		 * Found IO that is still pending w/ firmware and belongs to
17078c2ecf20Sopenharmony_ci		 * the LUN that is under reset, if lr_sc != NULL
17088c2ecf20Sopenharmony_ci		 */
17098c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost, "Found IO in %s on LUN\n",
17108c2ecf20Sopenharmony_ci			      snic_ioreq_state_to_str(CMD_STATE(sc)));
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci		if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING) {
17138c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(io_lock, flags);
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci			return 1;
17168c2ecf20Sopenharmony_ci		}
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
17198c2ecf20Sopenharmony_ci	}
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	return 0;
17228c2ecf20Sopenharmony_ci} /* end of snic_is_abts_pending */
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_cistatic int
17258c2ecf20Sopenharmony_cisnic_dr_clean_single_req(struct snic *snic,
17268c2ecf20Sopenharmony_ci			 u32 tag,
17278c2ecf20Sopenharmony_ci			 struct scsi_device *lr_sdev)
17288c2ecf20Sopenharmony_ci{
17298c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
17308c2ecf20Sopenharmony_ci	struct snic_tgt *tgt = NULL;
17318c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc = NULL;
17328c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
17338c2ecf20Sopenharmony_ci	u32 sv_state = 0, tmf = 0;
17348c2ecf20Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(tm_done);
17358c2ecf20Sopenharmony_ci	unsigned long flags;
17368c2ecf20Sopenharmony_ci	int ret = 0;
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	io_lock = snic_io_lock_tag(snic, tag);
17398c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
17408c2ecf20Sopenharmony_ci	sc = scsi_host_find_tag(snic->shost, tag);
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	/* Ignore Cmd that don't belong to Lun Reset device */
17438c2ecf20Sopenharmony_ci	if (!sc || sc->device != lr_sdev)
17448c2ecf20Sopenharmony_ci		goto skip_clean;
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	if (!rqi)
17498c2ecf20Sopenharmony_ci		goto skip_clean;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING)
17538c2ecf20Sopenharmony_ci		goto skip_clean;
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	if ((CMD_FLAGS(sc) & SNIC_DEVICE_RESET) &&
17578c2ecf20Sopenharmony_ci			(!(CMD_FLAGS(sc) & SNIC_DEV_RST_ISSUED))) {
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
17608c2ecf20Sopenharmony_ci			      "clean_single_req: devrst is not pending sc 0x%p\n",
17618c2ecf20Sopenharmony_ci			      sc);
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci		goto skip_clean;
17648c2ecf20Sopenharmony_ci	}
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
17678c2ecf20Sopenharmony_ci		"clean_single_req: Found IO in %s on lun\n",
17688c2ecf20Sopenharmony_ci		snic_ioreq_state_to_str(CMD_STATE(sc)));
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	/* Save Command State */
17718c2ecf20Sopenharmony_ci	sv_state = CMD_STATE(sc);
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	/*
17748c2ecf20Sopenharmony_ci	 * Any pending IO issued prior to reset is expected to be
17758c2ecf20Sopenharmony_ci	 * in abts pending state, if not we need to set SNIC_IOREQ_ABTS_PENDING
17768c2ecf20Sopenharmony_ci	 * to indicate the IO is abort pending.
17778c2ecf20Sopenharmony_ci	 * When IO is completed, the IO will be handed over and handled
17788c2ecf20Sopenharmony_ci	 * in this function.
17798c2ecf20Sopenharmony_ci	 */
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	CMD_STATE(sc) = SNIC_IOREQ_ABTS_PENDING;
17828c2ecf20Sopenharmony_ci	SNIC_BUG_ON(rqi->abts_done);
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	if (CMD_FLAGS(sc) & SNIC_DEVICE_RESET) {
17858c2ecf20Sopenharmony_ci		rqi->tm_tag = SNIC_TAG_DEV_RST;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
17888c2ecf20Sopenharmony_ci			      "clean_single_req:devrst sc 0x%p\n", sc);
17898c2ecf20Sopenharmony_ci	}
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	CMD_ABTS_STATUS(sc) = SNIC_INVALID_CODE;
17928c2ecf20Sopenharmony_ci	rqi->abts_done = &tm_done;
17938c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci	tgt = starget_to_tgt(scsi_target(sc->device));
17968c2ecf20Sopenharmony_ci	if ((snic_tgt_chkready(tgt) != 0) && (tgt->tdata.typ == SNIC_TGT_SAN))
17978c2ecf20Sopenharmony_ci		tmf = SNIC_ITMF_ABTS_TASK_TERM;
17988c2ecf20Sopenharmony_ci	else
17998c2ecf20Sopenharmony_ci		tmf = SNIC_ITMF_ABTS_TASK;
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci	/* Now queue the abort command to firmware */
18028c2ecf20Sopenharmony_ci	ret = snic_queue_abort_req(snic, rqi, sc, tmf);
18038c2ecf20Sopenharmony_ci	if (ret) {
18048c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
18058c2ecf20Sopenharmony_ci			      "clean_single_req_err:sc %p, tag %d abt failed. tm_tag %d flags 0x%llx\n",
18068c2ecf20Sopenharmony_ci			      sc, tag, rqi->tm_tag, CMD_FLAGS(sc));
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci		spin_lock_irqsave(io_lock, flags);
18098c2ecf20Sopenharmony_ci		rqi = (struct snic_req_info *) CMD_SP(sc);
18108c2ecf20Sopenharmony_ci		if (rqi)
18118c2ecf20Sopenharmony_ci			rqi->abts_done = NULL;
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci		/* Restore Command State */
18148c2ecf20Sopenharmony_ci		if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING)
18158c2ecf20Sopenharmony_ci			CMD_STATE(sc) = sv_state;
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci		ret = 1;
18188c2ecf20Sopenharmony_ci		goto skip_clean;
18198c2ecf20Sopenharmony_ci	}
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
18228c2ecf20Sopenharmony_ci	if (CMD_FLAGS(sc) & SNIC_DEVICE_RESET)
18238c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_DEV_RST_TERM_ISSUED;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci	CMD_FLAGS(sc) |= SNIC_IO_INTERNAL_TERM_ISSUED;
18268c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	wait_for_completion_timeout(&tm_done, SNIC_ABTS_TIMEOUT);
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci	/* Recheck cmd state to check if it now aborted. */
18318c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
18328c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
18338c2ecf20Sopenharmony_ci	if (!rqi) {
18348c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_ABTS_TERM_REQ_NULL;
18358c2ecf20Sopenharmony_ci		goto skip_clean;
18368c2ecf20Sopenharmony_ci	}
18378c2ecf20Sopenharmony_ci	rqi->abts_done = NULL;
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	/* if abort is still pending w/ fw, fail */
18408c2ecf20Sopenharmony_ci	if (CMD_ABTS_STATUS(sc) == SNIC_INVALID_CODE) {
18418c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
18428c2ecf20Sopenharmony_ci			      "clean_single_req_err:sc %p tag %d abt still pending w/ fw, tm_tag %d flags 0x%llx\n",
18438c2ecf20Sopenharmony_ci			      sc, tag, rqi->tm_tag, CMD_FLAGS(sc));
18448c2ecf20Sopenharmony_ci
18458c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_ABTS_TERM_DONE;
18468c2ecf20Sopenharmony_ci		ret = 1;
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci		goto skip_clean;
18498c2ecf20Sopenharmony_ci	}
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	CMD_STATE(sc) = SNIC_IOREQ_ABTS_COMPLETE;
18528c2ecf20Sopenharmony_ci	CMD_SP(sc) = NULL;
18538c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	snic_release_req_buf(snic, rqi, sc);
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	sc->result = (DID_ERROR << 16);
18588c2ecf20Sopenharmony_ci	sc->scsi_done(sc);
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci	ret = 0;
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci	return ret;
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ciskip_clean:
18658c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci	return ret;
18688c2ecf20Sopenharmony_ci} /* end of snic_dr_clean_single_req */
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_cistatic int
18718c2ecf20Sopenharmony_cisnic_dr_clean_pending_req(struct snic *snic, struct scsi_cmnd *lr_sc)
18728c2ecf20Sopenharmony_ci{
18738c2ecf20Sopenharmony_ci	struct scsi_device *lr_sdev = lr_sc->device;
18748c2ecf20Sopenharmony_ci	u32 tag = 0;
18758c2ecf20Sopenharmony_ci	int ret = FAILED;
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	for (tag = 0; tag < snic->max_tag_id; tag++) {
18788c2ecf20Sopenharmony_ci		if (tag == snic_cmd_tag(lr_sc))
18798c2ecf20Sopenharmony_ci			continue;
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci		ret = snic_dr_clean_single_req(snic, tag, lr_sdev);
18828c2ecf20Sopenharmony_ci		if (ret) {
18838c2ecf20Sopenharmony_ci			SNIC_HOST_ERR(snic->shost, "clean_err:tag = %d\n", tag);
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci			goto clean_err;
18868c2ecf20Sopenharmony_ci		}
18878c2ecf20Sopenharmony_ci	}
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	schedule_timeout(msecs_to_jiffies(100));
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	/* Walk through all the cmds and check abts status. */
18928c2ecf20Sopenharmony_ci	if (snic_is_abts_pending(snic, lr_sc)) {
18938c2ecf20Sopenharmony_ci		ret = FAILED;
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci		goto clean_err;
18968c2ecf20Sopenharmony_ci	}
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	ret = 0;
18998c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost, "clean_pending_req: Success.\n");
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci	return ret;
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ciclean_err:
19048c2ecf20Sopenharmony_ci	ret = FAILED;
19058c2ecf20Sopenharmony_ci	SNIC_HOST_ERR(snic->shost,
19068c2ecf20Sopenharmony_ci		      "Failed to Clean Pending IOs on %s device.\n",
19078c2ecf20Sopenharmony_ci		      dev_name(&lr_sdev->sdev_gendev));
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	return ret;
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci} /* end of snic_dr_clean_pending_req */
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci/*
19148c2ecf20Sopenharmony_ci * snic_dr_finish : Called by snic_device_reset
19158c2ecf20Sopenharmony_ci */
19168c2ecf20Sopenharmony_cistatic int
19178c2ecf20Sopenharmony_cisnic_dr_finish(struct snic *snic, struct scsi_cmnd *sc)
19188c2ecf20Sopenharmony_ci{
19198c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
19208c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
19218c2ecf20Sopenharmony_ci	unsigned long flags;
19228c2ecf20Sopenharmony_ci	int lr_res = 0;
19238c2ecf20Sopenharmony_ci	int ret = FAILED;
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	io_lock = snic_io_lock_hash(snic, sc);
19268c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
19278c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
19288c2ecf20Sopenharmony_ci	if (!rqi) {
19298c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
19308c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
19318c2ecf20Sopenharmony_ci			      "dr_fini: rqi is null tag 0x%x sc 0x%p flags 0x%llx\n",
19328c2ecf20Sopenharmony_ci			      snic_cmd_tag(sc), sc, CMD_FLAGS(sc));
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci		ret = FAILED;
19358c2ecf20Sopenharmony_ci		goto dr_fini_end;
19368c2ecf20Sopenharmony_ci	}
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	rqi->dr_done = NULL;
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci	lr_res = CMD_LR_STATUS(sc);
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci	switch (lr_res) {
19438c2ecf20Sopenharmony_ci	case SNIC_INVALID_CODE:
19448c2ecf20Sopenharmony_ci		/* stats */
19458c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
19468c2ecf20Sopenharmony_ci			      "dr_fini: Tag %x Dev Reset Timedout. flags 0x%llx\n",
19478c2ecf20Sopenharmony_ci			      snic_cmd_tag(sc), CMD_FLAGS(sc));
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_DEV_RST_TIMEDOUT;
19508c2ecf20Sopenharmony_ci		ret = FAILED;
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci		goto dr_failed;
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci	case SNIC_STAT_IO_SUCCESS:
19558c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
19568c2ecf20Sopenharmony_ci			      "dr_fini: Tag %x Dev Reset cmpl\n",
19578c2ecf20Sopenharmony_ci			      snic_cmd_tag(sc));
19588c2ecf20Sopenharmony_ci		ret = 0;
19598c2ecf20Sopenharmony_ci		break;
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	default:
19628c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
19638c2ecf20Sopenharmony_ci			      "dr_fini:Device Reset completed& failed.Tag = %x lr_status %s flags 0x%llx\n",
19648c2ecf20Sopenharmony_ci			      snic_cmd_tag(sc),
19658c2ecf20Sopenharmony_ci			      snic_io_status_to_str(lr_res), CMD_FLAGS(sc));
19668c2ecf20Sopenharmony_ci		ret = FAILED;
19678c2ecf20Sopenharmony_ci		goto dr_failed;
19688c2ecf20Sopenharmony_ci	}
19698c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci	/*
19728c2ecf20Sopenharmony_ci	 * Cleanup any IOs on this LUN that have still not completed.
19738c2ecf20Sopenharmony_ci	 * If any of these fail, then LUN Reset fails.
19748c2ecf20Sopenharmony_ci	 * Cleanup cleans all commands on this LUN except
19758c2ecf20Sopenharmony_ci	 * the lun reset command. If all cmds get cleaned, the LUN Reset
19768c2ecf20Sopenharmony_ci	 * succeeds.
19778c2ecf20Sopenharmony_ci	 */
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	ret = snic_dr_clean_pending_req(snic, sc);
19808c2ecf20Sopenharmony_ci	if (ret) {
19818c2ecf20Sopenharmony_ci		spin_lock_irqsave(io_lock, flags);
19828c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
19838c2ecf20Sopenharmony_ci			      "dr_fini: Device Reset Failed since could not abort all IOs. Tag = %x.\n",
19848c2ecf20Sopenharmony_ci			      snic_cmd_tag(sc));
19858c2ecf20Sopenharmony_ci		rqi = (struct snic_req_info *) CMD_SP(sc);
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci		goto dr_failed;
19888c2ecf20Sopenharmony_ci	} else {
19898c2ecf20Sopenharmony_ci		/* Cleanup LUN Reset Command */
19908c2ecf20Sopenharmony_ci		spin_lock_irqsave(io_lock, flags);
19918c2ecf20Sopenharmony_ci		rqi = (struct snic_req_info *) CMD_SP(sc);
19928c2ecf20Sopenharmony_ci		if (rqi)
19938c2ecf20Sopenharmony_ci			ret = SUCCESS; /* Completed Successfully */
19948c2ecf20Sopenharmony_ci		else
19958c2ecf20Sopenharmony_ci			ret = FAILED;
19968c2ecf20Sopenharmony_ci	}
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_cidr_failed:
19998c2ecf20Sopenharmony_ci	lockdep_assert_held(io_lock);
20008c2ecf20Sopenharmony_ci	if (rqi)
20018c2ecf20Sopenharmony_ci		CMD_SP(sc) = NULL;
20028c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci	if (rqi)
20058c2ecf20Sopenharmony_ci		snic_release_req_buf(snic, rqi, sc);
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_cidr_fini_end:
20088c2ecf20Sopenharmony_ci	return ret;
20098c2ecf20Sopenharmony_ci} /* end of snic_dr_finish */
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_cistatic int
20128c2ecf20Sopenharmony_cisnic_queue_dr_req(struct snic *snic,
20138c2ecf20Sopenharmony_ci		  struct snic_req_info *rqi,
20148c2ecf20Sopenharmony_ci		  struct scsi_cmnd *sc)
20158c2ecf20Sopenharmony_ci{
20168c2ecf20Sopenharmony_ci	/* Add special tag for device reset */
20178c2ecf20Sopenharmony_ci	rqi->tm_tag |= SNIC_TAG_DEV_RST;
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	return snic_issue_tm_req(snic, rqi, sc, SNIC_ITMF_LUN_RESET);
20208c2ecf20Sopenharmony_ci}
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_cistatic int
20238c2ecf20Sopenharmony_cisnic_send_dr_and_wait(struct snic *snic, struct scsi_cmnd *sc)
20248c2ecf20Sopenharmony_ci{
20258c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
20268c2ecf20Sopenharmony_ci	enum snic_ioreq_state sv_state;
20278c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
20288c2ecf20Sopenharmony_ci	unsigned long flags;
20298c2ecf20Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(tm_done);
20308c2ecf20Sopenharmony_ci	int ret = FAILED, tag = snic_cmd_tag(sc);
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	io_lock = snic_io_lock_hash(snic, sc);
20338c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
20348c2ecf20Sopenharmony_ci	CMD_FLAGS(sc) |= SNIC_DEVICE_RESET;
20358c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
20368c2ecf20Sopenharmony_ci	if (!rqi) {
20378c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
20388c2ecf20Sopenharmony_ci			      "send_dr: rqi is null, Tag 0x%x flags 0x%llx\n",
20398c2ecf20Sopenharmony_ci			      tag, CMD_FLAGS(sc));
20408c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci		ret = FAILED;
20438c2ecf20Sopenharmony_ci		goto send_dr_end;
20448c2ecf20Sopenharmony_ci	}
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	/* Save Command state to restore in case Queuing failed. */
20478c2ecf20Sopenharmony_ci	sv_state = CMD_STATE(sc);
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci	CMD_STATE(sc) = SNIC_IOREQ_LR_PENDING;
20508c2ecf20Sopenharmony_ci	CMD_LR_STATUS(sc) = SNIC_INVALID_CODE;
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost, "dr: TAG = %x\n", tag);
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci	rqi->dr_done = &tm_done;
20558c2ecf20Sopenharmony_ci	SNIC_BUG_ON(!rqi->dr_done);
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
20588c2ecf20Sopenharmony_ci	/*
20598c2ecf20Sopenharmony_ci	 * The Command state is changed to IOREQ_PENDING,
20608c2ecf20Sopenharmony_ci	 * in this case, if the command is completed, the icmnd_cmpl will
20618c2ecf20Sopenharmony_ci	 * mark the cmd as completed.
20628c2ecf20Sopenharmony_ci	 * This logic still makes LUN Reset is inevitable.
20638c2ecf20Sopenharmony_ci	 */
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	ret = snic_queue_dr_req(snic, rqi, sc);
20668c2ecf20Sopenharmony_ci	if (ret) {
20678c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
20688c2ecf20Sopenharmony_ci			      "send_dr: IO w/ Tag 0x%x Failed err = %d. flags 0x%llx\n",
20698c2ecf20Sopenharmony_ci			      tag, ret, CMD_FLAGS(sc));
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci		spin_lock_irqsave(io_lock, flags);
20728c2ecf20Sopenharmony_ci		/* Restore State */
20738c2ecf20Sopenharmony_ci		CMD_STATE(sc) = sv_state;
20748c2ecf20Sopenharmony_ci		rqi = (struct snic_req_info *) CMD_SP(sc);
20758c2ecf20Sopenharmony_ci		if (rqi)
20768c2ecf20Sopenharmony_ci			rqi->dr_done = NULL;
20778c2ecf20Sopenharmony_ci		/* rqi is freed in caller. */
20788c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
20798c2ecf20Sopenharmony_ci		ret = FAILED;
20808c2ecf20Sopenharmony_ci
20818c2ecf20Sopenharmony_ci		goto send_dr_end;
20828c2ecf20Sopenharmony_ci	}
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
20858c2ecf20Sopenharmony_ci	CMD_FLAGS(sc) |= SNIC_DEV_RST_ISSUED;
20868c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci	ret = 0;
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci	wait_for_completion_timeout(&tm_done, SNIC_LUN_RESET_TIMEOUT);
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_cisend_dr_end:
20938c2ecf20Sopenharmony_ci	return ret;
20948c2ecf20Sopenharmony_ci}
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci/*
20978c2ecf20Sopenharmony_ci * auxillary funciton to check lun reset op is supported or not
20988c2ecf20Sopenharmony_ci * Not supported if returns 0
20998c2ecf20Sopenharmony_ci */
21008c2ecf20Sopenharmony_cistatic int
21018c2ecf20Sopenharmony_cisnic_dev_reset_supported(struct scsi_device *sdev)
21028c2ecf20Sopenharmony_ci{
21038c2ecf20Sopenharmony_ci	struct snic_tgt *tgt = starget_to_tgt(scsi_target(sdev));
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	if (tgt->tdata.typ == SNIC_TGT_DAS)
21068c2ecf20Sopenharmony_ci		return 0;
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci	return 1;
21098c2ecf20Sopenharmony_ci}
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_cistatic void
21128c2ecf20Sopenharmony_cisnic_unlink_and_release_req(struct snic *snic, struct scsi_cmnd *sc, int flag)
21138c2ecf20Sopenharmony_ci{
21148c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
21158c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
21168c2ecf20Sopenharmony_ci	unsigned long flags;
21178c2ecf20Sopenharmony_ci	u32 start_time = jiffies;
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci	io_lock = snic_io_lock_hash(snic, sc);
21208c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
21218c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
21228c2ecf20Sopenharmony_ci	if (rqi) {
21238c2ecf20Sopenharmony_ci		start_time = rqi->start_time;
21248c2ecf20Sopenharmony_ci		CMD_SP(sc) = NULL;
21258c2ecf20Sopenharmony_ci	}
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	CMD_FLAGS(sc) |= flag;
21288c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci	if (rqi)
21318c2ecf20Sopenharmony_ci		snic_release_req_buf(snic, rqi, sc);
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ci	SNIC_TRC(snic->shost->host_no, snic_cmd_tag(sc), (ulong) sc,
21348c2ecf20Sopenharmony_ci		 jiffies_to_msecs(jiffies - start_time), (ulong) rqi,
21358c2ecf20Sopenharmony_ci		 SNIC_TRC_CMD(sc), SNIC_TRC_CMD_STATE_FLAGS(sc));
21368c2ecf20Sopenharmony_ci}
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci/*
21398c2ecf20Sopenharmony_ci * SCSI Eh thread issues a LUN Reset when one or more commands on a LUN
21408c2ecf20Sopenharmony_ci * fail to get aborted. It calls driver's eh_device_reset with a SCSI
21418c2ecf20Sopenharmony_ci * command on the LUN.
21428c2ecf20Sopenharmony_ci */
21438c2ecf20Sopenharmony_ciint
21448c2ecf20Sopenharmony_cisnic_device_reset(struct scsi_cmnd *sc)
21458c2ecf20Sopenharmony_ci{
21468c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = sc->device->host;
21478c2ecf20Sopenharmony_ci	struct snic *snic = shost_priv(shost);
21488c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
21498c2ecf20Sopenharmony_ci	int tag = snic_cmd_tag(sc);
21508c2ecf20Sopenharmony_ci	int start_time = jiffies;
21518c2ecf20Sopenharmony_ci	int ret = FAILED;
21528c2ecf20Sopenharmony_ci	int dr_supp = 0;
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(shost, "dev_reset:sc %p :0x%x :req = %p :tag = %d\n",
21558c2ecf20Sopenharmony_ci		      sc, sc->cmnd[0], sc->request,
21568c2ecf20Sopenharmony_ci		      snic_cmd_tag(sc));
21578c2ecf20Sopenharmony_ci	dr_supp = snic_dev_reset_supported(sc->device);
21588c2ecf20Sopenharmony_ci	if (!dr_supp) {
21598c2ecf20Sopenharmony_ci		/* device reset op is not supported */
21608c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(shost, "LUN Reset Op not supported.\n");
21618c2ecf20Sopenharmony_ci		snic_unlink_and_release_req(snic, sc, SNIC_DEV_RST_NOTSUP);
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci		goto dev_rst_end;
21648c2ecf20Sopenharmony_ci	}
21658c2ecf20Sopenharmony_ci
21668c2ecf20Sopenharmony_ci	if (unlikely(snic_get_state(snic) != SNIC_ONLINE)) {
21678c2ecf20Sopenharmony_ci		snic_unlink_and_release_req(snic, sc, 0);
21688c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(shost, "Devrst: Parent Devs are not online.\n");
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci		goto dev_rst_end;
21718c2ecf20Sopenharmony_ci	}
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	/* There is no tag when lun reset is issue through ioctl. */
21748c2ecf20Sopenharmony_ci	if (unlikely(tag <= SNIC_NO_TAG)) {
21758c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost,
21768c2ecf20Sopenharmony_ci			       "Devrst: LUN Reset Recvd thru IOCTL.\n");
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci		rqi = snic_req_init(snic, 0);
21798c2ecf20Sopenharmony_ci		if (!rqi)
21808c2ecf20Sopenharmony_ci			goto dev_rst_end;
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci		memset(scsi_cmd_priv(sc), 0,
21838c2ecf20Sopenharmony_ci			sizeof(struct snic_internal_io_state));
21848c2ecf20Sopenharmony_ci		CMD_SP(sc) = (char *)rqi;
21858c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) = SNIC_NO_FLAGS;
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci		/* Add special tag for dr coming from user spc */
21888c2ecf20Sopenharmony_ci		rqi->tm_tag = SNIC_TAG_IOCTL_DEV_RST;
21898c2ecf20Sopenharmony_ci		rqi->sc = sc;
21908c2ecf20Sopenharmony_ci	}
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci	ret = snic_send_dr_and_wait(snic, sc);
21938c2ecf20Sopenharmony_ci	if (ret) {
21948c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
21958c2ecf20Sopenharmony_ci			      "Devrst: IO w/ Tag %x Failed w/ err = %d\n",
21968c2ecf20Sopenharmony_ci			      tag, ret);
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci		snic_unlink_and_release_req(snic, sc, 0);
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci		goto dev_rst_end;
22018c2ecf20Sopenharmony_ci	}
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	ret = snic_dr_finish(snic, sc);
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_cidev_rst_end:
22068c2ecf20Sopenharmony_ci	SNIC_TRC(snic->shost->host_no, tag, (ulong) sc,
22078c2ecf20Sopenharmony_ci		 jiffies_to_msecs(jiffies - start_time),
22088c2ecf20Sopenharmony_ci		 0, SNIC_TRC_CMD(sc), SNIC_TRC_CMD_STATE_FLAGS(sc));
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
22118c2ecf20Sopenharmony_ci		      "Devrst: Returning from Device Reset : %s\n",
22128c2ecf20Sopenharmony_ci		      (ret == SUCCESS) ? "SUCCESS" : "FAILED");
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_ci	return ret;
22158c2ecf20Sopenharmony_ci} /* end of snic_device_reset */
22168c2ecf20Sopenharmony_ci
22178c2ecf20Sopenharmony_ci/*
22188c2ecf20Sopenharmony_ci * SCSI Error handling calls driver's eh_host_reset if all prior
22198c2ecf20Sopenharmony_ci * error handling levels return FAILED.
22208c2ecf20Sopenharmony_ci *
22218c2ecf20Sopenharmony_ci * Host Reset is the highest level of error recovery. If this fails, then
22228c2ecf20Sopenharmony_ci * host is offlined by SCSI.
22238c2ecf20Sopenharmony_ci */
22248c2ecf20Sopenharmony_ci/*
22258c2ecf20Sopenharmony_ci * snic_issue_hba_reset : Queues FW Reset Request.
22268c2ecf20Sopenharmony_ci */
22278c2ecf20Sopenharmony_cistatic int
22288c2ecf20Sopenharmony_cisnic_issue_hba_reset(struct snic *snic, struct scsi_cmnd *sc)
22298c2ecf20Sopenharmony_ci{
22308c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
22318c2ecf20Sopenharmony_ci	struct snic_host_req *req = NULL;
22328c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
22338c2ecf20Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(wait);
22348c2ecf20Sopenharmony_ci	unsigned long flags;
22358c2ecf20Sopenharmony_ci	int ret = -ENOMEM;
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci	rqi = snic_req_init(snic, 0);
22388c2ecf20Sopenharmony_ci	if (!rqi) {
22398c2ecf20Sopenharmony_ci		ret = -ENOMEM;
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci		goto hba_rst_end;
22428c2ecf20Sopenharmony_ci	}
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	if (snic_cmd_tag(sc) == SCSI_NO_TAG) {
22458c2ecf20Sopenharmony_ci		memset(scsi_cmd_priv(sc), 0,
22468c2ecf20Sopenharmony_ci			sizeof(struct snic_internal_io_state));
22478c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost, "issu_hr:Host reset thru ioctl.\n");
22488c2ecf20Sopenharmony_ci		rqi->sc = sc;
22498c2ecf20Sopenharmony_ci	}
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci	req = rqi_to_req(rqi);
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci	io_lock = snic_io_lock_hash(snic, sc);
22548c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
22558c2ecf20Sopenharmony_ci	SNIC_BUG_ON(CMD_SP(sc) != NULL);
22568c2ecf20Sopenharmony_ci	CMD_STATE(sc) = SNIC_IOREQ_PENDING;
22578c2ecf20Sopenharmony_ci	CMD_SP(sc) = (char *) rqi;
22588c2ecf20Sopenharmony_ci	CMD_FLAGS(sc) |= SNIC_IO_INITIALIZED;
22598c2ecf20Sopenharmony_ci	snic->remove_wait = &wait;
22608c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
22618c2ecf20Sopenharmony_ci
22628c2ecf20Sopenharmony_ci	/* Initialize Request */
22638c2ecf20Sopenharmony_ci	snic_io_hdr_enc(&req->hdr, SNIC_REQ_HBA_RESET, 0, snic_cmd_tag(sc),
22648c2ecf20Sopenharmony_ci			snic->config.hid, 0, (ulong) rqi);
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci	req->u.reset.flags = 0;
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci	ret = snic_queue_wq_desc(snic, req, sizeof(*req));
22698c2ecf20Sopenharmony_ci	if (ret) {
22708c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
22718c2ecf20Sopenharmony_ci			      "issu_hr:Queuing HBA Reset Failed. w err %d\n",
22728c2ecf20Sopenharmony_ci			      ret);
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci		goto hba_rst_err;
22758c2ecf20Sopenharmony_ci	}
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
22788c2ecf20Sopenharmony_ci	CMD_FLAGS(sc) |= SNIC_HOST_RESET_ISSUED;
22798c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
22808c2ecf20Sopenharmony_ci	atomic64_inc(&snic->s_stats.reset.hba_resets);
22818c2ecf20Sopenharmony_ci	SNIC_HOST_INFO(snic->shost, "Queued HBA Reset Successfully.\n");
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci	wait_for_completion_timeout(snic->remove_wait,
22848c2ecf20Sopenharmony_ci				    SNIC_HOST_RESET_TIMEOUT);
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci	if (snic_get_state(snic) == SNIC_FWRESET) {
22878c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost, "reset_cmpl: Reset Timedout.\n");
22888c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_ci		goto hba_rst_err;
22918c2ecf20Sopenharmony_ci	}
22928c2ecf20Sopenharmony_ci
22938c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
22948c2ecf20Sopenharmony_ci	snic->remove_wait = NULL;
22958c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
22968c2ecf20Sopenharmony_ci	CMD_SP(sc) = NULL;
22978c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_ci	if (rqi)
23008c2ecf20Sopenharmony_ci		snic_req_free(snic, rqi);
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_ci	ret = 0;
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci	return ret;
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_cihba_rst_err:
23078c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
23088c2ecf20Sopenharmony_ci	snic->remove_wait = NULL;
23098c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
23108c2ecf20Sopenharmony_ci	CMD_SP(sc) = NULL;
23118c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci	if (rqi)
23148c2ecf20Sopenharmony_ci		snic_req_free(snic, rqi);
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_cihba_rst_end:
23178c2ecf20Sopenharmony_ci	SNIC_HOST_ERR(snic->shost,
23188c2ecf20Sopenharmony_ci		      "reset:HBA Reset Failed w/ err = %d.\n",
23198c2ecf20Sopenharmony_ci		      ret);
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	return ret;
23228c2ecf20Sopenharmony_ci} /* end of snic_issue_hba_reset */
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ciint
23258c2ecf20Sopenharmony_cisnic_reset(struct Scsi_Host *shost, struct scsi_cmnd *sc)
23268c2ecf20Sopenharmony_ci{
23278c2ecf20Sopenharmony_ci	struct snic *snic = shost_priv(shost);
23288c2ecf20Sopenharmony_ci	enum snic_state sv_state;
23298c2ecf20Sopenharmony_ci	unsigned long flags;
23308c2ecf20Sopenharmony_ci	int ret = FAILED;
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	/* Set snic state as SNIC_FWRESET*/
23338c2ecf20Sopenharmony_ci	sv_state = snic_get_state(snic);
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci	spin_lock_irqsave(&snic->snic_lock, flags);
23368c2ecf20Sopenharmony_ci	if (snic_get_state(snic) == SNIC_FWRESET) {
23378c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&snic->snic_lock, flags);
23388c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(shost, "reset:prev reset is in progres\n");
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci		msleep(SNIC_HOST_RESET_TIMEOUT);
23418c2ecf20Sopenharmony_ci		ret = SUCCESS;
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_ci		goto reset_end;
23448c2ecf20Sopenharmony_ci	}
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	snic_set_state(snic, SNIC_FWRESET);
23478c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&snic->snic_lock, flags);
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci
23508c2ecf20Sopenharmony_ci	/* Wait for all the IOs that are entered in Qcmd */
23518c2ecf20Sopenharmony_ci	while (atomic_read(&snic->ios_inflight))
23528c2ecf20Sopenharmony_ci		schedule_timeout(msecs_to_jiffies(1));
23538c2ecf20Sopenharmony_ci
23548c2ecf20Sopenharmony_ci	ret = snic_issue_hba_reset(snic, sc);
23558c2ecf20Sopenharmony_ci	if (ret) {
23568c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(shost,
23578c2ecf20Sopenharmony_ci			      "reset:Host Reset Failed w/ err %d.\n",
23588c2ecf20Sopenharmony_ci			      ret);
23598c2ecf20Sopenharmony_ci		spin_lock_irqsave(&snic->snic_lock, flags);
23608c2ecf20Sopenharmony_ci		snic_set_state(snic, sv_state);
23618c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&snic->snic_lock, flags);
23628c2ecf20Sopenharmony_ci		atomic64_inc(&snic->s_stats.reset.hba_reset_fail);
23638c2ecf20Sopenharmony_ci		ret = FAILED;
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci		goto reset_end;
23668c2ecf20Sopenharmony_ci	}
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci	ret = SUCCESS;
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_cireset_end:
23718c2ecf20Sopenharmony_ci	return ret;
23728c2ecf20Sopenharmony_ci} /* end of snic_reset */
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci/*
23758c2ecf20Sopenharmony_ci * SCSI Error handling calls driver's eh_host_reset if all prior
23768c2ecf20Sopenharmony_ci * error handling levels return FAILED.
23778c2ecf20Sopenharmony_ci *
23788c2ecf20Sopenharmony_ci * Host Reset is the highest level of error recovery. If this fails, then
23798c2ecf20Sopenharmony_ci * host is offlined by SCSI.
23808c2ecf20Sopenharmony_ci */
23818c2ecf20Sopenharmony_ciint
23828c2ecf20Sopenharmony_cisnic_host_reset(struct scsi_cmnd *sc)
23838c2ecf20Sopenharmony_ci{
23848c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = sc->device->host;
23858c2ecf20Sopenharmony_ci	u32 start_time  = jiffies;
23868c2ecf20Sopenharmony_ci	int ret = FAILED;
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(shost,
23898c2ecf20Sopenharmony_ci		      "host reset:sc %p sc_cmd 0x%x req %p tag %d flags 0x%llx\n",
23908c2ecf20Sopenharmony_ci		      sc, sc->cmnd[0], sc->request,
23918c2ecf20Sopenharmony_ci		      snic_cmd_tag(sc), CMD_FLAGS(sc));
23928c2ecf20Sopenharmony_ci
23938c2ecf20Sopenharmony_ci	ret = snic_reset(shost, sc);
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci	SNIC_TRC(shost->host_no, snic_cmd_tag(sc), (ulong) sc,
23968c2ecf20Sopenharmony_ci		 jiffies_to_msecs(jiffies - start_time),
23978c2ecf20Sopenharmony_ci		 0, SNIC_TRC_CMD(sc), SNIC_TRC_CMD_STATE_FLAGS(sc));
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	return ret;
24008c2ecf20Sopenharmony_ci} /* end of snic_host_reset */
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci/*
24038c2ecf20Sopenharmony_ci * snic_cmpl_pending_tmreq : Caller should hold io_lock
24048c2ecf20Sopenharmony_ci */
24058c2ecf20Sopenharmony_cistatic void
24068c2ecf20Sopenharmony_cisnic_cmpl_pending_tmreq(struct snic *snic, struct scsi_cmnd *sc)
24078c2ecf20Sopenharmony_ci{
24088c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost,
24118c2ecf20Sopenharmony_ci		      "Completing Pending TM Req sc %p, state %s flags 0x%llx\n",
24128c2ecf20Sopenharmony_ci		      sc, snic_io_status_to_str(CMD_STATE(sc)), CMD_FLAGS(sc));
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci	/*
24158c2ecf20Sopenharmony_ci	 * CASE : FW didn't post itmf completion due to PCIe Errors.
24168c2ecf20Sopenharmony_ci	 * Marking the abort status as Success to call scsi completion
24178c2ecf20Sopenharmony_ci	 * in snic_abort_finish()
24188c2ecf20Sopenharmony_ci	 */
24198c2ecf20Sopenharmony_ci	CMD_ABTS_STATUS(sc) = SNIC_STAT_IO_SUCCESS;
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
24228c2ecf20Sopenharmony_ci	if (!rqi)
24238c2ecf20Sopenharmony_ci		return;
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	if (rqi->dr_done)
24268c2ecf20Sopenharmony_ci		complete(rqi->dr_done);
24278c2ecf20Sopenharmony_ci	else if (rqi->abts_done)
24288c2ecf20Sopenharmony_ci		complete(rqi->abts_done);
24298c2ecf20Sopenharmony_ci}
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci/*
24328c2ecf20Sopenharmony_ci * snic_scsi_cleanup: Walks through tag map and releases the reqs
24338c2ecf20Sopenharmony_ci */
24348c2ecf20Sopenharmony_cistatic void
24358c2ecf20Sopenharmony_cisnic_scsi_cleanup(struct snic *snic, int ex_tag)
24368c2ecf20Sopenharmony_ci{
24378c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
24388c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc = NULL;
24398c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
24408c2ecf20Sopenharmony_ci	unsigned long flags;
24418c2ecf20Sopenharmony_ci	int tag;
24428c2ecf20Sopenharmony_ci	u64 st_time = 0;
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost, "sc_clean: scsi cleanup.\n");
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci	for (tag = 0; tag < snic->max_tag_id; tag++) {
24478c2ecf20Sopenharmony_ci		/* Skip ex_tag */
24488c2ecf20Sopenharmony_ci		if (tag == ex_tag)
24498c2ecf20Sopenharmony_ci			continue;
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_ci		io_lock = snic_io_lock_tag(snic, tag);
24528c2ecf20Sopenharmony_ci		spin_lock_irqsave(io_lock, flags);
24538c2ecf20Sopenharmony_ci		sc = scsi_host_find_tag(snic->shost, tag);
24548c2ecf20Sopenharmony_ci		if (!sc) {
24558c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(io_lock, flags);
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_ci			continue;
24588c2ecf20Sopenharmony_ci		}
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci		if (unlikely(snic_tmreq_pending(sc))) {
24618c2ecf20Sopenharmony_ci			/*
24628c2ecf20Sopenharmony_ci			 * When FW Completes reset w/o sending completions
24638c2ecf20Sopenharmony_ci			 * for outstanding ios.
24648c2ecf20Sopenharmony_ci			 */
24658c2ecf20Sopenharmony_ci			snic_cmpl_pending_tmreq(snic, sc);
24668c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(io_lock, flags);
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci			continue;
24698c2ecf20Sopenharmony_ci		}
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci		rqi = (struct snic_req_info *) CMD_SP(sc);
24728c2ecf20Sopenharmony_ci		if (!rqi) {
24738c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(io_lock, flags);
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci			goto cleanup;
24768c2ecf20Sopenharmony_ci		}
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
24798c2ecf20Sopenharmony_ci			      "sc_clean: sc %p, rqi %p, tag %d flags 0x%llx\n",
24808c2ecf20Sopenharmony_ci			      sc, rqi, tag, CMD_FLAGS(sc));
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci		CMD_SP(sc) = NULL;
24838c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_SCSI_CLEANUP;
24848c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
24858c2ecf20Sopenharmony_ci		st_time = rqi->start_time;
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost,
24888c2ecf20Sopenharmony_ci			       "sc_clean: Releasing rqi %p : flags 0x%llx\n",
24898c2ecf20Sopenharmony_ci			       rqi, CMD_FLAGS(sc));
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci		snic_release_req_buf(snic, rqi, sc);
24928c2ecf20Sopenharmony_ci
24938c2ecf20Sopenharmony_cicleanup:
24948c2ecf20Sopenharmony_ci		sc->result = DID_TRANSPORT_DISRUPTED << 16;
24958c2ecf20Sopenharmony_ci		SNIC_HOST_INFO(snic->shost,
24968c2ecf20Sopenharmony_ci			       "sc_clean: DID_TRANSPORT_DISRUPTED for sc %p, Tag %d flags 0x%llx rqi %p duration %u msecs\n",
24978c2ecf20Sopenharmony_ci			       sc, sc->request->tag, CMD_FLAGS(sc), rqi,
24988c2ecf20Sopenharmony_ci			       jiffies_to_msecs(jiffies - st_time));
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci		/* Update IO stats */
25018c2ecf20Sopenharmony_ci		snic_stats_update_io_cmpl(&snic->s_stats);
25028c2ecf20Sopenharmony_ci
25038c2ecf20Sopenharmony_ci		if (sc->scsi_done) {
25048c2ecf20Sopenharmony_ci			SNIC_TRC(snic->shost->host_no, tag, (ulong) sc,
25058c2ecf20Sopenharmony_ci				 jiffies_to_msecs(jiffies - st_time), 0,
25068c2ecf20Sopenharmony_ci				 SNIC_TRC_CMD(sc),
25078c2ecf20Sopenharmony_ci				 SNIC_TRC_CMD_STATE_FLAGS(sc));
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci			sc->scsi_done(sc);
25108c2ecf20Sopenharmony_ci		}
25118c2ecf20Sopenharmony_ci	}
25128c2ecf20Sopenharmony_ci} /* end of snic_scsi_cleanup */
25138c2ecf20Sopenharmony_ci
25148c2ecf20Sopenharmony_civoid
25158c2ecf20Sopenharmony_cisnic_shutdown_scsi_cleanup(struct snic *snic)
25168c2ecf20Sopenharmony_ci{
25178c2ecf20Sopenharmony_ci	SNIC_HOST_INFO(snic->shost, "Shutdown time SCSI Cleanup.\n");
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci	snic_scsi_cleanup(snic, SCSI_NO_TAG);
25208c2ecf20Sopenharmony_ci} /* end of snic_shutdown_scsi_cleanup */
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci/*
25238c2ecf20Sopenharmony_ci * snic_internal_abort_io
25248c2ecf20Sopenharmony_ci * called by : snic_tgt_scsi_abort_io
25258c2ecf20Sopenharmony_ci */
25268c2ecf20Sopenharmony_cistatic int
25278c2ecf20Sopenharmony_cisnic_internal_abort_io(struct snic *snic, struct scsi_cmnd *sc, int tmf)
25288c2ecf20Sopenharmony_ci{
25298c2ecf20Sopenharmony_ci	struct snic_req_info *rqi = NULL;
25308c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
25318c2ecf20Sopenharmony_ci	unsigned long flags;
25328c2ecf20Sopenharmony_ci	u32 sv_state = 0;
25338c2ecf20Sopenharmony_ci	int ret = 0;
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ci	io_lock = snic_io_lock_hash(snic, sc);
25368c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
25378c2ecf20Sopenharmony_ci	rqi = (struct snic_req_info *) CMD_SP(sc);
25388c2ecf20Sopenharmony_ci	if (!rqi)
25398c2ecf20Sopenharmony_ci		goto skip_internal_abts;
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci	if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING)
25428c2ecf20Sopenharmony_ci		goto skip_internal_abts;
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci	if ((CMD_FLAGS(sc) & SNIC_DEVICE_RESET) &&
25458c2ecf20Sopenharmony_ci		(!(CMD_FLAGS(sc) & SNIC_DEV_RST_ISSUED))) {
25468c2ecf20Sopenharmony_ci
25478c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
25488c2ecf20Sopenharmony_ci			      "internal_abts: dev rst not pending sc 0x%p\n",
25498c2ecf20Sopenharmony_ci			      sc);
25508c2ecf20Sopenharmony_ci
25518c2ecf20Sopenharmony_ci		goto skip_internal_abts;
25528c2ecf20Sopenharmony_ci	}
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci	if (!(CMD_FLAGS(sc) & SNIC_IO_ISSUED)) {
25568c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost,
25578c2ecf20Sopenharmony_ci			"internal_abts: IO not yet issued sc 0x%p tag 0x%x flags 0x%llx state %d\n",
25588c2ecf20Sopenharmony_ci			sc, snic_cmd_tag(sc), CMD_FLAGS(sc), CMD_STATE(sc));
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci		goto skip_internal_abts;
25618c2ecf20Sopenharmony_ci	}
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci	sv_state = CMD_STATE(sc);
25648c2ecf20Sopenharmony_ci	CMD_STATE(sc) = SNIC_IOREQ_ABTS_PENDING;
25658c2ecf20Sopenharmony_ci	CMD_ABTS_STATUS(sc) = SNIC_INVALID_CODE;
25668c2ecf20Sopenharmony_ci	CMD_FLAGS(sc) |= SNIC_IO_INTERNAL_TERM_PENDING;
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_ci	if (CMD_FLAGS(sc) & SNIC_DEVICE_RESET) {
25698c2ecf20Sopenharmony_ci		/* stats */
25708c2ecf20Sopenharmony_ci		rqi->tm_tag = SNIC_TAG_DEV_RST;
25718c2ecf20Sopenharmony_ci		SNIC_SCSI_DBG(snic->shost, "internal_abts:dev rst sc %p\n", sc);
25728c2ecf20Sopenharmony_ci	}
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost, "internal_abts: Issuing abts tag %x\n",
25758c2ecf20Sopenharmony_ci		      snic_cmd_tag(sc));
25768c2ecf20Sopenharmony_ci	SNIC_BUG_ON(rqi->abts_done);
25778c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
25788c2ecf20Sopenharmony_ci
25798c2ecf20Sopenharmony_ci	ret = snic_queue_abort_req(snic, rqi, sc, tmf);
25808c2ecf20Sopenharmony_ci	if (ret) {
25818c2ecf20Sopenharmony_ci		SNIC_HOST_ERR(snic->shost,
25828c2ecf20Sopenharmony_ci			      "internal_abts: Tag = %x , Failed w/ err = %d\n",
25838c2ecf20Sopenharmony_ci			      snic_cmd_tag(sc), ret);
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci		spin_lock_irqsave(io_lock, flags);
25868c2ecf20Sopenharmony_ci
25878c2ecf20Sopenharmony_ci		if (CMD_STATE(sc) == SNIC_IOREQ_ABTS_PENDING)
25888c2ecf20Sopenharmony_ci			CMD_STATE(sc) = sv_state;
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_ci		goto skip_internal_abts;
25918c2ecf20Sopenharmony_ci	}
25928c2ecf20Sopenharmony_ci
25938c2ecf20Sopenharmony_ci	spin_lock_irqsave(io_lock, flags);
25948c2ecf20Sopenharmony_ci	if (CMD_FLAGS(sc) & SNIC_DEVICE_RESET)
25958c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_DEV_RST_TERM_ISSUED;
25968c2ecf20Sopenharmony_ci	else
25978c2ecf20Sopenharmony_ci		CMD_FLAGS(sc) |= SNIC_IO_INTERNAL_TERM_ISSUED;
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci	ret = SUCCESS;
26008c2ecf20Sopenharmony_ci
26018c2ecf20Sopenharmony_ciskip_internal_abts:
26028c2ecf20Sopenharmony_ci	lockdep_assert_held(io_lock);
26038c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(io_lock, flags);
26048c2ecf20Sopenharmony_ci
26058c2ecf20Sopenharmony_ci	return ret;
26068c2ecf20Sopenharmony_ci} /* end of snic_internal_abort_io */
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci/*
26098c2ecf20Sopenharmony_ci * snic_tgt_scsi_abort_io : called by snic_tgt_del
26108c2ecf20Sopenharmony_ci */
26118c2ecf20Sopenharmony_ciint
26128c2ecf20Sopenharmony_cisnic_tgt_scsi_abort_io(struct snic_tgt *tgt)
26138c2ecf20Sopenharmony_ci{
26148c2ecf20Sopenharmony_ci	struct snic *snic = NULL;
26158c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc = NULL;
26168c2ecf20Sopenharmony_ci	struct snic_tgt *sc_tgt = NULL;
26178c2ecf20Sopenharmony_ci	spinlock_t *io_lock = NULL;
26188c2ecf20Sopenharmony_ci	unsigned long flags;
26198c2ecf20Sopenharmony_ci	int ret = 0, tag, abt_cnt = 0, tmf = 0;
26208c2ecf20Sopenharmony_ci
26218c2ecf20Sopenharmony_ci	if (!tgt)
26228c2ecf20Sopenharmony_ci		return -1;
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci	snic = shost_priv(snic_tgt_to_shost(tgt));
26258c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost, "tgt_abt_io: Cleaning Pending IOs.\n");
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	if (tgt->tdata.typ == SNIC_TGT_DAS)
26288c2ecf20Sopenharmony_ci		tmf = SNIC_ITMF_ABTS_TASK;
26298c2ecf20Sopenharmony_ci	else
26308c2ecf20Sopenharmony_ci		tmf = SNIC_ITMF_ABTS_TASK_TERM;
26318c2ecf20Sopenharmony_ci
26328c2ecf20Sopenharmony_ci	for (tag = 0; tag < snic->max_tag_id; tag++) {
26338c2ecf20Sopenharmony_ci		io_lock = snic_io_lock_tag(snic, tag);
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_ci		spin_lock_irqsave(io_lock, flags);
26368c2ecf20Sopenharmony_ci		sc = scsi_host_find_tag(snic->shost, tag);
26378c2ecf20Sopenharmony_ci		if (!sc) {
26388c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(io_lock, flags);
26398c2ecf20Sopenharmony_ci
26408c2ecf20Sopenharmony_ci			continue;
26418c2ecf20Sopenharmony_ci		}
26428c2ecf20Sopenharmony_ci
26438c2ecf20Sopenharmony_ci		sc_tgt = starget_to_tgt(scsi_target(sc->device));
26448c2ecf20Sopenharmony_ci		if (sc_tgt != tgt) {
26458c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(io_lock, flags);
26468c2ecf20Sopenharmony_ci
26478c2ecf20Sopenharmony_ci			continue;
26488c2ecf20Sopenharmony_ci		}
26498c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(io_lock, flags);
26508c2ecf20Sopenharmony_ci
26518c2ecf20Sopenharmony_ci		ret = snic_internal_abort_io(snic, sc, tmf);
26528c2ecf20Sopenharmony_ci		if (ret < 0) {
26538c2ecf20Sopenharmony_ci			SNIC_HOST_ERR(snic->shost,
26548c2ecf20Sopenharmony_ci				      "tgt_abt_io: Tag %x, Failed w err = %d\n",
26558c2ecf20Sopenharmony_ci				      tag, ret);
26568c2ecf20Sopenharmony_ci
26578c2ecf20Sopenharmony_ci			continue;
26588c2ecf20Sopenharmony_ci		}
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci		if (ret == SUCCESS)
26618c2ecf20Sopenharmony_ci			abt_cnt++;
26628c2ecf20Sopenharmony_ci	}
26638c2ecf20Sopenharmony_ci
26648c2ecf20Sopenharmony_ci	SNIC_SCSI_DBG(snic->shost, "tgt_abt_io: abt_cnt = %d\n", abt_cnt);
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ci	return 0;
26678c2ecf20Sopenharmony_ci} /* end of snic_tgt_scsi_abort_io */
2668