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.
23904e51f6SJack Meng  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24*61dfa509SRick McNeal  * Copyright 2011, 2015 Nexenta Systems, Inc. All rights reserved.
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 
4730e7468fSPeter Dunlap 	if (idm_pattern_checking)  {					\
4830e7468fSPeter Dunlap 		struct scsi_pkt *pkt = (ICHK_CMD)->cmd_un.scsi.pkt;	\
49811eca55SToomas Soome 		if (((ICHK_HDR)->response == 0) &&			\
5030e7468fSPeter Dunlap 		    ((ICHK_HDR)->cmd_status == 0) &&			\
5130e7468fSPeter Dunlap 		    ((pkt->pkt_cdbp[0] == SCMD_READ_G1) ||		\
52811eca55SToomas Soome 		    (pkt->pkt_cdbp[0] == SCMD_READ_G4) ||		\
53811eca55SToomas Soome 		    (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 
60146832dbSMilos Muzik /* Size of structure scsi_arq_status without sense data. */
61146832dbSMilos Muzik #define	ISCSI_ARQ_STATUS_NOSENSE_LEN	(sizeof (struct scsi_arq_status) - \
62146832dbSMilos Muzik     sizeof (struct scsi_extended_sense))
63146832dbSMilos Muzik 
64fcf3ce44SJohn Forte /* generic io helpers */
65fcf3ce44SJohn Forte static uint32_t n2h24(uchar_t *ptr);
66fcf3ce44SJohn Forte static int iscsi_sna_lt(uint32_t n1, uint32_t n2);
6730e7468fSPeter Dunlap void iscsi_update_flow_control(iscsi_sess_t *isp,
68fcf3ce44SJohn Forte     uint32_t max, uint32_t exp);
6930e7468fSPeter Dunlap static iscsi_status_t iscsi_rx_process_scsi_itt_to_icmdp(iscsi_sess_t *isp,
7030e7468fSPeter Dunlap     idm_conn_t *ic, iscsi_scsi_rsp_hdr_t *ihp, iscsi_cmd_t **icmdp);
71fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_itt_to_icmdp(iscsi_sess_t *isp,
72fcf3ce44SJohn Forte     iscsi_hdr_t *ihp, iscsi_cmd_t **icmdp);
7330e7468fSPeter Dunlap static void iscsi_process_rsp_status(iscsi_sess_t *isp, iscsi_conn_t *icp,
7430e7468fSPeter Dunlap     idm_status_t status);
7530e7468fSPeter Dunlap static void iscsi_drop_conn_cleanup(iscsi_conn_t *icp);
76aff4bce5Syi zhang - Sun Microsystems - Beijing China static boolean_t iscsi_nop_timeout_checks(iscsi_cmd_t *icmdp);
7730e7468fSPeter Dunlap /* callbacks from idm */
7830e7468fSPeter Dunlap static idm_pdu_cb_t iscsi_tx_done;
7930e7468fSPeter Dunlap 
8030e7468fSPeter Dunlap /* receivers */
8130e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_nop(idm_conn_t *ic, idm_pdu_t *pdu);
8230e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_data_rsp(idm_conn_t *ic,
8330e7468fSPeter Dunlap     idm_pdu_t *pdu);
8430e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_cmd_rsp(idm_conn_t *ic, idm_pdu_t *pdu);
8530e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_reject_rsp(idm_conn_t *ic,
8630e7468fSPeter Dunlap     idm_pdu_t *pdu);
8730e7468fSPeter Dunlap 
8830e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_rejected_tsk_mgt(idm_conn_t *ic,
8930e7468fSPeter Dunlap     iscsi_hdr_t *old_ihp);
9030e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_task_mgt_rsp(idm_conn_t *ic,
9130e7468fSPeter Dunlap     idm_pdu_t *pdu);
9230e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_logout_rsp(idm_conn_t *ic,
9330e7468fSPeter Dunlap     idm_pdu_t *pdu);
9430e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_async_rsp(idm_conn_t *ic,
9530e7468fSPeter Dunlap     idm_pdu_t *pdu);
9630e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_text_rsp(idm_conn_t *ic,
9730e7468fSPeter Dunlap     idm_pdu_t *pdu);
98fcf3ce44SJohn Forte 
99fcf3ce44SJohn Forte /* senders */
100fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_scsi(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
101fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_nop(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
102fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_abort(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
103fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_reset(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
104fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_logout(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
105fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_text(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
106fcf3ce44SJohn Forte 
107fcf3ce44SJohn Forte 
108fcf3ce44SJohn Forte /* helpers */
10930e7468fSPeter Dunlap static void iscsi_logout_start(void *arg);
110fcf3ce44SJohn Forte static void iscsi_handle_passthru_callback(struct scsi_pkt *pkt);
111fcf3ce44SJohn Forte static void iscsi_handle_nop(iscsi_conn_t *icp, uint32_t itt, uint32_t ttt);
112fcf3ce44SJohn Forte 
113fcf3ce44SJohn Forte static void iscsi_timeout_checks(iscsi_sess_t *isp);
114fcf3ce44SJohn Forte static void iscsi_nop_checks(iscsi_sess_t *isp);
115904e51f6SJack Meng static boolean_t iscsi_decode_sense(uint8_t *sense_data, iscsi_cmd_t *icmdp);
1162b79d384Sbing zhao - Sun Microsystems - Beijing China static void iscsi_flush_cmd_after_reset(uint32_t cmd_sn, uint16_t lun_num,
1172b79d384Sbing zhao - Sun Microsystems - Beijing China     iscsi_conn_t *icp);
118fcf3ce44SJohn Forte 
119fcf3ce44SJohn Forte /*
120fcf3ce44SJohn Forte  * This file contains the main guts of the iSCSI protocol layer.
121fcf3ce44SJohn Forte  * It's broken into 5 sections; Basic helper functions, RX IO path,
122fcf3ce44SJohn Forte  * TX IO path, Completion (IC) IO path, and watchdog (WD) routines.
123fcf3ce44SJohn Forte  *
124fcf3ce44SJohn Forte  * The IO flow model is similiar to the below diagram.  The
125fcf3ce44SJohn Forte  * iscsi session, connection and command state machines are used
126fcf3ce44SJohn Forte  * to drive IO through this flow diagram.  Reference those files
127fcf3ce44SJohn Forte  * to get a detailed description of their respective state models
128fcf3ce44SJohn Forte  * prior to their xxx_state_machine_function().
129fcf3ce44SJohn Forte  *
130fcf3ce44SJohn Forte  * tran_start() -> CMD_E1     TX_THREAD                   RX_THREAD
131fcf3ce44SJohn Forte  *                   |            T                           T
132fcf3ce44SJohn Forte  *                   V            T                           T
133fcf3ce44SJohn Forte  *                PENDING_Q  --CMD_E2--> ACTIVE_Q -      --CMD_E3--+
134fcf3ce44SJohn Forte  *                                T                \ C        T    |
135fcf3ce44SJohn Forte  *                                T                 \M        T    |
136fcf3ce44SJohn Forte  *                                                   D        T    |
137fcf3ce44SJohn Forte  *                                       WD_THREAD TT|TT      T    |
138fcf3ce44SJohn Forte  *                                                  /E        T    |
139fcf3ce44SJohn Forte  *                                                 / 6        T    |
140fcf3ce44SJohn Forte  *                                     ABORTING_Q<-      --CMD_E3--+
141fcf3ce44SJohn Forte  *                                                            T    |
142fcf3ce44SJohn Forte  *                                T                           T    |
143fcf3ce44SJohn Forte  *                                T                                |
144fcf3ce44SJohn Forte  *               callback()  <--CMD_E#-- COMPLETION_Q <------------+
145fcf3ce44SJohn Forte  *                                T
146fcf3ce44SJohn Forte  *                                T
147fcf3ce44SJohn Forte  *                            IC_THREAD
148fcf3ce44SJohn Forte  *
149fcf3ce44SJohn Forte  * External and internal command are ran thru this same state
150fcf3ce44SJohn Forte  * machine.  All commands enter the state machine by receiving an
151fcf3ce44SJohn Forte  * ISCSI_CMD_EVENT_E1.  This event places the command into the
152fcf3ce44SJohn Forte  * PENDING_Q.  Next when resources are available the TX_THREAD
153fcf3ce44SJohn Forte  * issues a E2 event on the command.  This sends the command
154fcf3ce44SJohn Forte  * to the TCP stack and places the command on the ACTIVE_Q.  While
155fcf3ce44SJohn Forte  * on the PENDIING_Q and ACTIVE_Q, the command is monitored via the
156fcf3ce44SJohn Forte  * WD_THREAD to ensure the pkt_time has not elapsed.  If elapsed the
157fcf3ce44SJohn Forte  * command is issued an E6(timeout) event which moves either (if pending)
158fcf3ce44SJohn Forte  * completed the command or (if active) moves the command to the
159fcf3ce44SJohn Forte  * aborting queue and issues a SCSI TASK MANAGEMENT ABORT command
160fcf3ce44SJohn Forte  * to cancel the IO request.  If the original command is completed
161fcf3ce44SJohn Forte  * or the TASK MANAGEMENT command completes the command is moved
162fcf3ce44SJohn Forte  * to the COMPLETION_Q via a E3 event.  The IC_THREAD then processes
163fcf3ce44SJohn Forte  * the COMPLETION_Q and issues the scsi_pkt callback.  This
164fcf3ce44SJohn Forte  * callback can not be processed directly from the RX_THREAD
165fcf3ce44SJohn Forte  * because the callback might call back into the iscsi driver
166fcf3ce44SJohn Forte  * causing a deadlock condition.
167fcf3ce44SJohn Forte  *
168fcf3ce44SJohn Forte  * For more details on the complete CMD state machine reference
169fcf3ce44SJohn Forte  * the state machine diagram in iscsi_cmd.c.  The connection state
170fcf3ce44SJohn Forte  * machine is driven via IO events in this file.  Then session
171fcf3ce44SJohn Forte  * events are driven by the connection events.  For complete
172fcf3ce44SJohn Forte  * details on these state machines reference iscsi_sess.c and
173fcf3ce44SJohn Forte  * iscsi_conn.c
174fcf3ce44SJohn Forte  */
175fcf3ce44SJohn Forte 
176fcf3ce44SJohn Forte 
177fcf3ce44SJohn Forte /*
178fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
179fcf3ce44SJohn Forte  * | io helper routines							|
180fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
181fcf3ce44SJohn Forte  */
182fcf3ce44SJohn Forte 
183fcf3ce44SJohn Forte /*
184fcf3ce44SJohn Forte  * n2h24 - native to host 24 bit integer translation.
185fcf3ce44SJohn Forte  */
186fcf3ce44SJohn Forte static uint32_t
n2h24(uchar_t * ptr)187fcf3ce44SJohn Forte n2h24(uchar_t *ptr)
188fcf3ce44SJohn Forte {
189fcf3ce44SJohn Forte 	uint32_t idx;
190fcf3ce44SJohn Forte 	bcopy(ptr, &idx, 3);
191fcf3ce44SJohn Forte 	return (ntohl(idx) >> 8);
192fcf3ce44SJohn Forte }
193fcf3ce44SJohn Forte 
194fcf3ce44SJohn Forte /*
195fcf3ce44SJohn Forte  * iscsi_sna_lt - Serial Number Arithmetic, 32 bits, less than, RFC1982
196fcf3ce44SJohn Forte  */
197fcf3ce44SJohn Forte static int
iscsi_sna_lt(uint32_t n1,uint32_t n2)198fcf3ce44SJohn Forte iscsi_sna_lt(uint32_t n1, uint32_t n2)
199fcf3ce44SJohn Forte {
200fcf3ce44SJohn Forte 	return ((n1 != n2) &&
201fcf3ce44SJohn Forte 	    (((n1 < n2) && ((n2 - n1) < ISCSI_SNA32_CHECK)) ||
202fcf3ce44SJohn Forte 	    ((n1 > n2) && ((n1 - n2) > ISCSI_SNA32_CHECK))));
203fcf3ce44SJohn Forte }
204fcf3ce44SJohn Forte 
205fcf3ce44SJohn Forte /*
206fcf3ce44SJohn Forte  * iscsi_sna_lte - Serial Number Arithmetic, 32 bits, less than or equal,
207fcf3ce44SJohn Forte  * RFC1982
208fcf3ce44SJohn Forte  */
209fcf3ce44SJohn Forte int
iscsi_sna_lte(uint32_t n1,uint32_t n2)210fcf3ce44SJohn Forte iscsi_sna_lte(uint32_t n1, uint32_t n2)
211fcf3ce44SJohn Forte {
212fcf3ce44SJohn Forte 	return ((n1 == n2) ||
213fcf3ce44SJohn Forte 	    (((n1 < n2) && ((n2 - n1) < ISCSI_SNA32_CHECK)) ||
214fcf3ce44SJohn Forte 	    ((n1 > n2) && ((n1 - n2) > ISCSI_SNA32_CHECK))));
215fcf3ce44SJohn Forte }
216fcf3ce44SJohn Forte 
217fcf3ce44SJohn Forte /*
218fcf3ce44SJohn Forte  * iscsi_update_flow_control - Update expcmdsn and maxcmdsn iSCSI
219fcf3ce44SJohn Forte  * flow control information for a session
220fcf3ce44SJohn Forte  */
22130e7468fSPeter Dunlap void
iscsi_update_flow_control(iscsi_sess_t * isp,uint32_t max,uint32_t exp)222fcf3ce44SJohn Forte iscsi_update_flow_control(iscsi_sess_t *isp, uint32_t max, uint32_t exp)
223fcf3ce44SJohn Forte {
224fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
225fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&isp->sess_cmdsn_mutex));
226fcf3ce44SJohn Forte 
227fcf3ce44SJohn Forte 	if (!iscsi_sna_lt(max, (exp - 1))) {
228fcf3ce44SJohn Forte 
229fcf3ce44SJohn Forte 		if (!iscsi_sna_lte(exp, isp->sess_expcmdsn)) {
230fcf3ce44SJohn Forte 			isp->sess_expcmdsn = exp;
231fcf3ce44SJohn Forte 		}
232fcf3ce44SJohn Forte 
233fcf3ce44SJohn Forte 		if (!iscsi_sna_lte(max, isp->sess_maxcmdsn)) {
234fcf3ce44SJohn Forte 			isp->sess_maxcmdsn = max;
235fcf3ce44SJohn Forte 			if (iscsi_sna_lte(isp->sess_cmdsn,
236fcf3ce44SJohn Forte 			    isp->sess_maxcmdsn)) {
237fcf3ce44SJohn Forte 				/*
238fcf3ce44SJohn Forte 				 * the window is open again - schedule
239fcf3ce44SJohn Forte 				 * to send any held tasks soon
240fcf3ce44SJohn Forte 				 */
241fcf3ce44SJohn Forte 				iscsi_sess_redrive_io(isp);
242fcf3ce44SJohn Forte 			}
243fcf3ce44SJohn Forte 		}
244fcf3ce44SJohn Forte 	}
245fcf3ce44SJohn Forte }
246fcf3ce44SJohn Forte 
247fcf3ce44SJohn Forte 
248fcf3ce44SJohn Forte /*
249fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
250fcf3ce44SJohn Forte  * | io receive and processing routines					|
251fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
252fcf3ce44SJohn Forte  */
253fcf3ce44SJohn Forte 
254fcf3ce44SJohn Forte /*
25530e7468fSPeter Dunlap  * iscsi_rx_scsi_rsp - called from idm
25630e7468fSPeter Dunlap  * For each opcode type fan out the processing.
257fcf3ce44SJohn Forte  */
258fcf3ce44SJohn Forte void
iscsi_rx_scsi_rsp(idm_conn_t * ic,idm_pdu_t * pdu)25930e7468fSPeter Dunlap iscsi_rx_scsi_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
260fcf3ce44SJohn Forte {
26130e7468fSPeter Dunlap 	iscsi_conn_t	*icp;
26230e7468fSPeter Dunlap 	iscsi_sess_t	*isp;
26330e7468fSPeter Dunlap 	iscsi_hdr_t	*ihp;
26430e7468fSPeter Dunlap 	idm_status_t	status;
265fcf3ce44SJohn Forte 
26630e7468fSPeter Dunlap 	ASSERT(ic != NULL);
26730e7468fSPeter Dunlap 	ASSERT(pdu != NULL);
26830e7468fSPeter Dunlap 	icp		= ic->ic_handle;
269fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
27030e7468fSPeter Dunlap 	ihp		= (iscsi_hdr_t *)pdu->isp_hdr;
271fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
27230e7468fSPeter Dunlap 	isp		= icp->conn_sess;
273fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
274fcf3ce44SJohn Forte 
27530e7468fSPeter Dunlap 	/* reset the session timer when we receive the response */
27630e7468fSPeter Dunlap 	isp->sess_rx_lbolt = icp->conn_rx_lbolt = ddi_get_lbolt();
277fcf3ce44SJohn Forte 
278fcf3ce44SJohn Forte 	/* fan out the hdr processing */
279fcf3ce44SJohn Forte 	switch (ihp->opcode & ISCSI_OPCODE_MASK) {
280fcf3ce44SJohn Forte 	case ISCSI_OP_SCSI_DATA_RSP:
28130e7468fSPeter Dunlap 		status = iscsi_rx_process_data_rsp(ic, pdu);
282fcf3ce44SJohn Forte 		break;
283fcf3ce44SJohn Forte 	case ISCSI_OP_SCSI_RSP:
28430e7468fSPeter Dunlap 		status = iscsi_rx_process_cmd_rsp(ic, pdu);
28530e7468fSPeter Dunlap 		idm_pdu_complete(pdu, status);
286fcf3ce44SJohn Forte 		break;
287fcf3ce44SJohn Forte 	default:
288fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
28930e7468fSPeter Dunlap 		    "received pdu with unsupported opcode 0x%02x",
290fcf3ce44SJohn Forte 		    icp->conn_oid, ihp->opcode);
29130e7468fSPeter Dunlap 		status = IDM_STATUS_PROTOCOL_ERROR;
292fcf3ce44SJohn Forte 	}
29330e7468fSPeter Dunlap 	iscsi_process_rsp_status(isp, icp, status);
294fcf3ce44SJohn Forte }
295fcf3ce44SJohn Forte 
29630e7468fSPeter Dunlap void
iscsi_task_cleanup(int opcode,iscsi_cmd_t * icmdp)29730e7468fSPeter Dunlap iscsi_task_cleanup(int opcode, iscsi_cmd_t *icmdp)
298fcf3ce44SJohn Forte {
299811eca55SToomas Soome 	struct buf	*bp;
30030e7468fSPeter Dunlap 	idm_buf_t	*ibp, *obp;
30130e7468fSPeter Dunlap 	idm_task_t	*itp;
302fcf3ce44SJohn Forte 
30330e7468fSPeter Dunlap 	itp = icmdp->cmd_itp;
30430e7468fSPeter Dunlap 	ASSERT(itp != NULL);
30530e7468fSPeter Dunlap 	ASSERT((opcode == ISCSI_OP_SCSI_DATA_RSP) ||
30630e7468fSPeter Dunlap 	    (opcode == ISCSI_OP_SCSI_RSP));
307fcf3ce44SJohn Forte 
30830e7468fSPeter Dunlap 	bp = icmdp->cmd_un.scsi.bp;
30930e7468fSPeter Dunlap 	ibp = icmdp->cmd_un.scsi.ibp_ibuf;
31030e7468fSPeter Dunlap 	obp = icmdp->cmd_un.scsi.ibp_obuf;
31130e7468fSPeter Dunlap 	ISCSI_IO_LOG(CE_NOTE, "DEBUG: task_cleanup: itp: %p opcode: %d "
31230e7468fSPeter Dunlap 	    "icmdp: %p bp: %p ibp: %p", (void *)itp, opcode,
31330e7468fSPeter Dunlap 	    (void *)icmdp, (void *)bp, (void *)ibp);
31430e7468fSPeter Dunlap 	if (bp && bp->b_bcount) {
31530e7468fSPeter Dunlap 		if (ibp != NULL && bp->b_flags & B_READ) {
31630e7468fSPeter Dunlap 			idm_buf_unbind_in(itp, ibp);
31730e7468fSPeter Dunlap 			idm_buf_free(ibp);
31830e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.ibp_ibuf = NULL;
31930e7468fSPeter Dunlap 		} else if (obp != NULL && !(bp->b_flags & B_READ)) {
32030e7468fSPeter Dunlap 			idm_buf_unbind_out(itp, obp);
32130e7468fSPeter Dunlap 			idm_buf_free(obp);
32230e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.ibp_obuf = NULL;
323fcf3ce44SJohn Forte 		}
324fcf3ce44SJohn Forte 	}
325fcf3ce44SJohn Forte 
32630e7468fSPeter Dunlap 	idm_task_done(itp);
32730e7468fSPeter Dunlap }
32830e7468fSPeter Dunlap 
32930e7468fSPeter Dunlap idm_status_t
iscsi_rx_chk(iscsi_conn_t * icp,iscsi_sess_t * isp,iscsi_scsi_rsp_hdr_t * irhp,iscsi_cmd_t ** icmdp)33030e7468fSPeter Dunlap iscsi_rx_chk(iscsi_conn_t *icp, iscsi_sess_t *isp,
33130e7468fSPeter Dunlap     iscsi_scsi_rsp_hdr_t *irhp, iscsi_cmd_t **icmdp)
33230e7468fSPeter Dunlap {
33330e7468fSPeter Dunlap 	iscsi_status_t rval;
33430e7468fSPeter Dunlap 
335fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_cmdsn_mutex);
33630e7468fSPeter Dunlap 
33730e7468fSPeter Dunlap 	if (icp->conn_expstatsn == ntohl(irhp->statsn)) {
33830e7468fSPeter Dunlap 		icp->conn_expstatsn++;
33930e7468fSPeter Dunlap 	} else {
34030e7468fSPeter Dunlap 		cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - "
34130e7468fSPeter Dunlap 		    "received status out of order itt:0x%x statsn:0x%x "
34230e7468fSPeter Dunlap 		    "expstatsn:0x%x", icp->conn_oid, irhp->opcode,
34330e7468fSPeter Dunlap 		    irhp->itt, ntohl(irhp->statsn), icp->conn_expstatsn);
344fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_cmdsn_mutex);
34530e7468fSPeter Dunlap 		return (IDM_STATUS_PROTOCOL_ERROR);
34630e7468fSPeter Dunlap 	}
34730e7468fSPeter Dunlap 
34830e7468fSPeter Dunlap 	/* get icmdp so we can cleanup on error */
34930e7468fSPeter Dunlap 	if ((irhp->opcode == ISCSI_OP_SCSI_DATA_RSP) ||
35030e7468fSPeter Dunlap 	    (irhp->opcode == ISCSI_OP_SCSI_RSP)) {
35130e7468fSPeter Dunlap 		rval = iscsi_rx_process_scsi_itt_to_icmdp(isp, icp->conn_ic,
35230e7468fSPeter Dunlap 		    irhp, icmdp);
35330e7468fSPeter Dunlap 	} else {
35430e7468fSPeter Dunlap 		rval = iscsi_rx_process_itt_to_icmdp(isp,
35530e7468fSPeter Dunlap 		    (iscsi_hdr_t *)irhp, icmdp);
35630e7468fSPeter Dunlap 	}
35730e7468fSPeter Dunlap 
35830e7468fSPeter Dunlap 	if (!ISCSI_SUCCESS(rval)) {
35930e7468fSPeter Dunlap 		mutex_exit(&isp->sess_cmdsn_mutex);
36030e7468fSPeter Dunlap 		return (IDM_STATUS_PROTOCOL_ERROR);
361fcf3ce44SJohn Forte 	}
362fcf3ce44SJohn Forte 
363fcf3ce44SJohn Forte 	/* update expcmdsn and maxcmdsn */
36430e7468fSPeter Dunlap 	iscsi_update_flow_control(isp, ntohl(irhp->maxcmdsn),
36530e7468fSPeter Dunlap 	    ntohl(irhp->expcmdsn));
366fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_cmdsn_mutex);
36730e7468fSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
36830e7468fSPeter Dunlap }
369fcf3ce44SJohn Forte 
37030e7468fSPeter Dunlap static void
iscsi_cmd_rsp_chk(iscsi_cmd_t * icmdp,iscsi_scsi_rsp_hdr_t * issrhp)37130e7468fSPeter Dunlap iscsi_cmd_rsp_chk(iscsi_cmd_t *icmdp, iscsi_scsi_rsp_hdr_t *issrhp)
37230e7468fSPeter Dunlap {
37330e7468fSPeter Dunlap 	struct scsi_pkt *pkt;
37430e7468fSPeter Dunlap 	size_t data_transferred;
375fcf3ce44SJohn Forte 
37630e7468fSPeter Dunlap 	pkt = icmdp->cmd_un.scsi.pkt;
37730e7468fSPeter Dunlap 	pkt->pkt_resid = 0;
37830e7468fSPeter Dunlap 	data_transferred = icmdp->cmd_un.scsi.data_transferred;
37930e7468fSPeter Dunlap 	/* Check the residual count */
38030e7468fSPeter Dunlap 	if ((icmdp->cmd_un.scsi.bp) &&
38130e7468fSPeter Dunlap 	    (data_transferred != icmdp->cmd_un.scsi.bp->b_bcount)) {
382fcf3ce44SJohn Forte 		/*
38330e7468fSPeter Dunlap 		 * We didn't xfer the expected amount of data -
38430e7468fSPeter Dunlap 		 * the residual_count in the header is only
38530e7468fSPeter Dunlap 		 * valid if the underflow flag is set.
386fcf3ce44SJohn Forte 		 */
38730e7468fSPeter Dunlap 		if (issrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
38830e7468fSPeter Dunlap 			pkt->pkt_resid = ntohl(issrhp->residual_count);
38930e7468fSPeter Dunlap 		} else {
39030e7468fSPeter Dunlap 			if (icmdp->cmd_un.scsi.bp->b_bcount >
39130e7468fSPeter Dunlap 			    data_transferred) {
39230e7468fSPeter Dunlap 				/*
39330e7468fSPeter Dunlap 				 * Some data fell on the floor
39430e7468fSPeter Dunlap 				 * somehow - probably a CRC error
39530e7468fSPeter Dunlap 				 */
39630e7468fSPeter Dunlap 				pkt->pkt_resid =
39730e7468fSPeter Dunlap 				    icmdp->cmd_un.scsi.bp->b_bcount -
39830e7468fSPeter Dunlap 				    data_transferred;
39930e7468fSPeter Dunlap 			}
400fcf3ce44SJohn Forte 		}
40130e7468fSPeter Dunlap 		ISCSI_IO_LOG(CE_NOTE,
40230e7468fSPeter Dunlap 		    "DEBUG: iscsi_rx_cmd_rsp_chk: itt: %u"
40330e7468fSPeter Dunlap 		    "data_trans != b_count data_transferred: %lu "
40430e7468fSPeter Dunlap 		    "b_count: %lu cmd_status: %d flags: %d resid: %lu",
40530e7468fSPeter Dunlap 		    issrhp->itt, data_transferred,
40630e7468fSPeter Dunlap 		    icmdp->cmd_un.scsi.bp->b_bcount,
40730e7468fSPeter Dunlap 		    issrhp->cmd_status & STATUS_MASK,
40830e7468fSPeter Dunlap 		    issrhp->flags, pkt->pkt_resid);
40930e7468fSPeter Dunlap 	}
41030e7468fSPeter Dunlap 	/* set flags that tell SCSA that the command is complete */
41130e7468fSPeter Dunlap 	if (icmdp->cmd_crc_error_seen == B_FALSE) {
41230e7468fSPeter Dunlap 		/* Set successful completion */
41330e7468fSPeter Dunlap 		pkt->pkt_reason = CMD_CMPLT;
41430e7468fSPeter Dunlap 		if (icmdp->cmd_un.scsi.bp) {
41530e7468fSPeter Dunlap 			pkt->pkt_state |= (STATE_XFERRED_DATA |
41630e7468fSPeter Dunlap 			    STATE_GOT_STATUS);
41730e7468fSPeter Dunlap 		} else {
41830e7468fSPeter Dunlap 			pkt->pkt_state |= STATE_GOT_STATUS;
41930e7468fSPeter Dunlap 		}
42030e7468fSPeter Dunlap 	} else {
421fcf3ce44SJohn Forte 		/*
42230e7468fSPeter Dunlap 		 * Some of the data was found to have an incorrect
42330e7468fSPeter Dunlap 		 * error at the protocol error.
424fcf3ce44SJohn Forte 		 */
42530e7468fSPeter Dunlap 		pkt->pkt_reason = CMD_PER_FAIL;
42630e7468fSPeter Dunlap 		pkt->pkt_statistics |= STAT_PERR;
42730e7468fSPeter Dunlap 		if (icmdp->cmd_un.scsi.bp) {
42830e7468fSPeter Dunlap 			pkt->pkt_resid =
42930e7468fSPeter Dunlap 			    icmdp->cmd_un.scsi.bp->b_bcount;
430fcf3ce44SJohn Forte 		} else {
43130e7468fSPeter Dunlap 			pkt->pkt_resid = 0;
432fcf3ce44SJohn Forte 		}
433fcf3ce44SJohn Forte 	}
43430e7468fSPeter Dunlap }
43530e7468fSPeter Dunlap 
4362b79d384Sbing zhao - Sun Microsystems - Beijing China static boolean_t
iscsi_cmd_rsp_cmd_status(iscsi_cmd_t * icmdp,iscsi_scsi_rsp_hdr_t * issrhp,uint8_t * data)43730e7468fSPeter Dunlap iscsi_cmd_rsp_cmd_status(iscsi_cmd_t *icmdp, iscsi_scsi_rsp_hdr_t *issrhp,
43830e7468fSPeter Dunlap     uint8_t *data)
43930e7468fSPeter Dunlap {
440146832dbSMilos Muzik 	int32_t			dlength;
441146832dbSMilos Muzik 	struct scsi_arq_status	*arqstat;
442146832dbSMilos Muzik 	size_t			senselen;
443146832dbSMilos Muzik 	int32_t			statuslen;
444146832dbSMilos Muzik 	int32_t			sensebuf_len;
44530e7468fSPeter Dunlap 	struct scsi_pkt		*pkt;
446146832dbSMilos Muzik 	boolean_t		affect = B_FALSE;
447146832dbSMilos Muzik 	int32_t			senselen_to_copy;
44830e7468fSPeter Dunlap 
44930e7468fSPeter Dunlap 	pkt = icmdp->cmd_un.scsi.pkt;
45030e7468fSPeter Dunlap 	dlength = n2h24(issrhp->dlength);
451fcf3ce44SJohn Forte 
452fcf3ce44SJohn Forte 	/*
45330e7468fSPeter Dunlap 	 * Process iSCSI Cmd Response Status
45430e7468fSPeter Dunlap 	 * RFC 3720 Sectionn 10.4.2.
455fcf3ce44SJohn Forte 	 */
45630e7468fSPeter Dunlap 	switch (issrhp->cmd_status & STATUS_MASK) {
45730e7468fSPeter Dunlap 	case STATUS_GOOD:
45830e7468fSPeter Dunlap 		/* pass SCSI status up stack */
45930e7468fSPeter Dunlap 		if (pkt->pkt_scbp) {
46030e7468fSPeter Dunlap 			pkt->pkt_scbp[0] = issrhp->cmd_status;
46130e7468fSPeter Dunlap 		}
46230e7468fSPeter Dunlap 		break;
46330e7468fSPeter Dunlap 	case STATUS_CHECK:
46430e7468fSPeter Dunlap 		/*
46530e7468fSPeter Dunlap 		 * Verify we received a sense buffer and
46630e7468fSPeter Dunlap 		 * that there is the correct amount of
46730e7468fSPeter Dunlap 		 * request sense space to copy it to.
46830e7468fSPeter Dunlap 		 */
46930e7468fSPeter Dunlap 		if ((dlength > 1) &&
47030e7468fSPeter Dunlap 		    (pkt->pkt_scbp != NULL) &&
47130e7468fSPeter Dunlap 		    (icmdp->cmd_un.scsi.statuslen >=
47230e7468fSPeter Dunlap 		    sizeof (struct scsi_arq_status))) {
473fcf3ce44SJohn Forte 			/*
47430e7468fSPeter Dunlap 			 * If a bad command status is received we
47530e7468fSPeter Dunlap 			 * need to reset the pkt_resid to zero.
47630e7468fSPeter Dunlap 			 * The target driver compares its value
47730e7468fSPeter Dunlap 			 * before checking other error flags.
47830e7468fSPeter Dunlap 			 * (ex. check conditions)
479fcf3ce44SJohn Forte 			 */
48030e7468fSPeter Dunlap 			pkt->pkt_resid = 0;
48130e7468fSPeter Dunlap 
48230e7468fSPeter Dunlap 			/* get sense length from first 2 bytes */
48330e7468fSPeter Dunlap 			senselen = ((data[0] << 8) | data[1]) &
48430e7468fSPeter Dunlap 			    (size_t)0xFFFF;
48530e7468fSPeter Dunlap 			ISCSI_IO_LOG(CE_NOTE,
48630e7468fSPeter Dunlap 			    "DEBUG: iscsi_rx_cmd_rsp_cmd_status status_check: "
48730e7468fSPeter Dunlap 			    "dlen: %d scbp: %p statuslen: %d arq: %d senselen:"
48830e7468fSPeter Dunlap 			    " %lu", dlength, (void *)pkt->pkt_scbp,
48930e7468fSPeter Dunlap 			    icmdp->cmd_un.scsi.statuslen,
49030e7468fSPeter Dunlap 			    (int)sizeof (struct scsi_arq_status),
49130e7468fSPeter Dunlap 			    senselen);
49230e7468fSPeter Dunlap 
49330e7468fSPeter Dunlap 			/* Sanity-check on the sense length */
49430e7468fSPeter Dunlap 			if ((senselen + 2) > dlength) {
49530e7468fSPeter Dunlap 				senselen = dlength - 2;
496fcf3ce44SJohn Forte 			}
497fcf3ce44SJohn Forte 
49830e7468fSPeter Dunlap 			/*
49930e7468fSPeter Dunlap 			 * If there was a Data Digest error then
50030e7468fSPeter Dunlap 			 * the sense data cannot be trusted.
50130e7468fSPeter Dunlap 			 */
50230e7468fSPeter Dunlap 			if (icmdp->cmd_crc_error_seen) {
50330e7468fSPeter Dunlap 				senselen = 0;
50430e7468fSPeter Dunlap 			}
505fcf3ce44SJohn Forte 
50630e7468fSPeter Dunlap 			/* automatic request sense */
50730e7468fSPeter Dunlap 			arqstat =
50830e7468fSPeter Dunlap 			    (struct scsi_arq_status *)pkt->pkt_scbp;
50930e7468fSPeter Dunlap 
51030e7468fSPeter Dunlap 			/* pass SCSI status up stack */
51130e7468fSPeter Dunlap 			*((uchar_t *)&arqstat->sts_status) =
51230e7468fSPeter Dunlap 			    issrhp->cmd_status;
513fcf3ce44SJohn Forte 
514fcf3ce44SJohn Forte 			/*
51530e7468fSPeter Dunlap 			 * Set the status for the automatic
51630e7468fSPeter Dunlap 			 * request sense command
517fcf3ce44SJohn Forte 			 */
51830e7468fSPeter Dunlap 			arqstat->sts_rqpkt_state = (STATE_GOT_BUS |
51930e7468fSPeter Dunlap 			    STATE_GOT_TARGET | STATE_SENT_CMD |
52030e7468fSPeter Dunlap 			    STATE_XFERRED_DATA | STATE_GOT_STATUS |
52130e7468fSPeter Dunlap 			    STATE_ARQ_DONE);
522fcf3ce44SJohn Forte 
52330e7468fSPeter Dunlap 			*((uchar_t *)&arqstat->sts_rqpkt_status) =
52430e7468fSPeter Dunlap 			    STATUS_GOOD;
525fcf3ce44SJohn Forte 
52630e7468fSPeter Dunlap 			arqstat->sts_rqpkt_reason = CMD_CMPLT;
52730e7468fSPeter Dunlap 			statuslen = icmdp->cmd_un.scsi.statuslen;
528fcf3ce44SJohn Forte 
52930e7468fSPeter Dunlap 			if (senselen == 0) {
53030e7468fSPeter Dunlap 				/* auto request sense failed */
53130e7468fSPeter Dunlap 				arqstat->sts_rqpkt_status.sts_chk = 1;
53230e7468fSPeter Dunlap 				arqstat->sts_rqpkt_resid = statuslen;
53330e7468fSPeter Dunlap 			} else if (senselen < statuslen) {
53430e7468fSPeter Dunlap 				/* auto request sense short */
53530e7468fSPeter Dunlap 				arqstat->sts_rqpkt_resid = statuslen - senselen;
53630e7468fSPeter Dunlap 			} else {
53730e7468fSPeter Dunlap 				/* auto request sense complete */
53830e7468fSPeter Dunlap 				arqstat->sts_rqpkt_resid = 0;
53930e7468fSPeter Dunlap 			}
54030e7468fSPeter Dunlap 			arqstat->sts_rqpkt_statistics = 0;
54130e7468fSPeter Dunlap 			pkt->pkt_state |= STATE_ARQ_DONE;
542fcf3ce44SJohn Forte 
54330e7468fSPeter Dunlap 			if (icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_XARQ) {
54430e7468fSPeter Dunlap 				pkt->pkt_state |= STATE_XARQ_DONE;
54530e7468fSPeter Dunlap 			}
54630e7468fSPeter Dunlap 
547146832dbSMilos Muzik 			/*
548146832dbSMilos Muzik 			 * Calculate size of space reserved for sense data in
549146832dbSMilos Muzik 			 * pkt->pkt_scbp.
550146832dbSMilos Muzik 			 */
551146832dbSMilos Muzik 			sensebuf_len = statuslen - ISCSI_ARQ_STATUS_NOSENSE_LEN;
5525279807dSJack Meng 
55330e7468fSPeter Dunlap 			/* copy auto request sense */
554146832dbSMilos Muzik 			senselen_to_copy = min(senselen, sensebuf_len);
555146832dbSMilos Muzik 			if (senselen_to_copy > 0) {
55630e7468fSPeter Dunlap 				bcopy(&data[2], (uchar_t *)&arqstat->
557146832dbSMilos Muzik 				    sts_sensedata, senselen_to_copy);
5582b79d384Sbing zhao - Sun Microsystems - Beijing China 
5592b79d384Sbing zhao - Sun Microsystems - Beijing China 				affect = iscsi_decode_sense(
560904e51f6SJack Meng 				    (uint8_t *)&arqstat->sts_sensedata, icmdp);
56130e7468fSPeter Dunlap 			}
562146832dbSMilos Muzik 			arqstat->sts_rqpkt_resid = sensebuf_len -
563146832dbSMilos Muzik 			    senselen_to_copy;
564146832dbSMilos Muzik 			ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_cmd_rsp_cmd_status:"
565146832dbSMilos Muzik 			    " sts_rqpkt_resid: %d pkt_scblen: %d senselen: %lu"
566146832dbSMilos Muzik 			    " sensebuf_len: %d senselen_to_copy: %d affect: %d",
567146832dbSMilos Muzik 			    arqstat->sts_rqpkt_resid, pkt->pkt_scblen, senselen,
568146832dbSMilos Muzik 			    sensebuf_len, senselen_to_copy, affect);
56930e7468fSPeter Dunlap 			break;
570fcf3ce44SJohn Forte 		}
57130e7468fSPeter Dunlap 		/* FALLTHRU */
57230e7468fSPeter Dunlap 	case STATUS_BUSY:
57330e7468fSPeter Dunlap 	case STATUS_RESERVATION_CONFLICT:
57430e7468fSPeter Dunlap 	case STATUS_QFULL:
57530e7468fSPeter Dunlap 	case STATUS_ACA_ACTIVE:
57630e7468fSPeter Dunlap 	default:
57730e7468fSPeter Dunlap 		/*
57830e7468fSPeter Dunlap 		 * If a bad command status is received we need to
57930e7468fSPeter Dunlap 		 * reset the pkt_resid to zero.  The target driver
58030e7468fSPeter Dunlap 		 * compares its value before checking other error
58130e7468fSPeter Dunlap 		 * flags. (ex. check conditions)
58230e7468fSPeter Dunlap 		 */
58330e7468fSPeter Dunlap 		ISCSI_IO_LOG(CE_NOTE,
58430e7468fSPeter Dunlap 		    "DEBUG: iscsi_rx_cmd_rsp_cmd_status: status: "
58530e7468fSPeter Dunlap 		    "%d cmd_status: %d dlen: %u scbp: %p statuslen: %d "
58630e7468fSPeter Dunlap 		    "arg_len: %d", issrhp->cmd_status & STATUS_MASK,
58730e7468fSPeter Dunlap 		    issrhp->cmd_status, dlength, (void *)pkt->pkt_scbp,
58830e7468fSPeter Dunlap 		    icmdp->cmd_un.scsi.statuslen,
58930e7468fSPeter Dunlap 		    (int)sizeof (struct scsi_arq_status));
59030e7468fSPeter Dunlap 		pkt->pkt_resid = 0;
59130e7468fSPeter Dunlap 		/* pass SCSI status up stack */
59230e7468fSPeter Dunlap 		if (pkt->pkt_scbp) {
59330e7468fSPeter Dunlap 			pkt->pkt_scbp[0] = issrhp->cmd_status;
59430e7468fSPeter Dunlap 		}
59530e7468fSPeter Dunlap 	}
5962b79d384Sbing zhao - Sun Microsystems - Beijing China 
5972b79d384Sbing zhao - Sun Microsystems - Beijing China 	return (affect);
59830e7468fSPeter Dunlap }
599fcf3ce44SJohn Forte 
60030e7468fSPeter Dunlap /*
60130e7468fSPeter Dunlap  * iscsi_rx_process_login_pdup - Process login response PDU.  This function
60230e7468fSPeter Dunlap  * copies the data into the connection context so that the login code can
60330e7468fSPeter Dunlap  * interpret it.
60430e7468fSPeter Dunlap  */
60530e7468fSPeter Dunlap 
60630e7468fSPeter Dunlap idm_status_t
iscsi_rx_process_login_pdu(idm_conn_t * ic,idm_pdu_t * pdu)60730e7468fSPeter Dunlap iscsi_rx_process_login_pdu(idm_conn_t *ic, idm_pdu_t *pdu)
60830e7468fSPeter Dunlap {
609811eca55SToomas Soome 	iscsi_conn_t		*icp;
61030e7468fSPeter Dunlap 
61130e7468fSPeter Dunlap 	icp = ic->ic_handle;
61230e7468fSPeter Dunlap 
61330e7468fSPeter Dunlap 	/*
61430e7468fSPeter Dunlap 	 * Copy header and data into connection structure so iscsi_login()
61530e7468fSPeter Dunlap 	 * can process it.
61630e7468fSPeter Dunlap 	 */
61730e7468fSPeter Dunlap 	mutex_enter(&icp->conn_login_mutex);
61830e7468fSPeter Dunlap 	/*
61930e7468fSPeter Dunlap 	 * If conn_login_state != LOGIN_TX then we are not ready to handle
62030e7468fSPeter Dunlap 	 * this login response and we should just  drop it.
62130e7468fSPeter Dunlap 	 */
62230e7468fSPeter Dunlap 	if (icp->conn_login_state == LOGIN_TX) {
62330e7468fSPeter Dunlap 		icp->conn_login_datalen = pdu->isp_datalen;
62430e7468fSPeter Dunlap 		bcopy(pdu->isp_hdr, &icp->conn_login_resp_hdr,
62530e7468fSPeter Dunlap 		    sizeof (iscsi_hdr_t));
62630e7468fSPeter Dunlap 		/*
62730e7468fSPeter Dunlap 		 * Login code is sloppy with it's NULL handling so make sure
62830e7468fSPeter Dunlap 		 * we don't leave any stale data in there.
62930e7468fSPeter Dunlap 		 */
63030e7468fSPeter Dunlap 		bzero(icp->conn_login_data, icp->conn_login_max_data_length);
63130e7468fSPeter Dunlap 		bcopy(pdu->isp_data, icp->conn_login_data,
63230e7468fSPeter Dunlap 		    MIN(pdu->isp_datalen, icp->conn_login_max_data_length));
63330e7468fSPeter Dunlap 		iscsi_login_update_state_locked(icp, LOGIN_RX);
634fcf3ce44SJohn Forte 	}
63530e7468fSPeter Dunlap 	mutex_exit(&icp->conn_login_mutex);
636fcf3ce44SJohn Forte 
63730e7468fSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
638fcf3ce44SJohn Forte }
639fcf3ce44SJohn Forte 
640fcf3ce44SJohn Forte /*
641fcf3ce44SJohn Forte  * iscsi_rx_process_cmd_rsp - Process received scsi command response.  This
642fcf3ce44SJohn Forte  * will contain sense data if the command was not successful.  This data needs
643fcf3ce44SJohn Forte  * to be copied into the scsi_pkt.  Otherwise we just complete the IO.
644fcf3ce44SJohn Forte  */
64530e7468fSPeter Dunlap static idm_status_t
iscsi_rx_process_cmd_rsp(idm_conn_t * ic,idm_pdu_t * pdu)64630e7468fSPeter Dunlap iscsi_rx_process_cmd_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
647fcf3ce44SJohn Forte {
64830e7468fSPeter Dunlap 	iscsi_conn_t		*icp	= ic->ic_handle;
64930e7468fSPeter Dunlap 	iscsi_sess_t		*isp	= icp->conn_sess;
65030e7468fSPeter Dunlap 	iscsi_scsi_rsp_hdr_t	*issrhp	= (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr;
65130e7468fSPeter Dunlap 	uint8_t			*data	= pdu->isp_data;
65230e7468fSPeter Dunlap 	iscsi_cmd_t		*icmdp	= NULL;
65330e7468fSPeter Dunlap 	struct scsi_pkt		*pkt	= NULL;
65430e7468fSPeter Dunlap 	idm_status_t		rval;
65530e7468fSPeter Dunlap 	struct buf		*bp;
6562b79d384Sbing zhao - Sun Microsystems - Beijing China 	boolean_t		flush	= B_FALSE;
6572b79d384Sbing zhao - Sun Microsystems - Beijing China 	uint32_t		cmd_sn	= 0;
6582b79d384Sbing zhao - Sun Microsystems - Beijing China 	uint16_t		lun_num = 0;
659fcf3ce44SJohn Forte 
660fcf3ce44SJohn Forte 	/* make sure we get status in order */
66130e7468fSPeter Dunlap 	mutex_enter(&icp->conn_queue_active.mutex);
66230e7468fSPeter Dunlap 
66330e7468fSPeter Dunlap 	if ((rval = iscsi_rx_chk(icp, isp, issrhp,
66430e7468fSPeter Dunlap 	    &icmdp)) != IDM_STATUS_SUCCESS) {
66530e7468fSPeter Dunlap 		if (icmdp != NULL) {
66630e7468fSPeter Dunlap 			iscsi_task_cleanup(issrhp->opcode, icmdp);
66730e7468fSPeter Dunlap 		}
66830e7468fSPeter Dunlap 		mutex_exit(&icp->conn_queue_active.mutex);
66930e7468fSPeter Dunlap 		return (rval);
670fcf3ce44SJohn Forte 	}
671fcf3ce44SJohn Forte 
67230e7468fSPeter Dunlap 	/*
67330e7468fSPeter Dunlap 	 * If we are in "idm aborting" state then we shouldn't continue
67430e7468fSPeter Dunlap 	 * to process this command.  By definition this command is no longer
67530e7468fSPeter Dunlap 	 * on the active queue so we shouldn't try to remove it either.
67630e7468fSPeter Dunlap 	 */
67730e7468fSPeter Dunlap 	mutex_enter(&icmdp->cmd_mutex);
67830e7468fSPeter Dunlap 	if (icmdp->cmd_state == ISCSI_CMD_STATE_IDM_ABORTING) {
67930e7468fSPeter Dunlap 		mutex_exit(&icmdp->cmd_mutex);
680fcf3ce44SJohn Forte 		mutex_exit(&icp->conn_queue_active.mutex);
68130e7468fSPeter Dunlap 		return (IDM_STATUS_SUCCESS);
682fcf3ce44SJohn Forte 	}
68330e7468fSPeter Dunlap 	mutex_exit(&icmdp->cmd_mutex);
684fcf3ce44SJohn Forte 
68530e7468fSPeter Dunlap 	/* Get the IDM buffer and bytes transferred */
68630e7468fSPeter Dunlap 	bp = icmdp->cmd_un.scsi.bp;
68730e7468fSPeter Dunlap 	if (ic->ic_conn_flags & IDM_CONN_USE_SCOREBOARD) {
68830e7468fSPeter Dunlap 		/* Transport tracks bytes transferred so use those counts */
68930e7468fSPeter Dunlap 		if (bp && (bp->b_flags & B_READ)) {
69030e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.data_transferred +=
69130e7468fSPeter Dunlap 			    icmdp->cmd_itp->idt_rx_bytes;
69230e7468fSPeter Dunlap 		} else {
69330e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.data_transferred +=
69430e7468fSPeter Dunlap 			    icmdp->cmd_itp->idt_tx_bytes;
69530e7468fSPeter Dunlap 		}
69630e7468fSPeter Dunlap 	} else {
69730e7468fSPeter Dunlap 		/*
69830e7468fSPeter Dunlap 		 * Some transports cannot track the bytes transferred on
69930e7468fSPeter Dunlap 		 * the initiator side (like iSER) so we have to use the
70030e7468fSPeter Dunlap 		 * status info.  If the response field indicates that
70130e7468fSPeter Dunlap 		 * the command actually completed then we will assume
70230e7468fSPeter Dunlap 		 * the data_transferred value represents the entire buffer
70330e7468fSPeter Dunlap 		 * unless the resid field says otherwise.  This is a bit
70430e7468fSPeter Dunlap 		 * unintuitive but it's really impossible to know what
70530e7468fSPeter Dunlap 		 * has been transferred without detailed consideration
70630e7468fSPeter Dunlap 		 * of the SCSI status and sense key and that is outside
70730e7468fSPeter Dunlap 		 * the scope of the transport.  Instead the target/class driver
70830e7468fSPeter Dunlap 		 * can consider these values along with the resid and figure
70930e7468fSPeter Dunlap 		 * it out.  The data_transferred concept is just belt and
71030e7468fSPeter Dunlap 		 * suspenders anyway -- RFC 3720 actually explicitly rejects
71130e7468fSPeter Dunlap 		 * scoreboarding ("Initiators SHOULD NOT keep track of the
71230e7468fSPeter Dunlap 		 * data transferred to or from the target (scoreboarding)")
71330e7468fSPeter Dunlap 		 * perhaps for this very reason.
71430e7468fSPeter Dunlap 		 */
71530e7468fSPeter Dunlap 		if (issrhp->response != 0) {
71630e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.data_transferred = 0;
71730e7468fSPeter Dunlap 		} else {
71830e7468fSPeter Dunlap 			icmdp->cmd_un.scsi.data_transferred =
71930e7468fSPeter Dunlap 			    (bp == NULL) ? 0 : bp->b_bcount;
72030e7468fSPeter Dunlap 			if (issrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
72130e7468fSPeter Dunlap 				icmdp->cmd_un.scsi.data_transferred -=
72230e7468fSPeter Dunlap 				    ntohl(issrhp->residual_count);
72330e7468fSPeter Dunlap 			}
72430e7468fSPeter Dunlap 		}
72530e7468fSPeter Dunlap 	}
726fcf3ce44SJohn Forte 
72730e7468fSPeter Dunlap 	ISCSI_CHECK_SCSI_READ(icmdp, issrhp,
72830e7468fSPeter Dunlap 	    icmdp->cmd_un.scsi.data_transferred,
72930e7468fSPeter Dunlap 	    BP_CHECK_THOROUGH);
73030e7468fSPeter Dunlap 
73130e7468fSPeter Dunlap 	ISCSI_IO_LOG(CE_NOTE, "DEBUG: rx_process_cmd_rsp: ic: %p pdu: %p itt:"
73230e7468fSPeter Dunlap 	    " %x expcmdsn: %x sess_cmd: %x sess_expcmdsn: %x data_transfered:"
73330e7468fSPeter Dunlap 	    " %lu ibp: %p obp: %p", (void *)ic, (void *)pdu, issrhp->itt,
73430e7468fSPeter Dunlap 	    issrhp->expcmdsn, isp->sess_cmdsn, isp->sess_expcmdsn,
73530e7468fSPeter Dunlap 	    icmdp->cmd_un.scsi.data_transferred,
73630e7468fSPeter Dunlap 	    (void *)icmdp->cmd_un.scsi.ibp_ibuf,
73730e7468fSPeter Dunlap 	    (void *)icmdp->cmd_un.scsi.ibp_obuf);
73830e7468fSPeter Dunlap