1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
22fcf3ce44SJohn Forte  * Copyright 2000 by Cisco Systems, Inc.  All rights reserved.
23*1a1a84a3SPeter Dunlap  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24fcf3ce44SJohn Forte  * Use is subject to license terms.
25fcf3ce44SJohn Forte  *
26fcf3ce44SJohn Forte  * iSCSI Pseudo HBA Driver
27fcf3ce44SJohn Forte  */
28fcf3ce44SJohn Forte 
29fcf3ce44SJohn Forte #include <sys/socket.h>		/* networking stuff */
30fcf3ce44SJohn Forte #include <sys/t_kuser.h>	/* networking stuff */
31fcf3ce44SJohn Forte #include <sys/tihdr.h>		/* networking stuff */
32fcf3ce44SJohn Forte #include <sys/strsubr.h>	/* networking stuff */
33fcf3ce44SJohn Forte #include <netinet/tcp.h>	/* TCP_NODELAY */
34fcf3ce44SJohn Forte #include <sys/socketvar.h>	/* _ALLOC_SLEEP */
35fcf3ce44SJohn Forte #include <sys/strsun.h>		/* DB_TYPE() */
36fcf3ce44SJohn Forte 
37fcf3ce44SJohn Forte #include "iscsi.h"		/* iscsi driver */
38*1a1a84a3SPeter Dunlap #include <sys/iscsi_protocol.h>	/* iscsi protocol */
39fcf3ce44SJohn Forte 
40fcf3ce44SJohn Forte /* generic io helpers */
41fcf3ce44SJohn Forte static uint32_t n2h24(uchar_t *ptr);
42fcf3ce44SJohn Forte static int iscsi_sna_lt(uint32_t n1, uint32_t n2);
43fcf3ce44SJohn Forte static void iscsi_update_flow_control(iscsi_sess_t *isp,
44fcf3ce44SJohn Forte     uint32_t max, uint32_t exp);
45fcf3ce44SJohn Forte 
46fcf3ce44SJohn Forte /* receivers */
47fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_hdr(iscsi_conn_t *icp,
48fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, char *data, int data_size);
49fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_nop(iscsi_conn_t *icp,
50fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, char *data);
51fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_data_rsp(iscsi_conn_t *icp,
52fcf3ce44SJohn Forte     iscsi_hdr_t *ihp);
53fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_cmd_rsp(iscsi_conn_t *icp,
54fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, char *data);
55fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_rtt_rsp(iscsi_conn_t *icp,
56fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, char *data);
57fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_reject_rsp(iscsi_conn_t *icp,
58fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, char *data);
59fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_rejected_tsk_mgt(iscsi_conn_t *icp,
60fcf3ce44SJohn Forte     iscsi_hdr_t *old_ihp);
61fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_itt_to_icmdp(iscsi_sess_t *isp,
62fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, iscsi_cmd_t **icmdp);
63fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_task_mgt_rsp(iscsi_conn_t *icp,
64fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, void *data);
65fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_logout_rsp(iscsi_conn_t *icp,
66fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, char *data);
67fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_async_rsp(iscsi_conn_t *icp,
68fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, char *data);
69fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_text_rsp(iscsi_conn_t *icp,
70fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, char *data);
71fcf3ce44SJohn Forte 
72fcf3ce44SJohn Forte 
73fcf3ce44SJohn Forte /* senders */
74fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_scsi(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
75fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_r2t(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
76fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_data(iscsi_sess_t *isp, iscsi_conn_t *icp,
77fcf3ce44SJohn Forte     iscsi_cmd_t *icmdp, uint32_t ttt, size_t datalen, size_t offset);
78fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_nop(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
79fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_abort(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
80fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_reset(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
81fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_logout(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
82fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_text(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
83fcf3ce44SJohn Forte 
84fcf3ce44SJohn Forte 
85fcf3ce44SJohn Forte /* helpers */
86fcf3ce44SJohn Forte static void iscsi_handle_r2t(iscsi_conn_t *icp, iscsi_cmd_t *icmdp,
87fcf3ce44SJohn Forte     uint32_t offset, uint32_t length, uint32_t ttt);
88fcf3ce44SJohn Forte static void iscsi_handle_passthru_callback(struct scsi_pkt *pkt);
89fcf3ce44SJohn Forte static void iscsi_handle_nop(iscsi_conn_t *icp, uint32_t itt, uint32_t ttt);
90fcf3ce44SJohn Forte 
91fcf3ce44SJohn Forte static void iscsi_timeout_checks(iscsi_sess_t *isp);
92fcf3ce44SJohn Forte static void iscsi_nop_checks(iscsi_sess_t *isp);
93fcf3ce44SJohn Forte 
94fcf3ce44SJohn Forte 
95fcf3ce44SJohn Forte #define	ISCSI_CONN_TO_NET_DIGEST(icp)					    \
96fcf3ce44SJohn Forte 	((icp->conn_params.header_digest ? ISCSI_NET_HEADER_DIGEST : 0) |   \
97fcf3ce44SJohn Forte 	(icp->conn_params.data_digest ? ISCSI_NET_DATA_DIGEST : 0))
98fcf3ce44SJohn Forte 
99fcf3ce44SJohn Forte /*
100fcf3ce44SJohn Forte  * This file contains the main guts of the iSCSI protocol layer.
101fcf3ce44SJohn Forte  * It's broken into 5 sections; Basic helper functions, RX IO path,
102fcf3ce44SJohn Forte  * TX IO path, Completion (IC) IO path, and watchdog (WD) routines.
103fcf3ce44SJohn Forte  *
104fcf3ce44SJohn Forte  * The IO flow model is similiar to the below diagram.  The
105fcf3ce44SJohn Forte  * iscsi session, connection and command state machines are used
106fcf3ce44SJohn Forte  * to drive IO through this flow diagram.  Reference those files
107fcf3ce44SJohn Forte  * to get a detailed description of their respective state models
108fcf3ce44SJohn Forte  * prior to their xxx_state_machine_function().
109fcf3ce44SJohn Forte  *
110fcf3ce44SJohn Forte  * tran_start() -> CMD_E1     TX_THREAD                   RX_THREAD
111fcf3ce44SJohn Forte  *                   |            T                           T
112fcf3ce44SJohn Forte  *                   V            T                           T
113fcf3ce44SJohn Forte  *                PENDING_Q  --CMD_E2--> ACTIVE_Q -      --CMD_E3--+
114fcf3ce44SJohn Forte  *                                T                \ C        T    |
115fcf3ce44SJohn Forte  *                                T                 \M        T    |
116fcf3ce44SJohn Forte  *                                                   D        T    |
117fcf3ce44SJohn Forte  *                                       WD_THREAD TT|TT      T    |
118fcf3ce44SJohn Forte  *                                                  /E        T    |
119fcf3ce44SJohn Forte  *                                                 / 6        T    |
120fcf3ce44SJohn Forte  *                                     ABORTING_Q<-      --CMD_E3--+
121fcf3ce44SJohn Forte  *                                                            T    |
122fcf3ce44SJohn Forte  *                                T                           T    |
123fcf3ce44SJohn Forte  *                                T                                |
124fcf3ce44SJohn Forte  *               callback()  <--CMD_E#-- COMPLETION_Q <------------+
125fcf3ce44SJohn Forte  *                                T
126fcf3ce44SJohn Forte  *                                T
127fcf3ce44SJohn Forte  *                            IC_THREAD
128fcf3ce44SJohn Forte  *
129fcf3ce44SJohn Forte  * External and internal command are ran thru this same state
130fcf3ce44SJohn Forte  * machine.  All commands enter the state machine by receiving an
131fcf3ce44SJohn Forte  * ISCSI_CMD_EVENT_E1.  This event places the command into the
132fcf3ce44SJohn Forte  * PENDING_Q.  Next when resources are available the TX_THREAD
133fcf3ce44SJohn Forte  * issues a E2 event on the command.  This sends the command
134fcf3ce44SJohn Forte  * to the TCP stack and places the command on the ACTIVE_Q.  While
135fcf3ce44SJohn Forte  * on the PENDIING_Q and ACTIVE_Q, the command is monitored via the
136fcf3ce44SJohn Forte  * WD_THREAD to ensure the pkt_time has not elapsed.  If elapsed the
137fcf3ce44SJohn Forte  * command is issued an E6(timeout) event which moves either (if pending)
138fcf3ce44SJohn Forte  * completed the command or (if active) moves the command to the
139fcf3ce44SJohn Forte  * aborting queue and issues a SCSI TASK MANAGEMENT ABORT command
140fcf3ce44SJohn Forte  * to cancel the IO request.  If the original command is completed
141fcf3ce44SJohn Forte  * or the TASK MANAGEMENT command completes the command is moved
142fcf3ce44SJohn Forte  * to the COMPLETION_Q via a E3 event.  The IC_THREAD then processes
143fcf3ce44SJohn Forte  * the COMPLETION_Q and issues the scsi_pkt callback.  This
144fcf3ce44SJohn Forte  * callback can not be processed directly from the RX_THREAD
145fcf3ce44SJohn Forte  * because the callback might call back into the iscsi driver
146fcf3ce44SJohn Forte  * causing a deadlock condition.
147fcf3ce44SJohn Forte  *
148fcf3ce44SJohn Forte  * For more details on the complete CMD state machine reference
149fcf3ce44SJohn Forte  * the state machine diagram in iscsi_cmd.c.  The connection state
150fcf3ce44SJohn Forte  * machine is driven via IO events in this file.  Then session
151fcf3ce44SJohn Forte  * events are driven by the connection events.  For complete
152fcf3ce44SJohn Forte  * details on these state machines reference iscsi_sess.c and
153fcf3ce44SJohn Forte  * iscsi_conn.c
154fcf3ce44SJohn Forte  */
155fcf3ce44SJohn Forte 
156fcf3ce44SJohn Forte 
157fcf3ce44SJohn Forte /*
158fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
159fcf3ce44SJohn Forte  * | io helper routines							|
160fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
161fcf3ce44SJohn Forte  */
162fcf3ce44SJohn Forte 
163fcf3ce44SJohn Forte /*
164fcf3ce44SJohn Forte  * n2h24 - native to host 24 bit integer translation.
165fcf3ce44SJohn Forte  */
166fcf3ce44SJohn Forte static uint32_t
167fcf3ce44SJohn Forte n2h24(uchar_t *ptr)
168fcf3ce44SJohn Forte {
169fcf3ce44SJohn Forte 	uint32_t idx;
170fcf3ce44SJohn Forte 	bcopy(ptr, &idx, 3);
171fcf3ce44SJohn Forte 	return (ntohl(idx) >> 8);
172fcf3ce44SJohn Forte }
173fcf3ce44SJohn Forte 
174fcf3ce44SJohn Forte /*
175fcf3ce44SJohn Forte  * iscsi_sna_lt - Serial Number Arithmetic, 32 bits, less than, RFC1982
176fcf3ce44SJohn Forte  */
177fcf3ce44SJohn Forte static int
178fcf3ce44SJohn Forte iscsi_sna_lt(uint32_t n1, uint32_t n2)
179fcf3ce44SJohn Forte {
180fcf3ce44SJohn Forte 	return ((n1 != n2) &&
181fcf3ce44SJohn Forte 	    (((n1 < n2) && ((n2 - n1) < ISCSI_SNA32_CHECK)) ||
182fcf3ce44SJohn Forte 	    ((n1 > n2) && ((n1 - n2) > ISCSI_SNA32_CHECK))));
183fcf3ce44SJohn Forte }
184fcf3ce44SJohn Forte 
185fcf3ce44SJohn Forte /*
186fcf3ce44SJohn Forte  * iscsi_sna_lte - Serial Number Arithmetic, 32 bits, less than or equal,
187fcf3ce44SJohn Forte  * RFC1982
188fcf3ce44SJohn Forte  */
189fcf3ce44SJohn Forte int
190fcf3ce44SJohn Forte iscsi_sna_lte(uint32_t n1, uint32_t n2)
191fcf3ce44SJohn Forte {
192fcf3ce44SJohn Forte 	return ((n1 == n2) ||
193fcf3ce44SJohn Forte 	    (((n1 < n2) && ((n2 - n1) < ISCSI_SNA32_CHECK)) ||
194fcf3ce44SJohn Forte 	    ((n1 > n2) && ((n1 - n2) > ISCSI_SNA32_CHECK))));
195fcf3ce44SJohn Forte }
196fcf3ce44SJohn Forte 
197fcf3ce44SJohn Forte /*
198fcf3ce44SJohn Forte  * iscsi_update_flow_control - Update expcmdsn and maxcmdsn iSCSI
199fcf3ce44SJohn Forte  * flow control information for a session
200fcf3ce44SJohn Forte  */
201fcf3ce44SJohn Forte static void
202fcf3ce44SJohn Forte iscsi_update_flow_control(iscsi_sess_t *isp, uint32_t max, uint32_t exp)
203fcf3ce44SJohn Forte {
204fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
205fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&isp->sess_cmdsn_mutex));
206fcf3ce44SJohn Forte 
207fcf3ce44SJohn Forte 	if (!iscsi_sna_lt(max, (exp - 1))) {
208fcf3ce44SJohn Forte 
209fcf3ce44SJohn Forte 		if (!iscsi_sna_lte(exp, isp->sess_expcmdsn)) {
210fcf3ce44SJohn Forte 			isp->sess_expcmdsn = exp;
211fcf3ce44SJohn Forte 		}
212fcf3ce44SJohn Forte 
213fcf3ce44SJohn Forte 		if (!iscsi_sna_lte(max, isp->sess_maxcmdsn)) {
214fcf3ce44SJohn Forte 			isp->sess_maxcmdsn = max;
215fcf3ce44SJohn Forte 			if (iscsi_sna_lte(isp->sess_cmdsn,
216fcf3ce44SJohn Forte 			    isp->sess_maxcmdsn)) {
217fcf3ce44SJohn Forte 				/*
218fcf3ce44SJohn Forte 				 * the window is open again - schedule
219fcf3ce44SJohn Forte 				 * to send any held tasks soon
220fcf3ce44SJohn Forte 				 */
221fcf3ce44SJohn Forte 				iscsi_sess_redrive_io(isp);
222fcf3ce44SJohn Forte 			}
223fcf3ce44SJohn Forte 		}
224fcf3ce44SJohn Forte 	}
225fcf3ce44SJohn Forte }
226fcf3ce44SJohn Forte 
227fcf3ce44SJohn Forte 
228fcf3ce44SJohn Forte /*
229fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
230fcf3ce44SJohn Forte  * | io receive and processing routines					|
231fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
232fcf3ce44SJohn Forte  */
233fcf3ce44SJohn Forte 
234fcf3ce44SJohn Forte /*
235fcf3ce44SJohn Forte  * iscsi_rx_thread - The connection creates a thread of this
236fcf3ce44SJohn Forte  * function during login.  After which point this thread is
237fcf3ce44SJohn Forte  * used to receive and process all iSCSI PDUs on this connection.
238fcf3ce44SJohn Forte  * The PDUs received on this connection are used to drive the
239fcf3ce44SJohn Forte  * commands through their state machine.  This thread will
240fcf3ce44SJohn Forte  * continue processing while the connection is on a LOGGED_IN
241fcf3ce44SJohn Forte  * or IN_LOGOUT state.  Once the connection moves out of this
242fcf3ce44SJohn Forte  * state the thread will die.
243fcf3ce44SJohn Forte  */
244fcf3ce44SJohn Forte void
245fcf3ce44SJohn Forte iscsi_rx_thread(iscsi_thread_t *thread, void *arg)
246fcf3ce44SJohn Forte {
247fcf3ce44SJohn Forte 	iscsi_status_t		rval		= ISCSI_STATUS_SUCCESS;
248fcf3ce44SJohn Forte 	iscsi_conn_t		*icp		= (iscsi_conn_t *)arg;
249fcf3ce44SJohn Forte 	iscsi_sess_t		*isp		= NULL;
250fcf3ce44SJohn Forte 	char			*hdr		= NULL;
251fcf3ce44SJohn Forte 	int			hdr_size	= 0;
252fcf3ce44SJohn Forte 	char			*data		= NULL;
253fcf3ce44SJohn Forte 	int			data_size	= 0;
254fcf3ce44SJohn Forte 	iscsi_hdr_t		*ihp;
255fcf3ce44SJohn Forte 
256fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
257fcf3ce44SJohn Forte 	isp = icp->conn_sess;
258fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
259fcf3ce44SJohn Forte 
260fcf3ce44SJohn Forte 	/* pre-alloc recv header buffer for common actions */
261fcf3ce44SJohn Forte 	hdr_size = sizeof (iscsi_hdr_t) + 255; /* 255 = one byte hlength */
262fcf3ce44SJohn Forte 	hdr = (char *)kmem_zalloc(hdr_size, KM_SLEEP);
263fcf3ce44SJohn Forte 	ihp = (iscsi_hdr_t *)hdr;
264fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
265fcf3ce44SJohn Forte 
266fcf3ce44SJohn Forte 	/* pre-alloc max_recv_size buffer for common actions */
267fcf3ce44SJohn Forte 	data_size = icp->conn_params.max_recv_data_seg_len;
268fcf3ce44SJohn Forte 	data = (char *)kmem_zalloc(data_size, KM_SLEEP);
269fcf3ce44SJohn Forte 	ASSERT(data != NULL);
270fcf3ce44SJohn Forte 
271fcf3ce44SJohn Forte 	do {
272fcf3ce44SJohn Forte 		/* Wait for the next iSCSI header */
273fcf3ce44SJohn Forte 		rval = iscsi_net->recvhdr(icp->conn_socket,
274fcf3ce44SJohn Forte 		    ihp, hdr_size, 0, (icp->conn_params.header_digest ?
275fcf3ce44SJohn Forte 		    ISCSI_NET_HEADER_DIGEST : 0));
276fcf3ce44SJohn Forte 		if (ISCSI_SUCCESS(rval)) {
277fcf3ce44SJohn Forte 			isp->sess_rx_lbolt =
278fcf3ce44SJohn Forte 			    icp->conn_rx_lbolt =
279fcf3ce44SJohn Forte 			    ddi_get_lbolt();
280fcf3ce44SJohn Forte 
281fcf3ce44SJohn Forte 			/* Perform specific hdr handling */
282fcf3ce44SJohn Forte 			rval = iscsi_rx_process_hdr(icp, ihp,
283fcf3ce44SJohn Forte 			    data, data_size);
284fcf3ce44SJohn Forte 		}
285fcf3ce44SJohn Forte 
286fcf3ce44SJohn Forte 		/*
287fcf3ce44SJohn Forte 		 * handle failures
288fcf3ce44SJohn Forte 		 */
289fcf3ce44SJohn Forte 		switch (rval) {
290fcf3ce44SJohn Forte 		case ISCSI_STATUS_SUCCESS:
291fcf3ce44SJohn Forte 			/*
292fcf3ce44SJohn Forte 			 * If we successfully completed a receive
293fcf3ce44SJohn Forte 			 * and we are in an IN_FLUSH state then
294fcf3ce44SJohn Forte 			 * check the active queue count to see
295fcf3ce44SJohn Forte 			 * if its empty.  If its empty then force
296fcf3ce44SJohn Forte 			 * a disconnect event on the connection.
297fcf3ce44SJohn Forte 			 * This will move the session from IN_FLUSH
298fcf3ce44SJohn Forte 			 * to FLUSHED and complete the login
299fcf3ce44SJohn Forte 			 * parameter update.
300fcf3ce44SJohn Forte 			 */
301fcf3ce44SJohn Forte 			if ((isp->sess_state == ISCSI_SESS_STATE_IN_FLUSH) &&
302fcf3ce44SJohn Forte 			    (icp->conn_queue_active.count == 0)) {
303fcf3ce44SJohn Forte 				mutex_enter(&icp->conn_state_mutex);
304fcf3ce44SJohn Forte 				(void) iscsi_conn_state_machine(icp,
305fcf3ce44SJohn Forte 				    ISCSI_CONN_EVENT_T14);
306fcf3ce44SJohn Forte 				mutex_exit(&icp->conn_state_mutex);
307fcf3ce44SJohn Forte 			}
308fcf3ce44SJohn Forte 			break;
309fcf3ce44SJohn Forte 		case ISCSI_STATUS_TCP_RX_ERROR:
310fcf3ce44SJohn Forte 			/* connection had an error */
311fcf3ce44SJohn Forte 			mutex_enter(&icp->conn_state_mutex);
312fcf3ce44SJohn Forte 			(void) iscsi_conn_state_machine(icp,
313fcf3ce44SJohn Forte 			    ISCSI_CONN_EVENT_T15);
314fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_state_mutex);
315fcf3ce44SJohn Forte 			break;
316fcf3ce44SJohn Forte 		case ISCSI_STATUS_HEADER_DIGEST_ERROR:
317fcf3ce44SJohn Forte 			/*
318fcf3ce44SJohn Forte 			 * If we encounter a digest error we have to restart
319fcf3ce44SJohn Forte 			 * all the connections on this session. per iSCSI
320fcf3ce44SJohn Forte 			 * Level 0 Recovery.
321fcf3ce44SJohn Forte 			 */
322fcf3ce44SJohn Forte 			KSTAT_INC_CONN_ERR_HEADER_DIGEST(icp);
323fcf3ce44SJohn Forte 			mutex_enter(&icp->conn_state_mutex);
324fcf3ce44SJohn Forte 			(void) iscsi_conn_state_machine(icp,
325fcf3ce44SJohn Forte 			    ISCSI_CONN_EVENT_T14);
326fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_state_mutex);
327fcf3ce44SJohn Forte 			break;
328fcf3ce44SJohn Forte 		case ISCSI_STATUS_DATA_DIGEST_ERROR:
329fcf3ce44SJohn Forte 			/*
330fcf3ce44SJohn Forte 			 * We can continue with a data digest error.  The
331fcf3ce44SJohn Forte 			 * icmdp was flaged as having a crc problem.  It
332fcf3ce44SJohn Forte 			 * will be aborted when all data is received.  This
333fcf3ce44SJohn Forte 			 * saves us from restarting the session when we
334fcf3ce44SJohn Forte 			 * might be able to keep it going.  If the data
335fcf3ce44SJohn Forte 			 * digest issue was really bad we will hit a
336fcf3ce44SJohn Forte 			 * status protocol error on the next pdu, which
337fcf3ce44SJohn Forte 			 * will force a connection retstart.
338fcf3ce44SJohn Forte 			 */
339fcf3ce44SJohn Forte 			KSTAT_INC_CONN_ERR_DATA_DIGEST(icp);
340fcf3ce44SJohn Forte 			break;
341fcf3ce44SJohn Forte 		case ISCSI_STATUS_PROTOCOL_ERROR:
342fcf3ce44SJohn Forte 			/*
343fcf3ce44SJohn Forte 			 * A protocol problem was encountered.  Reset
344fcf3ce44SJohn Forte 			 * session to try and repair issue.
345fcf3ce44SJohn Forte 			 */
346fcf3ce44SJohn Forte 			KSTAT_INC_CONN_ERR_PROTOCOL(icp);
347fcf3ce44SJohn Forte 			mutex_enter(&icp->conn_state_mutex);
348fcf3ce44SJohn Forte 			(void) iscsi_conn_state_machine(icp,
349fcf3ce44SJohn Forte 			    ISCSI_CONN_EVENT_T14);
350fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_state_mutex);
351fcf3ce44SJohn Forte 			break;
352fcf3ce44SJohn Forte 		case ISCSI_STATUS_INTERNAL_ERROR:
353fcf3ce44SJohn Forte 			/*
354fcf3ce44SJohn Forte 			 * These should have all been handled before now.
355fcf3ce44SJohn Forte 			 */
356fcf3ce44SJohn Forte 			break;
357fcf3ce44SJohn Forte 		default:
358fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) encountered "
359fcf3ce44SJohn Forte 			    "unknown error(%d) on a receive", icp->conn_oid,
360fcf3ce44SJohn Forte 			    rval);
361fcf3ce44SJohn Forte 			ASSERT(B_FALSE);
362fcf3ce44SJohn Forte 		}
363fcf3ce44SJohn Forte 
364fcf3ce44SJohn Forte 	} while ((ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state)) &&
365fcf3ce44SJohn Forte 	    (iscsi_thread_wait(thread, 0) != 0));
366fcf3ce44SJohn Forte 
367fcf3ce44SJohn Forte 	kmem_free(hdr, hdr_size);
368fcf3ce44SJohn Forte 	kmem_free(data, data_size);
369fcf3ce44SJohn Forte }
370fcf3ce44SJohn Forte 
371fcf3ce44SJohn Forte 
372fcf3ce44SJohn Forte /*
373fcf3ce44SJohn Forte  * iscsi_rx_process_hdr - This function collects data for all PDUs
374fcf3ce44SJohn Forte  * that do not have data that will be mapped to a specific scsi_pkt.
375fcf3ce44SJohn Forte  * Then for each hdr type fan out the processing.
376fcf3ce44SJohn Forte  */
377fcf3ce44SJohn Forte static iscsi_status_t
378fcf3ce44SJohn Forte iscsi_rx_process_hdr(iscsi_conn_t *icp, iscsi_hdr_t *ihp,
379fcf3ce44SJohn Forte     char *data, int data_size)
380fcf3ce44SJohn Forte {
381fcf3ce44SJohn Forte 	iscsi_status_t	rval	= ISCSI_STATUS_SUCCESS;
382fcf3ce44SJohn Forte 	iscsi_sess_t	*isp	= NULL;
383fcf3ce44SJohn Forte 
384fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
385fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
386fcf3ce44SJohn Forte 	ASSERT(data != NULL);
387fcf3ce44SJohn Forte 	isp = icp->conn_sess;
388fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
389fcf3ce44SJohn Forte 
390fcf3ce44SJohn Forte 	/* If this is not a SCSI_DATA_RSP we can go ahead and get the data */
391fcf3ce44SJohn Forte 	if ((ihp->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_SCSI_DATA_RSP) {
392fcf3ce44SJohn Forte 		rval = iscsi_net->recvdata(icp->conn_socket, ihp,
393fcf3ce44SJohn Forte 		    data, data_size, 0, (icp->conn_params.data_digest) ?
394fcf3ce44SJohn Forte 		    ISCSI_NET_DATA_DIGEST : 0);
395fcf3ce44SJohn Forte 		if (!ISCSI_SUCCESS(rval)) {
396fcf3ce44SJohn Forte 			return (rval);
397fcf3ce44SJohn Forte 		}
398fcf3ce44SJohn Forte 		isp->sess_rx_lbolt = icp->conn_rx_lbolt = ddi_get_lbolt();
399fcf3ce44SJohn Forte 	}
400fcf3ce44SJohn Forte 
401fcf3ce44SJohn Forte 	/* fan out the hdr processing */
402fcf3ce44SJohn Forte 	switch (ihp->opcode & ISCSI_OPCODE_MASK) {
403fcf3ce44SJohn Forte 	case ISCSI_OP_SCSI_DATA_RSP:
404fcf3ce44SJohn Forte 		rval = iscsi_rx_process_data_rsp(icp, ihp);
405fcf3ce44SJohn Forte 		break;
406fcf3ce44SJohn Forte 	case ISCSI_OP_SCSI_RSP:
407fcf3ce44SJohn Forte 		rval = iscsi_rx_process_cmd_rsp(icp, ihp, data);
408fcf3ce44SJohn Forte 		break;
409fcf3ce44SJohn Forte 	case ISCSI_OP_RTT_RSP:
410fcf3ce44SJohn Forte 		rval = iscsi_rx_process_rtt_rsp(icp, ihp, data);
411fcf3ce44SJohn Forte 		break;
412fcf3ce44SJohn Forte 	case ISCSI_OP_NOOP_IN:
413fcf3ce44SJohn Forte 		rval = iscsi_rx_process_nop(icp, ihp, data);
414fcf3ce44SJohn Forte 		break;
415fcf3ce44SJohn Forte 	case ISCSI_OP_REJECT_MSG:
416fcf3ce44SJohn Forte 		rval = iscsi_rx_process_reject_rsp(icp, ihp, data);
417fcf3ce44SJohn Forte 		break;
418fcf3ce44SJohn Forte 	case ISCSI_OP_SCSI_TASK_MGT_RSP:
419fcf3ce44SJohn Forte 		rval = iscsi_rx_process_task_mgt_rsp(icp, ihp, data);
420fcf3ce44SJohn Forte 		break;
421fcf3ce44SJohn Forte 	case ISCSI_OP_LOGOUT_RSP:
422fcf3ce44SJohn Forte 		rval = iscsi_rx_process_logout_rsp(icp, ihp, data);
423fcf3ce44SJohn Forte 		break;
424fcf3ce44SJohn Forte 	case ISCSI_OP_ASYNC_EVENT:
425fcf3ce44SJohn Forte 		rval = iscsi_rx_process_async_rsp(icp, ihp, data);
426fcf3ce44SJohn Forte 		break;
427fcf3ce44SJohn Forte 	case ISCSI_OP_TEXT_RSP:
428fcf3ce44SJohn Forte 		rval = iscsi_rx_process_text_rsp(icp, ihp, data);
429fcf3ce44SJohn Forte 		break;
430fcf3ce44SJohn Forte 	default:
431fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
432fcf3ce44SJohn Forte 		    "received an unsupported opcode 0x%02x",
433fcf3ce44SJohn Forte 		    icp->conn_oid, ihp->opcode);
434fcf3ce44SJohn Forte 		rval = ISCSI_STATUS_PROTOCOL_ERROR;
435fcf3ce44SJohn Forte 	}
436fcf3ce44SJohn Forte 
437fcf3ce44SJohn Forte 	return (rval);
438fcf3ce44SJohn Forte }
439fcf3ce44SJohn Forte 
440fcf3ce44SJohn Forte 
441fcf3ce44SJohn Forte /*
442fcf3ce44SJohn Forte  * iscsi_rx_process_data_rsp - Processed received data header.  Once
443fcf3ce44SJohn Forte  * header is processed we read data off the connection directly into
444fcf3ce44SJohn Forte  * the scsi_pkt to avoid duplicate bcopy of a large amount of data.
445fcf3ce44SJohn Forte  * If this is the final data sequence denoted by the data response
446fcf3ce44SJohn Forte  * PDU Status bit being set.  We will not receive the SCSI response.
447fcf3ce44SJohn Forte  * This bit denotes that the PDU is the successful completion of the
448fcf3ce44SJohn Forte  * command.  In this case complete the command.  If This bit isn't
449fcf3ce44SJohn Forte  * set we wait for more data or a scsi command response.
450fcf3ce44SJohn Forte  */
451fcf3ce44SJohn Forte static iscsi_status_t
452fcf3ce44SJohn Forte iscsi_rx_process_data_rsp(iscsi_conn_t *icp, iscsi_hdr_t *ihp)
453fcf3ce44SJohn Forte {
454fcf3ce44SJohn Forte 	iscsi_status_t		rval		= ISCSI_STATUS_SUCCESS;
455fcf3ce44SJohn Forte 	iscsi_sess_t		*isp		= NULL;
456fcf3ce44SJohn Forte 	iscsi_data_rsp_hdr_t	*idrhp		= (iscsi_data_rsp_hdr_t *)ihp;
457fcf3ce44SJohn Forte 	iscsi_cmd_t		*icmdp		= NULL;
458fcf3ce44SJohn Forte 	struct scsi_pkt		*pkt		= NULL;
459fcf3ce44SJohn Forte 	struct buf		*bp		= NULL;
460fcf3ce44SJohn Forte 	uint32_t		offset		= 0;
461fcf3ce44SJohn Forte 	uint32_t		dlength		= 0;
462fcf3ce44SJohn Forte 	char			*bcp		= NULL;
463fcf3ce44SJohn Forte 
464fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
465fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
466fcf3ce44SJohn Forte 	isp = icp->conn_sess;
467fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
468fcf3ce44SJohn Forte 
469fcf3ce44SJohn Forte 	if (idrhp->flags & ISCSI_FLAG_DATA_STATUS) {
470fcf3ce44SJohn Forte 		/* make sure we got status in order */
471fcf3ce44SJohn Forte 		if (icp->conn_expstatsn == ntohl(idrhp->statsn)) {
472fcf3ce44SJohn Forte 			icp->conn_expstatsn++;
473fcf3ce44SJohn Forte 		} else {
474fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) protocol error "
475fcf3ce44SJohn Forte 			    "- received status out of order itt:0x%x "
476fcf3ce44SJohn Forte 			    "statsn:0x%x expstatsn:0x%x", icp->conn_oid,
477fcf3ce44SJohn Forte 			    idrhp->itt, ntohl(idrhp->statsn),
478fcf3ce44SJohn Forte 			    icp->conn_expstatsn);
479fcf3ce44SJohn Forte 			return (ISCSI_STATUS_PROTOCOL_ERROR);
480fcf3ce44SJohn Forte 		}
481fcf3ce44SJohn Forte 	}
482fcf3ce44SJohn Forte 
483fcf3ce44SJohn Forte 	/* match itt in the session's command table */
484fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
485fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
486fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(isp, ihp, &icmdp))) {
487fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_cmdsn_mutex);
488fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
489fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
490fcf3ce44SJohn Forte 	}
491fcf3ce44SJohn Forte 	/*
492fcf3ce44SJohn Forte 	 * Holding the pending/active queue locks across the
493fcf3ce44SJohn Forte 	 * iscsi_rx_data call later in this function may cause
494fcf3ce44SJohn Forte 	 * deadlock during fault injections.  Instead remove
495fcf3ce44SJohn Forte 	 * the cmd from the active queue and release the locks.
496fcf3ce44SJohn Forte 	 * Then before returning or completing the command
497fcf3ce44SJohn Forte 	 * return the cmd to the active queue and reacquire
498fcf3ce44SJohn Forte 	 * the locks.
499fcf3ce44SJohn Forte 	 */
500fcf3ce44SJohn Forte 	iscsi_dequeue_active_cmd(icp, icmdp);
501fcf3ce44SJohn Forte 
502fcf3ce44SJohn Forte 	/* update expcmdsn and maxcmdsn */
503fcf3ce44SJohn Forte 	iscsi_update_flow_control(isp, ntohl(idrhp->maxcmdsn),
504fcf3ce44SJohn Forte 	    ntohl(idrhp->expcmdsn));
505fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
506fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_queue_active.mutex);
507fcf3ce44SJohn Forte 
508fcf3ce44SJohn Forte 	/* shorthand some values */
509fcf3ce44SJohn Forte 	pkt = icmdp->cmd_un.scsi.pkt;
510fcf3ce44SJohn Forte 	bp = icmdp->cmd_un.scsi.bp;
511fcf3ce44SJohn Forte 	offset = ntohl(idrhp->offset);
512fcf3ce44SJohn Forte 	dlength = n2h24(idrhp->dlength);
513fcf3ce44SJohn Forte 
514fcf3ce44SJohn Forte 	/*
515fcf3ce44SJohn Forte 	 * some poorly behaved targets have been observed
516fcf3ce44SJohn Forte 	 * sending data-in pdu's during a write operation
517fcf3ce44SJohn Forte 	 */
518fcf3ce44SJohn Forte 	if (bp != NULL) {
519fcf3ce44SJohn Forte 		if (!(bp->b_flags & B_READ)) {
520fcf3ce44SJohn Forte 			cmn_err(CE_WARN,
521fcf3ce44SJohn Forte 			    "iscsi connection(%u) protocol error - "
522fcf3ce44SJohn Forte 			    "received data response during write operation "
523fcf3ce44SJohn Forte 			    "itt:0x%x",
524fcf3ce44SJohn Forte 			    icp->conn_oid, idrhp->itt);
525fcf3ce44SJohn Forte 			mutex_enter(&icp->conn_queue_active.mutex);
526fcf3ce44SJohn Forte 			iscsi_enqueue_active_cmd(icp, icmdp);
527fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_queue_active.mutex);
528fcf3ce44SJohn Forte 			return (ISCSI_STATUS_PROTOCOL_ERROR);
529fcf3ce44SJohn Forte 		}
530fcf3ce44SJohn Forte 
531fcf3ce44SJohn Forte 		/*
532fcf3ce44SJohn Forte 		 * We can't tolerate the target sending too much
533fcf3ce44SJohn Forte 		 * data for our buffer
534fcf3ce44SJohn Forte 		 */
535fcf3ce44SJohn Forte 		if ((dlength >
536fcf3ce44SJohn Forte 		    (bp->b_bcount - icmdp->cmd_un.scsi.data_transferred)) ||
537fcf3ce44SJohn Forte 		    (dlength > (bp->b_bcount - offset))) {
538fcf3ce44SJohn Forte 			cmn_err(CE_WARN,
539fcf3ce44SJohn Forte 			    "iscsi connection(%u) protocol error - "
540fcf3ce44SJohn Forte 			    "received too much data itt:0x%x",
541fcf3ce44SJohn Forte 			    icp->conn_oid, idrhp->itt);
542fcf3ce44SJohn Forte 			mutex_enter(&icp->conn_queue_active.mutex);
543fcf3ce44SJohn Forte 			iscsi_enqueue_active_cmd(icp, icmdp);
544fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_queue_active.mutex);
545fcf3ce44SJohn Forte 			return (ISCSI_STATUS_PROTOCOL_ERROR);
546fcf3ce44SJohn Forte 		}
547fcf3ce44SJohn Forte 
548fcf3ce44SJohn Forte 		bcp = ((char *)bp->b_un.b_addr) + offset;
549fcf3ce44SJohn Forte 
550fcf3ce44SJohn Forte 		/*
551fcf3ce44SJohn Forte 		 * Get the rest of the data and copy it directly into
552fcf3ce44SJohn Forte 		 * the scsi_pkt.
553fcf3ce44SJohn Forte 		 */
554fcf3ce44SJohn Forte 		rval = iscsi_net->recvdata(icp->conn_socket, ihp,
555fcf3ce44SJohn Forte 		    bcp, dlength, 0, (icp->conn_params.data_digest ?
556fcf3ce44SJohn Forte 		    ISCSI_NET_DATA_DIGEST : 0));
557fcf3ce44SJohn Forte 		if (ISCSI_SUCCESS(rval)) {
558fcf3ce44SJohn Forte 			KSTAT_ADD_CONN_RX_BYTES(icp, dlength);
559fcf3ce44SJohn Forte 		} else {
560fcf3ce44SJohn Forte 			/* If digest error flag icmdp with a crc error */
561fcf3ce44SJohn Forte 			if (rval == ISCSI_STATUS_DATA_DIGEST_ERROR) {
562fcf3ce44SJohn Forte 				icmdp->cmd_crc_error_seen = B_TRUE;
563fcf3ce44SJohn Forte 			}
564fcf3ce44SJohn Forte 			mutex_enter(&icp->conn_queue_active.mutex);
565fcf3ce44SJohn Forte 			iscsi_enqueue_active_cmd(icp, icmdp);
566fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_queue_active.mutex);
567fcf3ce44SJohn Forte 			return (rval);
568fcf3ce44SJohn Forte 		}
569fcf3ce44SJohn Forte 		isp->sess_rx_lbolt = icp->conn_rx_lbolt = ddi_get_lbolt();
570fcf3ce44SJohn Forte 
571fcf3ce44SJohn Forte 		/* update icmdp statistics */
572fcf3ce44SJohn Forte 		icmdp->cmd_un.scsi.data_transferred += dlength;
573fcf3ce44SJohn Forte 	}
574fcf3ce44SJohn Forte 
575fcf3ce44SJohn Forte 	/*
576fcf3ce44SJohn Forte 	 * We got status. This should only happen if we have
577fcf3ce44SJohn Forte 	 * received all the data with no errors.  The command
578fcf3ce44SJohn Forte 	 * must be completed now, since we won't get a command
579fcf3ce44SJohn Forte 	 * response PDU. The cmd_status and residual_count are
580fcf3ce44SJohn Forte 	 * not meaningful unless status_present is set.
581fcf3ce44SJohn Forte 	 */
582fcf3ce44SJohn Forte 	if (idrhp->flags & ISCSI_FLAG_DATA_STATUS) {
583fcf3ce44SJohn Forte 		pkt->pkt_resid = 0;
584fcf3ce44SJohn Forte 		/* Check the residual count */
585fcf3ce44SJohn Forte 		if (bp &&
586fcf3ce44SJohn Forte 		    (icmdp->cmd_un.scsi.data_transferred !=
587fcf3ce44SJohn Forte 		    bp->b_bcount)) {
588fcf3ce44SJohn Forte 			/*
589fcf3ce44SJohn Forte 			 * We didn't xfer the expected amount of data -
590fcf3ce44SJohn Forte 			 * the residual_count in the header is only valid
591fcf3ce44SJohn Forte 			 * if the underflow flag is set.
592fcf3ce44SJohn Forte 			 */
593fcf3ce44SJohn Forte 			if (idrhp->flags & ISCSI_FLAG_DATA_UNDERFLOW) {
594fcf3ce44SJohn Forte 				pkt->pkt_resid = ntohl(idrhp->residual_count);
595fcf3ce44SJohn Forte 			} else {
596fcf3ce44SJohn Forte 				if (bp->b_bcount >
597fcf3ce44SJohn Forte 				    icmdp->cmd_un.scsi.data_transferred) {
598fcf3ce44SJohn Forte 					/* Some data fell on the floor somehw */
599fcf3ce44SJohn Forte 					pkt->pkt_resid =
600fcf3ce44SJohn Forte 					    bp->b_bcount -
601fcf3ce44SJohn Forte 					    icmdp->cmd_un.scsi.data_transferred;
602fcf3ce44SJohn Forte 				}
603fcf3ce44SJohn Forte 			}
604fcf3ce44SJohn Forte 		}
605fcf3ce44SJohn Forte 
606fcf3ce44SJohn Forte 		pkt->pkt_reason = CMD_CMPLT;
607fcf3ce44SJohn Forte 		pkt->pkt_state |= (STATE_XFERRED_DATA | STATE_GOT_STATUS);
608fcf3ce44SJohn Forte 
609fcf3ce44SJohn Forte 		if (((idrhp->cmd_status & STATUS_MASK) != STATUS_GOOD) &&
610fcf3ce44SJohn Forte 		    (icmdp->cmd_un.scsi.statuslen >=
611fcf3ce44SJohn Forte 		    sizeof (struct scsi_arq_status)) && pkt->pkt_scbp) {
612fcf3ce44SJohn Forte 
613fcf3ce44SJohn Forte 			/*
614fcf3ce44SJohn Forte 			 * Not supposed to get exception status here!
615fcf3ce44SJohn Forte 			 * We have no request sense data so just do the
616fcf3ce44SJohn Forte 			 * best we can
617fcf3ce44SJohn Forte 			 */
618fcf3ce44SJohn Forte 			struct scsi_arq_status *arqstat =
619fcf3ce44SJohn Forte 			    (struct scsi_arq_status *)pkt->pkt_scbp;
620fcf3ce44SJohn Forte 
621fcf3ce44SJohn Forte 
622fcf3ce44SJohn Forte 			bzero(arqstat, sizeof (struct scsi_arq_status));
623fcf3ce44SJohn Forte 
624fcf3ce44SJohn Forte 			*((uchar_t *)&arqstat->sts_status) =
625fcf3ce44SJohn Forte 			    idrhp->cmd_status;
626fcf3ce44SJohn Forte 
627fcf3ce44SJohn Forte 			arqstat->sts_rqpkt_resid =
628fcf3ce44SJohn Forte 			    sizeof (struct scsi_extended_sense);
629fcf3ce44SJohn Forte 
630fcf3ce44SJohn Forte 		} else if (pkt->pkt_scbp) {
631fcf3ce44SJohn Forte 			/* just pass along the status we got */
632fcf3ce44SJohn Forte 			pkt->pkt_scbp[0] = idrhp->cmd_status;
633fcf3ce44SJohn Forte 		}
634fcf3ce44SJohn Forte 
635fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_queue_active.mutex);
636fcf3ce44SJohn Forte 		iscsi_enqueue_active_cmd(icp, icmdp);
637fcf3ce44SJohn Forte 		iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
638fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
639fcf3ce44SJohn Forte 	} else {
640fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_queue_active.mutex);
641fcf3ce44SJohn Forte 		iscsi_enqueue_active_cmd(icp, icmdp);
642fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
643fcf3ce44SJohn Forte 	}
644fcf3ce44SJohn Forte 
645fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
646fcf3ce44SJohn Forte }
647fcf3ce44SJohn Forte 
648fcf3ce44SJohn Forte 
649fcf3ce44SJohn Forte /*
650fcf3ce44SJohn Forte  * iscsi_rx_process_cmd_rsp - Process received scsi command response.  This
651fcf3ce44SJohn Forte  * will contain sense data if the command was not successful.  This data needs
652fcf3ce44SJohn Forte  * to be copied into the scsi_pkt.  Otherwise we just complete the IO.
653fcf3ce44SJohn Forte  */
654fcf3ce44SJohn Forte static iscsi_status_t
655fcf3ce44SJohn Forte iscsi_rx_process_cmd_rsp(iscsi_conn_t *icp, iscsi_hdr_t *ihp, char *data)
656fcf3ce44SJohn Forte {
657fcf3ce44SJohn Forte 	iscsi_sess_t		*isp		= icp->conn_sess;
658fcf3ce44SJohn Forte 	iscsi_scsi_rsp_hdr_t	*issrhp		= (iscsi_scsi_rsp_hdr_t *)ihp;
659fcf3ce44SJohn Forte 	iscsi_cmd_t		*icmdp		= NULL;
660fcf3ce44SJohn Forte 	struct scsi_pkt		*pkt		= NULL;
661fcf3ce44SJohn Forte 	uint32_t		dlength		= 0;
662fcf3ce44SJohn Forte 	struct scsi_arq_status	*arqstat	= NULL;
663fcf3ce44SJohn Forte 	size_t			senselen	= 0;
664b4243054SSheng-Liang Eric Zhang 	int			statuslen	= 0;
665fcf3ce44SJohn Forte 
666fcf3ce44SJohn Forte 	/* make sure we get status in order */
667fcf3ce44SJohn Forte 	if (icp->conn_expstatsn == ntohl(issrhp->statsn)) {
668fcf3ce44SJohn Forte 		icp->conn_expstatsn++;
669fcf3ce44SJohn Forte 	} else {
670fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
671fcf3ce44SJohn Forte 		    "received status out of order itt:0x%x statsn:0x%x "
672fcf3ce44SJohn Forte 		    "expstatsn:0x%x", icp->conn_oid, issrhp->itt,
673fcf3ce44SJohn Forte 		    ntohl(issrhp->statsn), icp->conn_expstatsn);
674fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
675fcf3ce44SJohn Forte 	}
676fcf3ce44SJohn Forte 
677fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
678fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
679fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(isp, ihp, &icmdp))) {
680fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_cmdsn_mutex);
681fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
682fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
683fcf3ce44SJohn Forte 	}
684fcf3ce44SJohn Forte 
685fcf3ce44SJohn Forte 	/* update expcmdsn and maxcmdsn */
686fcf3ce44SJohn Forte 	iscsi_update_flow_control(isp, ntohl(issrhp->maxcmdsn),
687fcf3ce44SJohn Forte 	    ntohl(issrhp->expcmdsn));
688fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
689fcf3ce44SJohn Forte 
690fcf3ce44SJohn Forte 	pkt = icmdp->cmd_un.scsi.pkt;
691fcf3ce44SJohn Forte 
692fcf3ce44SJohn Forte 	if (issrhp->response) {
693fcf3ce44SJohn Forte 		/* The target failed the command. */
694fcf3ce44SJohn Forte 		pkt->pkt_reason = CMD_TRAN_ERR;
695fcf3ce44SJohn Forte 		if (icmdp->cmd_un.scsi.bp) {
696fcf3ce44SJohn Forte 			pkt->pkt_resid = icmdp->cmd_un.scsi.bp->b_bcount;
697fcf3ce44SJohn Forte 		} else {
698fcf3ce44SJohn Forte 			pkt->pkt_resid = 0;
699fcf3ce44SJohn Forte 		}
700fcf3ce44SJohn Forte 	} else {
701fcf3ce44SJohn Forte 		/* success */
702fcf3ce44SJohn Forte 		pkt->pkt_resid = 0;
703fcf3ce44SJohn Forte 		/* Check the residual count */
704fcf3ce44SJohn Forte 		if ((icmdp->cmd_un.scsi.bp) &&
705fcf3ce44SJohn Forte 		    (icmdp->cmd_un.scsi.data_transferred !=
706fcf3ce44SJohn Forte 		    icmdp->cmd_un.scsi.bp->b_bcount)) {
707fcf3ce44SJohn Forte 			/*
708fcf3ce44SJohn Forte 			 * We didn't xfer the expected amount of data -
709fcf3ce44SJohn Forte 			 * the residual_count in the header is only
710fcf3ce44SJohn Forte 			 * valid if the underflow flag is set.
711fcf3ce44SJohn Forte 			 */
712fcf3ce44SJohn Forte 			if (issrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
713fcf3ce44SJohn Forte 				pkt->pkt_resid = ntohl(issrhp->residual_count);
714fcf3ce44SJohn Forte 			} else {
715fcf3ce44SJohn Forte 				if (icmdp->cmd_un.scsi.bp->b_bcount >
716fcf3ce44SJohn Forte 				    icmdp->cmd_un.scsi.data_transferred) {
717fcf3ce44SJohn Forte 					/*
718fcf3ce44SJohn Forte 					 * Some data fell on the floor
719fcf3ce44SJohn Forte 					 * somehow - probably a CRC error
720fcf3ce44SJohn Forte 					 */
721fcf3ce44SJohn Forte 					pkt->pkt_resid =
722fcf3ce44SJohn Forte 					    icmdp->cmd_un.scsi.bp->b_bcount -
723fcf3ce44SJohn Forte 					    icmdp->cmd_un.scsi.data_transferred;
724fcf3ce44SJohn Forte 				}
725fcf3ce44SJohn Forte 			}
726fcf3ce44SJohn Forte 		}
727fcf3ce44SJohn Forte 
728fcf3ce44SJohn Forte 		/* set flags that tell SCSA that the command is complete */
729fcf3ce44SJohn Forte 		if (icmdp->cmd_crc_error_seen == B_FALSE) {
730fcf3ce44SJohn Forte 			/* Set successful completion */
731fcf3ce44SJohn Forte 			pkt->pkt_reason = CMD_CMPLT;
732fcf3ce44SJohn Forte 			if (icmdp->cmd_un.scsi.bp) {
733fcf3ce44SJohn Forte 				pkt->pkt_state |= (STATE_XFERRED_DATA |
734fcf3ce44SJohn Forte 				    STATE_GOT_STATUS);
735fcf3ce44SJohn Forte 			} else {
736fcf3ce44SJohn Forte 				pkt->pkt_state |= STATE_GOT_STATUS;
737fcf3ce44SJohn Forte 			}
738fcf3ce44SJohn Forte 		} else {
739fcf3ce44SJohn Forte 			/*
740fcf3ce44SJohn Forte 			 * Some of the data was found to have an incorrect
741fcf3ce44SJohn Forte 			 * error at the protocol error.
742fcf3ce44SJohn Forte 			 */
743fcf3ce44SJohn Forte 			pkt->pkt_reason = CMD_PER_FAIL;
744fcf3ce44SJohn Forte 			pkt->pkt_statistics |= STAT_PERR;
745fcf3ce44SJohn Forte 			if (icmdp->cmd_un.scsi.bp) {
746fcf3ce44SJohn Forte 				pkt->pkt_resid =
747fcf3ce44SJohn Forte 				    icmdp->cmd_un.scsi.bp->b_bcount;
748fcf3ce44SJohn Forte 			} else {
749fcf3ce44SJohn Forte 				pkt->pkt_resid = 0;
750fcf3ce44SJohn Forte 			}
751fcf3ce44SJohn Forte 		}
752fcf3ce44SJohn Forte 
753fcf3ce44SJohn Forte 		dlength = n2h24(issrhp->dlength);
754fcf3ce44SJohn Forte 
755fcf3ce44SJohn Forte 		/*
756fcf3ce44SJohn Forte 		 * Process iSCSI Cmd Response Status
757fcf3ce44SJohn Forte 		 * RFC 3720 Sectionn 10.4.2.
758fcf3ce44SJohn Forte 		 */
759fcf3ce44SJohn Forte 		switch (issrhp->cmd_status & STATUS_MASK) {
760fcf3ce44SJohn Forte 		case STATUS_GOOD:
761fcf3ce44SJohn Forte 			/* pass SCSI status up stack */
762fcf3ce44SJohn Forte 			if (pkt->pkt_scbp) {
763fcf3ce44SJohn Forte 				pkt->pkt_scbp[0] = issrhp->cmd_status;
764fcf3ce44SJohn Forte 			}
765fcf3ce44SJohn Forte 			break;
766fcf3ce44SJohn Forte 		case STATUS_CHECK:
767fcf3ce44SJohn Forte 			/*
768fcf3ce44SJohn Forte 			 * Verify we received a sense buffer and
769fcf3ce44SJohn Forte 			 * that there is the correct amount of
770fcf3ce44SJohn Forte 			 * request sense space to copy it to.
771fcf3ce44SJohn Forte 			 */
772fcf3ce44SJohn Forte 			if ((dlength > 1) &&
773fcf3ce44SJohn Forte 			    (pkt->pkt_scbp != NULL) &&
774fcf3ce44SJohn Forte 			    (icmdp->cmd_un.scsi.statuslen >=
775fcf3ce44SJohn Forte 			    sizeof (struct scsi_arq_status))) {
776fcf3ce44SJohn Forte 				/*
777fcf3ce44SJohn Forte 				 * If a bad command status is received we
778fcf3ce44SJohn Forte 				 * need to reset the pkt_resid to zero.
779fcf3ce44SJohn Forte 				 * The target driver compares its value
780fcf3ce44SJohn Forte 				 * before checking other error flags.
781fcf3ce44SJohn Forte 				 * (ex. check conditions)
782fcf3ce44SJohn Forte 				 */
783fcf3ce44SJohn Forte 				pkt->pkt_resid = 0;
784fcf3ce44SJohn Forte 
785fcf3ce44SJohn Forte 				/* get sense length from first 2 bytes */
786fcf3ce44SJohn Forte 				senselen = ((data[0] << 8) | data[1]) &
787fcf3ce44SJohn Forte 				    (size_t)0xFFFF;
788fcf3ce44SJohn Forte 
789fcf3ce44SJohn Forte 				/* Sanity-check on the sense length */
790fcf3ce44SJohn Forte 				if ((senselen + 2) > dlength) {
791fcf3ce44SJohn Forte 					senselen = dlength - 2;
792fcf3ce44SJohn Forte 				}
793fcf3ce44SJohn Forte 
794fcf3ce44SJohn Forte 				/*
795fcf3ce44SJohn Forte 				 * If there was a Data Digest error then
796fcf3ce44SJohn Forte 				 * the sense data cannot be trusted.
797fcf3ce44SJohn Forte 				 */
798fcf3ce44SJohn Forte 				if (icmdp->cmd_crc_error_seen) {
799fcf3ce44SJohn Forte 					senselen = 0;
800fcf3ce44SJohn Forte 				}
801fcf3ce44SJohn Forte 
802fcf3ce44SJohn Forte 				/* automatic request sense */
803fcf3ce44SJohn Forte 				arqstat =
804fcf3ce44SJohn Forte 				    (struct scsi_arq_status *)pkt->pkt_scbp;
805fcf3ce44SJohn Forte 
806fcf3ce44SJohn Forte 				/* pass SCSI status up stack */
807fcf3ce44SJohn Forte 				*((uchar_t *)&arqstat->sts_status) =
808fcf3ce44SJohn Forte 				    issrhp->cmd_status;
809fcf3ce44SJohn Forte 
810fcf3ce44SJohn Forte 				/*
811fcf3ce44SJohn Forte 				 * Set the status for the automatic
812fcf3ce44SJohn Forte 				 * request sense command
813fcf3ce44SJohn Forte 				 */
814fcf3ce44SJohn Forte 				arqstat->sts_rqpkt_state = (STATE_GOT_BUS |
815fcf3ce44SJohn Forte 				    STATE_GOT_TARGET | STATE_SENT_CMD |
816fcf3ce44SJohn Forte 				    STATE_XFERRED_DATA | STATE_GOT_STATUS |
817fcf3ce44SJohn Forte 				    STATE_ARQ_DONE);
818fcf3ce44SJohn Forte 
819fcf3ce44SJohn Forte 				*((uchar_t *)&arqstat->sts_rqpkt_status) =
820fcf3ce44SJohn Forte 				    STATUS_GOOD;
821fcf3ce44SJohn Forte 
822fcf3ce44SJohn Forte 				arqstat->sts_rqpkt_reason = CMD_CMPLT;
823fcf3ce44SJohn Forte 
824b4243054SSheng-Liang Eric Zhang 				statuslen = icmdp->cmd_un.scsi.statuslen;
825b4243054SSheng-Liang Eric Zhang 
826fcf3ce44SJohn Forte 				if (senselen == 0) {
827fcf3ce44SJohn Forte 					/* auto request sense failed */
828fcf3ce44SJohn Forte 					arqstat->sts_rqpkt_status.sts_chk = 1;
829fcf3ce44SJohn Forte 					arqstat->sts_rqpkt_resid =
830b4243054SSheng-Liang Eric Zhang 					    statuslen;
831fcf3ce44SJohn Forte 				} else if (senselen <
832b4243054SSheng-Liang Eric Zhang 				    statuslen) {
833fcf3ce44SJohn Forte 					/* auto request sense short */
834fcf3ce44SJohn Forte 					arqstat->sts_rqpkt_resid =
835b4243054SSheng-Liang Eric Zhang 					    statuslen
836fcf3ce44SJohn Forte 					    - senselen;
837fcf3ce44SJohn Forte 				} else {
838fcf3ce44SJohn Forte 					/* auto request sense complete */
839fcf3ce44SJohn Forte 					arqstat->sts_rqpkt_resid = 0;
840fcf3ce44SJohn Forte 				}
841fcf3ce44SJohn Forte 				arqstat->sts_rqpkt_statistics = 0;
842fcf3ce44SJohn Forte 				pkt->pkt_state |= STATE_ARQ_DONE;
843fcf3ce44SJohn Forte 
844b4243054SSheng-Liang Eric Zhang 				if (icmdp->cmd_misc_flags &
845b4243054SSheng-Liang Eric Zhang 				    ISCSI_CMD_MISCFLAG_XARQ) {
846b4243054SSheng-Liang Eric Zhang 					pkt->pkt_state |= STATE_XARQ_DONE;
847b4243054SSheng-Liang Eric Zhang 				}
848b4243054SSheng-Liang Eric Zhang 
849fcf3ce44SJohn Forte 				/* copy auto request sense */
850fcf3ce44SJohn Forte 				dlength = min(senselen,
851b4243054SSheng-Liang Eric Zhang 				    statuslen);
852fcf3ce44SJohn Forte 				if (dlength) {
853fcf3ce44SJohn Forte 					bcopy(&data[2], (uchar_t *)&arqstat->
854fcf3ce44SJohn Forte 					    sts_sensedata, dlength);
855fcf3ce44SJohn Forte 				}
856fcf3ce44SJohn Forte 				break;
857fcf3ce44SJohn Forte 			}
858fcf3ce44SJohn Forte 			/* FALLTHRU */
859fcf3ce44SJohn Forte 		case STATUS_BUSY:
860fcf3ce44SJohn Forte 		case STATUS_RESERVATION_CONFLICT:
861fcf3ce44SJohn Forte 		case STATUS_QFULL:
862fcf3ce44SJohn Forte 		case STATUS_ACA_ACTIVE:
863fcf3ce44SJohn Forte 		default:
864fcf3ce44SJohn Forte 			/*
865fcf3ce44SJohn Forte 			 * If a bad command status is received we need to
866fcf3ce44SJohn Forte 			 * reset the pkt_resid to zero.  The target driver
867fcf3ce44SJohn Forte 			 * compares its value before checking other error
868fcf3ce44SJohn Forte 			 * flags. (ex. check conditions)
869fcf3ce44SJohn Forte 			 */
870fcf3ce44SJohn Forte 			pkt->pkt_resid = 0;
871fcf3ce44SJohn Forte 			/* pass SCSI status up stack */
872fcf3ce44SJohn Forte 			if (pkt->pkt_scbp) {
873fcf3ce44SJohn Forte 				pkt->pkt_scbp[0] = issrhp->cmd_status;
874fcf3ce44SJohn Forte 			}
875fcf3ce44SJohn Forte 		}
876fcf3ce44SJohn Forte 	}
877fcf3ce44SJohn Forte 
878fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
879fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_queue_active.mutex);
880fcf3ce44SJohn Forte 
881fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
882fcf3ce44SJohn Forte }
883fcf3ce44SJohn Forte 
884fcf3ce44SJohn Forte /*
885fcf3ce44SJohn Forte  * iscsi_rx_process_rtt_rsp - Process received RTT.  This means the target is
886fcf3ce44SJohn Forte  * requesting data.
887fcf3ce44SJohn Forte  */
888fcf3ce44SJohn Forte /* ARGSUSED */
889fcf3ce44SJohn Forte static iscsi_status_t
890fcf3ce44SJohn Forte iscsi_rx_process_rtt_rsp(iscsi_conn_t *icp, iscsi_hdr_t *ihp, char *data)
891fcf3ce44SJohn Forte {
892fcf3ce44SJohn Forte 	iscsi_sess_t		*isp = (iscsi_sess_t *)icp->conn_sess;
893fcf3ce44SJohn Forte 	iscsi_rtt_hdr_t		*irhp		= (iscsi_rtt_hdr_t *)ihp;
894fcf3ce44SJohn Forte 	iscsi_cmd_t		*icmdp		= NULL;
895fcf3ce44SJohn Forte 	struct buf		*bp		= NULL;
896fcf3ce44SJohn Forte 	uint32_t		data_length;
897fcf3ce44SJohn Forte 	iscsi_status_t		status = ISCSI_STATUS_PROTOCOL_ERROR;
898fcf3ce44SJohn Forte 
899fcf3ce44SJohn Forte 
900fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
901fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
902fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
903fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(isp, ihp, &icmdp))) {
904fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_cmdsn_mutex);
905fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
906fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_queue_pending.mutex);
907fcf3ce44SJohn Forte 		return (status);
908fcf3ce44SJohn Forte 	}
909fcf3ce44SJohn Forte 
910fcf3ce44SJohn Forte 	/* update expcmdsn and maxcmdsn */
911fcf3ce44SJohn Forte 	iscsi_update_flow_control(isp, ntohl(irhp->maxcmdsn),
912fcf3ce44SJohn Forte 	    ntohl(irhp->expcmdsn));
913fcf3ce44SJohn Forte 	mutex_enter(&icmdp->cmd_mutex);
914fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
915fcf3ce44SJohn Forte 
916fcf3ce44SJohn Forte 	bp = icmdp->cmd_un.scsi.bp;
917fcf3ce44SJohn Forte 	data_length = ntohl(irhp->data_length);
918fcf3ce44SJohn Forte 
919fcf3ce44SJohn Forte 	/*
920fcf3ce44SJohn Forte 	 * Perform boundary-checks per RFC 3720 (section 10.8.4).
921fcf3ce44SJohn Forte 	 * The Desired Data Transfer Length must satisfy this relation:
922fcf3ce44SJohn Forte 	 *
923fcf3ce44SJohn Forte 	 *	0 < Desired Data Transfer Length <= MaxBurstLength
924fcf3ce44SJohn Forte 	 */
925fcf3ce44SJohn Forte 	if ((bp == NULL) || (data_length == 0)) {
926fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) received r2t but pkt "
927fcf3ce44SJohn Forte 		    "has no data itt:0x%x - protocol error", icp->conn_oid,
928fcf3ce44SJohn Forte 		    irhp->itt);
929fcf3ce44SJohn Forte 	} else if (data_length > icp->conn_params.max_burst_length) {
930fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) received r2t but pkt "
931fcf3ce44SJohn Forte 		    "is larger than MaxBurstLength itt:0x%x len:0x%x - "
932fcf3ce44SJohn Forte 		    "protocol error",
933fcf3ce44SJohn Forte 		    icp->conn_oid, irhp->itt, data_length);
934fcf3ce44SJohn Forte 	} else {
935fcf3ce44SJohn Forte 		iscsi_handle_r2t(icp, icmdp, ntohl(irhp->data_offset),
936fcf3ce44SJohn Forte 		    data_length, irhp->ttt);
937fcf3ce44SJohn Forte 		status = ISCSI_STATUS_SUCCESS;
938fcf3ce44SJohn Forte 	}
939fcf3ce44SJohn Forte 
940fcf3ce44SJohn Forte 	mutex_exit(&icmdp->cmd_mutex);
941fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_queue_active.mutex);
942fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
943fcf3ce44SJohn Forte 
944fcf3ce44SJohn Forte 	return (status);
945fcf3ce44SJohn Forte }
946fcf3ce44SJohn Forte 
947fcf3ce44SJohn Forte 
948fcf3ce44SJohn Forte /*
949fcf3ce44SJohn Forte  * iscsi_rx_process_nop - Process a received nop.  If nop is in response
950fcf3ce44SJohn Forte  * to a ping we sent update stats.  If initiated by the target we need
951fcf3ce44SJohn Forte  * to response back to the target with a nop.  Schedule the response.
952fcf3ce44SJohn Forte  */
953fcf3ce44SJohn Forte /* ARGSUSED */
954fcf3ce44SJohn Forte static iscsi_status_t
955fcf3ce44SJohn Forte iscsi_rx_process_nop(iscsi_conn_t *icp, iscsi_hdr_t *ihp, char *data)
956fcf3ce44SJohn Forte {
957fcf3ce44SJohn Forte 	iscsi_status_t		rval	= ISCSI_STATUS_SUCCESS;
958fcf3ce44SJohn Forte 	iscsi_sess_t		*isp	= NULL;
959fcf3ce44SJohn Forte 	iscsi_nop_in_hdr_t	*inihp	= (iscsi_nop_in_hdr_t *)ihp;
960fcf3ce44SJohn Forte 	iscsi_cmd_t		*icmdp	= NULL;
961fcf3ce44SJohn Forte 
962fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
963fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
964fcf3ce44SJohn Forte 	/* ASSERT(data != NULL) data is allowed to be NULL */
965fcf3ce44SJohn Forte 	isp = icp->conn_sess;
966fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
967fcf3ce44SJohn Forte 
968fcf3ce44SJohn Forte 	if (icp->conn_expstatsn != ntohl(inihp->statsn)) {
969fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
970fcf3ce44SJohn Forte 		    "received status out of order itt:0x%x statsn:0x%x "
971fcf3ce44SJohn Forte 		    "expstatsn:0x%x", icp->conn_oid, inihp->itt,
972fcf3ce44SJohn Forte 		    ntohl(inihp->statsn), icp->conn_expstatsn);
973fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
974fcf3ce44SJohn Forte 	}
975fcf3ce44SJohn Forte 
976fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
977fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
978fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
979fcf3ce44SJohn Forte 	if (inihp->itt != ISCSI_RSVD_TASK_TAG) {
980fcf3ce44SJohn Forte 		if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(
981fcf3ce44SJohn Forte 		    isp, ihp, &icmdp))) {
982fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
983fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_queue_active.mutex);
984fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_queue_pending.mutex);
985fcf3ce44SJohn Forte 			return (ISCSI_STATUS_PROTOCOL_ERROR);
986fcf3ce44SJohn Forte 		}
987fcf3ce44SJohn Forte 	}
988fcf3ce44SJohn Forte 
989fcf3ce44SJohn Forte 	/* update expcmdsn and maxcmdsn */
990fcf3ce44SJohn Forte 	iscsi_update_flow_control(isp, ntohl(inihp->maxcmdsn),
991fcf3ce44SJohn Forte 	    ntohl(inihp->expcmdsn));
992fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
993fcf3ce44SJohn Forte 
994fcf3ce44SJohn Forte 	if ((inihp->itt != ISCSI_RSVD_TASK_TAG) &&
995fcf3ce44SJohn Forte 	    (inihp->ttt == ISCSI_RSVD_TASK_TAG)) {
996fcf3ce44SJohn Forte 		/* This is the only type of nop that incs. the expstatsn */
997fcf3ce44SJohn Forte 		icp->conn_expstatsn++;
998fcf3ce44SJohn Forte 
999fcf3ce44SJohn Forte 		/*
1000fcf3ce44SJohn Forte 		 * This is a targets response to our nop
1001fcf3ce44SJohn Forte 		 */
1002fcf3ce44SJohn Forte 		iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
1003fcf3ce44SJohn Forte 	} else if (inihp->ttt != ISCSI_RSVD_TASK_TAG) {
1004fcf3ce44SJohn Forte 		/*
1005fcf3ce44SJohn Forte 		 * Target requested a nop.  Send one.
1006fcf3ce44SJohn Forte 		 */
1007fcf3ce44SJohn Forte 		iscsi_handle_nop(icp, ISCSI_RSVD_TASK_TAG, inihp->ttt);
1008fcf3ce44SJohn Forte 	} else {
1009fcf3ce44SJohn Forte 		/*
1010fcf3ce44SJohn Forte 		 * This is a target-initiated ping that doesn't expect
1011fcf3ce44SJohn Forte 		 * a response; nothing to do except update our flow control
1012fcf3ce44SJohn Forte 		 * (which we do in all cases above).
1013fcf3ce44SJohn Forte 		 */
1014fcf3ce44SJohn Forte 		/* EMPTY */
1015fcf3ce44SJohn Forte 	}
1016fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_queue_active.mutex);
1017fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
1018fcf3ce44SJohn Forte 
1019fcf3ce44SJohn Forte 	return (rval);
1020fcf3ce44SJohn Forte }
1021fcf3ce44SJohn Forte 
1022fcf3ce44SJohn Forte 
1023fcf3ce44SJohn Forte /*
1024fcf3ce44SJohn Forte  * iscsi_rx_process_reject_rsp - The server rejected a PDU
1025fcf3ce44SJohn Forte  */
1026fcf3ce44SJohn Forte static iscsi_status_t
1027fcf3ce44SJohn Forte iscsi_rx_process_reject_rsp(iscsi_conn_t *icp,
1028fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, char *data)
1029fcf3ce44SJohn Forte {
1030fcf3ce44SJohn Forte 	iscsi_reject_rsp_hdr_t		*irrhp = (iscsi_reject_rsp_hdr_t *)ihp;
1031fcf3ce44SJohn Forte 	iscsi_sess_t			*isp		= NULL;
1032fcf3ce44SJohn Forte 	uint32_t			dlength		= 0;
1033fcf3ce44SJohn Forte 	iscsi_hdr_t			*old_ihp	= NULL;
1034fcf3ce44SJohn Forte 
1035fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1036fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1037fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
1038fcf3ce44SJohn Forte 	ASSERT(data != NULL);
1039fcf3ce44SJohn Forte 
1040fcf3ce44SJohn Forte 	/* make sure we only Ack Status numbers that we've actually received. */
1041fcf3ce44SJohn Forte 	if (icp->conn_expstatsn == ntohl(irrhp->statsn)) {
1042fcf3ce44SJohn Forte 		icp->conn_expstatsn++;
1043fcf3ce44SJohn Forte 	} else {
1044fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
1045fcf3ce44SJohn Forte 		    "received status out of order itt:0x%x statsn:0x%x "
1046fcf3ce44SJohn Forte 		    "expstatsn:0x%x", icp->conn_oid, ihp->itt,
1047fcf3ce44SJohn Forte 		    ntohl(irrhp->statsn), icp->conn_expstatsn);
1048fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1049fcf3ce44SJohn Forte 	}
1050fcf3ce44SJohn Forte 
1051fcf3ce44SJohn Forte 	/* update expcmdsn and maxcmdsn */
1052fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
1053fcf3ce44SJohn Forte 	iscsi_update_flow_control(isp, ntohl(irrhp->maxcmdsn),
1054fcf3ce44SJohn Forte 	    ntohl(irrhp->expcmdsn));
1055fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
1056fcf3ce44SJohn Forte 
1057fcf3ce44SJohn Forte 	/* If we don't have the rejected header we can't do anything */
1058fcf3ce44SJohn Forte 	dlength = n2h24(irrhp->dlength);
1059fcf3ce44SJohn Forte 	if (dlength < sizeof (iscsi_hdr_t)) {
1060fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1061fcf3ce44SJohn Forte 	}
1062fcf3ce44SJohn Forte 
1063fcf3ce44SJohn Forte 	/* map old ihp */
1064fcf3ce44SJohn Forte 	old_ihp = (iscsi_hdr_t *)data;
1065fcf3ce44SJohn Forte 
1066fcf3ce44SJohn Forte 	switch (irrhp->reason) {
1067fcf3ce44SJohn Forte 	/*
1068fcf3ce44SJohn Forte 	 * ISCSI_REJECT_IMM_CMD_REJECT - Immediate Command Reject
1069fcf3ce44SJohn Forte 	 * too many immediate commands (original cmd can be resent)
1070fcf3ce44SJohn Forte 	 */
1071fcf3ce44SJohn Forte 	case ISCSI_REJECT_IMM_CMD_REJECT:
1072fcf3ce44SJohn Forte 		/*
1073fcf3ce44SJohn Forte 		 * We have exceeded the server's capacity for outstanding
1074fcf3ce44SJohn Forte 		 * immediate commands.   This must be a task management
1075fcf3ce44SJohn Forte 		 * command so try to find it in the abortingqueue and
1076fcf3ce44SJohn Forte 		 * complete it.
1077fcf3ce44SJohn Forte 		 */
1078fcf3ce44SJohn Forte 		if (!(old_ihp->opcode & ISCSI_OP_IMMEDIATE)) {
1079fcf3ce44SJohn Forte 			/* Rejecting IMM but old old_hdr wasn't IMM */
1080fcf3ce44SJohn Forte 			return (ISCSI_STATUS_PROTOCOL_ERROR);
1081fcf3ce44SJohn Forte 		}
1082fcf3ce44SJohn Forte 
1083fcf3ce44SJohn Forte 		/*
1084fcf3ce44SJohn Forte 		 * We only send NOP and TASK_MGT as IMM.  All other
1085fcf3ce44SJohn Forte 		 * cases should be considered as a protocol error.
1086fcf3ce44SJohn Forte 		 */
1087fcf3ce44SJohn Forte 		switch (old_ihp->opcode & ISCSI_OPCODE_MASK) {
1088fcf3ce44SJohn Forte 		case ISCSI_OP_NOOP_OUT:
1089fcf3ce44SJohn Forte 			/*
1090fcf3ce44SJohn Forte 			 * A ping was rejected - treat this like
1091fcf3ce44SJohn Forte 			 * ping response.  The down side is we
1092fcf3ce44SJohn Forte 			 * didn't get an updated MaxCmdSn.
1093fcf3ce44SJohn Forte 			 */
1094fcf3ce44SJohn Forte 			break;
1095fcf3ce44SJohn Forte 		case ISCSI_OP_SCSI_TASK_MGT_MSG:
1096fcf3ce44SJohn Forte 			(void) iscsi_rx_process_rejected_tsk_mgt(icp,
1097fcf3ce44SJohn Forte 			    old_ihp);
1098fcf3ce44SJohn Forte 			break;
1099fcf3ce44SJohn Forte 		default:
1100fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) protocol error "
1101fcf3ce44SJohn Forte 			    "- received a reject for a command(0x%02x) not "
1102fcf3ce44SJohn Forte 			    "sent as an immediate", icp->conn_oid,
1103fcf3ce44SJohn Forte 			    old_ihp->opcode);
1104fcf3ce44SJohn Forte 			return (ISCSI_STATUS_PROTOCOL_ERROR);
1105fcf3ce44SJohn Forte 		}
1106fcf3ce44SJohn Forte 		break;
1107fcf3ce44SJohn Forte 
1108fcf3ce44SJohn Forte 	/*
1109fcf3ce44SJohn Forte 	 * For the rest of the reject cases just use the general
1110fcf3ce44SJohn Forte 	 * hammer of dis/reconnecting.  This will resolve all
1111fcf3ce44SJohn Forte 	 * noted issues although could be more graceful.
1112fcf3ce44SJohn Forte 	 */
1113fcf3ce44SJohn Forte 	case ISCSI_REJECT_DATA_DIGEST_ERROR:
1114fcf3ce44SJohn Forte 	case ISCSI_REJECT_CMD_BEFORE_LOGIN:
1115fcf3ce44SJohn Forte 	case ISCSI_REJECT_SNACK_REJECT:
1116fcf3ce44SJohn Forte 	case ISCSI_REJECT_PROTOCOL_ERROR:
1117fcf3ce44SJohn Forte 	case ISCSI_REJECT_CMD_NOT_SUPPORTED:
1118fcf3ce44SJohn Forte 	case ISCSI_REJECT_TASK_IN_PROGRESS:
1119fcf3ce44SJohn Forte 	case ISCSI_REJECT_INVALID_DATA_ACK:
1120fcf3ce44SJohn Forte 	case ISCSI_REJECT_INVALID_PDU_FIELD:
1121fcf3ce44SJohn Forte 	case ISCSI_REJECT_LONG_OPERATION_REJECT:
1122fcf3ce44SJohn Forte 	case ISCSI_REJECT_NEGOTIATION_RESET:
1123fcf3ce44SJohn Forte 	default:
1124fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) closing connection - "
1125fcf3ce44SJohn Forte 		    "target requested itt:0x%x reason:0x%x",
1126fcf3ce44SJohn Forte 		    icp->conn_oid, ihp->itt, irrhp->reason);
1127fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1128fcf3ce44SJohn Forte 	}
1129fcf3ce44SJohn Forte 
1130fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
1131fcf3ce44SJohn Forte }
1132fcf3ce44SJohn Forte 
1133fcf3ce44SJohn Forte 
1134fcf3ce44SJohn Forte /*
1135fcf3ce44SJohn Forte  * iscsi_rx_process_rejected_tsk_mgt -
1136fcf3ce44SJohn Forte  */
1137fcf3ce44SJohn Forte static iscsi_status_t
1138fcf3ce44SJohn Forte iscsi_rx_process_rejected_tsk_mgt(iscsi_conn_t *icp,
1139fcf3ce44SJohn Forte     iscsi_hdr_t *old_ihp)
1140fcf3ce44SJohn Forte {
1141fcf3ce44SJohn Forte 	iscsi_sess_t			*isp	= NULL;
1142fcf3ce44SJohn Forte 	iscsi_cmd_t			*icmdp	= NULL;
1143fcf3ce44SJohn Forte 
1144fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1145fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1146fcf3ce44SJohn Forte 	ASSERT(old_ihp != NULL);
1147fcf3ce44SJohn Forte 	ASSERT(icp->conn_sess != NULL);
1148fcf3ce44SJohn Forte 
1149fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
1150fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
1151fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(
1152fcf3ce44SJohn Forte 	    isp, old_ihp, &icmdp))) {
1153fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_cmdsn_mutex);
1154fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
1155fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1156fcf3ce44SJohn Forte 	}
1157fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
1158fcf3ce44SJohn Forte 
1159fcf3ce44SJohn Forte 	switch (icmdp->cmd_type) {
1160fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_ABORT:
1161fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_RESET:
1162fcf3ce44SJohn Forte 		iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E4,
1163fcf3ce44SJohn Forte 		    icp->conn_sess);
1164fcf3ce44SJohn Forte 		break;
1165fcf3ce44SJohn Forte 	/* We don't send any other task mgr types */
1166fcf3ce44SJohn Forte 	default:
1167fcf3ce44SJohn Forte 		ASSERT(B_FALSE);
1168fcf3ce44SJohn Forte 		break;
1169fcf3ce44SJohn Forte 	}
1170fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_queue_active.mutex);
1171fcf3ce44SJohn Forte 
1172fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
1173fcf3ce44SJohn Forte }
1174fcf3ce44SJohn Forte 
1175fcf3ce44SJohn Forte 
1176fcf3ce44SJohn Forte /*
1177fcf3ce44SJohn Forte  * iscsi_rx_process_task_mgt_rsp -
1178fcf3ce44SJohn Forte  */
1179fcf3ce44SJohn Forte /* ARGSUSED */
1180fcf3ce44SJohn Forte static iscsi_status_t
1181fcf3ce44SJohn Forte iscsi_rx_process_task_mgt_rsp(iscsi_conn_t *icp,
1182fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, void *data)
1183fcf3ce44SJohn Forte {
1184fcf3ce44SJohn Forte 	iscsi_sess_t			*isp		= NULL;
1185fcf3ce44SJohn Forte 	iscsi_scsi_task_mgt_rsp_hdr_t	*istmrhp	= NULL;
1186fcf3ce44SJohn Forte 	iscsi_cmd_t			*icmdp		= NULL;
1187fcf3ce44SJohn Forte 
1188fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
1189fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1190fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1191fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1192fcf3ce44SJohn Forte 	istmrhp = (iscsi_scsi_task_mgt_rsp_hdr_t *)ihp;
1193fcf3ce44SJohn Forte 
1194fcf3ce44SJohn Forte 	if (icp->conn_expstatsn == ntohl(istmrhp->statsn)) {
1195fcf3ce44SJohn Forte 		icp->conn_expstatsn++;
1196fcf3ce44SJohn Forte 	} else {
1197fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
1198fcf3ce44SJohn Forte 		    "received status out of order itt:0x%x statsn:0x%x "
1199fcf3ce44SJohn Forte 		    "expstatsn:0x%x", icp->conn_oid, istmrhp->itt,
1200fcf3ce44SJohn Forte 		    ntohl(istmrhp->statsn), icp->conn_expstatsn);
1201fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1202fcf3ce44SJohn Forte 	}
1203fcf3ce44SJohn Forte 
1204fcf3ce44SJohn Forte 	/* make sure we only Ack Status numbers that we've actually received. */
1205fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
1206fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
1207fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(isp, ihp, &icmdp))) {
1208fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_cmdsn_mutex);
1209fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
1210fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1211fcf3ce44SJohn Forte 	}
1212fcf3ce44SJohn Forte 
1213fcf3ce44SJohn Forte 	/* update expcmdsn and maxcmdn */
1214fcf3ce44SJohn Forte 	iscsi_update_flow_control(isp, ntohl(istmrhp->maxcmdsn),
1215fcf3ce44SJohn Forte 	    ntohl(istmrhp->expcmdsn));
1216fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
1217fcf3ce44SJohn Forte 
1218fcf3ce44SJohn Forte 	switch (icmdp->cmd_type) {
1219fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_ABORT:
1220fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_RESET:
1221fcf3ce44SJohn Forte 		switch (istmrhp->response) {
1222fcf3ce44SJohn Forte 		case SCSI_TCP_TM_RESP_COMPLETE:
1223fcf3ce44SJohn Forte 			/* success */
1224fcf3ce44SJohn Forte 			iscsi_cmd_state_machine(icmdp,
1225fcf3ce44SJohn Forte 			    ISCSI_CMD_EVENT_E3, isp);
1226fcf3ce44SJohn Forte 			break;
1227fcf3ce44SJohn Forte 		case SCSI_TCP_TM_RESP_NO_TASK:
1228fcf3ce44SJohn Forte 			/*
1229fcf3ce44SJohn Forte 			 * If the array no longer knows about
1230fcf3ce44SJohn Forte 			 * an ABORT RTT and we no longer have
1231fcf3ce44SJohn Forte 			 * a parent SCSI command it was just
1232fcf3ce44SJohn Forte 			 * completed, free this ABORT resource.
1233fcf3ce44SJohn Forte 			 * Otherwise FALLTHRU this will flag a
1234fcf3ce44SJohn Forte 			 * protocol problem.
1235fcf3ce44SJohn Forte 			 */
1236fcf3ce44SJohn Forte 			if ((icmdp->cmd_type == ISCSI_CMD_TYPE_ABORT) &&
1237fcf3ce44SJohn Forte 			    (icmdp->cmd_un.abort.icmdp == NULL)) {
1238fcf3ce44SJohn Forte 				iscsi_cmd_state_machine(icmdp,
1239fcf3ce44SJohn Forte 				    ISCSI_CMD_EVENT_E4, isp);
1240fcf3ce44SJohn Forte 				break;
1241fcf3ce44SJohn Forte 			}
1242fcf3ce44SJohn Forte 			/* FALLTHRU */
1243fcf3ce44SJohn Forte 		case SCSI_TCP_TM_RESP_NO_LUN:
1244fcf3ce44SJohn Forte 		case SCSI_TCP_TM_RESP_TASK_ALLEGIANT:
1245fcf3ce44SJohn Forte 		case SCSI_TCP_TM_RESP_NO_FAILOVER:
1246fcf3ce44SJohn Forte 		case SCSI_TCP_TM_RESP_IN_PRGRESS:
1247fcf3ce44SJohn Forte 		case SCSI_TCP_TM_RESP_REJECTED:
1248fcf3ce44SJohn Forte 		default:
1249fcf3ce44SJohn Forte 			/*
1250fcf3ce44SJohn Forte 			 * Something is out of sync.  Flush
1251fcf3ce44SJohn Forte 			 * active queues and resync the
1252fcf3ce44SJohn Forte 			 * the connection to try and recover
1253fcf3ce44SJohn Forte 			 * to a known state.
1254fcf3ce44SJohn Forte 			 */
1255fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_queue_active.mutex);
1256fcf3ce44SJohn Forte 			return (ISCSI_STATUS_PROTOCOL_ERROR);
1257fcf3ce44SJohn Forte 		}
1258fcf3ce44SJohn Forte 		break;
1259fcf3ce44SJohn Forte 
1260fcf3ce44SJohn Forte 	default:
1261fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
1262fcf3ce44SJohn Forte 		    "received a task mgt response for a non-task mgt "
1263fcf3ce44SJohn Forte 		    "cmd itt:0x%x type:%d", icp->conn_oid, istmrhp->itt,
1264fcf3ce44SJohn Forte 		    icmdp->cmd_type);
1265fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
1266fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1267fcf3ce44SJohn Forte 	}
1268fcf3ce44SJohn Forte 
1269fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_queue_active.mutex);
1270fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
1271fcf3ce44SJohn Forte }
1272fcf3ce44SJohn Forte 
1273fcf3ce44SJohn Forte 
1274fcf3ce44SJohn Forte /*
1275fcf3ce44SJohn Forte  * iscsi_rx_process_logout -
1276fcf3ce44SJohn Forte  *
1277fcf3ce44SJohn Forte  */
1278fcf3ce44SJohn Forte /* ARGSUSED */
1279fcf3ce44SJohn Forte static iscsi_status_t
1280fcf3ce44SJohn Forte iscsi_rx_process_logout_rsp(iscsi_conn_t *icp, iscsi_hdr_t *ihp, char *data)
1281fcf3ce44SJohn Forte {
1282fcf3ce44SJohn Forte 	iscsi_status_t		rval	= ISCSI_STATUS_SUCCESS;
1283fcf3ce44SJohn Forte 	iscsi_sess_t		*isp	= icp->conn_sess;
1284fcf3ce44SJohn Forte 	iscsi_logout_rsp_hdr_t	*ilrhp	= (iscsi_logout_rsp_hdr_t *)ihp;
1285fcf3ce44SJohn Forte 	iscsi_cmd_t		*icmdp	= NULL;
1286fcf3ce44SJohn Forte 
1287fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1288fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
1289fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1290fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1291fcf3ce44SJohn Forte 
1292fcf3ce44SJohn Forte 	if (icp->conn_expstatsn != ntohl(ilrhp->statsn)) {
1293fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
1294fcf3ce44SJohn Forte 		    "received status out of order itt:0x%x statsn:0x%x "
1295fcf3ce44SJohn Forte 		    "expstatsn:0x%x", icp->conn_oid, ilrhp->itt,
1296fcf3ce44SJohn Forte 		    ntohl(ilrhp->statsn), icp->conn_expstatsn);
1297fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1298fcf3ce44SJohn Forte 	}
1299fcf3ce44SJohn Forte 
1300fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
1301fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
1302fcf3ce44SJohn Forte 	if (ilrhp->itt != ISCSI_RSVD_TASK_TAG) {
1303fcf3ce44SJohn Forte 		if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(
1304fcf3ce44SJohn Forte 		    isp, ihp, &icmdp))) {
1305fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1306fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_queue_active.mutex);
1307fcf3ce44SJohn Forte 			return (ISCSI_STATUS_PROTOCOL_ERROR);
1308fcf3ce44SJohn Forte 		}
1309fcf3ce44SJohn Forte 	}
1310fcf3ce44SJohn Forte 
1311fcf3ce44SJohn Forte 	/* update expcmdsn and maxcmdsn */
1312fcf3ce44SJohn Forte 	iscsi_update_flow_control(isp, ntohl(ilrhp->maxcmdsn),
1313fcf3ce44SJohn Forte 	    ntohl(ilrhp->expcmdsn));
1314fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
1315fcf3ce44SJohn Forte 
1316fcf3ce44SJohn Forte 	switch (ilrhp->response) {
1317fcf3ce44SJohn Forte 	case ISCSI_LOGOUT_CID_NOT_FOUND:
1318fcf3ce44SJohn Forte 		/*
1319fcf3ce44SJohn Forte 		 * If the target doesn't know about our connection
1320fcf3ce44SJohn Forte 		 * then we can consider our self disconnected.
1321fcf3ce44SJohn Forte 		 */
1322fcf3ce44SJohn Forte 		/* FALLTHRU */
1323fcf3ce44SJohn Forte 	case ISCSI_LOGOUT_RECOVERY_UNSUPPORTED:
1324fcf3ce44SJohn Forte 		/*
1325fcf3ce44SJohn Forte 		 * We don't support ErrorRecovery levels above 0
1326fcf3ce44SJohn Forte 		 * currently so consider this success.
1327fcf3ce44SJohn Forte 		 */
1328fcf3ce44SJohn Forte 		/* FALLTHRU */
1329fcf3ce44SJohn Forte 	case ISCSI_LOGOUT_CLEANUP_FAILED:
1330fcf3ce44SJohn Forte 		/*
1331fcf3ce44SJohn Forte 		 * per spec. "cleanup failed for various reasons."
1332fcf3ce44SJohn Forte 		 * Although those various reasons are undefined.
1333fcf3ce44SJohn Forte 		 * Not sure what to do here.  So fake success,
1334fcf3ce44SJohn Forte 		 * which will disconnect the connection.
1335fcf3ce44SJohn Forte 		 */
1336fcf3ce44SJohn Forte 		/* FALLTHRU */
1337fcf3ce44SJohn Forte 	case ISCSI_LOGOUT_SUCCESS:
1338fcf3ce44SJohn Forte 		iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
1339fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
1340fcf3ce44SJohn Forte 		/* logout completed successfully notify the conn */
1341fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
1342fcf3ce44SJohn Forte 		(void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T17);
1343fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
1344fcf3ce44SJohn Forte 		break;
1345fcf3ce44SJohn Forte 	default:
1346fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
1347fcf3ce44SJohn Forte 		rval = ISCSI_STATUS_PROTOCOL_ERROR;
1348fcf3ce44SJohn Forte 	}
1349fcf3ce44SJohn Forte 
1350fcf3ce44SJohn Forte 	return (rval);
1351fcf3ce44SJohn Forte }
1352fcf3ce44SJohn Forte 
1353fcf3ce44SJohn Forte 
1354fcf3ce44SJohn Forte /*
1355fcf3ce44SJohn Forte  * iscsi_rx_process_logout -
1356fcf3ce44SJohn Forte  *
1357fcf3ce44SJohn Forte  */
1358fcf3ce44SJohn Forte /* ARGSUSED */
1359fcf3ce44SJohn Forte static iscsi_status_t
1360fcf3ce44SJohn Forte iscsi_rx_process_async_rsp(iscsi_conn_t *icp, iscsi_hdr_t *ihp, char *data)
1361fcf3ce44SJohn Forte {
1362fcf3ce44SJohn Forte 	iscsi_status_t		rval	= ISCSI_STATUS_SUCCESS;
1363fcf3ce44SJohn Forte 	iscsi_async_evt_hdr_t	*iaehp	= (iscsi_async_evt_hdr_t *)ihp;
1364fcf3ce44SJohn Forte 
1365fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1366fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
1367fcf3ce44SJohn Forte 	ASSERT(icp->conn_sess != NULL);
1368fcf3ce44SJohn Forte 
1369fcf3ce44SJohn Forte 	if (icp->conn_expstatsn != ntohl(iaehp->statsn)) {
1370fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
1371fcf3ce44SJohn Forte 		    "received status out of order itt:0x%x statsn:0x%x "
1372fcf3ce44SJohn Forte 		    "expstatsn:0x%x", icp->conn_oid, ihp->itt,
1373fcf3ce44SJohn Forte 		    ntohl(iaehp->statsn), icp->conn_expstatsn);
1374fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1375fcf3ce44SJohn Forte 	}
1376fcf3ce44SJohn Forte 
1377fcf3ce44SJohn Forte 	switch (iaehp->async_event) {
1378fcf3ce44SJohn Forte 	case ISCSI_ASYNC_EVENT_SCSI_EVENT:
1379fcf3ce44SJohn Forte 		/*
1380fcf3ce44SJohn Forte 		 * SCSI asynchronous event is reported in
1381fcf3ce44SJohn Forte 		 * the sense data.  Sense data that accompanies
1382fcf3ce44SJohn Forte 		 * the report in the data segment identifies the
1383fcf3ce44SJohn Forte 		 * condition.  If the target supports SCSI
1384fcf3ce44SJohn Forte 		 * asynchronous events reporting (see [SAM2])
1385fcf3ce44SJohn Forte 		 * as indicated in the stardard INQUIRY data
1386fcf3ce44SJohn Forte 		 * (see [SPC3]), its use may be enabled by
1387fcf3ce44SJohn Forte 		 * parameters in the SCSI control mode page
1388fcf3ce44SJohn Forte 		 * (see [SPC3]).
1389fcf3ce44SJohn Forte 		 *
1390fcf3ce44SJohn Forte 		 * T-10 has removed SCSI asunchronous events
1391fcf3ce44SJohn Forte 		 * from the standard.  Although we have seen
1392fcf3ce44SJohn Forte 		 * a couple targets still spending these requests.
1393fcf3ce44SJohn Forte 		 * Those targets were specifically sending them
1394fcf3ce44SJohn Forte 		 * for notification of a LUN/Volume change
1395fcf3ce44SJohn Forte 		 * (ex. LUN addition/removal).  Take a general
1396fcf3ce44SJohn Forte 		 * action to these events of dis/reconnecting.
1397fcf3ce44SJohn Forte 		 * Once reconnected we perform a reenumeration.
1398fcf3ce44SJohn Forte 		 */
1399fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
1400fcf3ce44SJohn Forte 		(void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T14);
1401fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
1402fcf3ce44SJohn Forte 		break;
1403fcf3ce44SJohn Forte 
1404fcf3ce44SJohn Forte 	case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT:
1405fcf3ce44SJohn Forte 		/* Target has requested this connection to logout. */
1406fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
1407fcf3ce44SJohn Forte 		(void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T14);
1408fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
1409fcf3ce44SJohn Forte 		break;
1410fcf3ce44SJohn Forte 
1411fcf3ce44SJohn Forte 	case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION:
1412fcf3ce44SJohn Forte 		/*
1413fcf3ce44SJohn Forte 		 * Target is going to drop our connection.
1414fcf3ce44SJohn Forte 		 *	param1 - CID which will be dropped.
1415fcf3ce44SJohn Forte 		 *	param2 - Min time to reconnect.
1416fcf3ce44SJohn Forte 		 *	param3 - Max time to reconnect.
1417fcf3ce44SJohn Forte 		 *
1418fcf3ce44SJohn Forte 		 * For now just let fail as another disconnect.
1419fcf3ce44SJohn Forte 		 *
1420fcf3ce44SJohn Forte 		 * MC/S Once we support > 1 connections then
1421fcf3ce44SJohn Forte 		 * we need to check the CID and drop that
1422fcf3ce44SJohn Forte 		 * specific connection.
1423fcf3ce44SJohn Forte 		 */
1424fcf3ce44SJohn Forte 		iscsi_conn_set_login_min_max(icp, iaehp->param2, iaehp->param3);
1425fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
1426fcf3ce44SJohn Forte 		(void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T14);
1427fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
1428fcf3ce44SJohn Forte 		break;
1429fcf3ce44SJohn Forte 
1430fcf3ce44SJohn Forte 	case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS:
1431fcf3ce44SJohn Forte 		/*
1432fcf3ce44SJohn Forte 		 * Target is going to drop ALL connections.
1433fcf3ce44SJohn Forte 		 *	param2 - Min time to reconnect.
1434fcf3ce44SJohn Forte 		 *	param3 - Max time to reconnect.
1435fcf3ce44SJohn Forte 		 *
1436fcf3ce44SJohn Forte 		 * For now just let fail as anyother disconnect.
1437fcf3ce44SJohn Forte 		 *
1438fcf3ce44SJohn Forte 		 * MC/S Once we support more than > 1 connections
1439fcf3ce44SJohn Forte 		 * then we need to drop all connections on the
1440fcf3ce44SJohn Forte 		 * session.
1441fcf3ce44SJohn Forte 		 */
1442fcf3ce44SJohn Forte 		iscsi_conn_set_login_min_max(icp, iaehp->param2, iaehp->param3);
1443fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
1444fcf3ce44SJohn Forte 		(void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T14);
1445fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
1446fcf3ce44SJohn Forte 		break;
1447fcf3ce44SJohn Forte 
1448fcf3ce44SJohn Forte 	case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION:
1449fcf3ce44SJohn Forte 		/*
1450fcf3ce44SJohn Forte 		 * Target requests parameter negotiation
1451fcf3ce44SJohn Forte 		 * on this connection.
1452fcf3ce44SJohn Forte 		 *
1453fcf3ce44SJohn Forte 		 * The initiator must honor this request.  For
1454fcf3ce44SJohn Forte 		 * now we will request a logout.  We can't
1455fcf3ce44SJohn Forte 		 * just ignore this or it might force corruption?
1456fcf3ce44SJohn Forte 		 */
1457fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
1458fcf3ce44SJohn Forte 		(void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T14);
1459fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
1460fcf3ce44SJohn Forte 		break;
1461fcf3ce44SJohn Forte 
1462fcf3ce44SJohn Forte 	case ISCSI_ASYNC_EVENT_VENDOR_SPECIFIC:
1463fcf3ce44SJohn Forte 		/*
1464fcf3ce44SJohn Forte 		 * We currently don't handle any vendor
1465fcf3ce44SJohn Forte 		 * specific async events.  So just ignore
1466fcf3ce44SJohn Forte 		 * the request.
1467fcf3ce44SJohn Forte 		 */
1468fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
1469fcf3ce44SJohn Forte 		(void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T14);
1470fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
1471fcf3ce44SJohn Forte 		break;
1472fcf3ce44SJohn Forte 	default:
1473fcf3ce44SJohn Forte 		rval = ISCSI_STATUS_PROTOCOL_ERROR;
1474fcf3ce44SJohn Forte 	}
1475fcf3ce44SJohn Forte 
1476fcf3ce44SJohn Forte 	return (rval);
1477fcf3ce44SJohn Forte }
1478fcf3ce44SJohn Forte 
1479fcf3ce44SJohn Forte /*
1480fcf3ce44SJohn Forte  * iscsi_rx_process_text_rsp - processes iSCSI text response.  It sets
1481fcf3ce44SJohn Forte  * the cmd_result field of the command data structure with the actual
1482fcf3ce44SJohn Forte  * status value instead of returning the status value.  The return value
1483fcf3ce44SJohn Forte  * is SUCCESS in order to let iscsi_handle_text control the operation of
1484fcf3ce44SJohn Forte  * a text request.
1485fcf3ce44SJohn Forte  * Test requests are a handled a little different than other types of
1486fcf3ce44SJohn Forte  * iSCSI commands because the initiator sends additional empty text requests
1487fcf3ce44SJohn Forte  * in order to obtain the remaining responses required to complete the
1488fcf3ce44SJohn Forte  * request.  iscsi_handle_text controls the operation of text request, while
1489fcf3ce44SJohn Forte  * iscsi_rx_process_text_rsp just process the current response.
1490fcf3ce44SJohn Forte  */
1491fcf3ce44SJohn Forte static iscsi_status_t
1492fcf3ce44SJohn Forte iscsi_rx_process_text_rsp(iscsi_conn_t *icp, iscsi_hdr_t *ihp, char *data)
1493fcf3ce44SJohn Forte {
1494fcf3ce44SJohn Forte 	iscsi_sess_t		*isp	= NULL;
1495fcf3ce44SJohn Forte 	iscsi_text_rsp_hdr_t	*ithp	= (iscsi_text_rsp_hdr_t *)ihp;
1496fcf3ce44SJohn Forte 	iscsi_cmd_t		*icmdp	= NULL;
1497fcf3ce44SJohn Forte 	boolean_t		final	= B_FALSE;
1498fcf3ce44SJohn Forte 	uint32_t		data_len;
1499fcf3ce44SJohn Forte 
1500fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1501fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
1502fcf3ce44SJohn Forte 	ASSERT(data != NULL);
1503fcf3ce44SJohn Forte 
1504fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1505fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1506fcf3ce44SJohn Forte 
1507fcf3ce44SJohn Forte 	if (icp->conn_expstatsn == ntohl(ithp->statsn)) {
1508fcf3ce44SJohn Forte 		icp->conn_expstatsn++;
1509fcf3ce44SJohn Forte 	} else {
1510fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
1511fcf3ce44SJohn Forte 		    "received status out of order itt:0x%x statsn:0x%x "
1512fcf3ce44SJohn Forte 		    "expstatsn:0x%x", icp->conn_oid, ithp->itt,
1513fcf3ce44SJohn Forte 		    ntohl(ithp->statsn), icp->conn_expstatsn);
1514fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1515fcf3ce44SJohn Forte 	}
1516fcf3ce44SJohn Forte 
1517fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
1518fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
1519fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(isp, ihp, &icmdp))) {
1520fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_cmdsn_mutex);
1521fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
1522fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1523fcf3ce44SJohn Forte 	}
1524fcf3ce44SJohn Forte 
1525fcf3ce44SJohn Forte 	/* update expcmdsn and maxcmdsn */
1526fcf3ce44SJohn Forte 	iscsi_update_flow_control(isp, ntohl(ithp->maxcmdsn),
1527fcf3ce44SJohn Forte 	    ntohl(ithp->expcmdsn));
1528fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
1529fcf3ce44SJohn Forte 
1530fcf3ce44SJohn Forte 	/* update local final response flag */
1531fcf3ce44SJohn Forte 	if (ithp->flags & ISCSI_FLAG_FINAL) {
1532fcf3ce44SJohn Forte 		final = B_TRUE;
1533fcf3ce44SJohn Forte 	}
1534fcf3ce44SJohn Forte 
1535fcf3ce44SJohn Forte 	/*
1536fcf3ce44SJohn Forte 	 * validate received TTT value.  RFC3720 specifies the following:
1537fcf3ce44SJohn Forte 	 * - F bit set to 1 MUST have a reserved TTT value 0xffffffff
1538fcf3ce44SJohn Forte 	 * - F bit set to 0 MUST have a non-reserved TTT value !0xffffffff
1539fcf3ce44SJohn Forte 	 * In addition, the received TTT value must not change between
1540fcf3ce44SJohn Forte 	 * responses of a long text response
1541fcf3ce44SJohn Forte 	 */
1542fcf3ce44SJohn Forte 	if (((final == B_TRUE) && (ithp->ttt != ISCSI_RSVD_TASK_TAG)) ||
1543fcf3ce44SJohn Forte 	    ((final == B_FALSE) && (ithp->ttt == ISCSI_RSVD_TASK_TAG))) {
1544fcf3ce44SJohn Forte 		icmdp->cmd_result = ISCSI_STATUS_PROTOCOL_ERROR;
1545fcf3ce44SJohn Forte 		icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
1546fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
1547fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
1548fcf3ce44SJohn Forte 		    "received text response with invalid flags:0x%x or "
1549fcf3ce44SJohn Forte 		    "ttt:0x%x", icp->conn_oid, ithp->flags, ithp->itt);
1550fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1551fcf3ce44SJohn Forte 	}
1552fcf3ce44SJohn Forte 
1553fcf3ce44SJohn Forte 	if ((icmdp->cmd_un.text.stage == ISCSI_CMD_TEXT_INITIAL_REQ) &&
1554fcf3ce44SJohn Forte 	    (ithp->ttt == ISCSI_RSVD_TASK_TAG) &&
1555fcf3ce44SJohn Forte 	    (final == B_FALSE)) {
1556fcf3ce44SJohn Forte 		/* TTT should have matched reserved value */
1557fcf3ce44SJohn Forte 		icmdp->cmd_result = ISCSI_STATUS_PROTOCOL_ERROR;
1558fcf3ce44SJohn Forte 		icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
1559fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
1560fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol "
1561fcf3ce44SJohn Forte 		    "error - received text response with invalid "
1562fcf3ce44SJohn Forte 		    "ttt:0x%x", icp->conn_oid, ithp->ttt);
1563fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1564fcf3ce44SJohn Forte 	}
1565fcf3ce44SJohn Forte 
1566fcf3ce44SJohn Forte 	/*
1567fcf3ce44SJohn Forte 	 * If this is first response, save away TTT value for later use
1568fcf3ce44SJohn Forte 	 * in a long text request/response sequence
1569fcf3ce44SJohn Forte 	 */
1570fcf3ce44SJohn Forte 	if (icmdp->cmd_un.text.stage == ISCSI_CMD_TEXT_INITIAL_REQ) {
1571fcf3ce44SJohn Forte 		icmdp->cmd_un.text.ttt = ithp->ttt;
1572fcf3ce44SJohn Forte 	}
1573fcf3ce44SJohn Forte 
1574fcf3ce44SJohn Forte 	data_len = ntoh24(ithp->dlength);
1575fcf3ce44SJohn Forte 
1576fcf3ce44SJohn Forte 	/* check whether enough buffer available to copy data */
1577fcf3ce44SJohn Forte 	if ((icmdp->cmd_un.text.total_rx_len + data_len) >
1578fcf3ce44SJohn Forte 	    icmdp->cmd_un.text.buf_len) {
1579fcf3ce44SJohn Forte 		icmdp->cmd_un.text.total_rx_len += data_len;
1580fcf3ce44SJohn Forte 		icmdp->cmd_result = ISCSI_STATUS_DATA_OVERFLOW;
1581fcf3ce44SJohn Forte 		/*
1582fcf3ce44SJohn Forte 		 * DATA_OVERFLOW will result in a SUCCESS return so that
1583fcf3ce44SJohn Forte 		 * iscsi_handle_text can continue to obtain the remaining
1584fcf3ce44SJohn Forte 		 * text response if needed.
1585fcf3ce44SJohn Forte 		 */
1586fcf3ce44SJohn Forte 	} else {
1587fcf3ce44SJohn Forte 		char *buf_data = (icmdp->cmd_un.text.buf +
1588fcf3ce44SJohn Forte 		    icmdp->cmd_un.text.offset);
1589fcf3ce44SJohn Forte 
1590fcf3ce44SJohn Forte 		bcopy(data, buf_data, data_len);
1591fcf3ce44SJohn Forte 		icmdp->cmd_un.text.offset += data_len;
1592fcf3ce44SJohn Forte 		icmdp->cmd_un.text.total_rx_len += data_len;
1593fcf3ce44SJohn Forte 		icmdp->cmd_result = ISCSI_STATUS_SUCCESS;
1594fcf3ce44SJohn Forte 		bcopy(ithp->rsvd4, icmdp->cmd_un.text.lun,
1595fcf3ce44SJohn Forte 		    sizeof (icmdp->cmd_un.text.lun));
1596fcf3ce44SJohn Forte 	}
1597fcf3ce44SJohn Forte 
1598fcf3ce44SJohn Forte 	/* update stage  */
1599fcf3ce44SJohn Forte 	if (final == B_TRUE) {
1600fcf3ce44SJohn Forte 		icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
1601fcf3ce44SJohn Forte 	} else {
1602fcf3ce44SJohn Forte 		icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_CONTINUATION;
1603fcf3ce44SJohn Forte 	}
1604fcf3ce44SJohn Forte 
1605fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
1606fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_queue_active.mutex);
1607fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
1608fcf3ce44SJohn Forte }
1609fcf3ce44SJohn Forte 
1610fcf3ce44SJohn Forte /*
1611fcf3ce44SJohn Forte  * iscsi_rx_process_itt_to_icmdp - Lookup itt in the session's
1612fcf3ce44SJohn Forte  * cmd table to find matching icmdp.  Verify itt in hdr and
1613fcf3ce44SJohn Forte  * icmdp are the same.
1614fcf3ce44SJohn Forte  */
1615fcf3ce44SJohn Forte static iscsi_status_t
1616fcf3ce44SJohn Forte iscsi_rx_process_itt_to_icmdp(iscsi_sess_t *isp, iscsi_hdr_t *ihp,
1617fcf3ce44SJohn Forte     iscsi_cmd_t **icmdp)
1618fcf3ce44SJohn Forte {
1619fcf3ce44SJohn Forte 	int cmd_table_idx = 0;
1620fcf3ce44SJohn Forte 
1621fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1622fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
1623fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
1624fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&isp->sess_cmdsn_mutex));
1625fcf3ce44SJohn Forte 
1626fcf3ce44SJohn Forte 	/* try to find an associated iscsi_pkt */
1627fcf3ce44SJohn Forte 	cmd_table_idx = ihp->itt % ISCSI_CMD_TABLE_SIZE;
1628fcf3ce44SJohn Forte 	if (isp->sess_cmd_table[cmd_table_idx] == NULL) {
1629fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi session(%u) protocol error - "
1630fcf3ce44SJohn Forte 		    "received unknown itt:0x%x - protocol error",
1631fcf3ce44SJohn Forte 		    isp->sess_oid, ihp->itt);
1632fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
1633fcf3ce44SJohn Forte 	}
1634fcf3ce44SJohn Forte 
1635fcf3ce44SJohn Forte 	/* verify itt */
1636fcf3ce44SJohn Forte 	if (isp->sess_cmd_table[cmd_table_idx]->cmd_itt != ihp->itt) {
1637fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi session(%u) received itt:0x%x "
1638fcf3ce44SJohn Forte 		    " which is out of sync with itt:0x%x", isp->sess_oid,
1639fcf3ce44SJohn Forte 		    ihp->itt, isp->sess_cmd_table[cmd_table_idx]->cmd_itt);
1640fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
1641fcf3ce44SJohn Forte 	}
1642fcf3ce44SJohn Forte 
164329e23f3fSandrew.rutz@sun.com 	/* ensure that icmdp is still in Active state */
164429e23f3fSandrew.rutz@sun.com 	if (isp->sess_cmd_table[cmd_table_idx]->cmd_state !=
164529e23f3fSandrew.rutz@sun.com 	    ISCSI_CMD_STATE_ACTIVE) {
164629e23f3fSandrew.rutz@sun.com 		cmn_err(CE_WARN, "iscsi session(%u) received itt:0x%x "
164729e23f3fSandrew.rutz@sun.com 		    "but icmdp (%p) is not in active state",
164829e23f3fSandrew.rutz@sun.com 		    isp->sess_oid, ihp->itt,
164929e23f3fSandrew.rutz@sun.com 		    (void *)isp->sess_cmd_table[cmd_table_idx]);
165029e23f3fSandrew.rutz@sun.com 		return (ISCSI_STATUS_INTERNAL_ERROR);
165129e23f3fSandrew.rutz@sun.com 	}
165229e23f3fSandrew.rutz@sun.com 
1653fcf3ce44SJohn Forte 	/* make sure this is a SCSI cmd */
1654fcf3ce44SJohn Forte 	*icmdp = isp->sess_cmd_table[cmd_table_idx];
1655fcf3ce44SJohn Forte 
1656fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
1657fcf3ce44SJohn Forte }
1658fcf3ce44SJohn Forte 
1659fcf3ce44SJohn Forte 
1660fcf3ce44SJohn Forte /*
1661fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
1662fcf3ce44SJohn Forte  * | End of protocol receive routines					|
1663fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
1664fcf3ce44SJohn Forte  */
1665fcf3ce44SJohn Forte 
1666fcf3ce44SJohn Forte /*
1667fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
1668fcf3ce44SJohn Forte  * | Beginning of protocol send routines				|
1669fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
1670fcf3ce44SJohn Forte  */
1671fcf3ce44SJohn Forte 
1672fcf3ce44SJohn Forte 
1673fcf3ce44SJohn Forte /*
1674fcf3ce44SJohn Forte  * iscsi_tx_thread - This thread is the driving point for all
1675fcf3ce44SJohn Forte  * iSCSI PDUs after login.  No PDUs should call sendpdu()
1676fcf3ce44SJohn Forte  * directly they should be funneled through iscsi_tx_thread.
1677fcf3ce44SJohn Forte  */
1678fcf3ce44SJohn Forte void
1679fcf3ce44SJohn Forte iscsi_tx_thread(iscsi_thread_t *thread, void *arg)
1680fcf3ce44SJohn Forte {
1681fcf3ce44SJohn Forte 	iscsi_conn_t	*icp	= (iscsi_conn_t *)arg;
1682fcf3ce44SJohn Forte 	iscsi_sess_t	*isp	= NULL;
1683fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp	= NULL;
1684fcf3ce44SJohn Forte 	clock_t		tout;
1685fcf3ce44SJohn Forte 	int		ret	= 1;
1686fcf3ce44SJohn Forte 
1687fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1688fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1689fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1690fcf3ce44SJohn Forte 	ASSERT(thread != NULL);
1691fcf3ce44SJohn Forte 	ASSERT(thread->signature == SIG_ISCSI_THREAD);
1692fcf3ce44SJohn Forte 
1693fcf3ce44SJohn Forte 	tout = SEC_TO_TICK(1);
1694fcf3ce44SJohn Forte 	/*
1695fcf3ce44SJohn Forte 	 * Transfer icmdps until shutdown by owning session.
1696fcf3ce44SJohn Forte 	 */
1697fcf3ce44SJohn Forte 	while (ret != 0) {
1698fcf3ce44SJohn Forte 
1699fcf3ce44SJohn Forte 		isp->sess_window_open = B_TRUE;
1700fcf3ce44SJohn Forte 
1701fcf3ce44SJohn Forte 		/*
1702fcf3ce44SJohn Forte 		 * While the window is open, there are commands available
1703fcf3ce44SJohn Forte 		 * to send and the session state allows those commands to
1704fcf3ce44SJohn Forte 		 * be sent try to transfer them.
1705fcf3ce44SJohn Forte 		 */
1706fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_queue_pending.mutex);
1707fcf3ce44SJohn Forte 		while ((isp->sess_window_open == B_TRUE) &&
1708fcf3ce44SJohn Forte 		    ((icmdp = isp->sess_queue_pending.head) != NULL) &&
1709fcf3ce44SJohn Forte 		    (((icmdp->cmd_type != ISCSI_CMD_TYPE_SCSI) &&
1710fcf3ce44SJohn Forte 		    (ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state))) ||
1711fcf3ce44SJohn Forte 		    (icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN))) {
1712fcf3ce44SJohn Forte 
1713fcf3ce44SJohn Forte 			/* update command with this connection info */
1714fcf3ce44SJohn Forte 			icmdp->cmd_conn = icp;
1715fcf3ce44SJohn Forte 			/* attempt to send this command */
1716fcf3ce44SJohn Forte 			iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E2, isp);
1717fcf3ce44SJohn Forte 
1718fcf3ce44SJohn Forte 			ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex));
1719fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_queue_pending.mutex);
1720fcf3ce44SJohn Forte 		}
1721fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_queue_pending.mutex);
1722fcf3ce44SJohn Forte 
1723fcf3ce44SJohn Forte 		/*
1724fcf3ce44SJohn Forte 		 * Go to sleep until there is something new
1725fcf3ce44SJohn Forte 		 * to process (awoken via cv_boardcast).
1726fcf3ce44SJohn Forte 		 * Or the timer goes off.
1727fcf3ce44SJohn Forte 		 */
1728fcf3ce44SJohn Forte 		ret = iscsi_thread_wait(thread, tout);
1729fcf3ce44SJohn Forte 	}
1730fcf3ce44SJohn Forte 
1731fcf3ce44SJohn Forte }
1732fcf3ce44SJohn Forte 
1733fcf3ce44SJohn Forte 
1734fcf3ce44SJohn Forte /*
1735fcf3ce44SJohn Forte  * iscsi_tx_cmd - transfers icmdp across wire as iscsi pdu
1736fcf3ce44SJohn Forte  *
1737fcf3ce44SJohn Forte  * Just prior to sending the command to the networking layer the
1738fcf3ce44SJohn Forte  * pending queue lock will be dropped.  At this point only local
1739fcf3ce44SJohn Forte  * resources will be used, not the icmdp.  Holding the queue lock
1740fcf3ce44SJohn Forte  * across the networking call can lead to a hang.  (This is due
1741fcf3ce44SJohn Forte  * to the the target driver and networking layers competing use
1742fcf3ce44SJohn Forte  * of the timeout() resources and the queue lock being held for
1743fcf3ce44SJohn Forte  * both sides.)  Upon the completion of this command the lock
1744fcf3ce44SJohn Forte  * will have been re-acquired.
1745fcf3ce44SJohn Forte  */
1746fcf3ce44SJohn Forte iscsi_status_t
1747fcf3ce44SJohn Forte iscsi_tx_cmd(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
1748fcf3ce44SJohn Forte {
1749fcf3ce44SJohn Forte 	iscsi_status_t	rval = ISCSI_STATUS_INTERNAL_ERROR;
1750fcf3ce44SJohn Forte 
1751fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1752fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
1753fcf3ce44SJohn Forte 
1754fcf3ce44SJohn Forte 	/* transfer specific command type */
1755fcf3ce44SJohn Forte 	switch (icmdp->cmd_type) {
1756fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_SCSI:
1757fcf3ce44SJohn Forte 		rval = iscsi_tx_scsi(isp, icmdp);
1758fcf3ce44SJohn Forte 		break;
1759fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_R2T:
1760fcf3ce44SJohn Forte 		rval = iscsi_tx_r2t(isp, icmdp);
1761fcf3ce44SJohn Forte 		break;
1762fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_NOP:
1763fcf3ce44SJohn Forte 		rval = iscsi_tx_nop(isp, icmdp);
1764fcf3ce44SJohn Forte 		break;
1765fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_ABORT:
1766fcf3ce44SJohn Forte 		rval = iscsi_tx_abort(isp, icmdp);
1767fcf3ce44SJohn Forte 		break;
1768fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_RESET:
1769fcf3ce44SJohn Forte 		rval = iscsi_tx_reset(isp, icmdp);
1770fcf3ce44SJohn Forte 		break;
1771fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_LOGOUT:
1772fcf3ce44SJohn Forte 		rval = iscsi_tx_logout(isp, icmdp);
1773fcf3ce44SJohn Forte 		break;
1774fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_TEXT:
1775fcf3ce44SJohn Forte 		rval = iscsi_tx_text(isp, icmdp);
1776fcf3ce44SJohn Forte 		break;
1777fcf3ce44SJohn Forte 	default:
1778fcf3ce44SJohn Forte 		ASSERT(FALSE);
1779fcf3ce44SJohn Forte 	}
1780fcf3ce44SJohn Forte 
1781fcf3ce44SJohn Forte 	ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex));
1782fcf3ce44SJohn Forte 	return (rval);
1783fcf3ce44SJohn Forte }
1784fcf3ce44SJohn Forte 
1785fcf3ce44SJohn Forte /*
1786fcf3ce44SJohn Forte  * a variable length cdb can be up to 16K, but we obviously don't want
1787fcf3ce44SJohn Forte  * to put that on the stack; go with 200 bytes; if we get something
1788fcf3ce44SJohn Forte  * bigger than that we will kmem_alloc a buffer
1789fcf3ce44SJohn Forte  */
1790fcf3ce44SJohn Forte #define	DEF_CDB_LEN	200
1791fcf3ce44SJohn Forte 
1792fcf3ce44SJohn Forte /*
1793fcf3ce44SJohn Forte  * given the size of the cdb, return how many bytes the header takes,
1794fcf3ce44SJohn Forte  * which is the sizeof addl_hdr_t + the CDB size, minus the 16 bytes
1795fcf3ce44SJohn Forte  * stored in the basic header, minus sizeof (ahs_extscb)
1796fcf3ce44SJohn Forte  */
1797fcf3ce44SJohn Forte #define	ADDLHDRSZ(x)		(sizeof (iscsi_addl_hdr_t) + (x) - \
1798fcf3ce44SJohn Forte 					16 - 4)
1799fcf3ce44SJohn Forte 
1800fcf3ce44SJohn Forte /*
1801fcf3ce44SJohn Forte  * iscsi_tx_scsi -
1802fcf3ce44SJohn Forte  *
1803fcf3ce44SJohn Forte  */
1804fcf3ce44SJohn Forte static iscsi_status_t
1805fcf3ce44SJohn Forte iscsi_tx_scsi(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
1806fcf3ce44SJohn Forte {
1807fcf3ce44SJohn Forte 	iscsi_status_t		rval		= ISCSI_STATUS_SUCCESS;
1808fcf3ce44SJohn Forte 	iscsi_conn_t		*icp		= NULL;
1809fcf3ce44SJohn Forte 	struct scsi_pkt		*pkt		= NULL;
1810fcf3ce44SJohn Forte 	struct buf		*bp		= NULL;
1811fcf3ce44SJohn Forte 	union {
1812fcf3ce44SJohn Forte 		iscsi_scsi_cmd_hdr_t	isch;
1813fcf3ce44SJohn Forte 		iscsi_addl_hdr_t	iah;
1814fcf3ce44SJohn Forte 		uchar_t			arr[ADDLHDRSZ(DEF_CDB_LEN)];
1815fcf3ce44SJohn Forte 	} hdr_un;
1816fcf3ce44SJohn Forte 	iscsi_scsi_cmd_hdr_t	*ihp		=
1817fcf3ce44SJohn Forte 	    (iscsi_scsi_cmd_hdr_t *)&hdr_un.isch;
1818fcf3ce44SJohn Forte 	int			cdblen		= 0;
1819fcf3ce44SJohn Forte 	size_t			buflen		= 0;
1820fcf3ce44SJohn Forte 	uint32_t		imdata		= 0;
1821fcf3ce44SJohn Forte 	uint32_t		first_burst_length = 0;
1822fcf3ce44SJohn Forte 
1823fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1824fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
1825fcf3ce44SJohn Forte 	pkt = icmdp->cmd_un.scsi.pkt;
1826fcf3ce44SJohn Forte 	ASSERT(pkt != NULL);
1827fcf3ce44SJohn Forte 	bp = icmdp->cmd_un.scsi.bp;
1828fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
1829fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1830fcf3ce44SJohn Forte 
1831fcf3ce44SJohn Forte 	/* Reset counts in case we are on a retry */
1832fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.data_transferred = 0;
1833fcf3ce44SJohn Forte 
1834fcf3ce44SJohn Forte 	if (icmdp->cmd_un.scsi.cmdlen > DEF_CDB_LEN) {
1835fcf3ce44SJohn Forte 		cdblen = icmdp->cmd_un.scsi.cmdlen;
1836fcf3ce44SJohn Forte 		ihp = kmem_zalloc(ADDLHDRSZ(cdblen), KM_SLEEP);
1837fcf3ce44SJohn Forte 	} else {
1838fcf3ce44SJohn Forte 		/*
1839fcf3ce44SJohn Forte 		 * only bzero the basic header; the additional header
1840fcf3ce44SJohn Forte 		 * will be set up correctly later, if needed
1841fcf3ce44SJohn Forte 		 */
1842fcf3ce44SJohn Forte 		bzero(ihp, sizeof (iscsi_scsi_cmd_hdr_t));
1843fcf3ce44SJohn Forte 	}
1844fcf3ce44SJohn Forte 	ihp->opcode		= ISCSI_OP_SCSI_CMD;
1845fcf3ce44SJohn Forte 	ihp->itt		= icmdp->cmd_itt;
1846fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
1847fcf3ce44SJohn Forte 	ihp->cmdsn		= htonl(isp->sess_cmdsn);
1848fcf3ce44SJohn Forte 	isp->sess_cmdsn++;
1849fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
1850fcf3ce44SJohn Forte 	ihp->expstatsn		= htonl(icp->conn_expstatsn);
1851fcf3ce44SJohn Forte 	icp->conn_laststatsn = icp->conn_expstatsn;
1852fcf3ce44SJohn Forte 
1853fcf3ce44SJohn Forte 	pkt->pkt_state = (STATE_GOT_BUS | STATE_GOT_TARGET);
1854fcf3ce44SJohn Forte 	pkt->pkt_reason = CMD_INCOMPLETE;
1855fcf3ce44SJohn Forte 
1856fcf3ce44SJohn Forte 	/*
1857fcf3ce44SJohn Forte 	 * Sestion 12.11 of the iSCSI specification has a good table
1858fcf3ce44SJohn Forte 	 * describing when uncolicited data and/or immediate data
1859fcf3ce44SJohn Forte 	 * should be sent.
1860fcf3ce44SJohn Forte 	 */
1861fcf3ce44SJohn Forte 	bp = icmdp->cmd_un.scsi.bp;
1862fcf3ce44SJohn Forte 	if ((bp != NULL) && bp->b_bcount) {
1863fcf3ce44SJohn Forte 		buflen = bp->b_bcount;
1864fcf3ce44SJohn Forte 		first_burst_length = icp->conn_params.first_burst_length;
1865fcf3ce44SJohn Forte 
1866fcf3ce44SJohn Forte 		if (bp->b_flags & B_READ) {
1867fcf3ce44SJohn Forte 			ihp->flags = ISCSI_FLAG_FINAL;
1868fcf3ce44SJohn Forte 			/*
1869fcf3ce44SJohn Forte 			 * fix problem where OS sends bp (B_READ &
1870fcf3ce44SJohn Forte 			 * b_bcount!=0) for a TUR or START_STOP.
1871fcf3ce44SJohn Forte 			 * (comment came from cisco code.)
1872fcf3ce44SJohn Forte 			 */
1873fcf3ce44SJohn Forte 			if ((pkt->pkt_cdbp[0] != SCMD_TEST_UNIT_READY) &&
1874fcf3ce44SJohn Forte 			    (pkt->pkt_cdbp[0] != SCMD_START_STOP)) {
1875fcf3ce44SJohn Forte 				ihp->flags |= ISCSI_FLAG_CMD_READ;
1876fcf3ce44SJohn Forte 				ihp->data_length = htonl(buflen);
1877fcf3ce44SJohn Forte 			}
1878fcf3ce44SJohn Forte 		} else {
1879fcf3ce44SJohn Forte 			ihp->flags = ISCSI_FLAG_CMD_WRITE;
1880fcf3ce44SJohn Forte 			/*
1881fcf3ce44SJohn Forte 			 * FinalBit on the the iSCSI PDU denotes this
1882fcf3ce44SJohn Forte 			 * is the last PDU in the sequence.
1883fcf3ce44SJohn Forte 			 *
1884fcf3ce44SJohn Forte 			 * initial_r2t = true means R2T is required
1885fcf3ce44SJohn Forte 			 * for additional PDU, so there will be no more
1886fcf3ce44SJohn Forte 			 * unsolicited PDUs following
1887fcf3ce44SJohn Forte 			 */
1888fcf3ce44SJohn Forte 			if (icp->conn_params.initial_r2t) {
1889fcf3ce44SJohn Forte 				ihp->flags |= ISCSI_FLAG_FINAL;
1890fcf3ce44SJohn Forte 			}
1891fcf3ce44SJohn Forte 
1892fcf3ce44SJohn Forte 			/* Check if we should send ImmediateData */
1893fcf3ce44SJohn Forte 			if (icp->conn_params.immediate_data) {
1894fcf3ce44SJohn Forte 				imdata = MIN(MIN(buflen,
1895fcf3ce44SJohn Forte 				    first_burst_length),
1896fcf3ce44SJohn Forte 				    icmdp->cmd_conn->conn_params.
1897fcf3ce44SJohn Forte 				    max_xmit_data_seg_len);
1898fcf3ce44SJohn Forte 
1899fcf3ce44SJohn Forte 				/*
1900fcf3ce44SJohn Forte 				 * if everything fits immediate, or
1901fcf3ce44SJohn Forte 				 * we can send all burst data immediate
1902fcf3ce44SJohn Forte 				 * (not unsol), set F
1903fcf3ce44SJohn Forte 				 */
1904fcf3ce44SJohn Forte 				if ((imdata == buflen) ||
1905fcf3ce44SJohn Forte 				    (imdata == first_burst_length)) {
1906fcf3ce44SJohn Forte 					ihp->flags |= ISCSI_FLAG_FINAL;
1907fcf3ce44SJohn Forte 				}
1908fcf3ce44SJohn Forte 
1909fcf3ce44SJohn Forte 				hton24(ihp->dlength, imdata);
1910fcf3ce44SJohn Forte 			}
1911fcf3ce44SJohn Forte 
1912fcf3ce44SJohn Forte 			/* total data transfer length */
1913fcf3ce44SJohn Forte 			ihp->data_length = htonl(buflen);
1914fcf3ce44SJohn Forte 		}
1915fcf3ce44SJohn Forte 	} else {
1916fcf3ce44SJohn Forte 		ihp->flags = ISCSI_FLAG_FINAL;
1917fcf3ce44SJohn Forte 		buflen = 0;
1918fcf3ce44SJohn Forte 	}
1919fcf3ce44SJohn Forte 
1920fcf3ce44SJohn Forte 	/* tagged queuing */
1921fcf3ce44SJohn Forte 	if (pkt->pkt_flags & FLAG_HTAG) {
1922fcf3ce44SJohn Forte 		ihp->flags |= ISCSI_ATTR_HEAD_OF_QUEUE;
1923fcf3ce44SJohn Forte 	} else if (pkt->pkt_flags & FLAG_OTAG) {
1924fcf3ce44SJohn Forte 		ihp->flags |= ISCSI_ATTR_ORDERED;
1925fcf3ce44SJohn Forte 	} else if (pkt->pkt_flags & FLAG_STAG) {
1926fcf3ce44SJohn Forte 		ihp->flags |= ISCSI_ATTR_SIMPLE;
1927fcf3ce44SJohn Forte 	} else {
1928fcf3ce44SJohn Forte 		/* ihp->flags |= ISCSI_ATTR_UNTAGGED; */
1929fcf3ce44SJohn Forte 		/* EMPTY */
1930fcf3ce44SJohn Forte 	}
1931fcf3ce44SJohn Forte 
1932fcf3ce44SJohn Forte 	/* iscsi states lun is based on spc.2 */
1933fcf3ce44SJohn Forte 	ISCSI_LUN_BYTE_COPY(ihp->lun, icmdp->cmd_un.scsi.lun);
1934fcf3ce44SJohn Forte 
1935fcf3ce44SJohn Forte 	if (icmdp->cmd_un.scsi.cmdlen <= 16) {
1936fcf3ce44SJohn Forte 		/* copy the SCSI Command Block into the PDU */
1937fcf3ce44SJohn Forte 		bcopy(pkt->pkt_cdbp, ihp->scb,
1938fcf3ce44SJohn Forte 		    icmdp->cmd_un.scsi.cmdlen);
1939fcf3ce44SJohn Forte 	} else {
1940fcf3ce44SJohn Forte 		iscsi_addl_hdr_t *iahp;
1941fcf3ce44SJohn Forte 
1942fcf3ce44SJohn Forte 		iahp = (iscsi_addl_hdr_t *)ihp;
1943fcf3ce44SJohn Forte 
1944fcf3ce44SJohn Forte 		ihp->hlength = (ADDLHDRSZ(icmdp->cmd_un.scsi.cmdlen) -
1945fcf3ce44SJohn Forte 		    sizeof (iscsi_scsi_cmd_hdr_t) + 3) / 4;
1946fcf3ce44SJohn Forte 		iahp->ahs_hlen_hi = 0;
1947fcf3ce44SJohn Forte 		iahp->ahs_hlen_lo = (icmdp->cmd_un.scsi.cmdlen - 15);
1948fcf3ce44SJohn Forte 		iahp->ahs_key = 0x01;
1949fcf3ce44SJohn Forte 		iahp->ahs_resv = 0;
1950fcf3ce44SJohn Forte 		bcopy(pkt->pkt_cdbp, ihp->scb, 16);
1951fcf3ce44SJohn Forte 		bcopy(((char *)pkt->pkt_cdbp) + 16, &iahp->ahs_extscb[0],
1952fcf3ce44SJohn Forte 		    icmdp->cmd_un.scsi.cmdlen);
1953fcf3ce44SJohn Forte 	}
1954fcf3ce44SJohn Forte 
1955fcf3ce44SJohn Forte 	/*
1956fcf3ce44SJohn Forte 	 * Update all values before transfering.
1957fcf3ce44SJohn Forte 	 * We should never touch the icmdp after
1958fcf3ce44SJohn Forte 	 * transfering if there is no more data
1959fcf3ce44SJohn Forte 	 * to send.  The only case the sendpdu()
1960fcf3ce44SJohn Forte 	 * will fail is a on a connection disconnect
1961fcf3ce44SJohn Forte 	 * in that case the command will be flushed.
1962fcf3ce44SJohn Forte 	 */
1963fcf3ce44SJohn Forte 	pkt->pkt_state |= STATE_SENT_CMD;
1964fcf3ce44SJohn Forte 
1965fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.data_transferred += imdata;
1966fcf3ce44SJohn Forte 
1967fcf3ce44SJohn Forte 	/*
1968fcf3ce44SJohn Forte 	 * Check if there is additional data to transfer beyond what
1969fcf3ce44SJohn Forte 	 * will be sent as part of the initial command.  If InitialR2T
1970fcf3ce44SJohn Forte 	 * is disabled then we should fake up a R2T so all the data,
1971fcf3ce44SJohn Forte 	 * up to first burst length, is sent in an unsolicited
1972fcf3ce44SJohn Forte 	 * fashion.  We have already sent as much immediate data
1973fcf3ce44SJohn Forte 	 * as possible.
1974fcf3ce44SJohn Forte 	 */
1975fcf3ce44SJohn Forte 	if ((buflen > 0) &&
1976fcf3ce44SJohn Forte 	    ((bp->b_flags & B_READ) == 0) &&
1977fcf3ce44SJohn Forte 	    (icp->conn_params.initial_r2t == 0) &&
1978fcf3ce44SJohn Forte 	    (MIN(first_burst_length, buflen) - imdata > 0)) {
1979fcf3ce44SJohn Forte 
1980fcf3ce44SJohn Forte 		uint32_t xfer_len = MIN(first_burst_length, buflen) - imdata;
1981fcf3ce44SJohn Forte 		/* data will be chunked at tx */
1982fcf3ce44SJohn Forte 		iscsi_handle_r2t(icp, icmdp, imdata,
1983fcf3ce44SJohn Forte 		    xfer_len, ISCSI_RSVD_TASK_TAG);
1984fcf3ce44SJohn Forte 	}
1985fcf3ce44SJohn Forte 
1986fcf3ce44SJohn Forte 	/* release pending queue mutex across the network call */
1987fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
1988fcf3ce44SJohn Forte 
1989fcf3ce44SJohn Forte 	/* Transfer Cmd PDU */
1990fcf3ce44SJohn Forte 	if (imdata) {
1991fcf3ce44SJohn Forte 		rval = iscsi_net->sendpdu(icp->conn_socket,
1992fcf3ce44SJohn Forte 		    (iscsi_hdr_t *)ihp, icmdp->cmd_un.scsi.bp->b_un.b_addr,
1993fcf3ce44SJohn Forte 		    ISCSI_CONN_TO_NET_DIGEST(icp));
1994fcf3ce44SJohn Forte 		if (ISCSI_SUCCESS(rval)) {
1995fcf3ce44SJohn Forte 			KSTAT_ADD_CONN_TX_BYTES(icp, imdata);
1996fcf3ce44SJohn Forte 		}
1997fcf3ce44SJohn Forte 	} else {
1998fcf3ce44SJohn Forte 		rval = iscsi_net->sendpdu(icp->conn_socket,
1999fcf3ce44SJohn Forte 		    (iscsi_hdr_t *)ihp, NULL,
2000fcf3ce44SJohn Forte 		    ISCSI_CONN_TO_NET_DIGEST(icp));
2001fcf3ce44SJohn Forte 	}
2002fcf3ce44SJohn Forte 	if (cdblen) {
2003fcf3ce44SJohn Forte 		kmem_free(ihp, ADDLHDRSZ(cdblen));
2004fcf3ce44SJohn Forte 	}
2005fcf3ce44SJohn Forte 
2006fcf3ce44SJohn Forte 	return (rval);
2007fcf3ce44SJohn Forte }
2008fcf3ce44SJohn Forte 
2009fcf3ce44SJohn Forte 
2010fcf3ce44SJohn Forte /*
2011fcf3ce44SJohn Forte  * iscsi_tx_r2t -
2012fcf3ce44SJohn Forte  *
2013fcf3ce44SJohn Forte  */
2014fcf3ce44SJohn Forte static iscsi_status_t
2015fcf3ce44SJohn Forte iscsi_tx_r2t(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2016fcf3ce44SJohn Forte {
2017fcf3ce44SJohn Forte 	iscsi_status_t	rval		= ISCSI_STATUS_SUCCESS;
2018fcf3ce44SJohn Forte 	iscsi_conn_t	*icp		= NULL;
2019fcf3ce44SJohn Forte 	iscsi_cmd_t	*orig_icmdp	= NULL;
2020fcf3ce44SJohn Forte 
2021fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2022fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2023fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
2024fcf3ce44SJohn Forte 	ASSERT(icp);
2025fcf3ce44SJohn Forte 	orig_icmdp = icmdp->cmd_un.r2t.icmdp;
2026fcf3ce44SJohn Forte 	ASSERT(orig_icmdp);
2027fcf3ce44SJohn Forte 
2028fcf3ce44SJohn Forte 	/* validate the offset and length against the buffer size */
2029fcf3ce44SJohn Forte 	if ((icmdp->cmd_un.r2t.offset + icmdp->cmd_un.r2t.length) >
2030fcf3ce44SJohn Forte 	    orig_icmdp->cmd_un.scsi.bp->b_bcount) {
2031fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi session(%u) ignoring invalid r2t "
2032fcf3ce44SJohn Forte 		    "for icmd itt:0x%x offset:0x%x length:0x%x bufsize:0x%lx",
2033fcf3ce44SJohn Forte 		    isp->sess_oid, icmdp->cmd_itt, icmdp->cmd_un.r2t.offset,
2034fcf3ce44SJohn Forte 		    icmdp->cmd_un.r2t.length, orig_icmdp->cmd_un.scsi.bp->
2035fcf3ce44SJohn Forte 		    b_bcount);
2036fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_queue_pending.mutex);
2037fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
2038fcf3ce44SJohn Forte 	}
2039fcf3ce44SJohn Forte 	ASSERT(orig_icmdp->cmd_un.scsi.r2t_icmdp);
2040fcf3ce44SJohn Forte 
2041fcf3ce44SJohn Forte 	rval = iscsi_tx_data(isp, icp, orig_icmdp, icmdp->cmd_ttt,
2042fcf3ce44SJohn Forte 	    icmdp->cmd_un.r2t.length, icmdp->cmd_un.r2t.offset);
2043fcf3ce44SJohn Forte 
2044fcf3ce44SJohn Forte 	mutex_enter(&orig_icmdp->cmd_mutex);
2045fcf3ce44SJohn Forte 	orig_icmdp->cmd_un.scsi.r2t_icmdp = NULL;
2046fcf3ce44SJohn Forte 	icmdp->cmd_un.r2t.icmdp = NULL;
2047fcf3ce44SJohn Forte 	/*
2048fcf3ce44SJohn Forte 	 * we're finished with this r2t; there could be another r2t
2049fcf3ce44SJohn Forte 	 * waiting on us to finish, so signal it.
2050fcf3ce44SJohn Forte 	 */
2051fcf3ce44SJohn Forte 	cv_broadcast(&orig_icmdp->cmd_completion);
2052fcf3ce44SJohn Forte 	mutex_exit(&orig_icmdp->cmd_mutex);
2053fcf3ce44SJohn Forte 	/*
2054fcf3ce44SJohn Forte 	 * the parent command may be waiting for us to finish; if so,
2055fcf3ce44SJohn Forte 	 * wake the _ic_ thread
2056fcf3ce44SJohn Forte 	 */
2057fcf3ce44SJohn Forte 	if ((orig_icmdp->cmd_state == ISCSI_CMD_STATE_COMPLETED) &&
2058e790cde8Sbing zhao - Sun Microsystems - Beijing China 	    (ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) &&
2059e790cde8Sbing zhao - Sun Microsystems - Beijing China 	    (orig_icmdp->cmd_un.scsi.r2t_more == B_FALSE))
2060fcf3ce44SJohn Forte 		iscsi_thread_send_wakeup(isp->sess_ic_thread);
2061fcf3ce44SJohn Forte 	ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex));
2062fcf3ce44SJohn Forte 	return (rval);
2063fcf3ce44SJohn Forte }
2064fcf3ce44SJohn Forte 
2065fcf3ce44SJohn Forte 
2066fcf3ce44SJohn Forte /*
2067fcf3ce44SJohn Forte  * iscsi_tx_data -
2068fcf3ce44SJohn Forte  */
2069fcf3ce44SJohn Forte static iscsi_status_t
2070fcf3ce44SJohn Forte iscsi_tx_data(iscsi_sess_t *isp, iscsi_conn_t *icp, iscsi_cmd_t *icmdp,
2071fcf3ce44SJohn Forte     uint32_t ttt, size_t datalen, size_t offset)
2072fcf3ce44SJohn Forte {
2073fcf3ce44SJohn Forte 	iscsi_status_t		rval		= ISCSI_STATUS_SUCCESS;
2074fcf3ce44SJohn Forte 	struct buf		*bp		= NULL;
2075fcf3ce44SJohn Forte 	size_t			remainder	= 0;
2076fcf3ce44SJohn Forte 	size_t			chunk		= 0;
2077fcf3ce44SJohn Forte 	char			*data		= NULL;
2078fcf3ce44SJohn Forte 	uint32_t		data_sn		= 0;
2079fcf3ce44SJohn Forte 	iscsi_data_hdr_t	idhp;
2080fcf3ce44SJohn Forte 	uint32_t		itt;
2081fcf3ce44SJohn Forte 	uint32_t		lun;
2082fcf3ce44SJohn Forte 
2083fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2084fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2085fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2086fcf3ce44SJohn Forte 	bp = icmdp->cmd_un.scsi.bp;
2087fcf3ce44SJohn Forte 
2088fcf3ce44SJohn Forte 	/* verify there is data to send */
2089fcf3ce44SJohn Forte 	if (bp == NULL) {
2090fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_queue_pending.mutex);
2091fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
2092fcf3ce44SJohn Forte 	}
2093fcf3ce44SJohn Forte 
2094fcf3ce44SJohn Forte 	itt = icmdp->cmd_itt;
2095fcf3ce44SJohn Forte 	lun = icmdp->cmd_un.scsi.lun;
2096fcf3ce44SJohn Forte 
2097fcf3ce44SJohn Forte 	/*
2098fcf3ce44SJohn Forte 	 * update the LUN with the amount of data we will
2099fcf3ce44SJohn Forte 	 * transfer.  If there is a failure it's because of
2100fcf3ce44SJohn Forte 	 * a network fault and the command will get flushed.
2101fcf3ce44SJohn Forte 	 */
2102fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.data_transferred += datalen;
2103fcf3ce44SJohn Forte 
2104fcf3ce44SJohn Forte 	/* release pending queue mutex across the network call */
2105fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2106fcf3ce44SJohn Forte 
2107fcf3ce44SJohn Forte 	remainder = datalen;
2108fcf3ce44SJohn Forte 	while (remainder) {
2109fcf3ce44SJohn Forte 
2110fcf3ce44SJohn Forte 		/* Check so see if we need to chunk the data */
2111fcf3ce44SJohn Forte 		if ((icp->conn_params.max_xmit_data_seg_len > 0) &&
2112fcf3ce44SJohn Forte 		    (remainder > icp->conn_params.max_xmit_data_seg_len)) {
2113fcf3ce44SJohn Forte 			chunk = icp->conn_params.max_xmit_data_seg_len;
2114fcf3ce44SJohn Forte 		} else {
2115fcf3ce44SJohn Forte 			chunk = remainder;
2116fcf3ce44SJohn Forte 		}
2117fcf3ce44SJohn Forte 
2118fcf3ce44SJohn Forte 		/* setup iscsi data hdr */
2119fcf3ce44SJohn Forte 		bzero(&idhp, sizeof (iscsi_data_hdr_t));
2120fcf3ce44SJohn Forte 		idhp.opcode	= ISCSI_OP_SCSI_DATA;
2121fcf3ce44SJohn Forte 		idhp.itt	= itt;
2122fcf3ce44SJohn Forte 		idhp.ttt	= ttt;
2123fcf3ce44SJohn Forte 		ISCSI_LUN_BYTE_COPY(idhp.lun, lun);
2124fcf3ce44SJohn Forte 		idhp.expstatsn	= htonl(icp->conn_expstatsn);
2125fcf3ce44SJohn Forte 		icp->conn_laststatsn = icp->conn_expstatsn;
2126fcf3ce44SJohn Forte 		idhp.datasn	= htonl(data_sn);
2127fcf3ce44SJohn Forte 		data_sn++;
2128fcf3ce44SJohn Forte 		idhp.offset	= htonl(offset);
2129fcf3ce44SJohn Forte 		hton24(idhp.dlength, chunk);
2130fcf3ce44SJohn Forte 
2131fcf3ce44SJohn Forte 		if (chunk == remainder) {
2132fcf3ce44SJohn Forte 			idhp.flags = ISCSI_FLAG_FINAL; /* final chunk */
2133fcf3ce44SJohn Forte 		}
2134fcf3ce44SJohn Forte 
2135fcf3ce44SJohn Forte 		/* setup data */
2136fcf3ce44SJohn Forte 		data = bp->b_un.b_addr + offset;
2137fcf3ce44SJohn Forte 
2138fcf3ce44SJohn Forte 		/*
2139fcf3ce44SJohn Forte 		 * Keep track of how much data we have
2140fcf3ce44SJohn Forte 		 * transfer so far and how much is remaining.
2141fcf3ce44SJohn Forte 		 */
2142fcf3ce44SJohn Forte 		remainder -= chunk;
2143fcf3ce44SJohn Forte 		offset += chunk;
2144fcf3ce44SJohn Forte 
2145fcf3ce44SJohn Forte 		rval = iscsi_net->sendpdu(icp->conn_socket,
2146fcf3ce44SJohn Forte 		    (iscsi_hdr_t *)&idhp, data,
2147fcf3ce44SJohn Forte 		    ISCSI_CONN_TO_NET_DIGEST(icp));
2148fcf3ce44SJohn Forte 
2149fcf3ce44SJohn Forte 		if (ISCSI_SUCCESS(rval)) {
2150fcf3ce44SJohn Forte 			KSTAT_ADD_CONN_TX_BYTES(icp, chunk);
2151fcf3ce44SJohn Forte 		} else {
2152fcf3ce44SJohn Forte 			break;
2153fcf3ce44SJohn Forte 		}
2154fcf3ce44SJohn Forte 	}
2155fcf3ce44SJohn Forte 
2156fcf3ce44SJohn Forte 	return (rval);
2157fcf3ce44SJohn Forte }
2158fcf3ce44SJohn Forte 
2159fcf3ce44SJohn Forte 
2160fcf3ce44SJohn Forte /*
2161fcf3ce44SJohn Forte  * iscsi_tx_nop -
2162fcf3ce44SJohn Forte  *
2163fcf3ce44SJohn Forte  */
2164fcf3ce44SJohn Forte static iscsi_status_t
2165fcf3ce44SJohn Forte iscsi_tx_nop(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2166fcf3ce44SJohn Forte {
2167fcf3ce44SJohn Forte 	iscsi_status_t		rval	= ISCSI_STATUS_SUCCESS;
2168fcf3ce44SJohn Forte 	iscsi_conn_t		*icp	= NULL;
2169fcf3ce44SJohn Forte 	iscsi_nop_out_hdr_t	inohp;
2170fcf3ce44SJohn Forte 
2171fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2172fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2173fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
2174fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2175fcf3ce44SJohn Forte 
2176fcf3ce44SJohn Forte 	bzero(&inohp, sizeof (iscsi_nop_out_hdr_t));
2177fcf3ce44SJohn Forte 	inohp.opcode	= ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
2178fcf3ce44SJohn Forte 	inohp.flags	= ISCSI_FLAG_FINAL;
2179fcf3ce44SJohn Forte 	inohp.itt	= icmdp->cmd_itt;
2180fcf3ce44SJohn Forte 	inohp.ttt	= icmdp->cmd_ttt;
2181fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
2182fcf3ce44SJohn Forte 	inohp.cmdsn	= htonl(isp->sess_cmdsn);
2183fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
2184fcf3ce44SJohn Forte 	inohp.expstatsn	= htonl(icp->conn_expstatsn);
2185fcf3ce44SJohn Forte 	icp->conn_laststatsn = icp->conn_expstatsn;
2186fcf3ce44SJohn Forte 
2187fcf3ce44SJohn Forte 	/* release pending queue mutex across the network call */
2188fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2189fcf3ce44SJohn Forte 
2190fcf3ce44SJohn Forte 	rval = iscsi_net->sendpdu(icp->conn_socket,
2191fcf3ce44SJohn Forte 	    (iscsi_hdr_t *)&inohp, NULL,
2192fcf3ce44SJohn Forte 	    ISCSI_CONN_TO_NET_DIGEST(icp));
2193fcf3ce44SJohn Forte 
2194fcf3ce44SJohn Forte 	return (rval);
2195fcf3ce44SJohn Forte }
2196fcf3ce44SJohn Forte 
2197fcf3ce44SJohn Forte 
2198fcf3ce44SJohn Forte /*
2199fcf3ce44SJohn Forte  * iscsi_tx_abort -
2200fcf3ce44SJohn Forte  *
2201fcf3ce44SJohn Forte  */
2202fcf3ce44SJohn Forte static iscsi_status_t
2203fcf3ce44SJohn Forte iscsi_tx_abort(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2204fcf3ce44SJohn Forte {
2205fcf3ce44SJohn Forte 	iscsi_status_t			rval	= ISCSI_STATUS_SUCCESS;
2206fcf3ce44SJohn Forte 	iscsi_conn_t			*icp	= NULL;
2207fcf3ce44SJohn Forte 	iscsi_scsi_task_mgt_hdr_t	istmh;
2208fcf3ce44SJohn Forte 
2209fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2210fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2211fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
2212fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2213fcf3ce44SJohn Forte 
2214fcf3ce44SJohn Forte 	bzero(&istmh, sizeof (iscsi_scsi_task_mgt_hdr_t));
2215fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
2216fcf3ce44SJohn Forte 	istmh.cmdsn	= htonl(isp->sess_cmdsn);
2217fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
2218fcf3ce44SJohn Forte 	istmh.expstatsn = htonl(icp->conn_expstatsn);
2219fcf3ce44SJohn Forte 	icp->conn_laststatsn = icp->conn_expstatsn;
2220fcf3ce44SJohn Forte 	istmh.itt	= icmdp->cmd_itt;
2221fcf3ce44SJohn Forte 	istmh.opcode	= ISCSI_OP_SCSI_TASK_MGT_MSG | ISCSI_OP_IMMEDIATE;
2222fcf3ce44SJohn Forte 	istmh.function	= ISCSI_FLAG_FINAL | ISCSI_TM_FUNC_ABORT_TASK;
2223fcf3ce44SJohn Forte 	ISCSI_LUN_BYTE_COPY(istmh.lun,
2224fcf3ce44SJohn Forte 	    icmdp->cmd_un.abort.icmdp->cmd_un.scsi.lun);
2225fcf3ce44SJohn Forte 	istmh.rtt	= icmdp->cmd_un.abort.icmdp->cmd_itt;
2226fcf3ce44SJohn Forte 
2227fcf3ce44SJohn Forte 	/* release pending queue mutex across the network call */
2228fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2229fcf3ce44SJohn Forte 
2230fcf3ce44SJohn Forte 	rval = iscsi_net->sendpdu(icp->conn_socket,
2231fcf3ce44SJohn Forte 	    (iscsi_hdr_t *)&istmh, NULL,
2232fcf3ce44SJohn Forte 	    ISCSI_CONN_TO_NET_DIGEST(icp));
2233fcf3ce44SJohn Forte 
2234fcf3ce44SJohn Forte 	return (rval);
2235fcf3ce44SJohn Forte }
2236fcf3ce44SJohn Forte 
2237fcf3ce44SJohn Forte 
2238fcf3ce44SJohn Forte /*
2239fcf3ce44SJohn Forte  * iscsi_tx_reset -
2240fcf3ce44SJohn Forte  *
2241fcf3ce44SJohn Forte  */
2242fcf3ce44SJohn Forte static iscsi_status_t
2243fcf3ce44SJohn Forte iscsi_tx_reset(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2244fcf3ce44SJohn Forte {
2245fcf3ce44SJohn Forte 	iscsi_status_t			rval	= ISCSI_STATUS_SUCCESS;
2246fcf3ce44SJohn Forte 	iscsi_conn_t			*icp	= NULL;
2247fcf3ce44SJohn Forte 	iscsi_scsi_task_mgt_hdr_t	istmh;
2248fcf3ce44SJohn Forte 
2249fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2250fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2251fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
2252fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2253fcf3ce44SJohn Forte 
2254fcf3ce44SJohn Forte 	bzero(&istmh, sizeof (iscsi_scsi_task_mgt_hdr_t));
2255fcf3ce44SJohn Forte 	istmh.opcode	= ISCSI_OP_SCSI_TASK_MGT_MSG | ISCSI_OP_IMMEDIATE;
2256fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
2257fcf3ce44SJohn Forte 	istmh.cmdsn	= htonl(isp->sess_cmdsn);
2258fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
2259fcf3ce44SJohn Forte 	istmh.expstatsn	= htonl(icp->conn_expstatsn);
2260fcf3ce44SJohn Forte 	istmh.itt	= icmdp->cmd_itt;
2261fcf3ce44SJohn Forte 
2262fcf3ce44SJohn Forte 	switch (icmdp->cmd_un.reset.level) {
2263fcf3ce44SJohn Forte 	case RESET_LUN:
2264fcf3ce44SJohn Forte 		istmh.function	= ISCSI_FLAG_FINAL |
2265fcf3ce44SJohn Forte 		    ISCSI_TM_FUNC_LOGICAL_UNIT_RESET;
2266fcf3ce44SJohn Forte 		ISCSI_LUN_BYTE_COPY(istmh.lun, icmdp->cmd_lun->lun_num);
2267fcf3ce44SJohn Forte 		break;
2268fcf3ce44SJohn Forte 	case RESET_TARGET:
2269fcf3ce44SJohn Forte 	case RESET_BUS:
2270fcf3ce44SJohn Forte 		istmh.function	= ISCSI_FLAG_FINAL |
2271fcf3ce44SJohn Forte 		    ISCSI_TM_FUNC_TARGET_WARM_RESET;
2272fcf3ce44SJohn Forte 		break;
2273fcf3ce44SJohn Forte 	default:
2274fcf3ce44SJohn Forte 		/* unsupported / unknown level */
2275fcf3ce44SJohn Forte 		ASSERT(FALSE);
2276fcf3ce44SJohn Forte 		break;
2277fcf3ce44SJohn Forte 	}
2278fcf3ce44SJohn Forte 
2279fcf3ce44SJohn Forte 	/* release pending queue mutex across the network call */
2280fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2281fcf3ce44SJohn Forte 
2282fcf3ce44SJohn Forte 	rval = iscsi_net->sendpdu(icp->conn_socket,
2283fcf3ce44SJohn Forte 	    (iscsi_hdr_t *)&istmh, NULL,
2284fcf3ce44SJohn Forte 	    ISCSI_CONN_TO_NET_DIGEST(icp));
2285fcf3ce44SJohn Forte 
2286fcf3ce44SJohn Forte 	return (rval);
2287fcf3ce44SJohn Forte }
2288fcf3ce44SJohn Forte 
2289fcf3ce44SJohn Forte 
2290fcf3ce44SJohn Forte /*
2291fcf3ce44SJohn Forte  * iscsi_tx_logout -
2292fcf3ce44SJohn Forte  *
2293fcf3ce44SJohn Forte  */
2294fcf3ce44SJohn Forte static iscsi_status_t
2295fcf3ce44SJohn Forte iscsi_tx_logout(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2296fcf3ce44SJohn Forte {
2297fcf3ce44SJohn Forte 	iscsi_status_t		rval	= ISCSI_STATUS_SUCCESS;
2298fcf3ce44SJohn Forte 	iscsi_conn_t		*icp	= NULL;
2299fcf3ce44SJohn Forte 	iscsi_logout_hdr_t	ilh;
2300fcf3ce44SJohn Forte 
2301fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2302fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2303fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
2304fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2305fcf3ce44SJohn Forte 
2306fcf3ce44SJohn Forte 	bzero(&ilh, sizeof (iscsi_logout_hdr_t));
2307fcf3ce44SJohn Forte 	ilh.opcode	= ISCSI_OP_LOGOUT_CMD | ISCSI_OP_IMMEDIATE;
2308fcf3ce44SJohn Forte 	ilh.flags	= ISCSI_FLAG_FINAL | ISCSI_LOGOUT_REASON_CLOSE_SESSION;
2309fcf3ce44SJohn Forte 	ilh.itt		= icmdp->cmd_itt;
2310fcf3ce44SJohn Forte 	ilh.cid		= icp->conn_cid;
2311fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
2312fcf3ce44SJohn Forte 	ilh.cmdsn	= htonl(isp->sess_cmdsn);
2313fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
2314fcf3ce44SJohn Forte 	ilh.expstatsn	= htonl(icp->conn_expstatsn);
2315fcf3ce44SJohn Forte 
2316fcf3ce44SJohn Forte 	/* release pending queue mutex across the network call */
2317fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2318fcf3ce44SJohn Forte 
2319fcf3ce44SJohn Forte 	rval = iscsi_net->sendpdu(icp->conn_socket,
2320fcf3ce44SJohn Forte 	    (iscsi_hdr_t *)&ilh, NULL,
2321fcf3ce44SJohn Forte 	    ISCSI_CONN_TO_NET_DIGEST(icp));
2322fcf3ce44SJohn Forte 
2323fcf3ce44SJohn Forte 	return (rval);
2324fcf3ce44SJohn Forte }
2325fcf3ce44SJohn Forte 
2326fcf3ce44SJohn Forte /*
2327fcf3ce44SJohn Forte  * iscsi_tx_text - setup iSCSI text request header and send PDU with
2328fcf3ce44SJohn Forte  * data given in the buffer attached to the command.  For a single
2329fcf3ce44SJohn Forte  * text request, the target may need to send its response in multiple
2330fcf3ce44SJohn Forte  * text response.  In this case, empty text requests are sent after
2331fcf3ce44SJohn Forte  * each received response to notify the target the initiator is ready
2332fcf3ce44SJohn Forte  * for more response.  For the initial request, the data_len field in
2333fcf3ce44SJohn Forte  * the text specific portion of a command is set to the amount of data
2334fcf3ce44SJohn Forte  * the initiator wants to send as part of the request. If additional
2335fcf3ce44SJohn Forte  * empty text requests are required for long responses, the data_len
2336fcf3ce44SJohn Forte  * field is set to 0 by the iscsi_handle_text function.
2337fcf3ce44SJohn Forte  */
2338fcf3ce44SJohn Forte static iscsi_status_t
2339fcf3ce44SJohn Forte iscsi_tx_text(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2340fcf3ce44SJohn Forte {
2341fcf3ce44SJohn Forte 	iscsi_status_t		rval	= ISCSI_STATUS_SUCCESS;
2342fcf3ce44SJohn Forte 	iscsi_conn_t		*icp	= NULL;
2343fcf3ce44SJohn Forte 	iscsi_text_hdr_t	ith;
2344fcf3ce44SJohn Forte 
2345fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2346fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2347fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
2348fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2349fcf3ce44SJohn Forte 
2350fcf3ce44SJohn Forte 	bzero(&ith, sizeof (iscsi_text_hdr_t));
2351fcf3ce44SJohn Forte 	ith.opcode	= ISCSI_OP_TEXT_CMD;
2352fcf3ce44SJohn Forte 	ith.flags	= ISCSI_FLAG_FINAL;
2353fcf3ce44SJohn Forte 	hton24(ith.dlength, icmdp->cmd_un.text.data_len);
2354fcf3ce44SJohn Forte 	ith.itt		= icmdp->cmd_itt;
2355fcf3ce44SJohn Forte 	ith.ttt		= icmdp->cmd_un.text.ttt;
2356fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
2357fcf3ce44SJohn Forte 	ith.cmdsn	= htonl(isp->sess_cmdsn);
2358fcf3ce44SJohn Forte 	isp->sess_cmdsn++;
2359fcf3ce44SJohn Forte 	ith.expstatsn	= htonl(icp->conn_expstatsn);
2360fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
2361fcf3ce44SJohn Forte 	bcopy(icmdp->cmd_un.text.lun, ith.rsvd4, sizeof (ith.rsvd4));
2362fcf3ce44SJohn Forte 
2363fcf3ce44SJohn Forte 	/* release pending queue mutex across the network call */
2364fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2365fcf3ce44SJohn Forte 
2366fcf3ce44SJohn Forte 	rval = iscsi_net->sendpdu(icp->conn_socket,
2367fcf3ce44SJohn Forte 	    (iscsi_hdr_t *)&ith, icmdp->cmd_un.text.buf,
2368fcf3ce44SJohn Forte 	    ISCSI_CONN_TO_NET_DIGEST(icp));
2369fcf3ce44SJohn Forte 
2370fcf3ce44SJohn Forte 	return (rval);
2371fcf3ce44SJohn Forte }
2372fcf3ce44SJohn Forte 
2373fcf3ce44SJohn Forte /*
2374fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
2375fcf3ce44SJohn Forte  * | End of protocol send routines					|
2376fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
2377fcf3ce44SJohn Forte  */
2378fcf3ce44SJohn Forte 
2379fcf3ce44SJohn Forte /*
2380e790cde8Sbing zhao - Sun Microsystems - Beijing China  * iscsi_handle_r2t - Create a R2T and put it into the pending queue.
2381e790cde8Sbing zhao - Sun Microsystems - Beijing China  *
2382e790cde8Sbing zhao - Sun Microsystems - Beijing China  * Since the rx thread can hold the pending mutex, the tx thread or wd
2383e790cde8Sbing zhao - Sun Microsystems - Beijing China  * thread may not have chance to check the commands in the pending queue.
2384e790cde8Sbing zhao - Sun Microsystems - Beijing China  * So if the previous R2T is still there, we will release the related
2385e790cde8Sbing zhao - Sun Microsystems - Beijing China  * mutex and wait for its completion in case of deadlock.
2386fcf3ce44SJohn Forte  */
2387fcf3ce44SJohn Forte static void
2388fcf3ce44SJohn Forte iscsi_handle_r2t(iscsi_conn_t *icp, iscsi_cmd_t *icmdp,
2389fcf3ce44SJohn Forte     uint32_t offset, uint32_t length, uint32_t ttt)
2390fcf3ce44SJohn Forte {
2391fcf3ce44SJohn Forte 	iscsi_sess_t	*isp		= NULL;
2392fcf3ce44SJohn Forte 	iscsi_cmd_t	*new_icmdp	= NULL;
2393e790cde8Sbing zhao - Sun Microsystems - Beijing China 	int		owned		= 0;
2394fcf3ce44SJohn Forte 
2395fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2396fcf3ce44SJohn Forte 	isp = icp->conn_sess;
2397fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2398fcf3ce44SJohn Forte 
2399e790cde8Sbing zhao - Sun Microsystems - Beijing China 	if (icmdp->cmd_un.scsi.r2t_icmdp != NULL) {
2400e790cde8Sbing zhao - Sun Microsystems - Beijing China 		/*
2401e790cde8Sbing zhao - Sun Microsystems - Beijing China 		 * Occasionally the tx thread doesn't have a chance to
2402e790cde8Sbing zhao - Sun Microsystems - Beijing China 		 * send commands when we hold the pending mutex.
2403e790cde8Sbing zhao - Sun Microsystems - Beijing China 		 * So we should mark this scsi command with more R2T
2404e790cde8Sbing zhao - Sun Microsystems - Beijing China 		 * and release the mutex. Then wait for completion.
2405e790cde8Sbing zhao - Sun Microsystems - Beijing China 		 */
2406e790cde8Sbing zhao - Sun Microsystems - Beijing China 		icmdp->cmd_un.scsi.r2t_more = B_TRUE;
2407e790cde8Sbing zhao - Sun Microsystems - Beijing China 
2408e790cde8Sbing zhao - Sun Microsystems - Beijing China 		mutex_exit(&icmdp->cmd_mutex);
2409e790cde8Sbing zhao - Sun Microsystems - Beijing China 		owned = mutex_owned(&icp->conn_queue_active.mutex);
2410e790cde8Sbing zhao - Sun Microsystems - Beijing China 		if (owned != 0) {
2411e790cde8Sbing zhao - Sun Microsystems - Beijing China 			mutex_exit(&icp->conn_queue_active.mutex);
2412e790cde8Sbing zhao - Sun Microsystems - Beijing China 		}
2413e790cde8Sbing zhao - Sun Microsystems - Beijing China 		mutex_exit(&isp->sess_queue_pending.mutex);
2414e790cde8Sbing zhao - Sun Microsystems - Beijing China 
2415e790cde8Sbing zhao - Sun Microsystems - Beijing China 		/*
2416e790cde8Sbing zhao - Sun Microsystems - Beijing China 		 * the transmission from a previous r2t can be
2417e790cde8Sbing zhao - Sun Microsystems - Beijing China 		 * slow to return; the array may have sent
2418e790cde8Sbing zhao - Sun Microsystems - Beijing China 		 * another r2t at this point, so wait until
2419e790cde8Sbing zhao - Sun Microsystems - Beijing China 		 * the first one finishes and signals us.
2420e790cde8Sbing zhao - Sun Microsystems - Beijing China 		 */
2421e790cde8Sbing zhao - Sun Microsystems - Beijing China 		mutex_enter(&icmdp->cmd_mutex);
2422e790cde8Sbing zhao - Sun Microsystems - Beijing China 		while (icmdp->cmd_un.scsi.r2t_icmdp != NULL) {
2423e790cde8Sbing zhao - Sun Microsystems - Beijing China 			ASSERT(icmdp->cmd_state != ISCSI_CMD_STATE_COMPLETED);
2424e790cde8Sbing zhao - Sun Microsystems - Beijing China 			cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
2425e790cde8Sbing zhao - Sun Microsystems - Beijing China 		}
2426e790cde8Sbing zhao - Sun Microsystems - Beijing China 		mutex_exit(&icmdp->cmd_mutex);
2427e790cde8Sbing zhao - Sun Microsystems - Beijing China 
2428e790cde8Sbing zhao - Sun Microsystems - Beijing China 		mutex_enter(&isp->sess_queue_pending.mutex);
2429e790cde8Sbing zhao - Sun Microsystems - Beijing China 		if (owned != 0) {
2430e790cde8Sbing zhao - Sun Microsystems - Beijing China 			mutex_enter(&icp->conn_queue_active.mutex);
2431e790cde8Sbing zhao - Sun Microsystems - Beijing China 		}
2432e790cde8Sbing zhao - Sun Microsystems - Beijing China 		mutex_enter(&icmdp->cmd_mutex);
2433fcf3ce44SJohn Forte 	}
2434e790cde8Sbing zhao - Sun Microsystems - Beijing China 
2435fcf3ce44SJohn Forte 	/*
2436fcf3ce44SJohn Forte 	 * try to create an R2T task to send it later.  If we can't,
2437fcf3ce44SJohn Forte 	 * we're screwed, and the command will eventually time out
2438fcf3ce44SJohn Forte 	 * and be retried by the SCSI layer.
2439fcf3ce44SJohn Forte 	 */
2440fcf3ce44SJohn Forte 	new_icmdp = iscsi_cmd_alloc(icp, KM_SLEEP);
2441fcf3ce44SJohn Forte 	new_icmdp->cmd_type		= ISCSI_CMD_TYPE_R2T;
2442fcf3ce44SJohn Forte 	new_icmdp->cmd_un.r2t.icmdp	= icmdp;
2443fcf3ce44SJohn Forte 	new_icmdp->cmd_un.r2t.offset	= offset;
2444fcf3ce44SJohn Forte 	new_icmdp->cmd_un.r2t.length	= length;
2445fcf3ce44SJohn Forte 	new_icmdp->cmd_ttt		= ttt;
2446fcf3ce44SJohn Forte 	new_icmdp->cmd_itt		= icmdp->cmd_itt;
2447fcf3ce44SJohn Forte 	new_icmdp->cmd_lun		= icmdp->cmd_lun;
2448fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.r2t_icmdp	= new_icmdp;
2449e790cde8Sbing zhao - Sun Microsystems - Beijing China 	icmdp->cmd_un.scsi.r2t_more	= B_FALSE;
2450fcf3ce44SJohn Forte 
2451fcf3ce44SJohn Forte 	/*
2452fcf3ce44SJohn Forte 	 * pending queue mutex is already held by the
2453fcf3ce44SJohn Forte 	 * tx_thread or rtt_rsp function.
2454fcf3ce44SJohn Forte 	 */
2455fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(new_icmdp, ISCSI_CMD_EVENT_E1, isp);
2456fcf3ce44SJohn Forte }
2457fcf3ce44SJohn Forte 
2458fcf3ce44SJohn Forte 
2459fcf3ce44SJohn Forte /*
2460fcf3ce44SJohn Forte  * iscsi_handle_abort -
2461fcf3ce44SJohn Forte  *
2462fcf3ce44SJohn Forte  */
2463fcf3ce44SJohn Forte void
2464fcf3ce44SJohn Forte iscsi_handle_abort(void *arg)
2465fcf3ce44SJohn Forte {
2466fcf3ce44SJohn Forte 	iscsi_sess_t	*isp		= NULL;
2467fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp		= (iscsi_cmd_t *)arg;
2468fcf3ce44SJohn Forte 	iscsi_cmd_t	*new_icmdp;
2469fcf3ce44SJohn Forte 	iscsi_conn_t	*icp;
2470fcf3ce44SJohn Forte 
2471fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2472fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
2473fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2474fcf3ce44SJohn Forte 	isp = icp->conn_sess;
2475fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2476fcf3ce44SJohn Forte 
2477fcf3ce44SJohn Forte 	/* there should only be one abort */
2478fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL);
2479fcf3ce44SJohn Forte 
2480fcf3ce44SJohn Forte 	new_icmdp = iscsi_cmd_alloc(icp, KM_SLEEP);
2481fcf3ce44SJohn Forte 	new_icmdp->cmd_type		= ISCSI_CMD_TYPE_ABORT;
2482fcf3ce44SJohn Forte 	new_icmdp->cmd_lun		= icmdp->cmd_lun;
2483fcf3ce44SJohn Forte 	new_icmdp->cmd_un.abort.icmdp	= icmdp;
2484fcf3ce44SJohn Forte 	new_icmdp->cmd_conn		= icmdp->cmd_conn;
2485fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.abort_icmdp	= new_icmdp;
2486fcf3ce44SJohn Forte 
2487fcf3ce44SJohn Forte 	/* pending queue mutex is already held by timeout_checks */
2488fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(new_icmdp, ISCSI_CMD_EVENT_E1, isp);
2489fcf3ce44SJohn Forte }
2490fcf3ce44SJohn Forte 
2491fcf3ce44SJohn Forte 
2492fcf3ce44SJohn Forte /*
2493fcf3ce44SJohn Forte  * iscsi_handle_nop -
2494fcf3ce44SJohn Forte  *
2495fcf3ce44SJohn Forte  */
2496fcf3ce44SJohn Forte static void
2497fcf3ce44SJohn Forte iscsi_handle_nop(iscsi_conn_t *icp, uint32_t itt, uint32_t ttt)
2498fcf3ce44SJohn Forte {
2499fcf3ce44SJohn Forte 	iscsi_sess_t	*isp	= NULL;
2500fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp	= NULL;
2501fcf3ce44SJohn Forte 
2502fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2503fcf3ce44SJohn Forte 	isp = icp->conn_sess;
2504fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2505fcf3ce44SJohn Forte 
2506fcf3ce44SJohn Forte 	icmdp = iscsi_cmd_alloc(icp, KM_NOSLEEP);
2507fcf3ce44SJohn Forte 	if (icmdp == NULL) {
2508fcf3ce44SJohn Forte 		return;
2509fcf3ce44SJohn Forte 	}
2510fcf3ce44SJohn Forte 
2511fcf3ce44SJohn Forte 	icmdp->cmd_type		= ISCSI_CMD_TYPE_NOP;
2512fcf3ce44SJohn Forte 	icmdp->cmd_itt		= itt;
2513fcf3ce44SJohn Forte 	icmdp->cmd_ttt		= ttt;
2514fcf3ce44SJohn Forte 	icmdp->cmd_lun		= NULL;
2515fcf3ce44SJohn Forte 	icp->conn_nop_lbolt	= ddi_get_lbolt();
2516fcf3ce44SJohn Forte 
2517fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
2518fcf3ce44SJohn Forte }
2519fcf3ce44SJohn Forte 
2520fcf3ce44SJohn Forte /*
2521fcf3ce44SJohn Forte  * iscsi_handle_reset -
2522fcf3ce44SJohn Forte  *
2523fcf3ce44SJohn Forte  */
2524fcf3ce44SJohn Forte iscsi_status_t
2525fcf3ce44SJohn Forte iscsi_handle_reset(iscsi_sess_t *isp, int level, iscsi_lun_t *ilp)
2526fcf3ce44SJohn Forte {
2527fcf3ce44SJohn Forte 	iscsi_status_t	rval	= ISCSI_STATUS_SUCCESS;
2528fcf3ce44SJohn Forte 	iscsi_conn_t	*icp;
2529fcf3ce44SJohn Forte 	iscsi_cmd_t	icmd;
2530fcf3ce44SJohn Forte 
2531fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2532fcf3ce44SJohn Forte 
2533fcf3ce44SJohn Forte 	bzero(&icmd, sizeof (iscsi_cmd_t));
2534fcf3ce44SJohn Forte 	icmd.cmd_sig		= ISCSI_SIG_CMD;
2535fcf3ce44SJohn Forte 	icmd.cmd_state		= ISCSI_CMD_STATE_FREE;
2536fcf3ce44SJohn Forte 	icmd.cmd_type		= ISCSI_CMD_TYPE_RESET;
2537fcf3ce44SJohn Forte 	icmd.cmd_lun		= ilp;
2538fcf3ce44SJohn Forte 	icmd.cmd_un.reset.level	= level;
2539fcf3ce44SJohn Forte 	icmd.cmd_result		= ISCSI_STATUS_SUCCESS;
2540fcf3ce44SJohn Forte 	icmd.cmd_completed	= B_FALSE;
2541fcf3ce44SJohn Forte 	mutex_init(&icmd.cmd_mutex, NULL, MUTEX_DRIVER, NULL);
2542fcf3ce44SJohn Forte 	cv_init(&icmd.cmd_completion, NULL, CV_DRIVER, NULL);
2543fcf3ce44SJohn Forte 	/*
2544fcf3ce44SJohn Forte 	 * If we received an IO and we are not in the
2545fcf3ce44SJohn Forte 	 * LOGGED_IN state we are in the process of
2546fcf3ce44SJohn Forte 	 * failing.  Just respond that we are BUSY.
2547fcf3ce44SJohn Forte 	 */
2548fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_state_mutex);
2549fcf3ce44SJohn Forte 	if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) {
2550fcf3ce44SJohn Forte 		/* We aren't connected to the target fake success */
2551fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
2552fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SUCCESS);
2553fcf3ce44SJohn Forte 	}
2554fcf3ce44SJohn Forte 
2555fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
2556fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(&icmd, ISCSI_CMD_EVENT_E1, isp);
2557fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2558fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_state_mutex);
2559fcf3ce44SJohn Forte 
2560fcf3ce44SJohn Forte 	/* stall until completed */
2561fcf3ce44SJohn Forte 	mutex_enter(&icmd.cmd_mutex);
2562fcf3ce44SJohn Forte 	while (icmd.cmd_completed == B_FALSE) {
2563fcf3ce44SJohn Forte 		cv_wait(&icmd.cmd_completion, &icmd.cmd_mutex);
2564fcf3ce44SJohn Forte 	}
2565fcf3ce44SJohn Forte 	mutex_exit(&icmd.cmd_mutex);
2566fcf3ce44SJohn Forte 
2567fcf3ce44SJohn Forte 	/* copy rval */
2568fcf3ce44SJohn Forte 	rval = icmd.cmd_result;
2569fcf3ce44SJohn Forte 
2570fcf3ce44SJohn Forte 	if (rval == ISCSI_STATUS_SUCCESS) {
2571fcf3ce44SJohn Forte 		/*
2572fcf3ce44SJohn Forte 		 * Reset was successful.  We need to flush
2573fcf3ce44SJohn Forte 		 * all active IOs.
2574fcf3ce44SJohn Forte 		 */
2575fcf3ce44SJohn Forte 		rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
2576fcf3ce44SJohn Forte 		icp = isp->sess_conn_list;
2577fcf3ce44SJohn Forte 		while (icp != NULL) {
2578fcf3ce44SJohn Forte 			iscsi_cmd_t *t_icmdp = NULL;
2579fcf3ce44SJohn Forte 
2580fcf3ce44SJohn Forte 			mutex_enter(&icp->conn_queue_active.mutex);
2581fcf3ce44SJohn Forte 			t_icmdp = icp->conn_queue_active.head;
2582fcf3ce44SJohn Forte 			while (t_icmdp != NULL) {
2583fcf3ce44SJohn Forte 				iscsi_cmd_state_machine(t_icmdp,
2584fcf3ce44SJohn Forte 				    ISCSI_CMD_EVENT_E7, isp);
2585fcf3ce44SJohn Forte 				t_icmdp = icp->conn_queue_active.head;
2586fcf3ce44SJohn Forte 			}
2587fcf3ce44SJohn Forte 
2588fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_queue_active.mutex);
2589fcf3ce44SJohn Forte 			icp = icp->conn_next;
2590fcf3ce44SJohn Forte 		}
2591fcf3ce44SJohn Forte 		rw_exit(&isp->sess_conn_list_rwlock);
2592fcf3ce44SJohn Forte 	}
2593fcf3ce44SJohn Forte 
2594fcf3ce44SJohn Forte 	/* clean up */
2595fcf3ce44SJohn Forte 	cv_destroy(&icmd.cmd_completion);
2596fcf3ce44SJohn Forte 	mutex_destroy(&icmd.cmd_mutex);
2597fcf3ce44SJohn Forte 
2598fcf3ce44SJohn Forte 	return (rval);
2599fcf3ce44SJohn Forte }
2600fcf3ce44SJohn Forte 
2601fcf3ce44SJohn Forte 
2602fcf3ce44SJohn Forte /*
2603fcf3ce44SJohn Forte  * iscsi_handle_logout - This function will issue a logout for
2604fcf3ce44SJohn Forte  * the session from a specific connection.
2605fcf3ce44SJohn Forte  */
2606fcf3ce44SJohn Forte iscsi_status_t
2607fcf3ce44SJohn Forte iscsi_handle_logout(iscsi_conn_t *icp)
2608fcf3ce44SJohn Forte {
2609fcf3ce44SJohn Forte 	iscsi_sess_t	*isp;
2610fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp;
2611fcf3ce44SJohn Forte 	int		rval;
2612fcf3ce44SJohn Forte 
2613fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2614fcf3ce44SJohn Forte 	isp = icp->conn_sess;
2615fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2616fcf3ce44SJohn Forte 	ASSERT(isp->sess_hba != NULL);
2617fcf3ce44SJohn Forte 
2618fcf3ce44SJohn Forte 	icmdp = iscsi_cmd_alloc(icp, KM_SLEEP);
2619fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2620fcf3ce44SJohn Forte 	icmdp->cmd_type		= ISCSI_CMD_TYPE_LOGOUT;
2621fcf3ce44SJohn Forte 	icmdp->cmd_result	= ISCSI_STATUS_SUCCESS;
2622fcf3ce44SJohn Forte 	icmdp->cmd_completed	= B_FALSE;
2623fcf3ce44SJohn Forte 
2624fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
2625fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
2626fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2627fcf3ce44SJohn Forte 
2628fcf3ce44SJohn Forte 	/*
2629fcf3ce44SJohn Forte 	 * release connection state mutex to avoid a deadlock.  This
2630fcf3ce44SJohn Forte 	 * function is called from within the connection state
2631fcf3ce44SJohn Forte 	 * machine with the lock held.  When the logout response is
2632fcf3ce44SJohn Forte 	 * received another call to the connection state machine
2633fcf3ce44SJohn Forte 	 * occurs which causes the deadlock
2634fcf3ce44SJohn Forte 	 */
2635fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_state_mutex);
2636fcf3ce44SJohn Forte 
2637fcf3ce44SJohn Forte 	/* stall until completed */
2638fcf3ce44SJohn Forte 	mutex_enter(&icmdp->cmd_mutex);
2639fcf3ce44SJohn Forte 	while (icmdp->cmd_completed == B_FALSE) {
2640fcf3ce44SJohn Forte 		cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
2641fcf3ce44SJohn Forte 	}
2642fcf3ce44SJohn Forte 	mutex_exit(&icmdp->cmd_mutex);
2643fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_state_mutex);
2644fcf3ce44SJohn Forte 
2645fcf3ce44SJohn Forte 	/* copy rval */
2646fcf3ce44SJohn Forte 	rval = icmdp->cmd_result;
2647fcf3ce44SJohn Forte 
2648fcf3ce44SJohn Forte 	/*
2649fcf3ce44SJohn Forte 	 * another way to do this would be to send t17 unconditionally,
2650fcf3ce44SJohn Forte 	 * but then the _rx_ thread would get bumped out with a receive
2651fcf3ce44SJohn Forte 	 * error, and send another t17.
2652fcf3ce44SJohn Forte 	 */
2653fcf3ce44SJohn Forte 	if (rval != ISCSI_STATUS_SUCCESS) {
2654fcf3ce44SJohn Forte 		(void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T17);
2655fcf3ce44SJohn Forte 	}
2656fcf3ce44SJohn Forte 
2657fcf3ce44SJohn Forte 	/* clean up */
2658fcf3ce44SJohn Forte 	iscsi_cmd_free(icmdp);
2659fcf3ce44SJohn Forte 
2660fcf3ce44SJohn Forte 	return (rval);
2661fcf3ce44SJohn Forte }
2662fcf3ce44SJohn Forte 
2663fcf3ce44SJohn Forte /*
2664fcf3ce44SJohn Forte  * iscsi_handle_text - main control function for iSCSI text requests.  This
2665fcf3ce44SJohn Forte  * function handles allocating the command, sending initial text request, and
2666fcf3ce44SJohn Forte  * handling long response sequence.
2667fcf3ce44SJohn Forte  * If a data overflow condition occurs, iscsi_handle_text continues to
2668fcf3ce44SJohn Forte  * receive responses until the all data has been recieved.  This allows
2669fcf3ce44SJohn Forte  * the full data length to be returned to the caller.
2670fcf3ce44SJohn Forte  */
2671fcf3ce44SJohn Forte iscsi_status_t
2672fcf3ce44SJohn Forte iscsi_handle_text(iscsi_conn_t *icp, char *buf, uint32_t buf_len,
2673fcf3ce44SJohn Forte     uint32_t data_len, uint32_t *rx_data_len)
2674fcf3ce44SJohn Forte {
2675fcf3ce44SJohn Forte 	iscsi_sess_t	*isp;
2676fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp;
2677fcf3ce44SJohn Forte 	iscsi_status_t	rval	= ISCSI_STATUS_SUCCESS;
2678fcf3ce44SJohn Forte 
2679fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2680fcf3ce44SJohn Forte 	ASSERT(buf != NULL);
2681fcf3ce44SJohn Forte 	ASSERT(rx_data_len != NULL);
2682fcf3ce44SJohn Forte 
2683fcf3ce44SJohn Forte 	isp = icp->conn_sess;
2684fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2685fcf3ce44SJohn Forte 
2686fcf3ce44SJohn Forte 	/*
2687fcf3ce44SJohn Forte 	 * Ensure data for text request command is not greater
2688fcf3ce44SJohn Forte 	 * than the negotiated maximum receive data seqment length.
2689fcf3ce44SJohn Forte 	 *
2690fcf3ce44SJohn Forte 	 * Although iSCSI allows for long text requests (multiple
2691fcf3ce44SJohn Forte 	 * pdus), this function places a restriction on text
2692fcf3ce44SJohn Forte 	 * requests to ensure it is handled by a single PDU.
2693fcf3ce44SJohn Forte 	 */
2694fcf3ce44SJohn Forte 	if (data_len > icp->conn_params.max_xmit_data_seg_len) {
2695fcf3ce44SJohn Forte 		return (ISCSI_STATUS_CMD_FAILED);
2696fcf3ce44SJohn Forte 	}
2697fcf3ce44SJohn Forte 
2698fcf3ce44SJohn Forte 	icmdp = iscsi_cmd_alloc(icp, KM_SLEEP);
2699fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2700fcf3ce44SJohn Forte 
2701fcf3ce44SJohn Forte 	icmdp->cmd_type		= ISCSI_CMD_TYPE_TEXT;
2702fcf3ce44SJohn Forte 	icmdp->cmd_result	= ISCSI_STATUS_SUCCESS;
2703d233de7eSJack Meng 	icmdp->cmd_misc_flags	&= ~ISCSI_CMD_MISCFLAG_FREE;
2704fcf3ce44SJohn Forte 	icmdp->cmd_completed	= B_FALSE;
2705fcf3ce44SJohn Forte 
2706fcf3ce44SJohn Forte 	icmdp->cmd_un.text.buf		= buf;
2707fcf3ce44SJohn Forte 	icmdp->cmd_un.text.buf_len	= buf_len;
2708fcf3ce44SJohn Forte 	icmdp->cmd_un.text.offset	= 0;
2709fcf3ce44SJohn Forte 	icmdp->cmd_un.text.data_len	= data_len;
2710fcf3ce44SJohn Forte 	icmdp->cmd_un.text.total_rx_len	= 0;
2711fcf3ce44SJohn Forte 	icmdp->cmd_un.text.ttt		= ISCSI_RSVD_TASK_TAG;
2712fcf3ce44SJohn Forte 	icmdp->cmd_un.text.stage	= ISCSI_CMD_TEXT_INITIAL_REQ;
2713fcf3ce44SJohn Forte 
2714fcf3ce44SJohn Forte long_text_response:
2715fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_state_mutex);
2716fcf3ce44SJohn Forte 	if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) {
2717fcf3ce44SJohn Forte 		iscsi_cmd_free(icmdp);
2718fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
2719fcf3ce44SJohn Forte 		return (ISCSI_STATUS_NO_CONN_LOGGED_IN);
2720fcf3ce44SJohn Forte 	}
2721fcf3ce44SJohn Forte 
2722fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
2723fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
2724fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2725fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_state_mutex);
2726fcf3ce44SJohn Forte 
2727fcf3ce44SJohn Forte 	/* stall until completed */
2728fcf3ce44SJohn Forte 	mutex_enter(&icmdp->cmd_mutex);
2729fcf3ce44SJohn Forte 	while (icmdp->cmd_completed == B_FALSE) {
2730fcf3ce44SJohn Forte 		cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
2731fcf3ce44SJohn Forte 	}
2732fcf3ce44SJohn Forte 	mutex_exit(&icmdp->cmd_mutex);
2733fcf3ce44SJohn Forte 
2734fcf3ce44SJohn Forte 	/*
2735fcf3ce44SJohn Forte 	 * check if error occured.  If data overflow occured, continue on
2736fcf3ce44SJohn Forte 	 * to ensure we get all data so that the full data length can be
2737fcf3ce44SJohn Forte 	 * returned to the user
2738fcf3ce44SJohn Forte 	 */
2739fcf3ce44SJohn Forte 	if ((icmdp->cmd_result != ISCSI_STATUS_SUCCESS) &&
2740fcf3ce44SJohn Forte 	    (icmdp->cmd_result != ISCSI_STATUS_DATA_OVERFLOW)) {
2741fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "iscsi: SendTarget discovery failed (%d)",
2742fcf3ce44SJohn Forte 		    icmdp->cmd_result);
2743fcf3ce44SJohn Forte 		rval = icmdp->cmd_result;
2744fcf3ce44SJohn Forte 		iscsi_cmd_free(icmdp);
2745fcf3ce44SJohn Forte 		return (rval);
2746fcf3ce44SJohn Forte 	}
2747fcf3ce44SJohn Forte 
2748fcf3ce44SJohn Forte 	/* check if this was a partial text PDU  */
2749fcf3ce44SJohn Forte 	if (icmdp->cmd_un.text.stage != ISCSI_CMD_TEXT_FINAL_RSP) {
2750fcf3ce44SJohn Forte 		/*
2751fcf3ce44SJohn Forte 		 * If a paritial text rexponse received, send an empty
2752fcf3ce44SJohn Forte 		 * text request.  This follows the behaviour specified
2753fcf3ce44SJohn Forte 		 * in RFC3720 regarding long text responses.
2754fcf3ce44SJohn Forte 		 */
2755d233de7eSJack Meng 		icmdp->cmd_misc_flags		&= ~ISCSI_CMD_MISCFLAG_FREE;
2756fcf3ce44SJohn Forte 		icmdp->cmd_completed		= B_FALSE;
2757fcf3ce44SJohn Forte 		icmdp->cmd_un.text.data_len	= 0;
2758fcf3ce44SJohn Forte 		icmdp->cmd_un.text.stage	= ISCSI_CMD_TEXT_CONTINUATION;
2759fcf3ce44SJohn Forte 		goto long_text_response;
2760fcf3ce44SJohn Forte 	}
2761fcf3ce44SJohn Forte 
2762fcf3ce44SJohn Forte 	/*
2763fcf3ce44SJohn Forte 	 * set total received data length.  If data overflow this would be
2764fcf3ce44SJohn Forte 	 * amount of data that would have been received if buffer large
2765fcf3ce44SJohn Forte 	 * enough.
2766fcf3ce44SJohn Forte 	 */
2767fcf3ce44SJohn Forte 	*rx_data_len = icmdp->cmd_un.text.total_rx_len;
2768fcf3ce44SJohn Forte 
2769fcf3ce44SJohn Forte 	/* copy rval */
2770fcf3ce44SJohn Forte 	rval = icmdp->cmd_result;
2771fcf3ce44SJohn Forte 
2772fcf3ce44SJohn Forte 	/* clean up  */
2773fcf3ce44SJohn Forte 	iscsi_cmd_free(icmdp);
2774fcf3ce44SJohn Forte 
2775fcf3ce44SJohn Forte 	return (rval);
2776fcf3ce44SJohn Forte }
2777fcf3ce44SJohn Forte 
2778fcf3ce44SJohn Forte /*
2779fcf3ce44SJohn Forte  * iscsi_handle_passthru - This function is used to send a uscsi_cmd
2780fcf3ce44SJohn Forte  * to a specific target lun.  This routine is used for internal purposes
2781fcf3ce44SJohn Forte  * during enumeration and via the ISCSI_USCSICMD IOCTL.  We restrict
2782fcf3ce44SJohn Forte  * the CDBs that can be issued to a target/lun to INQUIRY, REPORT_LUNS,
2783fcf3ce44SJohn Forte  * and READ_CAPACITY for security purposes.
2784fcf3ce44SJohn Forte  *
2785fcf3ce44SJohn Forte  * The logic here is broken into three phases.
2786fcf3ce44SJohn Forte  * 1) Allocate and initialize a pkt/icmdp
2787fcf3ce44SJohn Forte  * 2) Send the pkt/icmdp
2788fcf3ce44SJohn Forte  * 3) cv_wait for completion
2789fcf3ce44SJohn Forte  */
2790fcf3ce44SJohn Forte iscsi_status_t
2791fcf3ce44SJohn Forte iscsi_handle_passthru(iscsi_sess_t *isp, uint16_t lun, struct uscsi_cmd *ucmdp)
2792fcf3ce44SJohn Forte {
2793fcf3ce44SJohn Forte 	iscsi_status_t		rval		= ISCSI_STATUS_SUCCESS;
2794fcf3ce44SJohn Forte 	iscsi_cmd_t		*icmdp		= NULL;
2795fcf3ce44SJohn Forte 	struct scsi_pkt		*pkt		= NULL;
2796fcf3ce44SJohn Forte 	struct buf		*bp		= NULL;
2797fcf3ce44SJohn Forte 	struct scsi_arq_status  *arqstat	= NULL;
2798fcf3ce44SJohn Forte 	int			rqlen		= SENSE_LENGTH;
2799fcf3ce44SJohn Forte 
2800fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2801fcf3ce44SJohn Forte 	ASSERT(ucmdp != NULL);
2802fcf3ce44SJohn Forte 
2803fcf3ce44SJohn Forte 	/*
2804fcf3ce44SJohn Forte 	 * If the caller didn't provide a sense buffer we need
2805fcf3ce44SJohn Forte 	 * to allocation one to get the scsi status.
2806fcf3ce44SJohn Forte 	 */
2807fcf3ce44SJohn Forte 	if (ucmdp->uscsi_rqlen > SENSE_LENGTH) {
2808fcf3ce44SJohn Forte 		rqlen = ucmdp->uscsi_rqlen;
2809fcf3ce44SJohn Forte 	}
2810fcf3ce44SJohn Forte 
2811fcf3ce44SJohn Forte 	/*
2812fcf3ce44SJohn Forte 	 * Step 1. Setup structs - KM_SLEEP will always succeed
2813fcf3ce44SJohn Forte 	 */
2814fcf3ce44SJohn Forte 	bp = kmem_zalloc(sizeof (struct buf), KM_SLEEP);
2815fcf3ce44SJohn Forte 	ASSERT(bp != NULL);
2816fcf3ce44SJohn Forte 	pkt = kmem_zalloc(sizeof (struct scsi_pkt), KM_SLEEP);
2817fcf3ce44SJohn Forte 	ASSERT(pkt != NULL);
2818fcf3ce44SJohn Forte 	icmdp = iscsi_cmd_alloc(NULL, KM_SLEEP);
2819fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2820fcf3ce44SJohn Forte 
2821fcf3ce44SJohn Forte 	/* setup bp structure */
2822fcf3ce44SJohn Forte 	bp->b_flags		= B_READ;
2823fcf3ce44SJohn Forte 	bp->b_bcount		= ucmdp->uscsi_buflen;
2824fcf3ce44SJohn Forte 	bp->b_un.b_addr		= ucmdp->uscsi_bufaddr;
2825fcf3ce44SJohn Forte 
2826fcf3ce44SJohn Forte 	/* setup scsi_pkt structure */
2827fcf3ce44SJohn Forte 	pkt->pkt_ha_private	= icmdp;
2828fcf3ce44SJohn Forte 	pkt->pkt_scbp		= kmem_zalloc(rqlen, KM_SLEEP);
2829fcf3ce44SJohn Forte 	pkt->pkt_cdbp		= kmem_zalloc(ucmdp->uscsi_cdblen, KM_SLEEP);
2830fcf3ce44SJohn Forte 	/* callback routine for passthru, will wake cv_wait */
2831fcf3ce44SJohn Forte 	pkt->pkt_comp		= iscsi_handle_passthru_callback;
2832fcf3ce44SJohn Forte 	pkt->pkt_time		= ucmdp->uscsi_timeout;
2833fcf3ce44SJohn Forte 
2834fcf3ce44SJohn Forte 	/* setup iscsi_cmd structure */
2835fcf3ce44SJohn Forte 	icmdp->cmd_lun			= NULL;
2836fcf3ce44SJohn Forte 	icmdp->cmd_type			= ISCSI_CMD_TYPE_SCSI;
2837fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.lun		= lun;
2838fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.pkt		= pkt;
2839fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.bp		= bp;
2840fcf3ce44SJohn Forte 	bcopy(ucmdp->uscsi_cdb, pkt->pkt_cdbp, ucmdp->uscsi_cdblen);
2841fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.cmdlen	= ucmdp->uscsi_cdblen;
2842fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.statuslen	= rqlen;
2843fcf3ce44SJohn Forte 	icmdp->cmd_crc_error_seen	= B_FALSE;
2844fcf3ce44SJohn Forte 	icmdp->cmd_completed		= B_FALSE;
2845fcf3ce44SJohn Forte 	icmdp->cmd_result		= ISCSI_STATUS_SUCCESS;
2846fcf3ce44SJohn Forte 
2847fcf3ce44SJohn Forte 	/*
2848fcf3ce44SJohn Forte 	 * Step 2. Push IO onto pending queue.  If we aren't in
2849fcf3ce44SJohn Forte 	 * FULL_FEATURE we need to fail the IO.
2850fcf3ce44SJohn Forte 	 */
2851fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_state_mutex);
2852fcf3ce44SJohn Forte 	if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) {
2853fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
2854fcf3ce44SJohn Forte 
2855fcf3ce44SJohn Forte 		iscsi_cmd_free(icmdp);
2856fcf3ce44SJohn Forte 		kmem_free(pkt->pkt_cdbp, ucmdp->uscsi_cdblen);
2857fcf3ce44SJohn Forte 		kmem_free(pkt->pkt_scbp, rqlen);
2858fcf3ce44SJohn Forte 		kmem_free(pkt, sizeof (struct scsi_pkt));
2859fcf3ce44SJohn Forte 		kmem_free(bp, sizeof (struct buf));
2860fcf3ce44SJohn Forte 
2861fcf3ce44SJohn Forte 		return (ISCSI_STATUS_CMD_FAILED);
2862fcf3ce44SJohn Forte 	}
2863fcf3ce44SJohn Forte 
2864fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
2865fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
2866fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2867fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_state_mutex);
2868fcf3ce44SJohn Forte 
2869fcf3ce44SJohn Forte 	/*
2870fcf3ce44SJohn Forte 	 * Step 3. Wait on cv_wait for completion routine
2871fcf3ce44SJohn Forte 	 */
2872fcf3ce44SJohn Forte 	mutex_enter(&icmdp->cmd_mutex);
2873fcf3ce44SJohn Forte 	while (icmdp->cmd_completed == B_FALSE) {
2874fcf3ce44SJohn Forte 		cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
2875fcf3ce44SJohn Forte 	}
2876fcf3ce44SJohn Forte 	mutex_exit(&icmdp->cmd_mutex);
2877fcf3ce44SJohn Forte 
2878fcf3ce44SJohn Forte 	/* copy rval */
2879fcf3ce44SJohn Forte 	rval = icmdp->cmd_result;
2880fcf3ce44SJohn Forte 
2881fcf3ce44SJohn Forte 	ucmdp->uscsi_resid = pkt->pkt_resid;
2882fcf3ce44SJohn Forte 
2883fcf3ce44SJohn Forte 	/* update scsi status */
2884fcf3ce44SJohn Forte 	arqstat = (struct scsi_arq_status *)pkt->pkt_scbp;
2885fcf3ce44SJohn Forte 	ucmdp->uscsi_status = ((char *)&arqstat->sts_status)[0];
2886fcf3ce44SJohn Forte 
2887fcf3ce44SJohn Forte 	/* copy request sense buffers if caller gave space */
2888fcf3ce44SJohn Forte 	if ((ucmdp->uscsi_rqlen > 0) &&
2889fcf3ce44SJohn Forte 	    (ucmdp->uscsi_rqbuf != NULL)) {
2890fcf3ce44SJohn Forte 		bcopy(arqstat, ucmdp->uscsi_rqbuf,
2891fcf3ce44SJohn Forte 		    MIN(sizeof (struct scsi_arq_status), rqlen));
2892fcf3ce44SJohn Forte 	}
2893fcf3ce44SJohn Forte 
2894fcf3ce44SJohn Forte 	/* clean up */
2895fcf3ce44SJohn Forte 	iscsi_cmd_free(icmdp);
2896fcf3ce44SJohn Forte 	kmem_free(pkt->pkt_cdbp, ucmdp->uscsi_cdblen);
2897fcf3ce44SJohn Forte 	kmem_free(pkt->pkt_scbp, rqlen);
2898fcf3ce44SJohn Forte 	kmem_free(pkt, sizeof (struct scsi_pkt));
2899fcf3ce44SJohn Forte 	kmem_free(bp, sizeof (struct buf));
2900fcf3ce44SJohn Forte 
2901fcf3ce44SJohn Forte 	return (rval);
2902fcf3ce44SJohn Forte }
2903fcf3ce44SJohn Forte 
2904fcf3ce44SJohn Forte 
2905fcf3ce44SJohn Forte /*
2906fcf3ce44SJohn Forte  * iscsi_handle_passthru_callback -
2907fcf3ce44SJohn Forte  *
2908fcf3ce44SJohn Forte  */
2909fcf3ce44SJohn Forte static void
2910fcf3ce44SJohn Forte iscsi_handle_passthru_callback(struct scsi_pkt *pkt)
2911fcf3ce44SJohn Forte {
2912fcf3ce44SJohn Forte 	iscsi_cmd_t		*icmdp  = NULL;
2913fcf3ce44SJohn Forte 
2914fcf3ce44SJohn Forte 	ASSERT(pkt != NULL);
2915fcf3ce44SJohn Forte 	icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private;
2916fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2917fcf3ce44SJohn Forte 
2918fcf3ce44SJohn Forte 	mutex_enter(&icmdp->cmd_mutex);
2919fcf3ce44SJohn Forte 	icmdp->cmd_completed    = B_TRUE;
2920fcf3ce44SJohn Forte 	icmdp->cmd_result	= ISCSI_STATUS_SUCCESS;
2921fcf3ce44SJohn Forte 	cv_broadcast(&icmdp->cmd_completion);
2922fcf3ce44SJohn Forte 	mutex_exit(&icmdp->cmd_mutex);
2923fcf3ce44SJohn Forte 
2924fcf3ce44SJohn Forte }
2925fcf3ce44SJohn Forte 
2926fcf3ce44SJohn Forte /*
2927fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
2928fcf3ce44SJohn Forte  * | Beginning of completion routines					|
2929fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
2930fcf3ce44SJohn Forte  */
2931fcf3ce44SJohn Forte 
2932fcf3ce44SJohn Forte /*
2933fcf3ce44SJohn Forte  * iscsi_ic_thread -
2934fcf3ce44SJohn Forte  */
2935fcf3ce44SJohn Forte void
2936fcf3ce44SJohn Forte iscsi_ic_thread(iscsi_thread_t *thread, void *arg)
2937fcf3ce44SJohn Forte {
2938fcf3ce44SJohn Forte 	iscsi_sess_t	*isp = (iscsi_sess_t *)arg;
2939fcf3ce44SJohn Forte 	int		ret;
2940fcf3ce44SJohn Forte 	iscsi_queue_t	q;
2941fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp;
2942fcf3ce44SJohn Forte 	iscsi_cmd_t	*next_icmdp;
2943fcf3ce44SJohn Forte 
2944fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2945fcf3ce44SJohn Forte 	ASSERT(thread != NULL);
2946fcf3ce44SJohn Forte 	ASSERT(thread->signature == SIG_ISCSI_THREAD);
2947fcf3ce44SJohn Forte 
2948fcf3ce44SJohn Forte 	for (;;) {
2949fcf3ce44SJohn Forte 
2950fcf3ce44SJohn Forte 		/*
2951fcf3ce44SJohn Forte 		 * We wait till iodone or somebody else wakes us up.
2952fcf3ce44SJohn Forte 		 */
2953fcf3ce44SJohn Forte 		ret = iscsi_thread_wait(thread, -1);
2954fcf3ce44SJohn Forte 
2955fcf3ce44SJohn Forte 		/*
2956fcf3ce44SJohn Forte 		 * The value should never be negative since we never timeout.
2957fcf3ce44SJohn Forte 		 */
2958fcf3ce44SJohn Forte 		ASSERT(ret >= 0);
2959fcf3ce44SJohn Forte 
2960fcf3ce44SJohn Forte 		q.count = 0;
2961fcf3ce44SJohn Forte 		q.head  = NULL;
2962fcf3ce44SJohn Forte 		q.tail  = NULL;
2963fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_queue_completion.mutex);
2964fcf3ce44SJohn Forte 		icmdp = isp->sess_queue_completion.head;
2965fcf3ce44SJohn Forte 		while (icmdp != NULL) {
2966fcf3ce44SJohn Forte 			next_icmdp = icmdp->cmd_next;
2967fcf3ce44SJohn Forte 			mutex_enter(&icmdp->cmd_mutex);
2968fcf3ce44SJohn Forte 			/*
2969fcf3ce44SJohn Forte 			 * check if the associated r2t/abort has finished
2970e790cde8Sbing zhao - Sun Microsystems - Beijing China 			 * yet, and make sure this command has no R2T
2971e790cde8Sbing zhao - Sun Microsystems - Beijing China 			 * to handle. If not, don't complete this command.
2972fcf3ce44SJohn Forte 			 */
2973fcf3ce44SJohn Forte 			if ((icmdp->cmd_un.scsi.r2t_icmdp == NULL) &&
2974e790cde8Sbing zhao - Sun Microsystems - Beijing China 			    (icmdp->cmd_un.scsi.abort_icmdp == NULL) &&
2975e790cde8Sbing zhao - Sun Microsystems - Beijing China 			    (icmdp->cmd_un.scsi.r2t_more == B_FALSE)) {
2976fcf3ce44SJohn Forte 				mutex_exit(&icmdp->cmd_mutex);
2977fcf3ce44SJohn Forte 				(void) iscsi_dequeue_cmd(&isp->
2978fcf3ce44SJohn Forte 				    sess_queue_completion.head,
2979fcf3ce44SJohn Forte 				    &isp->sess_queue_completion.tail,
2980fcf3ce44SJohn Forte 				    icmdp);
2981fcf3ce44SJohn Forte 				--isp->sess_queue_completion.count;
2982fcf3ce44SJohn Forte 				iscsi_enqueue_cmd_head(&q.head,
2983fcf3ce44SJohn Forte 				    &q.tail, icmdp);
2984fcf3ce44SJohn Forte 			} else
2985fcf3ce44SJohn Forte 				mutex_exit(&icmdp->cmd_mutex);
2986fcf3ce44SJohn Forte 			icmdp = next_icmdp;
2987fcf3ce44SJohn Forte 		}
2988fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_queue_completion.mutex);
2989fcf3ce44SJohn Forte 		icmdp = q.head;
2990fcf3ce44SJohn Forte 		while (icmdp != NULL) {
2991fcf3ce44SJohn Forte 			next_icmdp = icmdp->cmd_next;
2992fcf3ce44SJohn Forte 			iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E8, isp);
2993fcf3ce44SJohn Forte 			icmdp = next_icmdp;
2994fcf3ce44SJohn Forte 		}
2995fcf3ce44SJohn Forte 
2996fcf3ce44SJohn Forte 		if (ret > 0)
2997fcf3ce44SJohn Forte 			/* Somebody woke us up to work */
2998fcf3ce44SJohn Forte 			continue;
2999fcf3ce44SJohn Forte 		else
3000fcf3ce44SJohn Forte 			/*
3001fcf3ce44SJohn Forte 			 * Somebody woke us up to kill ourselves. We will
3002fcf3ce44SJohn Forte 			 * make sure, however that the completion queue is
3003fcf3ce44SJohn Forte 			 * empty before leaving.  After we've done that it
3004fcf3ce44SJohn Forte 			 * is the originator of the signal that has to make
3005fcf3ce44SJohn Forte 			 * sure no other SCSI command is posted.
3006fcf3ce44SJohn Forte 			 */
3007fcf3ce44SJohn Forte 			break;
3008fcf3ce44SJohn Forte 	}
3009fcf3ce44SJohn Forte 
3010fcf3ce44SJohn Forte }
3011fcf3ce44SJohn Forte 
3012fcf3ce44SJohn Forte /*
3013fcf3ce44SJohn Forte  * iscsi_iodone -
3014fcf3ce44SJohn Forte  *
3015fcf3ce44SJohn Forte  */
3016fcf3ce44SJohn Forte void
3017fcf3ce44SJohn Forte iscsi_iodone(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
3018fcf3ce44SJohn Forte {
3019fcf3ce44SJohn Forte 	struct scsi_pkt		*pkt	= NULL;
3020fcf3ce44SJohn Forte 	struct buf		*bp	= icmdp->cmd_un.scsi.bp;
3021fcf3ce44SJohn Forte 
3022fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
3023fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
3024fcf3ce44SJohn Forte 	pkt = icmdp->cmd_un.scsi.pkt;
3025fcf3ce44SJohn Forte 	ASSERT(pkt != NULL);
3026fcf3ce44SJohn Forte 
3027fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL);
3028fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_un.scsi.r2t_icmdp == NULL);
3029fcf3ce44SJohn Forte 	if (pkt->pkt_reason == CMD_CMPLT) {
3030fcf3ce44SJohn Forte 		if (bp) {
3031fcf3ce44SJohn Forte 			if (bp->b_flags & B_READ) {
3032fcf3ce44SJohn Forte 				KSTAT_SESS_RX_IO_DONE(isp, bp->b_bcount);
3033fcf3ce44SJohn Forte 			} else {
3034fcf3ce44SJohn Forte 				KSTAT_SESS_TX_IO_DONE(isp, bp->b_bcount);
3035fcf3ce44SJohn Forte 			}
3036fcf3ce44SJohn Forte 		}
3037fcf3ce44SJohn Forte 	}
3038fcf3ce44SJohn Forte 
3039fcf3ce44SJohn Forte 	if (pkt->pkt_flags & FLAG_NOINTR) {
3040fcf3ce44SJohn Forte 		cv_broadcast(&icmdp->cmd_completion);
3041fcf3ce44SJohn Forte 		mutex_exit(&icmdp->cmd_mutex);
3042fcf3ce44SJohn Forte 	} else {
3043fcf3ce44SJohn Forte 		/*
3044fcf3ce44SJohn Forte 		 * Release mutex.  As soon as callback is
3045fcf3ce44SJohn Forte 		 * issued the caller may destroy the command.
3046fcf3ce44SJohn Forte 		 */
3047fcf3ce44SJohn Forte 		mutex_exit(&icmdp->cmd_mutex);
3048fcf3ce44SJohn Forte 		/*
3049fcf3ce44SJohn Forte 		 * We can't just directly call the pk_comp routine.  In
3050fcf3ce44SJohn Forte 		 * many error cases the target driver will use the calling
3051fcf3ce44SJohn Forte 		 * thread to re-drive error handling (reset, retries...)
3052fcf3ce44SJohn Forte 		 * back into the hba driver (iscsi).  If the target redrives
3053fcf3ce44SJohn Forte 		 * a reset back into the iscsi driver off this thead we have
3054fcf3ce44SJohn Forte 		 * a chance of deadlocking. So instead use the io completion
3055fcf3ce44SJohn Forte 		 * thread.
3056fcf3ce44SJohn Forte 		 */
3057fcf3ce44SJohn Forte 		(*icmdp->cmd_un.scsi.pkt->pkt_comp)(icmdp->cmd_un.scsi.pkt);
3058fcf3ce44SJohn Forte 	}
3059fcf3ce44SJohn Forte }
3060fcf3ce44SJohn Forte 
3061fcf3ce44SJohn Forte /*
3062fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3063fcf3ce44SJohn Forte  * | End of completion routines						|
3064fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3065fcf3ce44SJohn Forte  */
3066fcf3ce44SJohn Forte 
3067fcf3ce44SJohn Forte /*
3068fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3069fcf3ce44SJohn Forte  * | Beginning of watchdog routines					|
3070fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3071fcf3ce44SJohn Forte  */
3072fcf3ce44SJohn Forte 
3073fcf3ce44SJohn Forte /*
3074fcf3ce44SJohn Forte  * iscsi_watchdog_thread -
3075fcf3ce44SJohn Forte  *
3076fcf3ce44SJohn Forte  */
3077fcf3ce44SJohn Forte void
3078fcf3ce44SJohn Forte iscsi_wd_thread(iscsi_thread_t *thread, void *arg)
3079fcf3ce44SJohn Forte {
3080fcf3ce44SJohn Forte 	iscsi_sess_t	*isp = (iscsi_sess_t *)arg;
3081fcf3ce44SJohn Forte 	int		rc = 1;
3082fcf3ce44SJohn Forte 
3083fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
3084fcf3ce44SJohn Forte 
3085fcf3ce44SJohn Forte 	while (rc != NULL) {
3086fcf3ce44SJohn Forte 
3087fcf3ce44SJohn Forte 		iscsi_timeout_checks(isp);
3088fcf3ce44SJohn Forte 		iscsi_nop_checks(isp);
3089fcf3ce44SJohn Forte 
3090fcf3ce44SJohn Forte 		rc = iscsi_thread_wait(thread, SEC_TO_TICK(1));
3091fcf3ce44SJohn Forte 	}
3092fcf3ce44SJohn Forte }
3093fcf3ce44SJohn Forte 
3094fcf3ce44SJohn Forte /*
3095fcf3ce44SJohn Forte  * iscsi_timeout_checks -
3096fcf3ce44SJohn Forte  *
3097fcf3ce44SJohn Forte  */
3098fcf3ce44SJohn Forte static void
3099fcf3ce44SJohn Forte iscsi_timeout_checks(iscsi_sess_t *isp)
3100fcf3ce44SJohn Forte {
3101fcf3ce44SJohn Forte 	clock_t		now = ddi_get_lbolt();
3102fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp, *nicmdp;
3103fcf3ce44SJohn Forte 	iscsi_conn_t	*icp;
3104fcf3ce44SJohn Forte 
3105fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
3106fcf3ce44SJohn Forte 
3107fcf3ce44SJohn Forte 	/* PENDING */
3108fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_state_mutex);
3109fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
3110fcf3ce44SJohn Forte 	for (icmdp = isp->sess_queue_pending.head;
3111fcf3ce44SJohn Forte 	    icmdp; icmdp = nicmdp) {
3112fcf3ce44SJohn Forte 		nicmdp = icmdp->cmd_next;
3113fcf3ce44SJohn Forte 
3114fcf3ce44SJohn Forte 		/* Skip entries with no timeout */
3115fcf3ce44SJohn Forte 		if (icmdp->cmd_lbolt_timeout == 0)
3116fcf3ce44SJohn Forte 			continue;
3117fcf3ce44SJohn Forte 
3118fcf3ce44SJohn Forte 		/*
3119fcf3ce44SJohn Forte 		 * Skip pending queue entries for cmd_type values that depend
3120fcf3ce44SJohn Forte 		 * on having an open cmdsn window for successfull transition
3121fcf3ce44SJohn Forte 		 * from pending to the active (i.e. ones that depend on
3122fcf3ce44SJohn Forte 		 * sess_cmdsn .vs. sess_maxcmdsn). For them, the timer starts
3123fcf3ce44SJohn Forte 		 * when they are successfully moved to the active queue by
3124fcf3ce44SJohn Forte 		 * iscsi_cmd_state_pending() code.
3125fcf3ce44SJohn Forte 		 */
3126d233de7eSJack Meng 		/*
3127d233de7eSJack Meng 		 * If the cmd is stuck, at least give it a chance
3128d233de7eSJack Meng 		 * to timeout
3129d233de7eSJack Meng 		 */
3130d233de7eSJack Meng 		if (((icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) ||
3131d233de7eSJack Meng 		    (icmdp->cmd_type == ISCSI_CMD_TYPE_TEXT)) &&
3132d233de7eSJack Meng 		    !(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_STUCK))
3133fcf3ce44SJohn Forte 			continue;
3134fcf3ce44SJohn Forte 
3135fcf3ce44SJohn Forte 		/* Skip if timeout still in the future */
3136fcf3ce44SJohn Forte 		if (now <= icmdp->cmd_lbolt_timeout)
3137fcf3ce44SJohn Forte 			continue;
3138fcf3ce44SJohn Forte 
3139fcf3ce44SJohn Forte 		/* timeout */
3140fcf3ce44SJohn Forte 		iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E6, isp);
3141fcf3ce44SJohn Forte 	}
3142fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
3143fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_state_mutex);
3144fcf3ce44SJohn Forte 
3145fcf3ce44SJohn Forte 	rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
3146fcf3ce44SJohn Forte 	icp = isp->sess_conn_list;
3147fcf3ce44SJohn Forte 	while (icp != NULL) {
3148fcf3ce44SJohn Forte 
3149fcf3ce44SJohn Forte 		/* ACTIVE */
3150fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
3151fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_queue_pending.mutex);
3152fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_queue_active.mutex);
3153fcf3ce44SJohn Forte 		for (icmdp = icp->conn_queue_active.head;
3154fcf3ce44SJohn Forte 		    icmdp; icmdp = nicmdp) {
3155fcf3ce44SJohn Forte 			nicmdp = icmdp->cmd_next;
3156fcf3ce44SJohn Forte 
3157fcf3ce44SJohn Forte 			/* Skip entries with no timeout */
3158fcf3ce44SJohn Forte 			if (icmdp->cmd_lbolt_timeout == 0)
3159fcf3ce44SJohn Forte 				continue;
3160fcf3ce44SJohn Forte 
3161fcf3ce44SJohn Forte 			/* Skip if command is not active */
3162fcf3ce44SJohn Forte 			if (icmdp->cmd_state != ISCSI_CMD_STATE_ACTIVE)
3163fcf3ce44SJohn Forte 				continue;
3164fcf3ce44SJohn Forte 
3165fcf3ce44SJohn Forte 			/* Skip if timeout still in the future */
3166fcf3ce44SJohn Forte 			if (now <= icmdp->cmd_lbolt_timeout)
3167fcf3ce44SJohn Forte 				continue;
3168fcf3ce44SJohn Forte 
3169fcf3ce44SJohn Forte 			/* timeout */
3170fcf3ce44SJohn Forte 			iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E6, isp);
3171fcf3ce44SJohn Forte 		}
3172fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
3173fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_queue_pending.mutex);
3174fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
3175fcf3ce44SJohn Forte 
3176fcf3ce44SJohn Forte 		icp = icp->conn_next;
3177fcf3ce44SJohn Forte 	}
3178fcf3ce44SJohn Forte 	rw_exit(&isp->sess_conn_list_rwlock);
3179fcf3ce44SJohn Forte }
3180fcf3ce44SJohn Forte 
3181fcf3ce44SJohn Forte /*
3182fcf3ce44SJohn Forte  * iscsi_nop_checks - sends a NOP on idle connections
3183fcf3ce44SJohn Forte  *
3184fcf3ce44SJohn Forte  * This function walks the connections on a session and
3185fcf3ce44SJohn Forte  * issues NOPs on those connections that are in FULL
3186fcf3ce44SJohn Forte  * FEATURE mode and have not received data for the
3187fcf3ce44SJohn Forte  * time period specified by iscsi_nop_delay (global).
3188fcf3ce44SJohn Forte  */
3189fcf3ce44SJohn Forte static void
3190fcf3ce44SJohn Forte iscsi_nop_checks(iscsi_sess_t *isp)
3191fcf3ce44SJohn Forte {
3192fcf3ce44SJohn Forte 	iscsi_conn_t	*icp;
3193fcf3ce44SJohn Forte 
3194fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
3195fcf3ce44SJohn Forte 
3196fcf3ce44SJohn Forte 	if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) {
3197fcf3ce44SJohn Forte 		return;
3198fcf3ce44SJohn Forte 	}
3199fcf3ce44SJohn Forte 
3200fcf3ce44SJohn Forte 	rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
3201fcf3ce44SJohn Forte 	icp = isp->sess_conn_act;
3202fcf3ce44SJohn Forte 	if (icp != NULL) {
3203fcf3ce44SJohn Forte 
3204fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
3205fcf3ce44SJohn Forte 		if ((ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state)) &&
3206fcf3ce44SJohn Forte 		    (ddi_get_lbolt() > isp->sess_conn_act->conn_rx_lbolt +
3207fcf3ce44SJohn Forte 		    SEC_TO_TICK(iscsi_nop_delay)) && (ddi_get_lbolt() >
3208fcf3ce44SJohn Forte 		    isp->sess_conn_act->conn_nop_lbolt +
3209fcf3ce44SJohn Forte 		    SEC_TO_TICK(iscsi_nop_delay))) {
3210fcf3ce44SJohn Forte 
3211fcf3ce44SJohn Forte 			/*
3212fcf3ce44SJohn Forte 			 * We haven't received anything from the
3213fcf3ce44SJohn Forte 			 * target is a defined period of time,
3214fcf3ce44SJohn Forte 			 * send NOP to see if the target is alive.
3215fcf3ce44SJohn Forte 			 */
3216fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_queue_pending.mutex);
3217fcf3ce44SJohn Forte 			iscsi_handle_nop(isp->sess_conn_act,
3218fcf3ce44SJohn Forte 			    0, ISCSI_RSVD_TASK_TAG);
3219fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_queue_pending.mutex);
3220fcf3ce44SJohn Forte 		}
3221fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
3222fcf3ce44SJohn Forte 
3223fcf3ce44SJohn Forte 		icp = icp->conn_next;
3224fcf3ce44SJohn Forte 	}
3225fcf3ce44SJohn Forte 	rw_exit(&isp->sess_conn_list_rwlock);
3226fcf3ce44SJohn Forte }
3227fcf3ce44SJohn Forte 
3228fcf3ce44SJohn Forte /*
3229fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3230fcf3ce44SJohn Forte  * | End of wd routines						|
3231fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3232fcf3ce44SJohn Forte  */
3233