xref: /openbmc/linux/drivers/target/tcm_fc/tfc_io.c (revision d556546e)
13699d92aSKiran Patil /*
23699d92aSKiran Patil  * Copyright (c) 2010 Cisco Systems, Inc.
33699d92aSKiran Patil  *
43699d92aSKiran Patil  * Portions based on tcm_loop_fabric_scsi.c and libfc/fc_fcp.c
53699d92aSKiran Patil  *
63699d92aSKiran Patil  * Copyright (c) 2007 Intel Corporation. All rights reserved.
73699d92aSKiran Patil  * Copyright (c) 2008 Red Hat, Inc.  All rights reserved.
83699d92aSKiran Patil  * Copyright (c) 2008 Mike Christie
93699d92aSKiran Patil  * Copyright (c) 2009 Rising Tide, Inc.
103699d92aSKiran Patil  * Copyright (c) 2009 Linux-iSCSI.org
113699d92aSKiran Patil  * Copyright (c) 2009 Nicholas A. Bellinger <nab@linux-iscsi.org>
123699d92aSKiran Patil  *
133699d92aSKiran Patil  * This program is free software; you can redistribute it and/or modify it
143699d92aSKiran Patil  * under the terms and conditions of the GNU General Public License,
153699d92aSKiran Patil  * version 2, as published by the Free Software Foundation.
163699d92aSKiran Patil  *
173699d92aSKiran Patil  * This program is distributed in the hope it will be useful, but WITHOUT
183699d92aSKiran Patil  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
193699d92aSKiran Patil  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
203699d92aSKiran Patil  * more details.
213699d92aSKiran Patil  *
223699d92aSKiran Patil  * You should have received a copy of the GNU General Public License along with
233699d92aSKiran Patil  * this program; if not, write to the Free Software Foundation, Inc.,
243699d92aSKiran Patil  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
253699d92aSKiran Patil  */
263699d92aSKiran Patil 
273699d92aSKiran Patil /* XXX TBD some includes may be extraneous */
283699d92aSKiran Patil 
293699d92aSKiran Patil #include <linux/module.h>
303699d92aSKiran Patil #include <linux/moduleparam.h>
313699d92aSKiran Patil #include <linux/utsname.h>
323699d92aSKiran Patil #include <linux/init.h>
333699d92aSKiran Patil #include <linux/slab.h>
343699d92aSKiran Patil #include <linux/kthread.h>
353699d92aSKiran Patil #include <linux/types.h>
363699d92aSKiran Patil #include <linux/string.h>
373699d92aSKiran Patil #include <linux/configfs.h>
383699d92aSKiran Patil #include <linux/ctype.h>
393699d92aSKiran Patil #include <linux/hash.h>
406708bb27SAndy Grover #include <linux/ratelimit.h>
413699d92aSKiran Patil #include <asm/unaligned.h>
423699d92aSKiran Patil #include <scsi/scsi.h>
433699d92aSKiran Patil #include <scsi/scsi_host.h>
443699d92aSKiran Patil #include <scsi/scsi_device.h>
453699d92aSKiran Patil #include <scsi/scsi_cmnd.h>
463699d92aSKiran Patil #include <scsi/libfc.h>
473699d92aSKiran Patil #include <scsi/fc_encode.h>
483699d92aSKiran Patil 
493699d92aSKiran Patil #include <target/target_core_base.h>
50c4795fb2SChristoph Hellwig #include <target/target_core_fabric.h>
513699d92aSKiran Patil #include <target/target_core_configfs.h>
523699d92aSKiran Patil #include <target/configfs_macros.h>
533699d92aSKiran Patil 
543699d92aSKiran Patil #include "tcm_fc.h"
553699d92aSKiran Patil 
563699d92aSKiran Patil /*
573699d92aSKiran Patil  * Deliver read data back to initiator.
583699d92aSKiran Patil  * XXX TBD handle resource problems later.
593699d92aSKiran Patil  */
603699d92aSKiran Patil int ft_queue_data_in(struct se_cmd *se_cmd)
613699d92aSKiran Patil {
623699d92aSKiran Patil 	struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
633699d92aSKiran Patil 	struct fc_frame *fp = NULL;
643699d92aSKiran Patil 	struct fc_exch *ep;
653699d92aSKiran Patil 	struct fc_lport *lport;
66ec98f782SAndy Grover 	struct scatterlist *sg = NULL;
673699d92aSKiran Patil 	size_t remaining;
683699d92aSKiran Patil 	u32 f_ctl = FC_FC_EX_CTX | FC_FC_REL_OFF;
69ec98f782SAndy Grover 	u32 mem_off = 0;
703699d92aSKiran Patil 	u32 fh_off = 0;
713699d92aSKiran Patil 	u32 frame_off = 0;
723699d92aSKiran Patil 	size_t frame_len = 0;
73ec98f782SAndy Grover 	size_t mem_len = 0;
743699d92aSKiran Patil 	size_t tlen;
753699d92aSKiran Patil 	size_t off_in_page;
76ec98f782SAndy Grover 	struct page *page = NULL;
773699d92aSKiran Patil 	int use_sg;
783699d92aSKiran Patil 	int error;
793699d92aSKiran Patil 	void *page_addr;
803699d92aSKiran Patil 	void *from;
813699d92aSKiran Patil 	void *to = NULL;
823699d92aSKiran Patil 
83e1c40382SMark Rustad 	if (cmd->aborted)
84e1c40382SMark Rustad 		return 0;
85b3e5fe16SNicholas Bellinger 
86b3e5fe16SNicholas Bellinger 	if (se_cmd->scsi_status == SAM_STAT_TASK_SET_FULL)
87b3e5fe16SNicholas Bellinger 		goto queue_status;
88b3e5fe16SNicholas Bellinger 
893699d92aSKiran Patil 	ep = fc_seq_exch(cmd->seq);
903699d92aSKiran Patil 	lport = ep->lp;
913699d92aSKiran Patil 	cmd->seq = lport->tt.seq_start_next(cmd->seq);
923699d92aSKiran Patil 
933699d92aSKiran Patil 	remaining = se_cmd->data_length;
943699d92aSKiran Patil 
953699d92aSKiran Patil 	/*
9605d1c7c0SAndy Grover 	 * Setup to use first mem list entry, unless no data.
973699d92aSKiran Patil 	 */
98ec98f782SAndy Grover 	BUG_ON(remaining && !se_cmd->t_data_sg);
9905d1c7c0SAndy Grover 	if (remaining) {
100ec98f782SAndy Grover 		sg = se_cmd->t_data_sg;
101ec98f782SAndy Grover 		mem_len = sg->length;
102ec98f782SAndy Grover 		mem_off = sg->offset;
103ec98f782SAndy Grover 		page = sg_page(sg);
1043699d92aSKiran Patil 	}
1053699d92aSKiran Patil 
1063699d92aSKiran Patil 	/* no scatter/gather in skb for odd word length due to fc_seq_send() */
1073699d92aSKiran Patil 	use_sg = !(remaining % 4);
1083699d92aSKiran Patil 
1093699d92aSKiran Patil 	while (remaining) {
110d3682b1aSMark Rustad 		struct fc_seq *seq = cmd->seq;
111d3682b1aSMark Rustad 
112d3682b1aSMark Rustad 		if (!seq) {
113d3682b1aSMark Rustad 			pr_debug("%s: Command aborted, xid 0x%x\n",
114d3682b1aSMark Rustad 				 __func__, ep->xid);
115d3682b1aSMark Rustad 			break;
116d3682b1aSMark Rustad 		}
1173699d92aSKiran Patil 		if (!mem_len) {
118ec98f782SAndy Grover 			sg = sg_next(sg);
119ec98f782SAndy Grover 			mem_len = min((size_t)sg->length, remaining);
120ec98f782SAndy Grover 			mem_off = sg->offset;
121ec98f782SAndy Grover 			page = sg_page(sg);
1223699d92aSKiran Patil 		}
1233699d92aSKiran Patil 		if (!frame_len) {
1243699d92aSKiran Patil 			/*
1253699d92aSKiran Patil 			 * If lport's has capability of Large Send Offload LSO)
1263699d92aSKiran Patil 			 * , then allow 'frame_len' to be as big as 'lso_max'
1273699d92aSKiran Patil 			 * if indicated transfer length is >= lport->lso_max
1283699d92aSKiran Patil 			 */
1293699d92aSKiran Patil 			frame_len = (lport->seq_offload) ? lport->lso_max :
1303699d92aSKiran Patil 							  cmd->sess->max_frame;
1313699d92aSKiran Patil 			frame_len = min(frame_len, remaining);
1323699d92aSKiran Patil 			fp = fc_frame_alloc(lport, use_sg ? 0 : frame_len);
1333699d92aSKiran Patil 			if (!fp)
1343699d92aSKiran Patil 				return -ENOMEM;
1353699d92aSKiran Patil 			to = fc_frame_payload_get(fp, 0);
1363699d92aSKiran Patil 			fh_off = frame_off;
1373699d92aSKiran Patil 			frame_off += frame_len;
1383699d92aSKiran Patil 			/*
1393699d92aSKiran Patil 			 * Setup the frame's max payload which is used by base
1403699d92aSKiran Patil 			 * driver to indicate HW about max frame size, so that
1413699d92aSKiran Patil 			 * HW can do fragmentation appropriately based on
1423699d92aSKiran Patil 			 * "gso_max_size" of underline netdev.
1433699d92aSKiran Patil 			 */
1443699d92aSKiran Patil 			fr_max_payload(fp) = cmd->sess->max_frame;
1453699d92aSKiran Patil 		}
1463699d92aSKiran Patil 		tlen = min(mem_len, frame_len);
1473699d92aSKiran Patil 
1483699d92aSKiran Patil 		if (use_sg) {
1493699d92aSKiran Patil 			off_in_page = mem_off;
1503699d92aSKiran Patil 			BUG_ON(!page);
1513699d92aSKiran Patil 			get_page(page);
1523699d92aSKiran Patil 			skb_fill_page_desc(fp_skb(fp),
1533699d92aSKiran Patil 					   skb_shinfo(fp_skb(fp))->nr_frags,
1543699d92aSKiran Patil 					   page, off_in_page, tlen);
1553699d92aSKiran Patil 			fr_len(fp) += tlen;
1563699d92aSKiran Patil 			fp_skb(fp)->data_len += tlen;
1573699d92aSKiran Patil 			fp_skb(fp)->truesize +=
1583699d92aSKiran Patil 					PAGE_SIZE << compound_order(page);
15905d1c7c0SAndy Grover 		} else {
1603699d92aSKiran Patil 			BUG_ON(!page);
161ca747d61SCong Wang 			from = kmap_atomic(page + (mem_off >> PAGE_SHIFT));
1623699d92aSKiran Patil 			page_addr = from;
1633699d92aSKiran Patil 			from += mem_off & ~PAGE_MASK;
1643699d92aSKiran Patil 			tlen = min(tlen, (size_t)(PAGE_SIZE -
1653699d92aSKiran Patil 						(mem_off & ~PAGE_MASK)));
1663699d92aSKiran Patil 			memcpy(to, from, tlen);
167ca747d61SCong Wang 			kunmap_atomic(page_addr);
1683699d92aSKiran Patil 			to += tlen;
1693699d92aSKiran Patil 		}
1703699d92aSKiran Patil 
1713699d92aSKiran Patil 		mem_off += tlen;
1723699d92aSKiran Patil 		mem_len -= tlen;
1733699d92aSKiran Patil 		frame_len -= tlen;
1743699d92aSKiran Patil 		remaining -= tlen;
1753699d92aSKiran Patil 
1763699d92aSKiran Patil 		if (frame_len &&
1773699d92aSKiran Patil 		    (skb_shinfo(fp_skb(fp))->nr_frags < FC_FRAME_SG_LEN))
1783699d92aSKiran Patil 			continue;
1793699d92aSKiran Patil 		if (!remaining)
1803699d92aSKiran Patil 			f_ctl |= FC_FC_END_SEQ;
1813699d92aSKiran Patil 		fc_fill_fc_hdr(fp, FC_RCTL_DD_SOL_DATA, ep->did, ep->sid,
1823699d92aSKiran Patil 			       FC_TYPE_FCP, f_ctl, fh_off);
183d3682b1aSMark Rustad 		error = lport->tt.seq_send(lport, seq, fp);
1843699d92aSKiran Patil 		if (error) {
185b3e5fe16SNicholas Bellinger 			pr_info_ratelimited("%s: Failed to send frame %p, "
18695efa286SNicholas Bellinger 						"xid <0x%x>, remaining %zu, "
1873699d92aSKiran Patil 						"lso_max <0x%x>\n",
1883699d92aSKiran Patil 						__func__, fp, ep->xid,
1893699d92aSKiran Patil 						remaining, lport->lso_max);
190b3e5fe16SNicholas Bellinger 			/*
191b3e5fe16SNicholas Bellinger 			 * Go ahead and set TASK_SET_FULL status ignoring the
192b3e5fe16SNicholas Bellinger 			 * rest of the DataIN, and immediately attempt to
193b3e5fe16SNicholas Bellinger 			 * send the response via ft_queue_status() in order
194b3e5fe16SNicholas Bellinger 			 * to notify the initiator that it should reduce it's
195b3e5fe16SNicholas Bellinger 			 * per LUN queue_depth.
196b3e5fe16SNicholas Bellinger 			 */
197b3e5fe16SNicholas Bellinger 			se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL;
198b3e5fe16SNicholas Bellinger 			break;
1993699d92aSKiran Patil 		}
2003699d92aSKiran Patil 	}
201b3e5fe16SNicholas Bellinger queue_status:
2023699d92aSKiran Patil 	return ft_queue_status(se_cmd);
2033699d92aSKiran Patil }
2043699d92aSKiran Patil 
205b8b22533SChristoph Hellwig static void ft_execute_work(struct work_struct *work)
206b8b22533SChristoph Hellwig {
207b8b22533SChristoph Hellwig 	struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
208b8b22533SChristoph Hellwig 
209b8b22533SChristoph Hellwig 	target_execute_cmd(&cmd->se_cmd);
210b8b22533SChristoph Hellwig }
211b8b22533SChristoph Hellwig 
2123699d92aSKiran Patil /*
2133699d92aSKiran Patil  * Receive write data frame.
2143699d92aSKiran Patil  */
2153699d92aSKiran Patil void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
2163699d92aSKiran Patil {
2173699d92aSKiran Patil 	struct se_cmd *se_cmd = &cmd->se_cmd;
2183699d92aSKiran Patil 	struct fc_seq *seq = cmd->seq;
2193699d92aSKiran Patil 	struct fc_exch *ep;
2203699d92aSKiran Patil 	struct fc_lport *lport;
2213699d92aSKiran Patil 	struct fc_frame_header *fh;
222ec98f782SAndy Grover 	struct scatterlist *sg = NULL;
223ec98f782SAndy Grover 	u32 mem_off = 0;
2243699d92aSKiran Patil 	u32 rel_off;
2253699d92aSKiran Patil 	size_t frame_len;
226ec98f782SAndy Grover 	size_t mem_len = 0;
2273699d92aSKiran Patil 	size_t tlen;
228ec98f782SAndy Grover 	struct page *page = NULL;
2293699d92aSKiran Patil 	void *page_addr;
2303699d92aSKiran Patil 	void *from;
2313699d92aSKiran Patil 	void *to;
2323699d92aSKiran Patil 	u32 f_ctl;
2333699d92aSKiran Patil 	void *buf;
2343699d92aSKiran Patil 
2353699d92aSKiran Patil 	fh = fc_frame_header_get(fp);
2363699d92aSKiran Patil 	if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF))
2373699d92aSKiran Patil 		goto drop;
2383699d92aSKiran Patil 
239dcd998ccSKiran Patil 	f_ctl = ntoh24(fh->fh_f_ctl);
240dcd998ccSKiran Patil 	ep = fc_seq_exch(seq);
241dcd998ccSKiran Patil 	lport = ep->lp;
242dcd998ccSKiran Patil 	if (cmd->was_ddp_setup) {
243dcd998ccSKiran Patil 		BUG_ON(!ep);
244dcd998ccSKiran Patil 		BUG_ON(!lport);
2453699d92aSKiran Patil 		/*
246079587b4SKiran Patil 		 * Since DDP (Large Rx offload) was setup for this request,
247079587b4SKiran Patil 		 * payload is expected to be copied directly to user buffers.
2483699d92aSKiran Patil 		 */
249dcd998ccSKiran Patil 		buf = fc_frame_payload_get(fp, 1);
250dcd998ccSKiran Patil 		if (buf)
251dcd998ccSKiran Patil 			pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, "
252dcd998ccSKiran Patil 				"cmd->sg_cnt 0x%x. DDP was setup"
253dcd998ccSKiran Patil 				" hence not expected to receive frame with "
254dcd998ccSKiran Patil 				"payload, Frame will be dropped if"
255dcd998ccSKiran Patil 				"'Sequence Initiative' bit in f_ctl is"
256dcd998ccSKiran Patil 				"not set\n", __func__, ep->xid, f_ctl,
257e182d682SRoland Dreier 				se_cmd->t_data_sg, se_cmd->t_data_nents);
2583699d92aSKiran Patil 		/*
259dcd998ccSKiran Patil 		 * Invalidate HW DDP context if it was setup for respective
260dcd998ccSKiran Patil 		 * command. Invalidation of HW DDP context is requited in both
261dcd998ccSKiran Patil 		 * situation (success and error).
2623699d92aSKiran Patil 		 */
263dcd998ccSKiran Patil 		ft_invl_hw_context(cmd);
264dcd998ccSKiran Patil 
265dcd998ccSKiran Patil 		/*
266dcd998ccSKiran Patil 		 * If "Sequence Initiative (TSI)" bit set in f_ctl, means last
267dcd998ccSKiran Patil 		 * write data frame is received successfully where payload is
268dcd998ccSKiran Patil 		 * posted directly to user buffer and only the last frame's
269dcd998ccSKiran Patil 		 * header is posted in receive queue.
270dcd998ccSKiran Patil 		 *
271dcd998ccSKiran Patil 		 * If "Sequence Initiative (TSI)" bit is not set, means error
272dcd998ccSKiran Patil 		 * condition w.r.t. DDP, hence drop the packet and let explict
273dcd998ccSKiran Patil 		 * ABORTS from other end of exchange timer trigger the recovery.
274dcd998ccSKiran Patil 		 */
275dcd998ccSKiran Patil 		if (f_ctl & FC_FC_SEQ_INIT)
2763699d92aSKiran Patil 			goto last_frame;
277dcd998ccSKiran Patil 		else
2783699d92aSKiran Patil 			goto drop;
279079587b4SKiran Patil 	}
2803699d92aSKiran Patil 
2813699d92aSKiran Patil 	rel_off = ntohl(fh->fh_parm_offset);
2823699d92aSKiran Patil 	frame_len = fr_len(fp);
2833699d92aSKiran Patil 	if (frame_len <= sizeof(*fh))
2843699d92aSKiran Patil 		goto drop;
2853699d92aSKiran Patil 	frame_len -= sizeof(*fh);
2863699d92aSKiran Patil 	from = fc_frame_payload_get(fp, 0);
2873699d92aSKiran Patil 	if (rel_off >= se_cmd->data_length)
2883699d92aSKiran Patil 		goto drop;
2893699d92aSKiran Patil 	if (frame_len + rel_off > se_cmd->data_length)
2903699d92aSKiran Patil 		frame_len = se_cmd->data_length - rel_off;
2913699d92aSKiran Patil 
2923699d92aSKiran Patil 	/*
29305d1c7c0SAndy Grover 	 * Setup to use first mem list entry, unless no data.
2943699d92aSKiran Patil 	 */
295ec98f782SAndy Grover 	BUG_ON(frame_len && !se_cmd->t_data_sg);
29605d1c7c0SAndy Grover 	if (frame_len) {
297ec98f782SAndy Grover 		sg = se_cmd->t_data_sg;
298ec98f782SAndy Grover 		mem_len = sg->length;
299ec98f782SAndy Grover 		mem_off = sg->offset;
300ec98f782SAndy Grover 		page = sg_page(sg);
3013699d92aSKiran Patil 	}
3023699d92aSKiran Patil 
3033699d92aSKiran Patil 	while (frame_len) {
3043699d92aSKiran Patil 		if (!mem_len) {
305ec98f782SAndy Grover 			sg = sg_next(sg);
306ec98f782SAndy Grover 			mem_len = sg->length;
307ec98f782SAndy Grover 			mem_off = sg->offset;
308ec98f782SAndy Grover 			page = sg_page(sg);
3093699d92aSKiran Patil 		}
3103699d92aSKiran Patil 		if (rel_off >= mem_len) {
3113699d92aSKiran Patil 			rel_off -= mem_len;
3123699d92aSKiran Patil 			mem_len = 0;
3133699d92aSKiran Patil 			continue;
3143699d92aSKiran Patil 		}
3153699d92aSKiran Patil 		mem_off += rel_off;
3163699d92aSKiran Patil 		mem_len -= rel_off;
3173699d92aSKiran Patil 		rel_off = 0;
3183699d92aSKiran Patil 
3193699d92aSKiran Patil 		tlen = min(mem_len, frame_len);
3203699d92aSKiran Patil 
321ca747d61SCong Wang 		to = kmap_atomic(page + (mem_off >> PAGE_SHIFT));
3223699d92aSKiran Patil 		page_addr = to;
3233699d92aSKiran Patil 		to += mem_off & ~PAGE_MASK;
3243699d92aSKiran Patil 		tlen = min(tlen, (size_t)(PAGE_SIZE -
3253699d92aSKiran Patil 					  (mem_off & ~PAGE_MASK)));
3263699d92aSKiran Patil 		memcpy(to, from, tlen);
327ca747d61SCong Wang 		kunmap_atomic(page_addr);
32805d1c7c0SAndy Grover 
3293699d92aSKiran Patil 		from += tlen;
3303699d92aSKiran Patil 		frame_len -= tlen;
3313699d92aSKiran Patil 		mem_off += tlen;
3323699d92aSKiran Patil 		mem_len -= tlen;
3333699d92aSKiran Patil 		cmd->write_data_len += tlen;
3343699d92aSKiran Patil 	}
3353699d92aSKiran Patil last_frame:
336b8b22533SChristoph Hellwig 	if (cmd->write_data_len == se_cmd->data_length) {
337b8b22533SChristoph Hellwig 		INIT_WORK(&cmd->work, ft_execute_work);
338b8b22533SChristoph Hellwig 		queue_work(cmd->sess->tport->tpg->workqueue, &cmd->work);
339b8b22533SChristoph Hellwig 	}
3403699d92aSKiran Patil drop:
3413699d92aSKiran Patil 	fc_frame_free(fp);
3423699d92aSKiran Patil }
343dcd998ccSKiran Patil 
344dcd998ccSKiran Patil /*
345dcd998ccSKiran Patil  * Handle and cleanup any HW specific resources if
346dcd998ccSKiran Patil  * received ABORTS, errors, timeouts.
347dcd998ccSKiran Patil  */
348dcd998ccSKiran Patil void ft_invl_hw_context(struct ft_cmd *cmd)
349dcd998ccSKiran Patil {
3507875f179SWei Yongjun 	struct fc_seq *seq;
351dcd998ccSKiran Patil 	struct fc_exch *ep = NULL;
352dcd998ccSKiran Patil 	struct fc_lport *lport = NULL;
353dcd998ccSKiran Patil 
354dcd998ccSKiran Patil 	BUG_ON(!cmd);
3557875f179SWei Yongjun 	seq = cmd->seq;
356dcd998ccSKiran Patil 
357dcd998ccSKiran Patil 	/* Cleanup the DDP context in HW if DDP was setup */
358dcd998ccSKiran Patil 	if (cmd->was_ddp_setup && seq) {
359dcd998ccSKiran Patil 		ep = fc_seq_exch(seq);
360dcd998ccSKiran Patil 		if (ep) {
361dcd998ccSKiran Patil 			lport = ep->lp;
362d556546eSDan Carpenter 			if (lport && (ep->xid <= lport->lro_xid)) {
363dcd998ccSKiran Patil 				/*
364dcd998ccSKiran Patil 				 * "ddp_done" trigger invalidation of HW
365dcd998ccSKiran Patil 				 * specific DDP context
366dcd998ccSKiran Patil 				 */
367dcd998ccSKiran Patil 				cmd->write_data_len = lport->tt.ddp_done(lport,
368dcd998ccSKiran Patil 								      ep->xid);
369dcd998ccSKiran Patil 
370dcd998ccSKiran Patil 				/*
371dcd998ccSKiran Patil 				 * Resetting same variable to indicate HW's
372dcd998ccSKiran Patil 				 * DDP context has been invalidated to avoid
373dcd998ccSKiran Patil 				 * re_invalidation of same context (context is
374dcd998ccSKiran Patil 				 * identified using ep->xid)
375dcd998ccSKiran Patil 				 */
376dcd998ccSKiran Patil 				cmd->was_ddp_setup = 0;
377dcd998ccSKiran Patil 			}
378dcd998ccSKiran Patil 		}
379dcd998ccSKiran Patil 	}
380d556546eSDan Carpenter }
381