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
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; \
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
73930e7468fSPeter Dunlap iscsi_task_cleanup(issrhp->opcode, icmdp);
740fcf3ce44SJohn Forte
741fcf3ce44SJohn Forte if (issrhp->response) {
742fcf3ce44SJohn Forte /* The target failed the command. */
74330e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: rx_process_cmd_rsp: ic: %p pdu:"
74430e7468fSPeter Dunlap " %p response: %d bcount: %lu", (void *)ic, (void *)pdu,
74530e7468fSPeter Dunlap issrhp->response, icmdp->cmd_un.scsi.bp->b_bcount);
74630e7468fSPeter Dunlap pkt = icmdp->cmd_un.scsi.pkt;
747fcf3ce44SJohn Forte pkt->pkt_reason = CMD_TRAN_ERR;
748fcf3ce44SJohn Forte if (icmdp->cmd_un.scsi.bp) {
749fcf3ce44SJohn Forte pkt->pkt_resid = icmdp->cmd_un.scsi.bp->b_bcount;
750fcf3ce44SJohn Forte } else {
751fcf3ce44SJohn Forte pkt->pkt_resid = 0;
752fcf3ce44SJohn Forte }
753fcf3ce44SJohn Forte } else {
754fcf3ce44SJohn Forte /* success */
75530e7468fSPeter Dunlap iscsi_cmd_rsp_chk(icmdp, issrhp);
7562b79d384Sbing zhao - Sun Microsystems - Beijing China flush = iscsi_cmd_rsp_cmd_status(icmdp, issrhp, data);
757b97c1f92SMilos Muzik
758b97c1f92SMilos Muzik ASSERT(icmdp->cmd_lun == NULL || icmdp->cmd_lun->lun_num ==
759b97c1f92SMilos Muzik (icmdp->cmd_un.scsi.lun & ISCSI_LUN_MASK));
760b97c1f92SMilos Muzik
7612b79d384Sbing zhao - Sun Microsystems - Beijing China if (flush == B_TRUE) {
7622b79d384Sbing zhao - Sun Microsystems - Beijing China cmd_sn = icmdp->cmd_sn;
763b97c1f92SMilos Muzik lun_num = icmdp->cmd_un.scsi.lun & ISCSI_LUN_MASK;
7642b79d384Sbing zhao - Sun Microsystems - Beijing China }
76530e7468fSPeter Dunlap }
766fcf3ce44SJohn Forte
76730e7468fSPeter Dunlap iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
7682b79d384Sbing zhao - Sun Microsystems - Beijing China if (flush == B_TRUE) {
7692b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_flush_cmd_after_reset(cmd_sn, lun_num, icp);
7702b79d384Sbing zhao - Sun Microsystems - Beijing China }
77130e7468fSPeter Dunlap mutex_exit(&icp->conn_queue_active.mutex);
77230e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS);
77330e7468fSPeter Dunlap }
774fcf3ce44SJohn Forte
77530e7468fSPeter Dunlap static void
iscsi_data_rsp_pkt(iscsi_cmd_t * icmdp,iscsi_data_rsp_hdr_t * idrhp)77630e7468fSPeter Dunlap iscsi_data_rsp_pkt(iscsi_cmd_t *icmdp, iscsi_data_rsp_hdr_t *idrhp)
77730e7468fSPeter Dunlap {
77830e7468fSPeter Dunlap struct buf *bp = NULL;
77930e7468fSPeter Dunlap size_t data_transferred;
78030e7468fSPeter Dunlap struct scsi_pkt *pkt;
781fcf3ce44SJohn Forte
78230e7468fSPeter Dunlap bp = icmdp->cmd_un.scsi.bp;
78330e7468fSPeter Dunlap pkt = icmdp->cmd_un.scsi.pkt;
78430e7468fSPeter Dunlap data_transferred = icmdp->cmd_un.scsi.data_transferred;
78530e7468fSPeter Dunlap /*
78630e7468fSPeter Dunlap * The command* must be completed now, since we won't get a command
78730e7468fSPeter Dunlap * response PDU. The cmd_status and residual_count are
78830e7468fSPeter Dunlap * not meaningful unless status_present is set.
78930e7468fSPeter Dunlap */
79030e7468fSPeter Dunlap pkt->pkt_resid = 0;
79130e7468fSPeter Dunlap /* Check the residual count */
79230e7468fSPeter Dunlap if (bp && (data_transferred != bp->b_bcount)) {
793fcf3ce44SJohn Forte /*
79430e7468fSPeter Dunlap * We didn't xfer the expected amount of data -
79530e7468fSPeter Dunlap * the residual_count in the header is only valid
79630e7468fSPeter Dunlap * if the underflow flag is set.
797fcf3ce44SJohn Forte */
79830e7468fSPeter Dunlap if (idrhp->flags & ISCSI_FLAG_DATA_UNDERFLOW) {
79930e7468fSPeter Dunlap pkt->pkt_resid = ntohl(idrhp->residual_count);
80030e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_data_rsp_pkt: "
80130e7468fSPeter Dunlap "underflow: itt: %d "
80230e7468fSPeter Dunlap "transferred: %lu count: %lu", idrhp->itt,
80330e7468fSPeter Dunlap data_transferred, bp->b_bcount);
80430e7468fSPeter Dunlap } else {
80530e7468fSPeter Dunlap if (bp->b_bcount > data_transferred) {
80630e7468fSPeter Dunlap /* Some data fell on the floor somehw */
80730e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: "
80830e7468fSPeter Dunlap "iscsi_data_rsp_pkt: data fell: itt: %d "
80930e7468fSPeter Dunlap "transferred: %lu count: %lu", idrhp->itt,
81030e7468fSPeter Dunlap data_transferred, bp->b_bcount);
81130e7468fSPeter Dunlap pkt->pkt_resid =
81230e7468fSPeter Dunlap bp->b_bcount - data_transferred;
813fcf3ce44SJohn Forte }
81430e7468fSPeter Dunlap }
81530e7468fSPeter Dunlap }
816fcf3ce44SJohn Forte
81730e7468fSPeter Dunlap pkt->pkt_reason = CMD_CMPLT;
81830e7468fSPeter Dunlap pkt->pkt_state |= (STATE_XFERRED_DATA | STATE_GOT_STATUS);
819fcf3ce44SJohn Forte
82030e7468fSPeter Dunlap if (((idrhp->cmd_status & STATUS_MASK) != STATUS_GOOD) &&
82130e7468fSPeter Dunlap (icmdp->cmd_un.scsi.statuslen >=
82230e7468fSPeter Dunlap sizeof (struct scsi_arq_status)) && pkt->pkt_scbp) {
823fcf3ce44SJohn Forte
82430e7468fSPeter Dunlap /*
82530e7468fSPeter Dunlap * Not supposed to get exception status here!
82630e7468fSPeter Dunlap * We have no request sense data so just do the
82730e7468fSPeter Dunlap * best we can
82830e7468fSPeter Dunlap */
82930e7468fSPeter Dunlap struct scsi_arq_status *arqstat =
83030e7468fSPeter Dunlap (struct scsi_arq_status *)pkt->pkt_scbp;
831fcf3ce44SJohn Forte
832fcf3ce44SJohn Forte
83330e7468fSPeter Dunlap bzero(arqstat, sizeof (struct scsi_arq_status));
834fcf3ce44SJohn Forte
83530e7468fSPeter Dunlap *((uchar_t *)&arqstat->sts_status) =
83630e7468fSPeter Dunlap idrhp->cmd_status;
837fcf3ce44SJohn Forte
838146832dbSMilos Muzik /* sense residual is set to whole size of sense buffer */
839146832dbSMilos Muzik arqstat->sts_rqpkt_resid = icmdp->cmd_un.scsi.statuslen -
840146832dbSMilos Muzik ISCSI_ARQ_STATUS_NOSENSE_LEN;
84130e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_data_rsp_pkt: "
84230e7468fSPeter Dunlap "exception status: itt: %d resid: %d",
84330e7468fSPeter Dunlap idrhp->itt, arqstat->sts_rqpkt_resid);
844b4243054SSheng-Liang Eric Zhang
84530e7468fSPeter Dunlap } else if (pkt->pkt_scbp) {
84630e7468fSPeter Dunlap /* just pass along the status we got */
84730e7468fSPeter Dunlap pkt->pkt_scbp[0] = idrhp->cmd_status;
848fcf3ce44SJohn Forte }
849fcf3ce44SJohn Forte }
850fcf3ce44SJohn Forte
851fcf3ce44SJohn Forte /*
85230e7468fSPeter Dunlap * iscsi_rx_process_data_rsp -
85330e7468fSPeter Dunlap * This currently processes the final data sequence denoted by the data response
85430e7468fSPeter Dunlap * PDU Status bit being set. We will not receive the SCSI response.
85530e7468fSPeter Dunlap * This bit denotes that the PDU is the successful completion of the
85630e7468fSPeter Dunlap * command.
857fcf3ce44SJohn Forte */
85830e7468fSPeter Dunlap static idm_status_t
iscsi_rx_process_data_rsp(idm_conn_t * ic,idm_pdu_t * pdu)85930e7468fSPeter Dunlap iscsi_rx_process_data_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
860fcf3ce44SJohn Forte {
86130e7468fSPeter Dunlap iscsi_sess_t *isp = NULL;
86230e7468fSPeter Dunlap iscsi_data_rsp_hdr_t *idrhp = (iscsi_data_rsp_hdr_t *)pdu->isp_hdr;
86330e7468fSPeter Dunlap iscsi_cmd_t *icmdp = NULL;
86430e7468fSPeter Dunlap struct buf *bp = NULL;
86530e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle;
86630e7468fSPeter Dunlap idm_buf_t *ibp;
86730e7468fSPeter Dunlap idm_status_t rval;
868fcf3ce44SJohn Forte
869fcf3ce44SJohn Forte
87030e7468fSPeter Dunlap /* should only call this when the data rsp contains final rsp */
87130e7468fSPeter Dunlap ASSERT(idrhp->flags & ISCSI_FLAG_DATA_STATUS);
87230e7468fSPeter Dunlap isp = icp->conn_sess;
87330e7468fSPeter Dunlap
874fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex);
87530e7468fSPeter Dunlap if ((rval = iscsi_rx_chk(icp, isp, (iscsi_scsi_rsp_hdr_t *)idrhp,
87630e7468fSPeter Dunlap &icmdp)) != IDM_STATUS_SUCCESS) {
87730e7468fSPeter Dunlap if (icmdp != NULL) {
87830e7468fSPeter Dunlap iscsi_task_cleanup(idrhp->opcode, icmdp);
87930e7468fSPeter Dunlap }
880fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
88130e7468fSPeter Dunlap return (rval);
882fcf3ce44SJohn Forte }
883fcf3ce44SJohn Forte
88430e7468fSPeter Dunlap /*
88530e7468fSPeter Dunlap * If we are in "idm aborting" state then we shouldn't continue
88630e7468fSPeter Dunlap * to process this command. By definition this command is no longer
88730e7468fSPeter Dunlap * on the active queue so we shouldn't try to remove it either.
88830e7468fSPeter Dunlap */
889fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex);
89030e7468fSPeter Dunlap if (icmdp->cmd_state == ISCSI_CMD_STATE_IDM_ABORTING) {
89130e7468fSPeter Dunlap mutex_exit(&icmdp->cmd_mutex);
89230e7468fSPeter Dunlap mutex_exit(&icp->conn_queue_active.mutex);
89330e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS);
89430e7468fSPeter Dunlap }
89530e7468fSPeter Dunlap mutex_exit(&icmdp->cmd_mutex);
89630e7468fSPeter Dunlap
89730e7468fSPeter Dunlap /*
89830e7468fSPeter Dunlap * Holding the pending/active queue locks across the
89930e7468fSPeter Dunlap * iscsi_rx_data call later in this function may cause
90030e7468fSPeter Dunlap * deadlock during fault injections. Instead remove
90130e7468fSPeter Dunlap * the cmd from the active queue and release the locks.
90230e7468fSPeter Dunlap * Then before returning or completing the command
90330e7468fSPeter Dunlap * return the cmd to the active queue and reacquire
90430e7468fSPeter Dunlap * the locks.
90530e7468fSPeter Dunlap */
90630e7468fSPeter Dunlap iscsi_dequeue_active_cmd(icp, icmdp);
90730e7468fSPeter Dunlap
90830e7468fSPeter Dunlap mutex_exit(&icp->conn_queue_active.mutex);
909fcf3ce44SJohn Forte
91030e7468fSPeter Dunlap /* shorthand some values */
911fcf3ce44SJohn Forte bp = icmdp->cmd_un.scsi.bp;
912fcf3ce44SJohn Forte
91330e7468fSPeter Dunlap /*
91430e7468fSPeter Dunlap * some poorly behaved targets have been observed
91530e7468fSPeter Dunlap * sending data-in pdu's during a write operation
91630e7468fSPeter Dunlap */
91730e7468fSPeter Dunlap if (bp != NULL) {
91830e7468fSPeter Dunlap if (!(bp->b_flags & B_READ)) {
91930e7468fSPeter Dunlap cmn_err(CE_WARN,
92030e7468fSPeter Dunlap "iscsi connection(%u) protocol error - "
92130e7468fSPeter Dunlap "received data response during write operation "
92230e7468fSPeter Dunlap "itt:0x%x",
92330e7468fSPeter Dunlap icp->conn_oid, idrhp->itt);
92430e7468fSPeter Dunlap mutex_enter(&icp->conn_queue_active.mutex);
92530e7468fSPeter Dunlap iscsi_enqueue_active_cmd(icp, icmdp);
92630e7468fSPeter Dunlap mutex_exit(&icp->conn_queue_active.mutex);
92730e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR);
92830e7468fSPeter Dunlap }
92930e7468fSPeter Dunlap }
93030e7468fSPeter Dunlap
93130e7468fSPeter Dunlap ibp = icmdp->cmd_un.scsi.ibp_ibuf;
93230e7468fSPeter Dunlap if (ibp == NULL) {
93330e7468fSPeter Dunlap /*
93430e7468fSPeter Dunlap * After the check of bp above we *should* have a corresponding
93530e7468fSPeter Dunlap * idm_buf_t (ibp). It's possible that the original call
93630e7468fSPeter Dunlap * to idm_buf_alloc failed due to a pending connection state
93730e7468fSPeter Dunlap * transition in which case this value can be NULL. It's
93830e7468fSPeter Dunlap * highly unlikely that the connection would be shutting down
93930e7468fSPeter Dunlap * *and* we manage to process a data response and get to this
94030e7468fSPeter Dunlap * point in the code but just in case we should check for it.
94130e7468fSPeter Dunlap * This isn't really a protocol error -- we are almost certainly
94230e7468fSPeter Dunlap * closing the connection anyway so just return a generic error.
94330e7468fSPeter Dunlap */
94430e7468fSPeter Dunlap mutex_enter(&icp->conn_queue_active.mutex);
94530e7468fSPeter Dunlap iscsi_enqueue_active_cmd(icp, icmdp);
94630e7468fSPeter Dunlap mutex_exit(&icp->conn_queue_active.mutex);
94730e7468fSPeter Dunlap return (IDM_STATUS_FAIL);
94830e7468fSPeter Dunlap }
94930e7468fSPeter Dunlap
95030e7468fSPeter Dunlap if (ic->ic_conn_flags & IDM_CONN_USE_SCOREBOARD) {
95130e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred =
95230e7468fSPeter Dunlap icmdp->cmd_itp->idt_rx_bytes;
953fcf3ce44SJohn Forte } else {
95430e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred = bp->b_bcount;
95530e7468fSPeter Dunlap if (idrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
95630e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred -=
95730e7468fSPeter Dunlap ntohl(idrhp->residual_count);
95830e7468fSPeter Dunlap }
959fcf3ce44SJohn Forte }
960fcf3ce44SJohn Forte
96130e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: rx_process_data_rsp: icp: %p pdu: %p "
96230e7468fSPeter Dunlap "itt: %d ibp: %p icmdp: %p xfer_len: %lu transferred: %lu dlen: %u",
96330e7468fSPeter Dunlap (void *)icp, (void *)pdu, idrhp->itt, (void *)bp, (void *)icmdp,
96430e7468fSPeter Dunlap (ibp == NULL) ? 0 : ibp->idb_xfer_len,
96530e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred,
96630e7468fSPeter Dunlap n2h24(idrhp->dlength));
96730e7468fSPeter Dunlap
96830e7468fSPeter Dunlap iscsi_task_cleanup(idrhp->opcode, icmdp);
96930e7468fSPeter Dunlap
97030e7468fSPeter Dunlap iscsi_data_rsp_pkt(icmdp, idrhp);
97130e7468fSPeter Dunlap
97230e7468fSPeter Dunlap mutex_enter(&icp->conn_queue_active.mutex);
97330e7468fSPeter Dunlap iscsi_enqueue_active_cmd(icp, icmdp);
97430e7468fSPeter Dunlap iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
975fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
976fcf3ce44SJohn Forte
97730e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS);
978fcf3ce44SJohn Forte }
979fcf3ce44SJohn Forte
980fcf3ce44SJohn Forte /*
981fcf3ce44SJohn Forte * iscsi_rx_process_nop - Process a received nop. If nop is in response
982fcf3ce44SJohn Forte * to a ping we sent update stats. If initiated by the target we need
983fcf3ce44SJohn Forte * to response back to the target with a nop. Schedule the response.
984fcf3ce44SJohn Forte */
985fcf3ce44SJohn Forte /* ARGSUSED */
98630e7468fSPeter Dunlap static idm_status_t
iscsi_rx_process_nop(idm_conn_t * ic,idm_pdu_t * pdu)98730e7468fSPeter Dunlap iscsi_rx_process_nop(idm_conn_t *ic, idm_pdu_t *pdu)
988fcf3ce44SJohn Forte {
989fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL;
99030e7468fSPeter Dunlap iscsi_nop_in_hdr_t *inihp = (iscsi_nop_in_hdr_t *)pdu->isp_hdr;
991fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL;
99230e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle;
993fcf3ce44SJohn Forte
994fcf3ce44SJohn Forte if (icp->conn_expstatsn != ntohl(inihp->statsn)) {
99530e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - "
996fcf3ce44SJohn Forte "received status out of order itt:0x%x statsn:0x%x "
99730e7468fSPeter Dunlap "expstatsn:0x%x", icp->conn_oid, inihp->opcode, inihp->itt,
998fcf3ce44SJohn Forte ntohl(inihp->statsn), icp->conn_expstatsn);
99930e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR);
1000fcf3ce44SJohn Forte }
100130e7468fSPeter Dunlap isp = icp->conn_sess;
100230e7468fSPeter Dunlap ASSERT(isp != NULL);
1003fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex);
1004fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex);
1005fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex);
1006fcf3ce44SJohn Forte if (inihp->itt != ISCSI_RSVD_TASK_TAG) {
1007fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(
100830e7468fSPeter Dunlap isp, (iscsi_hdr_t *)inihp, &icmdp))) {
100930e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi connection(%u) protocol error "
101030e7468fSPeter Dunlap "- can not find cmd for itt:0x%x",
101130e7468fSPeter Dunlap icp->conn_oid, inihp->itt);
1012fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex);
1013fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
1014fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex);
101530e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR);
1016fcf3ce44SJohn Forte }
1017fcf3ce44SJohn Forte }
1018fcf3ce44SJohn Forte
1019fcf3ce44SJohn Forte /* update expcmdsn and maxcmdsn */
1020fcf3ce44SJohn Forte iscsi_update_flow_control(isp, ntohl(inihp->maxcmdsn),
1021fcf3ce44SJohn Forte ntohl(inihp->expcmdsn));
1022fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex);
1023fcf3ce44SJohn Forte
1024fcf3ce44SJohn Forte if ((inihp->itt != ISCSI_RSVD_TASK_TAG) &&
1025fcf3ce44SJohn Forte (inihp->ttt == ISCSI_RSVD_TASK_TAG)) {
1026fcf3ce44SJohn Forte /* This is the only type of nop that incs. the expstatsn */
1027fcf3ce44SJohn Forte icp->conn_expstatsn++;
1028fcf3ce44SJohn Forte
1029fcf3ce44SJohn Forte /*
1030fcf3ce44SJohn Forte * This is a targets response to our nop
1031fcf3ce44SJohn Forte */
1032fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
1033fcf3ce44SJohn Forte } else if (inihp->ttt != ISCSI_RSVD_TASK_TAG) {
1034fcf3ce44SJohn Forte /*
1035fcf3ce44SJohn Forte * Target requested a nop. Send one.
1036fcf3ce44SJohn Forte */
1037fcf3ce44SJohn Forte iscsi_handle_nop(icp, ISCSI_RSVD_TASK_TAG, inihp->ttt);
1038fcf3ce44SJohn Forte } else {
1039fcf3ce44SJohn Forte /*
1040fcf3ce44SJohn Forte * This is a target-initiated ping that doesn't expect
1041fcf3ce44SJohn Forte * a response; nothing to do except update our flow control
1042fcf3ce44SJohn Forte * (which we do in all cases above).
1043fcf3ce44SJohn Forte */
1044fcf3ce44SJohn Forte /* EMPTY */
1045fcf3ce44SJohn Forte }
1046fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
1047fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex);
1048fcf3ce44SJohn Forte
104930e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS);
1050fcf3ce44SJohn Forte }
1051fcf3ce44SJohn Forte
1052fcf3ce44SJohn Forte
1053fcf3ce44SJohn Forte /*
1054fcf3ce44SJohn Forte * iscsi_rx_process_reject_rsp - The server rejected a PDU
1055fcf3ce44SJohn Forte */
105630e7468fSPeter Dunlap static idm_status_t
iscsi_rx_process_reject_rsp(idm_conn_t * ic,idm_pdu_t * pdu)105730e7468fSPeter Dunlap iscsi_rx_process_reject_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
1058fcf3ce44SJohn Forte {
105930e7468fSPeter Dunlap iscsi_reject_rsp_hdr_t *irrhp = (iscsi_reject_rsp_hdr_t *)pdu->isp_hdr;
106030e7468fSPeter Dunlap iscsi_sess_t *isp = NULL;
106130e7468fSPeter Dunlap uint32_t dlength = 0;
106230e7468fSPeter Dunlap iscsi_hdr_t *old_ihp = NULL;
106330e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle;
1064811eca55SToomas Soome uint8_t *data = pdu->isp_data;
1065aefdd131Sbing zhao - Sun Microsystems - Beijing China idm_status_t status = IDM_STATUS_SUCCESS;
1066aefdd131Sbing zhao - Sun Microsystems - Beijing China int i = 0;
1067fcf3ce44SJohn Forte
1068fcf3ce44SJohn Forte ASSERT(data != NULL);
106930e7468fSPeter Dunlap isp = icp->conn_sess;
107030e7468fSPeter Dunlap ASSERT(isp != NULL);
1071fcf3ce44SJohn Forte
1072aefdd131Sbing zhao - Sun Microsystems - Beijing China /*
1073aefdd131Sbing zhao - Sun Microsystems - Beijing China * In RFC3720 section 10.17, this 4 bytes should be all 0xff.
1074aefdd131Sbing zhao - Sun Microsystems - Beijing China */
1075aefdd131Sbing zhao - Sun Microsystems - Beijing China for (i = 0; i < 4; i++) {
1076aefdd131Sbing zhao - Sun Microsystems - Beijing China if (irrhp->must_be_ff[i] != 0xff) {
1077aefdd131Sbing zhao - Sun Microsystems - Beijing China return (IDM_STATUS_PROTOCOL_ERROR);
1078aefdd131Sbing zhao - Sun Microsystems - Beijing China }
1079aefdd131Sbing zhao - Sun Microsystems - Beijing China }
1080aefdd131Sbing zhao - Sun Microsystems - Beijing China mutex_enter(&isp->sess_cmdsn_mutex);
1081aefdd131Sbing zhao - Sun Microsystems - Beijing China
1082aefdd131Sbing zhao - Sun Microsystems - Beijing China if (icp->conn_expstatsn == ntohl(irrhp->statsn)) {
1083aefdd131Sbing zhao - Sun Microsystems - Beijing China icp->conn_expstatsn++;
1084aefdd131Sbing zhao - Sun Microsystems - Beijing China } else {
1085aefdd131Sbing zhao - Sun Microsystems - Beijing China cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - "
1086aefdd131Sbing zhao - Sun Microsystems - Beijing China "received status out of order statsn:0x%x "
1087aefdd131Sbing zhao - Sun Microsystems - Beijing China "expstatsn:0x%x", icp->conn_oid, irrhp->opcode,
1088aefdd131Sbing zhao - Sun Microsystems - Beijing China ntohl(irrhp->statsn), icp->conn_expstatsn);
1089aefdd131Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&isp->sess_cmdsn_mutex);
1090aefdd131Sbing zhao - Sun Microsystems - Beijing China return (IDM_STATUS_PROTOCOL_ERROR);
1091fcf3ce44SJohn Forte }
1092aefdd131Sbing zhao - Sun Microsystems - Beijing China /* update expcmdsn and maxcmdsn */
1093aefdd131Sbing zhao - Sun Microsystems - Beijing China iscsi_update_flow_control(isp, ntohl(irrhp->maxcmdsn),
1094aefdd131Sbing zhao - Sun Microsystems - Beijing China ntohl(irrhp->expcmdsn));
1095aefdd131Sbing zhao - Sun Microsystems - Beijing China
1096aefdd131Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&isp->sess_cmdsn_mutex);
1097fcf3ce44SJohn Forte
1098fcf3ce44SJohn Forte /* If we don't have the rejected header we can't do anything */
1099fcf3ce44SJohn Forte dlength = n2h24(irrhp->dlength);
1100fcf3ce44SJohn Forte if (dlength < sizeof (iscsi_hdr_t)) {
110130e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR);
1102fcf3ce44SJohn Forte }
1103fcf3ce44SJohn Forte
1104fcf3ce44SJohn Forte /* map old ihp */
1105fcf3ce44SJohn Forte old_ihp = (iscsi_hdr_t *)data;
1106fcf3ce44SJohn Forte
1107fcf3ce44SJohn Forte switch (irrhp->reason) {
1108fcf3ce44SJohn Forte /*
1109fcf3ce44SJohn Forte * ISCSI_REJECT_IMM_CMD_REJECT - Immediate Command Reject
1110fcf3ce44SJohn Forte * too many immediate commands (original cmd can be resent)
1111fcf3ce44SJohn Forte */
1112fcf3ce44SJohn Forte case ISCSI_REJECT_IMM_CMD_REJECT:
1113fcf3ce44SJohn Forte /*
1114fcf3ce44SJohn Forte * We have exceeded the server's capacity for outstanding
1115fcf3ce44SJohn Forte * immediate commands. This must be a task management
1116fcf3ce44SJohn Forte * command so try to find it in the abortingqueue and
1117fcf3ce44SJohn Forte * complete it.
1118fcf3ce44SJohn Forte */
1119fcf3ce44SJohn Forte if (!(old_ihp->opcode & ISCSI_OP_IMMEDIATE)) {
1120fcf3ce44SJohn Forte /* Rejecting IMM but old old_hdr wasn't IMM */
112130e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR);
1122fcf3ce44SJohn Forte }
1123fcf3ce44SJohn Forte
1124fcf3ce44SJohn Forte /*
1125fcf3ce44SJohn Forte * We only send NOP and TASK_MGT as IMM. All other
1126fcf3ce44SJohn Forte * cases should be considered as a protocol error.
1127fcf3ce44SJohn Forte */
1128fcf3ce44SJohn Forte switch (old_ihp->opcode & ISCSI_OPCODE_MASK) {
1129fcf3ce44SJohn Forte case ISCSI_OP_NOOP_OUT:
1130fcf3ce44SJohn Forte /*
1131fcf3ce44SJohn Forte * A ping was rejected - treat this like
1132fcf3ce44SJohn Forte * ping response. The down side is we
1133fcf3ce44SJohn Forte * didn't get an updated MaxCmdSn.
1134fcf3ce44SJohn Forte */
1135fcf3ce44SJohn Forte break;
1136fcf3ce44SJohn Forte case ISCSI_OP_SCSI_TASK_MGT_MSG:
1137aefdd131Sbing zhao - Sun Microsystems - Beijing China status =
1138aefdd131Sbing zhao - Sun Microsystems - Beijing China iscsi_rx_process_rejected_tsk_mgt(ic, old_ihp);
1139fcf3ce44SJohn Forte break;
1140fcf3ce44SJohn Forte default:
1141fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error "
1142fcf3ce44SJohn Forte "- received a reject for a command(0x%02x) not "
1143fcf3ce44SJohn Forte "sent as an immediate", icp->conn_oid,
1144fcf3ce44SJohn Forte old_ihp->opcode);
114530e7468fSPeter Dunlap status = IDM_STATUS_PROTOCOL_ERROR;
114630e7468fSPeter Dunlap break;
1147fcf3ce44SJohn Forte }
1148fcf3ce44SJohn Forte break;
1149fcf3ce44SJohn Forte
1150fcf3ce44SJohn Forte /*
1151fcf3ce44SJohn Forte * For the rest of the reject cases just use the general
1152fcf3ce44SJohn Forte * hammer of dis/reconnecting. This will resolve all
1153fcf3ce44SJohn Forte * noted issues although could be more graceful.
1154fcf3ce44SJohn Forte */
1155fcf3ce44SJohn Forte case ISCSI_REJECT_DATA_DIGEST_ERROR:
1156fcf3ce44SJohn Forte case ISCSI_REJECT_CMD_BEFORE_LOGIN:
1157fcf3ce44SJohn Forte case ISCSI_REJECT_SNACK_REJECT:
1158fcf3ce44SJohn Forte case ISCSI_REJECT_PROTOCOL_ERROR:
1159fcf3ce44SJohn Forte case ISCSI_REJECT_CMD_NOT_SUPPORTED:
1160fcf3ce44SJohn Forte case ISCSI_REJECT_TASK_IN_PROGRESS:
1161fcf3ce44SJohn Forte case ISCSI_REJECT_INVALID_DATA_ACK:
1162fcf3ce44SJohn Forte case ISCSI_REJECT_INVALID_PDU_FIELD:
1163fcf3ce44SJohn Forte case ISCSI_REJECT_LONG_OPERATION_REJECT:
1164fcf3ce44SJohn Forte case ISCSI_REJECT_NEGOTIATION_RESET:
1165fcf3ce44SJohn Forte default:
1166aefdd131Sbing zhao - Sun Microsystems - Beijing China cmn_err(CE_WARN, "iscsi connection(%u/%x) closing connection - "
1167aefdd131Sbing zhao - Sun Microsystems - Beijing China "target requested reason:0x%x",
1168aefdd131Sbing zhao - Sun Microsystems - Beijing China icp->conn_oid, irrhp->opcode, irrhp->reason);
116930e7468fSPeter Dunlap status = IDM_STATUS_PROTOCOL_ERROR;
117030e7468fSPeter Dunlap break;
1171fcf3ce44SJohn Forte }
1172fcf3ce44SJohn Forte
1173aefdd131Sbing zhao - Sun Microsystems - Beijing China return (status);
1174fcf3ce44SJohn Forte }
1175fcf3ce44SJohn Forte
1176fcf3ce44SJohn Forte
1177fcf3ce44SJohn Forte /*
1178fcf3ce44SJohn Forte * iscsi_rx_process_rejected_tsk_mgt -
1179fcf3ce44SJohn Forte */
118030e7468fSPeter Dunlap /* ARGSUSED */
118130e7468fSPeter Dunlap static idm_status_t
iscsi_rx_process_rejected_tsk_mgt(idm_conn_t * ic,iscsi_hdr_t * old_ihp)118230e7468fSPeter Dunlap iscsi_rx_process_rejected_tsk_mgt(idm_conn_t *ic, iscsi_hdr_t *old_ihp)
1183fcf3ce44SJohn Forte {
118430e7468fSPeter Dunlap iscsi_sess_t *isp = NULL;
118530e7468fSPeter Dunlap iscsi_cmd_t *icmdp = NULL;
1186811eca55SToomas Soome iscsi_conn_t *icp = ic->ic_handle;
1187fcf3ce44SJohn Forte
1188fcf3ce44SJohn Forte isp = icp->conn_sess;
1189fcf3ce44SJohn Forte ASSERT(old_ihp != NULL);
119030e7468fSPeter Dunlap ASSERT(isp != NULL);
1191fcf3ce44SJohn Forte
1192fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex);
1193fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex);
1194fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(
1195fcf3ce44SJohn Forte isp, old_ihp, &icmdp))) {
1196fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex);
1197fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
119830e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR);
1199fcf3ce44SJohn Forte }
1200fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex);
1201fcf3ce44SJohn Forte
1202fcf3ce44SJohn Forte switch (icmdp->cmd_type) {
1203fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_ABORT:
1204fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_RESET:
1205fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E4,
1206fcf3ce44SJohn Forte icp->conn_sess);
1207fcf3ce44SJohn Forte break;
1208fcf3ce44SJohn Forte /* We don't send any other task mgr types */
1209fcf3ce44SJohn Forte default:
1210fcf3ce44SJohn Forte ASSERT(B_FALSE);
1211fcf3ce44SJohn Forte break;
1212fcf3ce44SJohn Forte }
1213fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
1214fcf3ce44SJohn Forte
121530e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS);
1216fcf3ce44SJohn Forte }
1217fcf3ce44SJohn Forte
1218fcf3ce44SJohn Forte
1219fcf3ce44SJohn Forte /*
1220fcf3ce44SJohn Forte * iscsi_rx_process_task_mgt_rsp -
1221fcf3ce44SJohn Forte */
1222fcf3ce44SJohn Forte /* ARGSUSED */
122330e7468fSPeter Dunlap static idm_status_t
iscsi_rx_process_task_mgt_rsp(idm_conn_t * ic,idm_pdu_t * pdu)122430e7468fSPeter Dunlap iscsi_rx_process_task_mgt_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
1225fcf3ce44SJohn Forte {
1226fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL;
1227fcf3ce44SJohn Forte iscsi_scsi_task_mgt_rsp_hdr_t *istmrhp = NULL;
1228fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL;
122930e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle;
123030e7468fSPeter Dunlap idm_status_t status = IDM_STATUS_SUCCESS;
1231fcf3ce44SJohn Forte
1232fcf3ce44SJohn Forte isp = icp->conn_sess;
123330e7468fSPeter Dunlap istmrhp = (iscsi_scsi_task_mgt_rsp_hdr_t *)pdu->isp_hdr;
1234fcf3ce44SJohn Forte
1235fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex);
123630e7468fSPeter Dunlap if ((status = iscsi_rx_chk(icp, isp, (iscsi_scsi_rsp_hdr_t *)istmrhp,
123730e7468fSPeter Dunlap &icmdp)) != IDM_STATUS_SUCCESS) {
1238fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
123930e7468fSPeter Dunlap return (status);
1240fcf3ce44SJohn Forte }
1241fcf3ce44SJohn Forte
1242fcf3ce44SJohn Forte switch (icmdp->cmd_type) {
1243fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_ABORT:
1244fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_RESET:
1245fcf3ce44SJohn Forte switch (istmrhp->response) {
1246fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_COMPLETE:
1247fcf3ce44SJohn Forte /* success */
1248fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp,
1249fcf3ce44SJohn Forte ISCSI_CMD_EVENT_E3, isp);
1250fcf3ce44SJohn Forte break;
1251fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_NO_TASK:
1252fcf3ce44SJohn Forte /*
1253fcf3ce44SJohn Forte * If the array no longer knows about
1254fcf3ce44SJohn Forte * an ABORT RTT and we no longer have
1255fcf3ce44SJohn Forte * a parent SCSI command it was just
1256fcf3ce44SJohn Forte * completed, free this ABORT resource.
1257fcf3ce44SJohn Forte * Otherwise FALLTHRU this will flag a
1258fcf3ce44SJohn Forte * protocol problem.
1259fcf3ce44SJohn Forte */
1260fcf3ce44SJohn Forte if ((icmdp->cmd_type == ISCSI_CMD_TYPE_ABORT) &&
1261fcf3ce44SJohn Forte (icmdp->cmd_un.abort.icmdp == NULL)) {
1262fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp,
1263fcf3ce44SJohn Forte ISCSI_CMD_EVENT_E4, isp);
1264fcf3ce44SJohn Forte break;
1265fcf3ce44SJohn Forte }
1266fcf3ce44SJohn Forte /* FALLTHRU */
12672b79d384Sbing zhao - Sun Microsystems - Beijing China case SCSI_TCP_TM_RESP_REJECTED:
12682b79d384Sbing zhao - Sun Microsystems - Beijing China /*
12692b79d384Sbing zhao - Sun Microsystems - Beijing China * If the target rejects our reset task,
12702b79d384Sbing zhao - Sun Microsystems - Beijing China * we should record the response and complete
12712b79d384Sbing zhao - Sun Microsystems - Beijing China * this command with the result.
12722b79d384Sbing zhao - Sun Microsystems - Beijing China */
12732b79d384Sbing zhao - Sun Microsystems - Beijing China if (icmdp->cmd_type == ISCSI_CMD_TYPE_RESET) {
12742b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_un.reset.response =
12752b79d384Sbing zhao - Sun Microsystems - Beijing China istmrhp->response;
12762b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_state_machine(icmdp,
12772b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_EVENT_E3, isp);
12782b79d384Sbing zhao - Sun Microsystems - Beijing China break;
12792b79d384Sbing zhao - Sun Microsystems - Beijing China }
12802b79d384Sbing zhao - Sun Microsystems - Beijing China /* FALLTHRU */
1281fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_NO_LUN:
1282fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_TASK_ALLEGIANT:
1283fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_NO_FAILOVER:
1284fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_IN_PRGRESS:
1285fcf3ce44SJohn Forte default:
1286fcf3ce44SJohn Forte /*
1287fcf3ce44SJohn Forte * Something is out of sync. Flush
1288fcf3ce44SJohn Forte * active queues and resync the
1289fcf3ce44SJohn Forte * the connection to try and recover
1290fcf3ce44SJohn Forte * to a known state.
1291fcf3ce44SJohn Forte */
129230e7468fSPeter Dunlap status = IDM_STATUS_PROTOCOL_ERROR;
1293fcf3ce44SJohn Forte }
1294fcf3ce44SJohn Forte break;
1295fcf3ce44SJohn Forte
1296fcf3ce44SJohn Forte default:
1297fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
1298fcf3ce44SJohn Forte "received a task mgt response for a non-task mgt "
1299fcf3ce44SJohn Forte "cmd itt:0x%x type:%d", icp->conn_oid, istmrhp->itt,
1300fcf3ce44SJohn Forte icmdp->cmd_type);
130130e7468fSPeter Dunlap status = IDM_STATUS_PROTOCOL_ERROR;
130230e7468fSPeter Dunlap break;
1303fcf3ce44SJohn Forte }
1304fcf3ce44SJohn Forte
1305fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
130630e7468fSPeter Dunlap return (status);
1307fcf3ce44SJohn Forte }
1308fcf3ce44SJohn Forte
1309fcf3ce44SJohn Forte
1310fcf3ce44SJohn Forte /*
131130e7468fSPeter Dunlap * iscsi_rx_process_logout_rsp -
1312fcf3ce44SJohn Forte *
1313fcf3ce44SJohn Forte */
1314fcf3ce44SJohn Forte /* ARGSUSED */
131530e7468fSPeter Dunlap idm_status_t
iscsi_rx_process_logout_rsp(idm_conn_t * ic,idm_pdu_t * pdu)131630e7468fSPeter Dunlap iscsi_rx_process_logout_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
1317fcf3ce44SJohn Forte {
131830e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle;
131930e7468fSPeter Dunlap iscsi_logout_rsp_hdr_t *ilrhp =
132030e7468fSPeter Dunlap (iscsi_logout_rsp_hdr_t *)pdu->isp_hdr;
1321fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL;
132230e7468fSPeter Dunlap iscsi_sess_t *isp;
132330e7468fSPeter Dunlap idm_status_t status = IDM_STATUS_SUCCESS;
1324fcf3ce44SJohn Forte
1325fcf3ce44SJohn Forte isp = icp->conn_sess;
1326fcf3ce44SJohn Forte
1327fcf3ce44SJohn Forte if (icp->conn_expstatsn != ntohl(ilrhp->statsn)) {
132830e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - "
1329fcf3ce44SJohn Forte "received status out of order itt:0x%x statsn:0x%x "
133030e7468fSPeter Dunlap "expstatsn:0x%x", icp->conn_oid, ilrhp->opcode, ilrhp->itt,
1331fcf3ce44SJohn Forte ntohl(ilrhp->statsn), icp->conn_expstatsn);
133230e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR);
1333fcf3ce44SJohn Forte }
1334fcf3ce44SJohn Forte
1335fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex);
1336fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex);
1337fcf3ce44SJohn Forte if (ilrhp->itt != ISCSI_RSVD_TASK_TAG) {
1338fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(
133930e7468fSPeter Dunlap isp, (iscsi_hdr_t *)ilrhp, &icmdp))) {
1340fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex);
1341fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
134230e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR);
1343fcf3ce44SJohn Forte }
1344fcf3ce44SJohn Forte }
1345fcf3ce44SJohn Forte
1346fcf3ce44SJohn Forte /* update expcmdsn and maxcmdsn */
1347fcf3ce44SJohn Forte iscsi_update_flow_control(isp, ntohl(ilrhp->maxcmdsn),
1348fcf3ce44SJohn Forte ntohl(ilrhp->expcmdsn));
1349fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex);
1350fcf3ce44SJohn Forte
135130e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE,
135230e7468fSPeter Dunlap "DEBUG: iscsi_rx_process_logout_rsp: response: %d",
135330e7468fSPeter Dunlap ilrhp->response);
1354fcf3ce44SJohn Forte switch (ilrhp->response) {
1355fcf3ce44SJohn Forte case ISCSI_LOGOUT_CID_NOT_FOUND:
1356fcf3ce44SJohn Forte /*
1357fcf3ce44SJohn Forte * If the target doesn't know about our connection
1358fcf3ce44SJohn Forte * then we can consider our self disconnected.
1359fcf3ce44SJohn Forte */
1360fcf3ce44SJohn Forte /* FALLTHRU */
1361fcf3ce44SJohn Forte case ISCSI_LOGOUT_RECOVERY_UNSUPPORTED:
1362fcf3ce44SJohn Forte /*
1363fcf3ce44SJohn Forte * We don't support ErrorRecovery levels above 0
1364fcf3ce44SJohn Forte * currently so consider this success.
1365fcf3ce44SJohn Forte */
1366fcf3ce44SJohn Forte /* FALLTHRU */
1367fcf3ce44SJohn Forte case ISCSI_LOGOUT_CLEANUP_FAILED:
1368fcf3ce44SJohn Forte /*
1369fcf3ce44SJohn Forte * per spec. "cleanup failed for various reasons."
1370fcf3ce44SJohn Forte * Although those various reasons are undefined.
1371fcf3ce44SJohn Forte * Not sure what to do here. So fake success,
1372fcf3ce44SJohn Forte * which will disconnect the connection.
1373fcf3ce44SJohn Forte */
1374fcf3ce44SJohn Forte /* FALLTHRU */
1375fcf3ce44SJohn Forte case ISCSI_LOGOUT_SUCCESS:
1376fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
1377fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
137830e7468fSPeter Dunlap iscsi_drop_conn_cleanup(icp);
1379fcf3ce44SJohn Forte break;
1380fcf3ce44SJohn Forte default:
1381fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
138230e7468fSPeter Dunlap status = IDM_STATUS_PROTOCOL_ERROR;
138330e7468fSPeter Dunlap break;
1384fcf3ce44SJohn Forte
138530e7468fSPeter Dunlap }
138630e7468fSPeter Dunlap return (status);
1387fcf3ce44SJohn Forte }
1388fcf3ce44SJohn Forte
1389fcf3ce44SJohn Forte /*
139030e7468fSPeter Dunlap * iscsi_rx_process_async_rsp
1391fcf3ce44SJohn Forte *
1392fcf3ce44SJohn Forte */
1393fcf3ce44SJohn Forte /* ARGSUSED */
139430e7468fSPeter Dunlap static idm_status_t
iscsi_rx_process_async_rsp(idm_conn_t * ic,idm_pdu_t * pdu)139530e7468fSPeter Dunlap iscsi_rx_process_async_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
1396fcf3ce44SJohn Forte {
139730e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle;
139830e7468fSPeter Dunlap iscsi_sess_t *isp = icp->conn_sess;
139930e7468fSPeter Dunlap idm_status_t rval = IDM_STATUS_SUCCESS;
140030e7468fSPeter Dunlap iscsi_task_t *itp;
140130e7468fSPeter Dunlap iscsi_async_evt_hdr_t *iaehp =
140230e7468fSPeter Dunlap (iscsi_async_evt_hdr_t *)pdu->isp_hdr;
1403fcf3ce44SJohn Forte
1404fcf3ce44SJohn Forte ASSERT(icp != NULL);
140530e7468fSPeter Dunlap ASSERT(pdu != NULL);
140630e7468fSPeter Dunlap ASSERT(isp != NULL);
1407fcf3ce44SJohn Forte
140830e7468fSPeter Dunlap mutex_enter(&isp->sess_cmdsn_mutex);
140930e7468fSPeter Dunlap if (icp->conn_expstatsn == ntohl(iaehp->statsn)) {
141030e7468fSPeter Dunlap icp->conn_expstatsn++;
141130e7468fSPeter Dunlap } else {
1412fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
141330e7468fSPeter Dunlap "received status out of order statsn:0x%x "
141430e7468fSPeter Dunlap "expstatsn:0x%x", icp->conn_oid,
1415fcf3ce44SJohn Forte ntohl(iaehp->statsn), icp->conn_expstatsn);
141630e7468fSPeter Dunlap mutex_exit(&isp->sess_cmdsn_mutex);
141730e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR);
1418fcf3ce44SJohn Forte }
141930e7468fSPeter Dunlap mutex_exit(&isp->sess_cmdsn_mutex);
1420fcf3ce44SJohn Forte
1421fcf3ce44SJohn Forte switch (iaehp->async_event) {
1422fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_SCSI_EVENT:
1423fcf3ce44SJohn Forte /*
1424fcf3ce44SJohn Forte * SCSI asynchronous event is reported in
1425fcf3ce44SJohn Forte * the sense data. Sense data that accompanies
1426fcf3ce44SJohn Forte * the report in the data segment identifies the
1427fcf3ce44SJohn Forte * condition. If the target supports SCSI
1428fcf3ce44SJohn Forte * asynchronous events reporting (see [SAM2])
1429fcf3ce44SJohn Forte * as indicated in the stardard INQUIRY data
1430fcf3ce44SJohn Forte * (see [SPC3]), its use may be enabled by
1431fcf3ce44SJohn Forte * parameters in the SCSI control mode page
1432fcf3ce44SJohn Forte * (see [SPC3]).
1433fcf3ce44SJohn Forte *
1434fcf3ce44SJohn Forte * T-10 has removed SCSI asunchronous events
1435fcf3ce44SJohn Forte * from the standard. Although we have seen
1436fcf3ce44SJohn Forte * a couple targets still spending these requests.
1437fcf3ce44SJohn Forte * Those targets were specifically sending them
1438fcf3ce44SJohn Forte * for notification of a LUN/Volume change
1439904e51f6SJack Meng * (ex. LUN addition/removal). Fire the enumeration
1440904e51f6SJack Meng * to handle the change.
1441fcf3ce44SJohn Forte */
1442904e51f6SJack Meng if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1443904e51f6SJack Meng rw_enter(&isp->sess_state_rwlock, RW_READER);
1444904e51f6SJack Meng if (isp->sess_state == ISCSI_SESS_STATE_LOGGED_IN) {
1445904e51f6SJack Meng (void) iscsi_sess_enum_request(isp, B_FALSE,
1446904e51f6SJack Meng isp->sess_state_event_count);
1447904e51f6SJack Meng }
1448904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock);
1449904e51f6SJack Meng }
1450fcf3ce44SJohn Forte break;
1451fcf3ce44SJohn Forte
1452fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT:
145330e7468fSPeter Dunlap /*
145430e7468fSPeter Dunlap * We've been asked to logout by the target --
145530e7468fSPeter Dunlap * we need to treat this differently from a normal logout
145630e7468fSPeter Dunlap * due to a discovery failure. Normal logouts result in
145730e7468fSPeter Dunlap * an N3 event to the session state machine and an offline
145830e7468fSPeter Dunlap * of the lun. In this case we want to put the connection
145930e7468fSPeter Dunlap * into "failed" state and generate N5 to the session state
146030e7468fSPeter Dunlap * machine since the initiator logged out at the target's
146130e7468fSPeter Dunlap * request. To track this we set a flag indicating we
146230e7468fSPeter Dunlap * received this async logout request from the tharget
146330e7468fSPeter Dunlap */
1464fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex);
146530e7468fSPeter Dunlap icp->conn_async_logout = B_TRUE;
1466fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex);
146730e7468fSPeter Dunlap
146892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* Hold is released in iscsi_handle_logout. */
146992adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_conn_hold(ic);
147092adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States
147130e7468fSPeter Dunlap /* Target has requested this connection to logout. */
147230e7468fSPeter Dunlap itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
147330e7468fSPeter Dunlap itp->t_arg = icp;
147430e7468fSPeter Dunlap itp->t_blocking = B_FALSE;
1475904e51f6SJack Meng if (ddi_taskq_dispatch(isp->sess_login_taskq,
147630e7468fSPeter Dunlap (void(*)())iscsi_logout_start, itp, DDI_SLEEP) !=
147730e7468fSPeter Dunlap DDI_SUCCESS) {
147892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_conn_rele(ic);
147930e7468fSPeter Dunlap /* Disconnect if we couldn't dispatch the task */
148030e7468fSPeter Dunlap idm_ini_conn_disconnect(ic);
148130e7468fSPeter Dunlap }
1482fcf3ce44SJohn Forte break;
1483fcf3ce44SJohn Forte
1484fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION:
1485fcf3ce44SJohn Forte /*
1486fcf3ce44SJohn Forte * Target is going to drop our connection.
1487fcf3ce44SJohn Forte * param1 - CID which will be dropped.
1488fcf3ce44SJohn Forte * param2 - Min time to reconnect.
1489fcf3ce44SJohn Forte * param3 - Max time to reconnect.
1490fcf3ce44SJohn Forte *
1491fcf3ce44SJohn Forte * For now just let fail as another disconnect.
1492fcf3ce44SJohn Forte *
1493fcf3ce44SJohn Forte * MC/S Once we support > 1 connections then
1494fcf3ce44SJohn Forte * we need to check the CID and drop that
1495fcf3ce44SJohn Forte * specific connection.
1496fcf3ce44SJohn Forte */
149730e7468fSPeter Dunlap iscsi_conn_set_login_min_max(icp, iaehp->param2,
149830e7468fSPeter Dunlap iaehp->param3);
149930e7468fSPeter Dunlap idm_ini_conn_disconnect(ic);
1500fcf3ce44SJohn Forte break;
1501fcf3ce44SJohn Forte
1502fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS:
1503fcf3ce44SJohn Forte /*
1504fcf3ce44SJohn Forte * Target is going to drop ALL connections.
1505fcf3ce44SJohn Forte * param2 - Min time to reconnect.
1506fcf3ce44SJohn Forte * param3 - Max time to reconnect.
1507fcf3ce44SJohn Forte *
1508fcf3ce44SJohn Forte * For now just let fail as anyother disconnect.
1509fcf3ce44SJohn Forte *
1510fcf3ce44SJohn Forte * MC/S Once we support more than > 1 connections
1511fcf3ce44SJohn Forte * then we need to drop all connections on the
1512fcf3ce44SJohn Forte * session.
1513fcf3ce44SJohn Forte */
151430e7468fSPeter Dunlap iscsi_conn_set_login_min_max(icp, iaehp->param2,
151530e7468fSPeter Dunlap iaehp->param3);
151630e7468fSPeter Dunlap idm_ini_conn_disconnect(ic);
1517fcf3ce44SJohn Forte break;
1518fcf3ce44SJohn Forte
1519fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION:
1520fcf3ce44SJohn Forte /*
1521fcf3ce44SJohn Forte * Target requests parameter negotiation
1522fcf3ce44SJohn Forte * on this connection.
1523fcf3ce44SJohn Forte *
1524fcf3ce44SJohn Forte * The initiator must honor this request. For
1525fcf3ce44SJohn Forte * now we will request a logout. We can't
1526fcf3ce44SJohn Forte * just ignore this or it might force corruption?
1527fcf3ce44SJohn Forte */
152892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States
152992adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* Hold is released in iscsi_handle_logout */
153092adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_conn_hold(ic);
153130e7468fSPeter Dunlap itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
153230e7468fSPeter Dunlap itp->t_arg = icp;
153330e7468fSPeter Dunlap itp->t_blocking = B_FALSE;
1534904e51f6SJack Meng if (ddi_taskq_dispatch(isp->sess_login_taskq,
153530e7468fSPeter Dunlap (void(*)())iscsi_logout_start, itp, DDI_SLEEP) !=
153630e7468fSPeter Dunlap DDI_SUCCESS) {
153730e7468fSPeter Dunlap /* Disconnect if we couldn't dispatch the task */
153892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_conn_rele(ic);
153930e7468fSPeter Dunlap idm_ini_conn_disconnect(ic);
154030e7468fSPeter Dunlap }
1541fcf3ce44SJohn Forte break;
1542fcf3ce44SJohn Forte
1543fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_VENDOR_SPECIFIC:
1544fcf3ce44SJohn Forte /*
1545fcf3ce44SJohn Forte * We currently don't handle any vendor
1546fcf3ce44SJohn Forte * specific async events. So just ignore
1547fcf3ce44SJohn Forte * the request.
1548fcf3ce44SJohn Forte */
154930e7468fSPeter Dunlap idm_ini_conn_disconnect(ic);
1550fcf3ce44SJohn Forte break;
1551fcf3ce44SJohn Forte default:
155230e7468fSPeter Dunlap rval = IDM_STATUS_PROTOCOL_ERROR;
1553fcf3ce44SJohn Forte }
1554fcf3ce44SJohn Forte
1555fcf3ce44SJohn Forte return (rval);
1556fcf3ce44SJohn Forte }
1557fcf3ce44SJohn Forte
1558fcf3ce44SJohn Forte /*
1559fcf3ce44SJohn Forte * iscsi_rx_process_text_rsp - processes iSCSI text response. It sets
1560fcf3ce44SJohn Forte * the cmd_result field of the command data structure with the actual
1561fcf3ce44SJohn Forte * status value instead of returning the status value. The return value
1562fcf3ce44SJohn Forte * is SUCCESS in order to let iscsi_handle_text control the operation of
1563fcf3ce44SJohn Forte * a text request.
156430e7468fSPeter Dunlap * Text requests are a handled a little different than other types of
1565fcf3ce44SJohn Forte * iSCSI commands because the initiator sends additional empty text requests
1566fcf3ce44SJohn Forte * in order to obtain the remaining responses required to complete the
1567fcf3ce44SJohn Forte * request. iscsi_handle_text controls the operation of text request, while
1568fcf3ce44SJohn Forte * iscsi_rx_process_text_rsp just process the current response.
1569fcf3ce44SJohn Forte */
157030e7468fSPeter Dunlap static idm_status_t
iscsi_rx_process_text_rsp(idm_conn_t * ic,idm_pdu_t * pdu)157130e7468fSPeter Dunlap iscsi_rx_process_text_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
1572fcf3ce44SJohn Forte {
1573fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL;
157430e7468fSPeter Dunlap iscsi_text_rsp_hdr_t *ithp =
157530e7468fSPeter Dunlap (iscsi_text_rsp_hdr_t *)pdu->isp_hdr;
157630e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle;
1577fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL;
1578fcf3ce44SJohn Forte boolean_t final = B_FALSE;
1579fcf3ce44SJohn Forte uint32_t data_len;
158030e7468fSPeter Dunlap uint8_t *data = pdu->isp_data;
158130e7468fSPeter Dunlap idm_status_t rval;
1582fcf3ce44SJohn Forte
1583fcf3ce44SJohn Forte isp = icp->conn_sess;
1584fcf3ce44SJohn Forte
1585fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex);
158630e7468fSPeter Dunlap if ((rval = iscsi_rx_chk(icp, isp, (iscsi_scsi_rsp_hdr_t *)ithp,
158730e7468fSPeter Dunlap &icmdp)) != IDM_STATUS_SUCCESS) {
1588fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
158930e7468fSPeter Dunlap return (rval);
1590fcf3ce44SJohn Forte }
1591fcf3ce44SJohn Forte
1592fcf3ce44SJohn Forte /* update local final response flag */
1593fcf3ce44SJohn Forte if (ithp->flags & ISCSI_FLAG_FINAL) {
1594fcf3ce44SJohn Forte final = B_TRUE;
1595fcf3ce44SJohn Forte }
1596fcf3ce44SJohn Forte
1597fcf3ce44SJohn Forte /*
1598fcf3ce44SJohn Forte * validate received TTT value. RFC3720 specifies the following:
1599fcf3ce44SJohn Forte * - F bit set to 1 MUST have a reserved TTT value 0xffffffff
1600fcf3ce44SJohn Forte * - F bit set to 0 MUST have a non-reserved TTT value !0xffffffff
1601fcf3ce44SJohn Forte * In addition, the received TTT value must not change between
1602fcf3ce44SJohn Forte * responses of a long text response
1603fcf3ce44SJohn Forte */
1604fcf3ce44SJohn Forte if (((final == B_TRUE) && (ithp->ttt != ISCSI_RSVD_TASK_TAG)) ||
1605fcf3ce44SJohn Forte ((final == B_FALSE) && (ithp->ttt == ISCSI_RSVD_TASK_TAG))) {
1606fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_PROTOCOL_ERROR;
1607fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
1608fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
1609fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
1610fcf3ce44SJohn Forte "received text response with invalid flags:0x%x or "
1611fcf3ce44SJohn Forte "ttt:0x%x", icp->conn_oid, ithp->flags, ithp->itt);
161230e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR);
1613fcf3ce44SJohn Forte }
1614fcf3ce44SJohn Forte
1615fcf3ce44SJohn Forte if ((icmdp->cmd_un.text.stage == ISCSI_CMD_TEXT_INITIAL_REQ) &&
1616fcf3ce44SJohn Forte (ithp->ttt == ISCSI_RSVD_TASK_TAG) &&
1617fcf3ce44SJohn Forte (final == B_FALSE)) {
1618fcf3ce44SJohn Forte /* TTT should have matched reserved value */
1619fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_PROTOCOL_ERROR;
1620fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
1621fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
1622fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol "
1623fcf3ce44SJohn Forte "error - received text response with invalid "
1624fcf3ce44SJohn Forte "ttt:0x%x", icp->conn_oid, ithp->ttt);
162530e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR);
1626fcf3ce44SJohn Forte }
1627fcf3ce44SJohn Forte
1628fcf3ce44SJohn Forte /*
1629fcf3ce44SJohn Forte * If this is first response, save away TTT value for later use
1630fcf3ce44SJohn Forte * in a long text request/response sequence
1631fcf3ce44SJohn Forte */
1632fcf3ce44SJohn Forte if (icmdp->cmd_un.text.stage == ISCSI_CMD_TEXT_INITIAL_REQ) {
1633fcf3ce44SJohn Forte icmdp->cmd_un.text.ttt = ithp->ttt;
1634fcf3ce44SJohn Forte }
1635fcf3ce44SJohn Forte
1636fcf3ce44SJohn Forte data_len = ntoh24(ithp->dlength);
1637fcf3ce44SJohn Forte
1638fcf3ce44SJohn Forte /* check whether enough buffer available to copy data */
1639fcf3ce44SJohn Forte if ((icmdp->cmd_un.text.total_rx_len + data_len) >
1640fcf3ce44SJohn Forte icmdp->cmd_un.text.buf_len) {
1641fcf3ce44SJohn Forte icmdp->cmd_un.text.total_rx_len += data_len;
1642fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_DATA_OVERFLOW;
1643fcf3ce44SJohn Forte /*
1644fcf3ce44SJohn Forte * DATA_OVERFLOW will result in a SUCCESS return so that
1645fcf3ce44SJohn Forte * iscsi_handle_text can continue to obtain the remaining
1646fcf3ce44SJohn Forte * text response if needed.
1647fcf3ce44SJohn Forte */
1648fcf3ce44SJohn Forte } else {
1649fcf3ce44SJohn Forte char *buf_data = (icmdp->cmd_un.text.buf +
1650fcf3ce44SJohn Forte icmdp->cmd_un.text.offset);
1651fcf3ce44SJohn Forte
1652fcf3ce44SJohn Forte bcopy(data, buf_data, data_len);
1653fcf3ce44SJohn Forte icmdp->cmd_un.text.offset += data_len;
1654fcf3ce44SJohn Forte icmdp->cmd_un.text.total_rx_len += data_len;
1655fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS;
1656fcf3ce44SJohn Forte bcopy(ithp->rsvd4, icmdp->cmd_un.text.lun,
1657fcf3ce44SJohn Forte sizeof (icmdp->cmd_un.text.lun));
1658fcf3ce44SJohn Forte }
1659fcf3ce44SJohn Forte
1660fcf3ce44SJohn Forte /* update stage */
1661fcf3ce44SJohn Forte if (final == B_TRUE) {
1662fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
1663fcf3ce44SJohn Forte } else {
1664fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_CONTINUATION;
1665fcf3ce44SJohn Forte }
1666fcf3ce44SJohn Forte
1667fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
1668fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
166930e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS);
167030e7468fSPeter Dunlap }
167130e7468fSPeter Dunlap
167230e7468fSPeter Dunlap /*
167330e7468fSPeter Dunlap * iscsi_rx_process_scsi_itt_to_icmdp - Lookup itt using IDM to find matching
167430e7468fSPeter Dunlap * icmdp. Verify itt in hdr and icmdp are the same.
167530e7468fSPeter Dunlap */
167630e7468fSPeter Dunlap static iscsi_status_t
iscsi_rx_process_scsi_itt_to_icmdp(iscsi_sess_t * isp,idm_conn_t * ic,iscsi_scsi_rsp_hdr_t * ihp,iscsi_cmd_t ** icmdp)167730e7468fSPeter Dunlap iscsi_rx_process_scsi_itt_to_icmdp(iscsi_sess_t *isp, idm_conn_t *ic,
167830e7468fSPeter Dunlap iscsi_scsi_rsp_hdr_t *ihp, iscsi_cmd_t **icmdp)
167930e7468fSPeter Dunlap {
168030e7468fSPeter Dunlap idm_task_t *itp;
168130e7468fSPeter Dunlap
168230e7468fSPeter Dunlap ASSERT(isp != NULL);
168330e7468fSPeter Dunlap ASSERT(ihp != NULL);
168430e7468fSPeter Dunlap ASSERT(icmdp != NULL);
168530e7468fSPeter Dunlap ASSERT(mutex_owned(&isp->sess_cmdsn_mutex));
168630e7468fSPeter Dunlap itp = idm_task_find_and_complete(ic, ihp->itt, ISCSI_INI_TASK_TTT);
168730e7468fSPeter Dunlap if (itp == NULL) {
168830e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi session(%u) protocol error - "
168930e7468fSPeter Dunlap "received unknown itt:0x%x - protocol error",
169030e7468fSPeter Dunlap isp->sess_oid, ihp->itt);
169130e7468fSPeter Dunlap return (ISCSI_STATUS_INTERNAL_ERROR);
169230e7468fSPeter Dunlap }
169330e7468fSPeter Dunlap *icmdp = itp->idt_private;
169430e7468fSPeter Dunlap
169530e7468fSPeter Dunlap idm_task_rele(itp);
169630e7468fSPeter Dunlap
1697fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS);
169830e7468fSPeter Dunlap
1699fcf3ce44SJohn Forte }
1700fcf3ce44SJohn Forte
1701fcf3ce44SJohn Forte /*
1702fcf3ce44SJohn Forte * iscsi_rx_process_itt_to_icmdp - Lookup itt in the session's
1703fcf3ce44SJohn Forte * cmd table to find matching icmdp. Verify itt in hdr and
1704fcf3ce44SJohn Forte * icmdp are the same.
1705fcf3ce44SJohn Forte */
1706fcf3ce44SJohn Forte static iscsi_status_t
iscsi_rx_process_itt_to_icmdp(iscsi_sess_t * isp,iscsi_hdr_t * ihp,iscsi_cmd_t ** icmdp)1707fcf3ce44SJohn Forte iscsi_rx_process_itt_to_icmdp(iscsi_sess_t *isp, iscsi_hdr_t *ihp,
1708fcf3ce44SJohn Forte iscsi_cmd_t **icmdp)
1709fcf3ce44SJohn Forte {
1710fcf3ce44SJohn Forte int cmd_table_idx = 0;
1711fcf3ce44SJohn Forte
1712fcf3ce44SJohn Forte ASSERT(isp != NULL);
1713fcf3ce44SJohn Forte ASSERT(ihp != NULL);
1714fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
1715fcf3ce44SJohn Forte ASSERT(mutex_owned(&isp->sess_cmdsn_mutex));
1716fcf3ce44SJohn Forte
1717fcf3ce44SJohn Forte /* try to find an associated iscsi_pkt */
171830e7468fSPeter Dunlap cmd_table_idx = (ihp->itt - IDM_TASKIDS_MAX) % ISCSI_CMD_TABLE_SIZE;
1719fcf3ce44SJohn Forte if (isp->sess_cmd_table[cmd_table_idx] == NULL) {
1720fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi session(%u) protocol error - "
1721fcf3ce44SJohn Forte "received unknown itt:0x%x - protocol error",
1722fcf3ce44SJohn Forte isp->sess_oid, ihp->itt);
1723fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
1724fcf3ce44SJohn Forte }
1725fcf3ce44SJohn Forte
1726fcf3ce44SJohn Forte /* verify itt */
1727fcf3ce44SJohn Forte if (isp->sess_cmd_table[cmd_table_idx]->cmd_itt != ihp->itt) {
1728fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi session(%u) received itt:0x%x "
1729fcf3ce44SJohn Forte " which is out of sync with itt:0x%x", isp->sess_oid,
1730fcf3ce44SJohn Forte ihp->itt, isp->sess_cmd_table[cmd_table_idx]->cmd_itt);
1731fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
1732fcf3ce44SJohn Forte }
1733fcf3ce44SJohn Forte
173429e23f3fSandrew.rutz@sun.com /* ensure that icmdp is still in Active state */
173529e23f3fSandrew.rutz@sun.com if (isp->sess_cmd_table[cmd_table_idx]->cmd_state !=
173629e23f3fSandrew.rutz@sun.com ISCSI_CMD_STATE_ACTIVE) {
173729e23f3fSandrew.rutz@sun.com cmn_err(CE_WARN, "iscsi session(%u) received itt:0x%x "
173829e23f3fSandrew.rutz@sun.com "but icmdp (%p) is not in active state",
173929e23f3fSandrew.rutz@sun.com isp->sess_oid, ihp->itt,
174029e23f3fSandrew.rutz@sun.com (void *)isp->sess_cmd_table[cmd_table_idx]);
174129e23f3fSandrew.rutz@sun.com return (ISCSI_STATUS_INTERNAL_ERROR);
174229e23f3fSandrew.rutz@sun.com }
174329e23f3fSandrew.rutz@sun.com
1744fcf3ce44SJohn Forte /* make sure this is a SCSI cmd */
1745fcf3ce44SJohn Forte *icmdp = isp->sess_cmd_table[cmd_table_idx];
1746fcf3ce44SJohn Forte
1747fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS);
1748fcf3ce44SJohn Forte }
1749fcf3ce44SJohn Forte
1750fcf3ce44SJohn Forte /*
1751fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
1752fcf3ce44SJohn Forte * | End of protocol receive routines |
1753fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
1754fcf3ce44SJohn Forte */
1755fcf3ce44SJohn Forte
1756fcf3ce44SJohn Forte /*
1757fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
1758fcf3ce44SJohn Forte * | Beginning of protocol send routines |
1759fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
1760fcf3ce44SJohn Forte */
1761fcf3ce44SJohn Forte
1762fcf3ce44SJohn Forte
1763fcf3ce44SJohn Forte /*
1764fcf3ce44SJohn Forte * iscsi_tx_thread - This thread is the driving point for all
176530e7468fSPeter Dunlap * iSCSI PDUs after login. No PDUs should call idm_pdu_tx()
1766fcf3ce44SJohn Forte * directly they should be funneled through iscsi_tx_thread.
1767fcf3ce44SJohn Forte */
1768fcf3ce44SJohn Forte void
iscsi_tx_thread(iscsi_thread_t * thread,void * arg)1769fcf3ce44SJohn Forte iscsi_tx_thread(iscsi_thread_t *thread, void *arg)
1770fcf3ce44SJohn Forte {
1771fcf3ce44SJohn Forte iscsi_conn_t *icp = (iscsi_conn_t *)arg;
1772fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL;
1773fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL;
1774fcf3ce44SJohn Forte clock_t tout;
1775fcf3ce44SJohn Forte int ret = 1;
1776fcf3ce44SJohn Forte
1777fcf3ce44SJohn Forte ASSERT(icp != NULL);
1778fcf3ce44SJohn Forte isp = icp->conn_sess;
1779fcf3ce44SJohn Forte ASSERT(isp != NULL);
1780fcf3ce44SJohn Forte ASSERT(thread != NULL);
1781fcf3ce44SJohn Forte ASSERT(thread->signature == SIG_ISCSI_THREAD);
1782fcf3ce44SJohn Forte
1783fcf3ce44SJohn Forte tout = SEC_TO_TICK(1);
1784fcf3ce44SJohn Forte /*
1785fcf3ce44SJohn Forte * Transfer icmdps until shutdown by owning session.
1786fcf3ce44SJohn Forte */
1787fcf3ce44SJohn Forte while (ret != 0) {
1788fcf3ce44SJohn Forte
1789fcf3ce44SJohn Forte isp->sess_window_open = B_TRUE;
1790fcf3ce44SJohn Forte /*
1791fcf3ce44SJohn Forte * While the window is open, there are commands available
1792fcf3ce44SJohn Forte * to send and the session state allows those commands to
1793fcf3ce44SJohn Forte * be sent try to transfer them.
1794fcf3ce44SJohn Forte */
1795fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex);
1796fcf3ce44SJohn Forte while ((isp->sess_window_open == B_TRUE) &&
1797904e51f6SJack Meng ((icmdp = isp->sess_queue_pending.head) != NULL)) {
1798904e51f6SJack Meng if (((icmdp->cmd_type != ISCSI_CMD_TYPE_SCSI) &&
1799904e51f6SJack Meng (ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state))) ||
1800904e51f6SJack Meng (icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN)) {
1801904e51f6SJack Meng
1802904e51f6SJack Meng /* update command with this connection info */
1803904e51f6SJack Meng icmdp->cmd_conn = icp;
1804904e51f6SJack Meng /* attempt to send this command */
1805904e51f6SJack Meng iscsi_cmd_state_machine(icmdp,
1806904e51f6SJack Meng ISCSI_CMD_EVENT_E2, isp);
1807fcf3ce44SJohn Forte
1808904e51f6SJack Meng ASSERT(!mutex_owned(
1809904e51f6SJack Meng &isp->sess_queue_pending.mutex));
1810904e51f6SJack Meng mutex_enter(&isp->sess_queue_pending.mutex);
1811904e51f6SJack Meng } else {
1812904e51f6SJack Meng while (icmdp != NULL) {
1813904e51f6SJack Meng if ((icmdp->cmd_type !=
1814904e51f6SJack Meng ISCSI_CMD_TYPE_SCSI) &&
1815904e51f6SJack Meng (ISCSI_CONN_STATE_FULL_FEATURE
1816904e51f6SJack Meng (icp->conn_state) != B_TRUE)) {
1817904e51f6SJack Meng icmdp->cmd_misc_flags |=
1818904e51f6SJack Meng ISCSI_CMD_MISCFLAG_STUCK;
1819904e51f6SJack Meng } else if (icp->conn_state !=
1820904e51f6SJack Meng ISCSI_CONN_STATE_LOGGED_IN) {
1821904e51f6SJack Meng icmdp->cmd_misc_flags |=
1822904e51f6SJack Meng ISCSI_CMD_MISCFLAG_STUCK;
1823904e51f6SJack Meng }
1824904e51f6SJack Meng icmdp = icmdp->cmd_next;
1825904e51f6SJack Meng }
1826904e51f6SJack Meng break;
1827904e51f6SJack Meng }
1828fcf3ce44SJohn Forte }
1829fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex);
1830fcf3ce44SJohn Forte
1831fcf3ce44SJohn Forte /*
1832fcf3ce44SJohn Forte * Go to sleep until there is something new
1833fcf3ce44SJohn Forte * to process (awoken via cv_boardcast).
1834fcf3ce44SJohn Forte * Or the timer goes off.
1835fcf3ce44SJohn Forte */
1836fcf3ce44SJohn Forte ret = iscsi_thread_wait(thread, tout);
1837fcf3ce44SJohn Forte }
1838fcf3ce44SJohn Forte
1839fcf3ce44SJohn Forte }
1840fcf3ce44SJohn Forte
1841fcf3ce44SJohn Forte
1842fcf3ce44SJohn Forte /*
1843fcf3ce44SJohn Forte * iscsi_tx_cmd - transfers icmdp across wire as iscsi pdu
1844fcf3ce44SJohn Forte *
1845fcf3ce44SJohn Forte * Just prior to sending the command to the networking layer the
1846fcf3ce44SJohn Forte * pending queue lock will be dropped. At this point only local
1847fcf3ce44SJohn Forte * resources will be used, not the icmdp. Holding the queue lock
1848fcf3ce44SJohn Forte * across the networking call can lead to a hang. (This is due
1849fcf3ce44SJohn Forte * to the the target driver and networking layers competing use
1850fcf3ce44SJohn Forte * of the timeout() resources and the queue lock being held for
1851fcf3ce44SJohn Forte * both sides.) Upon the completion of this command the lock
1852fcf3ce44SJohn Forte * will have been re-acquired.
1853fcf3ce44SJohn Forte */
1854fcf3ce44SJohn Forte iscsi_status_t
iscsi_tx_cmd(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)1855fcf3ce44SJohn Forte iscsi_tx_cmd(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
1856fcf3ce44SJohn Forte {
1857fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_INTERNAL_ERROR;
1858fcf3ce44SJohn Forte
1859fcf3ce44SJohn Forte ASSERT(isp != NULL);
1860fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
1861fcf3ce44SJohn Forte
1862fcf3ce44SJohn Forte /* transfer specific command type */
1863fcf3ce44SJohn Forte switch (icmdp->cmd_type) {
1864fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_SCSI:
1865fcf3ce44SJohn Forte rval = iscsi_tx_scsi(isp, icmdp);
1866fcf3ce44SJohn Forte break;
1867fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_NOP:
1868fcf3ce44SJohn Forte rval = iscsi_tx_nop(isp, icmdp);
1869fcf3ce44SJohn Forte break;
1870fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_ABORT:
1871fcf3ce44SJohn Forte rval = iscsi_tx_abort(isp, icmdp);
1872fcf3ce44SJohn Forte break;
1873fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_RESET:
1874fcf3ce44SJohn Forte rval = iscsi_tx_reset(isp, icmdp);
1875fcf3ce44SJohn Forte break;
1876fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_LOGOUT:
1877fcf3ce44SJohn Forte rval = iscsi_tx_logout(isp, icmdp);
1878fcf3ce44SJohn Forte break;
1879fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_TEXT:
1880fcf3ce44SJohn Forte rval = iscsi_tx_text(isp, icmdp);
1881fcf3ce44SJohn Forte break;
1882fcf3ce44SJohn Forte default:
188330e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi_tx_cmd: invalid cmdtype: %d",
188430e7468fSPeter Dunlap icmdp->cmd_type);
1885fcf3ce44SJohn Forte ASSERT(FALSE);
1886fcf3ce44SJohn Forte }
1887fcf3ce44SJohn Forte
1888fcf3ce44SJohn Forte ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex));
1889fcf3ce44SJohn Forte return (rval);
1890fcf3ce44SJohn Forte }
1891fcf3ce44SJohn Forte
1892fcf3ce44SJohn Forte /*
1893fcf3ce44SJohn Forte * a variable length cdb can be up to 16K, but we obviously don't want
1894fcf3ce44SJohn Forte * to put that on the stack; go with 200 bytes; if we get something
1895fcf3ce44SJohn Forte * bigger than that we will kmem_alloc a buffer
1896fcf3ce44SJohn Forte */
1897fcf3ce44SJohn Forte #define DEF_CDB_LEN 200
1898fcf3ce44SJohn Forte
1899fcf3ce44SJohn Forte /*
1900fcf3ce44SJohn Forte * given the size of the cdb, return how many bytes the header takes,
1901fcf3ce44SJohn Forte * which is the sizeof addl_hdr_t + the CDB size, minus the 16 bytes
1902fcf3ce44SJohn Forte * stored in the basic header, minus sizeof (ahs_extscb)
1903fcf3ce44SJohn Forte */
1904fcf3ce44SJohn Forte #define ADDLHDRSZ(x) (sizeof (iscsi_addl_hdr_t) + (x) - \
1905fcf3ce44SJohn Forte 16 - 4)
1906fcf3ce44SJohn Forte
190730e7468fSPeter Dunlap static void
iscsi_tx_init_hdr(iscsi_sess_t * isp,iscsi_conn_t * icp,iscsi_text_hdr_t * ihp,int opcode,iscsi_cmd_t * icmdp)190830e7468fSPeter Dunlap iscsi_tx_init_hdr(iscsi_sess_t *isp, iscsi_conn_t *icp,
19092b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_text_hdr_t *ihp, int opcode, iscsi_cmd_t *icmdp)
1910fcf3ce44SJohn Forte {
191130e7468fSPeter Dunlap ihp->opcode = opcode;
19122b79d384Sbing zhao - Sun Microsystems - Beijing China ihp->itt = icmdp->cmd_itt;
1913fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex);
19142b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_sn = isp->sess_cmdsn;
1915fcf3ce44SJohn Forte ihp->cmdsn = htonl(isp->sess_cmdsn);
1916fcf3ce44SJohn Forte isp->sess_cmdsn++;
1917fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex);
1918fcf3ce44SJohn Forte ihp->expstatsn = htonl(icp->conn_expstatsn);
1919fcf3ce44SJohn Forte icp->conn_laststatsn = icp->conn_expstatsn;
192030e7468fSPeter Dunlap }
1921fcf3ce44SJohn Forte
1922fcf3ce44SJohn Forte
192330e7468fSPeter Dunlap static void
iscsi_tx_scsi_data(iscsi_cmd_t * icmdp,iscsi_scsi_cmd_hdr_t * ihp,iscsi_conn_t * icp,idm_pdu_t * pdu)192430e7468fSPeter Dunlap iscsi_tx_scsi_data(iscsi_cmd_t *icmdp, iscsi_scsi_cmd_hdr_t *ihp,
192530e7468fSPeter Dunlap iscsi_conn_t *icp, idm_pdu_t *pdu)
192630e7468fSPeter Dunlap {
192730e7468fSPeter Dunlap struct buf *bp = NULL;
192830e7468fSPeter Dunlap size_t buflen = 0;
192930e7468fSPeter Dunlap uint32_t first_burst_length = 0;
193030e7468fSPeter Dunlap struct scsi_pkt *pkt;
193130e7468fSPeter Dunlap
193230e7468fSPeter Dunlap pkt = icmdp->cmd_un.scsi.pkt;
1933fcf3ce44SJohn Forte bp = icmdp->cmd_un.scsi.bp;
1934fcf3ce44SJohn Forte if ((bp != NULL) && bp->b_bcount) {
1935fcf3ce44SJohn Forte buflen = bp->b_bcount;
193630e7468fSPeter Dunlap first_burst_length =
193730e7468fSPeter Dunlap icp->conn_params.first_burst_length;
1938fcf3ce44SJohn Forte
1939fcf3ce44SJohn Forte if (bp->b_flags & B_READ) {
1940fcf3ce44SJohn Forte ihp->flags = ISCSI_FLAG_FINAL;
1941fcf3ce44SJohn Forte /*
1942fcf3ce44SJohn Forte * fix problem where OS sends bp (B_READ &
1943fcf3ce44SJohn Forte * b_bcount!=0) for a TUR or START_STOP.
1944fcf3ce44SJohn Forte * (comment came from cisco code.)
1945fcf3ce44SJohn Forte */
1946fcf3ce44SJohn Forte if ((pkt->pkt_cdbp[0] != SCMD_TEST_UNIT_READY) &&
1947fcf3ce44SJohn Forte (pkt->pkt_cdbp[0] != SCMD_START_STOP)) {
1948fcf3ce44SJohn Forte ihp->flags |= ISCSI_FLAG_CMD_READ;
1949fcf3ce44SJohn Forte ihp->data_length = htonl(buflen);
1950fcf3ce44SJohn Forte }
1951fcf3ce44SJohn Forte } else {
1952fcf3ce44SJohn Forte ihp->flags = ISCSI_FLAG_CMD_WRITE;
1953fcf3ce44SJohn Forte /*
1954fcf3ce44SJohn Forte * FinalBit on the the iSCSI PDU denotes this
1955fcf3ce44SJohn Forte * is the last PDU in the sequence.
1956fcf3ce44SJohn Forte *
1957fcf3ce44SJohn Forte * initial_r2t = true means R2T is required
1958fcf3ce44SJohn Forte * for additional PDU, so there will be no more
1959fcf3ce44SJohn Forte * unsolicited PDUs following
1960fcf3ce44SJohn Forte */
1961fcf3ce44SJohn Forte if (icp->conn_params.initial_r2t) {
1962fcf3ce44SJohn Forte ihp->flags |= ISCSI_FLAG_FINAL;
1963fcf3ce44SJohn Forte }
1964fcf3ce44SJohn Forte
1965fcf3ce44SJohn Forte /* Check if we should send ImmediateData */
1966fcf3ce44SJohn Forte if (icp->conn_params.immediate_data) {
196730e7468fSPeter Dunlap pdu->isp_data =
196830e7468fSPeter Dunlap (uint8_t *)icmdp->
196930e7468fSPeter Dunlap cmd_un.scsi.bp->b_un.b_addr;
197030e7468fSPeter Dunlap
197130e7468fSPeter Dunlap pdu->isp_datalen = MIN(MIN(buflen,
1972fcf3ce44SJohn Forte first_burst_length),
1973fcf3ce44SJohn Forte icmdp->cmd_conn->conn_params.
1974fcf3ce44SJohn Forte max_xmit_data_seg_len);
1975fcf3ce44SJohn Forte
1976fcf3ce44SJohn Forte /*
1977fcf3ce44SJohn Forte * if everything fits immediate, or
1978fcf3ce44SJohn Forte * we can send all burst data immediate
1979fcf3ce44SJohn Forte * (not unsol), set F
1980fcf3ce44SJohn Forte */
198130e7468fSPeter Dunlap /*
198230e7468fSPeter Dunlap * XXX This doesn't look right -- it's not
198330e7468fSPeter Dunlap * clear how we can handle transmitting
198430e7468fSPeter Dunlap * any unsolicited data. It looks like
198530e7468fSPeter Dunlap * we only support immediate data. So what
198630e7468fSPeter Dunlap * happens if we don't set ISCSI_FLAG_FINAL?
198730e7468fSPeter Dunlap *
198830e7468fSPeter Dunlap * Unless there's magic code somewhere that
198930e7468fSPeter Dunlap * is sending the remaining PDU's we should
199030e7468fSPeter Dunlap * simply set ISCSI_FLAG_FINAL and forget
199130e7468fSPeter Dunlap * about sending unsolicited data. The big
199230e7468fSPeter Dunlap * win is the immediate data anyway for small
199330e7468fSPeter Dunlap * PDU's.
199430e7468fSPeter Dunlap */
199530e7468fSPeter Dunlap if ((pdu->isp_datalen == buflen) ||
199630e7468fSPeter Dunlap (pdu->isp_datalen == first_burst_length)) {
1997fcf3ce44SJohn Forte ihp->flags |= ISCSI_FLAG_FINAL;
1998fcf3ce44SJohn Forte }
1999fcf3ce44SJohn Forte
200030e7468fSPeter Dunlap hton24(ihp->dlength, pdu->isp_datalen);
2001fcf3ce44SJohn Forte }
2002fcf3ce44SJohn Forte /* total data transfer length */
2003fcf3ce44SJohn Forte ihp->data_length = htonl(buflen);
2004fcf3ce44SJohn Forte }
2005fcf3ce44SJohn Forte } else {
2006fcf3ce44SJohn Forte ihp->flags = ISCSI_FLAG_FINAL;
2007fcf3ce44SJohn Forte }
200830e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred += pdu->isp_datalen;
200930e7468fSPeter Dunlap /* XXX How is this different from the code above? */
201030e7468fSPeter Dunlap /* will idm send the next data command up to burst length? */
201130e7468fSPeter Dunlap /* send the burstlen if we haven't sent immediate data */
201230e7468fSPeter Dunlap /* CRM: should idm send difference min(buflen, first_burst) and imm? */
201330e7468fSPeter Dunlap /* (MIN(first_burst_length, buflen) - imdata > 0) */
201430e7468fSPeter Dunlap /* CRM_LATER: change this to generate unsolicited pdu */
201530e7468fSPeter Dunlap if ((buflen > 0) &&
201630e7468fSPeter Dunlap ((bp->b_flags & B_READ) == 0) &&
201730e7468fSPeter Dunlap (icp->conn_params.initial_r2t == 0) &&
201830e7468fSPeter Dunlap pdu->isp_datalen == 0) {
201930e7468fSPeter Dunlap
202030e7468fSPeter Dunlap pdu->isp_datalen = MIN(first_burst_length, buflen);
202130e7468fSPeter Dunlap if ((pdu->isp_datalen == buflen) ||
202230e7468fSPeter Dunlap (pdu->isp_datalen == first_burst_length)) {
202330e7468fSPeter Dunlap ihp->flags |= ISCSI_FLAG_FINAL;
202430e7468fSPeter Dunlap }
202530e7468fSPeter Dunlap pdu->isp_data = (uint8_t *)icmdp->cmd_un.scsi.bp->b_un.b_addr;
202630e7468fSPeter Dunlap hton24(ihp->dlength, pdu->isp_datalen);
202730e7468fSPeter Dunlap }
202830e7468fSPeter Dunlap }
202930e7468fSPeter Dunlap
203030e7468fSPeter Dunlap static void
iscsi_tx_scsi_init_pkt(iscsi_cmd_t * icmdp,iscsi_scsi_cmd_hdr_t * ihp)203130e7468fSPeter Dunlap iscsi_tx_scsi_init_pkt(iscsi_cmd_t *icmdp, iscsi_scsi_cmd_hdr_t *ihp)
203230e7468fSPeter Dunlap {
203330e7468fSPeter Dunlap struct scsi_pkt *pkt;
203430e7468fSPeter Dunlap
203530e7468fSPeter Dunlap pkt = icmdp->cmd_un.scsi.pkt;
203630e7468fSPeter Dunlap pkt->pkt_state = (STATE_GOT_BUS | STATE_GOT_TARGET);
203730e7468fSPeter Dunlap pkt->pkt_reason = CMD_INCOMPLETE;
2038fcf3ce44SJohn Forte
2039fcf3ce44SJohn Forte /* tagged queuing */
2040fcf3ce44SJohn Forte if (pkt->pkt_flags & FLAG_HTAG) {
2041fcf3ce44SJohn Forte ihp->flags |= ISCSI_ATTR_HEAD_OF_QUEUE;
2042fcf3ce44SJohn Forte } else if (pkt->pkt_flags & FLAG_OTAG) {
2043fcf3ce44SJohn Forte ihp->flags |= ISCSI_ATTR_ORDERED;
2044fcf3ce44SJohn Forte } else if (pkt->pkt_flags & FLAG_STAG) {
2045fcf3ce44SJohn Forte ihp->flags |= ISCSI_ATTR_SIMPLE;
2046fcf3ce44SJohn Forte } else {
2047fcf3ce44SJohn Forte /* ihp->flags |= ISCSI_ATTR_UNTAGGED; */
2048fcf3ce44SJohn Forte /* EMPTY */
2049fcf3ce44SJohn Forte }
2050fcf3ce44SJohn Forte
2051fcf3ce44SJohn Forte /* iscsi states lun is based on spc.2 */
2052fcf3ce44SJohn Forte ISCSI_LUN_BYTE_COPY(ihp->lun, icmdp->cmd_un.scsi.lun);
2053fcf3ce44SJohn Forte
2054fcf3ce44SJohn Forte if (icmdp->cmd_un.scsi.cmdlen <= 16) {
2055fcf3ce44SJohn Forte /* copy the SCSI Command Block into the PDU */
2056fcf3ce44SJohn Forte bcopy(pkt->pkt_cdbp, ihp->scb,
2057fcf3ce44SJohn Forte icmdp->cmd_un.scsi.cmdlen);
2058fcf3ce44SJohn Forte } else {
2059fcf3ce44SJohn Forte iscsi_addl_hdr_t *iahp;
2060fcf3ce44SJohn Forte
2061fcf3ce44SJohn Forte iahp = (iscsi_addl_hdr_t *)ihp;
2062fcf3ce44SJohn Forte
2063fcf3ce44SJohn Forte ihp->hlength = (ADDLHDRSZ(icmdp->cmd_un.scsi.cmdlen) -
2064fcf3ce44SJohn Forte sizeof (iscsi_scsi_cmd_hdr_t) + 3) / 4;
2065fcf3ce44SJohn Forte iahp->ahs_hlen_hi = 0;
2066fcf3ce44SJohn Forte iahp->ahs_hlen_lo = (icmdp->cmd_un.scsi.cmdlen - 15);
2067fcf3ce44SJohn Forte iahp->ahs_key = 0x01;
2068fcf3ce44SJohn Forte iahp->ahs_resv = 0;
2069fcf3ce44SJohn Forte bcopy(pkt->pkt_cdbp, ihp->scb, 16);
207030e7468fSPeter Dunlap bcopy(((char *)pkt->pkt_cdbp) + 16, &iahp->ahs_extscb[0],
207130e7468fSPeter Dunlap icmdp->cmd_un.scsi.cmdlen);
2072fcf3ce44SJohn Forte }
2073fcf3ce44SJohn Forte
207430e7468fSPeter Dunlap /*
207530e7468fSPeter Dunlap * Update all values before transfering.
207630e7468fSPeter Dunlap * We should never touch the icmdp after
207730e7468fSPeter Dunlap * transfering if there is no more data
207830e7468fSPeter Dunlap * to send. The only case the idm_pdu_tx()
207930e7468fSPeter Dunlap * will fail is a on a connection disconnect
208030e7468fSPeter Dunlap * in that case the command will be flushed.
208130e7468fSPeter Dunlap */
208230e7468fSPeter Dunlap pkt->pkt_state |= STATE_SENT_CMD;
2083fcf3ce44SJohn Forte }
2084fcf3ce44SJohn Forte
208530e7468fSPeter Dunlap static void
iscsi_tx_scsi_init_task(iscsi_cmd_t * icmdp,iscsi_conn_t * icp,iscsi_scsi_cmd_hdr_t * ihp)208630e7468fSPeter Dunlap iscsi_tx_scsi_init_task(iscsi_cmd_t *icmdp, iscsi_conn_t *icp,
208730e7468fSPeter Dunlap iscsi_scsi_cmd_hdr_t *ihp)
2088fcf3ce44SJohn Forte {
208930e7468fSPeter Dunlap idm_task_t *itp;
209030e7468fSPeter Dunlap struct buf *bp = NULL;
209130e7468fSPeter Dunlap uint32_t data_length;
2092fcf3ce44SJohn Forte
209330e7468fSPeter Dunlap bp = icmdp->cmd_un.scsi.bp;
2094fcf3ce44SJohn Forte
209530e7468fSPeter Dunlap itp = icmdp->cmd_itp;
209630e7468fSPeter Dunlap ASSERT(itp != NULL);
209730e7468fSPeter Dunlap data_length = ntohl(ihp->data_length);
209830e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE,
209930e7468fSPeter Dunlap "DEBUG: iscsi_tx_init_task: task_start: %p idt_tt: %x cmdsn: %x "
210030e7468fSPeter Dunlap "sess_cmdsn: %x cmd: %p "
210130e7468fSPeter Dunlap "cmdtype: %d datalen: %u",
210230e7468fSPeter Dunlap (void *)itp, itp->idt_tt, ihp->cmdsn, icp->conn_sess->sess_cmdsn,
210330e7468fSPeter Dunlap (void *)icmdp, icmdp->cmd_type, data_length);
210430e7468fSPeter Dunlap if (data_length > 0) {
210530e7468fSPeter Dunlap if (bp->b_flags & B_READ) {
210630e7468fSPeter Dunlap icmdp->cmd_un.scsi.ibp_ibuf =
210730e7468fSPeter Dunlap idm_buf_alloc(icp->conn_ic,
210830e7468fSPeter Dunlap bp->b_un.b_addr, bp->b_bcount);
210930e7468fSPeter Dunlap if (icmdp->cmd_un.scsi.ibp_ibuf)
211030e7468fSPeter Dunlap idm_buf_bind_in(itp,
211130e7468fSPeter Dunlap icmdp->cmd_un.scsi.ibp_ibuf);
211230e7468fSPeter Dunlap } else {
211330e7468fSPeter Dunlap icmdp->cmd_un.scsi.ibp_obuf =
211430e7468fSPeter Dunlap idm_buf_alloc(icp->conn_ic,
211530e7468fSPeter Dunlap bp->b_un.b_addr, bp->b_bcount);
211630e7468fSPeter Dunlap if (icmdp->cmd_un.scsi.ibp_obuf)
211730e7468fSPeter Dunlap idm_buf_bind_out(itp,
211830e7468fSPeter Dunlap icmdp->cmd_un.scsi.ibp_obuf);
211930e7468fSPeter Dunlap }
212030e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE,
212130e7468fSPeter Dunlap "DEBUG: pdu_tx: task_start(%s): %p ic: %p idt_tt: %x "
212230e7468fSPeter Dunlap "cmdsn: %x sess_cmdsn: %x sess_expcmdsn: %x obuf: %p "
212330e7468fSPeter Dunlap "cmdp: %p cmdtype: %d "
212430e7468fSPeter Dunlap "buflen: %lu " "bpaddr: %p datalen: %u ",
212530e7468fSPeter Dunlap bp->b_flags & B_READ ? "B_READ" : "B_WRITE",
212630e7468fSPeter Dunlap (void *)itp, (void *)icp->conn_ic,
212730e7468fSPeter Dunlap itp->idt_tt, ihp->cmdsn,
212830e7468fSPeter Dunlap icp->conn_sess->sess_cmdsn,
212930e7468fSPeter Dunlap icp->conn_sess->sess_expcmdsn,
213030e7468fSPeter Dunlap (void *)icmdp->cmd_un.scsi.ibp_ibuf,
213130e7468fSPeter Dunlap (void *)icmdp, icmdp->cmd_type, bp->b_bcount,
213230e7468fSPeter Dunlap (void *)bp->b_un.b_addr,
213330e7468fSPeter Dunlap data_length);
213430e7468fSPeter Dunlap }
2135fcf3ce44SJohn Forte
2136fcf3ce44SJohn Forte /*
213730e7468fSPeter Dunlap * Task is now active
2138fcf3ce44SJohn Forte */
213930e7468fSPeter Dunlap idm_task_start(itp, ISCSI_INI_TASK_TTT);
2140fcf3ce44SJohn Forte }
2141fcf3ce44SJohn Forte
2142fcf3ce44SJohn Forte /*
214330e7468fSPeter Dunlap * iscsi_tx_scsi -
214430e7468fSPeter Dunlap *
2145fcf3ce44SJohn Forte */
2146fcf3ce44SJohn Forte static iscsi_status_t
iscsi_tx_scsi(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)214730e7468fSPeter Dunlap iscsi_tx_scsi(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2148fcf3ce44SJohn Forte {
2149fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
215030e7468fSPeter Dunlap iscsi_conn_t *icp = NULL;
215130e7468fSPeter Dunlap struct scsi_pkt *pkt = NULL;
215230e7468fSPeter Dunlap iscsi_scsi_cmd_hdr_t *ihp = NULL;
215330e7468fSPeter Dunlap int cdblen = 0;
215430e7468fSPeter Dunlap idm_pdu_t *pdu;
215530e7468fSPeter Dunlap int len;
2156fcf3ce44SJohn Forte
2157fcf3ce44SJohn Forte ASSERT(isp != NULL);
2158fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
2159fcf3ce44SJohn Forte
216030e7468fSPeter Dunlap pdu = kmem_zalloc(sizeof (idm_pdu_t), KM_SLEEP);
216130e7468fSPeter Dunlap
216230e7468fSPeter Dunlap pkt = icmdp->cmd_un.scsi.pkt;
216330e7468fSPeter Dunlap ASSERT(pkt != NULL);
216430e7468fSPeter Dunlap icp = icmdp->cmd_conn;
216530e7468fSPeter Dunlap ASSERT(icp != NULL);
216630e7468fSPeter Dunlap
216730e7468fSPeter Dunlap /* Reset counts in case we are on a retry */
216830e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred = 0;
216930e7468fSPeter Dunlap
217030e7468fSPeter Dunlap if (icmdp->cmd_un.scsi.cmdlen > DEF_CDB_LEN) {
217130e7468fSPeter Dunlap cdblen = icmdp->cmd_un.scsi.cmdlen;
217230e7468fSPeter Dunlap ihp = kmem_zalloc(ADDLHDRSZ(cdblen), KM_SLEEP);
217330e7468fSPeter Dunlap len = ADDLHDRSZ(cdblen);
217430e7468fSPeter Dunlap } else {
217530e7468fSPeter Dunlap /*
217630e7468fSPeter Dunlap * only bzero the basic header; the additional header
217730e7468fSPeter Dunlap * will be set up correctly later, if needed
217830e7468fSPeter Dunlap */
217930e7468fSPeter Dunlap ihp = kmem_zalloc(sizeof (iscsi_scsi_cmd_hdr_t), KM_SLEEP);
218030e7468fSPeter Dunlap len = sizeof (iscsi_scsi_cmd_hdr_t);
2181fcf3ce44SJohn Forte }
2182fcf3ce44SJohn Forte
218330e7468fSPeter Dunlap iscsi_tx_init_hdr(isp, icp, (iscsi_text_hdr_t *)ihp,
21842b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_OP_SCSI_CMD, icmdp);
218530e7468fSPeter Dunlap
218630e7468fSPeter Dunlap idm_pdu_init(pdu, icp->conn_ic, (void *)icmdp, &iscsi_tx_done);
218730e7468fSPeter Dunlap idm_pdu_init_hdr(pdu, (uint8_t *)ihp, len);
218830e7468fSPeter Dunlap pdu->isp_data = NULL;
218930e7468fSPeter Dunlap pdu->isp_datalen = 0;
2190fcf3ce44SJohn Forte
2191fcf3ce44SJohn Forte /*
219230e7468fSPeter Dunlap * Sestion 12.11 of the iSCSI specification has a good table
219330e7468fSPeter Dunlap * describing when uncolicited data and/or immediate data
219430e7468fSPeter Dunlap * should be sent.
2195fcf3ce44SJohn Forte */
2196fcf3ce44SJohn Forte
219730e7468fSPeter Dunlap iscsi_tx_scsi_data(icmdp, ihp, icp, pdu);
219830e7468fSPeter Dunlap
219930e7468fSPeter Dunlap iscsi_tx_scsi_init_pkt(icmdp, ihp);
220030e7468fSPeter Dunlap
220130e7468fSPeter Dunlap /* Calls idm_task_start */
220230e7468fSPeter Dunlap iscsi_tx_scsi_init_task(icmdp, icp, ihp);
220330e7468fSPeter Dunlap
2204fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex);
2205fcf3ce44SJohn Forte
220630e7468fSPeter Dunlap idm_pdu_tx(pdu);
2207fcf3ce44SJohn Forte
22082b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_SENT;
22092b79d384Sbing zhao - Sun Microsystems - Beijing China
221030e7468fSPeter Dunlap return (rval);
221130e7468fSPeter Dunlap }
2212fcf3ce44SJohn Forte
2213fcf3ce44SJohn Forte
221430e7468fSPeter Dunlap /* ARGSUSED */
221530e7468fSPeter Dunlap static void
iscsi_tx_done(idm_pdu_t * pdu,idm_status_t status)221630e7468fSPeter Dunlap iscsi_tx_done(idm_pdu_t *pdu, idm_status_t status)
221730e7468fSPeter Dunlap {
221830e7468fSPeter Dunlap kmem_free((iscsi_hdr_t *)pdu->isp_hdr, pdu->isp_hdrlen);
221930e7468fSPeter Dunlap kmem_free(pdu, sizeof (idm_pdu_t));
222030e7468fSPeter Dunlap }
2221fcf3ce44SJohn Forte
2222fcf3ce44SJohn Forte
222330e7468fSPeter Dunlap static void
iscsi_tx_pdu(iscsi_conn_t * icp,int opcode,void * hdr,int hdrlen,iscsi_cmd_t * icmdp)222430e7468fSPeter Dunlap iscsi_tx_pdu(iscsi_conn_t *icp, int opcode, void *hdr, int hdrlen,
222530e7468fSPeter Dunlap iscsi_cmd_t *icmdp)
222630e7468fSPeter Dunlap {
222730e7468fSPeter Dunlap idm_pdu_t *tx_pdu;
222830e7468fSPeter Dunlap iscsi_hdr_t *ihp = (iscsi_hdr_t *)hdr;
2229fcf3ce44SJohn Forte
223030e7468fSPeter Dunlap tx_pdu = kmem_zalloc(sizeof (idm_pdu_t), KM_SLEEP);
223130e7468fSPeter Dunlap ASSERT(tx_pdu != NULL);
2232fcf3ce44SJohn Forte
223330e7468fSPeter Dunlap idm_pdu_init(tx_pdu, icp->conn_ic, icmdp, &iscsi_tx_done);
223430e7468fSPeter Dunlap idm_pdu_init_hdr(tx_pdu, hdr, hdrlen);
223530e7468fSPeter Dunlap if (opcode == ISCSI_OP_TEXT_CMD) {
223630e7468fSPeter Dunlap idm_pdu_init_data(tx_pdu,
223730e7468fSPeter Dunlap (uint8_t *)icmdp->cmd_un.text.buf,
223830e7468fSPeter Dunlap ntoh24(ihp->dlength));
2239fcf3ce44SJohn Forte }
2240fcf3ce44SJohn Forte
224130e7468fSPeter Dunlap mutex_exit(&icp->conn_sess->sess_queue_pending.mutex);
224230e7468fSPeter Dunlap idm_pdu_tx(tx_pdu);
22432b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_SENT;
2244fcf3ce44SJohn Forte }
2245fcf3ce44SJohn Forte
2246fcf3ce44SJohn Forte
2247fcf3ce44SJohn Forte /*
2248fcf3ce44SJohn Forte * iscsi_tx_nop -
2249fcf3ce44SJohn Forte *
2250fcf3ce44SJohn Forte */
2251fcf3ce44SJohn Forte static iscsi_status_t
iscsi_tx_nop(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)2252fcf3ce44SJohn Forte iscsi_tx_nop(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2253fcf3ce44SJohn Forte {
2254fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
2255fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL;
225630e7468fSPeter Dunlap iscsi_nop_out_hdr_t *inohp;
2257fcf3ce44SJohn Forte
2258fcf3ce44SJohn Forte ASSERT(isp != NULL);
2259fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
2260fcf3ce44SJohn Forte icp = icmdp->cmd_conn;
2261fcf3ce44SJohn Forte ASSERT(icp != NULL);
2262fcf3ce44SJohn Forte
226330e7468fSPeter Dunlap inohp = kmem_zalloc(sizeof (iscsi_nop_out_hdr_t), KM_SLEEP);
226430e7468fSPeter Dunlap ASSERT(inohp != NULL);
226530e7468fSPeter Dunlap
226630e7468fSPeter Dunlap inohp->opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
226730e7468fSPeter Dunlap inohp->flags = ISCSI_FLAG_FINAL;
226830e7468fSPeter Dunlap inohp->itt = icmdp->cmd_itt;
226930e7468fSPeter Dunlap inohp->ttt = icmdp->cmd_ttt;
2270fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex);
22712b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_sn = isp->sess_cmdsn;
227230e7468fSPeter Dunlap inohp->cmdsn = htonl(isp->sess_cmdsn);
2273fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex);
227430e7468fSPeter Dunlap inohp->expstatsn = htonl(icp->conn_expstatsn);
2275fcf3ce44SJohn Forte icp->conn_laststatsn = icp->conn_expstatsn;
227630e7468fSPeter Dunlap iscsi_tx_pdu(icp, ISCSI_OP_NOOP_OUT, inohp,
227730e7468fSPeter Dunlap sizeof (iscsi_nop_out_hdr_t), icmdp);
2278fcf3ce44SJohn Forte return (rval);
2279fcf3ce44SJohn Forte }
2280fcf3ce44SJohn Forte
2281fcf3ce44SJohn Forte
2282fcf3ce44SJohn Forte /*
2283fcf3ce44SJohn Forte * iscsi_tx_abort -
2284fcf3ce44SJohn Forte *
2285fcf3ce44SJohn Forte */
2286fcf3ce44SJohn Forte static iscsi_status_t
iscsi_tx_abort(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)2287fcf3ce44SJohn Forte iscsi_tx_abort(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2288fcf3ce44SJohn Forte {
2289fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
2290fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL;
229130e7468fSPeter Dunlap iscsi_scsi_task_mgt_hdr_t *istmh;
2292fcf3ce44SJohn Forte
2293fcf3ce44SJohn Forte ASSERT(isp != NULL);
2294fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
2295fcf3ce44SJohn Forte icp = icmdp->cmd_conn;
2296fcf3ce44SJohn Forte ASSERT(icp != NULL);
2297fcf3ce44SJohn Forte
229830e7468fSPeter Dunlap istmh = kmem_zalloc(sizeof (iscsi_scsi_task_mgt_hdr_t), KM_SLEEP);
229930e7468fSPeter Dunlap ASSERT(istmh != NULL);
2300fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex);
23012b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_sn = isp->sess_cmdsn;
230230e7468fSPeter Dunlap istmh->cmdsn = htonl(isp->sess_cmdsn);
2303fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex);
230430e7468fSPeter Dunlap istmh->expstatsn = htonl(icp->conn_expstatsn);
2305fcf3ce44SJohn Forte icp->conn_laststatsn = icp->conn_expstatsn;
230630e7468fSPeter Dunlap istmh->itt = icmdp->cmd_itt;
230730e7468fSPeter Dunlap istmh->opcode = ISCSI_OP_SCSI_TASK_MGT_MSG | ISCSI_OP_IMMEDIATE;
230830e7468fSPeter Dunlap istmh->function = ISCSI_FLAG_FINAL | ISCSI_TM_FUNC_ABORT_TASK;
230930e7468fSPeter Dunlap ISCSI_LUN_BYTE_COPY(istmh->lun,
2310fcf3ce44SJohn Forte icmdp->cmd_un.abort.icmdp->cmd_un.scsi.lun);
231130e7468fSPeter Dunlap istmh->rtt = icmdp->cmd_un.abort.icmdp->cmd_itt;
231230e7468fSPeter Dunlap iscsi_tx_pdu(icp, ISCSI_OP_SCSI_TASK_MGT_MSG, istmh,
231330e7468fSPeter Dunlap sizeof (iscsi_scsi_task_mgt_hdr_t), icmdp);
2314fcf3ce44SJohn Forte
2315fcf3ce44SJohn Forte return (rval);
2316fcf3ce44SJohn Forte }
2317fcf3ce44SJohn Forte
2318fcf3ce44SJohn Forte
2319fcf3ce44SJohn Forte /*
2320fcf3ce44SJohn Forte * iscsi_tx_reset -
2321fcf3ce44SJohn Forte *
2322fcf3ce44SJohn Forte */
2323fcf3ce44SJohn Forte static iscsi_status_t
iscsi_tx_reset(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)2324fcf3ce44SJohn Forte iscsi_tx_reset(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2325fcf3ce44SJohn Forte {
2326fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
2327fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL;
232830e7468fSPeter Dunlap iscsi_scsi_task_mgt_hdr_t *istmh;
2329fcf3ce44SJohn Forte
2330fcf3ce44SJohn Forte ASSERT(isp != NULL);
2331fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
2332fcf3ce44SJohn Forte icp = icmdp->cmd_conn;
2333fcf3ce44SJohn Forte ASSERT(icp != NULL);
2334fcf3ce44SJohn Forte
233530e7468fSPeter Dunlap istmh = kmem_zalloc(sizeof (iscsi_scsi_task_mgt_hdr_t), KM_SLEEP);
233630e7468fSPeter Dunlap ASSERT(istmh != NULL);
233730e7468fSPeter Dunlap istmh->opcode = ISCSI_OP_SCSI_TASK_MGT_MSG | ISCSI_OP_IMMEDIATE;
2338fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex);
23392b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_sn = isp->sess_cmdsn;
234030e7468fSPeter Dunlap istmh->cmdsn = htonl(isp->sess_cmdsn);
2341fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex);
234230e7468fSPeter Dunlap istmh->expstatsn = htonl(icp->conn_expstatsn);
234330e7468fSPeter Dunlap istmh->itt = icmdp->cmd_itt;
2344fcf3ce44SJohn Forte
2345fcf3ce44SJohn Forte switch (icmdp->cmd_un.reset.level) {
2346fcf3ce44SJohn Forte case RESET_LUN:
234730e7468fSPeter Dunlap istmh->function = ISCSI_FLAG_FINAL |
2348fcf3ce44SJohn Forte ISCSI_TM_FUNC_LOGICAL_UNIT_RESET;
234930e7468fSPeter Dunlap ISCSI_LUN_BYTE_COPY(istmh->lun, icmdp->cmd_lun->lun_num);
2350fcf3ce44SJohn Forte break;
2351fcf3ce44SJohn Forte case RESET_TARGET:
2352fcf3ce44SJohn Forte case RESET_BUS:
235330e7468fSPeter Dunlap istmh->function = ISCSI_FLAG_FINAL |
2354fcf3ce44SJohn Forte ISCSI_TM_FUNC_TARGET_WARM_RESET;
2355fcf3ce44SJohn Forte break;
2356fcf3ce44SJohn Forte default:
2357fcf3ce44SJohn Forte /* unsupported / unknown level */
2358fcf3ce44SJohn Forte ASSERT(FALSE);
2359fcf3ce44SJohn Forte break;
2360fcf3ce44SJohn Forte }
2361fcf3ce44SJohn Forte
236230e7468fSPeter Dunlap iscsi_tx_pdu(icp, ISCSI_OP_SCSI_TASK_MGT_MSG, istmh,
236330e7468fSPeter Dunlap sizeof (iscsi_scsi_task_mgt_hdr_t), icmdp);
2364fcf3ce44SJohn Forte
2365fcf3ce44SJohn Forte return (rval);
2366fcf3ce44SJohn Forte }
2367fcf3ce44SJohn Forte
2368fcf3ce44SJohn Forte
2369fcf3ce44SJohn Forte /*
2370fcf3ce44SJohn Forte * iscsi_tx_logout -
2371fcf3ce44SJohn Forte *
2372fcf3ce44SJohn Forte */
2373fcf3ce44SJohn Forte static iscsi_status_t
iscsi_tx_logout(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)2374fcf3ce44SJohn Forte iscsi_tx_logout(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2375fcf3ce44SJohn Forte {
2376fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
2377fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL;
237830e7468fSPeter Dunlap iscsi_logout_hdr_t *ilh;
2379fcf3ce44SJohn Forte
2380fcf3ce44SJohn Forte ASSERT(isp != NULL);
2381fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
2382fcf3ce44SJohn Forte icp = icmdp->cmd_conn;
2383fcf3ce44SJohn Forte ASSERT(icp != NULL);
2384fcf3ce44SJohn Forte
238530e7468fSPeter Dunlap ilh = kmem_zalloc(sizeof (iscsi_logout_hdr_t), KM_SLEEP);
238630e7468fSPeter Dunlap ilh->opcode = ISCSI_OP_LOGOUT_CMD | ISCSI_OP_IMMEDIATE;
238730e7468fSPeter Dunlap ilh->flags = ISCSI_FLAG_FINAL | ISCSI_LOGOUT_REASON_CLOSE_SESSION;
238830e7468fSPeter Dunlap ilh->itt = icmdp->cmd_itt;
238930e7468fSPeter Dunlap ilh->cid = icp->conn_cid;
2390fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex);
23912b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_sn = isp->sess_cmdsn;
239230e7468fSPeter Dunlap ilh->cmdsn = htonl(isp->sess_cmdsn);
2393fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex);
239430e7468fSPeter Dunlap ilh->expstatsn = htonl(icp->conn_expstatsn);
239530e7468fSPeter Dunlap iscsi_tx_pdu(icp, ISCSI_OP_LOGOUT_CMD, ilh,
239630e7468fSPeter Dunlap sizeof (iscsi_logout_hdr_t), icmdp);
2397fcf3ce44SJohn Forte
2398fcf3ce44SJohn Forte return (rval);
2399fcf3ce44SJohn Forte }
2400fcf3ce44SJohn Forte
2401fcf3ce44SJohn Forte /*
2402fcf3ce44SJohn Forte * iscsi_tx_text - setup iSCSI text request header and send PDU with
2403fcf3ce44SJohn Forte * data given in the buffer attached to the command. For a single
2404fcf3ce44SJohn Forte * text request, the target may need to send its response in multiple
2405fcf3ce44SJohn Forte * text response. In this case, empty text requests are sent after
2406fcf3ce44SJohn Forte * each received response to notify the target the initiator is ready
2407fcf3ce44SJohn Forte * for more response. For the initial request, the data_len field in
2408fcf3ce44SJohn Forte * the text specific portion of a command is set to the amount of data
2409fcf3ce44SJohn Forte * the initiator wants to send as part of the request. If additional
2410fcf3ce44SJohn Forte * empty text requests are required for long responses, the data_len
2411fcf3ce44SJohn Forte * field is set to 0 by the iscsi_handle_text function.
2412fcf3ce44SJohn Forte */
2413fcf3ce44SJohn Forte static iscsi_status_t
iscsi_tx_text(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)2414fcf3ce44SJohn Forte iscsi_tx_text(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
2415fcf3ce44SJohn Forte {
2416fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
2417fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL;
241830e7468fSPeter Dunlap iscsi_text_hdr_t *ith;
2419fcf3ce44SJohn Forte
2420fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
2421fcf3ce44SJohn Forte icp = icmdp->cmd_conn;
2422fcf3ce44SJohn Forte ASSERT(icp != NULL);
2423fcf3ce44SJohn Forte
242430e7468fSPeter Dunlap ith = kmem_zalloc(sizeof (iscsi_text_hdr_t), KM_SLEEP);
242530e7468fSPeter Dunlap ASSERT(ith != NULL);
242630e7468fSPeter Dunlap ith->flags = ISCSI_FLAG_FINAL;
242730e7468fSPeter Dunlap hton24(ith->dlength, icmdp->cmd_un.text.data_len);
242830e7468fSPeter Dunlap ith->ttt = icmdp->cmd_un.text.ttt;
242930e7468fSPeter Dunlap iscsi_tx_init_hdr(isp, icp, (iscsi_text_hdr_t *)ith,
24302b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_OP_TEXT_CMD, icmdp);
243130e7468fSPeter Dunlap bcopy(icmdp->cmd_un.text.lun, ith->rsvd4, sizeof (ith->rsvd4));
2432fcf3ce44SJohn Forte
243330e7468fSPeter Dunlap iscsi_tx_pdu(icp, ISCSI_OP_TEXT_CMD, ith, sizeof (iscsi_text_hdr_t),
243430e7468fSPeter Dunlap icmdp);
2435fcf3ce44SJohn Forte
2436fcf3ce44SJohn Forte return (rval);
2437fcf3ce44SJohn Forte }
2438fcf3ce44SJohn Forte
2439fcf3ce44SJohn Forte /*
2440fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
2441fcf3ce44SJohn Forte * | End of protocol send routines |
2442fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
2443fcf3ce44SJohn Forte */
2444fcf3ce44SJohn Forte
2445fcf3ce44SJohn Forte /*
2446fcf3ce44SJohn Forte * iscsi_handle_abort -
2447fcf3ce44SJohn Forte *
2448fcf3ce44SJohn Forte */
2449fcf3ce44SJohn Forte void
iscsi_handle_abort(void * arg)2450fcf3ce44SJohn Forte iscsi_handle_abort(void *arg)
2451fcf3ce44SJohn Forte {
2452fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL;
2453fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = (iscsi_cmd_t *)arg;
2454fcf3ce44SJohn Forte iscsi_cmd_t *new_icmdp;
2455fcf3ce44SJohn Forte iscsi_conn_t *icp;
2456fcf3ce44SJohn Forte
2457fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
2458fcf3ce44SJohn Forte icp = icmdp->cmd_conn;
2459fcf3ce44SJohn Forte ASSERT(icp != NULL);
2460fcf3ce44SJohn Forte isp = icp->conn_sess;
2461fcf3ce44SJohn Forte ASSERT(isp != NULL);
2462fcf3ce44SJohn Forte
2463fcf3ce44SJohn Forte /* there should only be one abort */
2464fcf3ce44SJohn Forte ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL);
2465fcf3ce44SJohn Forte
2466fcf3ce44SJohn Forte new_icmdp = iscsi_cmd_alloc(icp, KM_SLEEP);
24672b79d384Sbing zhao - Sun Microsystems - Beijing China new_icmdp->cmd_type = ISCSI_CMD_TYPE_ABORT;
24682b79d384Sbing zhao - Sun Microsystems - Beijing China new_icmdp->cmd_lun = icmdp->cmd_lun;
24692b79d384Sbing zhao - Sun Microsystems - Beijing China new_icmdp->cmd_un.abort.icmdp = icmdp;
24702b79d384Sbing zhao - Sun Microsystems - Beijing China new_icmdp->cmd_conn = icmdp->cmd_conn;
24712b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_un.scsi.abort_icmdp = new_icmdp;
2472fcf3ce44SJohn Forte
2473fcf3ce44SJohn Forte /* pending queue mutex is already held by timeout_checks */
2474fcf3ce44SJohn Forte iscsi_cmd_state_machine(new_icmdp, ISCSI_CMD_EVENT_E1, isp);
2475fcf3ce44SJohn Forte }
2476fcf3ce44SJohn Forte
247730e7468fSPeter Dunlap /*
247830e7468fSPeter Dunlap * Callback from IDM indicating that the task has been suspended or aborted.
247930e7468fSPeter Dunlap */
248030e7468fSPeter Dunlap void
iscsi_task_aborted(idm_task_t * idt,idm_status_t status)248130e7468fSPeter Dunlap iscsi_task_aborted(idm_task_t *idt, idm_status_t status)
248230e7468fSPeter Dunlap {
248330e7468fSPeter Dunlap iscsi_cmd_t *icmdp = idt->idt_private;
248430e7468fSPeter Dunlap iscsi_conn_t *icp = icmdp->cmd_conn;
248530e7468fSPeter Dunlap iscsi_sess_t *isp = icp->conn_sess;
248630e7468fSPeter Dunlap
248730e7468fSPeter Dunlap ASSERT(icmdp->cmd_conn != NULL);
248830e7468fSPeter Dunlap
248930e7468fSPeter Dunlap switch (status) {
249030e7468fSPeter Dunlap case IDM_STATUS_SUSPENDED:
249130e7468fSPeter Dunlap /*
249230e7468fSPeter Dunlap * If the task is suspended, it may be aborted later,
249330e7468fSPeter Dunlap * so we can ignore this notification.
249430e7468fSPeter Dunlap */
249530e7468fSPeter Dunlap break;
249630e7468fSPeter Dunlap
249730e7468fSPeter Dunlap case IDM_STATUS_ABORTED:
249830e7468fSPeter Dunlap mutex_enter(&icp->conn_queue_active.mutex);
249930e7468fSPeter Dunlap iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E9, isp);
250030e7468fSPeter Dunlap mutex_exit(&icp->conn_queue_active.mutex);
250130e7468fSPeter Dunlap break;
250230e7468fSPeter Dunlap
250330e7468fSPeter Dunlap default:
250430e7468fSPeter Dunlap /*
250530e7468fSPeter Dunlap * Unexpected status.
250630e7468fSPeter Dunlap */
250730e7468fSPeter Dunlap ASSERT(0);
250830e7468fSPeter Dunlap }
250930e7468fSPeter Dunlap
251030e7468fSPeter Dunlap }
2511fcf3ce44SJohn Forte
2512fcf3ce44SJohn Forte /*
2513fcf3ce44SJohn Forte * iscsi_handle_nop -
2514fcf3ce44SJohn Forte *
2515fcf3ce44SJohn Forte */
2516fcf3ce44SJohn Forte static void
iscsi_handle_nop(iscsi_conn_t * icp,uint32_t itt,uint32_t ttt)2517fcf3ce44SJohn Forte iscsi_handle_nop(iscsi_conn_t *icp, uint32_t itt, uint32_t ttt)
2518fcf3ce44SJohn Forte {
2519fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL;
2520fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL;
2521fcf3ce44SJohn Forte
2522fcf3ce44SJohn Forte ASSERT(icp != NULL);
2523fcf3ce44SJohn Forte isp = icp->conn_sess;
2524fcf3ce44SJohn Forte ASSERT(isp != NULL);
2525fcf3ce44SJohn Forte
2526fcf3ce44SJohn Forte icmdp = iscsi_cmd_alloc(icp, KM_NOSLEEP);
2527fcf3ce44SJohn Forte if (icmdp == NULL) {
2528fcf3ce44SJohn Forte return;
2529fcf3ce44SJohn Forte }
2530fcf3ce44SJohn Forte
2531fcf3ce44SJohn Forte icmdp->cmd_type = ISCSI_CMD_TYPE_NOP;
2532fcf3ce44SJohn Forte icmdp->cmd_itt = itt;
2533fcf3ce44SJohn Forte icmdp->cmd_ttt = ttt;
2534fcf3ce44SJohn Forte icmdp->cmd_lun = NULL;
2535fcf3ce44SJohn Forte icp->conn_nop_lbolt = ddi_get_lbolt();
2536fcf3ce44SJohn Forte
2537fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
2538fcf3ce44SJohn Forte }
2539fcf3ce44SJohn Forte
2540fcf3ce44SJohn Forte /*
25412b79d384Sbing zhao - Sun Microsystems - Beijing China * iscsi_handle_reset - send reset request to the target
2542fcf3ce44SJohn Forte *
2543fcf3ce44SJohn Forte */
2544fcf3ce44SJohn Forte iscsi_status_t
iscsi_handle_reset(iscsi_sess_t * isp,int level,iscsi_lun_t * ilp)2545fcf3ce44SJohn Forte iscsi_handle_reset(iscsi_sess_t *isp, int level, iscsi_lun_t *ilp)
2546fcf3ce44SJohn Forte {
2547fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
2548fcf3ce44SJohn Forte iscsi_conn_t *icp;
2549fcf3ce44SJohn Forte iscsi_cmd_t icmd;
2550fcf3ce44SJohn Forte
2551fcf3ce44SJohn Forte ASSERT(isp != NULL);
2552fcf3ce44SJohn Forte
25532b79d384Sbing zhao - Sun Microsystems - Beijing China if (level == RESET_LUN) {
25542b79d384Sbing zhao - Sun Microsystems - Beijing China rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
25552b79d384Sbing zhao - Sun Microsystems - Beijing China ASSERT(ilp != NULL);
25562b79d384Sbing zhao - Sun Microsystems - Beijing China if (ilp->lun_state & ISCSI_LUN_STATE_BUSY) {
25572b79d384Sbing zhao - Sun Microsystems - Beijing China rw_exit(&isp->sess_lun_list_rwlock);
25582b79d384Sbing zhao - Sun Microsystems - Beijing China return (ISCSI_STATUS_SUCCESS);
25592b79d384Sbing zhao - Sun Microsystems - Beijing China }
25602b79d384Sbing zhao - Sun Microsystems - Beijing China ilp->lun_state |= ISCSI_LUN_STATE_BUSY;
25612b79d384Sbing zhao - Sun Microsystems - Beijing China rw_exit(&isp->sess_lun_list_rwlock);
25622b79d384Sbing zhao - Sun Microsystems - Beijing China } else {
25632b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_enter(&isp->sess_reset_mutex);
25642b79d384Sbing zhao - Sun Microsystems - Beijing China if (isp->sess_reset_in_progress == B_TRUE) {
25652b79d384Sbing zhao - Sun Microsystems - Beijing China /*
25662b79d384Sbing zhao - Sun Microsystems - Beijing China * If the reset is in progress, it is unnecessary
25672b79d384Sbing zhao - Sun Microsystems - Beijing China * to send reset to the target redunantly.
25682b79d384Sbing zhao - Sun Microsystems - Beijing China */
25692b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&isp->sess_reset_mutex);
25702b79d384Sbing zhao - Sun Microsystems - Beijing China return (ISCSI_STATUS_SUCCESS);
25712b79d384Sbing zhao - Sun Microsystems - Beijing China }
25722b79d384Sbing zhao - Sun Microsystems - Beijing China isp->sess_reset_in_progress = B_TRUE;
25732b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&isp->sess_reset_mutex);
25742b79d384Sbing zhao - Sun Microsystems - Beijing China }
25752b79d384Sbing zhao - Sun Microsystems - Beijing China
2576fcf3ce44SJohn Forte bzero(&icmd, sizeof (iscsi_cmd_t));
2577fcf3ce44SJohn Forte icmd.cmd_sig = ISCSI_SIG_CMD;
2578fcf3ce44SJohn Forte icmd.cmd_state = ISCSI_CMD_STATE_FREE;
2579fcf3ce44SJohn Forte icmd.cmd_type = ISCSI_CMD_TYPE_RESET;
2580fcf3ce44SJohn Forte icmd.cmd_lun = ilp;
2581fcf3ce44SJohn Forte icmd.cmd_un.reset.level = level;
2582fcf3ce44SJohn Forte icmd.cmd_result = ISCSI_STATUS_SUCCESS;
2583fcf3ce44SJohn Forte icmd.cmd_completed = B_FALSE;
25842b79d384Sbing zhao - Sun Microsystems - Beijing China icmd.cmd_un.reset.response = SCSI_TCP_TM_RESP_COMPLETE;
25852b79d384Sbing zhao - Sun Microsystems - Beijing China
2586fcf3ce44SJohn Forte mutex_init(&icmd.cmd_mutex, NULL, MUTEX_DRIVER, NULL);
2587fcf3ce44SJohn Forte cv_init(&icmd.cmd_completion, NULL, CV_DRIVER, NULL);
2588fcf3ce44SJohn Forte /*
2589fcf3ce44SJohn Forte * If we received an IO and we are not in the
2590fcf3ce44SJohn Forte * LOGGED_IN state we are in the process of
2591fcf3ce44SJohn Forte * failing. Just respond that we are BUSY.
2592fcf3ce44SJohn Forte */
2593904e51f6SJack Meng rw_enter(&isp->sess_state_rwlock, RW_READER);
2594fcf3ce44SJohn Forte if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) {
2595fcf3ce44SJohn Forte /* We aren't connected to the target fake success */
2596904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock);
25972b79d384Sbing zhao - Sun Microsystems - Beijing China
25982b79d384Sbing zhao - Sun Microsystems - Beijing China if (level == RESET_LUN) {
25992b79d384Sbing zhao - Sun Microsystems - Beijing China rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
26002b79d384Sbing zhao - Sun Microsystems - Beijing China ilp->lun_state &= ~ISCSI_LUN_STATE_BUSY;
26012b79d384Sbing zhao - Sun Microsystems - Beijing China rw_exit(&isp->sess_lun_list_rwlock);
26022b79d384Sbing zhao - Sun Microsystems - Beijing China } else {
26032b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_enter(&isp->sess_reset_mutex);
26042b79d384Sbing zhao - Sun Microsystems - Beijing China isp->sess_reset_in_progress = B_FALSE;
26052b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&isp->sess_reset_mutex);
26062b79d384Sbing zhao - Sun Microsystems - Beijing China }
26072b79d384Sbing zhao - Sun Microsystems - Beijing China
2608fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS);
2609fcf3ce44SJohn Forte }
2610fcf3ce44SJohn Forte
2611fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex);
2612fcf3ce44SJohn Forte iscsi_cmd_state_machine(&icmd, ISCSI_CMD_EVENT_E1, isp);
2613fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex);
2614904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock);
2615fcf3ce44SJohn Forte
2616fcf3ce44SJohn Forte /* stall until completed */
2617fcf3ce44SJohn Forte mutex_enter(&icmd.cmd_mutex);
2618fcf3ce44SJohn Forte while (icmd.cmd_completed == B_FALSE) {
2619fcf3ce44SJohn Forte cv_wait(&icmd.cmd_completion, &icmd.cmd_mutex);
2620fcf3ce44SJohn Forte }
2621fcf3ce44SJohn Forte mutex_exit(&icmd.cmd_mutex);
2622fcf3ce44SJohn Forte
2623fcf3ce44SJohn Forte /* copy rval */
2624fcf3ce44SJohn Forte rval = icmd.cmd_result;
2625fcf3ce44SJohn Forte
2626fcf3ce44SJohn Forte if (rval == ISCSI_STATUS_SUCCESS) {
2627fcf3ce44SJohn Forte /*
2628fcf3ce44SJohn Forte * Reset was successful. We need to flush
2629fcf3ce44SJohn Forte * all active IOs.
2630fcf3ce44SJohn Forte */
2631fcf3ce44SJohn Forte rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
2632fcf3ce44SJohn Forte icp = isp->sess_conn_list;
2633fcf3ce44SJohn Forte while (icp != NULL) {
2634fcf3ce44SJohn Forte iscsi_cmd_t *t_icmdp = NULL;
26352b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_t *next_icmdp = NULL;
2636fcf3ce44SJohn Forte
2637fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex);
2638fcf3ce44SJohn Forte t_icmdp = icp->conn_queue_active.head;
2639fcf3ce44SJohn Forte while (t_icmdp != NULL) {
26402b79d384Sbing zhao - Sun Microsystems - Beijing China next_icmdp = t_icmdp->cmd_next;
26412b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_enter(&t_icmdp->cmd_mutex);
26422b79d384Sbing zhao - Sun Microsystems - Beijing China if (!(t_icmdp->cmd_misc_flags &
26432b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_MISCFLAG_SENT)) {
26442b79d384Sbing zhao - Sun Microsystems - Beijing China /*
26452b79d384Sbing zhao - Sun Microsystems - Beijing China * Although this command is in the
26462b79d384Sbing zhao - Sun Microsystems - Beijing China * active queue, it has not been sent.
26472b79d384Sbing zhao - Sun Microsystems - Beijing China * Skip it.
26482b79d384Sbing zhao - Sun Microsystems - Beijing China */
26492b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&t_icmdp->cmd_mutex);
26502b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp = next_icmdp;
26512b79d384Sbing zhao - Sun Microsystems - Beijing China continue;
26522b79d384Sbing zhao - Sun Microsystems - Beijing China }
26532b79d384Sbing zhao - Sun Microsystems - Beijing China if (level == RESET_LUN) {
26542b79d384Sbing zhao - Sun Microsystems - Beijing China if (icmd.cmd_lun == NULL ||
26552b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_lun == NULL ||
26562b79d384Sbing zhao - Sun Microsystems - Beijing China (icmd.cmd_lun->lun_num !=
26572b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_lun->lun_num)) {
26582b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&t_icmdp->cmd_mutex);
26592b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp = next_icmdp;
26602b79d384Sbing zhao - Sun Microsystems - Beijing China continue;
26612b79d384Sbing zhao - Sun Microsystems - Beijing China }
26622b79d384Sbing zhao - Sun Microsystems - Beijing China }
26632b79d384Sbing zhao - Sun Microsystems - Beijing China
26642b79d384Sbing zhao - Sun Microsystems - Beijing China if (icmd.cmd_sn == t_icmdp->cmd_sn) {
26652b79d384Sbing zhao - Sun Microsystems - Beijing China /*
26662b79d384Sbing zhao - Sun Microsystems - Beijing China * This command may be replied with
26672b79d384Sbing zhao - Sun Microsystems - Beijing China * UA sense key later. So currently
26682b79d384Sbing zhao - Sun Microsystems - Beijing China * it is not a suitable time to flush
26692b79d384Sbing zhao - Sun Microsystems - Beijing China * it. Mark its flag with FLUSH. There
26702b79d384Sbing zhao - Sun Microsystems - Beijing China * is no harm to keep it for a while.
26712b79d384Sbing zhao - Sun Microsystems - Beijing China */
26722b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_misc_flags |=
26732b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_MISCFLAG_FLUSH;
26742b79d384Sbing zhao - Sun Microsystems - Beijing China if (t_icmdp->cmd_type ==
26752b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_TYPE_SCSI) {
26762b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_un.scsi.pkt_stat |=
26772b79d384Sbing zhao - Sun Microsystems - Beijing China STAT_BUS_RESET;
26782b79d384Sbing zhao - Sun Microsystems - Beijing China }
26792b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&t_icmdp->cmd_mutex);
26802b79d384Sbing zhao - Sun Microsystems - Beijing China } else if ((icmd.cmd_sn > t_icmdp->cmd_sn) ||
26812b79d384Sbing zhao - Sun Microsystems - Beijing China ((t_icmdp->cmd_sn - icmd.cmd_sn) >
26822b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_SN_WRAP)) {
26832b79d384Sbing zhao - Sun Microsystems - Beijing China /*
26842b79d384Sbing zhao - Sun Microsystems - Beijing China * This reset request must act on all
26852b79d384Sbing zhao - Sun Microsystems - Beijing China * the commnds from the same session
26862b79d384Sbing zhao - Sun Microsystems - Beijing China * having a CmdSN lower than the task
26872b79d384Sbing zhao - Sun Microsystems - Beijing China * mangement CmdSN. So flush these
26882b79d384Sbing zhao - Sun Microsystems - Beijing China * commands here.
26892b79d384Sbing zhao - Sun Microsystems - Beijing China */
26902b79d384Sbing zhao - Sun Microsystems - Beijing China if (t_icmdp->cmd_type ==
26912b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_TYPE_SCSI) {
26922b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_un.scsi.pkt_stat |=
26932b79d384Sbing zhao - Sun Microsystems - Beijing China STAT_BUS_RESET;
26942b79d384Sbing zhao - Sun Microsystems - Beijing China }
26952b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&t_icmdp->cmd_mutex);
26962b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_state_machine(t_icmdp,
26972b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_EVENT_E7, isp);
26982b79d384Sbing zhao - Sun Microsystems - Beijing China } else {
26992b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&t_icmdp->cmd_mutex);
27002b79d384Sbing zhao - Sun Microsystems - Beijing China }
27012b79d384Sbing zhao - Sun Microsystems - Beijing China
27022b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp = next_icmdp;
2703fcf3ce44SJohn Forte }
2704fcf3ce44SJohn Forte
2705fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
2706fcf3ce44SJohn Forte icp = icp->conn_next;
2707fcf3ce44SJohn Forte }
2708fcf3ce44SJohn Forte rw_exit(&isp->sess_conn_list_rwlock);
2709fcf3ce44SJohn Forte }
2710fcf3ce44SJohn Forte
2711fcf3ce44SJohn Forte /* clean up */
2712fcf3ce44SJohn Forte cv_destroy(&icmd.cmd_completion);
2713fcf3ce44SJohn Forte mutex_destroy(&icmd.cmd_mutex);
2714fcf3ce44SJohn Forte
27152b79d384Sbing zhao - Sun Microsystems - Beijing China if (level == RESET_LUN) {
27162b79d384Sbing zhao - Sun Microsystems - Beijing China rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
27172b79d384Sbing zhao - Sun Microsystems - Beijing China ilp->lun_state &= ~ISCSI_LUN_STATE_BUSY;
27182b79d384Sbing zhao - Sun Microsystems - Beijing China rw_exit(&isp->sess_lun_list_rwlock);
27192b79d384Sbing zhao - Sun Microsystems - Beijing China } else {
27202b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_enter(&isp->sess_reset_mutex);
27212b79d384Sbing zhao - Sun Microsystems - Beijing China isp->sess_reset_in_progress = B_FALSE;
27222b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&isp->sess_reset_mutex);
27232b79d384Sbing zhao - Sun Microsystems - Beijing China }
27242b79d384Sbing zhao - Sun Microsystems - Beijing China
2725fcf3ce44SJohn Forte return (rval);
2726fcf3ce44SJohn Forte }
2727fcf3ce44SJohn Forte
272830e7468fSPeter Dunlap /*
272992adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * iscsi_logout_start - task handler for deferred logout
273092adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Acquire a hold before call, released in iscsi_handle_logout
273130e7468fSPeter Dunlap */
273230e7468fSPeter Dunlap static void
iscsi_logout_start(void * arg)273330e7468fSPeter Dunlap iscsi_logout_start(void *arg)
273430e7468fSPeter Dunlap {
273530e7468fSPeter Dunlap iscsi_task_t *itp = (iscsi_task_t *)arg;
273630e7468fSPeter Dunlap iscsi_conn_t *icp;
273730e7468fSPeter Dunlap
273830e7468fSPeter Dunlap icp = (iscsi_conn_t *)itp->t_arg;
273930e7468fSPeter Dunlap
274030e7468fSPeter Dunlap mutex_enter(&icp->conn_state_mutex);
274130e7468fSPeter Dunlap (void) iscsi_handle_logout(icp);
274230e7468fSPeter Dunlap mutex_exit(&icp->conn_state_mutex);
274330e7468fSPeter Dunlap }
2744fcf3ce44SJohn Forte
2745fcf3ce44SJohn Forte /*
2746fcf3ce44SJohn Forte * iscsi_handle_logout - This function will issue a logout for
2747fcf3ce44SJohn Forte * the session from a specific connection.
274892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Acquire idm_conn_hold before call. Released internally.
2749fcf3ce44SJohn Forte */
2750fcf3ce44SJohn Forte iscsi_status_t
iscsi_handle_logout(iscsi_conn_t * icp)2751fcf3ce44SJohn Forte iscsi_handle_logout(iscsi_conn_t *icp)
2752fcf3ce44SJohn Forte {
2753fcf3ce44SJohn Forte iscsi_sess_t *isp;
275430e7468fSPeter Dunlap idm_conn_t *ic;
2755fcf3ce44SJohn Forte iscsi_cmd_t *icmdp;
2756fcf3ce44SJohn Forte int rval;
2757fcf3ce44SJohn Forte
2758fcf3ce44SJohn Forte ASSERT(icp != NULL);
2759fcf3ce44SJohn Forte isp = icp->conn_sess;
276030e7468fSPeter Dunlap ic = icp->conn_ic;
2761fcf3ce44SJohn Forte ASSERT(isp != NULL);
2762fcf3ce44SJohn Forte ASSERT(isp->sess_hba != NULL);
276330e7468fSPeter Dunlap ASSERT(mutex_owned(&icp->conn_state_mutex));
276430e7468fSPeter Dunlap
276530e7468fSPeter Dunlap /*
276692adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * If the connection has already gone down (e.g. if the transport
276792adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * failed between when this LOGOUT was generated and now) then we
276892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * can and must skip sending the LOGOUT. Check the same condition
276992adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * we use below to determine that connection has "settled".
277030e7468fSPeter Dunlap */
277192adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States if ((icp->conn_state == ISCSI_CONN_STATE_FREE) ||
277292adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States (icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
277392adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States (icp->conn_state == ISCSI_CONN_STATE_POLLING)) {
277492adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_conn_rele(ic);
277592adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (0);
277692adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States }
2777fcf3ce44SJohn Forte
2778fcf3ce44SJohn Forte icmdp = iscsi_cmd_alloc(icp, KM_SLEEP);
2779fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
2780fcf3ce44SJohn Forte icmdp->cmd_type = ISCSI_CMD_TYPE_LOGOUT;
2781fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS;
2782fcf3ce44SJohn Forte icmdp->cmd_completed = B_FALSE;
2783fcf3ce44SJohn Forte
2784fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex);
2785fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
2786fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex);
2787fcf3ce44SJohn Forte
2788fcf3ce44SJohn Forte /*
2789fcf3ce44SJohn Forte * release connection state mutex to avoid a deadlock. This
2790fcf3ce44SJohn Forte * function is called from within the connection state
2791fcf3ce44SJohn Forte * machine with the lock held. When the logout response is
2792fcf3ce44SJohn Forte * received another call to the connection state machine
2793fcf3ce44SJohn Forte * occurs which causes the deadlock
2794fcf3ce44SJohn Forte */
2795fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex);
2796fcf3ce44SJohn Forte
2797fcf3ce44SJohn Forte /* stall until completed */
2798fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex);
2799fcf3ce44SJohn Forte while (icmdp->cmd_completed == B_FALSE) {
2800fcf3ce44SJohn Forte cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
2801fcf3ce44SJohn Forte }
2802fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex);
2803fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex);
2804fcf3ce44SJohn Forte
2805fcf3ce44SJohn Forte /* copy rval */
2806fcf3ce44SJohn Forte rval = icmdp->cmd_result;
2807fcf3ce44SJohn Forte
2808fcf3ce44SJohn Forte /* clean up */
2809fcf3ce44SJohn Forte iscsi_cmd_free(icmdp);
2810fcf3ce44SJohn Forte
281130e7468fSPeter Dunlap if (rval != 0) {
281230e7468fSPeter Dunlap /* If the logout failed then drop the connection */
281330e7468fSPeter Dunlap idm_ini_conn_disconnect(icp->conn_ic);
281430e7468fSPeter Dunlap }
281530e7468fSPeter Dunlap
281630e7468fSPeter Dunlap /* stall until connection settles */
281730e7468fSPeter Dunlap while ((icp->conn_state != ISCSI_CONN_STATE_FREE) &&
281830e7468fSPeter Dunlap (icp->conn_state != ISCSI_CONN_STATE_FAILED) &&
281930e7468fSPeter Dunlap (icp->conn_state != ISCSI_CONN_STATE_POLLING)) {
282030e7468fSPeter Dunlap /* wait for transition */
282130e7468fSPeter Dunlap cv_wait(&icp->conn_state_change, &icp->conn_state_mutex);
282230e7468fSPeter Dunlap }
282330e7468fSPeter Dunlap
282430e7468fSPeter Dunlap idm_conn_rele(ic);
282530e7468fSPeter Dunlap
282630e7468fSPeter Dunlap /*
282730e7468fSPeter Dunlap * Return value reflects whether the logout command completed --
282830e7468fSPeter Dunlap * regardless of the return value the connection is closed and
282930e7468fSPeter Dunlap * ready for reconnection.
283030e7468fSPeter Dunlap */
2831fcf3ce44SJohn Forte return (rval);
2832fcf3ce44SJohn Forte }
2833fcf3ce44SJohn Forte
283430e7468fSPeter Dunlap
2835fcf3ce44SJohn Forte /*
2836fcf3ce44SJohn Forte * iscsi_handle_text - main control function for iSCSI text requests. This
2837fcf3ce44SJohn Forte * function handles allocating the command, sending initial text request, and
2838fcf3ce44SJohn Forte * handling long response sequence.
2839fcf3ce44SJohn Forte * If a data overflow condition occurs, iscsi_handle_text continues to
2840fcf3ce44SJohn Forte * receive responses until the all data has been recieved. This allows
2841fcf3ce44SJohn Forte * the full data length to be returned to the caller.
2842fcf3ce44SJohn Forte */
2843fcf3ce44SJohn Forte iscsi_status_t
iscsi_handle_text(iscsi_conn_t * icp,char * buf,uint32_t buf_len,uint32_t data_len,uint32_t * rx_data_len)2844fcf3ce44SJohn Forte iscsi_handle_text(iscsi_conn_t *icp, char *buf, uint32_t buf_len,
2845fcf3ce44SJohn Forte uint32_t data_len, uint32_t *rx_data_len)
2846fcf3ce44SJohn Forte {
2847fcf3ce44SJohn Forte iscsi_sess_t *isp;
2848fcf3ce44SJohn Forte iscsi_cmd_t *icmdp;
2849fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
2850fcf3ce44SJohn Forte
2851fcf3ce44SJohn Forte ASSERT(icp != NULL);
2852fcf3ce44SJohn Forte ASSERT(buf != NULL);
2853fcf3ce44SJohn Forte ASSERT(rx_data_len != NULL);
2854fcf3ce44SJohn Forte
2855fcf3ce44SJohn Forte isp = icp->conn_sess;
2856fcf3ce44SJohn Forte ASSERT(isp != NULL);
2857fcf3ce44SJohn Forte
2858fcf3ce44SJohn Forte /*
2859fcf3ce44SJohn Forte * Ensure data for text request command is not greater
2860fcf3ce44SJohn Forte * than the negotiated maximum receive data seqment length.
2861fcf3ce44SJohn Forte *
2862fcf3ce44SJohn Forte * Although iSCSI allows for long text requests (multiple
2863fcf3ce44SJohn Forte * pdus), this function places a restriction on text
2864fcf3ce44SJohn Forte * requests to ensure it is handled by a single PDU.
2865fcf3ce44SJohn Forte */
2866fcf3ce44SJohn Forte if (data_len > icp->conn_params.max_xmit_data_seg_len) {
2867fcf3ce44SJohn Forte return (ISCSI_STATUS_CMD_FAILED);
2868fcf3ce44SJohn Forte }
2869fcf3ce44SJohn Forte
2870fcf3ce44SJohn Forte icmdp = iscsi_cmd_alloc(icp, KM_SLEEP);
2871fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
2872fcf3ce44SJohn Forte
2873fcf3ce44SJohn Forte icmdp->cmd_type = ISCSI_CMD_TYPE_TEXT;
2874fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS;
2875d233de7eSJack Meng icmdp->cmd_misc_flags &= ~ISCSI_CMD_MISCFLAG_FREE;
2876fcf3ce44SJohn Forte icmdp->cmd_completed = B_FALSE;
2877fcf3ce44SJohn Forte
2878fcf3ce44SJohn Forte icmdp->cmd_un.text.buf = buf;
2879fcf3ce44SJohn Forte icmdp->cmd_un.text.buf_len = buf_len;
2880fcf3ce44SJohn Forte icmdp->cmd_un.text.offset = 0;
2881fcf3ce44SJohn Forte icmdp->cmd_un.text.data_len = data_len;
2882fcf3ce44SJohn Forte icmdp->cmd_un.text.total_rx_len = 0;
2883fcf3ce44SJohn Forte icmdp->cmd_un.text.ttt = ISCSI_RSVD_TASK_TAG;
2884fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_INITIAL_REQ;
2885fcf3ce44SJohn Forte
2886fcf3ce44SJohn Forte long_text_response:
2887904e51f6SJack Meng rw_enter(&isp->sess_state_rwlock, RW_READER);
2888fcf3ce44SJohn Forte if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) {
2889fcf3ce44SJohn Forte iscsi_cmd_free(icmdp);
2890904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock);
2891fcf3ce44SJohn Forte return (ISCSI_STATUS_NO_CONN_LOGGED_IN);
2892fcf3ce44SJohn Forte }
2893fcf3ce44SJohn Forte
2894fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex);
2895fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
2896fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex);
2897904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock);
2898fcf3ce44SJohn Forte
2899fcf3ce44SJohn Forte /* stall until completed */
2900fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex);
2901fcf3ce44SJohn Forte while (icmdp->cmd_completed == B_FALSE) {
2902fcf3ce44SJohn Forte cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
2903fcf3ce44SJohn Forte }
2904fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex);
2905fcf3ce44SJohn Forte
2906fcf3ce44SJohn Forte /*
2907fcf3ce44SJohn Forte * check if error occured. If data overflow occured, continue on
2908fcf3ce44SJohn Forte * to ensure we get all data so that the full data length can be
2909fcf3ce44SJohn Forte * returned to the user
2910fcf3ce44SJohn Forte */
2911fcf3ce44SJohn Forte if ((icmdp->cmd_result != ISCSI_STATUS_SUCCESS) &&
2912fcf3ce44SJohn Forte (icmdp->cmd_result != ISCSI_STATUS_DATA_OVERFLOW)) {
2913fcf3ce44SJohn Forte cmn_err(CE_NOTE, "iscsi: SendTarget discovery failed (%d)",
2914fcf3ce44SJohn Forte icmdp->cmd_result);
2915fcf3ce44SJohn Forte rval = icmdp->cmd_result;
2916fcf3ce44SJohn Forte iscsi_cmd_free(icmdp);
2917fcf3ce44SJohn Forte return (rval);
2918fcf3ce44SJohn Forte }
2919fcf3ce44SJohn Forte
2920fcf3ce44SJohn Forte /* check if this was a partial text PDU */
2921fcf3ce44SJohn Forte if (icmdp->cmd_un.text.stage != ISCSI_CMD_TEXT_FINAL_RSP) {
2922fcf3ce44SJohn Forte /*
2923fcf3ce44SJohn Forte * If a paritial text rexponse received, send an empty
2924fcf3ce44SJohn Forte * text request. This follows the behaviour specified
2925fcf3ce44SJohn Forte * in RFC3720 regarding long text responses.
2926fcf3ce44SJohn Forte */
2927d233de7eSJack Meng icmdp->cmd_misc_flags &= ~ISCSI_CMD_MISCFLAG_FREE;
2928fcf3ce44SJohn Forte icmdp->cmd_completed = B_FALSE;
2929fcf3ce44SJohn Forte icmdp->cmd_un.text.data_len = 0;
2930fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_CONTINUATION;
2931fcf3ce44SJohn Forte goto long_text_response;
2932fcf3ce44SJohn Forte }
2933fcf3ce44SJohn Forte
2934fcf3ce44SJohn Forte /*
2935fcf3ce44SJohn Forte * set total received data length. If data overflow this would be
2936fcf3ce44SJohn Forte * amount of data that would have been received if buffer large
2937fcf3ce44SJohn Forte * enough.
2938fcf3ce44SJohn Forte */
2939fcf3ce44SJohn Forte *rx_data_len = icmdp->cmd_un.text.total_rx_len;
2940fcf3ce44SJohn Forte
2941fcf3ce44SJohn Forte /* copy rval */
2942fcf3ce44SJohn Forte rval = icmdp->cmd_result;
2943fcf3ce44SJohn Forte
2944fcf3ce44SJohn Forte /* clean up */
2945fcf3ce44SJohn Forte iscsi_cmd_free(icmdp);
2946fcf3ce44SJohn Forte
2947fcf3ce44SJohn Forte return (rval);
2948fcf3ce44SJohn Forte }
2949fcf3ce44SJohn Forte
2950fcf3ce44SJohn Forte /*
2951fcf3ce44SJohn Forte * iscsi_handle_passthru - This function is used to send a uscsi_cmd
2952fcf3ce44SJohn Forte * to a specific target lun. This routine is used for internal purposes
2953fcf3ce44SJohn Forte * during enumeration and via the ISCSI_USCSICMD IOCTL. We restrict
2954fcf3ce44SJohn Forte * the CDBs that can be issued to a target/lun to INQUIRY, REPORT_LUNS,
2955fcf3ce44SJohn Forte * and READ_CAPACITY for security purposes.
2956fcf3ce44SJohn Forte *
2957fcf3ce44SJohn Forte * The logic here is broken into three phases.
2958fcf3ce44SJohn Forte * 1) Allocate and initialize a pkt/icmdp
2959fcf3ce44SJohn Forte * 2) Send the pkt/icmdp
2960fcf3ce44SJohn Forte * 3) cv_wait for completion
2961fcf3ce44SJohn Forte */
2962fcf3ce44SJohn Forte iscsi_status_t
iscsi_handle_passthru(iscsi_sess_t * isp,uint16_t lun,struct uscsi_cmd * ucmdp)2963fcf3ce44SJohn Forte iscsi_handle_passthru(iscsi_sess_t *isp, uint16_t lun, struct uscsi_cmd *ucmdp)
2964fcf3ce44SJohn Forte {
2965146832dbSMilos Muzik iscsi_status_t rval;
2966146832dbSMilos Muzik iscsi_cmd_t *icmdp;
2967146832dbSMilos Muzik struct scsi_pkt *pkt;
2968146832dbSMilos Muzik struct buf *bp;
2969146832dbSMilos Muzik struct scsi_arq_status *arqstat;
2970146832dbSMilos Muzik int statuslen;
2971fcf3ce44SJohn Forte
2972fcf3ce44SJohn Forte ASSERT(isp != NULL);
2973fcf3ce44SJohn Forte ASSERT(ucmdp != NULL);
2974fcf3ce44SJohn Forte
2975fcf3ce44SJohn Forte if (ucmdp->uscsi_rqlen > SENSE_LENGTH) {
2976146832dbSMilos Muzik /*
2977146832dbSMilos Muzik * The caller provided sense buffer large enough for additional
2978146832dbSMilos Muzik * sense bytes. We need to allocate pkt_scbp to fit them there
2979146832dbSMilos Muzik * too.
2980146832dbSMilos Muzik */
2981146832dbSMilos Muzik statuslen = ucmdp->uscsi_rqlen + ISCSI_ARQ_STATUS_NOSENSE_LEN;
2982146832dbSMilos Muzik } else {
2983146832dbSMilos Muzik /* The default size of pkt_scbp */
2984146832dbSMilos Muzik statuslen = sizeof (struct scsi_arq_status);
2985fcf3ce44SJohn Forte }
2986fcf3ce44SJohn Forte
2987fcf3ce44SJohn Forte /*
2988fcf3ce44SJohn Forte * Step 1. Setup structs - KM_SLEEP will always succeed
2989fcf3ce44SJohn Forte */
2990fcf3ce44SJohn Forte bp = kmem_zalloc(sizeof (struct buf), KM_SLEEP);
2991fcf3ce44SJohn Forte ASSERT(bp != NULL);
2992fcf3ce44SJohn Forte pkt = kmem_zalloc(sizeof (struct scsi_pkt), KM_SLEEP);
2993fcf3ce44SJohn Forte ASSERT(pkt != NULL);
2994fcf3ce44SJohn Forte icmdp = iscsi_cmd_alloc(NULL, KM_SLEEP);
2995fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
2996fcf3ce44SJohn Forte
2997fcf3ce44SJohn Forte /* setup bp structure */
2998fcf3ce44SJohn Forte bp->b_flags = B_READ;
2999fcf3ce44SJohn Forte bp->b_bcount = ucmdp->uscsi_buflen;
3000fcf3ce44SJohn Forte bp->b_un.b_addr = ucmdp->uscsi_bufaddr;
3001fcf3ce44SJohn Forte
3002fcf3ce44SJohn Forte /* setup scsi_pkt structure */
3003fcf3ce44SJohn Forte pkt->pkt_ha_private = icmdp;
3004146832dbSMilos Muzik pkt->pkt_scbp = kmem_zalloc(statuslen, KM_SLEEP);
3005fcf3ce44SJohn Forte pkt->pkt_cdbp = kmem_zalloc(ucmdp->uscsi_cdblen, KM_SLEEP);
3006fcf3ce44SJohn Forte /* callback routine for passthru, will wake cv_wait */
3007fcf3ce44SJohn Forte pkt->pkt_comp = iscsi_handle_passthru_callback;
3008fcf3ce44SJohn Forte pkt->pkt_time = ucmdp->uscsi_timeout;
3009fcf3ce44SJohn Forte
3010fcf3ce44SJohn Forte /* setup iscsi_cmd structure */
3011fcf3ce44SJohn Forte icmdp->cmd_lun = NULL;
3012fcf3ce44SJohn Forte icmdp->cmd_type = ISCSI_CMD_TYPE_SCSI;
3013fcf3ce44SJohn Forte icmdp->cmd_un.scsi.lun = lun;
3014fcf3ce44SJohn Forte icmdp->cmd_un.scsi.pkt = pkt;
3015fcf3ce44SJohn Forte icmdp->cmd_un.scsi.bp = bp;
3016fcf3ce44SJohn Forte bcopy(ucmdp->uscsi_cdb, pkt->pkt_cdbp, ucmdp->uscsi_cdblen);
3017fcf3ce44SJohn Forte icmdp->cmd_un.scsi.cmdlen = ucmdp->uscsi_cdblen;
3018146832dbSMilos Muzik icmdp->cmd_un.scsi.statuslen = statuslen;
3019fcf3ce44SJohn Forte icmdp->cmd_crc_error_seen = B_FALSE;
3020fcf3ce44SJohn Forte icmdp->cmd_completed = B_FALSE;
3021fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS;
3022fcf3ce44SJohn Forte
3023fcf3ce44SJohn Forte /*
3024fcf3ce44SJohn Forte * Step 2. Push IO onto pending queue. If we aren't in
3025fcf3ce44SJohn Forte * FULL_FEATURE we need to fail the IO.
3026fcf3ce44SJohn Forte */
3027904e51f6SJack Meng rw_enter(&isp->sess_state_rwlock, RW_READER);
3028fcf3ce44SJohn Forte if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) {
3029904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock);
3030fcf3ce44SJohn Forte
3031fcf3ce44SJohn Forte iscsi_cmd_free(icmdp);
3032fcf3ce44SJohn Forte kmem_free(pkt->pkt_cdbp, ucmdp->uscsi_cdblen);
3033146832dbSMilos Muzik kmem_free(pkt->pkt_scbp, statuslen);
3034fcf3ce44SJohn Forte kmem_free(pkt, sizeof (struct scsi_pkt));
3035fcf3ce44SJohn Forte kmem_free(bp, sizeof (struct buf));
3036fcf3ce44SJohn Forte
3037fcf3ce44SJohn Forte return (ISCSI_STATUS_CMD_FAILED);
3038fcf3ce44SJohn Forte }
3039fcf3ce44SJohn Forte
3040fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex);
3041fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
3042fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex);
3043904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock);
3044fcf3ce44SJohn Forte
3045fcf3ce44SJohn Forte /*
3046fcf3ce44SJohn Forte * Step 3. Wait on cv_wait for completion routine
3047fcf3ce44SJohn Forte */
3048fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex);
3049fcf3ce44SJohn Forte while (icmdp->cmd_completed == B_FALSE) {
3050fcf3ce44SJohn Forte cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
3051fcf3ce44SJohn Forte }
3052fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex);
3053fcf3ce44SJohn Forte
3054fcf3ce44SJohn Forte /* copy rval */
3055fcf3ce44SJohn Forte rval = icmdp->cmd_result;
3056fcf3ce44SJohn Forte
3057fcf3ce44SJohn Forte ucmdp->uscsi_resid = pkt->pkt_resid;
3058fcf3ce44SJohn Forte
3059fcf3ce44SJohn Forte /* update scsi status */
3060fcf3ce44SJohn Forte arqstat = (struct scsi_arq_status *)pkt->pkt_scbp;
3061fcf3ce44SJohn Forte ucmdp->uscsi_status = ((char *)&arqstat->sts_status)[0];
3062fcf3ce44SJohn Forte
3063fcf3ce44SJohn Forte /* copy request sense buffers if caller gave space */
3064fcf3ce44SJohn Forte if ((ucmdp->uscsi_rqlen > 0) &&
3065fcf3ce44SJohn Forte (ucmdp->uscsi_rqbuf != NULL)) {
3066146832dbSMilos Muzik ASSERT(ucmdp->uscsi_rqlen >= arqstat->sts_rqpkt_resid);
3067146832dbSMilos Muzik ucmdp->uscsi_rqresid = arqstat->sts_rqpkt_resid;
3068146832dbSMilos Muzik bcopy(&arqstat->sts_sensedata, ucmdp->uscsi_rqbuf,
3069146832dbSMilos Muzik ucmdp->uscsi_rqlen - arqstat->sts_rqpkt_resid);
3070fcf3ce44SJohn Forte }
3071fcf3ce44SJohn Forte
3072904e51f6SJack Meng if ((ucmdp->uscsi_status == STATUS_CHECK) &&
3073904e51f6SJack Meng ((icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_INTERNAL)) == B_TRUE) {
3074904e51f6SJack Meng /*
3075904e51f6SJack Meng * Internal SCSI commands received status
3076904e51f6SJack Meng */
3077904e51f6SJack Meng (void) iscsi_decode_sense(
3078904e51f6SJack Meng (uint8_t *)&arqstat->sts_sensedata, icmdp);
3079904e51f6SJack Meng }
3080904e51f6SJack Meng
3081fcf3ce44SJohn Forte /* clean up */
3082fcf3ce44SJohn Forte iscsi_cmd_free(icmdp);
3083fcf3ce44SJohn Forte kmem_free(pkt->pkt_cdbp, ucmdp->uscsi_cdblen);
3084146832dbSMilos Muzik kmem_free(pkt->pkt_scbp, statuslen);
3085fcf3ce44SJohn Forte kmem_free(pkt, sizeof (struct scsi_pkt));
3086fcf3ce44SJohn Forte kmem_free(bp, sizeof (struct buf));
3087fcf3ce44SJohn Forte
3088fcf3ce44SJohn Forte return (rval);
3089fcf3ce44SJohn Forte }
3090fcf3ce44SJohn Forte
3091fcf3ce44SJohn Forte
3092fcf3ce44SJohn Forte /*
3093fcf3ce44SJohn Forte * iscsi_handle_passthru_callback -
3094fcf3ce44SJohn Forte *
3095fcf3ce44SJohn Forte */
3096fcf3ce44SJohn Forte static void
iscsi_handle_passthru_callback(struct scsi_pkt * pkt)3097fcf3ce44SJohn Forte iscsi_handle_passthru_callback(struct scsi_pkt *pkt)
3098fcf3ce44SJohn Forte {
3099fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL;
3100fcf3ce44SJohn Forte
3101fcf3ce44SJohn Forte ASSERT(pkt != NULL);
3102fcf3ce44SJohn Forte icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private;
3103fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
3104fcf3ce44SJohn Forte
3105fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex);
3106fcf3ce44SJohn Forte icmdp->cmd_completed = B_TRUE;
3107fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS;
3108fcf3ce44SJohn Forte cv_broadcast(&icmdp->cmd_completion);
3109fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex);
3110fcf3ce44SJohn Forte
3111fcf3ce44SJohn Forte }
3112fcf3ce44SJohn Forte
311330e7468fSPeter Dunlap /*
311430e7468fSPeter Dunlap * IDM callbacks
311530e7468fSPeter Dunlap */
311630e7468fSPeter Dunlap void
iscsi_build_hdr(idm_task_t * idm_task,idm_pdu_t * pdu,uint8_t opcode)311730e7468fSPeter Dunlap iscsi_build_hdr(idm_task_t *idm_task, idm_pdu_t *pdu, uint8_t opcode)
311830e7468fSPeter Dunlap {
311930e7468fSPeter Dunlap iscsi_cmd_t *icmdp = idm_task->idt_private;
312030e7468fSPeter Dunlap iscsi_conn_t *icp = icmdp->cmd_conn;
312130e7468fSPeter Dunlap iscsi_data_hdr_t *ihp = (iscsi_data_hdr_t *)pdu->isp_hdr;
312230e7468fSPeter Dunlap
312330e7468fSPeter Dunlap mutex_enter(&icmdp->cmd_mutex);
312430e7468fSPeter Dunlap if (opcode == ISCSI_OP_SCSI_DATA) {
312530e7468fSPeter Dunlap uint32_t data_sn;
312630e7468fSPeter Dunlap uint32_t lun;
312730e7468fSPeter Dunlap icmdp = idm_task->idt_private;
312830e7468fSPeter Dunlap icp = icmdp->cmd_conn;
312930e7468fSPeter Dunlap ihp->opcode = opcode;
313030e7468fSPeter Dunlap ihp->itt = icmdp->cmd_itt;
313130e7468fSPeter Dunlap ihp->ttt = idm_task->idt_r2t_ttt;
313230e7468fSPeter Dunlap ihp->expstatsn = htonl(icp->conn_expstatsn);
313330e7468fSPeter Dunlap icp->conn_laststatsn = icp->conn_expstatsn;
313430e7468fSPeter Dunlap data_sn = ntohl(ihp->datasn);
313530e7468fSPeter Dunlap data_sn++;
313630e7468fSPeter Dunlap lun = icmdp->cmd_un.scsi.lun;
313730e7468fSPeter Dunlap ISCSI_LUN_BYTE_COPY(ihp->lun, lun);
313830e7468fSPeter Dunlap /* CRM: upate_flow_control */
313930e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_build_hdr"
314030e7468fSPeter Dunlap "(ISCSI_OP_SCSI_DATA): task: %p icp: %p ic: %p itt: %x "
314130e7468fSPeter Dunlap "exp: %d data_sn: %d", (void *)idm_task, (void *)icp,
314230e7468fSPeter Dunlap (void *)icp->conn_ic, ihp->itt, icp->conn_expstatsn,
314330e7468fSPeter Dunlap data_sn);
314430e7468fSPeter Dunlap } else {
314530e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi_build_hdr: unprocessed build "
314630e7468fSPeter Dunlap "header opcode: %x", opcode);
314730e7468fSPeter Dunlap }
314830e7468fSPeter Dunlap mutex_exit(&icmdp->cmd_mutex);
314930e7468fSPeter Dunlap }
315030e7468fSPeter Dunlap
315130e7468fSPeter Dunlap static void
iscsi_process_rsp_status(iscsi_sess_t * isp,iscsi_conn_t * icp,idm_status_t status)315230e7468fSPeter Dunlap iscsi_process_rsp_status(iscsi_sess_t *isp, iscsi_conn_t *icp,
315330e7468fSPeter Dunlap idm_status_t status)
315430e7468fSPeter Dunlap {
315530e7468fSPeter Dunlap switch (status) {
315630e7468fSPeter Dunlap case IDM_STATUS_SUCCESS:
315730e7468fSPeter Dunlap if ((isp->sess_state == ISCSI_SESS_STATE_IN_FLUSH) &&
315830e7468fSPeter Dunlap (icp->conn_queue_active.count == 0)) {
315930e7468fSPeter Dunlap iscsi_drop_conn_cleanup(icp);
316030e7468fSPeter Dunlap }
316130e7468fSPeter Dunlap break;
316230e7468fSPeter Dunlap case IDM_STATUS_PROTOCOL_ERROR:
316330e7468fSPeter Dunlap KSTAT_INC_CONN_ERR_PROTOCOL(icp);
316430e7468fSPeter Dunlap iscsi_drop_conn_cleanup(icp);
316530e7468fSPeter Dunlap break;
316630e7468fSPeter Dunlap default:
316730e7468fSPeter Dunlap break;
316830e7468fSPeter Dunlap }
316930e7468fSPeter Dunlap }
317030e7468fSPeter Dunlap
317130e7468fSPeter Dunlap static void
iscsi_drop_conn_cleanup(iscsi_conn_t * icp)3172811eca55SToomas Soome iscsi_drop_conn_cleanup(iscsi_conn_t *icp)
3173811eca55SToomas Soome {
317430e7468fSPeter Dunlap mutex_enter(&icp->conn_state_mutex);
317530e7468fSPeter Dunlap idm_ini_conn_disconnect(icp->conn_ic);
317630e7468fSPeter Dunlap mutex_exit(&icp->conn_state_mutex);
317730e7468fSPeter Dunlap }
317830e7468fSPeter Dunlap
317930e7468fSPeter Dunlap void
iscsi_rx_error_pdu(idm_conn_t * ic,idm_pdu_t * pdu,idm_status_t status)318030e7468fSPeter Dunlap iscsi_rx_error_pdu(idm_conn_t *ic, idm_pdu_t *pdu, idm_status_t status)
318130e7468fSPeter Dunlap {
318230e7468fSPeter Dunlap iscsi_conn_t *icp = (iscsi_conn_t *)ic->ic_handle;
318330e7468fSPeter Dunlap iscsi_sess_t *isp;
318430e7468fSPeter Dunlap
318530e7468fSPeter Dunlap ASSERT(icp != NULL);
318630e7468fSPeter Dunlap isp = icp->conn_sess;
318730e7468fSPeter Dunlap ASSERT(isp != NULL);
318830e7468fSPeter Dunlap iscsi_process_rsp_status(isp, icp, status);
318930e7468fSPeter Dunlap idm_pdu_complete(pdu, status);
319030e7468fSPeter Dunlap }
319130e7468fSPeter Dunlap
319230e7468fSPeter Dunlap void
iscsi_rx_misc_pdu(idm_conn_t * ic,idm_pdu_t * pdu)319330e7468fSPeter Dunlap iscsi_rx_misc_pdu(idm_conn_t *ic, idm_pdu_t *pdu)
319430e7468fSPeter Dunlap {
3195811eca55SToomas Soome iscsi_conn_t *icp;
319630e7468fSPeter Dunlap iscsi_hdr_t *ihp = (iscsi_hdr_t *)pdu->isp_hdr;
319730e7468fSPeter Dunlap iscsi_sess_t *isp;
319830e7468fSPeter Dunlap idm_status_t status;
319930e7468fSPeter Dunlap
320030e7468fSPeter Dunlap icp = ic->ic_handle;
320130e7468fSPeter Dunlap isp = icp->conn_sess;
320230e7468fSPeter Dunlap isp->sess_rx_lbolt = icp->conn_rx_lbolt = ddi_get_lbolt();
320330e7468fSPeter Dunlap switch (ihp->opcode & ISCSI_OPCODE_MASK) {
320430e7468fSPeter Dunlap case ISCSI_OP_LOGIN_RSP:
320530e7468fSPeter Dunlap status = iscsi_rx_process_login_pdu(ic, pdu);
320630e7468fSPeter Dunlap idm_pdu_complete(pdu, status);
320730e7468fSPeter Dunlap break;
320830e7468fSPeter Dunlap case ISCSI_OP_LOGOUT_RSP:
320930e7468fSPeter Dunlap status = iscsi_rx_process_logout_rsp(ic, pdu);
321030e7468fSPeter Dunlap idm_pdu_complete(pdu, status);
321130e7468fSPeter Dunlap break;
321230e7468fSPeter Dunlap case ISCSI_OP_REJECT_MSG:
321330e7468fSPeter Dunlap status = iscsi_rx_process_reject_rsp(ic, pdu);
321430e7468fSPeter Dunlap break;
321530e7468fSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_RSP:
321630e7468fSPeter Dunlap status = iscsi_rx_process_task_mgt_rsp(ic, pdu);
321730e7468fSPeter Dunlap idm_pdu_complete(pdu, status);
321830e7468fSPeter Dunlap break;
321930e7468fSPeter Dunlap case ISCSI_OP_NOOP_IN:
322030e7468fSPeter Dunlap status = iscsi_rx_process_nop(ic, pdu);
322130e7468fSPeter Dunlap idm_pdu_complete(pdu, status);
322230e7468fSPeter Dunlap break;
322330e7468fSPeter Dunlap case ISCSI_OP_ASYNC_EVENT:
322430e7468fSPeter Dunlap status = iscsi_rx_process_async_rsp(ic, pdu);
322530e7468fSPeter Dunlap break;
322630e7468fSPeter Dunlap case ISCSI_OP_TEXT_RSP:
322730e7468fSPeter Dunlap status = iscsi_rx_process_text_rsp(ic, pdu);
322830e7468fSPeter Dunlap idm_pdu_complete(pdu, status);
322930e7468fSPeter Dunlap break;
323030e7468fSPeter Dunlap default:
323130e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi connection(%u) protocol error "
323230e7468fSPeter Dunlap "- received misc unsupported opcode 0x%02x",
323330e7468fSPeter Dunlap icp->conn_oid, ihp->opcode);
323430e7468fSPeter Dunlap status = IDM_STATUS_PROTOCOL_ERROR;
323530e7468fSPeter Dunlap break;
323630e7468fSPeter Dunlap }
323730e7468fSPeter Dunlap iscsi_process_rsp_status(isp, icp, status);
323830e7468fSPeter Dunlap }
323930e7468fSPeter Dunlap
3240fcf3ce44SJohn Forte /*
3241fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
3242fcf3ce44SJohn Forte * | Beginning of completion routines |
3243fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
3244fcf3ce44SJohn Forte */
3245fcf3ce44SJohn Forte
3246fcf3ce44SJohn Forte /*
3247fcf3ce44SJohn Forte * iscsi_ic_thread -
3248fcf3ce44SJohn Forte */
3249fcf3ce44SJohn Forte void
iscsi_ic_thread(iscsi_thread_t * thread,void * arg)3250fcf3ce44SJohn Forte iscsi_ic_thread(iscsi_thread_t *thread, void *arg)
3251fcf3ce44SJohn Forte {
3252fcf3ce44SJohn Forte iscsi_sess_t *isp = (iscsi_sess_t *)arg;
3253fcf3ce44SJohn Forte int ret;
3254fcf3ce44SJohn Forte iscsi_queue_t q;
3255fcf3ce44SJohn Forte iscsi_cmd_t *icmdp;
3256fcf3ce44SJohn Forte iscsi_cmd_t *next_icmdp;
3257fcf3ce44SJohn Forte
3258fcf3ce44SJohn Forte ASSERT(isp != NULL);
3259fcf3ce44SJohn Forte ASSERT(thread != NULL);
3260fcf3ce44SJohn Forte ASSERT(thread->signature == SIG_ISCSI_THREAD);
3261fcf3ce44SJohn Forte
3262fcf3ce44SJohn Forte for (;;) {
3263fcf3ce44SJohn Forte
3264fcf3ce44SJohn Forte /*
3265fcf3ce44SJohn Forte * We wait till iodone or somebody else wakes us up.
3266fcf3ce44SJohn Forte */
3267fcf3ce44SJohn Forte ret = iscsi_thread_wait(thread, -1);
3268fcf3ce44SJohn Forte
3269fcf3ce44SJohn Forte /*
3270fcf3ce44SJohn Forte * The value should never be negative since we never timeout.
3271fcf3ce44SJohn Forte */
3272fcf3ce44SJohn Forte ASSERT(ret >= 0);
3273fcf3ce44SJohn Forte
3274fcf3ce44SJohn Forte q.count = 0;
3275fcf3ce44SJohn Forte q.head = NULL;
3276fcf3ce44SJohn Forte q.tail = NULL;
3277fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_completion.mutex);
3278fcf3ce44SJohn Forte icmdp = isp->sess_queue_completion.head;
3279fcf3ce44SJohn Forte while (icmdp != NULL) {
3280fcf3ce44SJohn Forte next_icmdp = icmdp->cmd_next;
3281fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex);
3282fcf3ce44SJohn Forte /*
3283fcf3ce44SJohn Forte * check if the associated r2t/abort has finished
328430e7468fSPeter Dunlap * yet. If not, don't complete the command.
3285fcf3ce44SJohn Forte */
3286fcf3ce44SJohn Forte if ((icmdp->cmd_un.scsi.r2t_icmdp == NULL) &&
328730e7468fSPeter Dunlap (icmdp->cmd_un.scsi.abort_icmdp == NULL)) {
3288fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex);
3289fcf3ce44SJohn Forte (void) iscsi_dequeue_cmd(&isp->
3290fcf3ce44SJohn Forte sess_queue_completion.head,
3291fcf3ce44SJohn Forte &isp->sess_queue_completion.tail,
3292fcf3ce44SJohn Forte icmdp);
3293fcf3ce44SJohn Forte --isp->sess_queue_completion.count;
3294fcf3ce44SJohn Forte iscsi_enqueue_cmd_head(&q.head,
3295fcf3ce44SJohn Forte &q.tail, icmdp);
329630e7468fSPeter Dunlap } else {
3297fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex);
329830e7468fSPeter Dunlap }
3299fcf3ce44SJohn Forte icmdp = next_icmdp;
3300fcf3ce44SJohn Forte }
3301fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_completion.mutex);
3302fcf3ce44SJohn Forte icmdp = q.head;
3303fcf3ce44SJohn Forte while (icmdp != NULL) {
3304fcf3ce44SJohn Forte next_icmdp = icmdp->cmd_next;
3305fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E8, isp);
3306fcf3ce44SJohn Forte icmdp = next_icmdp;
3307fcf3ce44SJohn Forte }
3308fcf3ce44SJohn Forte
3309fcf3ce44SJohn Forte if (ret > 0)
3310fcf3ce44SJohn Forte /* Somebody woke us up to work */
3311fcf3ce44SJohn Forte continue;
3312fcf3ce44SJohn Forte else
3313fcf3ce44SJohn Forte /*
3314fcf3ce44SJohn Forte * Somebody woke us up to kill ourselves. We will
3315fcf3ce44SJohn Forte * make sure, however that the completion queue is
3316fcf3ce44SJohn Forte * empty before leaving. After we've done that it
3317fcf3ce44SJohn Forte * is the originator of the signal that has to make
3318fcf3ce44SJohn Forte * sure no other SCSI command is posted.
3319fcf3ce44SJohn Forte */
3320fcf3ce44SJohn Forte break;
3321fcf3ce44SJohn Forte }
3322fcf3ce44SJohn Forte
3323fcf3ce44SJohn Forte }
3324fcf3ce44SJohn Forte
3325fcf3ce44SJohn Forte /*
3326fcf3ce44SJohn Forte * iscsi_iodone -
3327fcf3ce44SJohn Forte *
3328fcf3ce44SJohn Forte */
3329fcf3ce44SJohn Forte void
iscsi_iodone(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)3330fcf3ce44SJohn Forte iscsi_iodone(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
3331fcf3ce44SJohn Forte {
3332fcf3ce44SJohn Forte struct scsi_pkt *pkt = NULL;
3333fcf3ce44SJohn Forte struct buf *bp = icmdp->cmd_un.scsi.bp;
3334fcf3ce44SJohn Forte
3335fcf3ce44SJohn Forte ASSERT(isp != NULL);
3336fcf3ce44SJohn Forte ASSERT(icmdp != NULL);
3337fcf3ce44SJohn Forte pkt = icmdp->cmd_un.scsi.pkt;
3338fcf3ce44SJohn Forte ASSERT(pkt != NULL);
3339fcf3ce44SJohn Forte
3340fcf3ce44SJohn Forte ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL);
3341fcf3ce44SJohn Forte ASSERT(icmdp->cmd_un.scsi.r2t_icmdp == NULL);
3342fcf3ce44SJohn Forte if (pkt->pkt_reason == CMD_CMPLT) {
3343fcf3ce44SJohn Forte if (bp) {
3344fcf3ce44SJohn Forte if (bp->b_flags & B_READ) {
3345fcf3ce44SJohn Forte KSTAT_SESS_RX_IO_DONE(isp, bp->b_bcount);
3346fcf3ce44SJohn Forte } else {
3347fcf3ce44SJohn Forte KSTAT_SESS_TX_IO_DONE(isp, bp->b_bcount);
3348fcf3ce44SJohn Forte }
3349fcf3ce44SJohn Forte }
3350fcf3ce44SJohn Forte }
3351fcf3ce44SJohn Forte
3352fcf3ce44SJohn Forte if (pkt->pkt_flags & FLAG_NOINTR) {
3353fcf3ce44SJohn Forte cv_broadcast(&icmdp->cmd_completion);
3354fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex);
3355fcf3ce44SJohn Forte } else {
3356fcf3ce44SJohn Forte /*
3357fcf3ce44SJohn Forte * Release mutex. As soon as callback is
3358fcf3ce44SJohn Forte * issued the caller may destroy the command.
3359fcf3ce44SJohn Forte */
3360fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex);
3361fcf3ce44SJohn Forte /*
3362fcf3ce44SJohn Forte * We can't just directly call the pk_comp routine. In
3363fcf3ce44SJohn Forte * many error cases the target driver will use the calling
3364fcf3ce44SJohn Forte * thread to re-drive error handling (reset, retries...)
3365fcf3ce44SJohn Forte * back into the hba driver (iscsi). If the target redrives
3366fcf3ce44SJohn Forte * a reset back into the iscsi driver off this thead we have
3367fcf3ce44SJohn Forte * a chance of deadlocking. So instead use the io completion
3368fcf3ce44SJohn Forte * thread.
3369fcf3ce44SJohn Forte */
3370fcf3ce44SJohn Forte (*icmdp->cmd_un.scsi.pkt->pkt_comp)(icmdp->cmd_un.scsi.pkt);
3371fcf3ce44SJohn Forte }
3372fcf3ce44SJohn Forte }
3373fcf3ce44SJohn Forte
3374fcf3ce44SJohn Forte /*
3375fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
3376fcf3ce44SJohn Forte * | End of completion routines |
3377fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
3378fcf3ce44SJohn Forte */
3379fcf3ce44SJohn Forte
3380fcf3ce44SJohn Forte /*
3381fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
3382fcf3ce44SJohn Forte * | Beginning of watchdog routines |
3383fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
3384fcf3ce44SJohn Forte */
3385fcf3ce44SJohn Forte
3386fcf3ce44SJohn Forte /*
3387fcf3ce44SJohn Forte * iscsi_watchdog_thread -
3388fcf3ce44SJohn Forte *
3389fcf3ce44SJohn Forte */
3390fcf3ce44SJohn Forte void
iscsi_wd_thread(iscsi_thread_t * thread,void * arg)3391fcf3ce44SJohn Forte iscsi_wd_thread(iscsi_thread_t *thread, void *arg)
3392fcf3ce44SJohn Forte {
3393fcf3ce44SJohn Forte iscsi_sess_t *isp = (iscsi_sess_t *)arg;
3394fcf3ce44SJohn Forte int rc = 1;
3395fcf3ce44SJohn Forte
3396fcf3ce44SJohn Forte ASSERT(isp != NULL);
3397fcf3ce44SJohn Forte
3398811eca55SToomas Soome while (rc != 0) {
3399fcf3ce44SJohn Forte
3400fcf3ce44SJohn Forte iscsi_timeout_checks(isp);
3401fcf3ce44SJohn Forte iscsi_nop_checks(isp);
3402fcf3ce44SJohn Forte
3403fcf3ce44SJohn Forte rc = iscsi_thread_wait(thread, SEC_TO_TICK(1));
3404fcf3ce44SJohn Forte }
3405fcf3ce44SJohn Forte }
3406fcf3ce44SJohn Forte
3407fcf3ce44SJohn Forte /*
3408fcf3ce44SJohn Forte * iscsi_timeout_checks -
3409fcf3ce44SJohn Forte *
3410fcf3ce44SJohn Forte */
3411fcf3ce44SJohn Forte static void
iscsi_timeout_checks(iscsi_sess_t * isp)3412fcf3ce44SJohn Forte iscsi_timeout_checks(iscsi_sess_t *isp)
3413fcf3ce44SJohn Forte {
3414fcf3ce44SJohn Forte clock_t now = ddi_get_lbolt();
3415fcf3ce44SJohn Forte iscsi_conn_t *icp;
341630e7468fSPeter Dunlap iscsi_cmd_t *icmdp, *nicmdp;
3417fcf3ce44SJohn Forte
3418fcf3ce44SJohn Forte ASSERT(isp != NULL);
3419fcf3ce44SJohn Forte
3420fcf3ce44SJohn Forte /* PENDING */
3421904e51f6SJack Meng rw_enter(&isp->sess_state_rwlock, RW_READER);
3422fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex);
3423fcf3ce44SJohn Forte for (icmdp = isp->sess_queue_pending.head;
3424fcf3ce44SJohn Forte icmdp; icmdp = nicmdp) {
3425fcf3ce44SJohn Forte nicmdp = icmdp->cmd_next;
3426fcf3ce44SJohn Forte
3427fcf3ce44SJohn Forte /* Skip entries with no timeout */
3428fcf3ce44SJohn Forte if (icmdp->cmd_lbolt_timeout == 0)
3429fcf3ce44SJohn Forte continue;
3430fcf3ce44SJohn Forte
3431fcf3ce44SJohn Forte /*
3432fcf3ce44SJohn Forte * Skip pending queue entries for cmd_type values that depend
3433fcf3ce44SJohn Forte * on having an open cmdsn window for successfull transition
3434fcf3ce44SJohn Forte * from pending to the active (i.e. ones that depend on
3435fcf3ce44SJohn Forte * sess_cmdsn .vs. sess_maxcmdsn). For them, the timer starts
3436fcf3ce44SJohn Forte * when they are successfully moved to the active queue by
3437fcf3ce44SJohn Forte * iscsi_cmd_state_pending() code.
3438fcf3ce44SJohn Forte */
3439d233de7eSJack Meng /*
3440d233de7eSJack Meng * If the cmd is stuck, at least give it a chance
3441d233de7eSJack Meng * to timeout
3442d233de7eSJack Meng */
3443d233de7eSJack Meng if (((icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) ||
3444d233de7eSJack Meng (icmdp->cmd_type == ISCSI_CMD_TYPE_TEXT)) &&
3445d233de7eSJack Meng !(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_STUCK))
3446fcf3ce44SJohn Forte continue;
3447fcf3ce44SJohn Forte
3448fcf3ce44SJohn Forte /* Skip if timeout still in the future */
3449fcf3ce44SJohn Forte if (now <= icmdp->cmd_lbolt_timeout)
3450fcf3ce44SJohn Forte continue;
3451fcf3ce44SJohn Forte
3452fcf3ce44SJohn Forte /* timeout */
3453fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E6, isp);
3454fcf3ce44SJohn Forte }
3455fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex);
3456904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock);
3457fcf3ce44SJohn Forte
3458fcf3ce44SJohn Forte rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
3459fcf3ce44SJohn Forte icp = isp->sess_conn_list;
3460fcf3ce44SJohn Forte while (icp != NULL) {
3461fcf3ce44SJohn Forte
3462aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_timeout = B_FALSE;
3463fcf3ce44SJohn Forte /* ACTIVE */
3464fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex);
3465fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex);
3466fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex);
3467fcf3ce44SJohn Forte for (icmdp = icp->conn_queue_active.head;
3468fcf3ce44SJohn Forte icmdp; icmdp = nicmdp) {
3469fcf3ce44SJohn Forte nicmdp = icmdp->cmd_next;
3470fcf3ce44SJohn Forte
3471aff4bce5Syi zhang - Sun Microsystems - Beijing China if (iscsi_nop_timeout_checks(icmdp) == B_TRUE) {
3472aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_timeout = B_TRUE;
3473aff4bce5Syi zhang - Sun Microsystems - Beijing China }
3474aff4bce5Syi zhang - Sun Microsystems - Beijing China
3475fcf3ce44SJohn Forte /* Skip entries with no timeout */
3476fcf3ce44SJohn Forte if (icmdp->cmd_lbolt_timeout == 0)
3477fcf3ce44SJohn Forte continue;
3478fcf3ce44SJohn Forte
34792b79d384Sbing zhao - Sun Microsystems - Beijing China /*
34802b79d384Sbing zhao - Sun Microsystems - Beijing China * Skip if command is not active or not needed
34812b79d384Sbing zhao - Sun Microsystems - Beijing China * to flush.
34822b79d384Sbing zhao - Sun Microsystems - Beijing China */
34832b79d384Sbing zhao - Sun Microsystems - Beijing China if (icmdp->cmd_state != ISCSI_CMD_STATE_ACTIVE &&
34842b79d384Sbing zhao - Sun Microsystems - Beijing China !(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_FLUSH))
3485fcf3ce44SJohn Forte continue;
3486fcf3ce44SJohn Forte
3487fcf3ce44SJohn Forte /* Skip if timeout still in the future */
3488fcf3ce44SJohn Forte if (now <= icmdp->cmd_lbolt_timeout)
3489fcf3ce44SJohn Forte continue;
3490fcf3ce44SJohn Forte
34912b79d384Sbing zhao - Sun Microsystems - Beijing China if (icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_FLUSH) {
34922b79d384Sbing zhao - Sun Microsystems - Beijing China /*
34932b79d384Sbing zhao - Sun Microsystems - Beijing China * This command is left during target reset,
34942b79d384Sbing zhao - Sun Microsystems - Beijing China * we can flush it now.
34952b79d384Sbing zhao - Sun Microsystems - Beijing China */
34962b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_state_machine(icmdp,
34972b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_EVENT_E7, isp);
34982b79d384Sbing zhao - Sun Microsystems - Beijing China } else if (icmdp->cmd_state == ISCSI_CMD_STATE_ACTIVE) {
34992b79d384Sbing zhao - Sun Microsystems - Beijing China /* timeout */
35002b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_state_machine(icmdp,
35012b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_EVENT_E6, isp);
35022b79d384Sbing zhao - Sun Microsystems - Beijing China }
35032b79d384Sbing zhao - Sun Microsystems - Beijing China
3504fcf3ce44SJohn Forte }
3505fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex);
3506fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex);
3507fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex);
3508fcf3ce44SJohn Forte
3509fcf3ce44SJohn Forte icp = icp->conn_next;
3510fcf3ce44SJohn Forte }
3511aff4bce5Syi zhang - Sun Microsystems - Beijing China
3512aff4bce5Syi zhang - Sun Microsystems - Beijing China icp = isp->sess_conn_list;
3513aff4bce5Syi zhang - Sun Microsystems - Beijing China while (icp != NULL) {
3514*61dfa509SRick McNeal mutex_enter(&icp->conn_state_mutex);
3515*61dfa509SRick McNeal if ((icp->conn_timeout == B_TRUE) &&
3516*61dfa509SRick McNeal (icp->conn_state_idm_connected == B_TRUE)) {
3517aff4bce5Syi zhang - Sun Microsystems - Beijing China /* timeout on this connect detected */
3518aff4bce5Syi zhang - Sun Microsystems - Beijing China idm_ini_conn_disconnect(icp->conn_ic);
3519aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_timeout = B_FALSE;
3520aff4bce5Syi zhang - Sun Microsystems - Beijing China }
3521*61dfa509SRick McNeal mutex_exit(&icp->conn_state_mutex);
3522aff4bce5Syi zhang - Sun Microsystems - Beijing China icp = icp->conn_next;
3523aff4bce5Syi zhang - Sun Microsystems - Beijing China }
3524fcf3ce44SJohn Forte rw_exit(&isp->sess_conn_list_rwlock);
3525fcf3ce44SJohn Forte }
3526fcf3ce44SJohn Forte
3527fcf3ce44SJohn Forte /*
3528fcf3ce44SJohn Forte * iscsi_nop_checks - sends a NOP on idle connections
3529fcf3ce44SJohn Forte *
3530fcf3ce44SJohn Forte * This function walks the connections on a session and
3531fcf3ce44SJohn Forte * issues NOPs on those connections that are in FULL
3532fcf3ce44SJohn Forte * FEATURE mode and have not received data for the
3533fcf3ce44SJohn Forte * time period specified by iscsi_nop_delay (global).
3534fcf3ce44SJohn Forte */
3535fcf3ce44SJohn Forte static void
iscsi_nop_checks(iscsi_sess_t * isp)3536fcf3ce44SJohn Forte iscsi_nop_checks(iscsi_sess_t *isp)
3537fcf3ce44SJohn Forte {
3538fcf3ce44SJohn Forte iscsi_conn_t *icp;
3539fcf3ce44SJohn Forte
3540fcf3ce44SJohn Forte ASSERT(isp != NULL);
3541fcf3ce44SJohn Forte
3542fcf3ce44SJohn Forte if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) {
3543fcf3ce44SJohn Forte return;
3544fcf3ce44SJohn Forte }
3545fcf3ce44SJohn Forte
3546fcf3ce44SJohn Forte rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
3547fcf3ce44SJohn Forte icp = isp->sess_conn_act;
3548fcf3ce44SJohn Forte if (icp != NULL) {
3549fcf3ce44SJohn Forte
3550fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex);
3551fcf3ce44SJohn Forte if ((ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state)) &&
3552fcf3ce44SJohn Forte (ddi_get_lbolt() > isp->sess_conn_act->conn_rx_lbolt +
3553fcf3ce44SJohn Forte SEC_TO_TICK(iscsi_nop_delay)) && (ddi_get_lbolt() >
3554fcf3ce44SJohn Forte isp->sess_conn_act->conn_nop_lbolt +
3555fcf3ce44SJohn Forte SEC_TO_TICK(iscsi_nop_delay))) {
3556fcf3ce44SJohn Forte
3557fcf3ce44SJohn Forte /*
3558fcf3ce44SJohn Forte * We haven't received anything from the
3559fcf3ce44SJohn Forte * target is a defined period of time,
3560fcf3ce44SJohn Forte * send NOP to see if the target is alive.
3561fcf3ce44SJohn Forte */
3562fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex);
3563fcf3ce44SJohn Forte iscsi_handle_nop(isp->sess_conn_act,
3564fcf3ce44SJohn Forte 0, ISCSI_RSVD_TASK_TAG);
3565fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex);
3566fcf3ce44SJohn Forte }
3567fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex);
3568fcf3ce44SJohn Forte
3569fcf3ce44SJohn Forte icp = icp->conn_next;
3570fcf3ce44SJohn Forte }
3571fcf3ce44SJohn Forte rw_exit(&isp->sess_conn_list_rwlock);
3572fcf3ce44SJohn Forte }
3573fcf3ce44SJohn Forte
3574aff4bce5Syi zhang - Sun Microsystems - Beijing China static boolean_t
iscsi_nop_timeout_checks(iscsi_cmd_t * icmdp)3575aff4bce5Syi zhang - Sun Microsystems - Beijing China iscsi_nop_timeout_checks(iscsi_cmd_t *icmdp)
3576aff4bce5Syi zhang - Sun Microsystems - Beijing China {
3577aff4bce5Syi zhang - Sun Microsystems - Beijing China if (icmdp->cmd_type == ISCSI_CMD_TYPE_NOP) {
3578aff4bce5Syi zhang - Sun Microsystems - Beijing China if ((ddi_get_lbolt() - icmdp->cmd_lbolt_active) >
3579aff4bce5Syi zhang - Sun Microsystems - Beijing China SEC_TO_TICK(ISCSI_CONN_TIEMOUT_DETECT)) {
3580aff4bce5Syi zhang - Sun Microsystems - Beijing China return (B_TRUE);
3581aff4bce5Syi zhang - Sun Microsystems - Beijing China } else {
3582aff4bce5Syi zhang - Sun Microsystems - Beijing China return (B_FALSE);
3583aff4bce5Syi zhang - Sun Microsystems - Beijing China }
3584aff4bce5Syi zhang - Sun Microsystems - Beijing China }
3585aff4bce5Syi zhang - Sun Microsystems - Beijing China return (B_FALSE);
3586aff4bce5Syi zhang - Sun Microsystems - Beijing China }
3587fcf3ce44SJohn Forte /*
3588fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
3589fcf3ce44SJohn Forte * | End of wd routines |
3590fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
3591fcf3ce44SJohn Forte */
35922b79d384Sbing zhao - Sun Microsystems - Beijing China
35932b79d384Sbing zhao - Sun Microsystems - Beijing China /*
35942b79d384Sbing zhao - Sun Microsystems - Beijing China * iscsi_flush_cmd_after_reset - flush commands after reset
35952b79d384Sbing zhao - Sun Microsystems - Beijing China *
3596b97c1f92SMilos Muzik * Here we will flush all the commands for a specified LUN whose cmdsn is less
3597b97c1f92SMilos Muzik * than the one received with the Unit Attention.
35982b79d384Sbing zhao - Sun Microsystems - Beijing China */
35992b79d384Sbing zhao - Sun Microsystems - Beijing China static void
iscsi_flush_cmd_after_reset(uint32_t cmd_sn,uint16_t lun_num,iscsi_conn_t * icp)36002b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_flush_cmd_after_reset(uint32_t cmd_sn, uint16_t lun_num,
36012b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_conn_t *icp)
36022b79d384Sbing zhao - Sun Microsystems - Beijing China {
36032b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_t *t_icmdp = NULL;
36042b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_t *next_icmdp = NULL;
36052b79d384Sbing zhao - Sun Microsystems - Beijing China
36062b79d384Sbing zhao - Sun Microsystems - Beijing China ASSERT(icp != NULL);
36072b79d384Sbing zhao - Sun Microsystems - Beijing China
36082b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp = icp->conn_queue_active.head;
36092b79d384Sbing zhao - Sun Microsystems - Beijing China while (t_icmdp != NULL) {
36102b79d384Sbing zhao - Sun Microsystems - Beijing China next_icmdp = t_icmdp->cmd_next;
36112b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_enter(&t_icmdp->cmd_mutex);
36122b79d384Sbing zhao - Sun Microsystems - Beijing China /*
36132b79d384Sbing zhao - Sun Microsystems - Beijing China * We will flush the commands whose cmdsn is less than the one
36142b79d384Sbing zhao - Sun Microsystems - Beijing China * got Unit Attention.
36152b79d384Sbing zhao - Sun Microsystems - Beijing China * Here we will check for wrap by subtracting and compare to
36162b79d384Sbing zhao - Sun Microsystems - Beijing China * 1/2 of a 32 bit number, if greater then we wrapped.
36172b79d384Sbing zhao - Sun Microsystems - Beijing China */
36182b79d384Sbing zhao - Sun Microsystems - Beijing China if ((t_icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_SENT) &&
36192b79d384Sbing zhao - Sun Microsystems - Beijing China ((cmd_sn > t_icmdp->cmd_sn) ||
36202b79d384Sbing zhao - Sun Microsystems - Beijing China ((t_icmdp->cmd_sn - cmd_sn) >
36212b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_SN_WRAP))) {
3622b97c1f92SMilos Muzik /*
3623b97c1f92SMilos Muzik * Internally generated SCSI commands do not have
3624b97c1f92SMilos Muzik * t_icmdp->cmd_lun set, but the LUN can be retrieved
3625b97c1f92SMilos Muzik * from t_icmdp->cmd_un.scsi.lun.
3626b97c1f92SMilos Muzik */
3627b97c1f92SMilos Muzik if ((t_icmdp->cmd_lun != NULL &&
3628b97c1f92SMilos Muzik t_icmdp->cmd_lun->lun_num == lun_num) ||
3629b97c1f92SMilos Muzik (t_icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI &&
3630b97c1f92SMilos Muzik (t_icmdp->cmd_un.scsi.lun & ISCSI_LUN_MASK) ==
3631b97c1f92SMilos Muzik lun_num)) {
36322b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_misc_flags |=
36332b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_MISCFLAG_FLUSH;
36342b79d384Sbing zhao - Sun Microsystems - Beijing China if (t_icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
36352b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_un.scsi.pkt_stat |=
36362b79d384Sbing zhao - Sun Microsystems - Beijing China STAT_BUS_RESET;
36372b79d384Sbing zhao - Sun Microsystems - Beijing China }
36382b79d384Sbing zhao - Sun Microsystems - Beijing China }
36392b79d384Sbing zhao - Sun Microsystems - Beijing China }
36402b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&t_icmdp->cmd_mutex);
36412b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp = next_icmdp;
36422b79d384Sbing zhao - Sun Microsystems - Beijing China }
36432b79d384Sbing zhao - Sun Microsystems - Beijing China }
36442b79d384Sbing zhao - Sun Microsystems - Beijing China
36452b79d384Sbing zhao - Sun Microsystems - Beijing China /*
36462b79d384Sbing zhao - Sun Microsystems - Beijing China * iscsi_decode_sense - decode the sense data in the cmd response
3647904e51f6SJack Meng * and take proper actions
36482b79d384Sbing zhao - Sun Microsystems - Beijing China */
36492b79d384Sbing zhao - Sun Microsystems - Beijing China static boolean_t
iscsi_decode_sense(uint8_t * sense_data,iscsi_cmd_t * icmdp)3650904e51f6SJack Meng iscsi_decode_sense(uint8_t *sense_data, iscsi_cmd_t *icmdp)
36512b79d384Sbing zhao - Sun Microsystems - Beijing China {
3652904e51f6SJack Meng uint8_t sense_key = 0;
3653904e51f6SJack Meng uint8_t asc = 0;
3654904e51f6SJack Meng uint8_t ascq = 0;
3655904e51f6SJack Meng boolean_t flush_io = B_FALSE;
3656904e51f6SJack Meng boolean_t reconfig_lun = B_FALSE;
3657904e51f6SJack Meng iscsi_sess_t *isp = NULL;
36582b79d384Sbing zhao - Sun Microsystems - Beijing China
36592b79d384Sbing zhao - Sun Microsystems - Beijing China ASSERT(sense_data != NULL);
36602b79d384Sbing zhao - Sun Microsystems - Beijing China
3661904e51f6SJack Meng isp = icmdp->cmd_conn->conn_sess;
3662904e51f6SJack Meng
36632b79d384Sbing zhao - Sun Microsystems - Beijing China sense_key = scsi_sense_key(sense_data);
36642b79d384Sbing zhao - Sun Microsystems - Beijing China switch (sense_key) {
36652b79d384Sbing zhao - Sun Microsystems - Beijing China case KEY_UNIT_ATTENTION:
36662b79d384Sbing zhao - Sun Microsystems - Beijing China asc = scsi_sense_asc(sense_data);
36672b79d384Sbing zhao - Sun Microsystems - Beijing China switch (asc) {
36682b79d384Sbing zhao - Sun Microsystems - Beijing China case ISCSI_SCSI_RESET_SENSE_CODE:
36692b79d384Sbing zhao - Sun Microsystems - Beijing China /*
36702b79d384Sbing zhao - Sun Microsystems - Beijing China * POWER ON, RESET, OR BUS_DEVICE RESET
36712b79d384Sbing zhao - Sun Microsystems - Beijing China * OCCURRED
36722b79d384Sbing zhao - Sun Microsystems - Beijing China */
3673904e51f6SJack Meng flush_io = B_TRUE;
36742b79d384Sbing zhao - Sun Microsystems - Beijing China break;
3675904e51f6SJack Meng case ISCSI_SCSI_LUNCHANGED_CODE:
3676904e51f6SJack Meng ascq = scsi_sense_ascq(sense_data);
3677904e51f6SJack Meng if (ascq == ISCSI_SCSI_LUNCHANGED_ASCQ)
3678904e51f6SJack Meng reconfig_lun = B_TRUE;
36792b79d384Sbing zhao - Sun Microsystems - Beijing China default:
36802b79d384Sbing zhao - Sun Microsystems - Beijing China break;
36812b79d384Sbing zhao - Sun Microsystems - Beijing China }
36822b79d384Sbing zhao - Sun Microsystems - Beijing China break;
36832b79d384Sbing zhao - Sun Microsystems - Beijing China default:
36842b79d384Sbing zhao - Sun Microsystems - Beijing China /*
36852b79d384Sbing zhao - Sun Microsystems - Beijing China * Currently we don't care
36862b79d384Sbing zhao - Sun Microsystems - Beijing China * about other sense key.
36872b79d384Sbing zhao - Sun Microsystems - Beijing China */
36882b79d384Sbing zhao - Sun Microsystems - Beijing China break;
36892b79d384Sbing zhao - Sun Microsystems - Beijing China }
3690904e51f6SJack Meng
3691904e51f6SJack Meng if (reconfig_lun == B_TRUE) {
3692904e51f6SJack Meng rw_enter(&isp->sess_state_rwlock, RW_READER);
3693904e51f6SJack Meng if ((isp->sess_state == ISCSI_SESS_STATE_LOGGED_IN) &&
3694904e51f6SJack Meng (iscsi_sess_enum_request(isp, B_FALSE,
3695904e51f6SJack Meng isp->sess_state_event_count) !=
3696904e51f6SJack Meng ISCSI_SESS_ENUM_SUBMITTED)) {
3697904e51f6SJack Meng cmn_err(CE_WARN, "Unable to commit re-enumeration for"
3698904e51f6SJack Meng " session(%u) %s", isp->sess_oid, isp->sess_name);
3699904e51f6SJack Meng }
3700904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock);
3701904e51f6SJack Meng }
3702904e51f6SJack Meng
3703904e51f6SJack Meng return (flush_io);
37042b79d384Sbing zhao - Sun Microsystems - Beijing China }
3705