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.
231a1a84a3SPeter 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() */
362b79d384Sbing zhao - Sun Microsystems - Beijing China #include <sys/scsi/generic/sense.h>
37fcf3ce44SJohn Forte 
38fcf3ce44SJohn Forte #include "iscsi.h"		/* iscsi driver */
391a1a84a3SPeter Dunlap #include <sys/iscsi_protocol.h>	/* iscsi protocol */
40fcf3ce44SJohn Forte 
4130e7468fSPeter Dunlap #define	ISCSI_INI_TASK_TTT	0xffffffff
42aff4bce5Syi zhang - Sun Microsystems - Beijing China #define	ISCSI_CONN_TIEMOUT_DETECT	20
4330e7468fSPeter Dunlap 
4430e7468fSPeter Dunlap boolean_t iscsi_io_logging = B_FALSE;
4530e7468fSPeter Dunlap 
4630e7468fSPeter Dunlap #define	ISCSI_CHECK_SCSI_READ(ICHK_CMD, ICHK_HDR, ICHK_LEN, ICHK_TYPE)	\
4730e7468fSPeter Dunlap 	if (idm_pattern_checking)  {					\
4830e7468fSPeter Dunlap 		struct scsi_pkt *pkt = (ICHK_CMD)->cmd_un.scsi.pkt;	\
4930e7468fSPeter Dunlap 		if (((ICHK_HDR)->response == 0) && 			\
5030e7468fSPeter Dunlap 		    ((ICHK_HDR)->cmd_status == 0) &&			\
5130e7468fSPeter Dunlap 		    ((pkt->pkt_cdbp[0] == SCMD_READ_G1) ||		\
5230e7468fSPeter Dunlap 		    (pkt->pkt_cdbp[0] == SCMD_READ_G4) || 		\
5330e7468fSPeter Dunlap 		    (pkt->pkt_cdbp[0] == SCMD_READ) || 			\
5430e7468fSPeter Dunlap 		    (pkt->pkt_cdbp[0] == SCMD_READ_G5))) {		\
5530e7468fSPeter Dunlap 			idm_buf_t *idb = (ICHK_CMD)->cmd_un.scsi.ibp_ibuf; \
5630e7468fSPeter Dunlap 			IDM_BUFPAT_CHECK(idb, ICHK_LEN, ICHK_TYPE); \
5730e7468fSPeter Dunlap 		}						\
5830e7468fSPeter Dunlap 	}
5930e7468fSPeter Dunlap 
60fcf3ce44SJohn Forte /* generic io helpers */
61fcf3ce44SJohn Forte static uint32_t n2h24(uchar_t *ptr);
62fcf3ce44SJohn Forte static int iscsi_sna_lt(uint32_t n1, uint32_t n2);
6330e7468fSPeter Dunlap void iscsi_update_flow_control(iscsi_sess_t *isp,
64fcf3ce44SJohn Forte     uint32_t max, uint32_t exp);
6530e7468fSPeter Dunlap static iscsi_status_t iscsi_rx_process_scsi_itt_to_icmdp(iscsi_sess_t *isp,
6630e7468fSPeter Dunlap     idm_conn_t *ic, iscsi_scsi_rsp_hdr_t *ihp, iscsi_cmd_t **icmdp);
67fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_itt_to_icmdp(iscsi_sess_t *isp,
68fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, iscsi_cmd_t **icmdp);
6930e7468fSPeter Dunlap static void iscsi_process_rsp_status(iscsi_sess_t *isp, iscsi_conn_t *icp,
7030e7468fSPeter Dunlap     idm_status_t status);
7130e7468fSPeter Dunlap static void iscsi_drop_conn_cleanup(iscsi_conn_t *icp);
72aff4bce5Syi zhang - Sun Microsystems - Beijing China static boolean_t iscsi_nop_timeout_checks(iscsi_cmd_t *icmdp);
7330e7468fSPeter Dunlap /* callbacks from idm */
7430e7468fSPeter Dunlap static idm_pdu_cb_t iscsi_tx_done;
7530e7468fSPeter Dunlap 
7630e7468fSPeter Dunlap /* receivers */
7730e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_nop(idm_conn_t *ic, idm_pdu_t *pdu);
7830e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_data_rsp(idm_conn_t *ic,
7930e7468fSPeter Dunlap     idm_pdu_t *pdu);
8030e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_cmd_rsp(idm_conn_t *ic, idm_pdu_t *pdu);
8130e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_reject_rsp(idm_conn_t *ic,
8230e7468fSPeter Dunlap     idm_pdu_t *pdu);
8330e7468fSPeter Dunlap 
8430e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_rejected_tsk_mgt(idm_conn_t *ic,
8530e7468fSPeter Dunlap     iscsi_hdr_t *old_ihp);
8630e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_task_mgt_rsp(idm_conn_t *ic,
8730e7468fSPeter Dunlap     idm_pdu_t *pdu);
8830e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_logout_rsp(idm_conn_t *ic,
8930e7468fSPeter Dunlap     idm_pdu_t *pdu);
9030e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_async_rsp(idm_conn_t *ic,
9130e7468fSPeter Dunlap     idm_pdu_t *pdu);
9230e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_text_rsp(idm_conn_t *ic,
9330e7468fSPeter Dunlap     idm_pdu_t *pdu);
94fcf3ce44SJohn Forte 
95fcf3ce44SJohn Forte /* senders */
96fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_scsi(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
97fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_nop(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
98fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_abort(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
99fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_reset(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
100fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_logout(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
101fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_text(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
102fcf3ce44SJohn Forte 
103fcf3ce44SJohn Forte 
104fcf3ce44SJohn Forte /* helpers */
10530e7468fSPeter Dunlap static void iscsi_logout_start(void *arg);
106fcf3ce44SJohn Forte static void iscsi_handle_passthru_callback(struct scsi_pkt *pkt);
107fcf3ce44SJohn Forte static void iscsi_handle_nop(iscsi_conn_t *icp, uint32_t itt, uint32_t ttt);
108fcf3ce44SJohn Forte 
109fcf3ce44SJohn Forte static void iscsi_timeout_checks(iscsi_sess_t *isp);
110fcf3ce44SJohn Forte static void iscsi_nop_checks(iscsi_sess_t *isp);
1112b79d384Sbing zhao - Sun Microsystems - Beijing China static boolean_t iscsi_decode_sense(uint8_t *sense_data);
1122b79d384Sbing zhao - Sun Microsystems - Beijing China static void iscsi_flush_cmd_after_reset(uint32_t cmd_sn, uint16_t lun_num,
1132b79d384Sbing zhao - Sun Microsystems - Beijing China     iscsi_conn_t *icp);
114fcf3ce44SJohn Forte 
115fcf3ce44SJohn Forte /*
116fcf3ce44SJohn Forte  * This file contains the main guts of the iSCSI protocol layer.
117fcf3ce44SJohn Forte  * It's broken into 5 sections; Basic helper functions, RX IO path,
118fcf3ce44SJohn Forte  * TX IO path, Completion (IC) IO path, and watchdog (WD) routines.
119fcf3ce44SJohn Forte  *
120fcf3ce44SJohn Forte  * The IO flow model is similiar to the below diagram.  The
121fcf3ce44SJohn Forte  * iscsi session, connection and command state machines are used
122fcf3ce44SJohn Forte  * to drive IO through this flow diagram.  Reference those files
123fcf3ce44SJohn Forte  * to get a detailed description of their respective state models
124fcf3ce44SJohn Forte  * prior to their xxx_state_machine_function().
125fcf3ce44SJohn Forte  *
126fcf3ce44SJohn Forte  * tran_start() -> CMD_E1     TX_THREAD                   RX_THREAD
127fcf3ce44SJohn Forte  *                   |            T                           T
128fcf3ce44SJohn Forte  *                   V            T                           T
129fcf3ce44SJohn Forte  *                PENDING_Q  --CMD_E2--> ACTIVE_Q -      --CMD_E3--+
130fcf3ce44SJohn Forte  *                                T                \ C        T    |
131fcf3ce44SJohn Forte  *                                T                 \M        T    |
132fcf3ce44SJohn Forte  *                                                   D        T    |
133fcf3ce44SJohn Forte  *                                       WD_THREAD TT|TT      T    |
134fcf3ce44SJohn Forte  *                                                  /E        T    |
135fcf3ce44SJohn Forte  *                                                 / 6        T    |
136fcf3ce44SJohn Forte  *                                     ABORTING_Q<-      --CMD_E3--+
137fcf3ce44SJohn Forte  *                                                            T    |
138fcf3ce44SJohn Forte  *                                T                           T    |
139fcf3ce44SJohn Forte  *                                T                                |
140fcf3ce44SJohn Forte  *               callback()  <--CMD_E#-- COMPLETION_Q <------------+
141fcf3ce44SJohn Forte  *                                T
142fcf3ce44SJohn Forte  *                                T
143fcf3ce44SJohn Forte  *                            IC_THREAD
144fcf3ce44SJohn Forte  *
145fcf3ce44SJohn Forte  * External and internal command are ran thru this same state
146fcf3ce44SJohn Forte  * machine.  All commands enter the state machine by receiving an
147fcf3ce44SJohn Forte  * ISCSI_CMD_EVENT_E1.  This event places the command into the
148fcf3ce44SJohn Forte  * PENDING_Q.  Next when resources are available the TX_THREAD
149fcf3ce44SJohn Forte  * issues a E2 event on the command.  This sends the command
150fcf3ce44SJohn Forte  * to the TCP stack and places the command on the ACTIVE_Q.  While
151fcf3ce44SJohn Forte  * on the PENDIING_Q and ACTIVE_Q, the command is monitored via the
152fcf3ce44SJohn Forte  * WD_THREAD to ensure the pkt_time has not elapsed.  If elapsed the
153fcf3ce44SJohn Forte  * command is issued an E6(timeout) event which moves either (if pending)
154fcf3ce44SJohn Forte  * completed the command or (if active) moves the command to the
155fcf3ce44SJohn Forte  * aborting queue and issues a SCSI TASK MANAGEMENT ABORT command
156fcf3ce44SJohn Forte  * to cancel the IO request.  If the original command is completed
157fcf3ce44SJohn Forte  * or the TASK MANAGEMENT command completes the command is moved
158fcf3ce44SJohn Forte  * to the COMPLETION_Q via a E3 event.  The IC_THREAD then processes
159fcf3ce44SJohn Forte  * the COMPLETION_Q and issues the scsi_pkt callback.  This
160fcf3ce44SJohn Forte  * callback can not be processed directly from the RX_THREAD
161fcf3ce44SJohn Forte  * because the callback might call back into the iscsi driver
162fcf3ce44SJohn Forte  * causing a deadlock condition.
163fcf3ce44SJohn Forte  *
164fcf3ce44SJohn Forte  * For more details on the complete CMD state machine reference
165fcf3ce44SJohn Forte  * the state machine diagram in iscsi_cmd.c.  The connection state
166fcf3ce44SJohn Forte  * machine is driven via IO events in this file.  Then session
167fcf3ce44SJohn Forte  * events are driven by the connection events.  For complete
168fcf3ce44SJohn Forte  * details on these state machines reference iscsi_sess.c and
169fcf3ce44SJohn Forte  * iscsi_conn.c
170fcf3ce44SJohn Forte  */
171fcf3ce44SJohn Forte 
172fcf3ce44SJohn Forte 
173fcf3ce44SJohn Forte /*
174fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
175fcf3ce44SJohn Forte  * | io helper routines							|
176fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
177fcf3ce44SJohn Forte  */
178fcf3ce44SJohn Forte 
179fcf3ce44SJohn Forte /*
180fcf3ce44SJohn Forte  * n2h24 - native to host 24 bit integer translation.
181fcf3ce44SJohn Forte  */
182fcf3ce44SJohn Forte static uint32_t
183fcf3ce44SJohn Forte n2h24(uchar_t *ptr)
184fcf3ce44SJohn Forte {
185fcf3ce44SJohn Forte 	uint32_t idx;
186fcf3ce44SJohn Forte 	bcopy(ptr, &idx, 3);
187fcf3ce44SJohn Forte 	return (ntohl(idx) >> 8);
188fcf3ce44SJohn Forte }
189fcf3ce44SJohn Forte 
190fcf3ce44SJohn Forte /*
191fcf3ce44SJohn Forte  * iscsi_sna_lt - Serial Number Arithmetic, 32 bits, less than, RFC1982
192fcf3ce44SJohn Forte  */
193fcf3ce44SJohn Forte static int
194fcf3ce44SJohn Forte iscsi_sna_lt(uint32_t n1, uint32_t n2)
195fcf3ce44SJohn Forte {
196fcf3ce44SJohn Forte 	return ((n1 != n2) &&
197fcf3ce44SJohn Forte 	    (((n1 < n2) && ((n2 - n1) < ISCSI_SNA32_CHECK)) ||
198fcf3ce44SJohn Forte 	    ((n1 > n2) && ((n1 - n2) > ISCSI_SNA32_CHECK))));
199fcf3ce44SJohn Forte }
200fcf3ce44SJohn Forte 
201fcf3ce44SJohn Forte /*
202fcf3ce44SJohn Forte  * iscsi_sna_lte - Serial Number Arithmetic, 32 bits, less than or equal,
203fcf3ce44SJohn Forte  * RFC1982
204fcf3ce44SJohn Forte  */
205fcf3ce44SJohn Forte int
206fcf3ce44SJohn Forte iscsi_sna_lte(uint32_t n1, uint32_t n2)
207fcf3ce44SJohn Forte {
208fcf3ce44SJohn Forte 	return ((n1 == n2) ||
209fcf3ce44SJohn Forte 	    (((n1 < n2) && ((n2 - n1) < ISCSI_SNA32_CHECK)) ||
210fcf3ce44SJohn Forte 	    ((n1 > n2) && ((n1 - n2) > ISCSI_SNA32_CHECK))));
211fcf3ce44SJohn Forte }
212fcf3ce44SJohn Forte 
213fcf3ce44SJohn Forte /*
214fcf3ce44SJohn Forte  * iscsi_update_flow_control - Update expcmdsn and maxcmdsn iSCSI
215fcf3ce44SJohn Forte  * flow control information for a session
216fcf3ce44SJohn Forte  */
21730e7468fSPeter Dunlap void
218fcf3ce44SJohn Forte iscsi_update_flow_control(iscsi_sess_t *isp, uint32_t max, uint32_t exp)
219fcf3ce44SJohn Forte {
220fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
221fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&isp->sess_cmdsn_mutex));
222fcf3ce44SJohn Forte 
223fcf3ce44SJohn Forte 	if (!iscsi_sna_lt(max, (exp - 1))) {
224fcf3ce44SJohn Forte 
225fcf3ce44SJohn Forte 		if (!iscsi_sna_lte(exp, isp->sess_expcmdsn)) {
226fcf3ce44SJohn Forte 			isp->sess_expcmdsn = exp;
227fcf3ce44SJohn Forte 		}
228fcf3ce44SJohn Forte 
229fcf3ce44SJohn Forte 		if (!iscsi_sna_lte(max, isp->sess_maxcmdsn)) {
230fcf3ce44SJohn Forte 			isp->sess_maxcmdsn = max;
231fcf3ce44SJohn Forte 			if (iscsi_sna_lte(isp->sess_cmdsn,
232fcf3ce44SJohn Forte 			    isp->sess_maxcmdsn)) {
233fcf3ce44SJohn Forte 				/*
234fcf3ce44SJohn Forte 				 * the window is open again - schedule
235fcf3ce44SJohn Forte 				 * to send any held tasks soon
236fcf3ce44SJohn Forte 				 */
237fcf3ce44SJohn Forte 				iscsi_sess_redrive_io(isp);
238fcf3ce44SJohn Forte 			}
239fcf3ce44SJohn Forte 		}
240fcf3ce44SJohn Forte 	}
241fcf3ce44SJohn Forte }
242fcf3ce44SJohn Forte 
243fcf3ce44SJohn Forte 
244fcf3ce44SJohn Forte /*
245fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
246fcf3ce44SJohn Forte  * | io receive and processing routines					|
247fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
248fcf3ce44SJohn Forte  */
249fcf3ce44SJohn Forte 
250fcf3ce44SJohn Forte /*
25130e7468fSPeter Dunlap  * iscsi_rx_scsi_rsp - called from idm
25230e7468fSPeter Dunlap  * For each opcode type fan out the processing.
253fcf3ce44SJohn Forte  */
254fcf3ce44SJohn Forte void
25530e7468fSPeter Dunlap iscsi_rx_scsi_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
256fcf3ce44SJohn Forte {
25730e7468fSPeter Dunlap 	iscsi_conn_t	*icp;
25830e7468fSPeter Dunlap 	iscsi_sess_t	*isp;
25930e7468fSPeter Dunlap 	iscsi_hdr_t	*ihp;
26030e7468fSPeter Dunlap 	idm_status_t	status;
261fcf3ce44SJohn Forte 
26230e7468fSPeter Dunlap 	ASSERT(ic != NULL);
26330e7468fSPeter Dunlap 	ASSERT(pdu != NULL);
26430e7468fSPeter Dunlap 	icp		= ic->ic_handle;
265fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
26630e7468fSPeter Dunlap 	ihp		= (iscsi_hdr_t *)pdu->isp_hdr;
267fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
26830e7468fSPeter Dunlap 	isp		= icp->conn_sess;
269fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
270fcf3ce44SJohn Forte 
27130e7468fSPeter Dunlap 	/* reset the session timer when we receive the response */
27230e7468fSPeter Dunlap 	isp->sess_rx_lbolt = icp->conn_rx_lbolt = ddi_get_lbolt();
273fcf3ce44SJohn Forte 
274fcf3ce44SJohn Forte 	/* fan out the hdr processing */
275fcf3ce44SJohn Forte 	switch (ihp->opcode & ISCSI_OPCODE_MASK) {
276fcf3ce44SJohn Forte 	case ISCSI_OP_SCSI_DATA_RSP:
27730e7468fSPeter Dunlap 		status = iscsi_rx_process_data_rsp(ic, pdu);
278fcf3ce44SJohn Forte 		break;
279fcf3ce44SJohn Forte 	case ISCSI_OP_SCSI_RSP:
28030e7468fSPeter Dunlap 		status = iscsi_rx_process_cmd_rsp(ic, pdu);
28130e7468fSPeter Dunlap 		idm_pdu_complete(pdu, status);
282fcf3ce44SJohn Forte 		break;
283fcf3ce44SJohn Forte 	default:
284fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
28530e7468fSPeter Dunlap 		    "received pdu with unsupported opcode 0x%02x",
286fcf3ce44SJohn Forte 		    icp->conn_oid, ihp->opcode);
28730e7468fSPeter Dunlap 		status = IDM_STATUS_PROTOCOL_ERROR;
288fcf3ce44SJohn Forte 	}
28930e7468fSPeter Dunlap 	iscsi_process_rsp_status(isp, icp, status);
290fcf3ce44SJohn Forte }
291fcf3ce44SJohn Forte 
29230e7468fSPeter Dunlap void
29330e7468fSPeter Dunlap iscsi_task_cleanup(int opcode, iscsi_cmd_t *icmdp)
294fcf3ce44SJohn Forte {
29530e7468fSPeter Dunlap 	struct buf 	*bp;
29630e7468fSPeter Dunlap 	idm_buf_t	*ibp, *obp;
29730e7468fSPeter Dunlap 	idm_task_t	*itp;
298fcf3ce44SJohn Forte 
29930e7468fSPeter Dunlap 	itp = icmdp->cmd_itp;
30030e7468fSPeter Dunlap 	ASSERT(itp != NULL);
30130e7468fSPeter Dunlap 	ASSERT((opcode == ISCSI_OP_SCSI_DATA_RSP) ||
30230e7468fSPeter Dunlap 	    (opcode == ISCSI_OP_SCSI_RSP));
303fcf3ce44SJohn Forte 
30430e7468fSPeter Dunlap 	bp = icmdp->cmd_un.scsi.bp;
30530e7468fSPeter Dunlap 	ibp = icmdp->cmd_un.scsi.ibp_ibuf;
30630e7468fSPeter Dunlap 	obp = icmdp->cmd_un.scsi.ibp_obuf;
30730e7468fSPeter Dunlap 	ISCSI_IO_LOG(CE_NOTE, "DEBUG: task_cleanup: itp: %p opcode: %d "
30830e7468fSPeter Dunlap 	    "icmdp: %p bp: %p ibp: %p", (void *)itp, opcode,
30930e7468fSPeter Dunlap 	    (void *)icmdp, (void *)bp, (void *)ibp);
31030e7468fSPeter Dunlap 	if (bp && bp->b_bcount) {
31130e7468fSPeter Dunlap 		if (ibp != NULL && bp->b_flags & B_READ) {
31230e7468fSPeter Dunlap 			idm_buf_unbind_in(itp, ibp);
31330e7468fSPeter Dunlap 			idm_buf_free(ibp);
31430e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.ibp_ibuf = NULL;
31530e7468fSPeter Dunlap 		} else if (obp != NULL && !(bp->b_flags & B_READ)) {
31630e7468fSPeter Dunlap 			idm_buf_unbind_out(itp, obp);
31730e7468fSPeter Dunlap 			idm_buf_free(obp);
31830e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.ibp_obuf = NULL;
319fcf3ce44SJohn Forte 		}
320fcf3ce44SJohn Forte 	}
321fcf3ce44SJohn Forte 
32230e7468fSPeter Dunlap 	idm_task_done(itp);
32330e7468fSPeter Dunlap }
32430e7468fSPeter Dunlap 
32530e7468fSPeter Dunlap idm_status_t
32630e7468fSPeter Dunlap iscsi_rx_chk(iscsi_conn_t *icp, iscsi_sess_t *isp,
32730e7468fSPeter Dunlap     iscsi_scsi_rsp_hdr_t *irhp, iscsi_cmd_t **icmdp)
32830e7468fSPeter Dunlap {
32930e7468fSPeter Dunlap 	iscsi_status_t rval;
33030e7468fSPeter Dunlap 
331fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
33230e7468fSPeter Dunlap 
33330e7468fSPeter Dunlap 	if (icp->conn_expstatsn == ntohl(irhp->statsn)) {
33430e7468fSPeter Dunlap 		icp->conn_expstatsn++;
33530e7468fSPeter Dunlap 	} else {
33630e7468fSPeter Dunlap 		cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - "
33730e7468fSPeter Dunlap 		    "received status out of order itt:0x%x statsn:0x%x "
33830e7468fSPeter Dunlap 		    "expstatsn:0x%x", icp->conn_oid, irhp->opcode,
33930e7468fSPeter Dunlap 		    irhp->itt, ntohl(irhp->statsn), icp->conn_expstatsn);
340fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_cmdsn_mutex);
34130e7468fSPeter Dunlap 		return (IDM_STATUS_PROTOCOL_ERROR);
34230e7468fSPeter Dunlap 	}
34330e7468fSPeter Dunlap 
34430e7468fSPeter Dunlap 	/* get icmdp so we can cleanup on error */
34530e7468fSPeter Dunlap 	if ((irhp->opcode == ISCSI_OP_SCSI_DATA_RSP) ||
34630e7468fSPeter Dunlap 	    (irhp->opcode == ISCSI_OP_SCSI_RSP)) {
34730e7468fSPeter Dunlap 		rval = iscsi_rx_process_scsi_itt_to_icmdp(isp, icp->conn_ic,
34830e7468fSPeter Dunlap 		    irhp, icmdp);
34930e7468fSPeter Dunlap 	} else {
35030e7468fSPeter Dunlap 		rval = iscsi_rx_process_itt_to_icmdp(isp,
35130e7468fSPeter Dunlap 		    (iscsi_hdr_t *)irhp, icmdp);
35230e7468fSPeter Dunlap 	}
35330e7468fSPeter Dunlap 
35430e7468fSPeter Dunlap 	if (!ISCSI_SUCCESS(rval)) {
35530e7468fSPeter Dunlap 		mutex_exit(&isp->sess_cmdsn_mutex);
35630e7468fSPeter Dunlap 		return (IDM_STATUS_PROTOCOL_ERROR);
357fcf3ce44SJohn Forte 	}
358fcf3ce44SJohn Forte 
359fcf3ce44SJohn Forte 	/* update expcmdsn and maxcmdsn */
36030e7468fSPeter Dunlap 	iscsi_update_flow_control(isp, ntohl(irhp->maxcmdsn),
36130e7468fSPeter Dunlap 	    ntohl(irhp->expcmdsn));
362fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
36330e7468fSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
36430e7468fSPeter Dunlap }
365fcf3ce44SJohn Forte 
36630e7468fSPeter Dunlap static void
36730e7468fSPeter Dunlap iscsi_cmd_rsp_chk(iscsi_cmd_t *icmdp, iscsi_scsi_rsp_hdr_t *issrhp)
36830e7468fSPeter Dunlap {
36930e7468fSPeter Dunlap 	struct scsi_pkt *pkt;
37030e7468fSPeter Dunlap 	size_t data_transferred;
371fcf3ce44SJohn Forte 
37230e7468fSPeter Dunlap 	pkt = icmdp->cmd_un.scsi.pkt;
37330e7468fSPeter Dunlap 	pkt->pkt_resid = 0;
37430e7468fSPeter Dunlap 	data_transferred = icmdp->cmd_un.scsi.data_transferred;
37530e7468fSPeter Dunlap 	/* Check the residual count */
37630e7468fSPeter Dunlap 	if ((icmdp->cmd_un.scsi.bp) &&
37730e7468fSPeter Dunlap 	    (data_transferred != icmdp->cmd_un.scsi.bp->b_bcount)) {
378fcf3ce44SJohn Forte 		/*
37930e7468fSPeter Dunlap 		 * We didn't xfer the expected amount of data -
38030e7468fSPeter Dunlap 		 * the residual_count in the header is only
38130e7468fSPeter Dunlap 		 * valid if the underflow flag is set.
382fcf3ce44SJohn Forte 		 */
38330e7468fSPeter Dunlap 		if (issrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
38430e7468fSPeter Dunlap 			pkt->pkt_resid = ntohl(issrhp->residual_count);
38530e7468fSPeter Dunlap 		} else {
38630e7468fSPeter Dunlap 			if (icmdp->cmd_un.scsi.bp->b_bcount >
38730e7468fSPeter Dunlap 			    data_transferred) {
38830e7468fSPeter Dunlap 				/*
38930e7468fSPeter Dunlap 				 * Some data fell on the floor
39030e7468fSPeter Dunlap 				 * somehow - probably a CRC error
39130e7468fSPeter Dunlap 				 */
39230e7468fSPeter Dunlap 				pkt->pkt_resid =
39330e7468fSPeter Dunlap 				    icmdp->cmd_un.scsi.bp->b_bcount -
39430e7468fSPeter Dunlap 				    data_transferred;
39530e7468fSPeter Dunlap 			}
396fcf3ce44SJohn Forte 		}
39730e7468fSPeter Dunlap 		ISCSI_IO_LOG(CE_NOTE,
39830e7468fSPeter Dunlap 		    "DEBUG: iscsi_rx_cmd_rsp_chk: itt: %u"
39930e7468fSPeter Dunlap 		    "data_trans != b_count data_transferred: %lu "
40030e7468fSPeter Dunlap 		    "b_count: %lu cmd_status: %d flags: %d resid: %lu",
40130e7468fSPeter Dunlap 		    issrhp->itt, data_transferred,
40230e7468fSPeter Dunlap 		    icmdp->cmd_un.scsi.bp->b_bcount,
40330e7468fSPeter Dunlap 		    issrhp->cmd_status & STATUS_MASK,
40430e7468fSPeter Dunlap 		    issrhp->flags, pkt->pkt_resid);
40530e7468fSPeter Dunlap 	}
40630e7468fSPeter Dunlap 	/* set flags that tell SCSA that the command is complete */
40730e7468fSPeter Dunlap 	if (icmdp->cmd_crc_error_seen == B_FALSE) {
40830e7468fSPeter Dunlap 		/* Set successful completion */
40930e7468fSPeter Dunlap 		pkt->pkt_reason = CMD_CMPLT;
41030e7468fSPeter Dunlap 		if (icmdp->cmd_un.scsi.bp) {
41130e7468fSPeter Dunlap 			pkt->pkt_state |= (STATE_XFERRED_DATA |
41230e7468fSPeter Dunlap 			    STATE_GOT_STATUS);
41330e7468fSPeter Dunlap 		} else {
41430e7468fSPeter Dunlap 			pkt->pkt_state |= STATE_GOT_STATUS;
41530e7468fSPeter Dunlap 		}
41630e7468fSPeter Dunlap 	} else {
417fcf3ce44SJohn Forte 		/*
41830e7468fSPeter Dunlap 		 * Some of the data was found to have an incorrect
41930e7468fSPeter Dunlap 		 * error at the protocol error.
420fcf3ce44SJohn Forte 		 */
42130e7468fSPeter Dunlap 		pkt->pkt_reason = CMD_PER_FAIL;
42230e7468fSPeter Dunlap 		pkt->pkt_statistics |= STAT_PERR;
42330e7468fSPeter Dunlap 		if (icmdp->cmd_un.scsi.bp) {
42430e7468fSPeter Dunlap 			pkt->pkt_resid =
42530e7468fSPeter Dunlap 			    icmdp->cmd_un.scsi.bp->b_bcount;
426fcf3ce44SJohn Forte 		} else {
42730e7468fSPeter Dunlap 			pkt->pkt_resid = 0;
428fcf3ce44SJohn Forte 		}
429fcf3ce44SJohn Forte 	}
43030e7468fSPeter Dunlap }
43130e7468fSPeter Dunlap 
4322b79d384Sbing zhao - Sun Microsystems - Beijing China static boolean_t
43330e7468fSPeter Dunlap iscsi_cmd_rsp_cmd_status(iscsi_cmd_t *icmdp, iscsi_scsi_rsp_hdr_t *issrhp,
43430e7468fSPeter Dunlap     uint8_t *data)
43530e7468fSPeter Dunlap {
4365279807dSJack Meng 	int32_t			dlength		= 0;
43730e7468fSPeter Dunlap 	struct scsi_arq_status	*arqstat	= NULL;
43830e7468fSPeter Dunlap 	size_t			senselen	= 0;
4395279807dSJack Meng 	int32_t			statuslen	= 0;
4405279807dSJack Meng 	int32_t			senselen_to	= 0;
44130e7468fSPeter Dunlap 	struct scsi_pkt		*pkt;
4422b79d384Sbing zhao - Sun Microsystems - Beijing China 	boolean_t		affect		= B_FALSE;
44330e7468fSPeter Dunlap 
44430e7468fSPeter Dunlap 	pkt = icmdp->cmd_un.scsi.pkt;
44530e7468fSPeter Dunlap 	dlength = n2h24(issrhp->dlength);
446fcf3ce44SJohn Forte 
447fcf3ce44SJohn Forte 	/*
44830e7468fSPeter Dunlap 	 * Process iSCSI Cmd Response Status
44930e7468fSPeter Dunlap 	 * RFC 3720 Sectionn 10.4.2.
450fcf3ce44SJohn Forte 	 */
45130e7468fSPeter Dunlap 	switch (issrhp->cmd_status & STATUS_MASK) {
45230e7468fSPeter Dunlap 	case STATUS_GOOD:
45330e7468fSPeter Dunlap 		/* pass SCSI status up stack */
45430e7468fSPeter Dunlap 		if (pkt->pkt_scbp) {
45530e7468fSPeter Dunlap 			pkt->pkt_scbp[0] = issrhp->cmd_status;
45630e7468fSPeter Dunlap 		}
45730e7468fSPeter Dunlap 		break;
45830e7468fSPeter Dunlap 	case STATUS_CHECK:
45930e7468fSPeter Dunlap 		/*
46030e7468fSPeter Dunlap 		 * Verify we received a sense buffer and
46130e7468fSPeter Dunlap 		 * that there is the correct amount of
46230e7468fSPeter Dunlap 		 * request sense space to copy it to.
46330e7468fSPeter Dunlap 		 */
46430e7468fSPeter Dunlap 		if ((dlength > 1) &&
46530e7468fSPeter Dunlap 		    (pkt->pkt_scbp != NULL) &&
46630e7468fSPeter Dunlap 		    (icmdp->cmd_un.scsi.statuslen >=
46730e7468fSPeter Dunlap 		    sizeof (struct scsi_arq_status))) {
468fcf3ce44SJohn Forte 			/*
46930e7468fSPeter Dunlap 			 * If a bad command status is received we
47030e7468fSPeter Dunlap 			 * need to reset the pkt_resid to zero.
47130e7468fSPeter Dunlap 			 * The target driver compares its value
47230e7468fSPeter Dunlap 			 * before checking other error flags.
47330e7468fSPeter Dunlap 			 * (ex. check conditions)
474fcf3ce44SJohn Forte 			 */
47530e7468fSPeter Dunlap 			pkt->pkt_resid = 0;
47630e7468fSPeter Dunlap 
47730e7468fSPeter Dunlap 			/* get sense length from first 2 bytes */
47830e7468fSPeter Dunlap 			senselen = ((data[0] << 8) | data[1]) &
47930e7468fSPeter Dunlap 			    (size_t)0xFFFF;
48030e7468fSPeter Dunlap 			ISCSI_IO_LOG(CE_NOTE,
48130e7468fSPeter Dunlap 			    "DEBUG: iscsi_rx_cmd_rsp_cmd_status status_check: "
48230e7468fSPeter Dunlap 			    "dlen: %d scbp: %p statuslen: %d arq: %d senselen:"
48330e7468fSPeter Dunlap 			    " %lu", dlength, (void *)pkt->pkt_scbp,
48430e7468fSPeter Dunlap 			    icmdp->cmd_un.scsi.statuslen,
48530e7468fSPeter Dunlap 			    (int)sizeof (struct scsi_arq_status),
48630e7468fSPeter Dunlap 			    senselen);
48730e7468fSPeter Dunlap 
48830e7468fSPeter Dunlap 			/* Sanity-check on the sense length */
48930e7468fSPeter Dunlap 			if ((senselen + 2) > dlength) {
49030e7468fSPeter Dunlap 				senselen = dlength - 2;
491fcf3ce44SJohn Forte 			}
492fcf3ce44SJohn Forte 
49330e7468fSPeter Dunlap 			/*
49430e7468fSPeter Dunlap 			 * If there was a Data Digest error then
49530e7468fSPeter Dunlap 			 * the sense data cannot be trusted.
49630e7468fSPeter Dunlap 			 */
49730e7468fSPeter Dunlap 			if (icmdp->cmd_crc_error_seen) {
49830e7468fSPeter Dunlap 				senselen = 0;
49930e7468fSPeter Dunlap 			}
500fcf3ce44SJohn Forte 
50130e7468fSPeter Dunlap 			/* automatic request sense */
50230e7468fSPeter Dunlap 			arqstat =
50330e7468fSPeter Dunlap 			    (struct scsi_arq_status *)pkt->pkt_scbp;
50430e7468fSPeter Dunlap 
50530e7468fSPeter Dunlap 			/* pass SCSI status up stack */
50630e7468fSPeter Dunlap 			*((uchar_t *)&arqstat->sts_status) =
50730e7468fSPeter Dunlap 			    issrhp->cmd_status;
508fcf3ce44SJohn Forte 
509fcf3ce44SJohn Forte 			/*
51030e7468fSPeter Dunlap 			 * Set the status for the automatic
51130e7468fSPeter Dunlap 			 * request sense command
512fcf3ce44SJohn Forte 			 */
51330e7468fSPeter Dunlap 			arqstat->sts_rqpkt_state = (STATE_GOT_BUS |
51430e7468fSPeter Dunlap 			    STATE_GOT_TARGET | STATE_SENT_CMD |
51530e7468fSPeter Dunlap 			    STATE_XFERRED_DATA | STATE_GOT_STATUS |
51630e7468fSPeter Dunlap 			    STATE_ARQ_DONE);
517fcf3ce44SJohn Forte 
51830e7468fSPeter Dunlap 			*((uchar_t *)&arqstat->sts_rqpkt_status) =
51930e7468fSPeter Dunlap 			    STATUS_GOOD;
520fcf3ce44SJohn Forte 
52130e7468fSPeter Dunlap 			arqstat->sts_rqpkt_reason = CMD_CMPLT;
52230e7468fSPeter Dunlap 			statuslen = icmdp->cmd_un.scsi.statuslen;
523fcf3ce44SJohn Forte 
52430e7468fSPeter Dunlap 			if (senselen == 0) {
52530e7468fSPeter Dunlap 				/* auto request sense failed */
52630e7468fSPeter Dunlap 				arqstat->sts_rqpkt_status.sts_chk = 1;
52730e7468fSPeter Dunlap 				arqstat->sts_rqpkt_resid = statuslen;
52830e7468fSPeter Dunlap 			} else if (senselen < statuslen) {
52930e7468fSPeter Dunlap 				/* auto request sense short */
53030e7468fSPeter Dunlap 				arqstat->sts_rqpkt_resid = statuslen - senselen;
53130e7468fSPeter Dunlap 			} else {
53230e7468fSPeter Dunlap 				/* auto request sense complete */
53330e7468fSPeter Dunlap 				arqstat->sts_rqpkt_resid = 0;
53430e7468fSPeter Dunlap 			}
53530e7468fSPeter Dunlap 			arqstat->sts_rqpkt_statistics = 0;
53630e7468fSPeter Dunlap 			pkt->pkt_state |= STATE_ARQ_DONE;
537fcf3ce44SJohn Forte 
53830e7468fSPeter Dunlap 			if (icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_XARQ) {
53930e7468fSPeter Dunlap 				pkt->pkt_state |= STATE_XARQ_DONE;
54030e7468fSPeter Dunlap 			}
54130e7468fSPeter Dunlap 
5425279807dSJack Meng 			senselen_to =  pkt->pkt_scblen -
5435279807dSJack Meng 			    sizeof (struct scsi_arq_status) +
5445279807dSJack Meng 			    sizeof (struct scsi_extended_sense);
5455279807dSJack Meng 
54630e7468fSPeter Dunlap 			/* copy auto request sense */
5475279807dSJack Meng 			dlength = min(senselen, senselen_to);
5485279807dSJack Meng 			if (dlength > 0) {
54930e7468fSPeter Dunlap 				bcopy(&data[2], (uchar_t *)&arqstat->
55030e7468fSPeter Dunlap 				    sts_sensedata, dlength);
5512b79d384Sbing zhao - Sun Microsystems - Beijing China 
5522b79d384Sbing zhao - Sun Microsystems - Beijing China 				affect = iscsi_decode_sense(
5532b79d384Sbing zhao - Sun Microsystems - Beijing China 				    (uint8_t *)&arqstat->sts_sensedata);
55430e7468fSPeter Dunlap 			}
55530e7468fSPeter Dunlap 			break;
556fcf3ce44SJohn Forte 		}
55730e7468fSPeter Dunlap 		/* FALLTHRU */
55830e7468fSPeter Dunlap 	case STATUS_BUSY:
55930e7468fSPeter Dunlap 	case STATUS_RESERVATION_CONFLICT:
56030e7468fSPeter Dunlap 	case STATUS_QFULL:
56130e7468fSPeter Dunlap 	case STATUS_ACA_ACTIVE:
56230e7468fSPeter Dunlap 	default:
56330e7468fSPeter Dunlap 		/*
56430e7468fSPeter Dunlap 		 * If a bad command status is received we need to
56530e7468fSPeter Dunlap 		 * reset the pkt_resid to zero.  The target driver
56630e7468fSPeter Dunlap 		 * compares its value before checking other error
56730e7468fSPeter Dunlap 		 * flags. (ex. check conditions)
56830e7468fSPeter Dunlap 		 */
56930e7468fSPeter Dunlap 		ISCSI_IO_LOG(CE_NOTE,
57030e7468fSPeter Dunlap 		    "DEBUG: iscsi_rx_cmd_rsp_cmd_status: status: "
57130e7468fSPeter Dunlap 		    "%d cmd_status: %d dlen: %u scbp: %p statuslen: %d "
57230e7468fSPeter Dunlap 		    "arg_len: %d", issrhp->cmd_status & STATUS_MASK,
57330e7468fSPeter Dunlap 		    issrhp->cmd_status, dlength, (void *)pkt->pkt_scbp,
57430e7468fSPeter Dunlap 		    icmdp->cmd_un.scsi.statuslen,
57530e7468fSPeter Dunlap 		    (int)sizeof (struct scsi_arq_status));
57630e7468fSPeter Dunlap 		pkt->pkt_resid = 0;
57730e7468fSPeter Dunlap 		/* pass SCSI status up stack */
57830e7468fSPeter Dunlap 		if (pkt->pkt_scbp) {
57930e7468fSPeter Dunlap 			pkt->pkt_scbp[0] = issrhp->cmd_status;
58030e7468fSPeter Dunlap 		}
58130e7468fSPeter Dunlap 	}
5822b79d384Sbing zhao - Sun Microsystems - Beijing China 
5832b79d384Sbing zhao - Sun Microsystems - Beijing China 	return (affect);
58430e7468fSPeter Dunlap }
585fcf3ce44SJohn Forte 
58630e7468fSPeter Dunlap /*
58730e7468fSPeter Dunlap  * iscsi_rx_process_login_pdup - Process login response PDU.  This function
58830e7468fSPeter Dunlap  * copies the data into the connection context so that the login code can
58930e7468fSPeter Dunlap  * interpret it.
59030e7468fSPeter Dunlap  */
59130e7468fSPeter Dunlap 
59230e7468fSPeter Dunlap idm_status_t
59330e7468fSPeter Dunlap iscsi_rx_process_login_pdu(idm_conn_t *ic, idm_pdu_t *pdu)
59430e7468fSPeter Dunlap {
59530e7468fSPeter Dunlap 	iscsi_conn_t 		*icp;
59630e7468fSPeter Dunlap 
59730e7468fSPeter Dunlap 	icp = ic->ic_handle;
59830e7468fSPeter Dunlap 
59930e7468fSPeter Dunlap 	/*
60030e7468fSPeter Dunlap 	 * Copy header and data into connection structure so iscsi_login()
60130e7468fSPeter Dunlap 	 * can process it.
60230e7468fSPeter Dunlap 	 */
60330e7468fSPeter Dunlap 	mutex_enter(&icp->conn_login_mutex);
60430e7468fSPeter Dunlap 	/*
60530e7468fSPeter Dunlap 	 * If conn_login_state != LOGIN_TX then we are not ready to handle
60630e7468fSPeter Dunlap 	 * this login response and we should just  drop it.
60730e7468fSPeter Dunlap 	 */
60830e7468fSPeter Dunlap 	if (icp->conn_login_state == LOGIN_TX) {
60930e7468fSPeter Dunlap 		icp->conn_login_datalen = pdu->isp_datalen;
61030e7468fSPeter Dunlap 		bcopy(pdu->isp_hdr, &icp->conn_login_resp_hdr,
61130e7468fSPeter Dunlap 		    sizeof (iscsi_hdr_t));
61230e7468fSPeter Dunlap 		/*
61330e7468fSPeter Dunlap 		 * Login code is sloppy with it's NULL handling so make sure
61430e7468fSPeter Dunlap 		 * we don't leave any stale data in there.
61530e7468fSPeter Dunlap 		 */
61630e7468fSPeter Dunlap 		bzero(icp->conn_login_data, icp->conn_login_max_data_length);
61730e7468fSPeter Dunlap 		bcopy(pdu->isp_data, icp->conn_login_data,
61830e7468fSPeter Dunlap 		    MIN(pdu->isp_datalen, icp->conn_login_max_data_length));
61930e7468fSPeter Dunlap 		iscsi_login_update_state_locked(icp, LOGIN_RX);
620fcf3ce44SJohn Forte 	}
62130e7468fSPeter Dunlap 	mutex_exit(&icp->conn_login_mutex);
622fcf3ce44SJohn Forte 
62330e7468fSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
624fcf3ce44SJohn Forte }
625fcf3ce44SJohn Forte 
626fcf3ce44SJohn Forte /*
627fcf3ce44SJohn Forte  * iscsi_rx_process_cmd_rsp - Process received scsi command response.  This
628fcf3ce44SJohn Forte  * will contain sense data if the command was not successful.  This data needs
629fcf3ce44SJohn Forte  * to be copied into the scsi_pkt.  Otherwise we just complete the IO.
630fcf3ce44SJohn Forte  */
63130e7468fSPeter Dunlap static idm_status_t
63230e7468fSPeter Dunlap iscsi_rx_process_cmd_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
633fcf3ce44SJohn Forte {
63430e7468fSPeter Dunlap 	iscsi_conn_t		*icp	= ic->ic_handle;
63530e7468fSPeter Dunlap 	iscsi_sess_t		*isp	= icp->conn_sess;
63630e7468fSPeter Dunlap 	iscsi_scsi_rsp_hdr_t	*issrhp	= (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr;
63730e7468fSPeter Dunlap 	uint8_t			*data	= pdu->isp_data;
63830e7468fSPeter Dunlap 	iscsi_cmd_t		*icmdp	= NULL;
63930e7468fSPeter Dunlap 	struct scsi_pkt		*pkt	= NULL;
64030e7468fSPeter Dunlap 	idm_status_t		rval;
64130e7468fSPeter Dunlap 	struct buf		*bp;
6422b79d384Sbing zhao - Sun Microsystems - Beijing China 	boolean_t		flush	= B_FALSE;
6432b79d384Sbing zhao - Sun Microsystems - Beijing China 	uint32_t		cmd_sn	= 0;
6442b79d384Sbing zhao - Sun Microsystems - Beijing China 	uint16_t		lun_num = 0;
645fcf3ce44SJohn Forte 
646fcf3ce44SJohn Forte 	/* make sure we get status in order */
64730e7468fSPeter Dunlap 	mutex_enter(&icp->conn_queue_active.mutex);
64830e7468fSPeter Dunlap 
64930e7468fSPeter Dunlap 	if ((rval = iscsi_rx_chk(icp, isp, issrhp,
65030e7468fSPeter Dunlap 	    &icmdp)) != IDM_STATUS_SUCCESS) {
65130e7468fSPeter Dunlap 		if (icmdp != NULL) {
65230e7468fSPeter Dunlap 			iscsi_task_cleanup(issrhp->opcode, icmdp);
65330e7468fSPeter Dunlap 		}
65430e7468fSPeter Dunlap 		mutex_exit(&icp->conn_queue_active.mutex);
65530e7468fSPeter Dunlap 		return (rval);
656fcf3ce44SJohn Forte 	}
657fcf3ce44SJohn Forte 
65830e7468fSPeter Dunlap 	/*
65930e7468fSPeter Dunlap 	 * If we are in "idm aborting" state then we shouldn't continue
66030e7468fSPeter Dunlap 	 * to process this command.  By definition this command is no longer
66130e7468fSPeter Dunlap 	 * on the active queue so we shouldn't try to remove it either.
66230e7468fSPeter Dunlap 	 */
66330e7468fSPeter Dunlap 	mutex_enter(&icmdp->cmd_mutex);
66430e7468fSPeter Dunlap 	if (icmdp->cmd_state == ISCSI_CMD_STATE_IDM_ABORTING) {
66530e7468fSPeter Dunlap 		mutex_exit(&icmdp->cmd_mutex);
666fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
66730e7468fSPeter Dunlap 		return (IDM_STATUS_SUCCESS);
668fcf3ce44SJohn Forte 	}
66930e7468fSPeter Dunlap 	mutex_exit(&icmdp->cmd_mutex);
670fcf3ce44SJohn Forte 
67130e7468fSPeter Dunlap 	/* Get the IDM buffer and bytes transferred */
67230e7468fSPeter Dunlap 	bp = icmdp->cmd_un.scsi.bp;
67330e7468fSPeter Dunlap 	if (ic->ic_conn_flags & IDM_CONN_USE_SCOREBOARD) {
67430e7468fSPeter Dunlap 		/* Transport tracks bytes transferred so use those counts */
67530e7468fSPeter Dunlap 		if (bp && (bp->b_flags & B_READ)) {
67630e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.data_transferred +=
67730e7468fSPeter Dunlap 			    icmdp->cmd_itp->idt_rx_bytes;
67830e7468fSPeter Dunlap 		} else {
67930e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.data_transferred +=
68030e7468fSPeter Dunlap 			    icmdp->cmd_itp->idt_tx_bytes;
68130e7468fSPeter Dunlap 		}
68230e7468fSPeter Dunlap 	} else {
68330e7468fSPeter Dunlap 		/*
68430e7468fSPeter Dunlap 		 * Some transports cannot track the bytes transferred on
68530e7468fSPeter Dunlap 		 * the initiator side (like iSER) so we have to use the
68630e7468fSPeter Dunlap 		 * status info.  If the response field indicates that
68730e7468fSPeter Dunlap 		 * the command actually completed then we will assume
68830e7468fSPeter Dunlap 		 * the data_transferred value represents the entire buffer
68930e7468fSPeter Dunlap 		 * unless the resid field says otherwise.  This is a bit
69030e7468fSPeter Dunlap 		 * unintuitive but it's really impossible to know what
69130e7468fSPeter Dunlap 		 * has been transferred without detailed consideration
69230e7468fSPeter Dunlap 		 * of the SCSI status and sense key and that is outside
69330e7468fSPeter Dunlap 		 * the scope of the transport.  Instead the target/class driver
69430e7468fSPeter Dunlap 		 * can consider these values along with the resid and figure
69530e7468fSPeter Dunlap 		 * it out.  The data_transferred concept is just belt and
69630e7468fSPeter Dunlap 		 * suspenders anyway -- RFC 3720 actually explicitly rejects
69730e7468fSPeter Dunlap 		 * scoreboarding ("Initiators SHOULD NOT keep track of the
69830e7468fSPeter Dunlap 		 * data transferred to or from the target (scoreboarding)")
69930e7468fSPeter Dunlap 		 * perhaps for this very reason.
70030e7468fSPeter Dunlap 		 */
70130e7468fSPeter Dunlap 		if (issrhp->response != 0) {
70230e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.data_transferred = 0;
70330e7468fSPeter Dunlap 		} else {
70430e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.data_transferred =
70530e7468fSPeter Dunlap 			    (bp == NULL) ? 0 : bp->b_bcount;
70630e7468fSPeter Dunlap 			if (issrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
70730e7468fSPeter Dunlap 				icmdp->cmd_un.scsi.data_transferred -=
70830e7468fSPeter Dunlap 				    ntohl(issrhp->residual_count);
70930e7468fSPeter Dunlap 			}
71030e7468fSPeter Dunlap 		}
71130e7468fSPeter Dunlap 	}
712fcf3ce44SJohn Forte 
71330e7468fSPeter Dunlap 	ISCSI_CHECK_SCSI_READ(icmdp, issrhp,
71430e7468fSPeter Dunlap 	    icmdp->cmd_un.scsi.data_transferred,
71530e7468fSPeter Dunlap 	    BP_CHECK_THOROUGH);
71630e7468fSPeter Dunlap 
71730e7468fSPeter Dunlap 	ISCSI_IO_LOG(CE_NOTE, "DEBUG: rx_process_cmd_rsp: ic: %p pdu: %p itt:"
71830e7468fSPeter Dunlap 	    " %x expcmdsn: %x sess_cmd: %x sess_expcmdsn: %x data_transfered:"
71930e7468fSPeter Dunlap 	    " %lu ibp: %p obp: %p", (void *)ic, (void *)pdu, issrhp->itt,
72030e7468fSPeter Dunlap 	    issrhp->expcmdsn, isp->sess_cmdsn, isp->sess_expcmdsn,
72130e7468fSPeter Dunlap 	    icmdp->cmd_un.scsi.data_transferred,
72230e7468fSPeter Dunlap 	    (void *)icmdp->cmd_un.scsi.ibp_ibuf,
72330e7468fSPeter Dunlap 	    (void *)icmdp->cmd_un.scsi.ibp_obuf);
72430e7468fSPeter Dunlap 
72530e7468fSPeter Dunlap 	iscsi_task_cleanup(issrhp->opcode, icmdp);
726fcf3ce44SJohn Forte 
727fcf3ce44SJohn Forte 	if (issrhp->response) {
728fcf3ce44SJohn Forte 		/* The target failed the command. */
72930e7468fSPeter Dunlap 		ISCSI_IO_LOG(CE_NOTE, "DEBUG: rx_process_cmd_rsp: ic: %p pdu:"
73030e7468fSPeter Dunlap 		    " %p response: %d bcount: %lu", (void *)ic, (void *)pdu,
73130e7468fSPeter Dunlap 		    issrhp->response, icmdp->cmd_un.scsi.bp->b_bcount);
73230e7468fSPeter Dunlap 		pkt = icmdp->cmd_un.scsi.pkt;
733fcf3ce44SJohn Forte 		pkt->pkt_reason = CMD_TRAN_ERR;
734fcf3ce44SJohn Forte 		if (icmdp->cmd_un.scsi.bp) {
735fcf3ce44SJohn Forte 			pkt->pkt_resid = icmdp->cmd_un.scsi.bp->b_bcount;
736fcf3ce44SJohn Forte 		} else {
737fcf3ce44SJohn Forte 			pkt->pkt_resid = 0;
738fcf3ce44SJohn Forte 		}
739fcf3ce44SJohn Forte 	} else {
740fcf3ce44SJohn Forte 		/* success */
74130e7468fSPeter Dunlap 		iscsi_cmd_rsp_chk(icmdp, issrhp);
7422b79d384Sbing zhao - Sun Microsystems - Beijing China 		flush = iscsi_cmd_rsp_cmd_status(icmdp, issrhp, data);
7432b79d384Sbing zhao - Sun Microsystems - Beijing China 		if (flush == B_TRUE) {
7442b79d384Sbing zhao - Sun Microsystems - Beijing China 			cmd_sn = icmdp->cmd_sn;
7452b79d384Sbing zhao - Sun Microsystems - Beijing China 			ASSERT(icmdp->cmd_lun != NULL);
7462b79d384Sbing zhao - Sun Microsystems - Beijing China 			lun_num = icmdp->cmd_lun->lun_num;
7472b79d384Sbing zhao - Sun Microsystems - Beijing China 		}
74830e7468fSPeter Dunlap 	}
749fcf3ce44SJohn Forte 
75030e7468fSPeter Dunlap 	iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
7512b79d384Sbing zhao - Sun Microsystems - Beijing China 	if (flush == B_TRUE) {
7522b79d384Sbing zhao - Sun Microsystems - Beijing China 		iscsi_flush_cmd_after_reset(cmd_sn, lun_num, icp);
7532b79d384Sbing zhao - Sun Microsystems - Beijing China 	}
75430e7468fSPeter Dunlap 	mutex_exit(&icp->conn_queue_active.mutex);
75530e7468fSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
75630e7468fSPeter Dunlap }
757fcf3ce44SJohn Forte 
75830e7468fSPeter Dunlap static void
75930e7468fSPeter Dunlap iscsi_data_rsp_pkt(iscsi_cmd_t *icmdp, iscsi_data_rsp_hdr_t *idrhp)
76030e7468fSPeter Dunlap {
76130e7468fSPeter Dunlap 	struct buf		*bp	= NULL;
76230e7468fSPeter Dunlap 	size_t			data_transferred;
76330e7468fSPeter Dunlap 	struct scsi_pkt		*pkt;
764fcf3ce44SJohn Forte 
76530e7468fSPeter Dunlap 	bp = icmdp->cmd_un.scsi.bp;
76630e7468fSPeter Dunlap 	pkt = icmdp->cmd_un.scsi.pkt;
76730e7468fSPeter Dunlap 	data_transferred = icmdp->cmd_un.scsi.data_transferred;
76830e7468fSPeter Dunlap 	/*
76930e7468fSPeter Dunlap 	 * The command* must be completed now, since we won't get a command
77030e7468fSPeter Dunlap 	 * response PDU. The cmd_status and residual_count are
77130e7468fSPeter Dunlap 	 * not meaningful unless status_present is set.
77230e7468fSPeter Dunlap 	 */
77330e7468fSPeter Dunlap 	pkt->pkt_resid = 0;
77430e7468fSPeter Dunlap 	/* Check the residual count */
77530e7468fSPeter Dunlap 	if (bp && (data_transferred != bp->b_bcount)) {
776fcf3ce44SJohn Forte 		/*
77730e7468fSPeter Dunlap 		 * We didn't xfer the expected amount of data -
77830e7468fSPeter Dunlap 		 * the residual_count in the header is only valid
77930e7468fSPeter Dunlap 		 * if the underflow flag is set.
780fcf3ce44SJohn Forte 		 */
78130e7468fSPeter Dunlap 		if (idrhp->flags & ISCSI_FLAG_DATA_UNDERFLOW) {
78230e7468fSPeter Dunlap 			pkt->pkt_resid = ntohl(idrhp->residual_count);
78330e7468fSPeter Dunlap 			ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_data_rsp_pkt: "
78430e7468fSPeter Dunlap 			    "underflow: itt: %d "
78530e7468fSPeter Dunlap 			    "transferred: %lu count: %lu", idrhp->itt,
78630e7468fSPeter Dunlap 			    data_transferred, bp->b_bcount);
78730e7468fSPeter Dunlap 		} else {
78830e7468fSPeter Dunlap 			if (bp->b_bcount > data_transferred) {
78930e7468fSPeter Dunlap 				/* Some data fell on the floor somehw */
79030e7468fSPeter Dunlap 				ISCSI_IO_LOG(CE_NOTE, "DEBUG: "
79130e7468fSPeter Dunlap 				    "iscsi_data_rsp_pkt: data fell: itt: %d "
79230e7468fSPeter Dunlap 				    "transferred: %lu count: %lu", idrhp->itt,
79330e7468fSPeter Dunlap 				    data_transferred, bp->b_bcount);
79430e7468fSPeter Dunlap 				pkt->pkt_resid =
79530e7468fSPeter Dunlap 				    bp->b_bcount - data_transferred;
796fcf3ce44SJohn Forte 			}
79730e7468fSPeter Dunlap 		}
79830e7468fSPeter Dunlap 	}
799fcf3ce44SJohn Forte 
80030e7468fSPeter Dunlap 	pkt->pkt_reason = CMD_CMPLT;
80130e7468fSPeter Dunlap 	pkt->pkt_state |= (STATE_XFERRED_DATA | STATE_GOT_STATUS);
802fcf3ce44SJohn Forte 
80330e7468fSPeter Dunlap 	if (((idrhp->cmd_status & STATUS_MASK) != STATUS_GOOD) &&
80430e7468fSPeter Dunlap 	    (icmdp->cmd_un.scsi.statuslen >=
80530e7468fSPeter Dunlap 	    sizeof (struct scsi_arq_status)) && pkt->pkt_scbp) {
806fcf3ce44SJohn Forte 
80730e7468fSPeter Dunlap 		/*
80830e7468fSPeter Dunlap 		 * Not supposed to get exception status here!
80930e7468fSPeter Dunlap 		 * We have no request sense data so just do the
81030e7468fSPeter Dunlap 		 * best we can
81130e7468fSPeter Dunlap 		 */
81230e7468fSPeter Dunlap 		struct scsi_arq_status *arqstat =
81330e7468fSPeter Dunlap 		    (struct scsi_arq_status *)pkt->pkt_scbp;
814fcf3ce44SJohn Forte 
815fcf3ce44SJohn Forte 
81630e7468fSPeter Dunlap 		bzero(arqstat, sizeof (struct scsi_arq_status));
817fcf3ce44SJohn Forte 
81830e7468fSPeter Dunlap 		*((uchar_t *)&arqstat->sts_status) =
81930e7468fSPeter Dunlap 		    idrhp->cmd_status;
820fcf3ce44SJohn Forte 
82130e7468fSPeter Dunlap 		arqstat->sts_rqpkt_resid =
82230e7468fSPeter Dunlap 		    sizeof (struct scsi_extended_sense);
82330e7468fSPeter Dunlap 		ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_data_rsp_pkt: "
82430e7468fSPeter Dunlap 		    "exception status: itt: %d resid: %d",
82530e7468fSPeter Dunlap 		    idrhp->itt, arqstat->sts_rqpkt_resid);
826b4243054SSheng-Liang Eric Zhang 
82730e7468fSPeter Dunlap 	} else if (pkt->pkt_scbp) {
82830e7468fSPeter Dunlap 		/* just pass along the status we got */
82930e7468fSPeter Dunlap 		pkt->pkt_scbp[0] = idrhp->cmd_status;
830fcf3ce44SJohn Forte 	}
831fcf3ce44SJohn Forte }
832fcf3ce44SJohn Forte 
833fcf3ce44SJohn Forte /*
83430e7468fSPeter Dunlap  * iscsi_rx_process_data_rsp -
83530e7468fSPeter Dunlap  * This currently processes the final data sequence denoted by the data response
83630e7468fSPeter Dunlap  * PDU Status bit being set.  We will not receive the SCSI response.
83730e7468fSPeter Dunlap  * This bit denotes that the PDU is the successful completion of the
83830e7468fSPeter Dunlap  * command.
839fcf3ce44SJohn Forte  */
84030e7468fSPeter Dunlap static idm_status_t
84130e7468fSPeter Dunlap iscsi_rx_process_data_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
842fcf3ce44SJohn Forte {
84330e7468fSPeter Dunlap 	iscsi_sess_t		*isp	= NULL;
84430e7468fSPeter Dunlap 	iscsi_data_rsp_hdr_t	*idrhp	= (iscsi_data_rsp_hdr_t *)pdu->isp_hdr;
84530e7468fSPeter Dunlap 	iscsi_cmd_t		*icmdp	= NULL;
84630e7468fSPeter Dunlap 	struct buf		*bp	= NULL;
84730e7468fSPeter Dunlap 	iscsi_conn_t		*icp	= ic->ic_handle;
84830e7468fSPeter Dunlap 	idm_buf_t		*ibp;
84930e7468fSPeter Dunlap 	idm_status_t		rval;
850fcf3ce44SJohn Forte 
851fcf3ce44SJohn Forte 
85230e7468fSPeter Dunlap 	/* should only call this when the data rsp contains final rsp */
85330e7468fSPeter Dunlap 	ASSERT(idrhp->flags & ISCSI_FLAG_DATA_STATUS);
85430e7468fSPeter Dunlap 	isp = icp->conn_sess;
85530e7468fSPeter Dunlap 
856fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
85730e7468fSPeter Dunlap 	if ((rval = iscsi_rx_chk(icp, isp, (iscsi_scsi_rsp_hdr_t *)idrhp,
85830e7468fSPeter Dunlap 	    &icmdp)) != IDM_STATUS_SUCCESS) {
85930e7468fSPeter Dunlap 		if (icmdp != NULL) {
86030e7468fSPeter Dunlap 			iscsi_task_cleanup(idrhp->opcode, icmdp);
86130e7468fSPeter Dunlap 		}
862fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
86330e7468fSPeter Dunlap 		return (rval);
864fcf3ce44SJohn Forte 	}
865fcf3ce44SJohn Forte 
86630e7468fSPeter Dunlap 	/*
86730e7468fSPeter Dunlap 	 * If we are in "idm aborting" state then we shouldn't continue
86830e7468fSPeter Dunlap 	 * to process this command.  By definition this command is no longer
86930e7468fSPeter Dunlap 	 * on the active queue so we shouldn't try to remove it either.
87030e7468fSPeter Dunlap 	 */
871fcf3ce44SJohn Forte 	mutex_enter(&icmdp->cmd_mutex);
87230e7468fSPeter Dunlap 	if (icmdp->cmd_state == ISCSI_CMD_STATE_IDM_ABORTING) {
87330e7468fSPeter Dunlap 		mutex_exit(&icmdp->cmd_mutex);
87430e7468fSPeter Dunlap 		mutex_exit(&icp->conn_queue_active.mutex);
87530e7468fSPeter Dunlap 		return (IDM_STATUS_SUCCESS);
87630e7468fSPeter Dunlap 	}
87730e7468fSPeter Dunlap 	mutex_exit(&icmdp->cmd_mutex);
87830e7468fSPeter Dunlap 
87930e7468fSPeter Dunlap 	/*
88030e7468fSPeter Dunlap 	 * Holding the pending/active queue locks across the
88130e7468fSPeter Dunlap 	 * iscsi_rx_data call later in this function may cause
88230e7468fSPeter Dunlap 	 * deadlock during fault injections.  Instead remove
88330e7468fSPeter Dunlap 	 * the cmd from the active queue and release the locks.
88430e7468fSPeter Dunlap 	 * Then before returning or completing the command
88530e7468fSPeter Dunlap 	 * return the cmd to the active queue and reacquire
88630e7468fSPeter Dunlap 	 * the locks.
88730e7468fSPeter Dunlap 	 */
88830e7468fSPeter Dunlap 	iscsi_dequeue_active_cmd(icp, icmdp);
88930e7468fSPeter Dunlap 
89030e7468fSPeter Dunlap 	mutex_exit(&icp->conn_queue_active.mutex);
891fcf3ce44SJohn Forte 
89230e7468fSPeter Dunlap 	/* shorthand some values */
893fcf3ce44SJohn Forte 	bp = icmdp->cmd_un.scsi.bp;
894fcf3ce44SJohn Forte 
89530e7468fSPeter Dunlap 	/*
89630e7468fSPeter Dunlap 	 * some poorly behaved targets have been observed
89730e7468fSPeter Dunlap 	 * sending data-in pdu's during a write operation
89830e7468fSPeter Dunlap 	 */
89930e7468fSPeter Dunlap 	if (bp != NULL) {
90030e7468fSPeter Dunlap 		if (!(bp->b_flags & B_READ)) {
90130e7468fSPeter Dunlap 			cmn_err(CE_WARN,
90230e7468fSPeter Dunlap 			    "iscsi connection(%u) protocol error - "
90330e7468fSPeter Dunlap 			    "received data response during write operation "
90430e7468fSPeter Dunlap 			    "itt:0x%x",
90530e7468fSPeter Dunlap 			    icp->conn_oid, idrhp->itt);
90630e7468fSPeter Dunlap 			mutex_enter(&icp->conn_queue_active.mutex);
90730e7468fSPeter Dunlap 			iscsi_enqueue_active_cmd(icp, icmdp);
90830e7468fSPeter Dunlap 			mutex_exit(&icp->conn_queue_active.mutex);
90930e7468fSPeter Dunlap 			return (IDM_STATUS_PROTOCOL_ERROR);
91030e7468fSPeter Dunlap 		}
91130e7468fSPeter Dunlap 	}
91230e7468fSPeter Dunlap 
91330e7468fSPeter Dunlap 	ibp = icmdp->cmd_un.scsi.ibp_ibuf;
91430e7468fSPeter Dunlap 	if (ibp == NULL) {
91530e7468fSPeter Dunlap 		/*
91630e7468fSPeter Dunlap 		 * After the check of bp above we *should* have a corresponding
91730e7468fSPeter Dunlap 		 * idm_buf_t (ibp).  It's possible that the original call
91830e7468fSPeter Dunlap 		 * to idm_buf_alloc failed due to a pending connection state
91930e7468fSPeter Dunlap 		 * transition in which case this value can be NULL.  It's
92030e7468fSPeter Dunlap 		 * highly unlikely that the connection would be shutting down
92130e7468fSPeter Dunlap 		 * *and* we manage to process a data response and get to this
92230e7468fSPeter Dunlap 		 * point in the code but just in case we should check for it.
92330e7468fSPeter Dunlap 		 * This isn't really a protocol error -- we are almost certainly
92430e7468fSPeter Dunlap 		 * closing the connection anyway so just return a generic error.
92530e7468fSPeter Dunlap 		 */
92630e7468fSPeter Dunlap 		mutex_enter(&icp->conn_queue_active.mutex);
92730e7468fSPeter Dunlap 		iscsi_enqueue_active_cmd(icp, icmdp);
92830e7468fSPeter Dunlap 		mutex_exit(&icp->conn_queue_active.mutex);
92930e7468fSPeter Dunlap 		return (IDM_STATUS_FAIL);
93030e7468fSPeter Dunlap 	}
93130e7468fSPeter Dunlap 
93230e7468fSPeter Dunlap 	if (ic->ic_conn_flags & IDM_CONN_USE_SCOREBOARD) {
93330e7468fSPeter Dunlap 		icmdp->cmd_un.scsi.data_transferred =
93430e7468fSPeter Dunlap 		    icmdp->cmd_itp->idt_rx_bytes;
935fcf3ce44SJohn Forte 	} else {
93630e7468fSPeter Dunlap 		icmdp->cmd_un.scsi.data_transferred = bp->b_bcount;
93730e7468fSPeter Dunlap 		if (idrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
93830e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.data_transferred -=
93930e7468fSPeter Dunlap 			    ntohl(idrhp->residual_count);
94030e7468fSPeter Dunlap 		}
941fcf3ce44SJohn Forte 	}
942fcf3ce44SJohn Forte 
94330e7468fSPeter Dunlap 	ISCSI_IO_LOG(CE_NOTE, "DEBUG: rx_process_data_rsp: icp: %p pdu: %p "
94430e7468fSPeter Dunlap 	    "itt: %d ibp: %p icmdp: %p xfer_len: %lu transferred: %lu dlen: %u",
94530e7468fSPeter Dunlap 	    (void *)icp, (void *)pdu, idrhp->itt, (void *)bp, (void *)icmdp,
94630e7468fSPeter Dunlap 	    (ibp == NULL) ? 0 : ibp->idb_xfer_len,
94730e7468fSPeter Dunlap 	    icmdp->cmd_un.scsi.data_transferred,
94830e7468fSPeter Dunlap 	    n2h24(idrhp->dlength));
94930e7468fSPeter Dunlap 
95030e7468fSPeter Dunlap 	iscsi_task_cleanup(idrhp->opcode, icmdp);
95130e7468fSPeter Dunlap 
95230e7468fSPeter Dunlap 	iscsi_data_rsp_pkt(icmdp, idrhp);
95330e7468fSPeter Dunlap 
95430e7468fSPeter Dunlap 	mutex_enter(&icp->conn_queue_active.mutex);
95530e7468fSPeter Dunlap 	iscsi_enqueue_active_cmd(icp, icmdp);
95630e7468fSPeter Dunlap 	iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
957fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_queue_active.mutex);
958fcf3ce44SJohn Forte 
95930e7468fSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
960fcf3ce44SJohn Forte }
961fcf3ce44SJohn Forte 
962fcf3ce44SJohn Forte /*
963fcf3ce44SJohn Forte  * iscsi_rx_process_nop - Process a received nop.  If nop is in response
964fcf3ce44SJohn Forte  * to a ping we sent update stats.  If initiated by the target we need
965fcf3ce44SJohn Forte  * to response back to the target with a nop.  Schedule the response.
966fcf3ce44SJohn Forte  */
967fcf3ce44SJohn Forte /* ARGSUSED */
96830e7468fSPeter Dunlap static idm_status_t
96930e7468fSPeter Dunlap iscsi_rx_process_nop(idm_conn_t *ic, idm_pdu_t *pdu)
970fcf3ce44SJohn Forte {
971fcf3ce44SJohn Forte 	iscsi_sess_t		*isp	= NULL;
97230e7468fSPeter Dunlap 	iscsi_nop_in_hdr_t	*inihp	= (iscsi_nop_in_hdr_t *)pdu->isp_hdr;
973fcf3ce44SJohn Forte 	iscsi_cmd_t		*icmdp	= NULL;
97430e7468fSPeter Dunlap 	iscsi_conn_t		*icp	= ic->ic_handle;
975fcf3ce44SJohn Forte 
976fcf3ce44SJohn Forte 	if (icp->conn_expstatsn != ntohl(inihp->statsn)) {
97730e7468fSPeter Dunlap 		cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - "
978fcf3ce44SJohn Forte 		    "received status out of order itt:0x%x statsn:0x%x "
97930e7468fSPeter Dunlap 		    "expstatsn:0x%x", icp->conn_oid, inihp->opcode, inihp->itt,
980fcf3ce44SJohn Forte 		    ntohl(inihp->statsn), icp->conn_expstatsn);
98130e7468fSPeter Dunlap 		return (IDM_STATUS_PROTOCOL_ERROR);
982fcf3ce44SJohn Forte 	}
98330e7468fSPeter Dunlap 	isp = icp->conn_sess;
98430e7468fSPeter Dunlap 	ASSERT(isp != NULL);
985fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
986fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
987fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
988fcf3ce44SJohn Forte 	if (inihp->itt != ISCSI_RSVD_TASK_TAG) {
989fcf3ce44SJohn Forte 		if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(
99030e7468fSPeter Dunlap 		    isp, (iscsi_hdr_t *)inihp, &icmdp))) {
99130e7468fSPeter Dunlap 			cmn_err(CE_WARN, "iscsi connection(%u) protocol error "
99230e7468fSPeter Dunlap 			    "- can not find cmd for itt:0x%x",
99330e7468fSPeter Dunlap 			    icp->conn_oid, inihp->itt);
994fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
995fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_queue_active.mutex);
996fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_queue_pending.mutex);
99730e7468fSPeter Dunlap 			return (IDM_STATUS_PROTOCOL_ERROR);
998fcf3ce44SJohn Forte 		}
999fcf3ce44SJohn Forte 	}
1000fcf3ce44SJohn Forte 
1001fcf3ce44SJohn Forte 	/* update expcmdsn and maxcmdsn */
1002fcf3ce44SJohn Forte 	iscsi_update_flow_control(isp, ntohl(inihp->maxcmdsn),
1003fcf3ce44SJohn Forte 	    ntohl(inihp->expcmdsn));
1004fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
1005fcf3ce44SJohn Forte 
1006fcf3ce44SJohn Forte 	if ((inihp->itt != ISCSI_RSVD_TASK_TAG) &&
1007fcf3ce44SJohn Forte 	    (inihp->ttt == ISCSI_RSVD_TASK_TAG)) {
1008fcf3ce44SJohn Forte 		/* This is the only type of nop that incs. the expstatsn */
1009fcf3ce44SJohn Forte 		icp->conn_expstatsn++;
1010fcf3ce44SJohn Forte 
1011fcf3ce44SJohn Forte 		/*
1012fcf3ce44SJohn Forte 		 * This is a targets response to our nop
1013fcf3ce44SJohn Forte 		 */
1014fcf3ce44SJohn Forte 		iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
1015fcf3ce44SJohn Forte 	} else if (inihp->ttt != ISCSI_RSVD_TASK_TAG) {
1016fcf3ce44SJohn Forte 		/*
1017fcf3ce44SJohn Forte 		 * Target requested a nop.  Send one.
1018fcf3ce44SJohn Forte 		 */
1019fcf3ce44SJohn Forte 		iscsi_handle_nop(icp, ISCSI_RSVD_TASK_TAG, inihp->ttt);
1020fcf3ce44SJohn Forte 	} else {
1021fcf3ce44SJohn Forte 		/*
1022fcf3ce44SJohn Forte 		 * This is a target-initiated ping that doesn't expect
1023fcf3ce44SJohn Forte 		 * a response; nothing to do except update our flow control
1024fcf3ce44SJohn Forte 		 * (which we do in all cases above).
1025fcf3ce44SJohn Forte 		 */
1026fcf3ce44SJohn Forte 		/* EMPTY */
1027fcf3ce44SJohn Forte 	}
1028fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_queue_active.mutex);
1029fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
1030fcf3ce44SJohn Forte 
103130e7468fSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
1032fcf3ce44SJohn Forte }
1033fcf3ce44SJohn Forte 
1034fcf3ce44SJohn Forte 
1035fcf3ce44SJohn Forte /*
1036fcf3ce44SJohn Forte  * iscsi_rx_process_reject_rsp - The server rejected a PDU
1037fcf3ce44SJohn Forte  */
103830e7468fSPeter Dunlap static idm_status_t
103930e7468fSPeter Dunlap iscsi_rx_process_reject_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
1040fcf3ce44SJohn Forte {
104130e7468fSPeter Dunlap 	iscsi_reject_rsp_hdr_t	*irrhp = (iscsi_reject_rsp_hdr_t *)pdu->isp_hdr;
104230e7468fSPeter Dunlap 	iscsi_sess_t		*isp		= NULL;
104330e7468fSPeter Dunlap 	uint32_t		dlength		= 0;
104430e7468fSPeter Dunlap 	iscsi_hdr_t		*old_ihp	= NULL;
104530e7468fSPeter Dunlap 	iscsi_conn_t		*icp		= ic->ic_handle;
104630e7468fSPeter Dunlap 	uint8_t			*data 		= pdu->isp_data;
1047*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	idm_status_t		status		= IDM_STATUS_SUCCESS;
1048*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	int			i		= 0;
1049fcf3ce44SJohn Forte 
1050fcf3ce44SJohn Forte 	ASSERT(data != NULL);
105130e7468fSPeter Dunlap 	isp = icp->conn_sess;
105230e7468fSPeter Dunlap 	ASSERT(isp != NULL);
1053fcf3ce44SJohn Forte 
1054*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	/*
1055*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	 * In RFC3720 section 10.17, this 4 bytes should be all 0xff.
1056*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	 */
1057*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	for (i = 0; i < 4; i++) {
1058*aefdd131Sbing zhao - Sun Microsystems - Beijing China 		if (irrhp->must_be_ff[i] != 0xff) {
1059*aefdd131Sbing zhao - Sun Microsystems - Beijing China 			return (IDM_STATUS_PROTOCOL_ERROR);
1060*aefdd131Sbing zhao - Sun Microsystems - Beijing China 		}
1061*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	}
1062*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	mutex_enter(&isp->sess_cmdsn_mutex);
1063*aefdd131Sbing zhao - Sun Microsystems - Beijing China 
1064*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	if (icp->conn_expstatsn == ntohl(irrhp->statsn)) {
1065*aefdd131Sbing zhao - Sun Microsystems - Beijing China 		icp->conn_expstatsn++;
1066*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	} else {
1067*aefdd131Sbing zhao - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - "
1068*aefdd131Sbing zhao - Sun Microsystems - Beijing China 		    "received status out of order statsn:0x%x "
1069*aefdd131Sbing zhao - Sun Microsystems - Beijing China 		    "expstatsn:0x%x", icp->conn_oid, irrhp->opcode,
1070*aefdd131Sbing zhao - Sun Microsystems - Beijing China 		    ntohl(irrhp->statsn), icp->conn_expstatsn);
1071*aefdd131Sbing zhao - Sun Microsystems - Beijing China 		mutex_exit(&isp->sess_cmdsn_mutex);
1072*aefdd131Sbing zhao - Sun Microsystems - Beijing China 		return (IDM_STATUS_PROTOCOL_ERROR);
1073fcf3ce44SJohn Forte 	}
1074*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	/* update expcmdsn and maxcmdsn */
1075*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	iscsi_update_flow_control(isp, ntohl(irrhp->maxcmdsn),
1076*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	    ntohl(irrhp->expcmdsn));
1077*aefdd131Sbing zhao - Sun Microsystems - Beijing China 
1078*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	mutex_exit(&isp->sess_cmdsn_mutex);
1079fcf3ce44SJohn Forte 
1080fcf3ce44SJohn Forte 	/* If we don't have the rejected header we can't do anything */
1081fcf3ce44SJohn Forte 	dlength = n2h24(irrhp->dlength);
1082fcf3ce44SJohn Forte 	if (dlength < sizeof (iscsi_hdr_t)) {
108330e7468fSPeter Dunlap 		return (IDM_STATUS_PROTOCOL_ERROR);
1084fcf3ce44SJohn Forte 	}
1085fcf3ce44SJohn Forte 
1086fcf3ce44SJohn Forte 	/* map old ihp */
1087fcf3ce44SJohn Forte 	old_ihp = (iscsi_hdr_t *)data;
1088fcf3ce44SJohn Forte 
1089fcf3ce44SJohn Forte 	switch (irrhp->reason) {
1090fcf3ce44SJohn Forte 	/*
1091fcf3ce44SJohn Forte 	 * ISCSI_REJECT_IMM_CMD_REJECT - Immediate Command Reject
1092fcf3ce44SJohn Forte 	 * too many immediate commands (original cmd can be resent)
1093fcf3ce44SJohn Forte 	 */
1094fcf3ce44SJohn Forte 	case ISCSI_REJECT_IMM_CMD_REJECT:
1095fcf3ce44SJohn Forte 		/*
1096fcf3ce44SJohn Forte 		 * We have exceeded the server's capacity for outstanding
1097fcf3ce44SJohn Forte 		 * immediate commands.   This must be a task management
1098fcf3ce44SJohn Forte 		 * command so try to find it in the abortingqueue and
1099fcf3ce44SJohn Forte 		 * complete it.
1100fcf3ce44SJohn Forte 		 */
1101fcf3ce44SJohn Forte 		if (!(old_ihp->opcode & ISCSI_OP_IMMEDIATE)) {
1102fcf3ce44SJohn Forte 			/* Rejecting IMM but old old_hdr wasn't IMM */
110330e7468fSPeter Dunlap 			return (IDM_STATUS_PROTOCOL_ERROR);
1104fcf3ce44SJohn Forte 		}
1105fcf3ce44SJohn Forte 
1106fcf3ce44SJohn Forte 		/*
1107fcf3ce44SJohn Forte 		 * We only send NOP and TASK_MGT as IMM.  All other
1108fcf3ce44SJohn Forte 		 * cases should be considered as a protocol error.
1109fcf3ce44SJohn Forte 		 */
1110fcf3ce44SJohn Forte 		switch (old_ihp->opcode & ISCSI_OPCODE_MASK) {
1111fcf3ce44SJohn Forte 		case ISCSI_OP_NOOP_OUT:
1112fcf3ce44SJohn Forte 			/*
1113fcf3ce44SJohn Forte 			 * A ping was rejected - treat this like
1114fcf3ce44SJohn Forte 			 * ping response.  The down side is we
1115fcf3ce44SJohn Forte 			 * didn't get an updated MaxCmdSn.
1116fcf3ce44SJohn Forte 			 */
1117fcf3ce44SJohn Forte 			break;
1118fcf3ce44SJohn Forte 		case ISCSI_OP_SCSI_TASK_MGT_MSG:
1119*aefdd131Sbing zhao - Sun Microsystems - Beijing China 			status =
1120*aefdd131Sbing zhao - Sun Microsystems - Beijing China 			    iscsi_rx_process_rejected_tsk_mgt(ic, old_ihp);
1121fcf3ce44SJohn Forte 			break;
1122fcf3ce44SJohn Forte 		default:
1123fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) protocol error "
1124fcf3ce44SJohn Forte 			    "- received a reject for a command(0x%02x) not "
1125fcf3ce44SJohn Forte 			    "sent as an immediate", icp->conn_oid,
1126fcf3ce44SJohn Forte 			    old_ihp->opcode);
112730e7468fSPeter Dunlap 			status = IDM_STATUS_PROTOCOL_ERROR;
112830e7468fSPeter Dunlap 			break;
1129fcf3ce44SJohn Forte 		}
1130fcf3ce44SJohn Forte 		break;
1131fcf3ce44SJohn Forte 
1132fcf3ce44SJohn Forte 	/*
1133fcf3ce44SJohn Forte 	 * For the rest of the reject cases just use the general
1134fcf3ce44SJohn Forte 	 * hammer of dis/reconnecting.  This will resolve all
1135fcf3ce44SJohn Forte 	 * noted issues although could be more graceful.
1136fcf3ce44SJohn Forte 	 */
1137fcf3ce44SJohn Forte 	case ISCSI_REJECT_DATA_DIGEST_ERROR:
1138fcf3ce44SJohn Forte 	case ISCSI_REJECT_CMD_BEFORE_LOGIN:
1139fcf3ce44SJohn Forte 	case ISCSI_REJECT_SNACK_REJECT:
1140fcf3ce44SJohn Forte 	case ISCSI_REJECT_PROTOCOL_ERROR:
1141fcf3ce44SJohn Forte 	case ISCSI_REJECT_CMD_NOT_SUPPORTED:
1142fcf3ce44SJohn Forte 	case ISCSI_REJECT_TASK_IN_PROGRESS:
1143fcf3ce44SJohn Forte 	case ISCSI_REJECT_INVALID_DATA_ACK:
1144fcf3ce44SJohn Forte 	case ISCSI_REJECT_INVALID_PDU_FIELD:
1145fcf3ce44SJohn Forte 	case ISCSI_REJECT_LONG_OPERATION_REJECT:
1146fcf3ce44SJohn Forte 	case ISCSI_REJECT_NEGOTIATION_RESET:
1147fcf3ce44SJohn Forte 	default:
1148*aefdd131Sbing zhao - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iscsi connection(%u/%x) closing connection - "
1149*aefdd131Sbing zhao - Sun Microsystems - Beijing China 		    "target requested reason:0x%x",
1150*aefdd131Sbing zhao - Sun Microsystems - Beijing China 		    icp->conn_oid, irrhp->opcode, irrhp->reason);
115130e7468fSPeter Dunlap 		status = IDM_STATUS_PROTOCOL_ERROR;
115230e7468fSPeter Dunlap 		break;
1153fcf3ce44SJohn Forte 	}
1154fcf3ce44SJohn Forte 
1155*aefdd131Sbing zhao - Sun Microsystems - Beijing China 	return (status);
1156fcf3ce44SJohn Forte }
1157fcf3ce44SJohn Forte 
1158fcf3ce44SJohn Forte 
1159fcf3ce44SJohn Forte /*
1160fcf3ce44SJohn Forte  * iscsi_rx_process_rejected_tsk_mgt -
1161fcf3ce44SJohn Forte  */
116230e7468fSPeter Dunlap /* ARGSUSED */
116330e7468fSPeter Dunlap static idm_status_t
116430e7468fSPeter Dunlap iscsi_rx_process_rejected_tsk_mgt(idm_conn_t *ic, iscsi_hdr_t *old_ihp)
1165fcf3ce44SJohn Forte {
116630e7468fSPeter Dunlap 	iscsi_sess_t		*isp	= NULL;
116730e7468fSPeter Dunlap 	iscsi_cmd_t		*icmdp	= NULL;
116830e7468fSPeter Dunlap 	iscsi_conn_t		*icp 	= NULL;
1169fcf3ce44SJohn Forte 
1170fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1171fcf3ce44SJohn Forte 	ASSERT(old_ihp != NULL);
117230e7468fSPeter Dunlap 	ASSERT(isp != NULL);
1173fcf3ce44SJohn Forte 
1174fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
1175fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
1176fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(
1177fcf3ce44SJohn Forte 	    isp, old_ihp, &icmdp))) {
1178fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_cmdsn_mutex);
1179fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
118030e7468fSPeter Dunlap 		return (IDM_STATUS_PROTOCOL_ERROR);
1181fcf3ce44SJohn Forte 	}
1182fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
1183fcf3ce44SJohn Forte 
1184fcf3ce44SJohn Forte 	switch (icmdp->cmd_type) {
1185fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_ABORT:
1186fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_RESET:
1187fcf3ce44SJohn Forte 		iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E4,
1188fcf3ce44SJohn Forte 		    icp->conn_sess);
1189fcf3ce44SJohn Forte 		break;
1190fcf3ce44SJohn Forte 	/* We don't send any other task mgr types */
1191fcf3ce44SJohn Forte 	default:
1192fcf3ce44SJohn Forte 		ASSERT(B_FALSE);
1193fcf3ce44SJohn Forte 		break;
1194fcf3ce44SJohn Forte 	}
1195fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_queue_active.mutex);
1196fcf3ce44SJohn Forte 
119730e7468fSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
1198fcf3ce44SJohn Forte }
1199fcf3ce44SJohn Forte 
1200fcf3ce44SJohn Forte 
1201fcf3ce44SJohn Forte /*
1202fcf3ce44SJohn Forte  * iscsi_rx_process_task_mgt_rsp -
1203fcf3ce44SJohn Forte  */
1204fcf3ce44SJohn Forte /* ARGSUSED */
120530e7468fSPeter Dunlap static idm_status_t
120630e7468fSPeter Dunlap iscsi_rx_process_task_mgt_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
1207fcf3ce44SJohn Forte {
1208fcf3ce44SJohn Forte 	iscsi_sess_t			*isp		= NULL;
1209fcf3ce44SJohn Forte 	iscsi_scsi_task_mgt_rsp_hdr_t	*istmrhp	= NULL;
1210fcf3ce44SJohn Forte 	iscsi_cmd_t			*icmdp		= NULL;
121130e7468fSPeter Dunlap 	iscsi_conn_t			*icp		= ic->ic_handle;
121230e7468fSPeter Dunlap 	idm_status_t			status = IDM_STATUS_SUCCESS;
1213fcf3ce44SJohn Forte 
1214fcf3ce44SJohn Forte 	isp = icp->conn_sess;
121530e7468fSPeter Dunlap 	istmrhp = (iscsi_scsi_task_mgt_rsp_hdr_t *)pdu->isp_hdr;
1216fcf3ce44SJohn Forte 
1217fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
121830e7468fSPeter Dunlap 	if ((status = iscsi_rx_chk(icp, isp, (iscsi_scsi_rsp_hdr_t *)istmrhp,
121930e7468fSPeter Dunlap 	    &icmdp)) != IDM_STATUS_SUCCESS) {
1220fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
122130e7468fSPeter Dunlap 		return (status);
1222fcf3ce44SJohn Forte 	}
1223fcf3ce44SJohn Forte 
1224fcf3ce44SJohn Forte 	switch (icmdp->cmd_type) {
1225fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_ABORT:
1226fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_RESET:
1227fcf3ce44SJohn Forte 		switch (istmrhp->response) {
1228fcf3ce44SJohn Forte 		case SCSI_TCP_TM_RESP_COMPLETE:
1229fcf3ce44SJohn Forte 			/* success */
1230fcf3ce44SJohn Forte 			iscsi_cmd_state_machine(icmdp,
1231fcf3ce44SJohn Forte 			    ISCSI_CMD_EVENT_E3, isp);
1232fcf3ce44SJohn Forte 			break;
1233fcf3ce44SJohn Forte 		case SCSI_TCP_TM_RESP_NO_TASK:
1234fcf3ce44SJohn Forte 			/*
1235fcf3ce44SJohn Forte 			 * If the array no longer knows about
1236fcf3ce44SJohn Forte 			 * an ABORT RTT and we no longer have
1237fcf3ce44SJohn Forte 			 * a parent SCSI command it was just
1238fcf3ce44SJohn Forte 			 * completed, free this ABORT resource.
1239fcf3ce44SJohn Forte 			 * Otherwise FALLTHRU this will flag a
1240fcf3ce44SJohn Forte 			 * protocol problem.
1241fcf3ce44SJohn Forte 			 */
1242fcf3ce44SJohn Forte 			if ((icmdp->cmd_type == ISCSI_CMD_TYPE_ABORT) &&
1243fcf3ce44SJohn Forte 			    (icmdp->cmd_un.abort.icmdp == NULL)) {
1244fcf3ce44SJohn Forte 				iscsi_cmd_state_machine(icmdp,
1245fcf3ce44SJohn Forte 				    ISCSI_CMD_EVENT_E4, isp);
1246fcf3ce44SJohn Forte 				break;
1247fcf3ce44SJohn Forte 			}
1248fcf3ce44SJohn Forte 			/* FALLTHRU */
12492b79d384Sbing zhao - Sun Microsystems - Beijing China 		case SCSI_TCP_TM_RESP_REJECTED:
12502b79d384Sbing zhao - Sun Microsystems - Beijing China 			/*
12512b79d384Sbing zhao - Sun Microsystems - Beijing China 			 * If the target rejects our reset task,
12522b79d384Sbing zhao - Sun Microsystems - Beijing China 			 * we should record the response and complete
12532b79d384Sbing zhao - Sun Microsystems - Beijing China 			 * this command with the result.
12542b79d384Sbing zhao - Sun Microsystems - Beijing China 			 */
12552b79d384Sbing zhao - Sun Microsystems - Beijing China 			if (icmdp->cmd_type == ISCSI_CMD_TYPE_RESET) {
12562b79d384Sbing zhao - Sun Microsystems - Beijing China 				icmdp->cmd_un.reset.response =
12572b79d384Sbing zhao - Sun Microsystems - Beijing China 				    istmrhp->response;
12582b79d384Sbing zhao - Sun Microsystems - Beijing China 				iscsi_cmd_state_machine(icmdp,
12592b79d384Sbing zhao - Sun Microsystems - Beijing China 				    ISCSI_CMD_EVENT_E3, isp);
12602b79d384Sbing zhao - Sun Microsystems - Beijing China 				break;
12612b79d384Sbing zhao - Sun Microsystems - Beijing China 			}
12622b79d384Sbing zhao - Sun Microsystems - Beijing China 			/* FALLTHRU */
1263fcf3ce44SJohn Forte 		case SCSI_TCP_TM_RESP_NO_LUN:
1264fcf3ce44SJohn Forte 		case SCSI_TCP_TM_RESP_TASK_ALLEGIANT:
1265fcf3ce44SJohn Forte 		case SCSI_TCP_TM_RESP_NO_FAILOVER:
1266fcf3ce44SJohn Forte 		case SCSI_TCP_TM_RESP_IN_PRGRESS:
1267fcf3ce44SJohn Forte 		default:
1268fcf3ce44SJohn Forte 			/*
1269fcf3ce44SJohn Forte 			 * Something is out of sync.  Flush
1270fcf3ce44SJohn Forte 			 * active queues and resync the
1271fcf3ce44SJohn Forte 			 * the connection to try and recover
1272fcf3ce44SJohn Forte 			 * to a known state.
1273fcf3ce44SJohn Forte 			 */
127430e7468fSPeter Dunlap 			status = IDM_STATUS_PROTOCOL_ERROR;
1275fcf3ce44SJohn Forte 		}
1276fcf3ce44SJohn Forte 		break;
1277fcf3ce44SJohn Forte 
1278fcf3ce44SJohn Forte 	default:
1279fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
1280fcf3ce44SJohn Forte 		    "received a task mgt response for a non-task mgt "
1281fcf3ce44SJohn Forte 		    "cmd itt:0x%x type:%d", icp->conn_oid, istmrhp->itt,
1282fcf3ce44SJohn Forte 		    icmdp->cmd_type);
128330e7468fSPeter Dunlap 		status = IDM_STATUS_PROTOCOL_ERROR;
128430e7468fSPeter Dunlap 		break;
1285fcf3ce44SJohn Forte 	}
1286fcf3ce44SJohn Forte 
1287fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_queue_active.mutex);
128830e7468fSPeter Dunlap 	return (status);
1289fcf3ce44SJohn Forte }
1290fcf3ce44SJohn Forte 
1291fcf3ce44SJohn Forte 
1292fcf3ce44SJohn Forte /*
129330e7468fSPeter Dunlap  * iscsi_rx_process_logout_rsp -
1294fcf3ce44SJohn Forte  *
1295fcf3ce44SJohn Forte  */
1296fcf3ce44SJohn Forte /* ARGSUSED */
129730e7468fSPeter Dunlap idm_status_t
129830e7468fSPeter Dunlap iscsi_rx_process_logout_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
1299fcf3ce44SJohn Forte {
130030e7468fSPeter Dunlap 	iscsi_conn_t		*icp	= ic->ic_handle;
130130e7468fSPeter Dunlap 	iscsi_logout_rsp_hdr_t	*ilrhp	=
130230e7468fSPeter Dunlap 	    (iscsi_logout_rsp_hdr_t *)pdu->isp_hdr;
1303fcf3ce44SJohn Forte 	iscsi_cmd_t		*icmdp	= NULL;
130430e7468fSPeter Dunlap 	iscsi_sess_t		*isp;
130530e7468fSPeter Dunlap 	idm_status_t		status = IDM_STATUS_SUCCESS;
1306fcf3ce44SJohn Forte 
1307fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1308fcf3ce44SJohn Forte 
1309fcf3ce44SJohn Forte 	if (icp->conn_expstatsn != ntohl(ilrhp->statsn)) {
131030e7468fSPeter Dunlap 		cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - "
1311fcf3ce44SJohn Forte 		    "received status out of order itt:0x%x statsn:0x%x "
131230e7468fSPeter Dunlap 		    "expstatsn:0x%x", icp->conn_oid, ilrhp->opcode, ilrhp->itt,
1313fcf3ce44SJohn Forte 		    ntohl(ilrhp->statsn), icp->conn_expstatsn);
131430e7468fSPeter Dunlap 		return (IDM_STATUS_PROTOCOL_ERROR);
1315fcf3ce44SJohn Forte 	}
1316fcf3ce44SJohn Forte 
1317fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
1318fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
1319fcf3ce44SJohn Forte 	if (ilrhp->itt != ISCSI_RSVD_TASK_TAG) {
1320fcf3ce44SJohn Forte 		if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(
132130e7468fSPeter Dunlap 		    isp, (iscsi_hdr_t *)ilrhp, &icmdp))) {
1322fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1323fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_queue_active.mutex);
132430e7468fSPeter Dunlap 			return (IDM_STATUS_PROTOCOL_ERROR);
1325fcf3ce44SJohn Forte 		}
1326fcf3ce44SJohn Forte 	}
1327fcf3ce44SJohn Forte 
1328fcf3ce44SJohn Forte 	/* update expcmdsn and maxcmdsn */
1329fcf3ce44SJohn Forte 	iscsi_update_flow_control(isp, ntohl(ilrhp->maxcmdsn),
1330fcf3ce44SJohn Forte 	    ntohl(ilrhp->expcmdsn));
1331fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
1332fcf3ce44SJohn Forte 
133330e7468fSPeter Dunlap 	ISCSI_IO_LOG(CE_NOTE,
133430e7468fSPeter Dunlap 	    "DEBUG: iscsi_rx_process_logout_rsp: response: %d",
133530e7468fSPeter Dunlap 	    ilrhp->response);
1336fcf3ce44SJohn Forte 	switch (ilrhp->response) {
1337fcf3ce44SJohn Forte 	case ISCSI_LOGOUT_CID_NOT_FOUND:
1338fcf3ce44SJohn Forte 		/*
1339fcf3ce44SJohn Forte 		 * If the target doesn't know about our connection
1340fcf3ce44SJohn Forte 		 * then we can consider our self disconnected.
1341fcf3ce44SJohn Forte 		 */
1342fcf3ce44SJohn Forte 		/* FALLTHRU */
1343fcf3ce44SJohn Forte 	case ISCSI_LOGOUT_RECOVERY_UNSUPPORTED:
1344fcf3ce44SJohn Forte 		/*
1345fcf3ce44SJohn Forte 		 * We don't support ErrorRecovery levels above 0
1346fcf3ce44SJohn Forte 		 * currently so consider this success.
1347fcf3ce44SJohn Forte 		 */
1348fcf3ce44SJohn Forte 		/* FALLTHRU */
1349fcf3ce44SJohn Forte 	case ISCSI_LOGOUT_CLEANUP_FAILED:
1350fcf3ce44SJohn Forte 		/*
1351fcf3ce44SJohn Forte 		 * per spec. "cleanup failed for various reasons."
1352fcf3ce44SJohn Forte 		 * Although those various reasons are undefined.
1353fcf3ce44SJohn Forte 		 * Not sure what to do here.  So fake success,
1354fcf3ce44SJohn Forte 		 * which will disconnect the connection.
1355fcf3ce44SJohn Forte 		 */
1356fcf3ce44SJohn Forte 		/* FALLTHRU */
1357fcf3ce44SJohn Forte 	case ISCSI_LOGOUT_SUCCESS:
1358fcf3ce44SJohn Forte 		iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
1359fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
136030e7468fSPeter Dunlap 		iscsi_drop_conn_cleanup(icp);
1361fcf3ce44SJohn Forte 		break;
1362fcf3ce44SJohn Forte 	default:
1363fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
136430e7468fSPeter Dunlap 		status = IDM_STATUS_PROTOCOL_ERROR;
136530e7468fSPeter Dunlap 		break;
1366fcf3ce44SJohn Forte 
136730e7468fSPeter Dunlap 	}
136830e7468fSPeter Dunlap 	return (status);
1369fcf3ce44SJohn Forte }
1370fcf3ce44SJohn Forte 
1371fcf3ce44SJohn Forte /*
137230e7468fSPeter Dunlap  * iscsi_rx_process_async_rsp
1373fcf3ce44SJohn Forte  *
1374fcf3ce44SJohn Forte  */
1375fcf3ce44SJohn Forte /* ARGSUSED */
137630e7468fSPeter Dunlap static idm_status_t
137730e7468fSPeter Dunlap iscsi_rx_process_async_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
1378fcf3ce44SJohn Forte {
137930e7468fSPeter Dunlap 	iscsi_conn_t		*icp	= ic->ic_handle;
138030e7468fSPeter Dunlap 	iscsi_sess_t		*isp	= icp->conn_sess;
138130e7468fSPeter Dunlap 	idm_status_t		rval	= IDM_STATUS_SUCCESS;
138230e7468fSPeter Dunlap 	iscsi_task_t		*itp;
138330e7468fSPeter Dunlap 	iscsi_async_evt_hdr_t	*iaehp	=
138430e7468fSPeter Dunlap 	    (iscsi_async_evt_hdr_t *)pdu->isp_hdr;
1385fcf3ce44SJohn Forte 
1386fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
138730e7468fSPeter Dunlap 	ASSERT(pdu != NULL);
138830e7468fSPeter Dunlap 	ASSERT(isp != NULL);
1389fcf3ce44SJohn Forte 
139030e7468fSPeter Dunlap 	mutex_enter(&isp->sess_cmdsn_mutex);
139130e7468fSPeter Dunlap 	if (icp->conn_expstatsn == ntohl(iaehp->statsn)) {
139230e7468fSPeter Dunlap 		icp->conn_expstatsn++;
139330e7468fSPeter Dunlap 	} else {
1394fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
139530e7468fSPeter Dunlap 		    "received status out of order statsn:0x%x "
139630e7468fSPeter Dunlap 		    "expstatsn:0x%x", icp->conn_oid,
1397fcf3ce44SJohn Forte 		    ntohl(iaehp->statsn), icp->conn_expstatsn);
139830e7468fSPeter Dunlap 		mutex_exit(&isp->sess_cmdsn_mutex);
139930e7468fSPeter Dunlap 		return (IDM_STATUS_PROTOCOL_ERROR);
1400fcf3ce44SJohn Forte 	}
140130e7468fSPeter Dunlap 	mutex_exit(&isp->sess_cmdsn_mutex);
1402fcf3ce44SJohn Forte 
1403fcf3ce44SJohn Forte 	switch (iaehp->async_event) {
1404fcf3ce44SJohn Forte 	case ISCSI_ASYNC_EVENT_SCSI_EVENT:
1405fcf3ce44SJohn Forte 		/*
1406fcf3ce44SJohn Forte 		 * SCSI asynchronous event is reported in
1407fcf3ce44SJohn Forte 		 * the sense data.  Sense data that accompanies
1408fcf3ce44SJohn Forte 		 * the report in the data segment identifies the
1409fcf3ce44SJohn Forte 		 * condition.  If the target supports SCSI
1410fcf3ce44SJohn Forte 		 * asynchronous events reporting (see [SAM2])
1411fcf3ce44SJohn Forte 		 * as indicated in the stardard INQUIRY data
1412fcf3ce44SJohn Forte 		 * (see [SPC3]), its use may be enabled by
1413fcf3ce44SJohn Forte 		 * parameters in the SCSI control mode page
1414fcf3ce44SJohn Forte 		 * (see [SPC3]).
1415fcf3ce44SJohn Forte 		 *
1416fcf3ce44SJohn Forte 		 * T-10 has removed SCSI asunchronous events
1417fcf3ce44SJohn Forte 		 * from the standard.  Although we have seen
1418fcf3ce44SJohn Forte 		 * a couple targets still spending these requests.
1419fcf3ce44SJohn Forte 		 * Those targets were specifically sending them
1420fcf3ce44SJohn Forte 		 * for notification of a LUN/Volume change
1421fcf3ce44SJohn Forte 		 * (ex. LUN addition/removal).  Take a general
1422fcf3ce44SJohn Forte 		 * action to these events of dis/reconnecting.
1423fcf3ce44SJohn Forte 		 * Once reconnected we perform a reenumeration.
1424fcf3ce44SJohn Forte 		 */
142530e7468fSPeter Dunlap 		idm_ini_conn_disconnect(ic);
1426fcf3ce44SJohn Forte 		break;
1427fcf3ce44SJohn Forte 
1428fcf3ce44SJohn Forte 	case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT:
142930e7468fSPeter Dunlap 		/*
143030e7468fSPeter Dunlap 		 * We've been asked to logout by the target --
143130e7468fSPeter Dunlap 		 * we need to treat this differently from a normal logout
143230e7468fSPeter Dunlap 		 * due to a discovery failure.  Normal logouts result in
143330e7468fSPeter Dunlap 		 * an N3 event to the session state machine and an offline
143430e7468fSPeter Dunlap 		 * of the lun.  In this case we want to put the connection
143530e7468fSPeter Dunlap 		 * into "failed" state and generate N5 to the session state
143630e7468fSPeter Dunlap 		 * machine since the initiator logged out at the target's
143730e7468fSPeter Dunlap 		 * request.  To track this we set a flag indicating we
143830e7468fSPeter Dunlap 		 * received this async logout request from the tharget
143930e7468fSPeter Dunlap 		 */
1440fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
144130e7468fSPeter Dunlap 		icp->conn_async_logout = B_TRUE;
1442fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
144330e7468fSPeter Dunlap 
144492adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		/* Hold is released in iscsi_handle_logout. */
144592adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		idm_conn_hold(ic);
144692adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
144730e7468fSPeter Dunlap 		/* Target has requested this connection to logout. */
144830e7468fSPeter Dunlap 		itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
144930e7468fSPeter Dunlap 		itp->t_arg = icp;
145030e7468fSPeter Dunlap 		itp->t_blocking = B_FALSE;
145130e7468fSPeter Dunlap 		if (ddi_taskq_dispatch(isp->sess_taskq,
145230e7468fSPeter Dunlap 		    (void(*)())iscsi_logout_start, itp, DDI_SLEEP) !=
145330e7468fSPeter Dunlap 		    DDI_SUCCESS) {
145492adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			idm_conn_rele(ic);
145530e7468fSPeter Dunlap 			/* Disconnect if we couldn't dispatch the task */
145630e7468fSPeter Dunlap 			idm_ini_conn_disconnect(ic);
145730e7468fSPeter Dunlap 		}
1458fcf3ce44SJohn Forte 		break;
1459fcf3ce44SJohn Forte 
1460fcf3ce44SJohn Forte 	case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION:
1461fcf3ce44SJohn Forte 		/*
1462fcf3ce44SJohn Forte 		 * Target is going to drop our connection.
1463fcf3ce44SJohn Forte 		 *	param1 - CID which will be dropped.
1464fcf3ce44SJohn Forte 		 *	param2 - Min time to reconnect.
1465fcf3ce44SJohn Forte 		 *	param3 - Max time to reconnect.
1466fcf3ce44SJohn Forte 		 *
1467fcf3ce44SJohn Forte 		 * For now just let fail as another disconnect.
1468fcf3ce44SJohn Forte 		 *
1469fcf3ce44SJohn Forte 		 * MC/S Once we support > 1 connections then
1470fcf3ce44SJohn Forte 		 * we need to check the CID and drop that
1471fcf3ce44SJohn Forte 		 * specific connection.
1472fcf3ce44SJohn Forte 		 */
147330e7468fSPeter Dunlap 		iscsi_conn_set_login_min_max(icp, iaehp->param2,
147430e7468fSPeter Dunlap 		    iaehp->param3);
147530e7468fSPeter Dunlap 		idm_ini_conn_disconnect(ic);
1476fcf3ce44SJohn Forte 		break;
1477fcf3ce44SJohn Forte 
1478fcf3ce44SJohn Forte 	case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS:
1479fcf3ce44SJohn Forte 		/*
1480fcf3ce44SJohn Forte 		 * Target is going to drop ALL connections.
1481fcf3ce44SJohn Forte 		 *	param2 - Min time to reconnect.
1482fcf3ce44SJohn Forte 		 *	param3 - Max time to reconnect.
1483fcf3ce44SJohn Forte 		 *
1484fcf3ce44SJohn Forte 		 * For now just let fail as anyother disconnect.
1485fcf3ce44SJohn Forte 		 *
1486fcf3ce44SJohn Forte 		 * MC/S Once we support more than > 1 connections
1487fcf3ce44SJohn Forte 		 * then we need to drop all connections on the
1488fcf3ce44SJohn Forte 		 * session.
1489fcf3ce44SJohn Forte 		 */
149030e7468fSPeter Dunlap 		iscsi_conn_set_login_min_max(icp, iaehp->param2,
149130e7468fSPeter Dunlap 		    iaehp->param3);
149230e7468fSPeter Dunlap 		idm_ini_conn_disconnect(ic);
1493fcf3ce44SJohn Forte 		break;
1494fcf3ce44SJohn Forte 
1495fcf3ce44SJohn Forte 	case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION:
1496fcf3ce44SJohn Forte 		/*
1497fcf3ce44SJohn Forte 		 * Target requests parameter negotiation
1498fcf3ce44SJohn Forte 		 * on this connection.
1499fcf3ce44SJohn Forte 		 *
1500fcf3ce44SJohn Forte 		 * The initiator must honor this request.  For
1501fcf3ce44SJohn Forte 		 * now we will request a logout.  We can't
1502fcf3ce44SJohn Forte 		 * just ignore this or it might force corruption?
1503fcf3ce44SJohn Forte 		 */
150492adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
150592adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		/* Hold is released in iscsi_handle_logout */
150692adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		idm_conn_hold(ic);
150730e7468fSPeter Dunlap 		itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
150830e7468fSPeter Dunlap 		itp->t_arg = icp;
150930e7468fSPeter Dunlap 		itp->t_blocking = B_FALSE;
151030e7468fSPeter Dunlap 		if (ddi_taskq_dispatch(isp->sess_taskq,
151130e7468fSPeter Dunlap 		    (void(*)())iscsi_logout_start, itp, DDI_SLEEP) !=
151230e7468fSPeter Dunlap 		    DDI_SUCCESS) {
151330e7468fSPeter Dunlap 			/* Disconnect if we couldn't dispatch the task */
151492adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			idm_conn_rele(ic);
151530e7468fSPeter Dunlap 			idm_ini_conn_disconnect(ic);
151630e7468fSPeter Dunlap 		}
1517fcf3ce44SJohn Forte 		break;
1518fcf3ce44SJohn Forte 
1519fcf3ce44SJohn Forte 	case ISCSI_ASYNC_EVENT_VENDOR_SPECIFIC:
1520fcf3ce44SJohn Forte 		/*
1521fcf3ce44SJohn Forte 		 * We currently don't handle any vendor
1522fcf3ce44SJohn Forte 		 * specific async events.  So just ignore
1523fcf3ce44SJohn Forte 		 * the request.
1524fcf3ce44SJohn Forte 		 */
152530e7468fSPeter Dunlap 		idm_ini_conn_disconnect(ic);
1526fcf3ce44SJohn Forte 		break;
1527fcf3ce44SJohn Forte 	default:
152830e7468fSPeter Dunlap 		rval = IDM_STATUS_PROTOCOL_ERROR;
1529fcf3ce44SJohn Forte 	}
1530fcf3ce44SJohn Forte 
1531fcf3ce44SJohn Forte 	return (rval);
1532fcf3ce44SJohn Forte }
1533fcf3ce44SJohn Forte 
1534fcf3ce44SJohn Forte /*
1535fcf3ce44SJohn Forte  * iscsi_rx_process_text_rsp - processes iSCSI text response.  It sets
1536fcf3ce44SJohn Forte  * the cmd_result field of the command data structure with the actual
1537fcf3ce44SJohn Forte  * status value instead of returning the status value.  The return value
1538fcf3ce44SJohn Forte  * is SUCCESS in order to let iscsi_handle_text control the operation of
1539fcf3ce44SJohn Forte  * a text request.
154030e7468fSPeter Dunlap  * Text requests are a handled a little different than other types of
1541fcf3ce44SJohn Forte  * iSCSI commands because the initiator sends additional empty text requests
1542fcf3ce44SJohn Forte  * in order to obtain the remaining responses required to complete the
1543fcf3ce44SJohn Forte  * request.  iscsi_handle_text controls the operation of text request, while
1544fcf3ce44SJohn Forte  * iscsi_rx_process_text_rsp just process the current response.
1545fcf3ce44SJohn Forte  */
154630e7468fSPeter Dunlap static idm_status_t
154730e7468fSPeter Dunlap iscsi_rx_process_text_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
1548fcf3ce44SJohn Forte {
1549fcf3ce44SJohn Forte 	iscsi_sess_t		*isp	= NULL;
155030e7468fSPeter Dunlap 	iscsi_text_rsp_hdr_t	*ithp	=
155130e7468fSPeter Dunlap 	    (iscsi_text_rsp_hdr_t *)pdu->isp_hdr;
155230e7468fSPeter Dunlap 	iscsi_conn_t		*icp	= ic->ic_handle;
1553fcf3ce44SJohn Forte 	iscsi_cmd_t		*icmdp	= NULL;
1554fcf3ce44SJohn Forte 	boolean_t		final	= B_FALSE;
1555fcf3ce44SJohn Forte 	uint32_t		data_len;
155630e7468fSPeter Dunlap 	uint8_t			*data = pdu->isp_data;
155730e7468fSPeter Dunlap 	idm_status_t		rval;
1558fcf3ce44SJohn Forte 
1559fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1560fcf3ce44SJohn Forte 
1561fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_queue_active.mutex);
156230e7468fSPeter Dunlap 	if ((rval = iscsi_rx_chk(icp, isp, (iscsi_scsi_rsp_hdr_t *)ithp,
156330e7468fSPeter Dunlap 	    &icmdp)) != IDM_STATUS_SUCCESS) {
1564fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
156530e7468fSPeter Dunlap 		return (rval);
1566fcf3ce44SJohn Forte 	}
1567fcf3ce44SJohn Forte 
1568fcf3ce44SJohn Forte 	/* update local final response flag */
1569fcf3ce44SJohn Forte 	if (ithp->flags & ISCSI_FLAG_FINAL) {
1570fcf3ce44SJohn Forte 		final = B_TRUE;
1571fcf3ce44SJohn Forte 	}
1572fcf3ce44SJohn Forte 
1573fcf3ce44SJohn Forte 	/*
1574fcf3ce44SJohn Forte 	 * validate received TTT value.  RFC3720 specifies the following:
1575fcf3ce44SJohn Forte 	 * - F bit set to 1 MUST have a reserved TTT value 0xffffffff
1576fcf3ce44SJohn Forte 	 * - F bit set to 0 MUST have a non-reserved TTT value !0xffffffff
1577fcf3ce44SJohn Forte 	 * In addition, the received TTT value must not change between
1578fcf3ce44SJohn Forte 	 * responses of a long text response
1579fcf3ce44SJohn Forte 	 */
1580fcf3ce44SJohn Forte 	if (((final == B_TRUE) && (ithp->ttt != ISCSI_RSVD_TASK_TAG)) ||
1581fcf3ce44SJohn Forte 	    ((final == B_FALSE) && (ithp->ttt == ISCSI_RSVD_TASK_TAG))) {
1582fcf3ce44SJohn Forte 		icmdp->cmd_result = ISCSI_STATUS_PROTOCOL_ERROR;
1583fcf3ce44SJohn Forte 		icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
1584fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
1585fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
1586fcf3ce44SJohn Forte 		    "received text response with invalid flags:0x%x or "
1587fcf3ce44SJohn Forte 		    "ttt:0x%x", icp->conn_oid, ithp->flags, ithp->itt);
158830e7468fSPeter Dunlap 		return (IDM_STATUS_PROTOCOL_ERROR);
1589fcf3ce44SJohn Forte 	}
1590fcf3ce44SJohn Forte 
1591fcf3ce44SJohn Forte 	if ((icmdp->cmd_un.text.stage == ISCSI_CMD_TEXT_INITIAL_REQ) &&
1592fcf3ce44SJohn Forte 	    (ithp->ttt == ISCSI_RSVD_TASK_TAG) &&
1593fcf3ce44SJohn Forte 	    (final == B_FALSE)) {
1594fcf3ce44SJohn Forte 		/* TTT should have matched reserved value */
1595fcf3ce44SJohn Forte 		icmdp->cmd_result = ISCSI_STATUS_PROTOCOL_ERROR;
1596fcf3ce44SJohn Forte 		icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
1597fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
1598fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol "
1599fcf3ce44SJohn Forte 		    "error - received text response with invalid "
1600fcf3ce44SJohn Forte 		    "ttt:0x%x", icp->conn_oid, ithp->ttt);
160130e7468fSPeter Dunlap 		return (IDM_STATUS_PROTOCOL_ERROR);
1602fcf3ce44SJohn Forte 	}
1603fcf3ce44SJohn Forte 
1604fcf3ce44SJohn Forte 	/*
1605fcf3ce44SJohn Forte 	 * If this is first response, save away TTT value for later use
1606fcf3ce44SJohn Forte 	 * in a long text request/response sequence
1607fcf3ce44SJohn Forte 	 */
1608fcf3ce44SJohn Forte 	if (icmdp->cmd_un.text.stage == ISCSI_CMD_TEXT_INITIAL_REQ) {
1609fcf3ce44SJohn Forte 		icmdp->cmd_un.text.ttt = ithp->ttt;
1610fcf3ce44SJohn Forte 	}
1611fcf3ce44SJohn Forte 
1612fcf3ce44SJohn Forte 	data_len = ntoh24(ithp->dlength);
1613fcf3ce44SJohn Forte 
1614fcf3ce44SJohn Forte 	/* check whether enough buffer available to copy data */
1615fcf3ce44SJohn Forte 	if ((icmdp->cmd_un.text.total_rx_len + data_len) >
1616fcf3ce44SJohn Forte 	    icmdp->cmd_un.text.buf_len) {
1617fcf3ce44SJohn Forte 		icmdp->cmd_un.text.total_rx_len += data_len;
1618fcf3ce44SJohn Forte 		icmdp->cmd_result = ISCSI_STATUS_DATA_OVERFLOW;
1619fcf3ce44SJohn Forte 		/*
1620fcf3ce44SJohn Forte 		 * DATA_OVERFLOW will result in a SUCCESS return so that
1621fcf3ce44SJohn Forte 		 * iscsi_handle_text can continue to obtain the remaining
1622fcf3ce44SJohn Forte 		 * text response if needed.
1623fcf3ce44SJohn Forte 		 */
1624fcf3ce44SJohn Forte 	} else {
1625fcf3ce44SJohn Forte 		char *buf_data = (icmdp->cmd_un.text.buf +
1626fcf3ce44SJohn Forte 		    icmdp->cmd_un.text.offset);
1627fcf3ce44SJohn Forte 
1628fcf3ce44SJohn Forte 		bcopy(data, buf_data, data_len);
1629fcf3ce44SJohn Forte 		icmdp->cmd_un.text.offset += data_len;
1630fcf3ce44SJohn Forte 		icmdp->cmd_un.text.total_rx_len += data_len;
1631fcf3ce44SJohn Forte 		icmdp->cmd_result = ISCSI_STATUS_SUCCESS;
1632fcf3ce44SJohn Forte 		bcopy(ithp->rsvd4, icmdp->cmd_un.text.lun,
1633fcf3ce44SJohn Forte 		    sizeof (icmdp->cmd_un.text.lun));
1634fcf3ce44SJohn Forte 	}
1635fcf3ce44SJohn Forte 
1636fcf3ce44SJohn Forte 	/* update stage  */
1637fcf3ce44SJohn Forte 	if (final == B_TRUE) {
1638fcf3ce44SJohn Forte 		icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
1639fcf3ce44SJohn Forte 	} else {
1640fcf3ce44SJohn Forte 		icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_CONTINUATION;
1641fcf3ce44SJohn Forte 	}
1642fcf3ce44SJohn Forte 
1643fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
1644fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_queue_active.mutex);
164530e7468fSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
164630e7468fSPeter Dunlap }
164730e7468fSPeter Dunlap 
164830e7468fSPeter Dunlap /*
164930e7468fSPeter Dunlap  * iscsi_rx_process_scsi_itt_to_icmdp - Lookup itt using IDM to find matching
165030e7468fSPeter Dunlap  * icmdp.  Verify itt in hdr and icmdp are the same.
165130e7468fSPeter Dunlap  */
165230e7468fSPeter Dunlap static iscsi_status_t
165330e7468fSPeter Dunlap iscsi_rx_process_scsi_itt_to_icmdp(iscsi_sess_t *isp, idm_conn_t *ic,
165430e7468fSPeter Dunlap     iscsi_scsi_rsp_hdr_t *ihp, iscsi_cmd_t **icmdp)
165530e7468fSPeter Dunlap {
165630e7468fSPeter Dunlap 	idm_task_t *itp;
165730e7468fSPeter Dunlap 
165830e7468fSPeter Dunlap 	ASSERT(isp != NULL);
165930e7468fSPeter Dunlap 	ASSERT(ihp != NULL);
166030e7468fSPeter Dunlap 	ASSERT(icmdp != NULL);
166130e7468fSPeter Dunlap 	ASSERT(mutex_owned(&isp->sess_cmdsn_mutex));
166230e7468fSPeter Dunlap 	itp = idm_task_find_and_complete(ic, ihp->itt, ISCSI_INI_TASK_TTT);
166330e7468fSPeter Dunlap 	if (itp == NULL) {
166430e7468fSPeter Dunlap 		cmn_err(CE_WARN, "iscsi session(%u) protocol error - "
166530e7468fSPeter Dunlap 		    "received unknown itt:0x%x - protocol error",
166630e7468fSPeter Dunlap 		    isp->sess_oid, ihp->itt);
166730e7468fSPeter Dunlap 		return (ISCSI_STATUS_INTERNAL_ERROR);
166830e7468fSPeter Dunlap 	}
166930e7468fSPeter Dunlap 	*icmdp = itp->idt_private;
167030e7468fSPeter Dunlap 
167130e7468fSPeter Dunlap 	idm_task_rele(itp);
167230e7468fSPeter Dunlap 
1673fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
167430e7468fSPeter Dunlap 
1675fcf3ce44SJohn Forte }
1676fcf3ce44SJohn Forte 
1677fcf3ce44SJohn Forte /*
1678fcf3ce44SJohn Forte  * iscsi_rx_process_itt_to_icmdp - Lookup itt in the session's
1679fcf3ce44SJohn Forte  * cmd table to find matching icmdp.  Verify itt in hdr and
1680fcf3ce44SJohn Forte  * icmdp are the same.
1681fcf3ce44SJohn Forte  */
1682fcf3ce44SJohn Forte static iscsi_status_t
1683fcf3ce44SJohn Forte iscsi_rx_process_itt_to_icmdp(iscsi_sess_t *isp, iscsi_hdr_t *ihp,
1684fcf3ce44SJohn Forte     iscsi_cmd_t **icmdp)
1685fcf3ce44SJohn Forte {
1686fcf3ce44SJohn Forte 	int cmd_table_idx = 0;
1687fcf3ce44SJohn Forte 
1688fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1689fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
1690fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
1691fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&isp->sess_cmdsn_mutex));
1692fcf3ce44SJohn Forte 
1693fcf3ce44SJohn Forte 	/* try to find an associated iscsi_pkt */
169430e7468fSPeter Dunlap 	cmd_table_idx = (ihp->itt - IDM_TASKIDS_MAX) % ISCSI_CMD_TABLE_SIZE;
1695fcf3ce44SJohn Forte 	if (isp->sess_cmd_table[cmd_table_idx] == NULL) {
1696fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi session(%u) protocol error - "
1697fcf3ce44SJohn Forte 		    "received unknown itt:0x%x - protocol error",
1698fcf3ce44SJohn Forte 		    isp->sess_oid, ihp->itt);
1699fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
1700fcf3ce44SJohn Forte 	}
1701fcf3ce44SJohn Forte 
1702fcf3ce44SJohn Forte 	/* verify itt */
1703fcf3ce44SJohn Forte 	if (isp->sess_cmd_table[cmd_table_idx]->cmd_itt != ihp->itt) {
1704fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi session(%u) received itt:0x%x "
1705fcf3ce44SJohn Forte 		    " which is out of sync with itt:0x%x", isp->sess_oid,
1706fcf3ce44SJohn Forte 		    ihp->itt, isp->sess_cmd_table[cmd_table_idx]->cmd_itt);
1707fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
1708fcf3ce44SJohn Forte 	}
1709fcf3ce44SJohn Forte 
171029e23f3fSandrew.rutz@sun.com 	/* ensure that icmdp is still in Active state */
171129e23f3fSandrew.rutz@sun.com 	if (isp->sess_cmd_table[cmd_table_idx]->cmd_state !=
171229e23f3fSandrew.rutz@sun.com 	    ISCSI_CMD_STATE_ACTIVE) {
171329e23f3fSandrew.rutz@sun.com 		cmn_err(CE_WARN, "iscsi session(%u) received itt:0x%x "
171429e23f3fSandrew.rutz@sun.com 		    "but icmdp (%p) is not in active state",
171529e23f3fSandrew.rutz@sun.com 		    isp->sess_oid, ihp->itt,
171629e23f3fSandrew.rutz@sun.com 		    (void *)isp->sess_cmd_table[cmd_table_idx]);
171729e23f3fSandrew.rutz@sun.com 		return (ISCSI_STATUS_INTERNAL_ERROR);
171829e23f3fSandrew.rutz@sun.com 	}
171929e23f3fSandrew.rutz@sun.com 
1720fcf3ce44SJohn Forte 	/* make sure this is a SCSI cmd */
1721fcf3ce44SJohn Forte 	*icmdp = isp->sess_cmd_table[cmd_table_idx];
1722fcf3ce44SJohn Forte 
1723fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
1724fcf3ce44SJohn Forte }
1725fcf3ce44SJohn Forte 
1726fcf3ce44SJohn Forte /*
1727fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
1728fcf3ce44SJohn Forte  * | End of protocol receive routines					|
1729fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
1730fcf3ce44SJohn Forte  */
1731fcf3ce44SJohn Forte 
1732fcf3ce44SJohn Forte /*
1733fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
1734fcf3ce44SJohn Forte  * | Beginning of protocol send routines				|
1735fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
1736fcf3ce44SJohn Forte  */
1737fcf3ce44SJohn Forte 
1738fcf3ce44SJohn Forte 
1739fcf3ce44SJohn Forte /*
1740fcf3ce44SJohn Forte  * iscsi_tx_thread - This thread is the driving point for all
174130e7468fSPeter Dunlap  * iSCSI PDUs after login.  No PDUs should call idm_pdu_tx()
1742fcf3ce44SJohn Forte  * directly they should be funneled through iscsi_tx_thread.
1743fcf3ce44SJohn Forte  */
1744fcf3ce44SJohn Forte void
1745fcf3ce44SJohn Forte iscsi_tx_thread(iscsi_thread_t *thread, void *arg)
1746fcf3ce44SJohn Forte {
1747fcf3ce44SJohn Forte 	iscsi_conn_t	*icp	= (iscsi_conn_t *)arg;
1748fcf3ce44SJohn Forte 	iscsi_sess_t	*isp	= NULL;
1749fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp	= NULL;
1750fcf3ce44SJohn Forte 	clock_t		tout;
1751fcf3ce44SJohn Forte 	int		ret	= 1;
1752fcf3ce44SJohn Forte 
1753fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1754fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1755fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1756fcf3ce44SJohn Forte 	ASSERT(thread != NULL);
1757fcf3ce44SJohn Forte 	ASSERT(thread->signature == SIG_ISCSI_THREAD);
1758fcf3ce44SJohn Forte 
1759fcf3ce44SJohn Forte 	tout = SEC_TO_TICK(1);
1760fcf3ce44SJohn Forte 	/*
1761fcf3ce44SJohn Forte 	 * Transfer icmdps until shutdown by owning session.
1762fcf3ce44SJohn Forte 	 */
1763fcf3ce44SJohn Forte 	while (ret != 0) {
1764fcf3ce44SJohn Forte 
1765fcf3ce44SJohn Forte 		isp->sess_window_open = B_TRUE;
1766fcf3ce44SJohn Forte 		/*
1767fcf3ce44SJohn Forte 		 * While the window is open, there are commands available
1768fcf3ce44SJohn Forte 		 * to send and the session state allows those commands to
1769fcf3ce44SJohn Forte 		 * be sent try to transfer them.
1770fcf3ce44SJohn Forte 		 */
1771fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_queue_pending.mutex);
1772fcf3ce44SJohn Forte 		while ((isp->sess_window_open == B_TRUE) &&
1773fcf3ce44SJohn Forte 		    ((icmdp = isp->sess_queue_pending.head) != NULL) &&
1774fcf3ce44SJohn Forte 		    (((icmdp->cmd_type != ISCSI_CMD_TYPE_SCSI) &&
1775fcf3ce44SJohn Forte 		    (ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state))) ||
1776fcf3ce44SJohn Forte 		    (icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN))) {
1777fcf3ce44SJohn Forte 
1778fcf3ce44SJohn Forte 			/* update command with this connection info */
1779fcf3ce44SJohn Forte 			icmdp->cmd_conn = icp;
1780fcf3ce44SJohn Forte 			/* attempt to send this command */
1781fcf3ce44SJohn Forte 			iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E2, isp);
1782fcf3ce44SJohn Forte 
1783fcf3ce44SJohn Forte 			ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex));
1784fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_queue_pending.mutex);
1785fcf3ce44SJohn Forte 		}
1786fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_queue_pending.mutex);
1787fcf3ce44SJohn Forte 
1788fcf3ce44SJohn Forte 		/*
1789fcf3ce44SJohn Forte 		 * Go to sleep until there is something new
1790fcf3ce44SJohn Forte 		 * to process (awoken via cv_boardcast).
1791fcf3ce44SJohn Forte 		 * Or the timer goes off.
1792fcf3ce44SJohn Forte 		 */
1793fcf3ce44SJohn Forte 		ret = iscsi_thread_wait(thread, tout);
1794fcf3ce44SJohn Forte 	}
1795fcf3ce44SJohn Forte 
1796fcf3ce44SJohn Forte }
1797fcf3ce44SJohn Forte 
1798fcf3ce44SJohn Forte 
1799fcf3ce44SJohn Forte /*
1800fcf3ce44SJohn Forte  * iscsi_tx_cmd - transfers icmdp across wire as iscsi pdu
1801fcf3ce44SJohn Forte  *
1802fcf3ce44SJohn Forte  * Just prior to sending the command to the networking layer the
1803fcf3ce44SJohn Forte  * pending queue lock will be dropped.  At this point only local
1804fcf3ce44SJohn Forte  * resources will be used, not the icmdp.  Holding the queue lock
1805fcf3ce44SJohn Forte  * across the networking call can lead to a hang.  (This is due
1806fcf3ce44SJohn Forte  * to the the target driver and networking layers competing use
1807fcf3ce44SJohn Forte  * of the timeout() resources and the queue lock being held for
1808fcf3ce44SJohn Forte  * both sides.)  Upon the completion of this command the lock
1809fcf3ce44SJohn Forte  * will have been re-acquired.
1810fcf3ce44SJohn Forte  */
1811fcf3ce44SJohn Forte iscsi_status_t
1812fcf3ce44SJohn Forte iscsi_tx_cmd(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
1813fcf3ce44SJohn Forte {
1814fcf3ce44SJohn Forte 	iscsi_status_t	rval = ISCSI_STATUS_INTERNAL_ERROR;
1815fcf3ce44SJohn Forte 
1816fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1817fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
1818fcf3ce44SJohn Forte 
1819fcf3ce44SJohn Forte 	/* transfer specific command type */
1820fcf3ce44SJohn Forte 	switch (icmdp->cmd_type) {
1821fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_SCSI:
1822fcf3ce44SJohn Forte 		rval = iscsi_tx_scsi(isp, icmdp);
1823fcf3ce44SJohn Forte 		break;
1824fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_NOP:
1825fcf3ce44SJohn Forte 		rval = iscsi_tx_nop(isp, icmdp);
1826fcf3ce44SJohn Forte 		break;
1827fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_ABORT:
1828fcf3ce44SJohn Forte 		rval = iscsi_tx_abort(isp, icmdp);
1829fcf3ce44SJohn Forte 		break;
1830fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_RESET:
1831fcf3ce44SJohn Forte 		rval = iscsi_tx_reset(isp, icmdp);
1832fcf3ce44SJohn Forte 		break;
1833fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_LOGOUT:
1834fcf3ce44SJohn Forte 		rval = iscsi_tx_logout(isp, icmdp);
1835fcf3ce44SJohn Forte 		break;
1836fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_TEXT:
1837fcf3ce44SJohn Forte 		rval = iscsi_tx_text(isp, icmdp);
1838fcf3ce44SJohn Forte 		break;
1839fcf3ce44SJohn Forte 	default:
184030e7468fSPeter Dunlap 		cmn_err(CE_WARN, "iscsi_tx_cmd: invalid cmdtype: %d",
184130e7468fSPeter Dunlap 		    icmdp->cmd_type);
1842fcf3ce44SJohn Forte 		ASSERT(FALSE);
1843fcf3ce44SJohn Forte 	}
1844fcf3ce44SJohn Forte 
1845fcf3ce44SJohn Forte 	ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex));
1846fcf3ce44SJohn Forte 	return (rval);
1847fcf3ce44SJohn Forte }
1848fcf3ce44SJohn Forte 
1849fcf3ce44SJohn Forte /*
1850fcf3ce44SJohn Forte  * a variable length cdb can be up to 16K, but we obviously don't want
1851fcf3ce44SJohn Forte  * to put that on the stack; go with 200 bytes; if we get something
1852fcf3ce44SJohn Forte  * bigger than that we will kmem_alloc a buffer
1853fcf3ce44SJohn Forte  */
1854fcf3ce44SJohn Forte #define	DEF_CDB_LEN	200
1855fcf3ce44SJohn Forte 
1856fcf3ce44SJohn Forte /*
1857fcf3ce44SJohn Forte  * given the size of the cdb, return how many bytes the header takes,
1858fcf3ce44SJohn Forte  * which is the sizeof addl_hdr_t + the CDB size, minus the 16 bytes
1859fcf3ce44SJohn Forte  * stored in the basic header, minus sizeof (ahs_extscb)
1860fcf3ce44SJohn Forte  */
1861fcf3ce44SJohn Forte #define	ADDLHDRSZ(x)		(sizeof (iscsi_addl_hdr_t) + (x) - \
1862fcf3ce44SJohn Forte 					16 - 4)
1863fcf3ce44SJohn Forte 
186430e7468fSPeter Dunlap static void
186530e7468fSPeter Dunlap iscsi_tx_init_hdr(iscsi_sess_t *isp, iscsi_conn_t *icp,
18662b79d384Sbing zhao - Sun Microsystems - Beijing China     iscsi_text_hdr_t *ihp, int opcode, iscsi_cmd_t *icmdp)
1867fcf3ce44SJohn Forte {
186830e7468fSPeter Dunlap 	ihp->opcode		= opcode;
18692b79d384Sbing zhao - Sun Microsystems - Beijing China 	ihp->itt		= icmdp->cmd_itt;
1870fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
18712b79d384Sbing zhao - Sun Microsystems - Beijing China 	icmdp->cmd_sn		= isp->sess_cmdsn;
1872fcf3ce44SJohn Forte 	ihp->cmdsn		= htonl(isp->sess_cmdsn);
1873fcf3ce44SJohn Forte 	isp->sess_cmdsn++;
1874fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
1875fcf3ce44SJohn Forte 	ihp->expstatsn		= htonl(icp->conn_expstatsn);
1876fcf3ce44SJohn Forte 	icp->conn_laststatsn = icp->conn_expstatsn;
187730e7468fSPeter Dunlap }
1878fcf3ce44SJohn Forte 
1879fcf3ce44SJohn Forte 
188030e7468fSPeter Dunlap static void
188130e7468fSPeter Dunlap iscsi_tx_scsi_data(iscsi_cmd_t *icmdp, iscsi_scsi_cmd_hdr_t *ihp,
188230e7468fSPeter Dunlap     iscsi_conn_t *icp, idm_pdu_t *pdu)
188330e7468fSPeter Dunlap {
188430e7468fSPeter Dunlap 	struct buf		*bp		= NULL;
188530e7468fSPeter Dunlap 	size_t			buflen		= 0;
188630e7468fSPeter Dunlap 	uint32_t		first_burst_length = 0;
188730e7468fSPeter Dunlap 	struct scsi_pkt		*pkt;
188830e7468fSPeter Dunlap 
188930e7468fSPeter Dunlap 	pkt = icmdp->cmd_un.scsi.pkt;
1890fcf3ce44SJohn Forte 	bp = icmdp->cmd_un.scsi.bp;
1891fcf3ce44SJohn Forte 	if ((bp != NULL) && bp->b_bcount) {
1892fcf3ce44SJohn Forte 		buflen = bp->b_bcount;
189330e7468fSPeter Dunlap 		first_burst_length =
189430e7468fSPeter Dunlap 		    icp->conn_params.first_burst_length;
1895fcf3ce44SJohn Forte 
1896fcf3ce44SJohn Forte 		if (bp->b_flags & B_READ) {
1897fcf3ce44SJohn Forte 			ihp->flags = ISCSI_FLAG_FINAL;
1898fcf3ce44SJohn Forte 			/*
1899fcf3ce44SJohn Forte 			 * fix problem where OS sends bp (B_READ &
1900fcf3ce44SJohn Forte 			 * b_bcount!=0) for a TUR or START_STOP.
1901fcf3ce44SJohn Forte 			 * (comment came from cisco code.)
1902fcf3ce44SJohn Forte 			 */
1903fcf3ce44SJohn Forte 			if ((pkt->pkt_cdbp[0] != SCMD_TEST_UNIT_READY) &&
1904fcf3ce44SJohn Forte 			    (pkt->pkt_cdbp[0] != SCMD_START_STOP)) {
1905fcf3ce44SJohn Forte 				ihp->flags |= ISCSI_FLAG_CMD_READ;
1906fcf3ce44SJohn Forte 				ihp->data_length = htonl(buflen);
1907fcf3ce44SJohn Forte 			}
1908fcf3ce44SJohn Forte 		} else {
1909fcf3ce44SJohn Forte 			ihp->flags = ISCSI_FLAG_CMD_WRITE;
1910fcf3ce44SJohn Forte 			/*
1911fcf3ce44SJohn Forte 			 * FinalBit on the the iSCSI PDU denotes this
1912fcf3ce44SJohn Forte 			 * is the last PDU in the sequence.
1913fcf3ce44SJohn Forte 			 *
1914fcf3ce44SJohn Forte 			 * initial_r2t = true means R2T is required
1915fcf3ce44SJohn Forte 			 * for additional PDU, so there will be no more
1916fcf3ce44SJohn Forte 			 * unsolicited PDUs following
1917fcf3ce44SJohn Forte 			 */
1918fcf3ce44SJohn Forte 			if (icp->conn_params.initial_r2t) {
1919fcf3ce44SJohn Forte 				ihp->flags |= ISCSI_FLAG_FINAL;
1920fcf3ce44SJohn Forte 			}
1921fcf3ce44SJohn Forte 
1922fcf3ce44SJohn Forte 			/* Check if we should send ImmediateData */
1923fcf3ce44SJohn Forte 			if (icp->conn_params.immediate_data) {
192430e7468fSPeter Dunlap 				pdu->isp_data =
192530e7468fSPeter Dunlap 				    (uint8_t *)icmdp->
192630e7468fSPeter Dunlap 				    cmd_un.scsi.bp->b_un.b_addr;
192730e7468fSPeter Dunlap 
192830e7468fSPeter Dunlap 				pdu->isp_datalen = MIN(MIN(buflen,
1929fcf3ce44SJohn Forte 				    first_burst_length),
1930fcf3ce44SJohn Forte 				    icmdp->cmd_conn->conn_params.
1931fcf3ce44SJohn Forte 				    max_xmit_data_seg_len);
1932fcf3ce44SJohn Forte 
1933fcf3ce44SJohn Forte 				/*
1934fcf3ce44SJohn Forte 				 * if everything fits immediate, or
1935fcf3ce44SJohn Forte 				 * we can send all burst data immediate
1936fcf3ce44SJohn Forte 				 * (not unsol), set F
1937fcf3ce44SJohn Forte 				 */
193830e7468fSPeter Dunlap 				/*
193930e7468fSPeter Dunlap 				 * XXX This doesn't look right -- it's not
194030e7468fSPeter Dunlap 				 * clear how we can handle transmitting
194130e7468fSPeter Dunlap 				 * any unsolicited data.  It looks like
194230e7468fSPeter Dunlap 				 * we only support immediate data.  So what
194330e7468fSPeter Dunlap 				 * happens if we don't set ISCSI_FLAG_FINAL?
194430e7468fSPeter Dunlap 				 *
194530e7468fSPeter Dunlap 				 * Unless there's magic code somewhere that
194630e7468fSPeter Dunlap 				 * is sending the remaining PDU's we should
194730e7468fSPeter Dunlap 				 * simply set ISCSI_FLAG_FINAL and forget
194830e7468fSPeter Dunlap 				 * about sending unsolicited data.  The big
194930e7468fSPeter Dunlap 				 * win is the immediate data anyway for small
195030e7468fSPeter Dunlap 				 * PDU's.
195130e7468fSPeter Dunlap 				 */
195230e7468fSPeter Dunlap 				if ((pdu->isp_datalen == buflen) ||
195330e7468fSPeter Dunlap 				    (pdu->isp_datalen == first_burst_length)) {
1954fcf3ce44SJohn Forte 					ihp->flags |= ISCSI_FLAG_FINAL;
1955fcf3ce44SJohn Forte 				}
1956fcf3ce44SJohn Forte 
195730e7468fSPeter Dunlap 				hton24(ihp->dlength, pdu->isp_datalen);
1958fcf3ce44SJohn Forte 			}
1959fcf3ce44SJohn Forte 			/* total data transfer length */
1960fcf3ce44SJohn Forte 			ihp->data_length = htonl(buflen);
1961fcf3ce44SJohn Forte 		}
1962fcf3ce44SJohn Forte 	} else {
1963fcf3ce44SJohn Forte 		ihp->flags = ISCSI_FLAG_FINAL;
1964fcf3ce44SJohn Forte 	}
196530e7468fSPeter Dunlap 	icmdp->cmd_un.scsi.data_transferred += pdu->isp_datalen;
196630e7468fSPeter Dunlap 	/* XXX How is this different from the code above? */
196730e7468fSPeter Dunlap 	/* will idm send the next data command up to burst length? */
196830e7468fSPeter Dunlap 	/* send the burstlen if we haven't sent immediate data */
196930e7468fSPeter Dunlap 	/* CRM: should idm send difference min(buflen, first_burst) and  imm? */
197030e7468fSPeter Dunlap 	/*    (MIN(first_burst_length, buflen) - imdata > 0) */
197130e7468fSPeter Dunlap 	/* CRM_LATER: change this to generate unsolicited pdu */
197230e7468fSPeter Dunlap 	if ((buflen > 0) &&
197330e7468fSPeter Dunlap 	    ((bp->b_flags & B_READ) == 0) &&
197430e7468fSPeter Dunlap 	    (icp->conn_params.initial_r2t == 0) &&
197530e7468fSPeter Dunlap 	    pdu->isp_datalen == 0) {
197630e7468fSPeter Dunlap 
197730e7468fSPeter Dunlap 		pdu->isp_datalen = MIN(first_burst_length, buflen);
197830e7468fSPeter Dunlap 		if ((pdu->isp_datalen == buflen) ||
197930e7468fSPeter Dunlap 		    (pdu->isp_datalen == first_burst_length)) {
198030e7468fSPeter Dunlap 			ihp->flags |= ISCSI_FLAG_FINAL;
198130e7468fSPeter Dunlap 		}
198230e7468fSPeter Dunlap 		pdu->isp_data = (uint8_t *)icmdp->cmd_un.scsi.bp->b_un.b_addr;
198330e7468fSPeter Dunlap 		hton24(ihp->dlength, pdu->isp_datalen);
198430e7468fSPeter Dunlap 	}
198530e7468fSPeter Dunlap }
198630e7468fSPeter Dunlap 
198730e7468fSPeter Dunlap static void
198830e7468fSPeter Dunlap iscsi_tx_scsi_init_pkt(iscsi_cmd_t *icmdp, iscsi_scsi_cmd_hdr_t *ihp)
198930e7468fSPeter Dunlap {
199030e7468fSPeter Dunlap 	struct scsi_pkt *pkt;
199130e7468fSPeter Dunlap 
199230e7468fSPeter Dunlap 	pkt = icmdp->cmd_un.scsi.pkt;
199330e7468fSPeter Dunlap 	pkt->pkt_state = (STATE_GOT_BUS | STATE_GOT_TARGET);
199430e7468fSPeter Dunlap 	pkt->pkt_reason = CMD_INCOMPLETE;
1995fcf3ce44SJohn Forte 
1996fcf3ce44SJohn Forte 	/* tagged queuing */
1997fcf3ce44SJohn Forte 	if (pkt->pkt_flags & FLAG_HTAG) {
1998fcf3ce44SJohn Forte 		ihp->flags |= ISCSI_ATTR_HEAD_OF_QUEUE;
1999fcf3ce44SJohn Forte 	} else if (pkt->pkt_flags & FLAG_OTAG) {
2000fcf3ce44SJohn Forte 		ihp->flags |= ISCSI_ATTR_ORDERED;
2001fcf3ce44SJohn Forte 	} else if (pkt->pkt_flags & FLAG_STAG) {
2002fcf3ce44SJohn Forte 		ihp->flags |= ISCSI_ATTR_SIMPLE;
2003fcf3ce44SJohn Forte 	} else {
2004fcf3ce44SJohn Forte 		/* ihp->flags |= ISCSI_ATTR_UNTAGGED; */
2005fcf3ce44SJohn Forte 		/* EMPTY */
2006fcf3ce44SJohn Forte 	}
2007fcf3ce44SJohn Forte 
2008fcf3ce44SJohn Forte 	/* iscsi states lun is based on spc.2 */
2009fcf3ce44SJohn Forte 	ISCSI_LUN_BYTE_COPY(ihp->lun, icmdp->cmd_un.scsi.lun);
2010fcf3ce44SJohn Forte 
2011fcf3ce44SJohn Forte 	if (icmdp->cmd_un.scsi.cmdlen <= 16) {
2012fcf3ce44SJohn Forte 		/* copy the SCSI Command Block into the PDU */
2013fcf3ce44SJohn Forte 		bcopy(pkt->pkt_cdbp, ihp->scb,
2014fcf3ce44SJohn Forte 		    icmdp->cmd_un.scsi.cmdlen);
2015fcf3ce44SJohn Forte 	} else {
2016fcf3ce44SJohn Forte 		iscsi_addl_hdr_t *iahp;
2017fcf3ce44SJohn Forte 
2018fcf3ce44SJohn Forte 		iahp = (iscsi_addl_hdr_t *)ihp;
2019fcf3ce44SJohn Forte 
2020fcf3ce44SJohn Forte 		ihp->hlength = (ADDLHDRSZ(icmdp->cmd_un.scsi.cmdlen) -
2021fcf3ce44SJohn Forte 		    sizeof (iscsi_scsi_cmd_hdr_t) + 3) / 4;
2022fcf3ce44SJohn Forte 		iahp->ahs_hlen_hi = 0;
2023fcf3ce44SJohn Forte 		iahp->ahs_hlen_lo = (icmdp->cmd_un.scsi.cmdlen - 15);
2024fcf3ce44SJohn Forte 		iahp->ahs_key = 0x01;
2025fcf3ce44SJohn Forte 		iahp->ahs_resv = 0;
2026fcf3ce44SJohn Forte 		bcopy(pkt->pkt_cdbp, ihp->scb, 16);
202730e7468fSPeter Dunlap 		bcopy(((char *)pkt->pkt_cdbp) + 16, &iahp->ahs_extscb[0],
202830e7468fSPeter Dunlap 		    icmdp->cmd_un.scsi.cmdlen);
2029fcf3ce44SJohn Forte 	}
2030fcf3ce44SJohn Forte 
203130e7468fSPeter Dunlap 	/*
203230e7468fSPeter Dunlap 	 * Update all values before transfering.
203330e7468fSPeter Dunlap 	 * We should never touch the icmdp after
203430e7468fSPeter Dunlap 	 * transfering if there is no more data
203530e7468fSPeter Dunlap 	 * to send.  The only case the idm_pdu_tx()
203630e7468fSPeter Dunlap 	 * will fail is a on a connection disconnect
203730e7468fSPeter Dunlap 	 * in that case the command will be flushed.
203830e7468fSPeter Dunlap 	 */
203930e7468fSPeter Dunlap 	pkt->pkt_state |= STATE_SENT_CMD;
2040fcf3ce44SJohn Forte }
2041fcf3ce44SJohn Forte 
204230e7468fSPeter Dunlap static void
204330e7468fSPeter Dunlap iscsi_tx_scsi_init_task(iscsi_cmd_t *icmdp, iscsi_conn_t *icp,
204430e7468fSPeter Dunlap     iscsi_scsi_cmd_hdr_t *ihp)
2045fcf3ce44SJohn Forte {
204630e7468fSPeter Dunlap 	idm_task_t		*itp;
204730e7468fSPeter Dunlap 	struct buf		*bp		= NULL;
204830e7468fSPeter Dunlap 	uint32_t		data_length;
2049fcf3ce44SJohn Forte 
205030e7468fSPeter Dunlap 	bp = icmdp->cmd_un.scsi.bp;
2051fcf3ce44SJohn Forte 
205230e7468fSPeter Dunlap 	itp = icmdp->cmd_itp;
205330e7468fSPeter Dunlap 	ASSERT(itp != NULL);
205430e7468fSPeter Dunlap 	data_length = ntohl(ihp->data_length);
205530e7468fSPeter Dunlap 	ISCSI_IO_LOG(CE_NOTE,
205630e7468fSPeter Dunlap 	    "DEBUG: iscsi_tx_init_task: task_start: %p idt_tt: %x cmdsn: %x "
205730e7468fSPeter Dunlap 	    "sess_cmdsn: %x cmd: %p "
205830e7468fSPeter Dunlap 	    "cmdtype: %d datalen: %u",
205930e7468fSPeter Dunlap 	    (void *)itp, itp->idt_tt, ihp->cmdsn, icp->conn_sess->sess_cmdsn,
206030e7468fSPeter Dunlap 	    (void *)icmdp, icmdp->cmd_type, data_length);
206130e7468fSPeter Dunlap 	if (data_length > 0) {
206230e7468fSPeter Dunlap 		if (bp->b_flags & B_READ) {
206330e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.ibp_ibuf =
206430e7468fSPeter Dunlap 			    idm_buf_alloc(icp->conn_ic,
206530e7468fSPeter Dunlap 			    bp->b_un.b_addr, bp->b_bcount);
206630e7468fSPeter Dunlap 			if (icmdp->cmd_un.scsi.ibp_ibuf)
206730e7468fSPeter Dunlap 				idm_buf_bind_in(itp,
206830e7468fSPeter Dunlap 				    icmdp->cmd_un.scsi.ibp_ibuf);
206930e7468fSPeter Dunlap 		} else {
207030e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.ibp_obuf =
207130e7468fSPeter Dunlap 			    idm_buf_alloc(icp->conn_ic,
207230e7468fSPeter Dunlap 			    bp->b_un.b_addr, bp->b_bcount);
207330e7468fSPeter Dunlap 			if (icmdp->cmd_un.scsi.ibp_obuf)
207430e7468fSPeter Dunlap 				idm_buf_bind_out(itp,
207530e7468fSPeter Dunlap 				    icmdp->cmd_un.scsi.ibp_obuf);
207630e7468fSPeter Dunlap 		}
207730e7468fSPeter Dunlap 		ISCSI_IO_LOG(CE_NOTE,
207830e7468fSPeter Dunlap 		    "DEBUG: pdu_tx: task_start(%s): %p ic: %p idt_tt: %x "
207930e7468fSPeter Dunlap 		    "cmdsn: %x sess_cmdsn: %x sess_expcmdsn: %x obuf: %p "
208030e7468fSPeter Dunlap 		    "cmdp: %p cmdtype: %d "
208130e7468fSPeter Dunlap 		    "buflen: %lu " "bpaddr: %p datalen: %u ",
208230e7468fSPeter Dunlap 		    bp->b_flags & B_READ ? "B_READ" : "B_WRITE",
208330e7468fSPeter Dunlap 		    (void *)itp, (void *)icp->conn_ic,
208430e7468fSPeter Dunlap 		    itp->idt_tt, ihp->cmdsn,
208530e7468fSPeter Dunlap 		    icp->conn_sess->sess_cmdsn,
208630e7468fSPeter Dunlap 		    icp->conn_sess->sess_expcmdsn,
208730e7468fSPeter Dunlap 		    (void *)icmdp->cmd_un.scsi.ibp_ibuf,
208830e7468fSPeter Dunlap 		    (void *)icmdp, icmdp->cmd_type, bp->b_bcount,
208930e7468fSPeter Dunlap 		    (void *)bp->b_un.b_addr,
209030e7468fSPeter Dunlap 		    data_length);
209130e7468fSPeter Dunlap 	}
2092fcf3ce44SJohn Forte 
2093fcf3ce44SJohn Forte 	/*
209430e7468fSPeter Dunlap 	 * Task is now active
2095fcf3ce44SJohn Forte 	 */
209630e7468fSPeter Dunlap 	idm_task_start(itp, ISCSI_INI_TASK_TTT);
2097fcf3ce44SJohn Forte }
2098fcf3ce44SJohn Forte 
2099fcf3ce44SJohn Forte /*
210030e7468fSPeter Dunlap  * iscsi_tx_scsi -
210130e7468fSPeter Dunlap  *
2102fcf3ce44SJohn Forte  */
2103fcf3ce44SJohn Forte static iscsi_status_t
210430e7468fSPeter Dunlap iscsi_tx_scsi(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2105fcf3ce44SJohn Forte {
2106fcf3ce44SJohn Forte 	iscsi_status_t		rval		= ISCSI_STATUS_SUCCESS;
210730e7468fSPeter Dunlap 	iscsi_conn_t		*icp		= NULL;
210830e7468fSPeter Dunlap 	struct scsi_pkt		*pkt		= NULL;
210930e7468fSPeter Dunlap 	iscsi_scsi_cmd_hdr_t	*ihp		= NULL;
211030e7468fSPeter Dunlap 	int			cdblen		= 0;
211130e7468fSPeter Dunlap 	idm_pdu_t		*pdu;
211230e7468fSPeter Dunlap 	int			len;
2113fcf3ce44SJohn Forte 
2114fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2115fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2116fcf3ce44SJohn Forte 
211730e7468fSPeter Dunlap 	pdu = kmem_zalloc(sizeof (idm_pdu_t), KM_SLEEP);
211830e7468fSPeter Dunlap 
211930e7468fSPeter Dunlap 	pkt = icmdp->cmd_un.scsi.pkt;
212030e7468fSPeter Dunlap 	ASSERT(pkt != NULL);
212130e7468fSPeter Dunlap 	icp = icmdp->cmd_conn;
212230e7468fSPeter Dunlap 	ASSERT(icp != NULL);
212330e7468fSPeter Dunlap 
212430e7468fSPeter Dunlap 	/* Reset counts in case we are on a retry */
212530e7468fSPeter Dunlap 	icmdp->cmd_un.scsi.data_transferred = 0;
212630e7468fSPeter Dunlap 
212730e7468fSPeter Dunlap 	if (icmdp->cmd_un.scsi.cmdlen > DEF_CDB_LEN) {
212830e7468fSPeter Dunlap 		cdblen = icmdp->cmd_un.scsi.cmdlen;
212930e7468fSPeter Dunlap 		ihp = kmem_zalloc(ADDLHDRSZ(cdblen), KM_SLEEP);
213030e7468fSPeter Dunlap 		len = ADDLHDRSZ(cdblen);
213130e7468fSPeter Dunlap 	} else {
213230e7468fSPeter Dunlap 		/*
213330e7468fSPeter Dunlap 		 * only bzero the basic header; the additional header
213430e7468fSPeter Dunlap 		 * will be set up correctly later, if needed
213530e7468fSPeter Dunlap 		 */
213630e7468fSPeter Dunlap 		ihp = kmem_zalloc(sizeof (iscsi_scsi_cmd_hdr_t), KM_SLEEP);
213730e7468fSPeter Dunlap 		len = sizeof (iscsi_scsi_cmd_hdr_t);
2138fcf3ce44SJohn Forte 	}
2139fcf3ce44SJohn Forte 
214030e7468fSPeter Dunlap 	iscsi_tx_init_hdr(isp, icp, (iscsi_text_hdr_t *)ihp,
21412b79d384Sbing zhao - Sun Microsystems - Beijing China 	    ISCSI_OP_SCSI_CMD, icmdp);
214230e7468fSPeter Dunlap 
214330e7468fSPeter Dunlap 	idm_pdu_init(pdu, icp->conn_ic, (void *)icmdp, &iscsi_tx_done);
214430e7468fSPeter Dunlap 	idm_pdu_init_hdr(pdu, (uint8_t *)ihp, len);
214530e7468fSPeter Dunlap 	pdu->isp_data = NULL;
214630e7468fSPeter Dunlap 	pdu->isp_datalen = 0;
2147fcf3ce44SJohn Forte 
2148fcf3ce44SJohn Forte 	/*
214930e7468fSPeter Dunlap 	 * Sestion 12.11 of the iSCSI specification has a good table
215030e7468fSPeter Dunlap 	 * describing when uncolicited data and/or immediate data
215130e7468fSPeter Dunlap 	 * should be sent.
2152fcf3ce44SJohn Forte 	 */
2153fcf3ce44SJohn Forte 
215430e7468fSPeter Dunlap 	iscsi_tx_scsi_data(icmdp, ihp, icp, pdu);
215530e7468fSPeter Dunlap 
215630e7468fSPeter Dunlap 	iscsi_tx_scsi_init_pkt(icmdp, ihp);
215730e7468fSPeter Dunlap 
215830e7468fSPeter Dunlap 	/* Calls idm_task_start */
215930e7468fSPeter Dunlap 	iscsi_tx_scsi_init_task(icmdp, icp, ihp);
216030e7468fSPeter Dunlap 
2161fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2162fcf3ce44SJohn Forte 
216330e7468fSPeter Dunlap 	idm_pdu_tx(pdu);
2164fcf3ce44SJohn Forte 
21652b79d384Sbing zhao - Sun Microsystems - Beijing China 	icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_SENT;
21662b79d384Sbing zhao - Sun Microsystems - Beijing China 
216730e7468fSPeter Dunlap 	return (rval);
216830e7468fSPeter Dunlap }
2169fcf3ce44SJohn Forte 
2170fcf3ce44SJohn Forte 
217130e7468fSPeter Dunlap /* ARGSUSED */
217230e7468fSPeter Dunlap static void
217330e7468fSPeter Dunlap iscsi_tx_done(idm_pdu_t *pdu, idm_status_t status)
217430e7468fSPeter Dunlap {
217530e7468fSPeter Dunlap 	kmem_free((iscsi_hdr_t *)pdu->isp_hdr, pdu->isp_hdrlen);
217630e7468fSPeter Dunlap 	kmem_free(pdu, sizeof (idm_pdu_t));
217730e7468fSPeter Dunlap }
2178fcf3ce44SJohn Forte 
2179fcf3ce44SJohn Forte 
218030e7468fSPeter Dunlap static void
218130e7468fSPeter Dunlap iscsi_tx_pdu(iscsi_conn_t *icp, int opcode, void *hdr, int hdrlen,
218230e7468fSPeter Dunlap     iscsi_cmd_t *icmdp)
218330e7468fSPeter Dunlap {
218430e7468fSPeter Dunlap 	idm_pdu_t	*tx_pdu;
218530e7468fSPeter Dunlap 	iscsi_hdr_t	*ihp = (iscsi_hdr_t *)hdr;
2186fcf3ce44SJohn Forte 
218730e7468fSPeter Dunlap 	tx_pdu = kmem_zalloc(sizeof (idm_pdu_t), KM_SLEEP);
218830e7468fSPeter Dunlap 	ASSERT(tx_pdu != NULL);
2189fcf3ce44SJohn Forte 
219030e7468fSPeter Dunlap 	idm_pdu_init(tx_pdu, icp->conn_ic, icmdp, &iscsi_tx_done);
219130e7468fSPeter Dunlap 	idm_pdu_init_hdr(tx_pdu, hdr, hdrlen);
219230e7468fSPeter Dunlap 	if (opcode == ISCSI_OP_TEXT_CMD) {
219330e7468fSPeter Dunlap 		idm_pdu_init_data(tx_pdu,
219430e7468fSPeter Dunlap 		    (uint8_t *)icmdp->cmd_un.text.buf,
219530e7468fSPeter Dunlap 		    ntoh24(ihp->dlength));
2196fcf3ce44SJohn Forte 	}
2197fcf3ce44SJohn Forte 
219830e7468fSPeter Dunlap 	mutex_exit(&icp->conn_sess->sess_queue_pending.mutex);
219930e7468fSPeter Dunlap 	idm_pdu_tx(tx_pdu);
22002b79d384Sbing zhao - Sun Microsystems - Beijing China 	icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_SENT;
2201fcf3ce44SJohn Forte }
2202fcf3ce44SJohn Forte 
2203fcf3ce44SJohn Forte 
2204fcf3ce44SJohn Forte /*
2205fcf3ce44SJohn Forte  * iscsi_tx_nop -
2206fcf3ce44SJohn Forte  *
2207fcf3ce44SJohn Forte  */
2208fcf3ce44SJohn Forte static iscsi_status_t
2209fcf3ce44SJohn Forte iscsi_tx_nop(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2210fcf3ce44SJohn Forte {
2211fcf3ce44SJohn Forte 	iscsi_status_t		rval	= ISCSI_STATUS_SUCCESS;
2212fcf3ce44SJohn Forte 	iscsi_conn_t		*icp	= NULL;
221330e7468fSPeter Dunlap 	iscsi_nop_out_hdr_t	*inohp;
2214fcf3ce44SJohn Forte 
2215fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2216fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2217fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
2218fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2219fcf3ce44SJohn Forte 
222030e7468fSPeter Dunlap 	inohp = kmem_zalloc(sizeof (iscsi_nop_out_hdr_t), KM_SLEEP);
222130e7468fSPeter Dunlap 	ASSERT(inohp != NULL);
222230e7468fSPeter Dunlap 
222330e7468fSPeter Dunlap 	inohp->opcode	= ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
222430e7468fSPeter Dunlap 	inohp->flags	= ISCSI_FLAG_FINAL;
222530e7468fSPeter Dunlap 	inohp->itt	= icmdp->cmd_itt;
222630e7468fSPeter Dunlap 	inohp->ttt	= icmdp->cmd_ttt;
2227fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
22282b79d384Sbing zhao - Sun Microsystems - Beijing China 	icmdp->cmd_sn	= isp->sess_cmdsn;
222930e7468fSPeter Dunlap 	inohp->cmdsn	= htonl(isp->sess_cmdsn);
2230fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
223130e7468fSPeter Dunlap 	inohp->expstatsn	= htonl(icp->conn_expstatsn);
2232fcf3ce44SJohn Forte 	icp->conn_laststatsn = icp->conn_expstatsn;
223330e7468fSPeter Dunlap 	iscsi_tx_pdu(icp, ISCSI_OP_NOOP_OUT, inohp,
223430e7468fSPeter Dunlap 	    sizeof (iscsi_nop_out_hdr_t), icmdp);
2235fcf3ce44SJohn Forte 	return (rval);
2236fcf3ce44SJohn Forte }
2237fcf3ce44SJohn Forte 
2238fcf3ce44SJohn Forte 
2239fcf3ce44SJohn Forte /*
2240fcf3ce44SJohn Forte  * iscsi_tx_abort -
2241fcf3ce44SJohn Forte  *
2242fcf3ce44SJohn Forte  */
2243fcf3ce44SJohn Forte static iscsi_status_t
2244fcf3ce44SJohn Forte iscsi_tx_abort(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2245fcf3ce44SJohn Forte {
2246fcf3ce44SJohn Forte 	iscsi_status_t			rval	= ISCSI_STATUS_SUCCESS;
2247fcf3ce44SJohn Forte 	iscsi_conn_t			*icp	= NULL;
224830e7468fSPeter Dunlap 	iscsi_scsi_task_mgt_hdr_t	*istmh;
2249fcf3ce44SJohn Forte 
2250fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2251fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2252fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
2253fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2254fcf3ce44SJohn Forte 
225530e7468fSPeter Dunlap 	istmh = kmem_zalloc(sizeof (iscsi_scsi_task_mgt_hdr_t), KM_SLEEP);
225630e7468fSPeter Dunlap 	ASSERT(istmh != NULL);
2257fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
22582b79d384Sbing zhao - Sun Microsystems - Beijing China 	icmdp->cmd_sn	= isp->sess_cmdsn;
225930e7468fSPeter Dunlap 	istmh->cmdsn	= htonl(isp->sess_cmdsn);
2260fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
226130e7468fSPeter Dunlap 	istmh->expstatsn = htonl(icp->conn_expstatsn);
2262fcf3ce44SJohn Forte 	icp->conn_laststatsn = icp->conn_expstatsn;
226330e7468fSPeter Dunlap 	istmh->itt	= icmdp->cmd_itt;
226430e7468fSPeter Dunlap 	istmh->opcode	= ISCSI_OP_SCSI_TASK_MGT_MSG | ISCSI_OP_IMMEDIATE;
226530e7468fSPeter Dunlap 	istmh->function	= ISCSI_FLAG_FINAL | ISCSI_TM_FUNC_ABORT_TASK;
226630e7468fSPeter Dunlap 	ISCSI_LUN_BYTE_COPY(istmh->lun,
2267fcf3ce44SJohn Forte 	    icmdp->cmd_un.abort.icmdp->cmd_un.scsi.lun);
226830e7468fSPeter Dunlap 	istmh->rtt	= icmdp->cmd_un.abort.icmdp->cmd_itt;
226930e7468fSPeter Dunlap 	iscsi_tx_pdu(icp, ISCSI_OP_SCSI_TASK_MGT_MSG, istmh,
227030e7468fSPeter Dunlap 	    sizeof (iscsi_scsi_task_mgt_hdr_t), icmdp);
2271fcf3ce44SJohn Forte 
2272fcf3ce44SJohn Forte 	return (rval);
2273fcf3ce44SJohn Forte }
2274fcf3ce44SJohn Forte 
2275fcf3ce44SJohn Forte 
2276fcf3ce44SJohn Forte /*
2277fcf3ce44SJohn Forte  * iscsi_tx_reset -
2278fcf3ce44SJohn Forte  *
2279fcf3ce44SJohn Forte  */
2280fcf3ce44SJohn Forte static iscsi_status_t
2281fcf3ce44SJohn Forte iscsi_tx_reset(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2282fcf3ce44SJohn Forte {
2283fcf3ce44SJohn Forte 	iscsi_status_t			rval	= ISCSI_STATUS_SUCCESS;
2284fcf3ce44SJohn Forte 	iscsi_conn_t			*icp	= NULL;
228530e7468fSPeter Dunlap 	iscsi_scsi_task_mgt_hdr_t	*istmh;
2286fcf3ce44SJohn Forte 
2287fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2288fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2289fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
2290fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2291fcf3ce44SJohn Forte 
229230e7468fSPeter Dunlap 	istmh = kmem_zalloc(sizeof (iscsi_scsi_task_mgt_hdr_t), KM_SLEEP);
229330e7468fSPeter Dunlap 	ASSERT(istmh != NULL);
229430e7468fSPeter Dunlap 	istmh->opcode	= ISCSI_OP_SCSI_TASK_MGT_MSG | ISCSI_OP_IMMEDIATE;
2295fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
22962b79d384Sbing zhao - Sun Microsystems - Beijing China 	icmdp->cmd_sn	= isp->sess_cmdsn;
229730e7468fSPeter Dunlap 	istmh->cmdsn	= htonl(isp->sess_cmdsn);
2298fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
229930e7468fSPeter Dunlap 	istmh->expstatsn	= htonl(icp->conn_expstatsn);
230030e7468fSPeter Dunlap 	istmh->itt	= icmdp->cmd_itt;
2301fcf3ce44SJohn Forte 
2302fcf3ce44SJohn Forte 	switch (icmdp->cmd_un.reset.level) {
2303fcf3ce44SJohn Forte 	case RESET_LUN:
230430e7468fSPeter Dunlap 		istmh->function	= ISCSI_FLAG_FINAL |
2305fcf3ce44SJohn Forte 		    ISCSI_TM_FUNC_LOGICAL_UNIT_RESET;
230630e7468fSPeter Dunlap 		ISCSI_LUN_BYTE_COPY(istmh->lun, icmdp->cmd_lun->lun_num);
2307fcf3ce44SJohn Forte 		break;
2308fcf3ce44SJohn Forte 	case RESET_TARGET:
2309fcf3ce44SJohn Forte 	case RESET_BUS:
231030e7468fSPeter Dunlap 		istmh->function	= ISCSI_FLAG_FINAL |
2311fcf3ce44SJohn Forte 		    ISCSI_TM_FUNC_TARGET_WARM_RESET;
2312fcf3ce44SJohn Forte 		break;
2313fcf3ce44SJohn Forte 	default:
2314fcf3ce44SJohn Forte 		/* unsupported / unknown level */
2315fcf3ce44SJohn Forte 		ASSERT(FALSE);
2316fcf3ce44SJohn Forte 		break;
2317fcf3ce44SJohn Forte 	}
2318fcf3ce44SJohn Forte 
231930e7468fSPeter Dunlap 	iscsi_tx_pdu(icp, ISCSI_OP_SCSI_TASK_MGT_MSG, istmh,
232030e7468fSPeter Dunlap 	    sizeof (iscsi_scsi_task_mgt_hdr_t), icmdp);
2321fcf3ce44SJohn Forte 
2322fcf3ce44SJohn Forte 	return (rval);
2323fcf3ce44SJohn Forte }
2324fcf3ce44SJohn Forte 
2325fcf3ce44SJohn Forte 
2326fcf3ce44SJohn Forte /*
2327fcf3ce44SJohn Forte  * iscsi_tx_logout -
2328fcf3ce44SJohn Forte  *
2329fcf3ce44SJohn Forte  */
2330fcf3ce44SJohn Forte static iscsi_status_t
2331fcf3ce44SJohn Forte iscsi_tx_logout(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2332fcf3ce44SJohn Forte {
2333fcf3ce44SJohn Forte 	iscsi_status_t		rval	= ISCSI_STATUS_SUCCESS;
2334fcf3ce44SJohn Forte 	iscsi_conn_t		*icp	= NULL;
233530e7468fSPeter Dunlap 	iscsi_logout_hdr_t	*ilh;
2336fcf3ce44SJohn Forte 
2337fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2338fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2339fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
2340fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2341fcf3ce44SJohn Forte 
234230e7468fSPeter Dunlap 	ilh = kmem_zalloc(sizeof (iscsi_logout_hdr_t), KM_SLEEP);
234330e7468fSPeter Dunlap 	ilh->opcode	= ISCSI_OP_LOGOUT_CMD | ISCSI_OP_IMMEDIATE;
234430e7468fSPeter Dunlap 	ilh->flags	= ISCSI_FLAG_FINAL | ISCSI_LOGOUT_REASON_CLOSE_SESSION;
234530e7468fSPeter Dunlap 	ilh->itt		= icmdp->cmd_itt;
234630e7468fSPeter Dunlap 	ilh->cid		= icp->conn_cid;
2347fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
23482b79d384Sbing zhao - Sun Microsystems - Beijing China 	icmdp->cmd_sn	= isp->sess_cmdsn;
234930e7468fSPeter Dunlap 	ilh->cmdsn	= htonl(isp->sess_cmdsn);
2350fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
235130e7468fSPeter Dunlap 	ilh->expstatsn	= htonl(icp->conn_expstatsn);
235230e7468fSPeter Dunlap 	iscsi_tx_pdu(icp, ISCSI_OP_LOGOUT_CMD, ilh,
235330e7468fSPeter Dunlap 	    sizeof (iscsi_logout_hdr_t), icmdp);
2354fcf3ce44SJohn Forte 
2355fcf3ce44SJohn Forte 	return (rval);
2356fcf3ce44SJohn Forte }
2357fcf3ce44SJohn Forte 
2358fcf3ce44SJohn Forte /*
2359fcf3ce44SJohn Forte  * iscsi_tx_text - setup iSCSI text request header and send PDU with
2360fcf3ce44SJohn Forte  * data given in the buffer attached to the command.  For a single
2361fcf3ce44SJohn Forte  * text request, the target may need to send its response in multiple
2362fcf3ce44SJohn Forte  * text response.  In this case, empty text requests are sent after
2363fcf3ce44SJohn Forte  * each received response to notify the target the initiator is ready
2364fcf3ce44SJohn Forte  * for more response.  For the initial request, the data_len field in
2365fcf3ce44SJohn Forte  * the text specific portion of a command is set to the amount of data
2366fcf3ce44SJohn Forte  * the initiator wants to send as part of the request. If additional
2367fcf3ce44SJohn Forte  * empty text requests are required for long responses, the data_len
2368fcf3ce44SJohn Forte  * field is set to 0 by the iscsi_handle_text function.
2369fcf3ce44SJohn Forte  */
2370fcf3ce44SJohn Forte static iscsi_status_t
2371fcf3ce44SJohn Forte iscsi_tx_text(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2372fcf3ce44SJohn Forte {
2373fcf3ce44SJohn Forte 	iscsi_status_t		rval	= ISCSI_STATUS_SUCCESS;
2374fcf3ce44SJohn Forte 	iscsi_conn_t		*icp	= NULL;
237530e7468fSPeter Dunlap 	iscsi_text_hdr_t	*ith;
2376fcf3ce44SJohn Forte 
2377fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2378fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
2379fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2380fcf3ce44SJohn Forte 
238130e7468fSPeter Dunlap 	ith = kmem_zalloc(sizeof (iscsi_text_hdr_t), KM_SLEEP);
238230e7468fSPeter Dunlap 	ASSERT(ith != NULL);
238330e7468fSPeter Dunlap 	ith->flags	= ISCSI_FLAG_FINAL;
238430e7468fSPeter Dunlap 	hton24(ith->dlength, icmdp->cmd_un.text.data_len);
238530e7468fSPeter Dunlap 	ith->ttt		= icmdp->cmd_un.text.ttt;
238630e7468fSPeter Dunlap 	iscsi_tx_init_hdr(isp, icp, (iscsi_text_hdr_t *)ith,
23872b79d384Sbing zhao - Sun Microsystems - Beijing China 	    ISCSI_OP_TEXT_CMD, icmdp);
238830e7468fSPeter Dunlap 	bcopy(icmdp->cmd_un.text.lun, ith->rsvd4, sizeof (ith->rsvd4));
2389fcf3ce44SJohn Forte 
239030e7468fSPeter Dunlap 	iscsi_tx_pdu(icp, ISCSI_OP_TEXT_CMD, ith, sizeof (iscsi_text_hdr_t),
239130e7468fSPeter Dunlap 	    icmdp);
2392fcf3ce44SJohn Forte 
2393fcf3ce44SJohn Forte 	return (rval);
2394fcf3ce44SJohn Forte }
2395fcf3ce44SJohn Forte 
2396fcf3ce44SJohn Forte /*
2397fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
2398fcf3ce44SJohn Forte  * | End of protocol send routines					|
2399fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
2400fcf3ce44SJohn Forte  */
2401fcf3ce44SJohn Forte 
2402fcf3ce44SJohn Forte /*
2403fcf3ce44SJohn Forte  * iscsi_handle_abort -
2404fcf3ce44SJohn Forte  *
2405fcf3ce44SJohn Forte  */
2406fcf3ce44SJohn Forte void
2407fcf3ce44SJohn Forte iscsi_handle_abort(void *arg)
2408fcf3ce44SJohn Forte {
2409fcf3ce44SJohn Forte 	iscsi_sess_t	*isp		= NULL;
2410fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp		= (iscsi_cmd_t *)arg;
2411fcf3ce44SJohn Forte 	iscsi_cmd_t	*new_icmdp;
2412fcf3ce44SJohn Forte 	iscsi_conn_t	*icp;
2413fcf3ce44SJohn Forte 
2414fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2415fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
2416fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2417fcf3ce44SJohn Forte 	isp = icp->conn_sess;
2418fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2419fcf3ce44SJohn Forte 
2420fcf3ce44SJohn Forte 	/* there should only be one abort */
2421fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL);
2422fcf3ce44SJohn Forte 
2423fcf3ce44SJohn Forte 	new_icmdp = iscsi_cmd_alloc(icp, KM_SLEEP);
24242b79d384Sbing zhao - Sun Microsystems - Beijing China 	new_icmdp->cmd_type		    = ISCSI_CMD_TYPE_ABORT;
24252b79d384Sbing zhao - Sun Microsystems - Beijing China 	new_icmdp->cmd_lun		    = icmdp->cmd_lun;
24262b79d384Sbing zhao - Sun Microsystems - Beijing China 	new_icmdp->cmd_un.abort.icmdp	    = icmdp;
24272b79d384Sbing zhao - Sun Microsystems - Beijing China 	new_icmdp->cmd_conn		    = icmdp->cmd_conn;
24282b79d384Sbing zhao - Sun Microsystems - Beijing China 	icmdp->cmd_un.scsi.abort_icmdp	    = new_icmdp;
2429fcf3ce44SJohn Forte 
2430fcf3ce44SJohn Forte 	/* pending queue mutex is already held by timeout_checks */
2431fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(new_icmdp, ISCSI_CMD_EVENT_E1, isp);
2432fcf3ce44SJohn Forte }
2433fcf3ce44SJohn Forte 
243430e7468fSPeter Dunlap /*
243530e7468fSPeter Dunlap  * Callback from IDM indicating that the task has been suspended or aborted.
243630e7468fSPeter Dunlap  */
243730e7468fSPeter Dunlap void
243830e7468fSPeter Dunlap iscsi_task_aborted(idm_task_t *idt, idm_status_t status)
243930e7468fSPeter Dunlap {
244030e7468fSPeter Dunlap 	iscsi_cmd_t *icmdp = idt->idt_private;
244130e7468fSPeter Dunlap 	iscsi_conn_t *icp = icmdp->cmd_conn;
244230e7468fSPeter Dunlap 	iscsi_sess_t *isp = icp->conn_sess;
244330e7468fSPeter Dunlap 
244430e7468fSPeter Dunlap 	ASSERT(icmdp->cmd_conn != NULL);
244530e7468fSPeter Dunlap 
244630e7468fSPeter Dunlap 	switch (status) {
244730e7468fSPeter Dunlap 	case IDM_STATUS_SUSPENDED:
244830e7468fSPeter Dunlap 		/*
244930e7468fSPeter Dunlap 		 * If the task is suspended, it may be aborted later,
245030e7468fSPeter Dunlap 		 * so we can ignore this notification.
245130e7468fSPeter Dunlap 		 */
245230e7468fSPeter Dunlap 		break;
245330e7468fSPeter Dunlap 
245430e7468fSPeter Dunlap 	case IDM_STATUS_ABORTED:
245530e7468fSPeter Dunlap 		mutex_enter(&icp->conn_queue_active.mutex);
245630e7468fSPeter Dunlap 		iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E9, isp);
245730e7468fSPeter Dunlap 		mutex_exit(&icp->conn_queue_active.mutex);
245830e7468fSPeter Dunlap 		break;
245930e7468fSPeter Dunlap 
246030e7468fSPeter Dunlap 	default:
246130e7468fSPeter Dunlap 		/*
246230e7468fSPeter Dunlap 		 * Unexpected status.
246330e7468fSPeter Dunlap 		 */
246430e7468fSPeter Dunlap 		ASSERT(0);
246530e7468fSPeter Dunlap 	}
246630e7468fSPeter Dunlap 
246730e7468fSPeter Dunlap }
2468fcf3ce44SJohn Forte 
2469fcf3ce44SJohn Forte /*
2470fcf3ce44SJohn Forte  * iscsi_handle_nop -
2471fcf3ce44SJohn Forte  *
2472fcf3ce44SJohn Forte  */
2473fcf3ce44SJohn Forte static void
2474fcf3ce44SJohn Forte iscsi_handle_nop(iscsi_conn_t *icp, uint32_t itt, uint32_t ttt)
2475fcf3ce44SJohn Forte {
2476fcf3ce44SJohn Forte 	iscsi_sess_t	*isp	= NULL;
2477fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp	= NULL;
2478fcf3ce44SJohn Forte 
2479fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2480fcf3ce44SJohn Forte 	isp = icp->conn_sess;
2481fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2482fcf3ce44SJohn Forte 
2483fcf3ce44SJohn Forte 	icmdp = iscsi_cmd_alloc(icp, KM_NOSLEEP);
2484fcf3ce44SJohn Forte 	if (icmdp == NULL) {
2485fcf3ce44SJohn Forte 		return;
2486fcf3ce44SJohn Forte 	}
2487fcf3ce44SJohn Forte 
2488fcf3ce44SJohn Forte 	icmdp->cmd_type		= ISCSI_CMD_TYPE_NOP;
2489fcf3ce44SJohn Forte 	icmdp->cmd_itt		= itt;
2490fcf3ce44SJohn Forte 	icmdp->cmd_ttt		= ttt;
2491fcf3ce44SJohn Forte 	icmdp->cmd_lun		= NULL;
2492fcf3ce44SJohn Forte 	icp->conn_nop_lbolt	= ddi_get_lbolt();
2493fcf3ce44SJohn Forte 
2494fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
2495fcf3ce44SJohn Forte }
2496fcf3ce44SJohn Forte 
2497fcf3ce44SJohn Forte /*
24982b79d384Sbing zhao - Sun Microsystems - Beijing China  * iscsi_handle_reset - send reset request to the target
2499fcf3ce44SJohn Forte  *
2500fcf3ce44SJohn Forte  */
2501fcf3ce44SJohn Forte iscsi_status_t
2502fcf3ce44SJohn Forte iscsi_handle_reset(iscsi_sess_t *isp, int level, iscsi_lun_t *ilp)
2503fcf3ce44SJohn Forte {
2504fcf3ce44SJohn Forte 	iscsi_status_t	rval	= ISCSI_STATUS_SUCCESS;
2505fcf3ce44SJohn Forte 	iscsi_conn_t	*icp;
2506fcf3ce44SJohn Forte 	iscsi_cmd_t	icmd;
2507fcf3ce44SJohn Forte 
2508fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2509fcf3ce44SJohn Forte 
25102b79d384Sbing zhao - Sun Microsystems - Beijing China 	if (level == RESET_LUN) {
25112b79d384Sbing zhao - Sun Microsystems - Beijing China 		rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
25122b79d384Sbing zhao - Sun Microsystems - Beijing China 		ASSERT(ilp != NULL);
25132b79d384Sbing zhao - Sun Microsystems - Beijing China 		if (ilp->lun_state & ISCSI_LUN_STATE_BUSY) {
25142b79d384Sbing zhao - Sun Microsystems - Beijing China 			rw_exit(&isp->sess_lun_list_rwlock);
25152b79d384Sbing zhao - Sun Microsystems - Beijing China 			return (ISCSI_STATUS_SUCCESS);
25162b79d384Sbing zhao - Sun Microsystems - Beijing China 		}
25172b79d384Sbing zhao - Sun Microsystems - Beijing China 		ilp->lun_state |= ISCSI_LUN_STATE_BUSY;
25182b79d384Sbing zhao - Sun Microsystems - Beijing China 		rw_exit(&isp->sess_lun_list_rwlock);
25192b79d384Sbing zhao - Sun Microsystems - Beijing China 	} else {
25202b79d384Sbing zhao - Sun Microsystems - Beijing China 		mutex_enter(&isp->sess_reset_mutex);
25212b79d384Sbing zhao - Sun Microsystems - Beijing China 		if (isp->sess_reset_in_progress == B_TRUE) {
25222b79d384Sbing zhao - Sun Microsystems - Beijing China 			/*
25232b79d384Sbing zhao - Sun Microsystems - Beijing China 			 * If the reset is in progress, it is unnecessary
25242b79d384Sbing zhao - Sun Microsystems - Beijing China 			 * to send reset to the target redunantly.
25252b79d384Sbing zhao - Sun Microsystems - Beijing China 			 */
25262b79d384Sbing zhao - Sun Microsystems - Beijing China 			mutex_exit(&isp->sess_reset_mutex);
25272b79d384Sbing zhao - Sun Microsystems - Beijing China 			return (ISCSI_STATUS_SUCCESS);
25282b79d384Sbing zhao - Sun Microsystems - Beijing China 		}
25292b79d384Sbing zhao - Sun Microsystems - Beijing China 		isp->sess_reset_in_progress = B_TRUE;
25302b79d384Sbing zhao - Sun Microsystems - Beijing China 		mutex_exit(&isp->sess_reset_mutex);
25312b79d384Sbing zhao - Sun Microsystems - Beijing China 	}
25322b79d384Sbing zhao - Sun Microsystems - Beijing China 
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;
25412b79d384Sbing zhao - Sun Microsystems - Beijing China 	icmd.cmd_un.reset.response = SCSI_TCP_TM_RESP_COMPLETE;
25422b79d384Sbing zhao - Sun Microsystems - Beijing China 
2543fcf3ce44SJohn Forte 	mutex_init(&icmd.cmd_mutex, NULL, MUTEX_DRIVER, NULL);
2544fcf3ce44SJohn Forte 	cv_init(&icmd.cmd_completion, NULL, CV_DRIVER, NULL);
2545fcf3ce44SJohn Forte 	/*
2546fcf3ce44SJohn Forte 	 * If we received an IO and we are not in the
2547fcf3ce44SJohn Forte 	 * LOGGED_IN state we are in the process of
2548fcf3ce44SJohn Forte 	 * failing.  Just respond that we are BUSY.
2549fcf3ce44SJohn Forte 	 */
2550fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_state_mutex);
2551fcf3ce44SJohn Forte 	if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) {
2552fcf3ce44SJohn Forte 		/* We aren't connected to the target fake success */
2553fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
25542b79d384Sbing zhao - Sun Microsystems - Beijing China 
25552b79d384Sbing zhao - Sun Microsystems - Beijing China 		if (level == RESET_LUN) {
25562b79d384Sbing zhao - Sun Microsystems - Beijing China 			rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
25572b79d384Sbing zhao - Sun Microsystems - Beijing China 			ilp->lun_state &= ~ISCSI_LUN_STATE_BUSY;
25582b79d384Sbing zhao - Sun Microsystems - Beijing China 			rw_exit(&isp->sess_lun_list_rwlock);
25592b79d384Sbing zhao - Sun Microsystems - Beijing China 		} else {
25602b79d384Sbing zhao - Sun Microsystems - Beijing China 			mutex_enter(&isp->sess_reset_mutex);
25612b79d384Sbing zhao - Sun Microsystems - Beijing China 			isp->sess_reset_in_progress = B_FALSE;
25622b79d384Sbing zhao - Sun Microsystems - Beijing China 			mutex_exit(&isp->sess_reset_mutex);
25632b79d384Sbing zhao - Sun Microsystems - Beijing China 		}
25642b79d384Sbing zhao - Sun Microsystems - Beijing China 
2565fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SUCCESS);
2566fcf3ce44SJohn Forte 	}
2567fcf3ce44SJohn Forte 
2568fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
2569fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(&icmd, ISCSI_CMD_EVENT_E1, isp);
2570fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2571fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_state_mutex);
2572fcf3ce44SJohn Forte 
2573fcf3ce44SJohn Forte 	/* stall until completed */
2574fcf3ce44SJohn Forte 	mutex_enter(&icmd.cmd_mutex);
2575fcf3ce44SJohn Forte 	while (icmd.cmd_completed == B_FALSE) {
2576fcf3ce44SJohn Forte 		cv_wait(&icmd.cmd_completion, &icmd.cmd_mutex);
2577fcf3ce44SJohn Forte 	}
2578fcf3ce44SJohn Forte 	mutex_exit(&icmd.cmd_mutex);
2579fcf3ce44SJohn Forte 
2580fcf3ce44SJohn Forte 	/* copy rval */
2581fcf3ce44SJohn Forte 	rval = icmd.cmd_result;
2582fcf3ce44SJohn Forte 
2583fcf3ce44SJohn Forte 	if (rval == ISCSI_STATUS_SUCCESS) {
2584fcf3ce44SJohn Forte 		/*
2585fcf3ce44SJohn Forte 		 * Reset was successful.  We need to flush
2586fcf3ce44SJohn Forte 		 * all active IOs.
2587fcf3ce44SJohn Forte 		 */
2588fcf3ce44SJohn Forte 		rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
2589fcf3ce44SJohn Forte 		icp = isp->sess_conn_list;
2590fcf3ce44SJohn Forte 		while (icp != NULL) {
2591fcf3ce44SJohn Forte 			iscsi_cmd_t *t_icmdp = NULL;
25922b79d384Sbing zhao - Sun Microsystems - Beijing China 			iscsi_cmd_t *next_icmdp = NULL;
2593fcf3ce44SJohn Forte 
2594fcf3ce44SJohn Forte 			mutex_enter(&icp->conn_queue_active.mutex);
2595fcf3ce44SJohn Forte 			t_icmdp = icp->conn_queue_active.head;
2596fcf3ce44SJohn Forte 			while (t_icmdp != NULL) {
25972b79d384Sbing zhao - Sun Microsystems - Beijing China 				next_icmdp = t_icmdp->cmd_next;
25982b79d384Sbing zhao - Sun Microsystems - Beijing China 				mutex_enter(&t_icmdp->cmd_mutex);
25992b79d384Sbing zhao - Sun Microsystems - Beijing China 				if (!(t_icmdp->cmd_misc_flags &
26002b79d384Sbing zhao - Sun Microsystems - Beijing China 				    ISCSI_CMD_MISCFLAG_SENT)) {
26012b79d384Sbing zhao - Sun Microsystems - Beijing China 					/*
26022b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * Although this command is in the
26032b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * active queue, it has not been sent.
26042b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * Skip it.
26052b79d384Sbing zhao - Sun Microsystems - Beijing China 					 */
26062b79d384Sbing zhao - Sun Microsystems - Beijing China 					mutex_exit(&t_icmdp->cmd_mutex);
26072b79d384Sbing zhao - Sun Microsystems - Beijing China 					t_icmdp = next_icmdp;
26082b79d384Sbing zhao - Sun Microsystems - Beijing China 					continue;
26092b79d384Sbing zhao - Sun Microsystems - Beijing China 				}
26102b79d384Sbing zhao - Sun Microsystems - Beijing China 				if (level == RESET_LUN) {
26112b79d384Sbing zhao - Sun Microsystems - Beijing China 					if (icmd.cmd_lun == NULL ||
26122b79d384Sbing zhao - Sun Microsystems - Beijing China 					    t_icmdp->cmd_lun == NULL ||
26132b79d384Sbing zhao - Sun Microsystems - Beijing China 					    (icmd.cmd_lun->lun_num !=
26142b79d384Sbing zhao - Sun Microsystems - Beijing China 					    t_icmdp->cmd_lun->lun_num)) {
26152b79d384Sbing zhao - Sun Microsystems - Beijing China 						mutex_exit(&t_icmdp->cmd_mutex);
26162b79d384Sbing zhao - Sun Microsystems - Beijing China 						t_icmdp = next_icmdp;
26172b79d384Sbing zhao - Sun Microsystems - Beijing China 						continue;
26182b79d384Sbing zhao - Sun Microsystems - Beijing China 					}
26192b79d384Sbing zhao - Sun Microsystems - Beijing China 				}
26202b79d384Sbing zhao - Sun Microsystems - Beijing China 
26212b79d384Sbing zhao - Sun Microsystems - Beijing China 				if (icmd.cmd_sn == t_icmdp->cmd_sn) {
26222b79d384Sbing zhao - Sun Microsystems - Beijing China 					/*
26232b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * This command may be replied with
26242b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * UA sense key later. So currently
26252b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * it is not a suitable time to flush
26262b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * it. Mark its flag with FLUSH. There
26272b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * is no harm to keep it for a while.
26282b79d384Sbing zhao - Sun Microsystems - Beijing China 					 */
26292b79d384Sbing zhao - Sun Microsystems - Beijing China 					t_icmdp->cmd_misc_flags |=
26302b79d384Sbing zhao - Sun Microsystems - Beijing China 					    ISCSI_CMD_MISCFLAG_FLUSH;
26312b79d384Sbing zhao - Sun Microsystems - Beijing China 					if (t_icmdp->cmd_type ==
26322b79d384Sbing zhao - Sun Microsystems - Beijing China 					    ISCSI_CMD_TYPE_SCSI) {
26332b79d384Sbing zhao - Sun Microsystems - Beijing China 						t_icmdp->cmd_un.scsi.pkt_stat |=
26342b79d384Sbing zhao - Sun Microsystems - Beijing China 						    STAT_BUS_RESET;
26352b79d384Sbing zhao - Sun Microsystems - Beijing China 					}
26362b79d384Sbing zhao - Sun Microsystems - Beijing China 					mutex_exit(&t_icmdp->cmd_mutex);
26372b79d384Sbing zhao - Sun Microsystems - Beijing China 				} else if ((icmd.cmd_sn > t_icmdp->cmd_sn) ||
26382b79d384Sbing zhao - Sun Microsystems - Beijing China 				    ((t_icmdp->cmd_sn - icmd.cmd_sn) >
26392b79d384Sbing zhao - Sun Microsystems - Beijing China 				    ISCSI_CMD_SN_WRAP)) {
26402b79d384Sbing zhao - Sun Microsystems - Beijing China 					/*
26412b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * This reset request must act on all
26422b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * the commnds from the same session
26432b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * having a CmdSN lower than the task
26442b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * mangement CmdSN. So flush these
26452b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * commands here.
26462b79d384Sbing zhao - Sun Microsystems - Beijing China 					 */
26472b79d384Sbing zhao - Sun Microsystems - Beijing China 					if (t_icmdp->cmd_type ==
26482b79d384Sbing zhao - Sun Microsystems - Beijing China 					    ISCSI_CMD_TYPE_SCSI) {
26492b79d384Sbing zhao - Sun Microsystems - Beijing China 						t_icmdp->cmd_un.scsi.pkt_stat |=
26502b79d384Sbing zhao - Sun Microsystems - Beijing China 						    STAT_BUS_RESET;
26512b79d384Sbing zhao - Sun Microsystems - Beijing China 					}
26522b79d384Sbing zhao - Sun Microsystems - Beijing China 					mutex_exit(&t_icmdp->cmd_mutex);
26532b79d384Sbing zhao - Sun Microsystems - Beijing China 					iscsi_cmd_state_machine(t_icmdp,
26542b79d384Sbing zhao - Sun Microsystems - Beijing China 					    ISCSI_CMD_EVENT_E7, isp);
26552b79d384Sbing zhao - Sun Microsystems - Beijing China 				} else {
26562b79d384Sbing zhao - Sun Microsystems - Beijing China 					mutex_exit(&t_icmdp->cmd_mutex);
26572b79d384Sbing zhao - Sun Microsystems - Beijing China 				}
26582b79d384Sbing zhao - Sun Microsystems - Beijing China 
26592b79d384Sbing zhao - Sun Microsystems - Beijing China 				t_icmdp = next_icmdp;
2660fcf3ce44SJohn Forte 			}
2661fcf3ce44SJohn Forte 
2662fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_queue_active.mutex);
2663fcf3ce44SJohn Forte 			icp = icp->conn_next;
2664fcf3ce44SJohn Forte 		}
2665fcf3ce44SJohn Forte 		rw_exit(&isp->sess_conn_list_rwlock);
2666fcf3ce44SJohn Forte 	}
2667fcf3ce44SJohn Forte 
2668fcf3ce44SJohn Forte 	/* clean up */
2669fcf3ce44SJohn Forte 	cv_destroy(&icmd.cmd_completion);
2670fcf3ce44SJohn Forte 	mutex_destroy(&icmd.cmd_mutex);
2671fcf3ce44SJohn Forte 
26722b79d384Sbing zhao - Sun Microsystems - Beijing China 	if (level == RESET_LUN) {
26732b79d384Sbing zhao - Sun Microsystems - Beijing China 		rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
26742b79d384Sbing zhao - Sun Microsystems - Beijing China 		ilp->lun_state &= ~ISCSI_LUN_STATE_BUSY;
26752b79d384Sbing zhao - Sun Microsystems - Beijing China 		rw_exit(&isp->sess_lun_list_rwlock);
26762b79d384Sbing zhao - Sun Microsystems - Beijing China 	} else {
26772b79d384Sbing zhao - Sun Microsystems - Beijing China 		mutex_enter(&isp->sess_reset_mutex);
26782b79d384Sbing zhao - Sun Microsystems - Beijing China 		isp->sess_reset_in_progress = B_FALSE;
26792b79d384Sbing zhao - Sun Microsystems - Beijing China 		mutex_exit(&isp->sess_reset_mutex);
26802b79d384Sbing zhao - Sun Microsystems - Beijing China 	}
26812b79d384Sbing zhao - Sun Microsystems - Beijing China 
2682fcf3ce44SJohn Forte 	return (rval);
2683fcf3ce44SJohn Forte }
2684fcf3ce44SJohn Forte 
268530e7468fSPeter Dunlap /*
268692adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States  * iscsi_logout_start - task handler for deferred logout
268792adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States  * Acquire a hold before call, released in iscsi_handle_logout
268830e7468fSPeter Dunlap  */
268930e7468fSPeter Dunlap static void
269030e7468fSPeter Dunlap iscsi_logout_start(void *arg)
269130e7468fSPeter Dunlap {
269230e7468fSPeter Dunlap 	iscsi_task_t		*itp = (iscsi_task_t *)arg;
269330e7468fSPeter Dunlap 	iscsi_conn_t		*icp;
269430e7468fSPeter Dunlap 
269530e7468fSPeter Dunlap 	icp = (iscsi_conn_t *)itp->t_arg;
269630e7468fSPeter Dunlap 
269730e7468fSPeter Dunlap 	mutex_enter(&icp->conn_state_mutex);
269830e7468fSPeter Dunlap 	(void) iscsi_handle_logout(icp);
269930e7468fSPeter Dunlap 	mutex_exit(&icp->conn_state_mutex);
270030e7468fSPeter Dunlap }
2701fcf3ce44SJohn Forte 
2702fcf3ce44SJohn Forte /*
2703fcf3ce44SJohn Forte  * iscsi_handle_logout - This function will issue a logout for
2704fcf3ce44SJohn Forte  * the session from a specific connection.
270592adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States  * Acquire idm_conn_hold before call.  Released internally.
2706fcf3ce44SJohn Forte  */
2707fcf3ce44SJohn Forte iscsi_status_t
2708fcf3ce44SJohn Forte iscsi_handle_logout(iscsi_conn_t *icp)
2709fcf3ce44SJohn Forte {
2710fcf3ce44SJohn Forte 	iscsi_sess_t	*isp;
271130e7468fSPeter Dunlap 	idm_conn_t	*ic;
2712fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp;
2713fcf3ce44SJohn Forte 	int		rval;
2714fcf3ce44SJohn Forte 
2715fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2716fcf3ce44SJohn Forte 	isp = icp->conn_sess;
271730e7468fSPeter Dunlap 	ic = icp->conn_ic;
2718fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2719fcf3ce44SJohn Forte 	ASSERT(isp->sess_hba != NULL);
272030e7468fSPeter Dunlap 	ASSERT(mutex_owned(&icp->conn_state_mutex));
272130e7468fSPeter Dunlap 
272230e7468fSPeter Dunlap 	/*
272392adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	 * If the connection has already gone down (e.g. if the transport
272492adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	 * failed between when this LOGOUT was generated and now) then we
272592adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	 * can and must skip sending the LOGOUT.  Check the same condition
272692adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	 * we use below to determine that connection has "settled".
272730e7468fSPeter Dunlap 	 */
272892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	if ((icp->conn_state == ISCSI_CONN_STATE_FREE) ||
272992adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	    (icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
273092adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	    (icp->conn_state == ISCSI_CONN_STATE_POLLING)) {
273192adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		idm_conn_rele(ic);
273292adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		return (0);
273392adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	}
2734fcf3ce44SJohn Forte 
2735fcf3ce44SJohn Forte 	icmdp = iscsi_cmd_alloc(icp, KM_SLEEP);
2736fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2737fcf3ce44SJohn Forte 	icmdp->cmd_type		= ISCSI_CMD_TYPE_LOGOUT;
2738fcf3ce44SJohn Forte 	icmdp->cmd_result	= ISCSI_STATUS_SUCCESS;
2739fcf3ce44SJohn Forte 	icmdp->cmd_completed	= B_FALSE;
2740fcf3ce44SJohn Forte 
2741fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
2742fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
2743fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2744fcf3ce44SJohn Forte 
2745fcf3ce44SJohn Forte 	/*
2746fcf3ce44SJohn Forte 	 * release connection state mutex to avoid a deadlock.  This
2747fcf3ce44SJohn Forte 	 * function is called from within the connection state
2748fcf3ce44SJohn Forte 	 * machine with the lock held.  When the logout response is
2749fcf3ce44SJohn Forte 	 * received another call to the connection state machine
2750fcf3ce44SJohn Forte 	 * occurs which causes the deadlock
2751fcf3ce44SJohn Forte 	 */
2752fcf3ce44SJohn Forte 	mutex_exit(&icp->conn_state_mutex);
2753fcf3ce44SJohn Forte 
2754fcf3ce44SJohn Forte 	/* stall until completed */
2755fcf3ce44SJohn Forte 	mutex_enter(&icmdp->cmd_mutex);
2756fcf3ce44SJohn Forte 	while (icmdp->cmd_completed == B_FALSE) {
2757fcf3ce44SJohn Forte 		cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
2758fcf3ce44SJohn Forte 	}
2759fcf3ce44SJohn Forte 	mutex_exit(&icmdp->cmd_mutex);
2760fcf3ce44SJohn Forte 	mutex_enter(&icp->conn_state_mutex);
2761fcf3ce44SJohn Forte 
2762fcf3ce44SJohn Forte 	/* copy rval */
2763fcf3ce44SJohn Forte 	rval = icmdp->cmd_result;
2764fcf3ce44SJohn Forte 
2765fcf3ce44SJohn Forte 	/* clean up */
2766fcf3ce44SJohn Forte 	iscsi_cmd_free(icmdp);
2767fcf3ce44SJohn Forte 
276830e7468fSPeter Dunlap 	if (rval != 0) {
276930e7468fSPeter Dunlap 		/* If the logout failed then drop the connection */
277030e7468fSPeter Dunlap 		idm_ini_conn_disconnect(icp->conn_ic);
277130e7468fSPeter Dunlap 	}
277230e7468fSPeter Dunlap 
277330e7468fSPeter Dunlap 	/* stall until connection settles */
277430e7468fSPeter Dunlap 	while ((icp->conn_state != ISCSI_CONN_STATE_FREE) &&
277530e7468fSPeter Dunlap 	    (icp->conn_state != ISCSI_CONN_STATE_FAILED) &&
277630e7468fSPeter Dunlap 	    (icp->conn_state != ISCSI_CONN_STATE_POLLING)) {
277730e7468fSPeter Dunlap 		/* wait for transition */
277830e7468fSPeter Dunlap 		cv_wait(&icp->conn_state_change, &icp->conn_state_mutex);
277930e7468fSPeter Dunlap 	}
278030e7468fSPeter Dunlap 
278130e7468fSPeter Dunlap 	idm_conn_rele(ic);
278230e7468fSPeter Dunlap 
278330e7468fSPeter Dunlap 	/*
278430e7468fSPeter Dunlap 	 * Return value reflects whether the logout command completed --
278530e7468fSPeter Dunlap 	 * regardless of the return value the connection is closed and
278630e7468fSPeter Dunlap 	 * ready for reconnection.
278730e7468fSPeter Dunlap 	 */
2788fcf3ce44SJohn Forte 	return (rval);
2789fcf3ce44SJohn Forte }
2790fcf3ce44SJohn Forte 
279130e7468fSPeter Dunlap 
2792fcf3ce44SJohn Forte /*
2793fcf3ce44SJohn Forte  * iscsi_handle_text - main control function for iSCSI text requests.  This
2794fcf3ce44SJohn Forte  * function handles allocating the command, sending initial text request, and
2795fcf3ce44SJohn Forte  * handling long response sequence.
2796fcf3ce44SJohn Forte  * If a data overflow condition occurs, iscsi_handle_text continues to
2797fcf3ce44SJohn Forte  * receive responses until the all data has been recieved.  This allows
2798fcf3ce44SJohn Forte  * the full data length to be returned to the caller.
2799fcf3ce44SJohn Forte  */
2800fcf3ce44SJohn Forte iscsi_status_t
2801fcf3ce44SJohn Forte iscsi_handle_text(iscsi_conn_t *icp, char *buf, uint32_t buf_len,
2802fcf3ce44SJohn Forte     uint32_t data_len, uint32_t *rx_data_len)
2803fcf3ce44SJohn Forte {
2804fcf3ce44SJohn Forte 	iscsi_sess_t	*isp;
2805fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp;
2806fcf3ce44SJohn Forte 	iscsi_status_t	rval	= ISCSI_STATUS_SUCCESS;
2807fcf3ce44SJohn Forte 
2808fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2809fcf3ce44SJohn Forte 	ASSERT(buf != NULL);
2810fcf3ce44SJohn Forte 	ASSERT(rx_data_len != NULL);
2811fcf3ce44SJohn Forte 
2812fcf3ce44SJohn Forte 	isp = icp->conn_sess;
2813fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2814fcf3ce44SJohn Forte 
2815fcf3ce44SJohn Forte 	/*
2816fcf3ce44SJohn Forte 	 * Ensure data for text request command is not greater
2817fcf3ce44SJohn Forte 	 * than the negotiated maximum receive data seqment length.
2818fcf3ce44SJohn Forte 	 *
2819fcf3ce44SJohn Forte 	 * Although iSCSI allows for long text requests (multiple
2820fcf3ce44SJohn Forte 	 * pdus), this function places a restriction on text
2821fcf3ce44SJohn Forte 	 * requests to ensure it is handled by a single PDU.
2822fcf3ce44SJohn Forte 	 */
2823fcf3ce44SJohn Forte 	if (data_len > icp->conn_params.max_xmit_data_seg_len) {
2824fcf3ce44SJohn Forte 		return (ISCSI_STATUS_CMD_FAILED);
2825fcf3ce44SJohn Forte 	}
2826fcf3ce44SJohn Forte 
2827fcf3ce44SJohn Forte 	icmdp = iscsi_cmd_alloc(icp, KM_SLEEP);
2828fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2829fcf3ce44SJohn Forte 
2830fcf3ce44SJohn Forte 	icmdp->cmd_type		= ISCSI_CMD_TYPE_TEXT;
2831fcf3ce44SJohn Forte 	icmdp->cmd_result	= ISCSI_STATUS_SUCCESS;
2832d233de7eSJack Meng 	icmdp->cmd_misc_flags	&= ~ISCSI_CMD_MISCFLAG_FREE;
2833fcf3ce44SJohn Forte 	icmdp->cmd_completed	= B_FALSE;
2834fcf3ce44SJohn Forte 
2835fcf3ce44SJohn Forte 	icmdp->cmd_un.text.buf		= buf;
2836fcf3ce44SJohn Forte 	icmdp->cmd_un.text.buf_len	= buf_len;
2837fcf3ce44SJohn Forte 	icmdp->cmd_un.text.offset	= 0;
2838fcf3ce44SJohn Forte 	icmdp->cmd_un.text.data_len	= data_len;
2839fcf3ce44SJohn Forte 	icmdp->cmd_un.text.total_rx_len	= 0;
2840fcf3ce44SJohn Forte 	icmdp->cmd_un.text.ttt		= ISCSI_RSVD_TASK_TAG;
2841fcf3ce44SJohn Forte 	icmdp->cmd_un.text.stage	= ISCSI_CMD_TEXT_INITIAL_REQ;
2842fcf3ce44SJohn Forte 
2843fcf3ce44SJohn Forte long_text_response:
2844fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_state_mutex);
2845fcf3ce44SJohn Forte 	if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) {
2846fcf3ce44SJohn Forte 		iscsi_cmd_free(icmdp);
2847fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
2848fcf3ce44SJohn Forte 		return (ISCSI_STATUS_NO_CONN_LOGGED_IN);
2849fcf3ce44SJohn Forte 	}
2850fcf3ce44SJohn Forte 
2851fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
2852fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
2853fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2854fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_state_mutex);
2855fcf3ce44SJohn Forte 
2856fcf3ce44SJohn Forte 	/* stall until completed */
2857fcf3ce44SJohn Forte 	mutex_enter(&icmdp->cmd_mutex);
2858fcf3ce44SJohn Forte 	while (icmdp->cmd_completed == B_FALSE) {
2859fcf3ce44SJohn Forte 		cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
2860fcf3ce44SJohn Forte 	}
2861fcf3ce44SJohn Forte 	mutex_exit(&icmdp->cmd_mutex);
2862fcf3ce44SJohn Forte 
2863fcf3ce44SJohn Forte 	/*
2864fcf3ce44SJohn Forte 	 * check if error occured.  If data overflow occured, continue on
2865fcf3ce44SJohn Forte 	 * to ensure we get all data so that the full data length can be
2866fcf3ce44SJohn Forte 	 * returned to the user
2867fcf3ce44SJohn Forte 	 */
2868fcf3ce44SJohn Forte 	if ((icmdp->cmd_result != ISCSI_STATUS_SUCCESS) &&
2869fcf3ce44SJohn Forte 	    (icmdp->cmd_result != ISCSI_STATUS_DATA_OVERFLOW)) {
2870fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "iscsi: SendTarget discovery failed (%d)",
2871fcf3ce44SJohn Forte 		    icmdp->cmd_result);
2872fcf3ce44SJohn Forte 		rval = icmdp->cmd_result;
2873fcf3ce44SJohn Forte 		iscsi_cmd_free(icmdp);
2874fcf3ce44SJohn Forte 		return (rval);
2875fcf3ce44SJohn Forte 	}
2876fcf3ce44SJohn Forte 
2877fcf3ce44SJohn Forte 	/* check if this was a partial text PDU  */
2878fcf3ce44SJohn Forte 	if (icmdp->cmd_un.text.stage != ISCSI_CMD_TEXT_FINAL_RSP) {
2879fcf3ce44SJohn Forte 		/*
2880fcf3ce44SJohn Forte 		 * If a paritial text rexponse received, send an empty
2881fcf3ce44SJohn Forte 		 * text request.  This follows the behaviour specified
2882fcf3ce44SJohn Forte 		 * in RFC3720 regarding long text responses.
2883fcf3ce44SJohn Forte 		 */
2884d233de7eSJack Meng 		icmdp->cmd_misc_flags		&= ~ISCSI_CMD_MISCFLAG_FREE;
2885fcf3ce44SJohn Forte 		icmdp->cmd_completed		= B_FALSE;
2886fcf3ce44SJohn Forte 		icmdp->cmd_un.text.data_len	= 0;
2887fcf3ce44SJohn Forte 		icmdp->cmd_un.text.stage	= ISCSI_CMD_TEXT_CONTINUATION;
2888fcf3ce44SJohn Forte 		goto long_text_response;
2889fcf3ce44SJohn Forte 	}
2890fcf3ce44SJohn Forte 
2891fcf3ce44SJohn Forte 	/*
2892fcf3ce44SJohn Forte 	 * set total received data length.  If data overflow this would be
2893fcf3ce44SJohn Forte 	 * amount of data that would have been received if buffer large
2894fcf3ce44SJohn Forte 	 * enough.
2895fcf3ce44SJohn Forte 	 */
2896fcf3ce44SJohn Forte 	*rx_data_len = icmdp->cmd_un.text.total_rx_len;
2897fcf3ce44SJohn Forte 
2898fcf3ce44SJohn Forte 	/* copy rval */
2899fcf3ce44SJohn Forte 	rval = icmdp->cmd_result;
2900fcf3ce44SJohn Forte 
2901fcf3ce44SJohn Forte 	/* clean up  */
2902fcf3ce44SJohn Forte 	iscsi_cmd_free(icmdp);
2903fcf3ce44SJohn Forte 
2904fcf3ce44SJohn Forte 	return (rval);
2905fcf3ce44SJohn Forte }
2906fcf3ce44SJohn Forte 
2907fcf3ce44SJohn Forte /*
2908fcf3ce44SJohn Forte  * iscsi_handle_passthru - This function is used to send a uscsi_cmd
2909fcf3ce44SJohn Forte  * to a specific target lun.  This routine is used for internal purposes
2910fcf3ce44SJohn Forte  * during enumeration and via the ISCSI_USCSICMD IOCTL.  We restrict
2911fcf3ce44SJohn Forte  * the CDBs that can be issued to a target/lun to INQUIRY, REPORT_LUNS,
2912fcf3ce44SJohn Forte  * and READ_CAPACITY for security purposes.
2913fcf3ce44SJohn Forte  *
2914fcf3ce44SJohn Forte  * The logic here is broken into three phases.
2915fcf3ce44SJohn Forte  * 1) Allocate and initialize a pkt/icmdp
2916fcf3ce44SJohn Forte  * 2) Send the pkt/icmdp
2917fcf3ce44SJohn Forte  * 3) cv_wait for completion
2918fcf3ce44SJohn Forte  */
2919fcf3ce44SJohn Forte iscsi_status_t
2920fcf3ce44SJohn Forte iscsi_handle_passthru(iscsi_sess_t *isp, uint16_t lun, struct uscsi_cmd *ucmdp)
2921fcf3ce44SJohn Forte {
2922fcf3ce44SJohn Forte 	iscsi_status_t		rval		= ISCSI_STATUS_SUCCESS;
2923fcf3ce44SJohn Forte 	iscsi_cmd_t		*icmdp		= NULL;
2924fcf3ce44SJohn Forte 	struct scsi_pkt		*pkt		= NULL;
2925fcf3ce44SJohn Forte 	struct buf		*bp		= NULL;
2926fcf3ce44SJohn Forte 	struct scsi_arq_status  *arqstat	= NULL;
2927fcf3ce44SJohn Forte 	int			rqlen		= SENSE_LENGTH;
2928fcf3ce44SJohn Forte 
2929fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2930fcf3ce44SJohn Forte 	ASSERT(ucmdp != NULL);
2931fcf3ce44SJohn Forte 
2932fcf3ce44SJohn Forte 	/*
2933fcf3ce44SJohn Forte 	 * If the caller didn't provide a sense buffer we need
2934fcf3ce44SJohn Forte 	 * to allocation one to get the scsi status.
2935fcf3ce44SJohn Forte 	 */
2936fcf3ce44SJohn Forte 	if (ucmdp->uscsi_rqlen > SENSE_LENGTH) {
2937fcf3ce44SJohn Forte 		rqlen = ucmdp->uscsi_rqlen;
2938fcf3ce44SJohn Forte 	}
2939fcf3ce44SJohn Forte 
2940fcf3ce44SJohn Forte 	/*
2941fcf3ce44SJohn Forte 	 * Step 1. Setup structs - KM_SLEEP will always succeed
2942fcf3ce44SJohn Forte 	 */
2943fcf3ce44SJohn Forte 	bp = kmem_zalloc(sizeof (struct buf), KM_SLEEP);
2944fcf3ce44SJohn Forte 	ASSERT(bp != NULL);
2945fcf3ce44SJohn Forte 	pkt = kmem_zalloc(sizeof (struct scsi_pkt), KM_SLEEP);
2946fcf3ce44SJohn Forte 	ASSERT(pkt != NULL);
2947fcf3ce44SJohn Forte 	icmdp = iscsi_cmd_alloc(NULL, KM_SLEEP);
2948fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
2949fcf3ce44SJohn Forte 
2950fcf3ce44SJohn Forte 	/* setup bp structure */
2951fcf3ce44SJohn Forte 	bp->b_flags		= B_READ;
2952fcf3ce44SJohn Forte 	bp->b_bcount		= ucmdp->uscsi_buflen;
2953fcf3ce44SJohn Forte 	bp->b_un.b_addr		= ucmdp->uscsi_bufaddr;
2954fcf3ce44SJohn Forte 
2955fcf3ce44SJohn Forte 	/* setup scsi_pkt structure */
2956fcf3ce44SJohn Forte 	pkt->pkt_ha_private	= icmdp;
2957fcf3ce44SJohn Forte 	pkt->pkt_scbp		= kmem_zalloc(rqlen, KM_SLEEP);
2958fcf3ce44SJohn Forte 	pkt->pkt_cdbp		= kmem_zalloc(ucmdp->uscsi_cdblen, KM_SLEEP);
2959fcf3ce44SJohn Forte 	/* callback routine for passthru, will wake cv_wait */
2960fcf3ce44SJohn Forte 	pkt->pkt_comp		= iscsi_handle_passthru_callback;
2961fcf3ce44SJohn Forte 	pkt->pkt_time		= ucmdp->uscsi_timeout;
2962fcf3ce44SJohn Forte 
2963fcf3ce44SJohn Forte 	/* setup iscsi_cmd structure */
2964fcf3ce44SJohn Forte 	icmdp->cmd_lun			= NULL;
2965fcf3ce44SJohn Forte 	icmdp->cmd_type			= ISCSI_CMD_TYPE_SCSI;
2966fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.lun		= lun;
2967fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.pkt		= pkt;
2968fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.bp		= bp;
2969fcf3ce44SJohn Forte 	bcopy(ucmdp->uscsi_cdb, pkt->pkt_cdbp, ucmdp->uscsi_cdblen);
2970fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.cmdlen	= ucmdp->uscsi_cdblen;
2971fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.statuslen	= rqlen;
2972fcf3ce44SJohn Forte 	icmdp->cmd_crc_error_seen	= B_FALSE;
2973fcf3ce44SJohn Forte 	icmdp->cmd_completed		= B_FALSE;
2974fcf3ce44SJohn Forte 	icmdp->cmd_result		= ISCSI_STATUS_SUCCESS;
2975fcf3ce44SJohn Forte 
2976fcf3ce44SJohn Forte 	/*
2977fcf3ce44SJohn Forte 	 * Step 2. Push IO onto pending queue.  If we aren't in
2978fcf3ce44SJohn Forte 	 * FULL_FEATURE we need to fail the IO.
2979fcf3ce44SJohn Forte 	 */
2980fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_state_mutex);
2981fcf3ce44SJohn Forte 	if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) {
2982fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_state_mutex);
2983fcf3ce44SJohn Forte 
2984fcf3ce44SJohn Forte 		iscsi_cmd_free(icmdp);
2985fcf3ce44SJohn Forte 		kmem_free(pkt->pkt_cdbp, ucmdp->uscsi_cdblen);
2986fcf3ce44SJohn Forte 		kmem_free(pkt->pkt_scbp, rqlen);
2987fcf3ce44SJohn Forte 		kmem_free(pkt, sizeof (struct scsi_pkt));
2988fcf3ce44SJohn Forte 		kmem_free(bp, sizeof (struct buf));
2989fcf3ce44SJohn Forte 
2990fcf3ce44SJohn Forte 		return (ISCSI_STATUS_CMD_FAILED);
2991fcf3ce44SJohn Forte 	}
2992fcf3ce44SJohn Forte 
2993fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
2994fcf3ce44SJohn Forte 	iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
2995fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
2996fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_state_mutex);
2997fcf3ce44SJohn Forte 
2998fcf3ce44SJohn Forte 	/*
2999fcf3ce44SJohn Forte 	 * Step 3. Wait on cv_wait for completion routine
3000fcf3ce44SJohn Forte 	 */
3001fcf3ce44SJohn Forte 	mutex_enter(&icmdp->cmd_mutex);
3002fcf3ce44SJohn Forte 	while (icmdp->cmd_completed == B_FALSE) {
3003fcf3ce44SJohn Forte 		cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
3004fcf3ce44SJohn Forte 	}
3005fcf3ce44SJohn Forte 	mutex_exit(&icmdp->cmd_mutex);
3006fcf3ce44SJohn Forte 
3007fcf3ce44SJohn Forte 	/* copy rval */
3008fcf3ce44SJohn Forte 	rval = icmdp->cmd_result;
3009fcf3ce44SJohn Forte 
3010fcf3ce44SJohn Forte 	ucmdp->uscsi_resid = pkt->pkt_resid;
3011fcf3ce44SJohn Forte 
3012fcf3ce44SJohn Forte 	/* update scsi status */
3013fcf3ce44SJohn Forte 	arqstat = (struct scsi_arq_status *)pkt->pkt_scbp;
3014fcf3ce44SJohn Forte 	ucmdp->uscsi_status = ((char *)&arqstat->sts_status)[0];
3015fcf3ce44SJohn Forte 
3016fcf3ce44SJohn Forte 	/* copy request sense buffers if caller gave space */
3017fcf3ce44SJohn Forte 	if ((ucmdp->uscsi_rqlen > 0) &&
3018fcf3ce44SJohn Forte 	    (ucmdp->uscsi_rqbuf != NULL)) {
3019fcf3ce44SJohn Forte 		bcopy(arqstat, ucmdp->uscsi_rqbuf,
3020fcf3ce44SJohn Forte 		    MIN(sizeof (struct scsi_arq_status), rqlen));
3021fcf3ce44SJohn Forte 	}
3022fcf3ce44SJohn Forte 
3023fcf3ce44SJohn Forte 	/* clean up */
3024fcf3ce44SJohn Forte 	iscsi_cmd_free(icmdp);
3025fcf3ce44SJohn Forte 	kmem_free(pkt->pkt_cdbp, ucmdp->uscsi_cdblen);
3026fcf3ce44SJohn Forte 	kmem_free(pkt->pkt_scbp, rqlen);
3027fcf3ce44SJohn Forte 	kmem_free(pkt, sizeof (struct scsi_pkt));
3028fcf3ce44SJohn Forte 	kmem_free(bp, sizeof (struct buf));
3029fcf3ce44SJohn Forte 
3030fcf3ce44SJohn Forte 	return (rval);
3031fcf3ce44SJohn Forte }
3032fcf3ce44SJohn Forte 
3033fcf3ce44SJohn Forte 
3034fcf3ce44SJohn Forte /*
3035fcf3ce44SJohn Forte  * iscsi_handle_passthru_callback -
3036fcf3ce44SJohn Forte  *
3037fcf3ce44SJohn Forte  */
3038fcf3ce44SJohn Forte static void
3039fcf3ce44SJohn Forte iscsi_handle_passthru_callback(struct scsi_pkt *pkt)
3040fcf3ce44SJohn Forte {
3041fcf3ce44SJohn Forte 	iscsi_cmd_t		*icmdp  = NULL;
3042fcf3ce44SJohn Forte 
3043fcf3ce44SJohn Forte 	ASSERT(pkt != NULL);
3044fcf3ce44SJohn Forte 	icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private;
3045fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
3046fcf3ce44SJohn Forte 
3047fcf3ce44SJohn Forte 	mutex_enter(&icmdp->cmd_mutex);
3048fcf3ce44SJohn Forte 	icmdp->cmd_completed    = B_TRUE;
3049fcf3ce44SJohn Forte 	icmdp->cmd_result	= ISCSI_STATUS_SUCCESS;
3050fcf3ce44SJohn Forte 	cv_broadcast(&icmdp->cmd_completion);
3051fcf3ce44SJohn Forte 	mutex_exit(&icmdp->cmd_mutex);
3052fcf3ce44SJohn Forte 
3053fcf3ce44SJohn Forte }
3054fcf3ce44SJohn Forte 
305530e7468fSPeter Dunlap /*
305630e7468fSPeter Dunlap  * IDM callbacks
305730e7468fSPeter Dunlap  */
305830e7468fSPeter Dunlap void
305930e7468fSPeter Dunlap iscsi_build_hdr(idm_task_t *idm_task, idm_pdu_t *pdu, uint8_t opcode)
306030e7468fSPeter Dunlap {
306130e7468fSPeter Dunlap 	iscsi_cmd_t *icmdp = idm_task->idt_private;
306230e7468fSPeter Dunlap 	iscsi_conn_t *icp = icmdp->cmd_conn;
306330e7468fSPeter Dunlap 	iscsi_data_hdr_t *ihp = (iscsi_data_hdr_t *)pdu->isp_hdr;
306430e7468fSPeter Dunlap 
306530e7468fSPeter Dunlap 	mutex_enter(&icmdp->cmd_mutex);
306630e7468fSPeter Dunlap 	if (opcode == ISCSI_OP_SCSI_DATA) {
306730e7468fSPeter Dunlap 		uint32_t	data_sn;
306830e7468fSPeter Dunlap 		uint32_t	lun;
306930e7468fSPeter Dunlap 		icmdp = idm_task->idt_private;
307030e7468fSPeter Dunlap 		icp = icmdp->cmd_conn;
307130e7468fSPeter Dunlap 		ihp->opcode	= opcode;
307230e7468fSPeter Dunlap 		ihp->itt	= icmdp->cmd_itt;
307330e7468fSPeter Dunlap 		ihp->ttt	= idm_task->idt_r2t_ttt;
307430e7468fSPeter Dunlap 		ihp->expstatsn	= htonl(icp->conn_expstatsn);
307530e7468fSPeter Dunlap 		icp->conn_laststatsn = icp->conn_expstatsn;
307630e7468fSPeter Dunlap 		data_sn = ntohl(ihp->datasn);
307730e7468fSPeter Dunlap 		data_sn++;
307830e7468fSPeter Dunlap 		lun = icmdp->cmd_un.scsi.lun;
307930e7468fSPeter Dunlap 		ISCSI_LUN_BYTE_COPY(ihp->lun, lun);
308030e7468fSPeter Dunlap 		/* CRM: upate_flow_control */
308130e7468fSPeter Dunlap 		ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_build_hdr"
308230e7468fSPeter Dunlap 		    "(ISCSI_OP_SCSI_DATA): task: %p icp: %p ic: %p itt: %x "
308330e7468fSPeter Dunlap 		    "exp: %d data_sn: %d", (void *)idm_task, (void *)icp,
308430e7468fSPeter Dunlap 		    (void *)icp->conn_ic, ihp->itt, icp->conn_expstatsn,
308530e7468fSPeter Dunlap 		    data_sn);
308630e7468fSPeter Dunlap 	} else {
308730e7468fSPeter Dunlap 		cmn_err(CE_WARN, "iscsi_build_hdr: unprocessed build "
308830e7468fSPeter Dunlap 		    "header opcode: %x", opcode);
308930e7468fSPeter Dunlap 	}
309030e7468fSPeter Dunlap 	mutex_exit(&icmdp->cmd_mutex);
309130e7468fSPeter Dunlap }
309230e7468fSPeter Dunlap 
309330e7468fSPeter Dunlap static void
309430e7468fSPeter Dunlap iscsi_process_rsp_status(iscsi_sess_t *isp, iscsi_conn_t *icp,
309530e7468fSPeter Dunlap     idm_status_t status)
309630e7468fSPeter Dunlap {
309730e7468fSPeter Dunlap 	switch (status) {
309830e7468fSPeter Dunlap 	case IDM_STATUS_SUCCESS:
309930e7468fSPeter Dunlap 		if ((isp->sess_state == ISCSI_SESS_STATE_IN_FLUSH) &&
310030e7468fSPeter Dunlap 		    (icp->conn_queue_active.count == 0)) {
310130e7468fSPeter Dunlap 			iscsi_drop_conn_cleanup(icp);
310230e7468fSPeter Dunlap 		}
310330e7468fSPeter Dunlap 		break;
310430e7468fSPeter Dunlap 	case IDM_STATUS_PROTOCOL_ERROR:
310530e7468fSPeter Dunlap 		KSTAT_INC_CONN_ERR_PROTOCOL(icp);
310630e7468fSPeter Dunlap 		iscsi_drop_conn_cleanup(icp);
310730e7468fSPeter Dunlap 		break;
310830e7468fSPeter Dunlap 	default:
310930e7468fSPeter Dunlap 		break;
311030e7468fSPeter Dunlap 	}
311130e7468fSPeter Dunlap }
311230e7468fSPeter Dunlap 
311330e7468fSPeter Dunlap static void
311430e7468fSPeter Dunlap iscsi_drop_conn_cleanup(iscsi_conn_t *icp) {
311530e7468fSPeter Dunlap 	mutex_enter(&icp->conn_state_mutex);
311630e7468fSPeter Dunlap 	idm_ini_conn_disconnect(icp->conn_ic);
311730e7468fSPeter Dunlap 	mutex_exit(&icp->conn_state_mutex);
311830e7468fSPeter Dunlap }
311930e7468fSPeter Dunlap 
312030e7468fSPeter Dunlap void
312130e7468fSPeter Dunlap iscsi_rx_error_pdu(idm_conn_t *ic, idm_pdu_t *pdu, idm_status_t status)
312230e7468fSPeter Dunlap {
312330e7468fSPeter Dunlap 	iscsi_conn_t *icp = (iscsi_conn_t *)ic->ic_handle;
312430e7468fSPeter Dunlap 	iscsi_sess_t *isp;
312530e7468fSPeter Dunlap 
312630e7468fSPeter Dunlap 	ASSERT(icp != NULL);
312730e7468fSPeter Dunlap 	isp = icp->conn_sess;
312830e7468fSPeter Dunlap 	ASSERT(isp != NULL);
312930e7468fSPeter Dunlap 	iscsi_process_rsp_status(isp, icp, status);
313030e7468fSPeter Dunlap 	idm_pdu_complete(pdu, status);
313130e7468fSPeter Dunlap }
313230e7468fSPeter Dunlap 
313330e7468fSPeter Dunlap void
313430e7468fSPeter Dunlap iscsi_rx_misc_pdu(idm_conn_t *ic, idm_pdu_t *pdu)
313530e7468fSPeter Dunlap {
313630e7468fSPeter Dunlap 	iscsi_conn_t 		*icp;
313730e7468fSPeter Dunlap 	iscsi_hdr_t		*ihp	= (iscsi_hdr_t *)pdu->isp_hdr;
313830e7468fSPeter Dunlap 	iscsi_sess_t		*isp;
313930e7468fSPeter Dunlap 	idm_status_t		status;
314030e7468fSPeter Dunlap 
314130e7468fSPeter Dunlap 	icp = ic->ic_handle;
314230e7468fSPeter Dunlap 	isp = icp->conn_sess;
314330e7468fSPeter Dunlap 	isp->sess_rx_lbolt = icp->conn_rx_lbolt = ddi_get_lbolt();
314430e7468fSPeter Dunlap 	switch (ihp->opcode & ISCSI_OPCODE_MASK) {
314530e7468fSPeter Dunlap 	case ISCSI_OP_LOGIN_RSP:
314630e7468fSPeter Dunlap 		status = iscsi_rx_process_login_pdu(ic, pdu);
314730e7468fSPeter Dunlap 		idm_pdu_complete(pdu, status);
314830e7468fSPeter Dunlap 		break;
314930e7468fSPeter Dunlap 	case ISCSI_OP_LOGOUT_RSP:
315030e7468fSPeter Dunlap 		status = iscsi_rx_process_logout_rsp(ic, pdu);
315130e7468fSPeter Dunlap 		idm_pdu_complete(pdu, status);
315230e7468fSPeter Dunlap 		break;
315330e7468fSPeter Dunlap 	case ISCSI_OP_REJECT_MSG:
315430e7468fSPeter Dunlap 		status = iscsi_rx_process_reject_rsp(ic, pdu);
315530e7468fSPeter Dunlap 		break;
315630e7468fSPeter Dunlap 	case ISCSI_OP_SCSI_TASK_MGT_RSP:
315730e7468fSPeter Dunlap 		status = iscsi_rx_process_task_mgt_rsp(ic, pdu);
315830e7468fSPeter Dunlap 		idm_pdu_complete(pdu, status);
315930e7468fSPeter Dunlap 		break;
316030e7468fSPeter Dunlap 	case ISCSI_OP_NOOP_IN:
316130e7468fSPeter Dunlap 		status = iscsi_rx_process_nop(ic, pdu);
316230e7468fSPeter Dunlap 		idm_pdu_complete(pdu, status);
316330e7468fSPeter Dunlap 		break;
316430e7468fSPeter Dunlap 	case ISCSI_OP_ASYNC_EVENT:
316530e7468fSPeter Dunlap 		status = iscsi_rx_process_async_rsp(ic, pdu);
316630e7468fSPeter Dunlap 		break;
316730e7468fSPeter Dunlap 	case ISCSI_OP_TEXT_RSP:
316830e7468fSPeter Dunlap 		status = iscsi_rx_process_text_rsp(ic, pdu);
316930e7468fSPeter Dunlap 		idm_pdu_complete(pdu, status);
317030e7468fSPeter Dunlap 		break;
317130e7468fSPeter Dunlap 	default:
317230e7468fSPeter Dunlap 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error "
317330e7468fSPeter Dunlap 		    "- received misc unsupported opcode 0x%02x",
317430e7468fSPeter Dunlap 		    icp->conn_oid, ihp->opcode);
317530e7468fSPeter Dunlap 		status = IDM_STATUS_PROTOCOL_ERROR;
317630e7468fSPeter Dunlap 		break;
317730e7468fSPeter Dunlap 	}
317830e7468fSPeter Dunlap 	iscsi_process_rsp_status(isp, icp, status);
317930e7468fSPeter Dunlap }
318030e7468fSPeter Dunlap 
3181fcf3ce44SJohn Forte /*
3182fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3183fcf3ce44SJohn Forte  * | Beginning of completion routines					|
3184fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3185fcf3ce44SJohn Forte  */
3186fcf3ce44SJohn Forte 
3187fcf3ce44SJohn Forte /*
3188fcf3ce44SJohn Forte  * iscsi_ic_thread -
3189fcf3ce44SJohn Forte  */
3190fcf3ce44SJohn Forte void
3191fcf3ce44SJohn Forte iscsi_ic_thread(iscsi_thread_t *thread, void *arg)
3192fcf3ce44SJohn Forte {
3193fcf3ce44SJohn Forte 	iscsi_sess_t	*isp = (iscsi_sess_t *)arg;
3194fcf3ce44SJohn Forte 	int		ret;
3195fcf3ce44SJohn Forte 	iscsi_queue_t	q;
3196fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp;
3197fcf3ce44SJohn Forte 	iscsi_cmd_t	*next_icmdp;
3198fcf3ce44SJohn Forte 
3199fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
3200fcf3ce44SJohn Forte 	ASSERT(thread != NULL);
3201fcf3ce44SJohn Forte 	ASSERT(thread->signature == SIG_ISCSI_THREAD);
3202fcf3ce44SJohn Forte 
3203fcf3ce44SJohn Forte 	for (;;) {
3204fcf3ce44SJohn Forte 
3205fcf3ce44SJohn Forte 		/*
3206fcf3ce44SJohn Forte 		 * We wait till iodone or somebody else wakes us up.
3207fcf3ce44SJohn Forte 		 */
3208fcf3ce44SJohn Forte 		ret = iscsi_thread_wait(thread, -1);
3209fcf3ce44SJohn Forte 
3210fcf3ce44SJohn Forte 		/*
3211fcf3ce44SJohn Forte 		 * The value should never be negative since we never timeout.
3212fcf3ce44SJohn Forte 		 */
3213fcf3ce44SJohn Forte 		ASSERT(ret >= 0);
3214fcf3ce44SJohn Forte 
3215fcf3ce44SJohn Forte 		q.count = 0;
3216fcf3ce44SJohn Forte 		q.head  = NULL;
3217fcf3ce44SJohn Forte 		q.tail  = NULL;
3218fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_queue_completion.mutex);
3219fcf3ce44SJohn Forte 		icmdp = isp->sess_queue_completion.head;
3220fcf3ce44SJohn Forte 		while (icmdp != NULL) {
3221fcf3ce44SJohn Forte 			next_icmdp = icmdp->cmd_next;
3222fcf3ce44SJohn Forte 			mutex_enter(&icmdp->cmd_mutex);
3223fcf3ce44SJohn Forte 			/*
3224fcf3ce44SJohn Forte 			 * check if the associated r2t/abort has finished
322530e7468fSPeter Dunlap 			 * yet.  If not, don't complete the command.
3226fcf3ce44SJohn Forte 			 */
3227fcf3ce44SJohn Forte 			if ((icmdp->cmd_un.scsi.r2t_icmdp == NULL) &&
322830e7468fSPeter Dunlap 			    (icmdp->cmd_un.scsi.abort_icmdp == NULL)) {
3229fcf3ce44SJohn Forte 				mutex_exit(&icmdp->cmd_mutex);
3230fcf3ce44SJohn Forte 				(void) iscsi_dequeue_cmd(&isp->
3231fcf3ce44SJohn Forte 				    sess_queue_completion.head,
3232fcf3ce44SJohn Forte 				    &isp->sess_queue_completion.tail,
3233fcf3ce44SJohn Forte 				    icmdp);
3234fcf3ce44SJohn Forte 				--isp->sess_queue_completion.count;
3235fcf3ce44SJohn Forte 				iscsi_enqueue_cmd_head(&q.head,
3236fcf3ce44SJohn Forte 				    &q.tail, icmdp);
323730e7468fSPeter Dunlap 			} else {
3238fcf3ce44SJohn Forte 				mutex_exit(&icmdp->cmd_mutex);
323930e7468fSPeter Dunlap 			}
3240fcf3ce44SJohn Forte 			icmdp = next_icmdp;
3241fcf3ce44SJohn Forte 		}
3242fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_queue_completion.mutex);
3243fcf3ce44SJohn Forte 		icmdp = q.head;
3244fcf3ce44SJohn Forte 		while (icmdp != NULL) {
3245fcf3ce44SJohn Forte 			next_icmdp = icmdp->cmd_next;
3246fcf3ce44SJohn Forte 			iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E8, isp);
3247fcf3ce44SJohn Forte 			icmdp = next_icmdp;
3248fcf3ce44SJohn Forte 		}
3249fcf3ce44SJohn Forte 
3250fcf3ce44SJohn Forte 		if (ret > 0)
3251fcf3ce44SJohn Forte 			/* Somebody woke us up to work */
3252fcf3ce44SJohn Forte 			continue;
3253fcf3ce44SJohn Forte 		else
3254fcf3ce44SJohn Forte 			/*
3255fcf3ce44SJohn Forte 			 * Somebody woke us up to kill ourselves. We will
3256fcf3ce44SJohn Forte 			 * make sure, however that the completion queue is
3257fcf3ce44SJohn Forte 			 * empty before leaving.  After we've done that it
3258fcf3ce44SJohn Forte 			 * is the originator of the signal that has to make
3259fcf3ce44SJohn Forte 			 * sure no other SCSI command is posted.
3260fcf3ce44SJohn Forte 			 */
3261fcf3ce44SJohn Forte 			break;
3262fcf3ce44SJohn Forte 	}
3263fcf3ce44SJohn Forte 
3264fcf3ce44SJohn Forte }
3265fcf3ce44SJohn Forte 
3266fcf3ce44SJohn Forte /*
3267fcf3ce44SJohn Forte  * iscsi_iodone -
3268fcf3ce44SJohn Forte  *
3269fcf3ce44SJohn Forte  */
3270fcf3ce44SJohn Forte void
3271fcf3ce44SJohn Forte iscsi_iodone(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
3272fcf3ce44SJohn Forte {
3273fcf3ce44SJohn Forte 	struct scsi_pkt		*pkt	= NULL;
3274fcf3ce44SJohn Forte 	struct buf		*bp	= icmdp->cmd_un.scsi.bp;
3275fcf3ce44SJohn Forte 
3276fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
3277fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
3278fcf3ce44SJohn Forte 	pkt = icmdp->cmd_un.scsi.pkt;
3279fcf3ce44SJohn Forte 	ASSERT(pkt != NULL);
3280fcf3ce44SJohn Forte 
3281fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL);
3282fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_un.scsi.r2t_icmdp == NULL);
3283fcf3ce44SJohn Forte 	if (pkt->pkt_reason == CMD_CMPLT) {
3284fcf3ce44SJohn Forte 		if (bp) {
3285fcf3ce44SJohn Forte 			if (bp->b_flags & B_READ) {
3286fcf3ce44SJohn Forte 				KSTAT_SESS_RX_IO_DONE(isp, bp->b_bcount);
3287fcf3ce44SJohn Forte 			} else {
3288fcf3ce44SJohn Forte 				KSTAT_SESS_TX_IO_DONE(isp, bp->b_bcount);
3289fcf3ce44SJohn Forte 			}
3290fcf3ce44SJohn Forte 		}
3291fcf3ce44SJohn Forte 	}
3292fcf3ce44SJohn Forte 
3293fcf3ce44SJohn Forte 	if (pkt->pkt_flags & FLAG_NOINTR) {
3294fcf3ce44SJohn Forte 		cv_broadcast(&icmdp->cmd_completion);
3295fcf3ce44SJohn Forte 		mutex_exit(&icmdp->cmd_mutex);
3296fcf3ce44SJohn Forte 	} else {
3297fcf3ce44SJohn Forte 		/*
3298fcf3ce44SJohn Forte 		 * Release mutex.  As soon as callback is
3299fcf3ce44SJohn Forte 		 * issued the caller may destroy the command.
3300fcf3ce44SJohn Forte 		 */
3301fcf3ce44SJohn Forte 		mutex_exit(&icmdp->cmd_mutex);
3302fcf3ce44SJohn Forte 		/*
3303fcf3ce44SJohn Forte 		 * We can't just directly call the pk_comp routine.  In
3304fcf3ce44SJohn Forte 		 * many error cases the target driver will use the calling
3305fcf3ce44SJohn Forte 		 * thread to re-drive error handling (reset, retries...)
3306fcf3ce44SJohn Forte 		 * back into the hba driver (iscsi).  If the target redrives
3307fcf3ce44SJohn Forte 		 * a reset back into the iscsi driver off this thead we have
3308fcf3ce44SJohn Forte 		 * a chance of deadlocking. So instead use the io completion
3309fcf3ce44SJohn Forte 		 * thread.
3310fcf3ce44SJohn Forte 		 */
3311fcf3ce44SJohn Forte 		(*icmdp->cmd_un.scsi.pkt->pkt_comp)(icmdp->cmd_un.scsi.pkt);
3312fcf3ce44SJohn Forte 	}
3313fcf3ce44SJohn Forte }
3314fcf3ce44SJohn Forte 
3315fcf3ce44SJohn Forte /*
3316fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3317fcf3ce44SJohn Forte  * | End of completion routines						|
3318fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3319fcf3ce44SJohn Forte  */
3320fcf3ce44SJohn Forte 
3321fcf3ce44SJohn Forte /*
3322fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3323fcf3ce44SJohn Forte  * | Beginning of watchdog routines					|
3324fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3325fcf3ce44SJohn Forte  */
3326fcf3ce44SJohn Forte 
3327fcf3ce44SJohn Forte /*
3328fcf3ce44SJohn Forte  * iscsi_watchdog_thread -
3329fcf3ce44SJohn Forte  *
3330fcf3ce44SJohn Forte  */
3331fcf3ce44SJohn Forte void
3332fcf3ce44SJohn Forte iscsi_wd_thread(iscsi_thread_t *thread, void *arg)
3333fcf3ce44SJohn Forte {
3334fcf3ce44SJohn Forte 	iscsi_sess_t	*isp = (iscsi_sess_t *)arg;
3335fcf3ce44SJohn Forte 	int		rc = 1;
3336fcf3ce44SJohn Forte 
3337fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
3338fcf3ce44SJohn Forte 
3339fcf3ce44SJohn Forte 	while (rc != NULL) {
3340fcf3ce44SJohn Forte 
3341fcf3ce44SJohn Forte 		iscsi_timeout_checks(isp);
3342fcf3ce44SJohn Forte 		iscsi_nop_checks(isp);
3343fcf3ce44SJohn Forte 
3344fcf3ce44SJohn Forte 		rc = iscsi_thread_wait(thread, SEC_TO_TICK(1));
3345fcf3ce44SJohn Forte 	}
3346fcf3ce44SJohn Forte }
3347fcf3ce44SJohn Forte 
3348fcf3ce44SJohn Forte /*
3349fcf3ce44SJohn Forte  * iscsi_timeout_checks -
3350fcf3ce44SJohn Forte  *
3351fcf3ce44SJohn Forte  */
3352fcf3ce44SJohn Forte static void
3353fcf3ce44SJohn Forte iscsi_timeout_checks(iscsi_sess_t *isp)
3354fcf3ce44SJohn Forte {
3355fcf3ce44SJohn Forte 	clock_t		now = ddi_get_lbolt();
3356fcf3ce44SJohn Forte 	iscsi_conn_t	*icp;
335730e7468fSPeter Dunlap 	iscsi_cmd_t	*icmdp, *nicmdp;
3358fcf3ce44SJohn Forte 
3359fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
3360fcf3ce44SJohn Forte 
3361fcf3ce44SJohn Forte 	/* PENDING */
3362fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_state_mutex);
3363fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_pending.mutex);
3364fcf3ce44SJohn Forte 	for (icmdp = isp->sess_queue_pending.head;
3365fcf3ce44SJohn Forte 	    icmdp; icmdp = nicmdp) {
3366fcf3ce44SJohn Forte 		nicmdp = icmdp->cmd_next;
3367fcf3ce44SJohn Forte 
3368fcf3ce44SJohn Forte 		/* Skip entries with no timeout */
3369fcf3ce44SJohn Forte 		if (icmdp->cmd_lbolt_timeout == 0)
3370fcf3ce44SJohn Forte 			continue;
3371fcf3ce44SJohn Forte 
3372fcf3ce44SJohn Forte 		/*
3373fcf3ce44SJohn Forte 		 * Skip pending queue entries for cmd_type values that depend
3374fcf3ce44SJohn Forte 		 * on having an open cmdsn window for successfull transition
3375fcf3ce44SJohn Forte 		 * from pending to the active (i.e. ones that depend on
3376fcf3ce44SJohn Forte 		 * sess_cmdsn .vs. sess_maxcmdsn). For them, the timer starts
3377fcf3ce44SJohn Forte 		 * when they are successfully moved to the active queue by
3378fcf3ce44SJohn Forte 		 * iscsi_cmd_state_pending() code.
3379fcf3ce44SJohn Forte 		 */
3380d233de7eSJack Meng 		/*
3381d233de7eSJack Meng 		 * If the cmd is stuck, at least give it a chance
3382d233de7eSJack Meng 		 * to timeout
3383d233de7eSJack Meng 		 */
3384d233de7eSJack Meng 		if (((icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) ||
3385d233de7eSJack Meng 		    (icmdp->cmd_type == ISCSI_CMD_TYPE_TEXT)) &&
3386d233de7eSJack Meng 		    !(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_STUCK))
3387fcf3ce44SJohn Forte 			continue;
3388fcf3ce44SJohn Forte 
3389fcf3ce44SJohn Forte 		/* Skip if timeout still in the future */
3390fcf3ce44SJohn Forte 		if (now <= icmdp->cmd_lbolt_timeout)
3391fcf3ce44SJohn Forte 			continue;
3392fcf3ce44SJohn Forte 
3393fcf3ce44SJohn Forte 		/* timeout */
3394fcf3ce44SJohn Forte 		iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E6, isp);
3395fcf3ce44SJohn Forte 	}
3396fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_pending.mutex);
3397fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_state_mutex);
3398fcf3ce44SJohn Forte 
3399fcf3ce44SJohn Forte 	rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
3400fcf3ce44SJohn Forte 	icp = isp->sess_conn_list;
3401fcf3ce44SJohn Forte 	while (icp != NULL) {
3402fcf3ce44SJohn Forte 
3403aff4bce5Syi zhang - Sun Microsystems - Beijing China 		icp->conn_timeout = B_FALSE;
3404fcf3ce44SJohn Forte 		/* ACTIVE */
3405fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
3406fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_queue_pending.mutex);
3407fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_queue_active.mutex);
3408fcf3ce44SJohn Forte 		for (icmdp = icp->conn_queue_active.head;
3409fcf3ce44SJohn Forte 		    icmdp; icmdp = nicmdp) {
3410fcf3ce44SJohn Forte 			nicmdp = icmdp->cmd_next;
3411fcf3ce44SJohn Forte 
3412aff4bce5Syi zhang - Sun Microsystems - Beijing China 			if (iscsi_nop_timeout_checks(icmdp) == B_TRUE) {
3413aff4bce5Syi zhang - Sun Microsystems - Beijing China 				icp->conn_timeout = B_TRUE;
3414aff4bce5Syi zhang - Sun Microsystems - Beijing China 			}
3415aff4bce5Syi zhang - Sun Microsystems - Beijing China 
3416fcf3ce44SJohn Forte 			/* Skip entries with no timeout */
3417fcf3ce44SJohn Forte 			if (icmdp->cmd_lbolt_timeout == 0)
3418fcf3ce44SJohn Forte 				continue;
3419fcf3ce44SJohn Forte 
34202b79d384Sbing zhao - Sun Microsystems - Beijing China 			/*
34212b79d384Sbing zhao - Sun Microsystems - Beijing China 			 * Skip if command is not active or not needed
34222b79d384Sbing zhao - Sun Microsystems - Beijing China 			 * to flush.
34232b79d384Sbing zhao - Sun Microsystems - Beijing China 			 */
34242b79d384Sbing zhao - Sun Microsystems - Beijing China 			if (icmdp->cmd_state != ISCSI_CMD_STATE_ACTIVE &&
34252b79d384Sbing zhao - Sun Microsystems - Beijing China 			    !(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_FLUSH))
3426fcf3ce44SJohn Forte 				continue;
3427fcf3ce44SJohn Forte 
3428fcf3ce44SJohn Forte 			/* Skip if timeout still in the future */
3429fcf3ce44SJohn Forte 			if (now <= icmdp->cmd_lbolt_timeout)
3430fcf3ce44SJohn Forte 				continue;
3431fcf3ce44SJohn Forte 
34322b79d384Sbing zhao - Sun Microsystems - Beijing China 			if (icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_FLUSH) {
34332b79d384Sbing zhao - Sun Microsystems - Beijing China 				/*
34342b79d384Sbing zhao - Sun Microsystems - Beijing China 				 * This command is left during target reset,
34352b79d384Sbing zhao - Sun Microsystems - Beijing China 				 * we can flush it now.
34362b79d384Sbing zhao - Sun Microsystems - Beijing China 				 */
34372b79d384Sbing zhao - Sun Microsystems - Beijing China 				iscsi_cmd_state_machine(icmdp,
34382b79d384Sbing zhao - Sun Microsystems - Beijing China 				    ISCSI_CMD_EVENT_E7, isp);
34392b79d384Sbing zhao - Sun Microsystems - Beijing China 			} else if (icmdp->cmd_state == ISCSI_CMD_STATE_ACTIVE) {
34402b79d384Sbing zhao - Sun Microsystems - Beijing China 				/* timeout */
34412b79d384Sbing zhao - Sun Microsystems - Beijing China 				iscsi_cmd_state_machine(icmdp,
34422b79d384Sbing zhao - Sun Microsystems - Beijing China 				    ISCSI_CMD_EVENT_E6, isp);
34432b79d384Sbing zhao - Sun Microsystems - Beijing China 			}
34442b79d384Sbing zhao - Sun Microsystems - Beijing China 
3445fcf3ce44SJohn Forte 		}
3446fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
3447fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_queue_pending.mutex);
3448fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
3449fcf3ce44SJohn Forte 
3450fcf3ce44SJohn Forte 		icp = icp->conn_next;
3451fcf3ce44SJohn Forte 	}
3452aff4bce5Syi zhang - Sun Microsystems - Beijing China 
3453aff4bce5Syi zhang - Sun Microsystems - Beijing China 	icp = isp->sess_conn_list;
3454aff4bce5Syi zhang - Sun Microsystems - Beijing China 	while (icp != NULL) {
3455aff4bce5Syi zhang - Sun Microsystems - Beijing China 		if (icp->conn_timeout == B_TRUE) {
3456aff4bce5Syi zhang - Sun Microsystems - Beijing China 			/* timeout on this connect detected */
3457aff4bce5Syi zhang - Sun Microsystems - Beijing China 			idm_ini_conn_disconnect(icp->conn_ic);
3458aff4bce5Syi zhang - Sun Microsystems - Beijing China 			icp->conn_timeout = B_FALSE;
3459aff4bce5Syi zhang - Sun Microsystems - Beijing China 		}
3460aff4bce5Syi zhang - Sun Microsystems - Beijing China 		icp = icp->conn_next;
3461aff4bce5Syi zhang - Sun Microsystems - Beijing China 	}
3462fcf3ce44SJohn Forte 	rw_exit(&isp->sess_conn_list_rwlock);
3463fcf3ce44SJohn Forte }
3464fcf3ce44SJohn Forte 
3465fcf3ce44SJohn Forte /*
3466fcf3ce44SJohn Forte  * iscsi_nop_checks - sends a NOP on idle connections
3467fcf3ce44SJohn Forte  *
3468fcf3ce44SJohn Forte  * This function walks the connections on a session and
3469fcf3ce44SJohn Forte  * issues NOPs on those connections that are in FULL
3470fcf3ce44SJohn Forte  * FEATURE mode and have not received data for the
3471fcf3ce44SJohn Forte  * time period specified by iscsi_nop_delay (global).
3472fcf3ce44SJohn Forte  */
3473fcf3ce44SJohn Forte static void
3474fcf3ce44SJohn Forte iscsi_nop_checks(iscsi_sess_t *isp)
3475fcf3ce44SJohn Forte {
3476fcf3ce44SJohn Forte 	iscsi_conn_t	*icp;
3477fcf3ce44SJohn Forte 
3478fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
3479fcf3ce44SJohn Forte 
3480fcf3ce44SJohn Forte 	if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) {
3481fcf3ce44SJohn Forte 		return;
3482fcf3ce44SJohn Forte 	}
3483fcf3ce44SJohn Forte 
3484fcf3ce44SJohn Forte 	rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
3485fcf3ce44SJohn Forte 	icp = isp->sess_conn_act;
3486fcf3ce44SJohn Forte 	if (icp != NULL) {
3487fcf3ce44SJohn Forte 
3488fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
3489fcf3ce44SJohn Forte 		if ((ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state)) &&
3490fcf3ce44SJohn Forte 		    (ddi_get_lbolt() > isp->sess_conn_act->conn_rx_lbolt +
3491fcf3ce44SJohn Forte 		    SEC_TO_TICK(iscsi_nop_delay)) && (ddi_get_lbolt() >
3492fcf3ce44SJohn Forte 		    isp->sess_conn_act->conn_nop_lbolt +
3493fcf3ce44SJohn Forte 		    SEC_TO_TICK(iscsi_nop_delay))) {
3494fcf3ce44SJohn Forte 
3495fcf3ce44SJohn Forte 			/*
3496fcf3ce44SJohn Forte 			 * We haven't received anything from the
3497fcf3ce44SJohn Forte 			 * target is a defined period of time,
3498fcf3ce44SJohn Forte 			 * send NOP to see if the target is alive.
3499fcf3ce44SJohn Forte 			 */
3500fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_queue_pending.mutex);
3501fcf3ce44SJohn Forte 			iscsi_handle_nop(isp->sess_conn_act,
3502fcf3ce44SJohn Forte 			    0, ISCSI_RSVD_TASK_TAG);
3503fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_queue_pending.mutex);
3504fcf3ce44SJohn Forte 		}
3505fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_state_mutex);
3506fcf3ce44SJohn Forte 
3507fcf3ce44SJohn Forte 		icp = icp->conn_next;
3508fcf3ce44SJohn Forte 	}
3509fcf3ce44SJohn Forte 	rw_exit(&isp->sess_conn_list_rwlock);
3510fcf3ce44SJohn Forte }
3511fcf3ce44SJohn Forte 
3512aff4bce5Syi zhang - Sun Microsystems - Beijing China static boolean_t
3513aff4bce5Syi zhang - Sun Microsystems - Beijing China iscsi_nop_timeout_checks(iscsi_cmd_t *icmdp)
3514aff4bce5Syi zhang - Sun Microsystems - Beijing China {
3515aff4bce5Syi zhang - Sun Microsystems - Beijing China 	if (icmdp->cmd_type == ISCSI_CMD_TYPE_NOP) {
3516aff4bce5Syi zhang - Sun Microsystems - Beijing China 		if ((ddi_get_lbolt() - icmdp->cmd_lbolt_active) >
3517aff4bce5Syi zhang - Sun Microsystems - Beijing China 		    SEC_TO_TICK(ISCSI_CONN_TIEMOUT_DETECT)) {
3518aff4bce5Syi zhang - Sun Microsystems - Beijing China 			return (B_TRUE);
3519aff4bce5Syi zhang - Sun Microsystems - Beijing China 		} else {
3520aff4bce5Syi zhang - Sun Microsystems - Beijing China 			return (B_FALSE);
3521aff4bce5Syi zhang - Sun Microsystems - Beijing China 		}
3522aff4bce5Syi zhang - Sun Microsystems - Beijing China 	}
3523aff4bce5Syi zhang - Sun Microsystems - Beijing China 	return (B_FALSE);
3524aff4bce5Syi zhang - Sun Microsystems - Beijing China }
3525fcf3ce44SJohn Forte /*
3526fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3527fcf3ce44SJohn Forte  * | End of wd routines						|
3528fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
3529fcf3ce44SJohn Forte  */
35302b79d384Sbing zhao - Sun Microsystems - Beijing China 
35312b79d384Sbing zhao - Sun Microsystems - Beijing China /*
35322b79d384Sbing zhao - Sun Microsystems - Beijing China  * iscsi_flush_cmd_after_reset - flush commands after reset
35332b79d384Sbing zhao - Sun Microsystems - Beijing China  *
35342b79d384Sbing zhao - Sun Microsystems - Beijing China  * Here we will flush all the commands in the same connection whose cmdsn is
35352b79d384Sbing zhao - Sun Microsystems - Beijing China  * less than the one received with the Unit Attention.
35362b79d384Sbing zhao - Sun Microsystems - Beijing China  */
35372b79d384Sbing zhao - Sun Microsystems - Beijing China static void
35382b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_flush_cmd_after_reset(uint32_t cmd_sn, uint16_t lun_num,
35392b79d384Sbing zhao - Sun Microsystems - Beijing China     iscsi_conn_t *icp)
35402b79d384Sbing zhao - Sun Microsystems - Beijing China {
35412b79d384Sbing zhao - Sun Microsystems - Beijing China 	iscsi_cmd_t	*t_icmdp    = NULL;
35422b79d384Sbing zhao - Sun Microsystems - Beijing China 	iscsi_cmd_t	*next_icmdp = NULL;
35432b79d384Sbing zhao - Sun Microsystems - Beijing China 
35442b79d384Sbing zhao - Sun Microsystems - Beijing China 	ASSERT(icp != NULL);
35452b79d384Sbing zhao - Sun Microsystems - Beijing China 
35462b79d384Sbing zhao - Sun Microsystems - Beijing China 	t_icmdp = icp->conn_queue_active.head;
35472b79d384Sbing zhao - Sun Microsystems - Beijing China 	while (t_icmdp != NULL) {
35482b79d384Sbing zhao - Sun Microsystems - Beijing China 		next_icmdp = t_icmdp->cmd_next;
35492b79d384Sbing zhao - Sun Microsystems - Beijing China 		mutex_enter(&t_icmdp->cmd_mutex);
35502b79d384Sbing zhao - Sun Microsystems - Beijing China 		/*
35512b79d384Sbing zhao - Sun Microsystems - Beijing China 		 * We will flush the commands whose cmdsn is less than the one
35522b79d384Sbing zhao - Sun Microsystems - Beijing China 		 * got Unit Attention.
35532b79d384Sbing zhao - Sun Microsystems - Beijing China 		 * Here we will check for wrap by subtracting and compare to
35542b79d384Sbing zhao - Sun Microsystems - Beijing China 		 * 1/2 of a 32 bit number, if greater then we wrapped.
35552b79d384Sbing zhao - Sun Microsystems - Beijing China 		 */
35562b79d384Sbing zhao - Sun Microsystems - Beijing China 		if ((t_icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_SENT) &&
35572b79d384Sbing zhao - Sun Microsystems - Beijing China 		    ((cmd_sn > t_icmdp->cmd_sn) ||
35582b79d384Sbing zhao - Sun Microsystems - Beijing China 		    ((t_icmdp->cmd_sn - cmd_sn) >
35592b79d384Sbing zhao - Sun Microsystems - Beijing China 		    ISCSI_CMD_SN_WRAP))) {
35602b79d384Sbing zhao - Sun Microsystems - Beijing China 			if (t_icmdp->cmd_lun != NULL &&
35612b79d384Sbing zhao - Sun Microsystems - Beijing China 			    t_icmdp->cmd_lun->lun_num == lun_num) {
35622b79d384Sbing zhao - Sun Microsystems - Beijing China 				t_icmdp->cmd_misc_flags |=
35632b79d384Sbing zhao - Sun Microsystems - Beijing China 				    ISCSI_CMD_MISCFLAG_FLUSH;
35642b79d384Sbing zhao - Sun Microsystems - Beijing China 				if (t_icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
35652b79d384Sbing zhao - Sun Microsystems - Beijing China 					t_icmdp->cmd_un.scsi.pkt_stat |=
35662b79d384Sbing zhao - Sun Microsystems - Beijing China 					    STAT_BUS_RESET;
35672b79d384Sbing zhao - Sun Microsystems - Beijing China 				}
35682b79d384Sbing zhao - Sun Microsystems - Beijing China 			}
35692b79d384Sbing zhao - Sun Microsystems - Beijing China 		}
35702b79d384Sbing zhao - Sun Microsystems - Beijing China 		mutex_exit(&t_icmdp->cmd_mutex);
35712b79d384Sbing zhao - Sun Microsystems - Beijing China 		t_icmdp = next_icmdp;
35722b79d384Sbing zhao - Sun Microsystems - Beijing China 	}
35732b79d384Sbing zhao - Sun Microsystems - Beijing China }
35742b79d384Sbing zhao - Sun Microsystems - Beijing China 
35752b79d384Sbing zhao - Sun Microsystems - Beijing China /*
35762b79d384Sbing zhao - Sun Microsystems - Beijing China  * iscsi_decode_sense - decode the sense data in the cmd response
35772b79d384Sbing zhao - Sun Microsystems - Beijing China  *
35782b79d384Sbing zhao - Sun Microsystems - Beijing China  * Here we only care about Unit Attention with 0x29.
35792b79d384Sbing zhao - Sun Microsystems - Beijing China  */
35802b79d384Sbing zhao - Sun Microsystems - Beijing China static boolean_t
35812b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_decode_sense(uint8_t *sense_data)
35822b79d384Sbing zhao - Sun Microsystems - Beijing China {
35832b79d384Sbing zhao - Sun Microsystems - Beijing China 	uint8_t	sense_key   = 0;
35842b79d384Sbing zhao - Sun Microsystems - Beijing China 	uint8_t	asc	    = 0;
35852b79d384Sbing zhao - Sun Microsystems - Beijing China 	boolean_t affect    = B_FALSE;
35862b79d384Sbing zhao - Sun Microsystems - Beijing China 
35872b79d384Sbing zhao - Sun Microsystems - Beijing China 	ASSERT(sense_data != NULL);
35882b79d384Sbing zhao - Sun Microsystems - Beijing China 
35892b79d384Sbing zhao - Sun Microsystems - Beijing China 	sense_key = scsi_sense_key(sense_data);
35902b79d384Sbing zhao - Sun Microsystems - Beijing China 	switch (sense_key) {
35912b79d384Sbing zhao - Sun Microsystems - Beijing China 		case KEY_UNIT_ATTENTION:
35922b79d384Sbing zhao - Sun Microsystems - Beijing China 			asc = scsi_sense_asc(sense_data);
35932b79d384Sbing zhao - Sun Microsystems - Beijing China 			switch (asc) {
35942b79d384Sbing zhao - Sun Microsystems - Beijing China 				case ISCSI_SCSI_RESET_SENSE_CODE:
35952b79d384Sbing zhao - Sun Microsystems - Beijing China 					/*
35962b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * POWER ON, RESET, OR BUS_DEVICE RESET
35972b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * OCCURRED
35982b79d384Sbing zhao - Sun Microsystems - Beijing China 					 */
35992b79d384Sbing zhao - Sun Microsystems - Beijing China 					affect = B_TRUE;
36002b79d384Sbing zhao - Sun Microsystems - Beijing China 					break;
36012b79d384Sbing zhao - Sun Microsystems - Beijing China 				default:
36022b79d384Sbing zhao - Sun Microsystems - Beijing China 					/*
36032b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * Currently we don't care
36042b79d384Sbing zhao - Sun Microsystems - Beijing China 					 * about other sense key.
36052b79d384Sbing zhao - Sun Microsystems - Beijing China 					 */
36062b79d384Sbing zhao - Sun Microsystems - Beijing China 					break;
36072b79d384Sbing zhao - Sun Microsystems - Beijing China 			}
36082b79d384Sbing zhao - Sun Microsystems - Beijing China 			break;
36092b79d384Sbing zhao - Sun Microsystems - Beijing China 		default:
36102b79d384Sbing zhao - Sun Microsystems - Beijing China 			/*
36112b79d384Sbing zhao - Sun Microsystems - Beijing China 			 * Currently we don't care
36122b79d384Sbing zhao - Sun Microsystems - Beijing China 			 * about other sense key.
36132b79d384Sbing zhao - Sun Microsystems - Beijing China 			 */
36142b79d384Sbing zhao - Sun Microsystems - Beijing China 			break;
36152b79d384Sbing zhao - Sun Microsystems - Beijing China 	}
36162b79d384Sbing zhao - Sun Microsystems - Beijing China 	return (affect);
36172b79d384Sbing zhao - Sun Microsystems - Beijing China }
3618