xref: /linux/drivers/scsi/fnic/fnic_nvme.c (revision 35748ddd3b2c91555bd86b8cf88edc90e7317e57)
15efdd5cfSKaran Tilak Kumar // SPDX-License-Identifier: GPL-2.0-only
25efdd5cfSKaran Tilak Kumar /*
35efdd5cfSKaran Tilak Kumar  * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
45efdd5cfSKaran Tilak Kumar  * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
55efdd5cfSKaran Tilak Kumar  */
65efdd5cfSKaran Tilak Kumar #include <linux/mempool.h>
75efdd5cfSKaran Tilak Kumar #include <linux/errno.h>
85efdd5cfSKaran Tilak Kumar #include <linux/init.h>
95efdd5cfSKaran Tilak Kumar #include <linux/workqueue.h>
105efdd5cfSKaran Tilak Kumar #include <linux/pci.h>
115efdd5cfSKaran Tilak Kumar #include <linux/scatterlist.h>
125efdd5cfSKaran Tilak Kumar #include <linux/skbuff.h>
135efdd5cfSKaran Tilak Kumar #include <linux/spinlock.h>
145efdd5cfSKaran Tilak Kumar #include <linux/kthread.h>
155efdd5cfSKaran Tilak Kumar #include <linux/if_ether.h>
165efdd5cfSKaran Tilak Kumar #include <linux/if_vlan.h>
175efdd5cfSKaran Tilak Kumar #include <linux/delay.h>
185efdd5cfSKaran Tilak Kumar #include <linux/gfp.h>
195efdd5cfSKaran Tilak Kumar #include <linux/nvme.h>
205efdd5cfSKaran Tilak Kumar #include <linux/nvme-fc.h>
215efdd5cfSKaran Tilak Kumar #include "fnic.h"
225efdd5cfSKaran Tilak Kumar #include "fnic_trace.h"
235efdd5cfSKaran Tilak Kumar #include "fdls_fc.h"
245efdd5cfSKaran Tilak Kumar 
25*376a3960SKaran Tilak Kumar #if IS_REACHABLE(CONFIG_NVME_FC)
265efdd5cfSKaran Tilak Kumar 
27f06ee33dSKaran Tilak Kumar static bool nvfnic_ls_req_cleanup(struct fnic_iport_s *iport,
28f06ee33dSKaran Tilak Kumar 				  struct nvmefc_ls_req *lsreq,
29f06ee33dSKaran Tilak Kumar 				  uint16_t oxid);
30f06ee33dSKaran Tilak Kumar 
315efdd5cfSKaran Tilak Kumar int nvfnic_get_sg_count(struct fnic_io_req *io_req)
325efdd5cfSKaran Tilak Kumar {
335efdd5cfSKaran Tilak Kumar 	return io_req->fcp_req->sg_cnt;
345efdd5cfSKaran Tilak Kumar }
355efdd5cfSKaran Tilak Kumar 
365efdd5cfSKaran Tilak Kumar int nvfnic_dma_map_sgl(struct fnic *fnic, struct fnic_io_req *io_req,
375efdd5cfSKaran Tilak Kumar 		       int sg_count)
385efdd5cfSKaran Tilak Kumar {
395efdd5cfSKaran Tilak Kumar 	io_req->sgl_list_pa = dma_map_single(&fnic->pdev->dev,
405efdd5cfSKaran Tilak Kumar 					     io_req->sgl_list,
415efdd5cfSKaran Tilak Kumar 					     sizeof(io_req->sgl_list[0]) *
425efdd5cfSKaran Tilak Kumar 					     sg_count, DMA_TO_DEVICE);
435efdd5cfSKaran Tilak Kumar 	if (dma_mapping_error(&fnic->pdev->dev, io_req->sgl_list_pa)) {
445efdd5cfSKaran Tilak Kumar 		dev_err(&fnic->pdev->dev, "DMA mapping failed\n");
455efdd5cfSKaran Tilak Kumar 		io_req->sgl_list_pa = 0;
465efdd5cfSKaran Tilak Kumar 		io_req->sgl_mapped = 0;
475efdd5cfSKaran Tilak Kumar 		return -EBUSY;
485efdd5cfSKaran Tilak Kumar 	}
495efdd5cfSKaran Tilak Kumar 
505efdd5cfSKaran Tilak Kumar 	io_req->sgl_mapped = 1;
515efdd5cfSKaran Tilak Kumar 	return 0;
525efdd5cfSKaran Tilak Kumar }
535efdd5cfSKaran Tilak Kumar 
545efdd5cfSKaran Tilak Kumar void nvfnic_dma_unmap_sgl(struct fnic *fnic, struct fnic_io_req *io_req)
555efdd5cfSKaran Tilak Kumar {
565efdd5cfSKaran Tilak Kumar 	if (io_req->sgl_mapped) {
575efdd5cfSKaran Tilak Kumar 		dma_unmap_single(&fnic->pdev->dev, io_req->sgl_list_pa,
585efdd5cfSKaran Tilak Kumar 				 sizeof(io_req->sgl_list[0]) * io_req->sgl_cnt,
595efdd5cfSKaran Tilak Kumar 				 DMA_TO_DEVICE);
605efdd5cfSKaran Tilak Kumar 		io_req->sgl_mapped = 0;
615efdd5cfSKaran Tilak Kumar 		io_req->sgl_list_pa = 0;
625efdd5cfSKaran Tilak Kumar 	}
635efdd5cfSKaran Tilak Kumar }
645efdd5cfSKaran Tilak Kumar 
655efdd5cfSKaran Tilak Kumar static void nvfnic_update_io_bytes(struct fnic *fnic,
665efdd5cfSKaran Tilak Kumar 				   struct fnic_io_req *io_req, u8 opcode)
675efdd5cfSKaran Tilak Kumar {
685efdd5cfSKaran Tilak Kumar 	if (opcode == nvme_cmd_read)
695efdd5cfSKaran Tilak Kumar 		fnic->fcp_input_bytes += io_req->fcp_req->transferred_length;
705efdd5cfSKaran Tilak Kumar 	else if (opcode == nvme_cmd_write)
715efdd5cfSKaran Tilak Kumar 		fnic->fcp_output_bytes += io_req->fcp_req->transferred_length;
725efdd5cfSKaran Tilak Kumar }
735efdd5cfSKaran Tilak Kumar 
74d25a557dSKaran Tilak Kumar static void nvfnic_update_io_stats(struct fnic *fnic, u8 opcode)
75d25a557dSKaran Tilak Kumar {
76d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
77d25a557dSKaran Tilak Kumar 
78d25a557dSKaran Tilak Kumar 	switch (opcode) {
79d25a557dSKaran Tilak Kumar 	case nvme_cmd_read:
80d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->nvme_stats.nvme_input_requests);
81d25a557dSKaran Tilak Kumar 		break;
82d25a557dSKaran Tilak Kumar 	case nvme_cmd_write:
83d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->nvme_stats.nvme_output_requests);
84d25a557dSKaran Tilak Kumar 		break;
85d25a557dSKaran Tilak Kumar 	default:
86d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->nvme_stats.nvme_control_requests);
87d25a557dSKaran Tilak Kumar 		break;
88d25a557dSKaran Tilak Kumar 	}
89d25a557dSKaran Tilak Kumar }
90d25a557dSKaran Tilak Kumar 
91d25a557dSKaran Tilak Kumar static void nvfnic_update_cmpl_stats(struct fnic *fnic,
92d25a557dSKaran Tilak Kumar 				     struct fnic_io_req *io_req)
93d25a557dSKaran Tilak Kumar {
94d25a557dSKaran Tilak Kumar 	struct io_path_stats *io_stats = &fnic->fnic_stats.io_stats;
95d25a557dSKaran Tilak Kumar 	atomic64_t *duration_stat;
96d25a557dSKaran Tilak Kumar 	unsigned long io_duration_time;
97d25a557dSKaran Tilak Kumar 
98d25a557dSKaran Tilak Kumar 	atomic64_dec(&io_stats->active_ios);
99d25a557dSKaran Tilak Kumar 	if (atomic64_read(&fnic->io_cmpl_skip))
100d25a557dSKaran Tilak Kumar 		atomic64_dec(&fnic->io_cmpl_skip);
101d25a557dSKaran Tilak Kumar 	else
102d25a557dSKaran Tilak Kumar 		atomic64_inc(&io_stats->io_completions);
103d25a557dSKaran Tilak Kumar 
104d25a557dSKaran Tilak Kumar 	io_duration_time = jiffies_to_msecs(jiffies - io_req->start_time);
105d25a557dSKaran Tilak Kumar 
106d25a557dSKaran Tilak Kumar 	if (io_duration_time <= 10)
107d25a557dSKaran Tilak Kumar 		duration_stat = &io_stats->io_btw_0_to_10_msec;
108d25a557dSKaran Tilak Kumar 	else if (io_duration_time <= 100)
109d25a557dSKaran Tilak Kumar 		duration_stat = &io_stats->io_btw_10_to_100_msec;
110d25a557dSKaran Tilak Kumar 	else if (io_duration_time <= 500)
111d25a557dSKaran Tilak Kumar 		duration_stat = &io_stats->io_btw_100_to_500_msec;
112d25a557dSKaran Tilak Kumar 	else if (io_duration_time <= 5000)
113d25a557dSKaran Tilak Kumar 		duration_stat = &io_stats->io_btw_500_to_5000_msec;
114d25a557dSKaran Tilak Kumar 	else if (io_duration_time <= 10000)
115d25a557dSKaran Tilak Kumar 		duration_stat = &io_stats->io_btw_5000_to_10000_msec;
116d25a557dSKaran Tilak Kumar 	else if (io_duration_time <= 30000)
117d25a557dSKaran Tilak Kumar 		duration_stat = &io_stats->io_btw_10000_to_30000_msec;
118d25a557dSKaran Tilak Kumar 	else {
119d25a557dSKaran Tilak Kumar 		duration_stat = &io_stats->io_greater_than_30000_msec;
120d25a557dSKaran Tilak Kumar 		if (io_duration_time >
121d25a557dSKaran Tilak Kumar 		    atomic64_read(&io_stats->current_max_io_time))
122d25a557dSKaran Tilak Kumar 			atomic64_set(&io_stats->current_max_io_time,
123d25a557dSKaran Tilak Kumar 				     io_duration_time);
124d25a557dSKaran Tilak Kumar 	}
125d25a557dSKaran Tilak Kumar 
126d25a557dSKaran Tilak Kumar 	atomic64_inc(duration_stat);
127d25a557dSKaran Tilak Kumar }
128d25a557dSKaran Tilak Kumar 
1295efdd5cfSKaran Tilak Kumar int
1305efdd5cfSKaran Tilak Kumar nvfnic_alloc_fcpio_tag(struct fnic_iport_s *iport, struct fnic_io_req *io_req)
1315efdd5cfSKaran Tilak Kumar {
1325efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
1335efdd5cfSKaran Tilak Kumar 	int tag;
1345efdd5cfSKaran Tilak Kumar 
1355efdd5cfSKaran Tilak Kumar 	tag = sbitmap_get(&fnic->nvfnic_tag_map);
1365efdd5cfSKaran Tilak Kumar 	if (tag >= 0) {
1375efdd5cfSKaran Tilak Kumar 		WRITE_ONCE(io_req->tag, tag);
1385efdd5cfSKaran Tilak Kumar 		fnic->sw_copy_wq[0].io_req_table[tag] = io_req;
1395efdd5cfSKaran Tilak Kumar 		return tag;
1405efdd5cfSKaran Tilak Kumar 	}
1415efdd5cfSKaran Tilak Kumar 	return FNIC_NVME_NO_FREE_TAG;
1425efdd5cfSKaran Tilak Kumar }
1435efdd5cfSKaran Tilak Kumar 
1445efdd5cfSKaran Tilak Kumar void
1455efdd5cfSKaran Tilak Kumar nvfnic_free_fcpio_tag(struct fnic_iport_s *iport, struct fnic_io_req *io_req)
1465efdd5cfSKaran Tilak Kumar {
1475efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
1485efdd5cfSKaran Tilak Kumar 	uint16_t tag = io_req->tag;
1495efdd5cfSKaran Tilak Kumar 
1505efdd5cfSKaran Tilak Kumar 	if (tag == FNIC_NVME_NO_FREE_TAG) {
1515efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
1525efdd5cfSKaran Tilak Kumar 			    "Attempting to free invalid tag: 0x%x\n", tag);
1535efdd5cfSKaran Tilak Kumar 		return;
1545efdd5cfSKaran Tilak Kumar 	}
1555efdd5cfSKaran Tilak Kumar 	fnic->sw_copy_wq[0].io_req_table[tag] = NULL;
1565efdd5cfSKaran Tilak Kumar 	WRITE_ONCE(io_req->tag, FNIC_NVME_NO_FREE_TAG);
1575efdd5cfSKaran Tilak Kumar 	sbitmap_clear_bit(&fnic->nvfnic_tag_map, tag);
1585efdd5cfSKaran Tilak Kumar }
1595efdd5cfSKaran Tilak Kumar 
1605efdd5cfSKaran Tilak Kumar void
1615efdd5cfSKaran Tilak Kumar nvfnic_reset_fcpio_tag_pool(struct fnic_iport_s *iport)
1625efdd5cfSKaran Tilak Kumar {
1635efdd5cfSKaran Tilak Kumar 	WARN_ON(sbitmap_weight(&iport->fnic->nvfnic_tag_map));
1645efdd5cfSKaran Tilak Kumar }
1655efdd5cfSKaran Tilak Kumar 
1665efdd5cfSKaran Tilak Kumar struct fnic_io_req *
1675efdd5cfSKaran Tilak Kumar nvfnic_find_io_req_by_tag(struct fnic *fnic, uint16_t tag)
1685efdd5cfSKaran Tilak Kumar {
1695efdd5cfSKaran Tilak Kumar 	if (tag == FNIC_NVME_NO_FREE_TAG ||
1705efdd5cfSKaran Tilak Kumar 		!sbitmap_test_bit(&fnic->nvfnic_tag_map, tag))
1715efdd5cfSKaran Tilak Kumar 		return NULL;
1725efdd5cfSKaran Tilak Kumar 	return fnic->sw_copy_wq[0].io_req_table[tag];
1735efdd5cfSKaran Tilak Kumar }
1745efdd5cfSKaran Tilak Kumar 
1755efdd5cfSKaran Tilak Kumar /*
1765efdd5cfSKaran Tilak Kumar  * Unmap the data buffer and sense buffer for an io_req,
1775efdd5cfSKaran Tilak Kumar  * also unmap and free the device-private scatter/gather list.
1785efdd5cfSKaran Tilak Kumar  */
1795efdd5cfSKaran Tilak Kumar void nvfnic_release_nvme_ioreq_buf(struct fnic_iport_s *iport,
1805efdd5cfSKaran Tilak Kumar 					struct fnic_io_req *io_req)
1815efdd5cfSKaran Tilak Kumar {
1825efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
1835efdd5cfSKaran Tilak Kumar 
1845efdd5cfSKaran Tilak Kumar 	nvfnic_dma_unmap_sgl(fnic, io_req);
1855efdd5cfSKaran Tilak Kumar 
1865efdd5cfSKaran Tilak Kumar 	if (io_req->sgl_cnt)
1875efdd5cfSKaran Tilak Kumar 		mempool_free(io_req->sgl_list_alloc,
1885efdd5cfSKaran Tilak Kumar 			     fnic->io_sgl_pool[io_req->sgl_type]);
1895efdd5cfSKaran Tilak Kumar }
1905efdd5cfSKaran Tilak Kumar 
1918ef412ceSKaran Tilak Kumar int nvfnic_get_nvmef_info(struct fnic *fnic, struct fnic_nvmef_info *info)
1928ef412ceSKaran Tilak Kumar {
1938ef412ceSKaran Tilak Kumar 	int len = 0;
1948ef412ceSKaran Tilak Kumar 	struct fnic_iport_s *iport = &fnic->iport;
1958ef412ceSKaran Tilak Kumar 	int buf_size = info->buf_size;
1968ef412ceSKaran Tilak Kumar 	struct fnic_tport_s *tport;
1978ef412ceSKaran Tilak Kumar 	struct fnic_tport_s *next;
1988ef412ceSKaran Tilak Kumar 	unsigned long flags;
1998ef412ceSKaran Tilak Kumar 
2008ef412ceSKaran Tilak Kumar 	if (buf_size <= 0)
2018ef412ceSKaran Tilak Kumar 		return 0;
2028ef412ceSKaran Tilak Kumar 
2038ef412ceSKaran Tilak Kumar 	len += scnprintf(info->info_buffer + len, buf_size - len,
2048ef412ceSKaran Tilak Kumar 			 "lport wwpn 0x%llx wwnn 0x%llx fcid 0x%06x\n",
2058ef412ceSKaran Tilak Kumar 			 iport->wwpn, iport->wwnn, iport->fcid);
2068ef412ceSKaran Tilak Kumar 
2078ef412ceSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, flags);
2088ef412ceSKaran Tilak Kumar 	list_for_each_entry_safe(tport, next, &iport->tport_list, links) {
2098ef412ceSKaran Tilak Kumar 		if (len >= buf_size - 1)
2108ef412ceSKaran Tilak Kumar 			break;
2118ef412ceSKaran Tilak Kumar 
2128ef412ceSKaran Tilak Kumar 		len += scnprintf(info->info_buffer + len, buf_size - len,
2138ef412ceSKaran Tilak Kumar 				 "tport wwpn 0x%llx wwnn 0x%llx fcid 0x%06x\n",
2148ef412ceSKaran Tilak Kumar 				 tport->wwpn, tport->wwnn, tport->fcid);
2158ef412ceSKaran Tilak Kumar 	}
2168ef412ceSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
2178ef412ceSKaran Tilak Kumar 
2188ef412ceSKaran Tilak Kumar 	return len;
2198ef412ceSKaran Tilak Kumar }
2208ef412ceSKaran Tilak Kumar 
2215efdd5cfSKaran Tilak Kumar inline int nvfnic_queue_wq_nvme_copy_desc(struct fnic *fnic,
2225efdd5cfSKaran Tilak Kumar 					       struct vnic_wq_copy *wq,
2235efdd5cfSKaran Tilak Kumar 					       struct fnic_io_req *io_req,
2245efdd5cfSKaran Tilak Kumar 					       int sg_count)
2255efdd5cfSKaran Tilak Kumar {
2265efdd5cfSKaran Tilak Kumar 	struct scatterlist *sg;
2275efdd5cfSKaran Tilak Kumar 	struct fnic_tport_s *tport = io_req->tport;
2285efdd5cfSKaran Tilak Kumar 	struct host_sg_desc *desc;
229d25a557dSKaran Tilak Kumar 	struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats;
2305efdd5cfSKaran Tilak Kumar 	unsigned int i;
2315efdd5cfSKaran Tilak Kumar 	unsigned long intr_flags;
2325efdd5cfSKaran Tilak Kumar 	int flags;
2335efdd5cfSKaran Tilak Kumar 	u8 exch_flags;
2345efdd5cfSKaran Tilak Kumar 	struct scatterlist *sgl;
2355efdd5cfSKaran Tilak Kumar 	int idx;
2365efdd5cfSKaran Tilak Kumar 	int ret = 0;
2375efdd5cfSKaran Tilak Kumar 
2385efdd5cfSKaran Tilak Kumar 	if (sg_count) {
2395efdd5cfSKaran Tilak Kumar 		/* For each SGE, create a device desc entry */
2405efdd5cfSKaran Tilak Kumar 		desc = io_req->sgl_list;
2415efdd5cfSKaran Tilak Kumar 		sgl = io_req->fcp_req->first_sgl;
2425efdd5cfSKaran Tilak Kumar 		for_each_sg(sgl, sg, sg_count, i) {
2435efdd5cfSKaran Tilak Kumar 			desc->addr = cpu_to_le64(sg_dma_address(sg));
2445efdd5cfSKaran Tilak Kumar 			desc->len = cpu_to_le32(sg_dma_len(sg));
2455efdd5cfSKaran Tilak Kumar 			desc->_resvd = 0;
2465efdd5cfSKaran Tilak Kumar 			desc++;
2475efdd5cfSKaran Tilak Kumar 		}
2485efdd5cfSKaran Tilak Kumar 
2495efdd5cfSKaran Tilak Kumar 		ret = nvfnic_dma_map_sgl(fnic, io_req, sg_count);
2505efdd5cfSKaran Tilak Kumar 		if (ret)
2515efdd5cfSKaran Tilak Kumar 			return ret;
2525efdd5cfSKaran Tilak Kumar 	}
2535efdd5cfSKaran Tilak Kumar 
2545efdd5cfSKaran Tilak Kumar 	idx = (struct vnic_wq_copy *)wq - &fnic->hw_copy_wq[0];
2555efdd5cfSKaran Tilak Kumar 
2565efdd5cfSKaran Tilak Kumar 	/* Enqueue the descriptor in the Copy WQ */
2575efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->wq_copy_lock[idx], intr_flags);
2585efdd5cfSKaran Tilak Kumar 
2595efdd5cfSKaran Tilak Kumar 	if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[idx])
2605efdd5cfSKaran Tilak Kumar 		free_wq_copy_descs(fnic, wq, idx);
2615efdd5cfSKaran Tilak Kumar 
2625efdd5cfSKaran Tilak Kumar 	if (unlikely(!vnic_wq_copy_desc_avail(wq))) {
2635efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->wq_copy_lock[idx], intr_flags);
2645efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
2655efdd5cfSKaran Tilak Kumar 			    "Enqueue failure: No descriptors\n");
266d25a557dSKaran Tilak Kumar 		atomic64_inc(&misc_stats->io_cpwq_alloc_failures);
2675efdd5cfSKaran Tilak Kumar 		return -EBUSY;
2685efdd5cfSKaran Tilak Kumar 	}
2695efdd5cfSKaran Tilak Kumar 
2705efdd5cfSKaran Tilak Kumar 	flags = 0;
2715efdd5cfSKaran Tilak Kumar 	if (io_req->fcp_req->io_dir == NVMEFC_FCP_READ)
2725efdd5cfSKaran Tilak Kumar 		flags = FCPIO_ICMND_RDDATA;
2735efdd5cfSKaran Tilak Kumar 	else if (io_req->fcp_req->io_dir == NVMEFC_FCP_WRITE)
2745efdd5cfSKaran Tilak Kumar 		flags = FCPIO_ICMND_WRDATA;
2755efdd5cfSKaran Tilak Kumar 
2765efdd5cfSKaran Tilak Kumar 	exch_flags = 0;
2775efdd5cfSKaran Tilak Kumar 
2785efdd5cfSKaran Tilak Kumar 	fnic_queue_wq_copy_desc_nvme_io(wq, io_req->tag,
2795efdd5cfSKaran Tilak Kumar 					exch_flags, io_req->sgl_cnt,
2805efdd5cfSKaran Tilak Kumar 					io_req->sgl_list_pa, flags,
2815efdd5cfSKaran Tilak Kumar 					io_req->fcp_req->cmdaddr,
2825efdd5cfSKaran Tilak Kumar 					io_req->fcp_req->cmdlen,
2835efdd5cfSKaran Tilak Kumar 					io_req->fcp_req->payload_length,
2845efdd5cfSKaran Tilak Kumar 					io_req->port_id,
2855efdd5cfSKaran Tilak Kumar 					tport->max_payload_size, tport->r_a_tov,
2865efdd5cfSKaran Tilak Kumar 					tport->e_d_tov);
2875efdd5cfSKaran Tilak Kumar 
288d25a557dSKaran Tilak Kumar 	atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs);
289d25a557dSKaran Tilak Kumar 	if (atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs) >
290d25a557dSKaran Tilak Kumar 	    atomic64_read(&fnic->fnic_stats.fw_stats.max_fw_reqs))
291d25a557dSKaran Tilak Kumar 		atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs,
292d25a557dSKaran Tilak Kumar 		     atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs));
2935efdd5cfSKaran Tilak Kumar 
2945efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->wq_copy_lock[idx], intr_flags);
2955efdd5cfSKaran Tilak Kumar 	return 0;
2965efdd5cfSKaran Tilak Kumar }
2975efdd5cfSKaran Tilak Kumar 
2985efdd5cfSKaran Tilak Kumar bool
2995efdd5cfSKaran Tilak Kumar nvfnic_transport_ready(struct fnic_iport_s *iport, struct fnic_tport_s *tport)
3005efdd5cfSKaran Tilak Kumar {
3015efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
302d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
3035efdd5cfSKaran Tilak Kumar 
3045efdd5cfSKaran Tilak Kumar 	if (tport == NULL)
3055efdd5cfSKaran Tilak Kumar 		return false;
3065efdd5cfSKaran Tilak Kumar 
3075efdd5cfSKaran Tilak Kumar 	if (fdls_get_state(&iport->fabric) == FDLS_STATE_LINKDOWN ||
3085efdd5cfSKaran Tilak Kumar 	    iport->state != FNIC_IPORT_STATE_READY) {
309d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->misc_stats.iport_not_ready);
3105efdd5cfSKaran Tilak Kumar 		return false;
3115efdd5cfSKaran Tilak Kumar 	}
3125efdd5cfSKaran Tilak Kumar 
3135efdd5cfSKaran Tilak Kumar 	if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED)))
3145efdd5cfSKaran Tilak Kumar 		return false;
3155efdd5cfSKaran Tilak Kumar 
316d25a557dSKaran Tilak Kumar 	if (fdls_tport_is_offline(tport)) {
317d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->misc_stats.tport_not_ready);
3185efdd5cfSKaran Tilak Kumar 		return false;
319d25a557dSKaran Tilak Kumar 	}
3205efdd5cfSKaran Tilak Kumar 
3215efdd5cfSKaran Tilak Kumar 	return true;
3225efdd5cfSKaran Tilak Kumar }
3235efdd5cfSKaran Tilak Kumar 
3245efdd5cfSKaran Tilak Kumar int nvfnic_queuecommand(struct fnic_io_req *io_req)
3255efdd5cfSKaran Tilak Kumar {
3265efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = io_req->iport;
3275efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
3285efdd5cfSKaran Tilak Kumar 	struct fnic_tport_s *tport = io_req->tport;
329d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
330d25a557dSKaran Tilak Kumar 	struct vnic_wq_copy *wq = io_req->wq;
3315efdd5cfSKaran Tilak Kumar 	int ret = 0;
3325efdd5cfSKaran Tilak Kumar 	int sg_count = 0;
3335efdd5cfSKaran Tilak Kumar 	unsigned long ptr;
3345efdd5cfSKaran Tilak Kumar 	unsigned char *lba;
3355efdd5cfSKaran Tilak Kumar 	u64 cmd_trace;
336d25a557dSKaran Tilak Kumar 	int idx;
3375efdd5cfSKaran Tilak Kumar 	struct nvme_fc_cmd_iu *cmdiu = io_req->fcp_req->cmdaddr;
3385efdd5cfSKaran Tilak Kumar 
3395efdd5cfSKaran Tilak Kumar 	io_req->cmd_state = FNIC_IOREQ_NOT_INITED;
3405efdd5cfSKaran Tilak Kumar 	io_req->cmd_flags = FNIC_NO_FLAGS;
3415efdd5cfSKaran Tilak Kumar 	/* Map the data buffer */
3425efdd5cfSKaran Tilak Kumar 	sg_count = nvfnic_get_sg_count(io_req);
3435efdd5cfSKaran Tilak Kumar 	if (sg_count < 0) {
3445efdd5cfSKaran Tilak Kumar 		FNIC_TRACE(nvfnic_queuecommand, fnic->fnic_num,
3455efdd5cfSKaran Tilak Kumar 			   io_req->tag, io_req, 0, io_req->fcp_req->io_dir,
3465efdd5cfSKaran Tilak Kumar 			   sg_count, io_req->cmd_state);
3475efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic, "sg count is less-than-zero\n");
3485efdd5cfSKaran Tilak Kumar 		ret = -1;
3495efdd5cfSKaran Tilak Kumar 		goto out;
3505efdd5cfSKaran Tilak Kumar 	}
3515efdd5cfSKaran Tilak Kumar 
3525efdd5cfSKaran Tilak Kumar 	/* Determine the type of scatter/gather list we need */
3535efdd5cfSKaran Tilak Kumar 	io_req->sgl_cnt = sg_count;
3545efdd5cfSKaran Tilak Kumar 	io_req->sgl_type = FNIC_SGL_CACHE_DFLT;
3555efdd5cfSKaran Tilak Kumar 	if (sg_count > FNIC_DFLT_SG_DESC_CNT)
3565efdd5cfSKaran Tilak Kumar 		io_req->sgl_type = FNIC_SGL_CACHE_MAX;
3575efdd5cfSKaran Tilak Kumar 
3585efdd5cfSKaran Tilak Kumar 	if (sg_count) {
3595efdd5cfSKaran Tilak Kumar 		io_req->sgl_list =
3605efdd5cfSKaran Tilak Kumar 		    mempool_alloc(fnic->io_sgl_pool[io_req->sgl_type],
3615efdd5cfSKaran Tilak Kumar 				  GFP_ATOMIC);
3625efdd5cfSKaran Tilak Kumar 		if (!io_req->sgl_list) {
363d25a557dSKaran Tilak Kumar 			atomic64_inc(&fnic_stats->io_stats.alloc_failures);
3645efdd5cfSKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_INFO, fnic,
3655efdd5cfSKaran Tilak Kumar 				      "Unable to alloc SGLs\n");
3665efdd5cfSKaran Tilak Kumar 			ret = -ENOMEM;
3675efdd5cfSKaran Tilak Kumar 			goto out;
3685efdd5cfSKaran Tilak Kumar 		}
3695efdd5cfSKaran Tilak Kumar 
3705efdd5cfSKaran Tilak Kumar 		/* Cache sgl list allocated address before alignment */
3715efdd5cfSKaran Tilak Kumar 		io_req->sgl_list_alloc = io_req->sgl_list;
3725efdd5cfSKaran Tilak Kumar 		ptr = (unsigned long)io_req->sgl_list;
3735efdd5cfSKaran Tilak Kumar 		if (ptr % FNIC_SG_DESC_ALIGN) {
3745efdd5cfSKaran Tilak Kumar 			io_req->sgl_list = (struct host_sg_desc *)
3755efdd5cfSKaran Tilak Kumar 			    (((unsigned long)ptr + FNIC_SG_DESC_ALIGN - 1)
3765efdd5cfSKaran Tilak Kumar 			     & ~(FNIC_SG_DESC_ALIGN - 1));
3775efdd5cfSKaran Tilak Kumar 		}
3785efdd5cfSKaran Tilak Kumar 	}
3795efdd5cfSKaran Tilak Kumar 
3805efdd5cfSKaran Tilak Kumar 	io_req->port_id = tport->fcid;
3815efdd5cfSKaran Tilak Kumar 	io_req->start_time = jiffies;
3825efdd5cfSKaran Tilak Kumar 	io_req->cmd_state = FNIC_IOREQ_CMD_PENDING;
3835efdd5cfSKaran Tilak Kumar 	io_req->cmd_flags = FNIC_IO_INITIALIZED;
3845efdd5cfSKaran Tilak Kumar 
3855efdd5cfSKaran Tilak Kumar 	/* create copy wq desc and enqueue it */
386d25a557dSKaran Tilak Kumar 	idx = wq - &fnic->hw_copy_wq[0];
387d25a557dSKaran Tilak Kumar 	atomic64_inc(&fnic_stats->io_stats.ios[idx]);
3885efdd5cfSKaran Tilak Kumar 	ret = nvfnic_queue_wq_nvme_copy_desc(fnic, io_req->wq, io_req, sg_count);
3895efdd5cfSKaran Tilak Kumar 	if (ret) {
3905efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic, "Unable to queue frame\n");
3915efdd5cfSKaran Tilak Kumar 		/*
3925efdd5cfSKaran Tilak Kumar 		 * In case another thread cancelled the request,
3935efdd5cfSKaran Tilak Kumar 		 * refetch the pointer under the lock.
3945efdd5cfSKaran Tilak Kumar 		 */
3955efdd5cfSKaran Tilak Kumar 		nvfnic_release_nvme_ioreq_buf(iport, io_req);
3965efdd5cfSKaran Tilak Kumar 		FNIC_TRACE(nvfnic_queuecommand, fnic->fnic_num,
3975efdd5cfSKaran Tilak Kumar 			   io_req->tag, io_req->fcp_req, 0, 0, 0,
3985efdd5cfSKaran Tilak Kumar 			   (((u64)io_req->cmd_flags << 32) | io_req->cmd_state));
3995efdd5cfSKaran Tilak Kumar 		return ret;
4005efdd5cfSKaran Tilak Kumar 	}
401d25a557dSKaran Tilak Kumar 
402d25a557dSKaran Tilak Kumar 	atomic64_inc(&fnic_stats->io_stats.active_ios);
403d25a557dSKaran Tilak Kumar 	atomic64_inc(&fnic_stats->io_stats.num_ios);
404d25a557dSKaran Tilak Kumar 	if (atomic64_read(&fnic_stats->io_stats.active_ios) >
405d25a557dSKaran Tilak Kumar 	    atomic64_read(&fnic_stats->io_stats.max_active_ios))
406d25a557dSKaran Tilak Kumar 		atomic64_set(&fnic_stats->io_stats.max_active_ios,
407d25a557dSKaran Tilak Kumar 		     atomic64_read(&fnic_stats->io_stats.active_ios));
4085efdd5cfSKaran Tilak Kumar 	io_req->cmd_flags |= FNIC_IO_ISSUED;
4095efdd5cfSKaran Tilak Kumar  out:
4105efdd5cfSKaran Tilak Kumar 	lba = (char *)&cmdiu->sqe.rw.slba;
4115efdd5cfSKaran Tilak Kumar 	cmd_trace = ((u64) cmdiu->sqe.rw.opcode << 56 | (u64) lba[4] << 40 |
4125efdd5cfSKaran Tilak Kumar 		     (u64) lba[5] << 32 | (u64) lba[0] << 24 |
4135efdd5cfSKaran Tilak Kumar 		     (u64) lba[1] << 16 | (u64) lba[2] << 8 | lba[3]);
4145efdd5cfSKaran Tilak Kumar 
4155efdd5cfSKaran Tilak Kumar 	FNIC_TRACE(nvfnic_queuecommand, fnic->fnic_num,
4165efdd5cfSKaran Tilak Kumar 		   io_req->tag, 0, io_req,
4175efdd5cfSKaran Tilak Kumar 		   sg_count, cmd_trace,
4185efdd5cfSKaran Tilak Kumar 		   (((u64)io_req->cmd_flags >> 32) |
4195efdd5cfSKaran Tilak Kumar 		    io_req->cmd_state));
4205efdd5cfSKaran Tilak Kumar 
4215efdd5cfSKaran Tilak Kumar 	return ret;
4225efdd5cfSKaran Tilak Kumar }
4235efdd5cfSKaran Tilak Kumar 
4245efdd5cfSKaran Tilak Kumar int nvfnic_fcpio_send(struct nvme_fc_local_port *lport,
4255efdd5cfSKaran Tilak Kumar 		  struct nvme_fc_remote_port *rport, void *hw_queue_handle,
4265efdd5cfSKaran Tilak Kumar 		  struct nvmefc_fcp_req *fcp_req)
4275efdd5cfSKaran Tilak Kumar {
4285efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = lport->private;
4295efdd5cfSKaran Tilak Kumar 	struct fnic_io_req *io_req;
4305efdd5cfSKaran Tilak Kumar 	int ret;
4315efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
4325efdd5cfSKaran Tilak Kumar 	unsigned long flags = 0;
4335efdd5cfSKaran Tilak Kumar 	struct fnic_tport_s *tport;
434d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
4355efdd5cfSKaran Tilak Kumar 
4365efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, flags);
4375efdd5cfSKaran Tilak Kumar 
4385efdd5cfSKaran Tilak Kumar 	tport = (struct fnic_tport_s *)rport->private;
439d25a557dSKaran Tilak Kumar 	atomic64_inc(&fnic_stats->io_stats.nvme_io_reqs_rcvd);
4405efdd5cfSKaran Tilak Kumar 	if (!nvfnic_transport_ready(iport, tport)) {
441d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->io_stats.nvme_io_rsps_sent);
4425efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
4435efdd5cfSKaran Tilak Kumar 		if (tport != NULL)
4445efdd5cfSKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_INFO, fnic,
4455efdd5cfSKaran Tilak Kumar 				      "iport: 0x%x tport: 0x%x not ready\n",
4465efdd5cfSKaran Tilak Kumar 				      iport->fcid, tport->fcid);
4475efdd5cfSKaran Tilak Kumar 		else
4485efdd5cfSKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_INFO, fnic,
4495efdd5cfSKaran Tilak Kumar 				      "iport: 0x%x tport not ready\n",
4505efdd5cfSKaran Tilak Kumar 				      iport->fcid);
4515efdd5cfSKaran Tilak Kumar 		return -ENODEV;
4525efdd5cfSKaran Tilak Kumar 	}
4535efdd5cfSKaran Tilak Kumar 	atomic_inc(&fnic->in_flight);
4545efdd5cfSKaran Tilak Kumar 
4555efdd5cfSKaran Tilak Kumar 	io_req = (struct fnic_io_req *) fcp_req->private;
4565efdd5cfSKaran Tilak Kumar 	io_req->iport = iport;
4575efdd5cfSKaran Tilak Kumar 	io_req->tport = (struct fnic_tport_s *)rport->private;
4585efdd5cfSKaran Tilak Kumar 	io_req->fcp_req = fcp_req;
4595efdd5cfSKaran Tilak Kumar 	io_req->done = nvfnic_fcpio_cmpl;
4605efdd5cfSKaran Tilak Kumar 	io_req->sgl_list = NULL;
4615efdd5cfSKaran Tilak Kumar 	io_req->sgl_list_alloc = NULL;
4625efdd5cfSKaran Tilak Kumar 	io_req->sgl_list_pa = 0;
4635efdd5cfSKaran Tilak Kumar 	io_req->sgl_cnt = 0;
4645efdd5cfSKaran Tilak Kumar 	io_req->sgl_mapped = 0;
4655efdd5cfSKaran Tilak Kumar 	io_req->wq = hw_queue_handle;
4665efdd5cfSKaran Tilak Kumar 	init_llist_node(&io_req->nvfnic_io_cmpl);
4675efdd5cfSKaran Tilak Kumar 
4685efdd5cfSKaran Tilak Kumar 	io_req->tag = nvfnic_alloc_fcpio_tag(iport, io_req);
4695efdd5cfSKaran Tilak Kumar 	if (io_req->tag == FNIC_NVME_NO_FREE_TAG) {
4705efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
4715efdd5cfSKaran Tilak Kumar 			    "No free tag available. Failing IO\n");
472d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->io_stats.alloc_failures);
4735efdd5cfSKaran Tilak Kumar 		atomic_dec(&fnic->in_flight);
474d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->io_stats.nvme_io_rsps_sent);
4755efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
4765efdd5cfSKaran Tilak Kumar 		return -EBUSY;
4775efdd5cfSKaran Tilak Kumar 	}
4785efdd5cfSKaran Tilak Kumar 
4795efdd5cfSKaran Tilak Kumar 	ret = nvfnic_queuecommand(io_req);
4805efdd5cfSKaran Tilak Kumar 	if (ret) {
4815efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
4825efdd5cfSKaran Tilak Kumar 			      "Queuecommand failed tag: 0x%x\n",
4835efdd5cfSKaran Tilak Kumar 			      io_req->tag);
4845efdd5cfSKaran Tilak Kumar 		nvfnic_free_fcpio_tag(iport, io_req);
4855efdd5cfSKaran Tilak Kumar 	}
4865efdd5cfSKaran Tilak Kumar 
4875efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
4885efdd5cfSKaran Tilak Kumar 	atomic_dec(&fnic->in_flight);
4895efdd5cfSKaran Tilak Kumar 	return ret;
4905efdd5cfSKaran Tilak Kumar }
4915efdd5cfSKaran Tilak Kumar 
4925efdd5cfSKaran Tilak Kumar void nvfnic_fcpio_nvme_fast_cmpl_handler(struct fnic *fnic,
4935efdd5cfSKaran Tilak Kumar 				       struct fcpio_fw_req *desc)
4945efdd5cfSKaran Tilak Kumar {
4955efdd5cfSKaran Tilak Kumar 	u8 type;
4965efdd5cfSKaran Tilak Kumar 	u8 hdr_status;
4975efdd5cfSKaran Tilak Kumar 	struct fcpio_tag ftag;
4985efdd5cfSKaran Tilak Kumar 	u32 id;
4995efdd5cfSKaran Tilak Kumar 	struct fnic_io_req *io_req;
500d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
5015efdd5cfSKaran Tilak Kumar 	unsigned long start_time;
5025efdd5cfSKaran Tilak Kumar 	u64 cmd_trace;
5035efdd5cfSKaran Tilak Kumar 	char *lba;
5045efdd5cfSKaran Tilak Kumar 	struct nvme_fc_cmd_iu *cmdiu;
5055efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport;
5065efdd5cfSKaran Tilak Kumar 	unsigned int tag;
5075efdd5cfSKaran Tilak Kumar 
5085efdd5cfSKaran Tilak Kumar 	/* Decode the cmpl description to get the io_req id */
5095efdd5cfSKaran Tilak Kumar 	fcpio_header_dec(&desc->hdr, &type, &hdr_status, &ftag);
5105efdd5cfSKaran Tilak Kumar 	fcpio_tag_id_dec(&ftag, &id);
5115efdd5cfSKaran Tilak Kumar 	tag = id & FNIC_TAG_MASK;
5125efdd5cfSKaran Tilak Kumar 
5135efdd5cfSKaran Tilak Kumar 	if (tag >= fnic->fnic_max_tag_id) {
5145efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
5155efdd5cfSKaran Tilak Kumar 			    "Tag out of range tag: 0x%x hdr status: %s\n", tag,
5165efdd5cfSKaran Tilak Kumar 			    fnic_fcpio_status_to_str(hdr_status));
5175efdd5cfSKaran Tilak Kumar 		return;
5185efdd5cfSKaran Tilak Kumar 	}
5195efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
5205efdd5cfSKaran Tilak Kumar 
5215efdd5cfSKaran Tilak Kumar 	io_req = nvfnic_find_io_req_by_tag(fnic, tag);
5225efdd5cfSKaran Tilak Kumar 
5235efdd5cfSKaran Tilak Kumar 	WARN_ON_ONCE(!io_req);
5245efdd5cfSKaran Tilak Kumar 	if (!io_req) {
525d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->io_stats.ioreq_null);
5265efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
5275efdd5cfSKaran Tilak Kumar 			      "IO req null hdr: %s tag: 0x%x desc: 0x%p\n",
5285efdd5cfSKaran Tilak Kumar 			      fnic_fcpio_status_to_str(hdr_status), id, desc);
5295efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
5305efdd5cfSKaran Tilak Kumar 			    "type: 0x%x status: 0x%x rsvd: 0x%x tag: 0x%x\n",
5315efdd5cfSKaran Tilak Kumar 			    desc->hdr.type, desc->hdr.status, desc->hdr._resvd,
5325efdd5cfSKaran Tilak Kumar 			    id);
5335efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
5345efdd5cfSKaran Tilak Kumar 		return;
5355efdd5cfSKaran Tilak Kumar 	}
5365efdd5cfSKaran Tilak Kumar 
5375efdd5cfSKaran Tilak Kumar 	cmdiu = io_req->fcp_req->cmdaddr;
5385efdd5cfSKaran Tilak Kumar 	if (io_req->tag != tag) {
5395efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
5405efdd5cfSKaran Tilak Kumar 			      "Tag mismatch tag:%d io:0x%x id:0x%x csn:%08x\n",
5415efdd5cfSKaran Tilak Kumar 			      tag, io_req->tag, id, be32_to_cpu(cmdiu->csn));
5425efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
5435efdd5cfSKaran Tilak Kumar 		return;
5445efdd5cfSKaran Tilak Kumar 	}
5455efdd5cfSKaran Tilak Kumar 	iport = io_req->iport;
5465efdd5cfSKaran Tilak Kumar 
5475efdd5cfSKaran Tilak Kumar 	start_time = io_req->start_time;
5485efdd5cfSKaran Tilak Kumar 
5495efdd5cfSKaran Tilak Kumar 	/* firmware completed the io */
5505efdd5cfSKaran Tilak Kumar 	io_req->io_completed = 1;
5515efdd5cfSKaran Tilak Kumar 	if (io_req->cmd_state == FNIC_IOREQ_ABTS_PENDING) {
5525efdd5cfSKaran Tilak Kumar 		/*
5535efdd5cfSKaran Tilak Kumar 		 * set the FNIC_IO_DONE so that this doesn't get
5545efdd5cfSKaran Tilak Kumar 		 * flagged as 'out of order' if it was not aborted
5555efdd5cfSKaran Tilak Kumar 		 */
5565efdd5cfSKaran Tilak Kumar 		io_req->cmd_flags |= FNIC_IO_DONE;
5575efdd5cfSKaran Tilak Kumar 		io_req->cmd_flags |= FNIC_IO_ABTS_PENDING;
5585efdd5cfSKaran Tilak Kumar 		if (hdr_status == FCPIO_ABORTED)
5595efdd5cfSKaran Tilak Kumar 			io_req->cmd_flags |= FNIC_IO_ABORTED;
5605efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
5615efdd5cfSKaran Tilak Kumar 
5625efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
5635efdd5cfSKaran Tilak Kumar 			      "icmnd abts hdr:%d %s tag:0x%x io:%p",
5645efdd5cfSKaran Tilak Kumar 			      hdr_status, fnic_fcpio_status_to_str(hdr_status),
5655efdd5cfSKaran Tilak Kumar 			      id, io_req);
5665efdd5cfSKaran Tilak Kumar 		return;
5675efdd5cfSKaran Tilak Kumar 	}
5685efdd5cfSKaran Tilak Kumar 
5695efdd5cfSKaran Tilak Kumar 	if (io_req->cmd_state != FNIC_IOREQ_CMD_PENDING) {
5705efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
5715efdd5cfSKaran Tilak Kumar 			      "IO freed id:%d tag:0x%x st:0x%x csn:%08x\n",
5725efdd5cfSKaran Tilak Kumar 			      id, io_req->tag, io_req->cmd_state,
5735efdd5cfSKaran Tilak Kumar 			      be32_to_cpu(cmdiu->csn));
5745efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
5755efdd5cfSKaran Tilak Kumar 		return;
5765efdd5cfSKaran Tilak Kumar 	}
5775efdd5cfSKaran Tilak Kumar 
5785efdd5cfSKaran Tilak Kumar 	/* Mark the IO as complete */
5795efdd5cfSKaran Tilak Kumar 	io_req->cmd_state = FNIC_IOREQ_CMD_COMPLETE;
5805efdd5cfSKaran Tilak Kumar 	switch (hdr_status) {
5815efdd5cfSKaran Tilak Kumar 	case FCPIO_SUCCESS:
5825efdd5cfSKaran Tilak Kumar 		io_req->fcp_req->status = 0;
5835efdd5cfSKaran Tilak Kumar 		io_req->fcp_req->transferred_length =
5845efdd5cfSKaran Tilak Kumar 		    io_req->fcp_req->payload_length;
5855efdd5cfSKaran Tilak Kumar 		io_req->fcp_req->rcv_rsplen = 12;
5865efdd5cfSKaran Tilak Kumar 		break;
5875efdd5cfSKaran Tilak Kumar 	default:
5885efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic, "HDR status is non-zero\n");
5895efdd5cfSKaran Tilak Kumar 		io_req->fcp_req->status = NVME_SC_INTERNAL;
5905efdd5cfSKaran Tilak Kumar 		break;
5915efdd5cfSKaran Tilak Kumar 	}
5925efdd5cfSKaran Tilak Kumar 
5935efdd5cfSKaran Tilak Kumar 	if (hdr_status != FCPIO_SUCCESS) {
594d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->io_stats.io_failures);
5955efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic, "hdr status: %s\n",
5965efdd5cfSKaran Tilak Kumar 			    fnic_fcpio_status_to_str(hdr_status));
5975efdd5cfSKaran Tilak Kumar 	}
5985efdd5cfSKaran Tilak Kumar 
5995efdd5cfSKaran Tilak Kumar 	io_req->cmd_flags |= FNIC_IO_DONE;
6005efdd5cfSKaran Tilak Kumar 
6015efdd5cfSKaran Tilak Kumar 	cmdiu = io_req->fcp_req->cmdaddr;
6025efdd5cfSKaran Tilak Kumar 	lba = (char *)&cmdiu->sqe.rw.slba;
6035efdd5cfSKaran Tilak Kumar 	cmd_trace = ((u64) hdr_status << 56) |
6045efdd5cfSKaran Tilak Kumar 	    (u64) cmdiu->sqe.rw.opcode << 32 |
6055efdd5cfSKaran Tilak Kumar 	    (u64) lba[0] << 24 | (u64) lba[1] << 16 |
6065efdd5cfSKaran Tilak Kumar 	    (u64) lba[2] << 8 | lba[3];
6075efdd5cfSKaran Tilak Kumar 
6085efdd5cfSKaran Tilak Kumar 	FNIC_TRACE(nvfnic_fcpio_nvme_fast_cmpl_handler, fnic->fnic_num,
6095efdd5cfSKaran Tilak Kumar 			tag, io_req,
6105efdd5cfSKaran Tilak Kumar 		   jiffies_to_msecs(jiffies - start_time),
6115efdd5cfSKaran Tilak Kumar 		   desc, cmd_trace,
6125efdd5cfSKaran Tilak Kumar 		   (((u64) io_req->cmd_flags << 32) |
6135efdd5cfSKaran Tilak Kumar 		    io_req->cmd_state));
6145efdd5cfSKaran Tilak Kumar 
615d25a557dSKaran Tilak Kumar 	nvfnic_update_io_stats(fnic, cmdiu->sqe.rw.opcode);
6165efdd5cfSKaran Tilak Kumar 	nvfnic_update_io_bytes(fnic, io_req, cmdiu->sqe.rw.opcode);
617d25a557dSKaran Tilak Kumar 	nvfnic_update_cmpl_stats(fnic, io_req);
6185efdd5cfSKaran Tilak Kumar 
6195efdd5cfSKaran Tilak Kumar 	nvfnic_release_nvme_ioreq_buf(iport, io_req);
6205efdd5cfSKaran Tilak Kumar 	if (io_req->done)
6215efdd5cfSKaran Tilak Kumar 		io_req->done(io_req);
6225efdd5cfSKaran Tilak Kumar 
6235efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
6245efdd5cfSKaran Tilak Kumar }
6255efdd5cfSKaran Tilak Kumar 
6265efdd5cfSKaran Tilak Kumar void nvfnic_fcpio_ersp_cmpl_handler(struct fnic *fnic,
6275efdd5cfSKaran Tilak Kumar 				  struct fcpio_fw_req *desc, int sw_flag)
6285efdd5cfSKaran Tilak Kumar {
6295efdd5cfSKaran Tilak Kumar 	u8 type;
6305efdd5cfSKaran Tilak Kumar 	u8 hdr_status;
6315efdd5cfSKaran Tilak Kumar 	struct fcpio_tag ftag;
6325efdd5cfSKaran Tilak Kumar 	u32 id;
6335efdd5cfSKaran Tilak Kumar 	struct fcpio_nvme_cmpl *nvme_cmpl;
6345efdd5cfSKaran Tilak Kumar 	struct fnic_io_req *io_req;
635d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
6365efdd5cfSKaran Tilak Kumar 	unsigned long start_time;
6375efdd5cfSKaran Tilak Kumar 	uint32_t rsplen;
6385efdd5cfSKaran Tilak Kumar 	struct nvme_fc_ersp_iu *ersp;
6395efdd5cfSKaran Tilak Kumar 	struct nvme_fc_ersp_iu *nrsp;
6405efdd5cfSKaran Tilak Kumar 	struct nvme_fc_cmd_iu *cmdiu;
6415efdd5cfSKaran Tilak Kumar 	struct nvme_command *sqe;
6425efdd5cfSKaran Tilak Kumar 	struct nvme_completion *cqe;
6435efdd5cfSKaran Tilak Kumar 	u64 cmd_trace;
6445efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport;
6455efdd5cfSKaran Tilak Kumar 	unsigned int tag;
6465efdd5cfSKaran Tilak Kumar 	char *lba;
6475efdd5cfSKaran Tilak Kumar 	uint64_t tport_wwpn = 0;
6485efdd5cfSKaran Tilak Kumar 
6495efdd5cfSKaran Tilak Kumar 	/* Decode the cmpl description to get the io_req id */
6505efdd5cfSKaran Tilak Kumar 	fcpio_header_dec(&desc->hdr, &type, &hdr_status, &ftag);
6515efdd5cfSKaran Tilak Kumar 	fcpio_tag_id_dec(&ftag, &id);
6525efdd5cfSKaran Tilak Kumar 	nvme_cmpl = &desc->u.nvme_cmpl;
6535efdd5cfSKaran Tilak Kumar 	ersp = (struct nvme_fc_ersp_iu *) nvme_cmpl->resp_bytes;
6545efdd5cfSKaran Tilak Kumar 	tag = id & FNIC_TAG_MASK;
6555efdd5cfSKaran Tilak Kumar 
6565efdd5cfSKaran Tilak Kumar 	if (tag >= fnic->fnic_max_tag_id) {
6575efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
6585efdd5cfSKaran Tilak Kumar 			      "Tag out of range tag:0x%x hdr:%s\n", tag,
6595efdd5cfSKaran Tilak Kumar 			      fnic_fcpio_status_to_str(hdr_status));
6605efdd5cfSKaran Tilak Kumar 		return;
6615efdd5cfSKaran Tilak Kumar 	}
6625efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
6635efdd5cfSKaran Tilak Kumar 
6645efdd5cfSKaran Tilak Kumar 	io_req = nvfnic_find_io_req_by_tag(fnic, tag);
6655efdd5cfSKaran Tilak Kumar 	if (!io_req) {
666d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->io_stats.ioreq_null);
6675efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
6685efdd5cfSKaran Tilak Kumar 			    "IOREQ is null hdr status: %s tag: 0x%x desc: %p\n",
6695efdd5cfSKaran Tilak Kumar 			    fnic_fcpio_status_to_str(hdr_status), tag, desc);
6705efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
6715efdd5cfSKaran Tilak Kumar 			    "type: 0x%x status: 0x%x rsvd: 0x%x\n",
6725efdd5cfSKaran Tilak Kumar 			    desc->hdr.type, desc->hdr.status, desc->hdr._resvd);
6735efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
6745efdd5cfSKaran Tilak Kumar 		return;
6755efdd5cfSKaran Tilak Kumar 	}
6765efdd5cfSKaran Tilak Kumar 	iport = io_req->iport;
6775efdd5cfSKaran Tilak Kumar 	if (io_req->tport != NULL)
6785efdd5cfSKaran Tilak Kumar 		tport_wwpn = io_req->tport->wwpn;
6795efdd5cfSKaran Tilak Kumar 	cmdiu = io_req->fcp_req->cmdaddr;
6805efdd5cfSKaran Tilak Kumar 
6815efdd5cfSKaran Tilak Kumar 	if (io_req->tag != tag) {
6825efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
6835efdd5cfSKaran Tilak Kumar 			      "Tag mismatch io:0x%x tag:0x%x id:0x%x\n",
6845efdd5cfSKaran Tilak Kumar 			      io_req->tag, tag, id);
6855efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
6865efdd5cfSKaran Tilak Kumar 		return;
6875efdd5cfSKaran Tilak Kumar 	}
6885efdd5cfSKaran Tilak Kumar 
6895efdd5cfSKaran Tilak Kumar 	nrsp = (struct nvme_fc_ersp_iu *)io_req->fcp_req->rspaddr;
6905efdd5cfSKaran Tilak Kumar 	cmdiu = (struct nvme_fc_cmd_iu *)io_req->fcp_req->cmdaddr;
6915efdd5cfSKaran Tilak Kumar 	sqe = &cmdiu->sqe;
6925efdd5cfSKaran Tilak Kumar 	cqe = &nrsp->cqe;
6935efdd5cfSKaran Tilak Kumar 	start_time = io_req->start_time;
6945efdd5cfSKaran Tilak Kumar 
6955efdd5cfSKaran Tilak Kumar 	/* firmware completed the io */
6965efdd5cfSKaran Tilak Kumar 	io_req->io_completed = 1;
6975efdd5cfSKaran Tilak Kumar 
6985efdd5cfSKaran Tilak Kumar 	if (io_req->cmd_state == FNIC_IOREQ_ABTS_PENDING) {
6995efdd5cfSKaran Tilak Kumar 		/*
7005efdd5cfSKaran Tilak Kumar 		 * set the FNIC_IO_DONE so that this doesn't get
7015efdd5cfSKaran Tilak Kumar 		 * flagged as 'out of order' if it was not aborted
7025efdd5cfSKaran Tilak Kumar 		 */
7035efdd5cfSKaran Tilak Kumar 		io_req->cmd_flags |= FNIC_IO_DONE;
7045efdd5cfSKaran Tilak Kumar 		io_req->cmd_flags |= FNIC_IO_ABTS_PENDING;
7055efdd5cfSKaran Tilak Kumar 		if (hdr_status == FCPIO_ABORTED)
7065efdd5cfSKaran Tilak Kumar 			io_req->cmd_flags |= FNIC_IO_ABORTED;
7075efdd5cfSKaran Tilak Kumar 
7085efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
7095efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
7105efdd5cfSKaran Tilak Kumar 			      "ABTS pending hdr status: %s tag: 0x%x",
7115efdd5cfSKaran Tilak Kumar 			      fnic_fcpio_status_to_str(hdr_status), tag);
7125efdd5cfSKaran Tilak Kumar 		return;
7135efdd5cfSKaran Tilak Kumar 	}
7145efdd5cfSKaran Tilak Kumar 
7155efdd5cfSKaran Tilak Kumar 	if (io_req->cmd_state != FNIC_IOREQ_CMD_PENDING) {
7165efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
7175efdd5cfSKaran Tilak Kumar 			      "IO already freed by abort. tag: 0x%x id: 0x%x\n",
7185efdd5cfSKaran Tilak Kumar 			      io_req->tag, id);
7195efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
7205efdd5cfSKaran Tilak Kumar 		return;
7215efdd5cfSKaran Tilak Kumar 	}
7225efdd5cfSKaran Tilak Kumar 
7235efdd5cfSKaran Tilak Kumar 	/* Mark the IO as complete */
7245efdd5cfSKaran Tilak Kumar 	io_req->cmd_state = FNIC_IOREQ_CMD_COMPLETE;
7255efdd5cfSKaran Tilak Kumar 
7265efdd5cfSKaran Tilak Kumar 	switch (hdr_status) {
7275efdd5cfSKaran Tilak Kumar 	case FCPIO_SUCCESS:
7285efdd5cfSKaran Tilak Kumar 		io_req->fcp_req->status = 0;
7295efdd5cfSKaran Tilak Kumar 		if (!sw_flag) {
7305efdd5cfSKaran Tilak Kumar 			io_req->fcp_req->transferred_length =
7315efdd5cfSKaran Tilak Kumar 			    io_req->fcp_req->payload_length;
7325efdd5cfSKaran Tilak Kumar 			rsplen = 32;
7335efdd5cfSKaran Tilak Kumar 			nrsp->iu_len =
7345efdd5cfSKaran Tilak Kumar 			    cpu_to_be16(sizeof(struct nvme_fc_ersp_iu) / 4);
7355efdd5cfSKaran Tilak Kumar 			nrsp->xfrd_len =
7365efdd5cfSKaran Tilak Kumar 			    cpu_to_be32(io_req->fcp_req->payload_length);
7375efdd5cfSKaran Tilak Kumar 
7385efdd5cfSKaran Tilak Kumar 			nrsp->ersp_result = 0;
7395efdd5cfSKaran Tilak Kumar 			cqe->command_id = sqe->common.command_id;
7405efdd5cfSKaran Tilak Kumar 			cqe->status = 0;
7415efdd5cfSKaran Tilak Kumar 			cqe->result.u64 = 0;
7425efdd5cfSKaran Tilak Kumar 		} else {
7435efdd5cfSKaran Tilak Kumar 			io_req->fcp_req->transferred_length =
7445efdd5cfSKaran Tilak Kumar 			    be32_to_cpu(ersp->xfrd_len);
7455efdd5cfSKaran Tilak Kumar 			rsplen = be16_to_cpu(ersp->iu_len) * 4;
7465efdd5cfSKaran Tilak Kumar 			if (rsplen > sizeof(nvme_cmpl->resp_bytes) ||
7475efdd5cfSKaran Tilak Kumar 			    rsplen > io_req->fcp_req->rsplen) {
7485efdd5cfSKaran Tilak Kumar 				FNIC_NVME_DBG(KERN_ERR, fnic,
7495efdd5cfSKaran Tilak Kumar 					      "tport wwpn 0x%llx ERSP len %u desc %u req %u\n",
7505efdd5cfSKaran Tilak Kumar 					      tport_wwpn, rsplen,
7515efdd5cfSKaran Tilak Kumar 					      (u32)sizeof(nvme_cmpl->resp_bytes),
7525efdd5cfSKaran Tilak Kumar 					      io_req->fcp_req->rsplen);
7535efdd5cfSKaran Tilak Kumar 				io_req->fcp_req->status = NVME_SC_INTERNAL;
7545efdd5cfSKaran Tilak Kumar 				io_req->fcp_req->rcv_rsplen = 0;
7555efdd5cfSKaran Tilak Kumar 				break;
7565efdd5cfSKaran Tilak Kumar 			}
7575efdd5cfSKaran Tilak Kumar 			memcpy(io_req->fcp_req->rspaddr, ersp, rsplen);
7585efdd5cfSKaran Tilak Kumar 		}
759d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->nvme_stats.nvme_ersps);
7605efdd5cfSKaran Tilak Kumar 		io_req->fcp_req->rcv_rsplen = rsplen;
7615efdd5cfSKaran Tilak Kumar 		break;
7625efdd5cfSKaran Tilak Kumar 
7635efdd5cfSKaran Tilak Kumar 	default:
7645efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
7655efdd5cfSKaran Tilak Kumar 				"Unexpected header status: %d\n", hdr_status);
7665efdd5cfSKaran Tilak Kumar 		io_req->fcp_req->status = NVME_SC_INTERNAL;
7675efdd5cfSKaran Tilak Kumar 		break;
7685efdd5cfSKaran Tilak Kumar 	}
7695efdd5cfSKaran Tilak Kumar 
7705efdd5cfSKaran Tilak Kumar 	if (hdr_status != FCPIO_SUCCESS) {
771d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->io_stats.io_failures);
7725efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic, "hdr status: %s tag: 0x%x\n",
7735efdd5cfSKaran Tilak Kumar 			    fnic_fcpio_status_to_str(hdr_status), tag);
7745efdd5cfSKaran Tilak Kumar 	}
7755efdd5cfSKaran Tilak Kumar 
7765efdd5cfSKaran Tilak Kumar 	io_req->cmd_flags |= FNIC_IO_DONE;
7775efdd5cfSKaran Tilak Kumar 
7785efdd5cfSKaran Tilak Kumar 	lba = (char *) &cmdiu->sqe.rw.slba;
7795efdd5cfSKaran Tilak Kumar 	cmd_trace = ((u64) hdr_status << 56) |
7805efdd5cfSKaran Tilak Kumar 	    (u64) ersp->ersp_result << 48 |
7815efdd5cfSKaran Tilak Kumar 	    (u64) cmdiu->sqe.rw.opcode << 32 |
7825efdd5cfSKaran Tilak Kumar 	    (u64) lba[0] << 24 | (u64) lba[1] << 16 |
7835efdd5cfSKaran Tilak Kumar 	    (u64) lba[2] << 8 | lba[3];
7845efdd5cfSKaran Tilak Kumar 
7855efdd5cfSKaran Tilak Kumar 	FNIC_TRACE(nvfnic_fcpio_ersp_cmpl_handler, fnic->fnic_num,
7865efdd5cfSKaran Tilak Kumar 		   tag, io_req,
7875efdd5cfSKaran Tilak Kumar 		   ((u64) nvme_cmpl->resvd[1] << 56 |
7885efdd5cfSKaran Tilak Kumar 		    (u64) nvme_cmpl->resvd[0] << 48 |
7895efdd5cfSKaran Tilak Kumar 		    jiffies_to_msecs(jiffies - start_time)),
7905efdd5cfSKaran Tilak Kumar 		   desc, cmd_trace,
7915efdd5cfSKaran Tilak Kumar 		   (((u64) io_req->cmd_flags << 32) |
7925efdd5cfSKaran Tilak Kumar 		    io_req->cmd_state));
7935efdd5cfSKaran Tilak Kumar 
794d25a557dSKaran Tilak Kumar 	nvfnic_update_io_stats(fnic, cmdiu->sqe.rw.opcode);
7955efdd5cfSKaran Tilak Kumar 	nvfnic_update_io_bytes(fnic, io_req, cmdiu->sqe.rw.opcode);
796d25a557dSKaran Tilak Kumar 	nvfnic_update_cmpl_stats(fnic, io_req);
7975efdd5cfSKaran Tilak Kumar 
7985efdd5cfSKaran Tilak Kumar 	nvfnic_release_nvme_ioreq_buf(iport, io_req);
7995efdd5cfSKaran Tilak Kumar 
8005efdd5cfSKaran Tilak Kumar 	/* Call NVME completion function to complete the IO */
8015efdd5cfSKaran Tilak Kumar 	if (io_req->done)
8025efdd5cfSKaran Tilak Kumar 		io_req->done(io_req);
8035efdd5cfSKaran Tilak Kumar 
8045efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
8055efdd5cfSKaran Tilak Kumar }
8065efdd5cfSKaran Tilak Kumar 
8075efdd5cfSKaran Tilak Kumar void nvfnic_fcpio_nvme_itmf_cmpl_handler(struct fnic *fnic,
8085efdd5cfSKaran Tilak Kumar 				       struct fcpio_fw_req *desc)
8095efdd5cfSKaran Tilak Kumar {
8105efdd5cfSKaran Tilak Kumar 	u8 type;
8115efdd5cfSKaran Tilak Kumar 	u8 hdr_status;
8125efdd5cfSKaran Tilak Kumar 	struct fcpio_tag ftag;
8135efdd5cfSKaran Tilak Kumar 	u32 id;
8145efdd5cfSKaran Tilak Kumar 	unsigned int tag;
8155efdd5cfSKaran Tilak Kumar 	struct fnic_io_req *io_req;
8165efdd5cfSKaran Tilak Kumar 	struct nvme_fc_cmd_iu *cmd_iu;
817d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
818d25a557dSKaran Tilak Kumar 	struct abort_stats *abts_stats = &fnic->fnic_stats.abts_stats;
819d25a557dSKaran Tilak Kumar 	struct terminate_stats *term_stats = &fnic->fnic_stats.term_stats;
820d25a557dSKaran Tilak Kumar 	struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats;
8215efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport;
8225efdd5cfSKaran Tilak Kumar 
8235efdd5cfSKaran Tilak Kumar 	fcpio_header_dec(&desc->hdr, &type, &hdr_status, &ftag);
8245efdd5cfSKaran Tilak Kumar 	fcpio_tag_id_dec(&ftag, &id);
8255efdd5cfSKaran Tilak Kumar 	tag = id & FNIC_TAG_MASK;
8265efdd5cfSKaran Tilak Kumar 
8275efdd5cfSKaran Tilak Kumar 	if (tag >= fnic->fnic_max_tag_id) {
8285efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
8295efdd5cfSKaran Tilak Kumar 			      "Tag out of range id:0x%x tag:0x%x hdr:%s\n",
8305efdd5cfSKaran Tilak Kumar 			      id, tag, fnic_fcpio_status_to_str(hdr_status));
8315efdd5cfSKaran Tilak Kumar 		return;
8325efdd5cfSKaran Tilak Kumar 	}
8335efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
8345efdd5cfSKaran Tilak Kumar 
8355efdd5cfSKaran Tilak Kumar 	io_req = nvfnic_find_io_req_by_tag(fnic, tag);
8365efdd5cfSKaran Tilak Kumar 	WARN_ON_ONCE(!io_req);
8375efdd5cfSKaran Tilak Kumar 	if (!io_req) {
838d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->io_stats.ioreq_null);
8395efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
8405efdd5cfSKaran Tilak Kumar 			      "IOREQ null hdr:%s tag:0x%x desc:%p\n",
8415efdd5cfSKaran Tilak Kumar 			      fnic_fcpio_status_to_str(hdr_status), tag, desc);
8425efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
8435efdd5cfSKaran Tilak Kumar 			      "type: 0x%x status: 0x%x rsvd: 0x%x\n",
8445efdd5cfSKaran Tilak Kumar 			      desc->hdr.type, desc->hdr.status, desc->hdr._resvd);
8455efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
8465efdd5cfSKaran Tilak Kumar 		return;
8475efdd5cfSKaran Tilak Kumar 	}
8485efdd5cfSKaran Tilak Kumar 
8495efdd5cfSKaran Tilak Kumar 	cmd_iu = io_req->fcp_req->cmdaddr;
8505efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic,
8515efdd5cfSKaran Tilak Kumar 	      "Received ITMF completion tag: 0x%x hdr_status: %d csn: 0x%08x\n",
8525efdd5cfSKaran Tilak Kumar 	      tag, hdr_status, be32_to_cpu(cmd_iu->csn));
8535efdd5cfSKaran Tilak Kumar 
8545efdd5cfSKaran Tilak Kumar 	iport = io_req->iport;
8555efdd5cfSKaran Tilak Kumar 
8565efdd5cfSKaran Tilak Kumar 	/* Completion of abort cmd */
8575efdd5cfSKaran Tilak Kumar 	switch (hdr_status) {
8585efdd5cfSKaran Tilak Kumar 	case FCPIO_SUCCESS:
8595efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_DEBUG, fnic,
8605efdd5cfSKaran Tilak Kumar 				"Abort success received tag: 0x%x id: 0x%x\n",
8615efdd5cfSKaran Tilak Kumar 			      tag, id);
8625efdd5cfSKaran Tilak Kumar 		break;
8635efdd5cfSKaran Tilak Kumar 	case FCPIO_TIMEOUT:
8645efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
8655efdd5cfSKaran Tilak Kumar 				"Abort timeout received tag: 0x%x id: 0x%x\n",
8665efdd5cfSKaran Tilak Kumar 			      tag, id);
867d25a557dSKaran Tilak Kumar 		if (io_req->cmd_flags & FNIC_IO_ABTS_ISSUED)
868d25a557dSKaran Tilak Kumar 			atomic64_inc(&abts_stats->abort_fw_timeouts);
869d25a557dSKaran Tilak Kumar 		else
870d25a557dSKaran Tilak Kumar 			atomic64_inc(&term_stats->terminate_fw_timeouts);
8715efdd5cfSKaran Tilak Kumar 		break;
8725efdd5cfSKaran Tilak Kumar 	case FCPIO_ITMF_REJECTED:
8735efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
8745efdd5cfSKaran Tilak Kumar 				"Abort reject received tag: 0x%x id: 0x%x\n",
8755efdd5cfSKaran Tilak Kumar 			      tag, id);
8765efdd5cfSKaran Tilak Kumar 		break;
8775efdd5cfSKaran Tilak Kumar 
8785efdd5cfSKaran Tilak Kumar 	case FCPIO_IO_NOT_FOUND:
8795efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
8805efdd5cfSKaran Tilak Kumar 			      "Abort IO not found tag:0x%x id:0x%x\n",
8815efdd5cfSKaran Tilak Kumar 			      tag, id);
882d25a557dSKaran Tilak Kumar 		if (io_req->cmd_flags & FNIC_IO_ABTS_ISSUED)
883d25a557dSKaran Tilak Kumar 			atomic64_inc(&abts_stats->abort_io_not_found);
884d25a557dSKaran Tilak Kumar 		else
885d25a557dSKaran Tilak Kumar 			atomic64_inc(&term_stats->terminate_io_not_found);
8865efdd5cfSKaran Tilak Kumar 		break;
8875efdd5cfSKaran Tilak Kumar 	default:
8885efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
8895efdd5cfSKaran Tilak Kumar 				"Abort unknown received tag: 0x%x id: 0x%x\n",
8905efdd5cfSKaran Tilak Kumar 			    tag, id);
891d25a557dSKaran Tilak Kumar 		if (io_req->cmd_flags & FNIC_IO_ABTS_ISSUED)
892d25a557dSKaran Tilak Kumar 			atomic64_inc(&abts_stats->abort_failures);
893d25a557dSKaran Tilak Kumar 		else
894d25a557dSKaran Tilak Kumar 			atomic64_inc(&term_stats->terminate_failures);
8955efdd5cfSKaran Tilak Kumar 		break;
8965efdd5cfSKaran Tilak Kumar 	}
8975efdd5cfSKaran Tilak Kumar 
8985efdd5cfSKaran Tilak Kumar 	if (io_req->cmd_state != FNIC_IOREQ_ABTS_PENDING) {
8995efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
9005efdd5cfSKaran Tilak Kumar 			      "Abort late completion tag:0x%x id:0x%x\n",
9015efdd5cfSKaran Tilak Kumar 			      tag, id);
9025efdd5cfSKaran Tilak Kumar 		/* This is a late completion. Ignore it */
9035efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
9045efdd5cfSKaran Tilak Kumar 		return;
9055efdd5cfSKaran Tilak Kumar 	}
9065efdd5cfSKaran Tilak Kumar 
9075efdd5cfSKaran Tilak Kumar 	io_req->abts_state = hdr_status;
9085efdd5cfSKaran Tilak Kumar 
9095efdd5cfSKaran Tilak Kumar 	/* If the status is IO not found consider it as success.
9105efdd5cfSKaran Tilak Kumar 	 * NVME sends abort even if rport is down in which case
9115efdd5cfSKaran Tilak Kumar 	 * we will get FCPIO_TIMEOUT. Consider this as success.
9125efdd5cfSKaran Tilak Kumar 	 */
9135efdd5cfSKaran Tilak Kumar 	if ((hdr_status == FCPIO_IO_NOT_FOUND) ||
9145efdd5cfSKaran Tilak Kumar 	    (hdr_status == FCPIO_TIMEOUT) ||
9155efdd5cfSKaran Tilak Kumar 	    (hdr_status == FCPIO_ITMF_REJECTED))
9165efdd5cfSKaran Tilak Kumar 		io_req->abts_state = FCPIO_SUCCESS;
9175efdd5cfSKaran Tilak Kumar 
9185efdd5cfSKaran Tilak Kumar 	io_req->cmd_flags |= FNIC_IO_ABT_TERM_DONE;
9195efdd5cfSKaran Tilak Kumar 
920d25a557dSKaran Tilak Kumar 	if (!(io_req->cmd_flags & (FNIC_IO_ABORTED | FNIC_IO_DONE)))
921d25a557dSKaran Tilak Kumar 		atomic64_inc(&misc_stats->no_icmnd_itmf_cmpls);
9225efdd5cfSKaran Tilak Kumar 
9235efdd5cfSKaran Tilak Kumar 	io_req->fcp_req->transferred_length = 0;
9245efdd5cfSKaran Tilak Kumar 	io_req->fcp_req->rcv_rsplen = 0;
9255efdd5cfSKaran Tilak Kumar 	if (io_req->abts_state == FCPIO_SUCCESS)
9265efdd5cfSKaran Tilak Kumar 		io_req->fcp_req->status = NVME_SC_ABORT_REQ;
9275efdd5cfSKaran Tilak Kumar 	else
9285efdd5cfSKaran Tilak Kumar 		io_req->fcp_req->status = NVME_SC_INTERNAL;
9295efdd5cfSKaran Tilak Kumar 
930d25a557dSKaran Tilak Kumar 	atomic64_dec(&fnic_stats->io_stats.active_ios);
931d25a557dSKaran Tilak Kumar 	if (atomic64_read(&fnic->io_cmpl_skip))
932d25a557dSKaran Tilak Kumar 		atomic64_dec(&fnic->io_cmpl_skip);
933d25a557dSKaran Tilak Kumar 	else
934d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->io_stats.io_completions);
935d25a557dSKaran Tilak Kumar 
9365efdd5cfSKaran Tilak Kumar 	nvfnic_release_nvme_ioreq_buf(iport, io_req);
9375efdd5cfSKaran Tilak Kumar 	if (io_req->done)
9385efdd5cfSKaran Tilak Kumar 		io_req->done(io_req);
9395efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
9405efdd5cfSKaran Tilak Kumar }
9415efdd5cfSKaran Tilak Kumar 
9425efdd5cfSKaran Tilak Kumar bool _cleanup_tport_io(struct sbitmap *map, unsigned int tag,
9435efdd5cfSKaran Tilak Kumar 			      void *data)
9445efdd5cfSKaran Tilak Kumar {
9455efdd5cfSKaran Tilak Kumar 	struct fnic_tport_s *tport = data;
9465efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = tport->iport;
9475efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
9485efdd5cfSKaran Tilak Kumar 	struct fnic_io_req *io_req;
9495efdd5cfSKaran Tilak Kumar 	enum fnic_ioreq_state old_ioreq_state;
9505efdd5cfSKaran Tilak Kumar 	unsigned long flags;
9515efdd5cfSKaran Tilak Kumar 
9525efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, flags);
9535efdd5cfSKaran Tilak Kumar 	io_req = nvfnic_find_io_req_by_tag(fnic, tag);
9545efdd5cfSKaran Tilak Kumar 	if (!io_req || io_req->tport != tport) {
9555efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
9565efdd5cfSKaran Tilak Kumar 		return true;
9575efdd5cfSKaran Tilak Kumar 	}
9585efdd5cfSKaran Tilak Kumar 
9595efdd5cfSKaran Tilak Kumar 	if ((io_req->cmd_state == FNIC_IOREQ_ABTS_PENDING) ||
9605efdd5cfSKaran Tilak Kumar 	    (io_req->cmd_state == FNIC_DEV_RST_TERM_ISSUED)) {
9615efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
9625efdd5cfSKaran Tilak Kumar 			      "Abort already pending 0x%x\n", io_req->tag);
9635efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
9645efdd5cfSKaran Tilak Kumar 		return true;
9655efdd5cfSKaran Tilak Kumar 	}
9665efdd5cfSKaran Tilak Kumar 
9675efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_ERR, fnic,
9685efdd5cfSKaran Tilak Kumar 		      "io_req tag: 0x%x abort after unregister timeout\n",
9695efdd5cfSKaran Tilak Kumar 		      io_req->tag);
9705efdd5cfSKaran Tilak Kumar 
9715efdd5cfSKaran Tilak Kumar 	old_ioreq_state = io_req->cmd_state;
9725efdd5cfSKaran Tilak Kumar 	io_req->cmd_state = FNIC_IOREQ_ABTS_PENDING;
9735efdd5cfSKaran Tilak Kumar 	io_req->abts_state = FCPIO_INVALID_CODE;
9745efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
9755efdd5cfSKaran Tilak Kumar 
9765efdd5cfSKaran Tilak Kumar 	if (!nvfnic_queue_abort_io_req(fnic, io_req->tag,
9775efdd5cfSKaran Tilak Kumar 				      FCPIO_ITMF_ABT_TASK_TERM,
9785efdd5cfSKaran Tilak Kumar 				      io_req)) {
9795efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
9805efdd5cfSKaran Tilak Kumar 			    "Failed to enqueue abort for ioreq tag: 0x%x\n",
9815efdd5cfSKaran Tilak Kumar 			    io_req->tag);
9825efdd5cfSKaran Tilak Kumar 		spin_lock_irqsave(&fnic->fnic_lock, flags);
9835efdd5cfSKaran Tilak Kumar 		io_req->cmd_state = old_ioreq_state;
9845efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
9855efdd5cfSKaran Tilak Kumar 	}
9865efdd5cfSKaran Tilak Kumar 	return true;
9875efdd5cfSKaran Tilak Kumar }
9885efdd5cfSKaran Tilak Kumar 
9895efdd5cfSKaran Tilak Kumar void
9905efdd5cfSKaran Tilak Kumar nvfnic_cleanup_tport_io(struct fnic *fnic, struct fnic_tport_s *tport)
9915efdd5cfSKaran Tilak Kumar {
9925efdd5cfSKaran Tilak Kumar 	unsigned long flags;
9935efdd5cfSKaran Tilak Kumar 	struct nvfnic_ls_req *nvfnic_ls_req, *next;
9945efdd5cfSKaran Tilak Kumar 	struct nvmefc_ls_req *lsreq;
9955efdd5cfSKaran Tilak Kumar 	uint16_t oxid;
9965efdd5cfSKaran Tilak Kumar 	LIST_HEAD(done_reqs);
9975efdd5cfSKaran Tilak Kumar 
9985efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, flags);
9995efdd5cfSKaran Tilak Kumar 	list_for_each_entry_safe(nvfnic_ls_req, next,
10005efdd5cfSKaran Tilak Kumar 				 &(tport->ls_req_list), list) {
10015efdd5cfSKaran Tilak Kumar 		lsreq = nvfnic_ls_req->ls_req;
10025efdd5cfSKaran Tilak Kumar 		if (!lsreq || (lsreq->private == NULL)) {
10035efdd5cfSKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_INFO, fnic,
10045efdd5cfSKaran Tilak Kumar 				"fnic_cleanup_tport_io lsreq NULL\n");
10055efdd5cfSKaran Tilak Kumar 			continue;
10065efdd5cfSKaran Tilak Kumar 		}
10075efdd5cfSKaran Tilak Kumar 		if (nvfnic_ls_req->state == FNIC_LS_REQ_CMD_ABTS_STARTED) {
10085efdd5cfSKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_INFO, fnic,
10095efdd5cfSKaran Tilak Kumar 				"fnic_cleanup_tport_io lsreq abort started\n");
10105efdd5cfSKaran Tilak Kumar 			continue;
10115efdd5cfSKaran Tilak Kumar 		}
10125efdd5cfSKaran Tilak Kumar 		list_del_init(&nvfnic_ls_req->list);
10135efdd5cfSKaran Tilak Kumar 		lsreq->private = NULL;
10145efdd5cfSKaran Tilak Kumar 		oxid = nvfnic_ls_req->oxid;
10155efdd5cfSKaran Tilak Kumar 		fdls_free_oxid(&fnic->iport, oxid, &nvfnic_ls_req->oxid);
10165efdd5cfSKaran Tilak Kumar 		nvfnic_ls_req->state = FNIC_LS_REQ_CMD_COMPLETE;
10175efdd5cfSKaran Tilak Kumar 		list_add_tail(&nvfnic_ls_req->list, &done_reqs);
10185efdd5cfSKaran Tilak Kumar 	}
10195efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
10205efdd5cfSKaran Tilak Kumar 
10215efdd5cfSKaran Tilak Kumar 	list_for_each_entry_safe(nvfnic_ls_req, next, &done_reqs, list) {
10225efdd5cfSKaran Tilak Kumar 		list_del_init(&nvfnic_ls_req->list);
10235efdd5cfSKaran Tilak Kumar 		lsreq = nvfnic_ls_req->ls_req;
10245efdd5cfSKaran Tilak Kumar 		timer_delete_sync(&nvfnic_ls_req->ls_req_timer);
10255efdd5cfSKaran Tilak Kumar 		lsreq->done(lsreq, -ENXIO);
10265efdd5cfSKaran Tilak Kumar 	}
10275efdd5cfSKaran Tilak Kumar 
10285efdd5cfSKaran Tilak Kumar 	/* For link-down, IOs are freed by firmware reset completion */
10295efdd5cfSKaran Tilak Kumar 	if (fdls_get_state(&fnic->iport.fabric) == FDLS_STATE_LINKDOWN)
10305efdd5cfSKaran Tilak Kumar 		return;
10315efdd5cfSKaran Tilak Kumar 
10325efdd5cfSKaran Tilak Kumar 	sbitmap_for_each_set(&fnic->nvfnic_tag_map, _cleanup_tport_io, tport);
10335efdd5cfSKaran Tilak Kumar }
10345efdd5cfSKaran Tilak Kumar 
10355efdd5cfSKaran Tilak Kumar void
10365efdd5cfSKaran Tilak Kumar nvfnic_terminate_tport_ls_reqs(struct fnic *fnic, struct fnic_tport_s *tport)
10375efdd5cfSKaran Tilak Kumar {
10385efdd5cfSKaran Tilak Kumar 	struct nvmefc_ls_req *lsreq;
10395efdd5cfSKaran Tilak Kumar 	struct nvfnic_ls_req *nvfnic_ls_req, *next;
10405efdd5cfSKaran Tilak Kumar 	int count = 0;
10415efdd5cfSKaran Tilak Kumar 	uint16_t oxid;
10425efdd5cfSKaran Tilak Kumar 	LIST_HEAD(done_reqs);
10435efdd5cfSKaran Tilak Kumar 
10445efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
10455efdd5cfSKaran Tilak Kumar 	list_for_each_entry_safe(nvfnic_ls_req, next,
10465efdd5cfSKaran Tilak Kumar 		&(tport->ls_req_list), list) {
10475efdd5cfSKaran Tilak Kumar 
10485efdd5cfSKaran Tilak Kumar 		lsreq = nvfnic_ls_req->ls_req;
10495efdd5cfSKaran Tilak Kumar 		if (!lsreq || (lsreq->private == NULL)) {
10505efdd5cfSKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_ERR, fnic,
10515efdd5cfSKaran Tilak Kumar 				"lsreq is NULL\n");
10525efdd5cfSKaran Tilak Kumar 			continue;
10535efdd5cfSKaran Tilak Kumar 		}
10545efdd5cfSKaran Tilak Kumar 		if (nvfnic_ls_req->state == FNIC_LS_REQ_CMD_ABTS_STARTED) {
10555efdd5cfSKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_INFO, fnic,
10565efdd5cfSKaran Tilak Kumar 				"lsreq abort started\n");
10575efdd5cfSKaran Tilak Kumar 			continue;
10585efdd5cfSKaran Tilak Kumar 		}
10595efdd5cfSKaran Tilak Kumar 		oxid = nvfnic_ls_req->oxid;
10605efdd5cfSKaran Tilak Kumar 		list_del_init(&nvfnic_ls_req->list);
10615efdd5cfSKaran Tilak Kumar 		lsreq->private = NULL;
10625efdd5cfSKaran Tilak Kumar 		fdls_free_oxid(&fnic->iport, oxid, &nvfnic_ls_req->oxid);
10635efdd5cfSKaran Tilak Kumar 		nvfnic_ls_req->state = FNIC_LS_REQ_CMD_COMPLETE;
10645efdd5cfSKaran Tilak Kumar 		list_add_tail(&nvfnic_ls_req->list, &done_reqs);
10655efdd5cfSKaran Tilak Kumar 	}
10665efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
10675efdd5cfSKaran Tilak Kumar 
10685efdd5cfSKaran Tilak Kumar 	list_for_each_entry_safe(nvfnic_ls_req, next, &done_reqs, list) {
10695efdd5cfSKaran Tilak Kumar 		list_del_init(&nvfnic_ls_req->list);
10705efdd5cfSKaran Tilak Kumar 		lsreq = nvfnic_ls_req->ls_req;
10715efdd5cfSKaran Tilak Kumar 		timer_delete_sync(&nvfnic_ls_req->ls_req_timer);
10725efdd5cfSKaran Tilak Kumar 		lsreq->done(lsreq, -ENXIO);
10735efdd5cfSKaran Tilak Kumar 		count++;
10745efdd5cfSKaran Tilak Kumar 	}
10755efdd5cfSKaran Tilak Kumar 
10765efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic,
10775efdd5cfSKaran Tilak Kumar 		"fnic_terminate_tport_lsreqs tport: 0x%x: freed lsreq: %d\n",
10785efdd5cfSKaran Tilak Kumar 		tport->fcid, count);
10795efdd5cfSKaran Tilak Kumar }
10805efdd5cfSKaran Tilak Kumar 
10815efdd5cfSKaran Tilak Kumar bool _terminate_tport_ios(struct sbitmap *map, unsigned int tag,
10825efdd5cfSKaran Tilak Kumar 				       void *data)
10835efdd5cfSKaran Tilak Kumar {
10845efdd5cfSKaran Tilak Kumar 	struct fnic_tport_s *tport = data;
10855efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = tport->iport;
10865efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
10875efdd5cfSKaran Tilak Kumar 	struct fnic_io_req *io_req;
10885efdd5cfSKaran Tilak Kumar 	enum fnic_ioreq_state old_ioreq_state;
10895efdd5cfSKaran Tilak Kumar 	unsigned long flags;
10905efdd5cfSKaran Tilak Kumar 
10915efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, flags);
10925efdd5cfSKaran Tilak Kumar 	io_req = fnic->sw_copy_wq[0].io_req_table[tag];
10935efdd5cfSKaran Tilak Kumar 	if (!io_req) {
10945efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
10955efdd5cfSKaran Tilak Kumar 		return true;
10965efdd5cfSKaran Tilak Kumar 	}
10975efdd5cfSKaran Tilak Kumar 
10985efdd5cfSKaran Tilak Kumar 	if (io_req->tport != tport) {
10995efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
11005efdd5cfSKaran Tilak Kumar 		return true;
11015efdd5cfSKaran Tilak Kumar 	}
11025efdd5cfSKaran Tilak Kumar 
11035efdd5cfSKaran Tilak Kumar 	if ((io_req->cmd_state == FNIC_IOREQ_ABTS_PENDING) ||
11045efdd5cfSKaran Tilak Kumar 	    (io_req->cmd_state == FNIC_DEV_RST_TERM_ISSUED)) {
11055efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
11065efdd5cfSKaran Tilak Kumar 			      "Abort already pending 0x%x\n", io_req->tag);
11075efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
11085efdd5cfSKaran Tilak Kumar 		return true;
11095efdd5cfSKaran Tilak Kumar 	}
11105efdd5cfSKaran Tilak Kumar 
11115efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic,
11125efdd5cfSKaran Tilak Kumar 		      "Terminate tag: 0x%x (tport fcid 0x%x)\n",
11135efdd5cfSKaran Tilak Kumar 		      io_req->tag, io_req->tport->fcid);
11145efdd5cfSKaran Tilak Kumar 
11155efdd5cfSKaran Tilak Kumar 	old_ioreq_state = io_req->cmd_state;
11165efdd5cfSKaran Tilak Kumar 	io_req->cmd_state = FNIC_IOREQ_ABTS_PENDING;
11175efdd5cfSKaran Tilak Kumar 	io_req->abts_state = FCPIO_INVALID_CODE;
11185efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
11195efdd5cfSKaran Tilak Kumar 
11205efdd5cfSKaran Tilak Kumar 	if (!nvfnic_queue_abort_io_req(fnic, io_req->tag,
11215efdd5cfSKaran Tilak Kumar 					  FCPIO_ITMF_ABT_TASK_TERM, io_req)) {
11225efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
11235efdd5cfSKaran Tilak Kumar 			      "Failed to enqueue abort for ioreq tag: 0x%x\n",
11245efdd5cfSKaran Tilak Kumar 			      io_req->tag);
11255efdd5cfSKaran Tilak Kumar 		spin_lock_irqsave(&fnic->fnic_lock, flags);
11265efdd5cfSKaran Tilak Kumar 		io_req->cmd_state = old_ioreq_state;
11275efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
11285efdd5cfSKaran Tilak Kumar 	}
11295efdd5cfSKaran Tilak Kumar 	return true;
11305efdd5cfSKaran Tilak Kumar }
11315efdd5cfSKaran Tilak Kumar 
11325efdd5cfSKaran Tilak Kumar void nvfnic_terminate_tport_ios(struct fnic *fnic,
11335efdd5cfSKaran Tilak Kumar 				     struct fnic_tport_s *tport)
11345efdd5cfSKaran Tilak Kumar {
1135d25a557dSKaran Tilak Kumar 	struct abort_stats *abts_stats = &fnic->fnic_stats.abts_stats;
11365efdd5cfSKaran Tilak Kumar 
11375efdd5cfSKaran Tilak Kumar 	sbitmap_for_each_set(&fnic->nvfnic_tag_map, _terminate_tport_ios, tport);
11385efdd5cfSKaran Tilak Kumar 
1139d25a557dSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic,
1140d25a557dSKaran Tilak Kumar 		      "tport: 0x%x aborted %lld in_flight %d\n",
1141d25a557dSKaran Tilak Kumar 		      tport->fcid, atomic64_read(&abts_stats->aborts),
1142d25a557dSKaran Tilak Kumar 		      atomic_read(&fnic->in_flight));
11435efdd5cfSKaran Tilak Kumar }
11445efdd5cfSKaran Tilak Kumar 
11455efdd5cfSKaran Tilak Kumar bool _cleanup_all_nvme_io(struct sbitmap *map, unsigned int tag,
11465efdd5cfSKaran Tilak Kumar 				 void *data)
11475efdd5cfSKaran Tilak Kumar {
11485efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = data;
11495efdd5cfSKaran Tilak Kumar 	struct fnic_io_req *io_req;
11505efdd5cfSKaran Tilak Kumar 
11515efdd5cfSKaran Tilak Kumar 	io_req = iport->fnic->sw_copy_wq[0].io_req_table[tag];
11525efdd5cfSKaran Tilak Kumar 	if (!io_req)
11535efdd5cfSKaran Tilak Kumar 		return true;
11545efdd5cfSKaran Tilak Kumar 
11555efdd5cfSKaran Tilak Kumar 	io_req->cmd_state = FNIC_DEV_RST_TERM_ISSUED;
11565efdd5cfSKaran Tilak Kumar 	io_req->fcp_req->status = NVME_SC_INTERNAL;
11575efdd5cfSKaran Tilak Kumar 	io_req->fcp_req->transferred_length = 0;
11585efdd5cfSKaran Tilak Kumar 	io_req->fcp_req->rcv_rsplen = 0;
11595efdd5cfSKaran Tilak Kumar 	nvfnic_release_nvme_ioreq_buf(iport, io_req);
11605efdd5cfSKaran Tilak Kumar 	io_req->done(io_req);
11615efdd5cfSKaran Tilak Kumar 	return true;
11625efdd5cfSKaran Tilak Kumar }
11635efdd5cfSKaran Tilak Kumar 
11645efdd5cfSKaran Tilak Kumar void nvfnic_cleanup_all_nvme_ios(struct fnic *fnic)
11655efdd5cfSKaran Tilak Kumar {
11665efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = &fnic->iport;
11675efdd5cfSKaran Tilak Kumar 
11685efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
11695efdd5cfSKaran Tilak Kumar 	sbitmap_for_each_set(&fnic->nvfnic_tag_map, _cleanup_all_nvme_io,
11705efdd5cfSKaran Tilak Kumar 			     iport);
11715efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
11725efdd5cfSKaran Tilak Kumar }
11735efdd5cfSKaran Tilak Kumar 
11745efdd5cfSKaran Tilak Kumar void nvfnic_nvme_zero_devloss_tports(struct fnic *fnic)
11755efdd5cfSKaran Tilak Kumar {
11765efdd5cfSKaran Tilak Kumar 	struct fnic_tport_s *tport, *next;
11775efdd5cfSKaran Tilak Kumar 
11785efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
11795efdd5cfSKaran Tilak Kumar 	list_for_each_entry_safe(tport, next, &fnic->iport.tport_list, links) {
11805efdd5cfSKaran Tilak Kumar 		if (tport->flags & FNIC_FDLS_NVME_REGISTERED) {
11815efdd5cfSKaran Tilak Kumar 			spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
11825efdd5cfSKaran Tilak Kumar 			nvme_fc_set_remoteport_devloss(tport->nv_rport, 0);
11835efdd5cfSKaran Tilak Kumar 			spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
11845efdd5cfSKaran Tilak Kumar 		}
11855efdd5cfSKaran Tilak Kumar 	}
11865efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
11875efdd5cfSKaran Tilak Kumar }
11885efdd5cfSKaran Tilak Kumar 
11895efdd5cfSKaran Tilak Kumar void nvfnic_nvme_unload(struct fnic *fnic)
11905efdd5cfSKaran Tilak Kumar {
11915efdd5cfSKaran Tilak Kumar 	int ret = 0;
11925efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = &fnic->iport;
11935efdd5cfSKaran Tilak Kumar 	unsigned long flags;
11945efdd5cfSKaran Tilak Kumar 	unsigned int time_wait =  FNIC_NVME_LPORT_REMOVE_WAIT;
11955efdd5cfSKaran Tilak Kumar 	unsigned int time_remain;
11965efdd5cfSKaran Tilak Kumar 	DECLARE_COMPLETION_ONSTACK(nvme_lport_unreg_done);
11975efdd5cfSKaran Tilak Kumar 
11985efdd5cfSKaran Tilak Kumar 	/* Mark iport state as INIT so that no IOs can be issued from this point */
11995efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, flags);
12005efdd5cfSKaran Tilak Kumar 	fnic->in_remove = 1;
12015efdd5cfSKaran Tilak Kumar 	fnic->iport.state = FNIC_IPORT_STATE_LINK_WAIT;
12025efdd5cfSKaran Tilak Kumar 	fnic->nvme_lport_unreg_done = &nvme_lport_unreg_done;
12035efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
12045efdd5cfSKaran Tilak Kumar 
12055efdd5cfSKaran Tilak Kumar 	/*
12065efdd5cfSKaran Tilak Kumar 	 * If fnic is already processing link-down or fnic is held
12075efdd5cfSKaran Tilak Kumar 	 * in disabled state following a reboot we dont need to issue
12085efdd5cfSKaran Tilak Kumar 	 * firmware reset and unregister remote ports as it is already
12095efdd5cfSKaran Tilak Kumar 	 * done as part of link down handling.
12105efdd5cfSKaran Tilak Kumar 	 */
12115efdd5cfSKaran Tilak Kumar 	if (fdls_get_state(&iport->fabric) == FDLS_STATE_LINKDOWN) {
12125efdd5cfSKaran Tilak Kumar 		while (fnic->reset_in_progress == IN_PROGRESS) {
12135efdd5cfSKaran Tilak Kumar 			wait_for_completion_timeout(&fnic->reset_completion_wait,
12145efdd5cfSKaran Tilak Kumar 						    msecs_to_jiffies(5000));
12155efdd5cfSKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_INFO, fnic,
12165efdd5cfSKaran Tilak Kumar 				      "rmmod waiting for reset %p\n", fnic);
12175efdd5cfSKaran Tilak Kumar 		}
12185efdd5cfSKaran Tilak Kumar 	} else if (fdls_get_state(&iport->fabric) != FDLS_STATE_INIT)
12195efdd5cfSKaran Tilak Kumar 		fnic_fcpio_reset(fnic);
12205efdd5cfSKaran Tilak Kumar 
12215efdd5cfSKaran Tilak Kumar 	/*
12225efdd5cfSKaran Tilak Kumar 	 * Mark state so that the workqueue thread stops forwarding
12235efdd5cfSKaran Tilak Kumar 	 * received frames and link events to the local port. ISR and
12245efdd5cfSKaran Tilak Kumar 	 * other threads that can queue work items will also stop
12255efdd5cfSKaran Tilak Kumar 	 * creating work items on the fnic workqueue
12265efdd5cfSKaran Tilak Kumar 	 */
12275efdd5cfSKaran Tilak Kumar 	nvfnic_nvme_zero_devloss_tports(fnic);
12285efdd5cfSKaran Tilak Kumar 	fnic_flush_tport_event_list(fnic);
12295efdd5cfSKaran Tilak Kumar 	fnic_delete_fcp_tports(fnic);
12305efdd5cfSKaran Tilak Kumar 
12315efdd5cfSKaran Tilak Kumar 	if (iport->flags & FNIC_LPORT_NVME_REGISTERED) {
12325efdd5cfSKaran Tilak Kumar 		ret = nvme_fc_unregister_localport(fnic->iport.nv_lport);
12335efdd5cfSKaran Tilak Kumar 		if (ret) {
12345efdd5cfSKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_ERR, fnic,
12355efdd5cfSKaran Tilak Kumar 				"Unregister nvme localport failed: %d\n", ret);
12365efdd5cfSKaran Tilak Kumar 		} else {
12375efdd5cfSKaran Tilak Kumar 			time_remain = wait_for_completion_timeout(
12385efdd5cfSKaran Tilak Kumar 				fnic->nvme_lport_unreg_done,
12395efdd5cfSKaran Tilak Kumar 				msecs_to_jiffies(time_wait));
12405efdd5cfSKaran Tilak Kumar 			if (!time_remain) {
12415efdd5cfSKaran Tilak Kumar 				FNIC_NVME_DBG(KERN_ERR, fnic,
12425efdd5cfSKaran Tilak Kumar 					      "Local port removal timed out\n");
12435efdd5cfSKaran Tilak Kumar 				WARN_ON(1);
12445efdd5cfSKaran Tilak Kumar 			}
12455efdd5cfSKaran Tilak Kumar 			iport->flags &= ~FNIC_LPORT_NVME_REGISTERED;
12465efdd5cfSKaran Tilak Kumar 			kfree(iport->nv_tmpl);
12475efdd5cfSKaran Tilak Kumar 		}
12485efdd5cfSKaran Tilak Kumar 	}
12495efdd5cfSKaran Tilak Kumar 
12505efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, flags);
12515efdd5cfSKaran Tilak Kumar 	fnic->nvme_lport_unreg_done = NULL;
12525efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
12535efdd5cfSKaran Tilak Kumar 
12545efdd5cfSKaran Tilak Kumar 	nvfnic_flush_nvme_io_list(fnic);
12555efdd5cfSKaran Tilak Kumar }
12565efdd5cfSKaran Tilak Kumar 
12575efdd5cfSKaran Tilak Kumar struct nvfnic_ls_req*
12585efdd5cfSKaran Tilak Kumar nvfnic_find_ls_req(struct fnic_tport_s *tport, uint16_t oxid)
12595efdd5cfSKaran Tilak Kumar {
12605efdd5cfSKaran Tilak Kumar 	struct nvfnic_ls_req *nvfnic_ls_req, *next;
12615efdd5cfSKaran Tilak Kumar 
12625efdd5cfSKaran Tilak Kumar 	list_for_each_entry_safe(nvfnic_ls_req, next, &(tport->ls_req_list), list) {
12635efdd5cfSKaran Tilak Kumar 		if (nvfnic_ls_req->oxid == oxid)
12645efdd5cfSKaran Tilak Kumar 			return nvfnic_ls_req;
12655efdd5cfSKaran Tilak Kumar 	}
12665efdd5cfSKaran Tilak Kumar 	return NULL;
12675efdd5cfSKaran Tilak Kumar }
12685efdd5cfSKaran Tilak Kumar 
12695efdd5cfSKaran Tilak Kumar void nvfnic_fcpio_cmpl(struct fnic_io_req *io_req)
12705efdd5cfSKaran Tilak Kumar {
12715efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = io_req->iport->fnic;
1272d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
12735efdd5cfSKaran Tilak Kumar 
12745efdd5cfSKaran Tilak Kumar 	nvfnic_free_fcpio_tag(io_req->iport, io_req);
1275d25a557dSKaran Tilak Kumar 	atomic64_inc(&fnic_stats->io_stats.nvme_ios_queued_for_rsp);
12765efdd5cfSKaran Tilak Kumar 	io_req->waitq_start_time = jiffies;
12775efdd5cfSKaran Tilak Kumar 
12785efdd5cfSKaran Tilak Kumar 	llist_add(&io_req->nvfnic_io_cmpl, &fnic->nvme_io_event_llist);
12795efdd5cfSKaran Tilak Kumar 	atomic_inc(&fnic->nvme_io_event_queued);
1280d25a557dSKaran Tilak Kumar 	atomic64_inc(&fnic_stats->io_stats.nvme_num_ios_in_waitq);
12815efdd5cfSKaran Tilak Kumar 
12825efdd5cfSKaran Tilak Kumar 	queue_work(fnic_cmpl_queue, &fnic->nvme_io_cmpl_work);
12835efdd5cfSKaran Tilak Kumar }
12845efdd5cfSKaran Tilak Kumar 
12855efdd5cfSKaran Tilak Kumar void nvfnic_process_ls_abts_rsp(struct fnic_iport_s *iport,
12865efdd5cfSKaran Tilak Kumar 		struct fc_frame_header *fchdr)
12875efdd5cfSKaran Tilak Kumar {
12885efdd5cfSKaran Tilak Kumar 	uint32_t tport_fcid;
12895efdd5cfSKaran Tilak Kumar 	struct fnic_tport_s *tport;
12905efdd5cfSKaran Tilak Kumar 	struct nvfnic_ls_req *nvfnic_ls_req;
12915efdd5cfSKaran Tilak Kumar 	struct nvmefc_ls_req *lsreq;
12925efdd5cfSKaran Tilak Kumar 	uint8_t *fcid;
12935efdd5cfSKaran Tilak Kumar 	uint16_t oxid = FNIC_STD_GET_OX_ID(fchdr);
12945efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
1295d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
12965efdd5cfSKaran Tilak Kumar 
12975efdd5cfSKaran Tilak Kumar 	fcid = FNIC_STD_GET_S_ID(fchdr);
12985efdd5cfSKaran Tilak Kumar 	tport_fcid = ntoh24(fcid);
12995efdd5cfSKaran Tilak Kumar 
13005efdd5cfSKaran Tilak Kumar 	tport = fnic_find_tport_by_fcid(iport, tport_fcid);
13015efdd5cfSKaran Tilak Kumar 	if (tport == NULL) {
13025efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
13035efdd5cfSKaran Tilak Kumar 			      "tport: 0x%x not found\n", tport_fcid);
13045efdd5cfSKaran Tilak Kumar 		return;
13055efdd5cfSKaran Tilak Kumar 	}
13065efdd5cfSKaran Tilak Kumar 
13075efdd5cfSKaran Tilak Kumar 	nvfnic_ls_req = nvfnic_find_ls_req(tport, oxid);
13085efdd5cfSKaran Tilak Kumar 	if (nvfnic_ls_req == NULL) {
13095efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
13105efdd5cfSKaran Tilak Kumar 			      "tport: 0x%x lsreq oxid: 0x%x not found\n",
13115efdd5cfSKaran Tilak Kumar 			      tport_fcid, oxid);
13125efdd5cfSKaran Tilak Kumar 		return;
13135efdd5cfSKaran Tilak Kumar 	}
13145efdd5cfSKaran Tilak Kumar 
13155efdd5cfSKaran Tilak Kumar 	lsreq = nvfnic_ls_req->ls_req;
13165efdd5cfSKaran Tilak Kumar 	if ((lsreq == NULL) || (lsreq->private == NULL)) {
13175efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
13185efdd5cfSKaran Tilak Kumar 			      "tport: 0x%x lsreq oxid: 0x%x already aborted\n",
13195efdd5cfSKaran Tilak Kumar 			      tport_fcid, oxid);
13205efdd5cfSKaran Tilak Kumar 		return;
13215efdd5cfSKaran Tilak Kumar 	}
13225efdd5cfSKaran Tilak Kumar 
1323d25a557dSKaran Tilak Kumar 	atomic64_inc(&fnic_stats->nvme_stats.nvme_ls_abort_responses);
13245efdd5cfSKaran Tilak Kumar 	nvfnic_ls_req->state = FNIC_LS_REQ_ABTS_COMPLETE;
13255efdd5cfSKaran Tilak Kumar 
1326d25a557dSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_DEBUG, fnic, "nvme_ls_requests: %lld\n",
1327d25a557dSKaran Tilak Kumar 		      (u64) atomic64_read(&fnic_stats->nvme_stats.nvme_ls_requests));
1328d25a557dSKaran Tilak Kumar 
13295efdd5cfSKaran Tilak Kumar 	list_del(&nvfnic_ls_req->list);
13305efdd5cfSKaran Tilak Kumar 	fdls_free_oxid(iport, oxid, &nvfnic_ls_req->oxid);
13315efdd5cfSKaran Tilak Kumar 	lsreq->private = NULL;
13325efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
13335efdd5cfSKaran Tilak Kumar 	timer_delete_sync(&nvfnic_ls_req->ls_req_timer);
13345efdd5cfSKaran Tilak Kumar 	lsreq->done(lsreq, NVME_SC_HOST_ABORTED_CMD);
13355efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
13365efdd5cfSKaran Tilak Kumar }
13375efdd5cfSKaran Tilak Kumar 
13385efdd5cfSKaran Tilak Kumar /**
13395efdd5cfSKaran Tilak Kumar  * nvfnic_ls_rsp_recv - Handle received NVMe FC link service (LS) response
13405efdd5cfSKaran Tilak Kumar  * @iport:  Pointer to the local FNIC port structure
13415efdd5cfSKaran Tilak Kumar  * @fchdr:  Pointer to the Fibre Channel frame header for the
13425efdd5cfSKaran Tilak Kumar  *          received response
13435efdd5cfSKaran Tilak Kumar  * @len:    Length of the received frame
13445efdd5cfSKaran Tilak Kumar  *
13455efdd5cfSKaran Tilak Kumar  * This function processes link service (LS) responses received from
13465efdd5cfSKaran Tilak Kumar  * NVMe Discovery Controllers or regular NVMe subsystems during
13475efdd5cfSKaran Tilak Kumar  * association.
13485efdd5cfSKaran Tilak Kumar  */
13495efdd5cfSKaran Tilak Kumar void nvfnic_ls_rsp_recv(struct fnic_iport_s *iport,
13505efdd5cfSKaran Tilak Kumar 		struct fc_frame_header *fchdr, int len)
13515efdd5cfSKaran Tilak Kumar {
13525efdd5cfSKaran Tilak Kumar 	uint8_t *fcid;
13535efdd5cfSKaran Tilak Kumar 	uint32_t tport_fcid;
13545efdd5cfSKaran Tilak Kumar 	struct fnic_tport_s *tport;
13555efdd5cfSKaran Tilak Kumar 	struct nvfnic_ls_req *nvfnic_ls_req;
13565efdd5cfSKaran Tilak Kumar 	struct nvmefc_ls_req *lsreq;
13575efdd5cfSKaran Tilak Kumar 	uint16_t oxid;
13585efdd5cfSKaran Tilak Kumar 	uint32_t rsp_len;
13595efdd5cfSKaran Tilak Kumar 	int sid_len = offsetof(struct fc_frame_header, fh_s_id) +
13605efdd5cfSKaran Tilak Kumar 		      sizeof(fchdr->fh_s_id);
13615efdd5cfSKaran Tilak Kumar 	int status = 0;
13625efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
1363d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
13645efdd5cfSKaran Tilak Kumar 
13655efdd5cfSKaran Tilak Kumar 	if (len < (int)sizeof(*fchdr)) {
13665efdd5cfSKaran Tilak Kumar 		if (len >= sid_len) {
13675efdd5cfSKaran Tilak Kumar 			fcid = FNIC_STD_GET_S_ID(fchdr);
13685efdd5cfSKaran Tilak Kumar 			tport_fcid = ntoh24(fcid);
13695efdd5cfSKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_ERR, fnic,
13705efdd5cfSKaran Tilak Kumar 				      "tport: 0x%x LS rsp len %d too short\n",
13715efdd5cfSKaran Tilak Kumar 				      tport_fcid, len);
13725efdd5cfSKaran Tilak Kumar 		} else {
13735efdd5cfSKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_ERR, fnic,
13745efdd5cfSKaran Tilak Kumar 				      "LS response len %d too short\n", len);
13755efdd5cfSKaran Tilak Kumar 		}
13765efdd5cfSKaran Tilak Kumar 		return;
13775efdd5cfSKaran Tilak Kumar 	}
13785efdd5cfSKaran Tilak Kumar 	rsp_len = len - sizeof(*fchdr);
13795efdd5cfSKaran Tilak Kumar 
13805efdd5cfSKaran Tilak Kumar 	fcid = FNIC_STD_GET_S_ID(fchdr);
13815efdd5cfSKaran Tilak Kumar 	tport_fcid = ntoh24(fcid);
13825efdd5cfSKaran Tilak Kumar 
13835efdd5cfSKaran Tilak Kumar 	tport = fnic_find_tport_by_fcid(iport, tport_fcid);
13845efdd5cfSKaran Tilak Kumar 	if (!tport) {
13855efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
13865efdd5cfSKaran Tilak Kumar 			      "tport: 0x%x not found\n", tport_fcid);
13875efdd5cfSKaran Tilak Kumar 		return;
13885efdd5cfSKaran Tilak Kumar 	}
13895efdd5cfSKaran Tilak Kumar 
13905efdd5cfSKaran Tilak Kumar 	oxid = FNIC_STD_GET_OX_ID(fchdr);
13915efdd5cfSKaran Tilak Kumar 	nvfnic_ls_req = nvfnic_find_ls_req(tport, oxid);
13925efdd5cfSKaran Tilak Kumar 	if (!nvfnic_ls_req) {
13935efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
13945efdd5cfSKaran Tilak Kumar 			      "tport: 0x%x no nvfnic_lsreq for oxid: 0x%x\n",
13955efdd5cfSKaran Tilak Kumar 			      tport_fcid, oxid);
13965efdd5cfSKaran Tilak Kumar 		return;
13975efdd5cfSKaran Tilak Kumar 	}
13985efdd5cfSKaran Tilak Kumar 
13995efdd5cfSKaran Tilak Kumar 	lsreq = nvfnic_ls_req->ls_req;
14005efdd5cfSKaran Tilak Kumar 	if (!lsreq || (lsreq->private == NULL)) {
14015efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
14025efdd5cfSKaran Tilak Kumar 			      "tport:0x%x lsreq:0x%x already done\n",
14035efdd5cfSKaran Tilak Kumar 			      tport_fcid, oxid);
14045efdd5cfSKaran Tilak Kumar 		return;
14055efdd5cfSKaran Tilak Kumar 	}
14065efdd5cfSKaran Tilak Kumar 	if (!lsreq->rspaddr) {
14075efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
14085efdd5cfSKaran Tilak Kumar 			      "tport 0x%x lsreq 0x%x rspaddr NULL\n",
14095efdd5cfSKaran Tilak Kumar 			      tport_fcid, oxid);
14105efdd5cfSKaran Tilak Kumar 		return;
14115efdd5cfSKaran Tilak Kumar 	}
14125efdd5cfSKaran Tilak Kumar 
14135efdd5cfSKaran Tilak Kumar 	if ((nvfnic_ls_req->state == FNIC_LS_REQ_CMD_ABTS_PENDING) ||
14145efdd5cfSKaran Tilak Kumar 	    (nvfnic_ls_req->state == FNIC_LS_REQ_CMD_ABTS_STARTED)) {
14155efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
14165efdd5cfSKaran Tilak Kumar 			      "tport 0x%x lsreq oxid: 0x%x abts pending\n",
14175efdd5cfSKaran Tilak Kumar 			      tport_fcid, oxid);
14185efdd5cfSKaran Tilak Kumar 		return;
14195efdd5cfSKaran Tilak Kumar 	}
14205efdd5cfSKaran Tilak Kumar 
14215efdd5cfSKaran Tilak Kumar 	if (rsp_len > lsreq->rsplen) {
14225efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
14235efdd5cfSKaran Tilak Kumar 			      "tport:0x%x lsreq:0x%x rsp %u > %u\n",
14245efdd5cfSKaran Tilak Kumar 			      tport_fcid, oxid, rsp_len, lsreq->rsplen);
14255efdd5cfSKaran Tilak Kumar 		status = -EOVERFLOW;
14265efdd5cfSKaran Tilak Kumar 	}
14275efdd5cfSKaran Tilak Kumar 
14285efdd5cfSKaran Tilak Kumar 	nvfnic_ls_req->state = FNIC_LS_REQ_CMD_COMPLETE;
1429d25a557dSKaran Tilak Kumar 	atomic64_inc(&fnic_stats->nvme_stats.nvme_ls_responses);
14305efdd5cfSKaran Tilak Kumar 
14315efdd5cfSKaran Tilak Kumar 	list_del_init(&nvfnic_ls_req->list);
14325efdd5cfSKaran Tilak Kumar 	lsreq->private = NULL;
14335efdd5cfSKaran Tilak Kumar 	fdls_free_oxid(iport, oxid, &nvfnic_ls_req->oxid);
14345efdd5cfSKaran Tilak Kumar 
14355efdd5cfSKaran Tilak Kumar 	if (status == 0) {
14365efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_DEBUG, fnic,
14375efdd5cfSKaran Tilak Kumar 			      "tport:0x%x lsreq:0x%x completed\n",
14385efdd5cfSKaran Tilak Kumar 			      tport_fcid, oxid);
14395efdd5cfSKaran Tilak Kumar 
14405efdd5cfSKaran Tilak Kumar 		/* Copy the Response */
14415efdd5cfSKaran Tilak Kumar 		memcpy(lsreq->rspaddr, (uint8_t *)fchdr + sizeof(*fchdr),
14425efdd5cfSKaran Tilak Kumar 		       rsp_len);
14435efdd5cfSKaran Tilak Kumar 	}
14445efdd5cfSKaran Tilak Kumar 
14455efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
14465efdd5cfSKaran Tilak Kumar 	timer_delete_sync(&nvfnic_ls_req->ls_req_timer);
14475efdd5cfSKaran Tilak Kumar 	lsreq->done(lsreq, status);
14485efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
14495efdd5cfSKaran Tilak Kumar }
14505efdd5cfSKaran Tilak Kumar 
1451f06ee33dSKaran Tilak Kumar static bool nvfnic_ls_req_cleanup(struct fnic_iport_s *iport,
1452f06ee33dSKaran Tilak Kumar 				  struct nvmefc_ls_req *lsreq,
1453f06ee33dSKaran Tilak Kumar 				  uint16_t oxid)
1454f06ee33dSKaran Tilak Kumar {
1455f06ee33dSKaran Tilak Kumar 	struct nvfnic_ls_req *nvfnic_ls_req = lsreq->private;
1456f06ee33dSKaran Tilak Kumar 
1457f06ee33dSKaran Tilak Kumar 	if (!nvfnic_ls_req)
1458f06ee33dSKaran Tilak Kumar 		return false;
1459f06ee33dSKaran Tilak Kumar 
1460f06ee33dSKaran Tilak Kumar 	lsreq->private = NULL;
1461f06ee33dSKaran Tilak Kumar 	list_del(&nvfnic_ls_req->list);
1462f06ee33dSKaran Tilak Kumar 	fdls_free_oxid(iport, oxid, &nvfnic_ls_req->oxid);
1463f06ee33dSKaran Tilak Kumar 	nvfnic_ls_req->state = FNIC_LS_REQ_CMD_COMPLETE;
1464f06ee33dSKaran Tilak Kumar 
1465f06ee33dSKaran Tilak Kumar 	return true;
1466f06ee33dSKaran Tilak Kumar }
1467f06ee33dSKaran Tilak Kumar 
14685efdd5cfSKaran Tilak Kumar void nvfnic_ls_req_timeout(struct timer_list *t)
14695efdd5cfSKaran Tilak Kumar {
14705efdd5cfSKaran Tilak Kumar 	struct nvfnic_ls_req *nvfnic_ls_req = timer_container_of(nvfnic_ls_req,
14715efdd5cfSKaran Tilak Kumar 			t, ls_req_timer);
14725efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = nvfnic_ls_req->fnic;
14735efdd5cfSKaran Tilak Kumar 	struct nvmefc_ls_req *ls_req = nvfnic_ls_req->ls_req;
14745efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = &fnic->iport;
14755efdd5cfSKaran Tilak Kumar 	struct fnic_tport_s *tport = (struct fnic_tport_s *) nvfnic_ls_req->tport;
1476d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
14775efdd5cfSKaran Tilak Kumar 	uint16_t oxid = nvfnic_ls_req->oxid;
1478f06ee33dSKaran Tilak Kumar 	int timeout;
14795efdd5cfSKaran Tilak Kumar 
14805efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic,
14815efdd5cfSKaran Tilak Kumar 		      "tport: 0x%x lsreq: 0x%x state: %d timeout\n",
14825efdd5cfSKaran Tilak Kumar 		      tport->fcid, nvfnic_ls_req->oxid,
14835efdd5cfSKaran Tilak Kumar 		      nvfnic_ls_req->state);
14845efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
14855efdd5cfSKaran Tilak Kumar 
14865efdd5cfSKaran Tilak Kumar 	if ((ls_req->private == NULL) ||
14875efdd5cfSKaran Tilak Kumar 	    (nvfnic_ls_req->state == FNIC_LS_REQ_CMD_ABTS_STARTED)) {
14885efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
14895efdd5cfSKaran Tilak Kumar 			      "tport: 0x%x lsreq: 0x%x already aborted\n",
14905efdd5cfSKaran Tilak Kumar 			      tport->fcid, nvfnic_ls_req->oxid);
14915efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
14925efdd5cfSKaran Tilak Kumar 		return;
14935efdd5cfSKaran Tilak Kumar 	}
14945efdd5cfSKaran Tilak Kumar 
14955efdd5cfSKaran Tilak Kumar 	if (nvfnic_ls_req->state == FNIC_LS_REQ_CMD_ABTS_PENDING) {
14965efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
14975efdd5cfSKaran Tilak Kumar 			      "tport: 0x%x lsreq: 0x%x abort timeout\n",
14985efdd5cfSKaran Tilak Kumar 			      tport->fcid, nvfnic_ls_req->oxid);
14995efdd5cfSKaran Tilak Kumar 
15005efdd5cfSKaran Tilak Kumar 		ls_req = nvfnic_ls_req->ls_req;
1501f06ee33dSKaran Tilak Kumar 		nvfnic_ls_req_cleanup(iport, ls_req, oxid);
15025efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
15035efdd5cfSKaran Tilak Kumar 		ls_req->done(ls_req, -ETIMEDOUT);
15045efdd5cfSKaran Tilak Kumar 		return;
15055efdd5cfSKaran Tilak Kumar 	} else if ((nvfnic_ls_req->state == FNIC_LS_REQ_CMD_PENDING) &&
15065efdd5cfSKaran Tilak Kumar 		   (nvfnic_transport_ready(iport, tport))) {
15075efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
15085efdd5cfSKaran Tilak Kumar 			      "tport: 0x%x lsreq: 0x%x sending abort\n",
15095efdd5cfSKaran Tilak Kumar 			      tport->fcid, nvfnic_ls_req->oxid);
1510f06ee33dSKaran Tilak Kumar 		nvfnic_ls_req->state = FNIC_LS_REQ_CMD_ABTS_PENDING;
1511d25a557dSKaran Tilak Kumar 		atomic64_inc(&fnic_stats->nvme_stats.nvme_ls_aborts);
1512f06ee33dSKaran Tilak Kumar 
1513f06ee33dSKaran Tilak Kumar 		if (fdls_send_ls_req_abts(iport, tport, nvfnic_ls_req->oxid) == 0) {
1514f06ee33dSKaran Tilak Kumar 			timeout = FNIC_LS_REQ_TMO_MSECS(ls_req->timeout);
1515f06ee33dSKaran Tilak Kumar 			mod_timer(&nvfnic_ls_req->ls_req_timer,
1516f06ee33dSKaran Tilak Kumar 				  round_jiffies(jiffies + msecs_to_jiffies(timeout)));
1517f06ee33dSKaran Tilak Kumar 			spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
1518f06ee33dSKaran Tilak Kumar 			return;
1519f06ee33dSKaran Tilak Kumar 		}
1520f06ee33dSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
1521f06ee33dSKaran Tilak Kumar 			      "tport: 0x%x lsreq: 0x%x cannot send abort\n",
1522f06ee33dSKaran Tilak Kumar 			      tport->fcid, oxid);
15235efdd5cfSKaran Tilak Kumar 	}
15245efdd5cfSKaran Tilak Kumar 
15255efdd5cfSKaran Tilak Kumar 	if (ls_req->private == NULL) {
15265efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
15275efdd5cfSKaran Tilak Kumar 		return;
15285efdd5cfSKaran Tilak Kumar 	}
15295efdd5cfSKaran Tilak Kumar 
15305efdd5cfSKaran Tilak Kumar 	ls_req = nvfnic_ls_req->ls_req;
1531f06ee33dSKaran Tilak Kumar 	nvfnic_ls_req_cleanup(iport, ls_req, oxid);
15325efdd5cfSKaran Tilak Kumar 
15335efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
15345efdd5cfSKaran Tilak Kumar 	ls_req->done(ls_req, -ETIMEDOUT);
15355efdd5cfSKaran Tilak Kumar }
15365efdd5cfSKaran Tilak Kumar 
153739bf0755SKaran Tilak Kumar /**
153839bf0755SKaran Tilak Kumar  * nvfnic_ls_req_send - Send NVMe FC link service (LS) request
153939bf0755SKaran Tilak Kumar  * @lport:   Pointer to local NVMe FC port structure
154039bf0755SKaran Tilak Kumar  * @rport:   Pointer to remote NVMe FC port structure
154139bf0755SKaran Tilak Kumar  * @ls_req:  Pointer to the link service request structure
154239bf0755SKaran Tilak Kumar  *
154339bf0755SKaran Tilak Kumar  * This function is used to send link service (LS) commands to an NVMe
154439bf0755SKaran Tilak Kumar  * Discovery Controller for discovery operations, as well as to regular
154539bf0755SKaran Tilak Kumar  * NVMe subsystems during association. It encapsulates the logic for
154639bf0755SKaran Tilak Kumar  * transmitting LS requests over the NVMe over Fabrics (NVMe-oF) FC
154739bf0755SKaran Tilak Kumar  * transport.
154839bf0755SKaran Tilak Kumar  *
154939bf0755SKaran Tilak Kumar  * Returns: 0 on success, or a negative error code on failure.
155039bf0755SKaran Tilak Kumar  */
155139bf0755SKaran Tilak Kumar int nvfnic_ls_req_send(struct nvme_fc_local_port *lport,
155239bf0755SKaran Tilak Kumar 		  struct nvme_fc_remote_port *rport,
155339bf0755SKaran Tilak Kumar 		  struct nvmefc_ls_req *ls_req)
155439bf0755SKaran Tilak Kumar {
155539bf0755SKaran Tilak Kumar 	int timeout;
155639bf0755SKaran Tilak Kumar 	uint8_t *frame;
155739bf0755SKaran Tilak Kumar 	uint8_t fcid[3];
155839bf0755SKaran Tilak Kumar 	unsigned long flags = 0;
155939bf0755SKaran Tilak Kumar 	struct fnic_iport_s *iport = lport->private;
156039bf0755SKaran Tilak Kumar 	uint8_t *ls_req_payload;
156139bf0755SKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
156239bf0755SKaran Tilak Kumar 	struct fc_frame_header *fchdr;
1563d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
156439bf0755SKaran Tilak Kumar 	struct nvfnic_ls_req *nvfnic_ls_req = ls_req->private;
156539bf0755SKaran Tilak Kumar 	uint16_t frame_size = FNIC_ETH_FCOE_HDRS_OFFSET +
156639bf0755SKaran Tilak Kumar 			sizeof(struct fc_frame_header) + ls_req->rqstlen;
156739bf0755SKaran Tilak Kumar 	struct fnic_tport_s *tport;
156839bf0755SKaran Tilak Kumar 	int ret;
156939bf0755SKaran Tilak Kumar 
157039bf0755SKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, flags);
157139bf0755SKaran Tilak Kumar 
157239bf0755SKaran Tilak Kumar 	tport = (struct fnic_tport_s *)rport->private;
157339bf0755SKaran Tilak Kumar 	INIT_LIST_HEAD(&nvfnic_ls_req->list);
157439bf0755SKaran Tilak Kumar 
157539bf0755SKaran Tilak Kumar 	if (!nvfnic_transport_ready(iport, tport)) {
157639bf0755SKaran Tilak Kumar 		if (tport != NULL)
157739bf0755SKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_INFO, fnic,
157839bf0755SKaran Tilak Kumar 				      "iport: 0x%x tport: 0x%x transport not ready\n",
157939bf0755SKaran Tilak Kumar 				      iport->fcid, tport->fcid);
158039bf0755SKaran Tilak Kumar 		else
158139bf0755SKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_INFO, fnic,
158239bf0755SKaran Tilak Kumar 				      "iport: 0x%x transport not ready\n",
158339bf0755SKaran Tilak Kumar 				      iport->fcid);
158439bf0755SKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
158539bf0755SKaran Tilak Kumar 		return -ENOLINK;
158639bf0755SKaran Tilak Kumar 	}
158739bf0755SKaran Tilak Kumar 
158839bf0755SKaran Tilak Kumar 	frame = fdls_alloc_frame(iport);
158939bf0755SKaran Tilak Kumar 	if (frame == NULL) {
159039bf0755SKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
159139bf0755SKaran Tilak Kumar 		     "Failed to allocate frame to send NVME LS REQ");
159239bf0755SKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
159339bf0755SKaran Tilak Kumar 		return -ENOMEM;
159439bf0755SKaran Tilak Kumar 	}
159539bf0755SKaran Tilak Kumar 
159639bf0755SKaran Tilak Kumar 	if (fdls_alloc_oxid(iport, FNIC_FRAME_TYPE_NVME_LS,
159739bf0755SKaran Tilak Kumar 			&nvfnic_ls_req->oxid) == FNIC_UNASSIGNED_OXID) {
159839bf0755SKaran Tilak Kumar 		FNIC_FCS_DBG(KERN_INFO, fnic,
159939bf0755SKaran Tilak Kumar 		     "0x%x: Failed to allocate OXID to send NVME LS REQ",
160039bf0755SKaran Tilak Kumar 			 iport->fcid);
160139bf0755SKaran Tilak Kumar 		mempool_free(frame, fnic->frame_pool);
160239bf0755SKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
160339bf0755SKaran Tilak Kumar 		return -EAGAIN;
160439bf0755SKaran Tilak Kumar 	}
160539bf0755SKaran Tilak Kumar 
1606d25a557dSKaran Tilak Kumar 	atomic64_inc(&fnic_stats->nvme_stats.nvme_ls_requests);
160739bf0755SKaran Tilak Kumar 	timer_setup(&nvfnic_ls_req->ls_req_timer, nvfnic_ls_req_timeout,
160839bf0755SKaran Tilak Kumar 		     0UL);
160939bf0755SKaran Tilak Kumar 
161039bf0755SKaran Tilak Kumar 	nvfnic_ls_req->fnic = fnic;
161139bf0755SKaran Tilak Kumar 	nvfnic_ls_req->tport = tport;
161239bf0755SKaran Tilak Kumar 	nvfnic_ls_req->state = FNIC_LS_REQ_CMD_INIT;
161339bf0755SKaran Tilak Kumar 	nvfnic_ls_req->ls_req = ls_req;
161439bf0755SKaran Tilak Kumar 
161539bf0755SKaran Tilak Kumar 	fchdr = (struct fc_frame_header *)(frame + FNIC_ETH_FCOE_HDRS_OFFSET);
161639bf0755SKaran Tilak Kumar 	*fchdr = (struct fc_frame_header) {
161739bf0755SKaran Tilak Kumar 		.fh_r_ctl = FC_RCTL_ELS4_REQ,
161839bf0755SKaran Tilak Kumar 		.fh_type = FC_TYPE_NVME,
161939bf0755SKaran Tilak Kumar 		.fh_f_ctl = {FNIC_ELS_REQ_FCTL, 0, 0},
162039bf0755SKaran Tilak Kumar 		.fh_rx_id = cpu_to_be16(FNIC_UNASSIGNED_RXID)
162139bf0755SKaran Tilak Kumar 	};
162239bf0755SKaran Tilak Kumar 
162339bf0755SKaran Tilak Kumar 	hton24(fcid, iport->fcid);
162439bf0755SKaran Tilak Kumar 	FNIC_STD_SET_S_ID(*fchdr, fcid);
162539bf0755SKaran Tilak Kumar 
162639bf0755SKaran Tilak Kumar 	hton24(fcid, tport->fcid);
162739bf0755SKaran Tilak Kumar 	FNIC_STD_SET_D_ID(*fchdr, fcid);
162839bf0755SKaran Tilak Kumar 
162939bf0755SKaran Tilak Kumar 	FNIC_STD_SET_OX_ID(*fchdr, nvfnic_ls_req->oxid);
163039bf0755SKaran Tilak Kumar 
163139bf0755SKaran Tilak Kumar 	ls_req_payload = frame + FNIC_ETH_FCOE_HDRS_OFFSET + sizeof(*fchdr);
163239bf0755SKaran Tilak Kumar 	memcpy(ls_req_payload, ls_req->rqstaddr, ls_req->rqstlen);
163339bf0755SKaran Tilak Kumar 
163439bf0755SKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic,
163539bf0755SKaran Tilak Kumar 		 "0x%x: NVME send ls req with oxid: 0x%x type: 0x%02x len: %d",
163639bf0755SKaran Tilak Kumar 		 iport->fcid, nvfnic_ls_req->oxid, *((uint8_t *) ls_req->rqstaddr),
163739bf0755SKaran Tilak Kumar 		 ls_req->rqstlen);
163839bf0755SKaran Tilak Kumar 
1639d25a557dSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic,
1640d25a557dSKaran Tilak Kumar 		 "0x%x: ls_reqs count: %lld",
1641d25a557dSKaran Tilak Kumar 		 iport->fcid,
1642d25a557dSKaran Tilak Kumar 		 (u64) atomic64_read(&fnic_stats->nvme_stats.nvme_ls_requests));
1643d25a557dSKaran Tilak Kumar 
164439bf0755SKaran Tilak Kumar 	list_add_tail(&nvfnic_ls_req->list, &tport->ls_req_list);
164539bf0755SKaran Tilak Kumar 	nvfnic_ls_req->state = FNIC_LS_REQ_CMD_PENDING;
164639bf0755SKaran Tilak Kumar 
164739bf0755SKaran Tilak Kumar 	ret = fnic_send_fcoe_frame(iport, frame, frame_size);
164839bf0755SKaran Tilak Kumar 	if (ret) {
1649f06ee33dSKaran Tilak Kumar 		nvfnic_ls_req_cleanup(iport, ls_req, nvfnic_ls_req->oxid);
165039bf0755SKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
165139bf0755SKaran Tilak Kumar 		mempool_free(frame, fnic->frame_pool);
165239bf0755SKaran Tilak Kumar 		return ret;
165339bf0755SKaran Tilak Kumar 	}
165439bf0755SKaran Tilak Kumar 
165539bf0755SKaran Tilak Kumar 	timeout = FNIC_LS_REQ_TMO_MSECS(ls_req->timeout);
165639bf0755SKaran Tilak Kumar 	mod_timer(&nvfnic_ls_req->ls_req_timer,
165739bf0755SKaran Tilak Kumar 		  round_jiffies(jiffies + msecs_to_jiffies(timeout)));
165839bf0755SKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
165939bf0755SKaran Tilak Kumar 
166039bf0755SKaran Tilak Kumar 	return 0;
166139bf0755SKaran Tilak Kumar }
166239bf0755SKaran Tilak Kumar 
16635efdd5cfSKaran Tilak Kumar void nvfnic_local_port_delete(struct nvme_fc_local_port *lport)
16645efdd5cfSKaran Tilak Kumar {
16655efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = (struct fnic_iport_s *) lport->private;
16665efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
16675efdd5cfSKaran Tilak Kumar 	unsigned long flags = 0;
16685efdd5cfSKaran Tilak Kumar 
16695efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic, "lport delete 0x%x\n",
16705efdd5cfSKaran Tilak Kumar 		      iport->fcid);
16715efdd5cfSKaran Tilak Kumar 
16725efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, flags);
16735efdd5cfSKaran Tilak Kumar 	if (fnic->nvme_lport_unreg_done)
16745efdd5cfSKaran Tilak Kumar 		complete(fnic->nvme_lport_unreg_done);
16755efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
16765efdd5cfSKaran Tilak Kumar }
16775efdd5cfSKaran Tilak Kumar 
16785efdd5cfSKaran Tilak Kumar void nvfnic_remote_port_delete(struct nvme_fc_remote_port *rport)
16795efdd5cfSKaran Tilak Kumar {
16805efdd5cfSKaran Tilak Kumar 	/*
16815efdd5cfSKaran Tilak Kumar 	 * Read rport->private without the lock only to find fnic.
16825efdd5cfSKaran Tilak Kumar 	 * Re-read it under fnic_lock to claim this delete callback, since
16835efdd5cfSKaran Tilak Kumar 	 * another callback may already have cleared it.
16845efdd5cfSKaran Tilak Kumar 	 */
16855efdd5cfSKaran Tilak Kumar 	struct fnic_tport_s *tport = (struct fnic_tport_s *)rport->private;
16865efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport;
16875efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = NULL;
16885efdd5cfSKaran Tilak Kumar 	unsigned long flags = 0;
16895efdd5cfSKaran Tilak Kumar 
16905efdd5cfSKaran Tilak Kumar 	if (tport == NULL) {
16915efdd5cfSKaran Tilak Kumar 		pr_err("Attempt to delete already deleted tport\n");
16925efdd5cfSKaran Tilak Kumar 		return;
16935efdd5cfSKaran Tilak Kumar 	}
16945efdd5cfSKaran Tilak Kumar 
16955efdd5cfSKaran Tilak Kumar 	iport = tport->iport;
16965efdd5cfSKaran Tilak Kumar 	fnic = iport->fnic;
16975efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic, "0x%x tport 0x%x\n",
16985efdd5cfSKaran Tilak Kumar 		      iport->fcid, tport->fcid);
16995efdd5cfSKaran Tilak Kumar 
17005efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, flags);
17015efdd5cfSKaran Tilak Kumar 	tport = (struct fnic_tport_s *)rport->private;
17025efdd5cfSKaran Tilak Kumar 	if (tport == NULL) {
17035efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
17045efdd5cfSKaran Tilak Kumar 			      "NVMe tport callback after NULL set %p\n",
17055efdd5cfSKaran Tilak Kumar 			      rport);
17065efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
17075efdd5cfSKaran Tilak Kumar 		return;
17085efdd5cfSKaran Tilak Kumar 	}
17095efdd5cfSKaran Tilak Kumar 
17105efdd5cfSKaran Tilak Kumar 	iport = tport->iport;
17115efdd5cfSKaran Tilak Kumar 	rport->private = NULL;
17125efdd5cfSKaran Tilak Kumar 
17135efdd5cfSKaran Tilak Kumar 	if (tport->timer_pending) {
17145efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
17155efdd5cfSKaran Tilak Kumar 			      "tport: 0x%x canceling discovery timer\n",
17165efdd5cfSKaran Tilak Kumar 			      tport->fcid);
17175efdd5cfSKaran Tilak Kumar 		/*
17185efdd5cfSKaran Tilak Kumar 		 * The retry timer callback takes fnic_lock and dereferences
17195efdd5cfSKaran Tilak Kumar 		 * this tport. Set del_timer_inprogress before dropping the
17205efdd5cfSKaran Tilak Kumar 		 * lock so a callback that is already running observes teardown
17215efdd5cfSKaran Tilak Kumar 		 * and exits.
17225efdd5cfSKaran Tilak Kumar 		 *
17235efdd5cfSKaran Tilak Kumar 		 * timer_delete_sync() then waits until no callback can still
17245efdd5cfSKaran Tilak Kumar 		 * hold a reference before the remoteport-delete path completes
17255efdd5cfSKaran Tilak Kumar 		 * or frees the target port.
17265efdd5cfSKaran Tilak Kumar 		 */
17275efdd5cfSKaran Tilak Kumar 		tport->del_timer_inprogress = 1;
17285efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
17295efdd5cfSKaran Tilak Kumar 		timer_delete_sync(&tport->retry_timer);
17305efdd5cfSKaran Tilak Kumar 		spin_lock_irqsave(&fnic->fnic_lock, flags);
17315efdd5cfSKaran Tilak Kumar 		tport->del_timer_inprogress = 0;
17325efdd5cfSKaran Tilak Kumar 		tport->timer_pending = 0;
17335efdd5cfSKaran Tilak Kumar 	}
17345efdd5cfSKaran Tilak Kumar 
17355efdd5cfSKaran Tilak Kumar 	if (tport->flags & FNIC_FDLS_NVME_TPORT_CLEANUP_PENDING) {
17365efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
17375efdd5cfSKaran Tilak Kumar 			      "tport %8x waiting on clean pending\n",
17385efdd5cfSKaran Tilak Kumar 			      tport->fcid);
17395efdd5cfSKaran Tilak Kumar 	}
17405efdd5cfSKaran Tilak Kumar 
17415efdd5cfSKaran Tilak Kumar 	while (tport->flags & FNIC_FDLS_NVME_TPORT_CLEANUP_PENDING) {
17425efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
17435efdd5cfSKaran Tilak Kumar 		msleep(2000);
17445efdd5cfSKaran Tilak Kumar 		spin_lock_irqsave(&fnic->fnic_lock, flags);
17455efdd5cfSKaran Tilak Kumar 	}
17465efdd5cfSKaran Tilak Kumar 
17475efdd5cfSKaran Tilak Kumar 	list_del(&tport->links);
17485efdd5cfSKaran Tilak Kumar 
17495efdd5cfSKaran Tilak Kumar 	if (tport->tport_del_done) {
17505efdd5cfSKaran Tilak Kumar 		tport->flags |= FNIC_TPORT_CAN_BE_FREED;
17515efdd5cfSKaran Tilak Kumar 		complete(tport->tport_del_done);
17525efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
17535efdd5cfSKaran Tilak Kumar 		return;
17545efdd5cfSKaran Tilak Kumar 	}
17555efdd5cfSKaran Tilak Kumar 
17565efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
17575efdd5cfSKaran Tilak Kumar 	kfree(tport);
17585efdd5cfSKaran Tilak Kumar }
17595efdd5cfSKaran Tilak Kumar 
17605efdd5cfSKaran Tilak Kumar int nvfnic_create_queue(struct nvme_fc_local_port *lport,
17615efdd5cfSKaran Tilak Kumar 		    unsigned int idx, u16 size, void **handle)
17625efdd5cfSKaran Tilak Kumar {
17635efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = (struct fnic_iport_s *)lport->private;
17645efdd5cfSKaran Tilak Kumar 	struct fnic *fnic  = iport->fnic;
17655efdd5cfSKaran Tilak Kumar 
17665efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_DEBUG, fnic,
17675efdd5cfSKaran Tilak Kumar 		      "iport:0x%x queue:%d size:%d\n", iport->fcid, idx, size);
17685efdd5cfSKaran Tilak Kumar 
17695efdd5cfSKaran Tilak Kumar 	if (idx > fnic->wq_copy_count)
17705efdd5cfSKaran Tilak Kumar 		return -EINVAL;
17715efdd5cfSKaran Tilak Kumar 
17725efdd5cfSKaran Tilak Kumar 	if (idx == 0) {
17735efdd5cfSKaran Tilak Kumar 		/* Admin queue */
17745efdd5cfSKaran Tilak Kumar 		*handle = &fnic->hw_copy_wq[0];
17755efdd5cfSKaran Tilak Kumar 	} else {
17765efdd5cfSKaran Tilak Kumar 		/* IO queues */
17775efdd5cfSKaran Tilak Kumar 		*handle = &fnic->hw_copy_wq[idx-1];
17785efdd5cfSKaran Tilak Kumar 	}
17795efdd5cfSKaran Tilak Kumar 
17805efdd5cfSKaran Tilak Kumar 	return 0;
17815efdd5cfSKaran Tilak Kumar }
17825efdd5cfSKaran Tilak Kumar 
17835efdd5cfSKaran Tilak Kumar void nvfnic_ls_req_abort(struct nvme_fc_local_port *lport,
17845efdd5cfSKaran Tilak Kumar 		   struct nvme_fc_remote_port *rport,
17855efdd5cfSKaran Tilak Kumar 		   struct nvmefc_ls_req *lsreq)
17865efdd5cfSKaran Tilak Kumar {
17875efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = lport->private;
17885efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
17895efdd5cfSKaran Tilak Kumar 	struct fnic_tport_s *tport;
17905efdd5cfSKaran Tilak Kumar 	struct nvfnic_ls_req *nvfnic_ls_req;
1791d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
17925efdd5cfSKaran Tilak Kumar 	uint16_t oxid;
17935efdd5cfSKaran Tilak Kumar 	int timeout;
1794f06ee33dSKaran Tilak Kumar 	int ret;
17955efdd5cfSKaran Tilak Kumar 
17965efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
17975efdd5cfSKaran Tilak Kumar 
17985efdd5cfSKaran Tilak Kumar 	tport = (struct fnic_tport_s *) rport->private;
17995efdd5cfSKaran Tilak Kumar 	/* find the request */
18005efdd5cfSKaran Tilak Kumar 	nvfnic_ls_req = lsreq->private;
18015efdd5cfSKaran Tilak Kumar 
18025efdd5cfSKaran Tilak Kumar 	if (nvfnic_ls_req == NULL) {
18035efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
18045efdd5cfSKaran Tilak Kumar 			      "0x%x null lsreq already scheduled for abort\n",
18055efdd5cfSKaran Tilak Kumar 			      iport->fcid);
18065efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
18075efdd5cfSKaran Tilak Kumar 		return;
18085efdd5cfSKaran Tilak Kumar 	}
18095efdd5cfSKaran Tilak Kumar 
18105efdd5cfSKaran Tilak Kumar 	if (nvfnic_ls_req->state == FNIC_LS_REQ_CMD_ABTS_PENDING) {
18115efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
18125efdd5cfSKaran Tilak Kumar 			      "0x%x lsreq 0x%x already scheduled for abort\n",
18135efdd5cfSKaran Tilak Kumar 			      iport->fcid, nvfnic_ls_req->oxid);
18145efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
18155efdd5cfSKaran Tilak Kumar 		return;
18165efdd5cfSKaran Tilak Kumar 	}
18175efdd5cfSKaran Tilak Kumar 
18185efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic,
18195efdd5cfSKaran Tilak Kumar 		      "0x%x lsreq 0x%x abts\n",
18205efdd5cfSKaran Tilak Kumar 		      iport->fcid, nvfnic_ls_req->oxid);
18215efdd5cfSKaran Tilak Kumar 
18225efdd5cfSKaran Tilak Kumar 	nvfnic_ls_req->state = FNIC_LS_REQ_CMD_ABTS_STARTED;
18235efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
18245efdd5cfSKaran Tilak Kumar 	timer_delete_sync(&nvfnic_ls_req->ls_req_timer);
18255efdd5cfSKaran Tilak Kumar 
18265efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
18275efdd5cfSKaran Tilak Kumar 	nvfnic_ls_req = lsreq->private;
18285efdd5cfSKaran Tilak Kumar 
18295efdd5cfSKaran Tilak Kumar 	if ((nvfnic_ls_req == NULL) ||
18305efdd5cfSKaran Tilak Kumar 	    (nvfnic_ls_req->state == FNIC_LS_REQ_CMD_ABTS_PENDING)) {
18315efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
18325efdd5cfSKaran Tilak Kumar 			      "lsreq timeout raced with midlayer abort\n");
18335efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
18345efdd5cfSKaran Tilak Kumar 		return;
18355efdd5cfSKaran Tilak Kumar 	}
18365efdd5cfSKaran Tilak Kumar 
18375efdd5cfSKaran Tilak Kumar 	/* Basic validations of the state */
18385efdd5cfSKaran Tilak Kumar 	if (!nvfnic_transport_ready(iport, tport)) {
18395efdd5cfSKaran Tilak Kumar 		/* If iport or tport offline, it will be handled from that event */
18405efdd5cfSKaran Tilak Kumar 		oxid = nvfnic_ls_req->oxid;
18415efdd5cfSKaran Tilak Kumar 		lsreq->private = NULL;
18425efdd5cfSKaran Tilak Kumar 		list_del(&nvfnic_ls_req->list);
18435efdd5cfSKaran Tilak Kumar 		fdls_free_oxid(iport, oxid, &nvfnic_ls_req->oxid);
18445efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
18455efdd5cfSKaran Tilak Kumar 		lsreq->done(lsreq, -ENXIO);
18465efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
18475efdd5cfSKaran Tilak Kumar 				"nvfnic_lsreq_abort transport not ready\n");
18485efdd5cfSKaran Tilak Kumar 		return;
18495efdd5cfSKaran Tilak Kumar 	}
18505efdd5cfSKaran Tilak Kumar 
18515efdd5cfSKaran Tilak Kumar 	/* Mark the state and flags */
18525efdd5cfSKaran Tilak Kumar 	nvfnic_ls_req->state = FNIC_LS_REQ_CMD_ABTS_PENDING;
1853d25a557dSKaran Tilak Kumar 	atomic64_inc(&fnic_stats->nvme_stats.nvme_ls_aborts);
1854f06ee33dSKaran Tilak Kumar 	oxid = nvfnic_ls_req->oxid;
1855f06ee33dSKaran Tilak Kumar 
1856f06ee33dSKaran Tilak Kumar 	ret = fdls_send_ls_req_abts(iport, tport, oxid);
1857f06ee33dSKaran Tilak Kumar 	if (!ret) {
18585efdd5cfSKaran Tilak Kumar 		timeout = FNIC_LS_REQ_TMO_MSECS(lsreq->timeout);
18595efdd5cfSKaran Tilak Kumar 		mod_timer(&nvfnic_ls_req->ls_req_timer,
18605efdd5cfSKaran Tilak Kumar 			  round_jiffies(jiffies + msecs_to_jiffies(timeout)));
18615efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
1862f06ee33dSKaran Tilak Kumar 		return;
1863f06ee33dSKaran Tilak Kumar 	}
1864f06ee33dSKaran Tilak Kumar 
1865f06ee33dSKaran Tilak Kumar 	if (!nvfnic_ls_req_cleanup(iport, lsreq, oxid)) {
1866f06ee33dSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
1867f06ee33dSKaran Tilak Kumar 		return;
1868f06ee33dSKaran Tilak Kumar 	}
1869f06ee33dSKaran Tilak Kumar 
1870f06ee33dSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
1871f06ee33dSKaran Tilak Kumar 	lsreq->done(lsreq, -EAGAIN);
18725efdd5cfSKaran Tilak Kumar }
18735efdd5cfSKaran Tilak Kumar 
18745efdd5cfSKaran Tilak Kumar bool nvfnic_queue_abort_io_req(struct fnic *fnic, int tag,
18755efdd5cfSKaran Tilak Kumar 			 u32 task_req, struct fnic_io_req *io_req)
18765efdd5cfSKaran Tilak Kumar {
18775efdd5cfSKaran Tilak Kumar 	int idx;
18785efdd5cfSKaran Tilak Kumar 	unsigned long flags;
1879d25a557dSKaran Tilak Kumar 	struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats;
18805efdd5cfSKaran Tilak Kumar 
18815efdd5cfSKaran Tilak Kumar 	idx = io_req->wq - &fnic->hw_copy_wq[0];
18825efdd5cfSKaran Tilak Kumar 
18835efdd5cfSKaran Tilak Kumar 	atomic_inc(&fnic->in_flight);
18845efdd5cfSKaran Tilak Kumar 
18855efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->wq_copy_lock[idx], flags);
18865efdd5cfSKaran Tilak Kumar 
18875efdd5cfSKaran Tilak Kumar 	if (vnic_wq_copy_desc_avail(io_req->wq) <= fnic->wq_copy_desc_low[idx])
18885efdd5cfSKaran Tilak Kumar 		free_wq_copy_descs(fnic, io_req->wq, idx);
18895efdd5cfSKaran Tilak Kumar 
18905efdd5cfSKaran Tilak Kumar 	if (!vnic_wq_copy_desc_avail(io_req->wq)) {
18915efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->wq_copy_lock[idx], flags);
18925efdd5cfSKaran Tilak Kumar 		atomic_dec(&fnic->in_flight);
18935efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
18945efdd5cfSKaran Tilak Kumar 				"tag 0x%x failure: no descriptors\n", tag);
1895d25a557dSKaran Tilak Kumar 		atomic64_inc(&misc_stats->abts_cpwq_alloc_failures);
18965efdd5cfSKaran Tilak Kumar 		return false;
18975efdd5cfSKaran Tilak Kumar 	}
18985efdd5cfSKaran Tilak Kumar 	fnic_queue_wq_copy_desc_itmf(io_req->wq, tag | FNIC_TAG_ABORT,
18995efdd5cfSKaran Tilak Kumar 				     0, task_req, tag, NULL, io_req->port_id,
19005efdd5cfSKaran Tilak Kumar 				     fnic->config.ra_tov, fnic->config.ed_tov);
19015efdd5cfSKaran Tilak Kumar 
1902d25a557dSKaran Tilak Kumar 	atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs);
1903d25a557dSKaran Tilak Kumar 	if (atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs) >
1904d25a557dSKaran Tilak Kumar 	    atomic64_read(&fnic->fnic_stats.fw_stats.max_fw_reqs))
1905d25a557dSKaran Tilak Kumar 		atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs,
1906d25a557dSKaran Tilak Kumar 			     atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs));
19075efdd5cfSKaran Tilak Kumar 
19085efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->wq_copy_lock[idx], flags);
19095efdd5cfSKaran Tilak Kumar 	atomic_dec(&fnic->in_flight);
19105efdd5cfSKaran Tilak Kumar 
19115efdd5cfSKaran Tilak Kumar 	return true;
19125efdd5cfSKaran Tilak Kumar }
19135efdd5cfSKaran Tilak Kumar 
19145efdd5cfSKaran Tilak Kumar void nvfnic_fcpio_abort(struct nvme_fc_local_port *lport,
19155efdd5cfSKaran Tilak Kumar 			struct nvme_fc_remote_port *rport,
19165efdd5cfSKaran Tilak Kumar 			void *hw_queue_handle, struct nvmefc_fcp_req *fcp_req)
19175efdd5cfSKaran Tilak Kumar {
19185efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = lport->private;
19195efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
19205efdd5cfSKaran Tilak Kumar 	struct nvme_fc_cmd_iu *cmd_iu = fcp_req->cmdaddr;
19215efdd5cfSKaran Tilak Kumar 	struct fnic_io_req *io_req = (struct fnic_io_req *)fcp_req->private;
19225efdd5cfSKaran Tilak Kumar 	unsigned int tag = io_req->tag;
1923d25a557dSKaran Tilak Kumar 	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
1924d25a557dSKaran Tilak Kumar 	struct abort_stats *abts_stats;
19255efdd5cfSKaran Tilak Kumar 	unsigned long flags = 0;
1926d25a557dSKaran Tilak Kumar 	unsigned long abt_issued_time;
19275efdd5cfSKaran Tilak Kumar 	unsigned int task_req;
19285efdd5cfSKaran Tilak Kumar 	enum fnic_ioreq_state old_ioreq_state;
1929d25a557dSKaran Tilak Kumar 	unsigned long num_ios_waitq, waitq_2sec, waitq_max_time;
19305efdd5cfSKaran Tilak Kumar 
19315efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, flags);
19325efdd5cfSKaran Tilak Kumar 
19335efdd5cfSKaran Tilak Kumar 	if (io_req->tag == FNIC_NVME_NO_FREE_TAG) {
19345efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
19355efdd5cfSKaran Tilak Kumar 			      "tag: (0x%x) tport_fcid: 0x%x\n",
19365efdd5cfSKaran Tilak Kumar 			      io_req->tag, io_req->tport->fcid);
19375efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
19385efdd5cfSKaran Tilak Kumar 		return;
19395efdd5cfSKaran Tilak Kumar 	}
19405efdd5cfSKaran Tilak Kumar 
19415efdd5cfSKaran Tilak Kumar 	if (io_req != nvfnic_find_io_req_by_tag(fnic, io_req->tag)) {
19425efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
19435efdd5cfSKaran Tilak Kumar 			      "cmd tag freed or not issued:0x%x sn:0x%08x\n",
19445efdd5cfSKaran Tilak Kumar 			      io_req->tag, be32_to_cpu(cmd_iu->csn));
1945d25a557dSKaran Tilak Kumar 		num_ios_waitq =
1946d25a557dSKaran Tilak Kumar 		    atomic64_read(&fnic_stats->io_stats.nvme_num_ios_in_waitq);
1947d25a557dSKaran Tilak Kumar 		waitq_2sec =
1948d25a557dSKaran Tilak Kumar 		    atomic64_read(&fnic_stats->io_stats.nvme_ios_in_waitq_3000_msec);
1949d25a557dSKaran Tilak Kumar 		waitq_max_time =
1950d25a557dSKaran Tilak Kumar 		    atomic64_read(&fnic_stats->io_stats.nvme_ios_in_waitq_max_time);
1951d25a557dSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
1952d25a557dSKaran Tilak Kumar 			      "waitq:%ld waitq_2sec:%ld max_wait:%ld\n",
1953d25a557dSKaran Tilak Kumar 			      num_ios_waitq, waitq_2sec, waitq_max_time);
19545efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
19555efdd5cfSKaran Tilak Kumar 		return;
19565efdd5cfSKaran Tilak Kumar 	}
19575efdd5cfSKaran Tilak Kumar 
19585efdd5cfSKaran Tilak Kumar 	if (io_req->cmd_state == FNIC_IOREQ_CMD_COMPLETE) {
19595efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
19605efdd5cfSKaran Tilak Kumar 			      "IO already completed before abort: 0x%x\n", tag);
19615efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
19625efdd5cfSKaran Tilak Kumar 		return;
19635efdd5cfSKaran Tilak Kumar 	}
19645efdd5cfSKaran Tilak Kumar 
19655efdd5cfSKaran Tilak Kumar 	if ((io_req->cmd_state == FNIC_IOREQ_ABTS_PENDING) ||
19665efdd5cfSKaran Tilak Kumar 	    (io_req->cmd_state == FNIC_DEV_RST_TERM_ISSUED)) {
19675efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic, "abort already pending %d\n",
19685efdd5cfSKaran Tilak Kumar 			      tag);
19695efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
19705efdd5cfSKaran Tilak Kumar 		return;
19715efdd5cfSKaran Tilak Kumar 	}
19725efdd5cfSKaran Tilak Kumar 
19735efdd5cfSKaran Tilak Kumar 	if (io_req->cmd_state != FNIC_IOREQ_CMD_PENDING) {
19745efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
19755efdd5cfSKaran Tilak Kumar 			      "io_req completed or aborted for tag:0x%x\n",
19765efdd5cfSKaran Tilak Kumar 			      tag);
19775efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
19785efdd5cfSKaran Tilak Kumar 		return;
19795efdd5cfSKaran Tilak Kumar 	}
19805efdd5cfSKaran Tilak Kumar 
19815efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic, "in abort cmd_sn:%08x %llx tag: 0x%x\n",
19825efdd5cfSKaran Tilak Kumar 		      be32_to_cpu(cmd_iu->csn),
19835efdd5cfSKaran Tilak Kumar 		      le64_to_cpu(cmd_iu->sqe.rw.slba), io_req->tag);
19845efdd5cfSKaran Tilak Kumar 
19855efdd5cfSKaran Tilak Kumar 	if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED))) {
19865efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
19875efdd5cfSKaran Tilak Kumar 			      "abort tag:0x%x returned during fw reset\n",
19885efdd5cfSKaran Tilak Kumar 			      io_req->tag);
19895efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
19905efdd5cfSKaran Tilak Kumar 		return;
19915efdd5cfSKaran Tilak Kumar 	}
19925efdd5cfSKaran Tilak Kumar 	atomic_inc(&fnic->in_flight);
19935efdd5cfSKaran Tilak Kumar 
19945efdd5cfSKaran Tilak Kumar 	if (fdls_tport_is_offline(io_req->tport) ||
19955efdd5cfSKaran Tilak Kumar 	    (io_req->cmd_state == FNIC_IOREQ_RESET_TERM)) {
19965efdd5cfSKaran Tilak Kumar 		task_req = FCPIO_ITMF_ABT_TASK_TERM;
19975efdd5cfSKaran Tilak Kumar 	} else {
19985efdd5cfSKaran Tilak Kumar 		task_req = FCPIO_ITMF_ABT_TASK;
19995efdd5cfSKaran Tilak Kumar 	}
20005efdd5cfSKaran Tilak Kumar 
2001d25a557dSKaran Tilak Kumar 	abts_stats = &fnic->fnic_stats.abts_stats;
2002d25a557dSKaran Tilak Kumar 	atomic64_inc(&abts_stats->aborts);
20035efdd5cfSKaran Tilak Kumar 
2004d25a557dSKaran Tilak Kumar 	abt_issued_time = jiffies_to_msecs(jiffies - io_req->start_time);
2005d25a557dSKaran Tilak Kumar 	if (abt_issued_time <= 6000)
2006d25a557dSKaran Tilak Kumar 		atomic64_inc(&abts_stats->abort_issued_btw_0_to_6_sec);
2007d25a557dSKaran Tilak Kumar 	else if (abt_issued_time > 6000 && abt_issued_time <= 20000)
2008d25a557dSKaran Tilak Kumar 		atomic64_inc(&abts_stats->abort_issued_btw_6_to_20_sec);
2009d25a557dSKaran Tilak Kumar 	else if (abt_issued_time > 20000 && abt_issued_time <= 30000)
2010d25a557dSKaran Tilak Kumar 		atomic64_inc(&abts_stats->abort_issued_btw_20_to_30_sec);
2011d25a557dSKaran Tilak Kumar 	else if (abt_issued_time > 30000 && abt_issued_time <= 40000)
2012d25a557dSKaran Tilak Kumar 		atomic64_inc(&abts_stats->abort_issued_btw_30_to_40_sec);
2013d25a557dSKaran Tilak Kumar 	else if (abt_issued_time > 40000 && abt_issued_time <= 50000)
2014d25a557dSKaran Tilak Kumar 		atomic64_inc(&abts_stats->abort_issued_btw_40_to_50_sec);
2015d25a557dSKaran Tilak Kumar 	else if (abt_issued_time > 50000 && abt_issued_time <= 60000)
2016d25a557dSKaran Tilak Kumar 		atomic64_inc(&abts_stats->abort_issued_btw_50_to_60_sec);
2017d25a557dSKaran Tilak Kumar 	else
2018d25a557dSKaran Tilak Kumar 		atomic64_inc(&abts_stats->abort_issued_greater_than_60_sec);
20195efdd5cfSKaran Tilak Kumar 
20205efdd5cfSKaran Tilak Kumar 	old_ioreq_state = io_req->cmd_state;
20215efdd5cfSKaran Tilak Kumar 	io_req->cmd_state = FNIC_IOREQ_ABTS_PENDING;
20225efdd5cfSKaran Tilak Kumar 	io_req->abts_state = FCPIO_INVALID_CODE;
20235efdd5cfSKaran Tilak Kumar 
20245efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
20255efdd5cfSKaran Tilak Kumar 
20265efdd5cfSKaran Tilak Kumar 	if (!nvfnic_queue_abort_io_req(fnic, io_req->tag, task_req, io_req)) {
20275efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
20285efdd5cfSKaran Tilak Kumar 			      "Abort io req queue failed\n");
20295efdd5cfSKaran Tilak Kumar 		spin_lock_irqsave(&fnic->fnic_lock, flags);
20305efdd5cfSKaran Tilak Kumar 		io_req->cmd_state = old_ioreq_state;
20315efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
20325efdd5cfSKaran Tilak Kumar 	}
20335efdd5cfSKaran Tilak Kumar 	atomic_dec(&fnic->in_flight);
20345efdd5cfSKaran Tilak Kumar }
20355efdd5cfSKaran Tilak Kumar 
20365efdd5cfSKaran Tilak Kumar struct
20375efdd5cfSKaran Tilak Kumar nvme_fc_port_template nvfnic_port = {
20385efdd5cfSKaran Tilak Kumar 	.localport_delete = nvfnic_local_port_delete,
20395efdd5cfSKaran Tilak Kumar 	.remoteport_delete = nvfnic_remote_port_delete,
20405efdd5cfSKaran Tilak Kumar 	.create_queue = nvfnic_create_queue,
20415efdd5cfSKaran Tilak Kumar 	.delete_queue = NULL,
204239bf0755SKaran Tilak Kumar 	.ls_req = nvfnic_ls_req_send,
20435efdd5cfSKaran Tilak Kumar 	.ls_abort = nvfnic_ls_req_abort,
20445efdd5cfSKaran Tilak Kumar 	.fcp_io = nvfnic_fcpio_send,
20455efdd5cfSKaran Tilak Kumar 	.fcp_abort = nvfnic_fcpio_abort,
20465efdd5cfSKaran Tilak Kumar 	.max_hw_queues = 1,
20475efdd5cfSKaran Tilak Kumar 	.max_sgl_segments = 256,
20485efdd5cfSKaran Tilak Kumar 	.max_dif_sgl_segments = 64,
20495efdd5cfSKaran Tilak Kumar 	.dma_boundary = 0xFFFFFFFF,
20505efdd5cfSKaran Tilak Kumar 	.local_priv_sz = sizeof(struct fnic_iport_s *),
20515efdd5cfSKaran Tilak Kumar 	.remote_priv_sz = sizeof(struct fnic_tport_s *),
20525efdd5cfSKaran Tilak Kumar 	.lsrqst_priv_sz = sizeof(struct nvfnic_ls_req),
20535efdd5cfSKaran Tilak Kumar 	.fcprqst_priv_sz = sizeof(struct fnic_io_req),
20545efdd5cfSKaran Tilak Kumar };
20555efdd5cfSKaran Tilak Kumar 
20565efdd5cfSKaran Tilak Kumar void nvfnic_flush_nvme_io_list(struct fnic *fnic)
20575efdd5cfSKaran Tilak Kumar {
20585efdd5cfSKaran Tilak Kumar 	queue_work(fnic_cmpl_queue, &fnic->nvme_io_cmpl_work);
20595efdd5cfSKaran Tilak Kumar 	flush_work(&fnic->nvme_io_cmpl_work);
20605efdd5cfSKaran Tilak Kumar }
20615efdd5cfSKaran Tilak Kumar 
20625efdd5cfSKaran Tilak Kumar void nvfnic_nvme_iodone_work(struct work_struct *work)
20635efdd5cfSKaran Tilak Kumar {
20645efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = container_of(work, struct fnic, nvme_io_cmpl_work);
20655efdd5cfSKaran Tilak Kumar 	struct llist_node *llnode;
20665efdd5cfSKaran Tilak Kumar 	struct fnic_io_req *io_req, *tmp;
20675efdd5cfSKaran Tilak Kumar 
20685efdd5cfSKaran Tilak Kumar 	llnode = llist_del_all(&fnic->nvme_io_event_llist);
20695efdd5cfSKaran Tilak Kumar 	llist_for_each_entry_safe(io_req, tmp, llnode, nvfnic_io_cmpl) {
20705efdd5cfSKaran Tilak Kumar 		atomic_dec(&fnic->nvme_io_event_queued);
2071d25a557dSKaran Tilak Kumar 		atomic64_dec(&fnic->fnic_stats.io_stats.nvme_num_ios_in_waitq);
20725efdd5cfSKaran Tilak Kumar 		io_req->fcp_req->done(io_req->fcp_req);
20735efdd5cfSKaran Tilak Kumar 	}
20745efdd5cfSKaran Tilak Kumar }
20755efdd5cfSKaran Tilak Kumar 
20765efdd5cfSKaran Tilak Kumar void nvfnic_exch_reset(struct fnic_iport_s *iport, struct fnic_tport_s *tport)
20775efdd5cfSKaran Tilak Kumar {
20785efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_DEBUG, iport->fnic,
20795efdd5cfSKaran Tilak Kumar 			"0x%x: Exchange reset scheduled for tport: 0x%x\n",
20805efdd5cfSKaran Tilak Kumar 		    iport->fcid, tport->fcid);
20815efdd5cfSKaran Tilak Kumar 
20825efdd5cfSKaran Tilak Kumar 	nvfnic_terminate_tport_ls_reqs(iport->fnic, tport);
20835efdd5cfSKaran Tilak Kumar 	nvfnic_terminate_tport_ios(iport->fnic, tport);
20845efdd5cfSKaran Tilak Kumar }
20855efdd5cfSKaran Tilak Kumar 
20865efdd5cfSKaran Tilak Kumar void nvfnic_delete_tport(struct fnic_iport_s *iport,
20875efdd5cfSKaran Tilak Kumar 						struct fnic_tport_s *tport,
20885efdd5cfSKaran Tilak Kumar 						unsigned long flags)
20895efdd5cfSKaran Tilak Kumar {
20905efdd5cfSKaran Tilak Kumar 	struct fnic *fnic = iport->fnic;
20915efdd5cfSKaran Tilak Kumar 	int ret;
20925efdd5cfSKaran Tilak Kumar 	unsigned int time_wait = FNIC_NVME_TPORT_REMOVE_WAIT;
20935efdd5cfSKaran Tilak Kumar 	unsigned int time_remain;
20945efdd5cfSKaran Tilak Kumar 	DECLARE_COMPLETION_ONSTACK(tm_done);
20955efdd5cfSKaran Tilak Kumar 	unsigned int fcid;
20965efdd5cfSKaran Tilak Kumar 	int count = 0;
20975efdd5cfSKaran Tilak Kumar 
20985efdd5cfSKaran Tilak Kumar 	if (!tport)
20995efdd5cfSKaran Tilak Kumar 		return;
21005efdd5cfSKaran Tilak Kumar 
21015efdd5cfSKaran Tilak Kumar 	fcid = tport->fcid;
21025efdd5cfSKaran Tilak Kumar 	fdls_set_tport_state(tport, FDLS_TGT_STATE_OFFLINE);
21035efdd5cfSKaran Tilak Kumar 
21045efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_DEBUG, fnic,
21055efdd5cfSKaran Tilak Kumar 			"0x%x: scheduled deletion for tport: 0x%x\n",
21065efdd5cfSKaran Tilak Kumar 		    iport->fcid, tport->fcid);
21075efdd5cfSKaran Tilak Kumar 
21085efdd5cfSKaran Tilak Kumar 	if (!(tport->flags & FNIC_FDLS_NVME_REGISTERED)) {
21095efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
21105efdd5cfSKaran Tilak Kumar 			"0x%x: tport: 0x%x not registered. Freeing\n",
21115efdd5cfSKaran Tilak Kumar 		    iport->fcid, tport->fcid);
21125efdd5cfSKaran Tilak Kumar 		list_del(&tport->links);
21135efdd5cfSKaran Tilak Kumar 		kfree(tport);
21145efdd5cfSKaran Tilak Kumar 		return;
21155efdd5cfSKaran Tilak Kumar 	}
21165efdd5cfSKaran Tilak Kumar 
21175efdd5cfSKaran Tilak Kumar 	tport->tport_del_done = &tm_done;
21185efdd5cfSKaran Tilak Kumar 
21195efdd5cfSKaran Tilak Kumar 	tport->flags |= FNIC_FDLS_TPORT_DELETED;
21205efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
21215efdd5cfSKaran Tilak Kumar 	ret = nvme_fc_unregister_remoteport(tport->nv_rport);
21225efdd5cfSKaran Tilak Kumar 	if (ret) {
21235efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
21245efdd5cfSKaran Tilak Kumar 			    "tport: 0x%x unregister failed %d\n",
21255efdd5cfSKaran Tilak Kumar 			    tport->fcid, ret);
21265efdd5cfSKaran Tilak Kumar 
21275efdd5cfSKaran Tilak Kumar 		nvfnic_terminate_tport_ls_reqs(fnic, tport);
21285efdd5cfSKaran Tilak Kumar 
21295efdd5cfSKaran Tilak Kumar 		spin_lock_irqsave(&fnic->fnic_lock, flags);
21305efdd5cfSKaran Tilak Kumar 		tport->tport_del_done = NULL;
21315efdd5cfSKaran Tilak Kumar 		if (tport->nv_rport && tport->nv_rport->private == tport)
21325efdd5cfSKaran Tilak Kumar 			tport->nv_rport->private = NULL;
21335efdd5cfSKaran Tilak Kumar 		list_del(&tport->links);
21345efdd5cfSKaran Tilak Kumar 		kfree(tport);
21355efdd5cfSKaran Tilak Kumar 		return;
21365efdd5cfSKaran Tilak Kumar 	}
21375efdd5cfSKaran Tilak Kumar 	time_remain = wait_for_completion_timeout(tport->tport_del_done,
21385efdd5cfSKaran Tilak Kumar 				msecs_to_jiffies(time_wait));
21395efdd5cfSKaran Tilak Kumar 
21405efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_DEBUG, fnic,
21415efdd5cfSKaran Tilak Kumar 		      "tport: 0x%x wait for deletion done\n",
21425efdd5cfSKaran Tilak Kumar 		      tport->fcid);
21435efdd5cfSKaran Tilak Kumar 
21445efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, flags);
21455efdd5cfSKaran Tilak Kumar 	tport->tport_del_done = NULL;
21465efdd5cfSKaran Tilak Kumar 
21475efdd5cfSKaran Tilak Kumar 	if (!time_remain) {
21485efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_ERR, fnic,
21495efdd5cfSKaran Tilak Kumar 			    "tport: 0x%x nvme midlayer completion timed out\n",
21505efdd5cfSKaran Tilak Kumar 			    tport->fcid);
21515efdd5cfSKaran Tilak Kumar 
21525efdd5cfSKaran Tilak Kumar 		if (tport->flags & FNIC_TPORT_CAN_BE_FREED) {
21535efdd5cfSKaran Tilak Kumar 			kfree(tport);
21545efdd5cfSKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_INFO, fnic,
21555efdd5cfSKaran Tilak Kumar 			      "tport: 0x%x delete complete\n", fcid);
21565efdd5cfSKaran Tilak Kumar 			return;
21575efdd5cfSKaran Tilak Kumar 		}
21585efdd5cfSKaran Tilak Kumar 
21595efdd5cfSKaran Tilak Kumar 		tport->flags |= FNIC_FDLS_NVME_TPORT_CLEANUP_PENDING;
21605efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
21615efdd5cfSKaran Tilak Kumar 		nvfnic_cleanup_tport_io(fnic, tport);
21625efdd5cfSKaran Tilak Kumar 		spin_lock_irqsave(&fnic->fnic_lock, flags);
21635efdd5cfSKaran Tilak Kumar 		tport->flags &= ~FNIC_FDLS_NVME_TPORT_CLEANUP_PENDING;
21645efdd5cfSKaran Tilak Kumar 		return;
21655efdd5cfSKaran Tilak Kumar 	}
21665efdd5cfSKaran Tilak Kumar 	while (!(tport->flags & FNIC_TPORT_CAN_BE_FREED) &&
21675efdd5cfSKaran Tilak Kumar 	       (count < FNIC_TPORT_CLEANUP_WAIT_COUNT)) {
21685efdd5cfSKaran Tilak Kumar 		count++;
21695efdd5cfSKaran Tilak Kumar 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
21705efdd5cfSKaran Tilak Kumar 		msleep(2000);
21715efdd5cfSKaran Tilak Kumar 		spin_lock_irqsave(&fnic->fnic_lock, flags);
21725efdd5cfSKaran Tilak Kumar 	}
21735efdd5cfSKaran Tilak Kumar 	if (tport->flags & FNIC_TPORT_CAN_BE_FREED)
21745efdd5cfSKaran Tilak Kumar 		kfree(tport);
21755efdd5cfSKaran Tilak Kumar 
21765efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic,
21775efdd5cfSKaran Tilak Kumar 		      "tport: 0x%x delete complete\n", fcid);
21785efdd5cfSKaran Tilak Kumar }
21795efdd5cfSKaran Tilak Kumar 
21805efdd5cfSKaran Tilak Kumar int nvfnic_add_tport(struct fnic *fnic, struct fnic_tport_s *tport,
21815efdd5cfSKaran Tilak Kumar 		     unsigned long flags)
21825efdd5cfSKaran Tilak Kumar {
21835efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = &fnic->iport;
21845efdd5cfSKaran Tilak Kumar 	struct nvme_fc_port_info pinfo;
21855efdd5cfSKaran Tilak Kumar 	int ret = 0;
21865efdd5cfSKaran Tilak Kumar 
21875efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic,
21885efdd5cfSKaran Tilak Kumar 		      "Adding tport to nvme wwpn: 0x%llx\n",
21895efdd5cfSKaran Tilak Kumar 		      tport->wwpn);
21905efdd5cfSKaran Tilak Kumar 
21915efdd5cfSKaran Tilak Kumar 	memset(&pinfo, 0, sizeof(struct nvme_fc_port_info));
21925efdd5cfSKaran Tilak Kumar 
21935efdd5cfSKaran Tilak Kumar 	pinfo.port_name = tport->wwpn;
21945efdd5cfSKaran Tilak Kumar 	pinfo.node_name = tport->wwnn;
21955efdd5cfSKaran Tilak Kumar 	pinfo.port_role = FC_PORT_ROLE_NVME_DISCOVERY | FC_PORT_ROLE_NVME_TARGET;
21965efdd5cfSKaran Tilak Kumar 	pinfo.port_id = tport->fcid;
21975efdd5cfSKaran Tilak Kumar 	pinfo.dev_loss_tmo = nvme_dev_loss_tmo;
21985efdd5cfSKaran Tilak Kumar 
21995efdd5cfSKaran Tilak Kumar 	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
22005efdd5cfSKaran Tilak Kumar 	ret = nvme_fc_register_remoteport(iport->nv_lport, &pinfo,
22015efdd5cfSKaran Tilak Kumar 					  &tport->nv_rport);
22025efdd5cfSKaran Tilak Kumar 	spin_lock_irqsave(&fnic->fnic_lock, flags);
22035efdd5cfSKaran Tilak Kumar 	if (ret) {
22045efdd5cfSKaran Tilak Kumar 		FNIC_NVME_DBG(KERN_INFO, fnic,
22055efdd5cfSKaran Tilak Kumar 			    "Failed to register tport wwpn: 0x%llx ret: %d\n",
22065efdd5cfSKaran Tilak Kumar 			    tport->wwpn, ret);
22075efdd5cfSKaran Tilak Kumar 		return ret;
22085efdd5cfSKaran Tilak Kumar 	}
22095efdd5cfSKaran Tilak Kumar 	tport->flags |= FNIC_FDLS_NVME_REGISTERED;
22105efdd5cfSKaran Tilak Kumar 	tport->nv_rport->private = tport;
22115efdd5cfSKaran Tilak Kumar 
22125efdd5cfSKaran Tilak Kumar 	snprintf(tport->str_wwpn, sizeof(tport->str_wwpn), "0x%llx", tport->wwpn);
22135efdd5cfSKaran Tilak Kumar 	snprintf(tport->str_wwnn, sizeof(tport->str_wwnn), "0x%llx", tport->wwnn);
22145efdd5cfSKaran Tilak Kumar 	return ret;
22155efdd5cfSKaran Tilak Kumar }
22165efdd5cfSKaran Tilak Kumar 
22175efdd5cfSKaran Tilak Kumar int nvfnic_add_lport(struct fnic *fnic)
22185efdd5cfSKaran Tilak Kumar {
22195efdd5cfSKaran Tilak Kumar 	struct nvme_fc_port_info pinfo;
22205efdd5cfSKaran Tilak Kumar 	struct fnic_iport_s *iport = &fnic->iport;
22215efdd5cfSKaran Tilak Kumar 	int ret = 0;
22225efdd5cfSKaran Tilak Kumar 
22235efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic,
22245efdd5cfSKaran Tilak Kumar 		      "Adding lport nvme wwpn: 0x%llx\n",
22255efdd5cfSKaran Tilak Kumar 		      iport->wwpn);
22265efdd5cfSKaran Tilak Kumar 
22275efdd5cfSKaran Tilak Kumar 	pinfo.node_name = iport->wwnn;
22285efdd5cfSKaran Tilak Kumar 	pinfo.port_name = iport->wwpn;
22295efdd5cfSKaran Tilak Kumar 	pinfo.port_role = FC_PORT_ROLE_NVME_INITIATOR;
22305efdd5cfSKaran Tilak Kumar 	pinfo.port_id = iport->fcid;
22315efdd5cfSKaran Tilak Kumar 
22325efdd5cfSKaran Tilak Kumar 	nvfnic_reset_fcpio_tag_pool(iport);
22335efdd5cfSKaran Tilak Kumar 
22345efdd5cfSKaran Tilak Kumar 	if (!(iport->flags & FNIC_LPORT_NVME_REGISTERED)) {
22355efdd5cfSKaran Tilak Kumar 		iport->nv_tmpl = kzalloc_obj(struct nvme_fc_port_template, GFP_ATOMIC);
22365efdd5cfSKaran Tilak Kumar 		if (!iport->nv_tmpl) {
22375efdd5cfSKaran Tilak Kumar 			FNIC_FCS_DBG(KERN_INFO, fnic,
22385efdd5cfSKaran Tilak Kumar 				     "iport:0x%x NVMe tmpl alloc failed\n",
22395efdd5cfSKaran Tilak Kumar 				     iport->fcid);
22405efdd5cfSKaran Tilak Kumar 			return -ENOMEM;
22415efdd5cfSKaran Tilak Kumar 		}
22425efdd5cfSKaran Tilak Kumar 		memcpy(iport->nv_tmpl, &nvfnic_port,
22435efdd5cfSKaran Tilak Kumar 		       sizeof(struct nvme_fc_port_template));
22445efdd5cfSKaran Tilak Kumar 		iport->nv_tmpl->max_hw_queues = fnic->wq_copy_count;
22455efdd5cfSKaran Tilak Kumar 
22465efdd5cfSKaran Tilak Kumar 		ret = nvme_fc_register_localport(&pinfo, iport->nv_tmpl,
22475efdd5cfSKaran Tilak Kumar 						 &fnic->pdev->dev, &iport->nv_lport);
22485efdd5cfSKaran Tilak Kumar 		if (ret) {
22495efdd5cfSKaran Tilak Kumar 			FNIC_NVME_DBG(KERN_ERR, fnic,
22505efdd5cfSKaran Tilak Kumar 					"Failed to add wwpn: 0x%llx ret: %d\n",
22515efdd5cfSKaran Tilak Kumar 					iport->wwpn, ret);
22525efdd5cfSKaran Tilak Kumar 			kfree(iport->nv_tmpl);
22535efdd5cfSKaran Tilak Kumar 			return ret;
22545efdd5cfSKaran Tilak Kumar 		}
22555efdd5cfSKaran Tilak Kumar 		iport->flags |= FNIC_LPORT_NVME_REGISTERED;
22565efdd5cfSKaran Tilak Kumar 		iport->nv_lport->private = iport;
22575efdd5cfSKaran Tilak Kumar 	}
22585efdd5cfSKaran Tilak Kumar 
22595efdd5cfSKaran Tilak Kumar 	sprintf(iport->str_wwpn, "0x%llx", iport->wwpn);
22605efdd5cfSKaran Tilak Kumar 	sprintf(iport->str_wwnn, "0x%llx", iport->wwnn);
22615efdd5cfSKaran Tilak Kumar 
22625efdd5cfSKaran Tilak Kumar 	FNIC_NVME_DBG(KERN_INFO, fnic,
22635efdd5cfSKaran Tilak Kumar 		      "Successfully added lport wwpn: 0x%llx\n",
22645efdd5cfSKaran Tilak Kumar 		      iport->wwpn);
22655efdd5cfSKaran Tilak Kumar 	return 0;
22665efdd5cfSKaran Tilak Kumar }
22675efdd5cfSKaran Tilak Kumar 
22685efdd5cfSKaran Tilak Kumar #endif
2269