Sun Dec 3 07:23:12 2017 UTC ()
add debug messages


(mlelstv)
diff -r1.34 -r1.35 src/sys/dev/iscsi/iscsi_send.c

cvs diff -r1.34 -r1.35 src/sys/dev/iscsi/iscsi_send.c (switch to unified diff)

--- src/sys/dev/iscsi/iscsi_send.c 2017/02/25 12:03:57 1.34
+++ src/sys/dev/iscsi/iscsi_send.c 2017/12/03 07:23:12 1.35
@@ -1,1677 +1,1683 @@ @@ -1,1677 +1,1683 @@
1/* $NetBSD: iscsi_send.c,v 1.34 2017/02/25 12:03:57 mlelstv Exp $ */ 1/* $NetBSD: iscsi_send.c,v 1.35 2017/12/03 07:23:12 mlelstv Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc. 4 * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Wasabi Systems, Inc. 8 * by Wasabi Systems, Inc.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31#include "iscsi_globals.h" 31#include "iscsi_globals.h"
32 32
33#include <sys/file.h> 33#include <sys/file.h>
34#include <sys/filedesc.h> 34#include <sys/filedesc.h>
35#include <sys/socket.h> 35#include <sys/socket.h>
36#include <sys/socketvar.h> 36#include <sys/socketvar.h>
37#include <sys/atomic.h> 37#include <sys/atomic.h>
38 38
39/*#define LUN_1 1 */ 39/*#define LUN_1 1 */
40 40
41/*****************************************************************************/ 41/*****************************************************************************/
42 42
43/* 43/*
44 * my_soo_write: 44 * my_soo_write:
45 * Replacement for soo_write with flag handling. 45 * Replacement for soo_write with flag handling.
46 * 46 *
47 * Parameter: 47 * Parameter:
48 * conn The connection 48 * conn The connection
49 * u The uio descriptor 49 * u The uio descriptor
50 * 50 *
51 * Returns: 0 on success, else EIO. 51 * Returns: 0 on success, else EIO.
52 */ 52 */
53 53
54STATIC int 54STATIC int
55my_soo_write(connection_t *conn, struct uio *u) 55my_soo_write(connection_t *conn, struct uio *u)
56{ 56{
57 struct socket *so = conn->sock->f_socket; 57 struct socket *so = conn->sock->f_socket;
58 int ret; 58 int ret;
59#ifdef ISCSI_DEBUG 59#ifdef ISCSI_DEBUG
60 size_t resid = u->uio_resid; 60 size_t resid = u->uio_resid;
61#endif 61#endif
62 62
63 KASSERT(u->uio_resid != 0); 63 KASSERT(u->uio_resid != 0);
64 64
65 ret = (*so->so_send)(so, NULL, u, NULL, NULL, 0, conn->threadobj); 65 ret = (*so->so_send)(so, NULL, u, NULL, NULL, 0, conn->threadobj);
66 66
67 DEB(99, ("soo_write done: len = %zu\n", u->uio_resid)); 67 DEB(99, ("soo_write done: len = %zu\n", u->uio_resid));
68 68
69 if (ret != 0 || u->uio_resid) { 69 if (ret != 0 || u->uio_resid) {
70 DEBC(conn, 0, ("Write failed sock %p (ret: %d, req: %zu, resid: %zu)\n", 70 DEBC(conn, 0, ("Write failed sock %p (ret: %d, req: %zu, resid: %zu)\n",
71 conn->sock, ret, resid, u->uio_resid)); 71 conn->sock, ret, resid, u->uio_resid));
72 handle_connection_error(conn, ISCSI_STATUS_SOCKET_ERROR, NO_LOGOUT); 72 handle_connection_error(conn, ISCSI_STATUS_SOCKET_ERROR, NO_LOGOUT);
73 return EIO; 73 return EIO;
74 } 74 }
75 return 0; 75 return 0;
76} 76}
77 77
78/*****************************************************************************/ 78/*****************************************************************************/
79 79
80/* 80/*
81 * assign_connection: 81 * assign_connection:
82 * This function returns the connection to use for the next transaction. 82 * This function returns the connection to use for the next transaction.
83 * 83 *
84 * Parameter: The session 84 * Parameter: The session
85 * 85 *
86 * Returns: The connection 86 * Returns: The connection
87 */ 87 */
88 88
89connection_t * 89connection_t *
90assign_connection(session_t *session, bool waitok) 90assign_connection(session_t *session, bool waitok)
91{ 91{
92 connection_t *conn, *next; 92 connection_t *conn, *next;
93 93
94 mutex_enter(&session->lock); 94 mutex_enter(&session->lock);
95 do { 95 do {
96 if (session->terminating || 96 if (session->terminating ||
97 (conn = session->mru_connection) == NULL) { 97 (conn = session->mru_connection) == NULL) {
98 mutex_exit(&session->lock); 98 mutex_exit(&session->lock);
99 return NULL; 99 return NULL;
100 } 100 }
101 next = conn; 101 next = conn;
102 do { 102 do {
103 next = TAILQ_NEXT(next, connections); 103 next = TAILQ_NEXT(next, connections);
104 if (next == NULL) { 104 if (next == NULL) {
105 next = TAILQ_FIRST(&session->conn_list); 105 next = TAILQ_FIRST(&session->conn_list);
106 } 106 }
107 } while (next != NULL && next != conn && 107 } while (next != NULL && next != conn &&
108 next->state != ST_FULL_FEATURE); 108 next->state != ST_FULL_FEATURE);
109 109
110 if (next->state != ST_FULL_FEATURE) { 110 if (next->state != ST_FULL_FEATURE) {
111 if (waitok) { 111 if (waitok) {
112 cv_wait(&session->sess_cv, &session->lock); 112 cv_wait(&session->sess_cv, &session->lock);
113 next = TAILQ_FIRST(&session->conn_list); 113 next = TAILQ_FIRST(&session->conn_list);
114 } else { 114 } else {
115 mutex_exit(&session->lock); 115 mutex_exit(&session->lock);
116 return NULL; 116 return NULL;
117 } 117 }
118 } else { 118 } else {
119 session->mru_connection = next; 119 session->mru_connection = next;
120 } 120 }
121 } while (next != NULL && next->state != ST_FULL_FEATURE); 121 } while (next != NULL && next->state != ST_FULL_FEATURE);
122 mutex_exit(&session->lock); 122 mutex_exit(&session->lock);
123 123
124 return next; 124 return next;
125} 125}
126 126
127 127
128/* 128/*
129 * reassign_tasks: 129 * reassign_tasks:
130 * Reassign pending commands to one of the still existing connections 130 * Reassign pending commands to one of the still existing connections
131 * of a session. 131 * of a session.
132 * 132 *
133 * Parameter: 133 * Parameter:
134 * oldconn The terminating connection 134 * oldconn The terminating connection
135 */ 135 */
136 136
137STATIC void 137STATIC void
138reassign_tasks(connection_t *oldconn) 138reassign_tasks(connection_t *oldconn)
139{ 139{
140 session_t *sess = oldconn->session; 140 session_t *sess = oldconn->session;
141 connection_t *conn; 141 connection_t *conn;
142 ccb_t *ccb; 142 ccb_t *ccb;
143 pdu_t *pdu = NULL; 143 pdu_t *pdu = NULL;
144 pdu_t *opdu; 144 pdu_t *opdu;
145 int no_tm = 1; 145 int no_tm = 1;
146 int rc = 1; 146 int rc = 1;
147 uint32_t sn; 147 uint32_t sn;
148 148
149 if ((conn = assign_connection(sess, FALSE)) == NULL) { 149 if ((conn = assign_connection(sess, FALSE)) == NULL) {
150 DEB(1, ("Reassign_tasks of Session %d, connection %d failed, " 150 DEB(1, ("Reassign_tasks of Session %d, connection %d failed, "
151 "no active connection\n", 151 "no active connection\n",
152 sess->id, oldconn->id)); 152 sess->id, oldconn->id));
153 /* XXX here we need to abort the waiting CCBs */ 153 /* XXX here we need to abort the waiting CCBs */
154 return; 154 return;
155 } 155 }
156 156
157 if (sess->ErrorRecoveryLevel >= 2) { 157 if (sess->ErrorRecoveryLevel >= 2) {
158 if (oldconn->loggedout == NOT_LOGGED_OUT) { 158 if (oldconn->loggedout == NOT_LOGGED_OUT) {
159 oldconn->loggedout = LOGOUT_SENT; 159 oldconn->loggedout = LOGOUT_SENT;
160 no_tm = send_logout(conn, oldconn, RECOVER_CONNECTION, TRUE); 160 no_tm = send_logout(conn, oldconn, RECOVER_CONNECTION, TRUE);
161 oldconn->loggedout = (rc) ? LOGOUT_FAILED : LOGOUT_SUCCESS; 161 oldconn->loggedout = (rc) ? LOGOUT_FAILED : LOGOUT_SUCCESS;
162 if (!oldconn->Time2Retain) { 162 if (!oldconn->Time2Retain) {
163 DEBC(conn, 1, ("Time2Retain is zero, setting no_tm\n")); 163 DEBC(conn, 1, ("Time2Retain is zero, setting no_tm\n"));
164 no_tm = 1; 164 no_tm = 1;
165 } 165 }
166 } else if (oldconn->loggedout == LOGOUT_SUCCESS) { 166 } else if (oldconn->loggedout == LOGOUT_SUCCESS) {
167 no_tm = 0; 167 no_tm = 0;
168 } 168 }
169 if (!no_tm && oldconn->Time2Wait) { 169 if (!no_tm && oldconn->Time2Wait) {
170 DEBC(conn, 1, ("Time2Wait=%d, hz=%d, waiting...\n", 170 DEBC(conn, 1, ("Time2Wait=%d, hz=%d, waiting...\n",
171 oldconn->Time2Wait, hz)); 171 oldconn->Time2Wait, hz));
172 kpause("Time2Wait", false, oldconn->Time2Wait * hz, NULL); 172 kpause("Time2Wait", false, oldconn->Time2Wait * hz, NULL);
173 } 173 }
174 } 174 }
175 175
176 DEBC(conn, 1, ("Reassign_tasks: Session %d, conn %d -> conn %d, no_tm=%d\n", 176 DEBC(conn, 1, ("Reassign_tasks: Session %d, conn %d -> conn %d, no_tm=%d\n",
177 sess->id, oldconn->id, conn->id, no_tm)); 177 sess->id, oldconn->id, conn->id, no_tm));
178 178
179 179
180 /* XXX reassign waiting CCBs to new connection */ 180 /* XXX reassign waiting CCBs to new connection */
181 181
182 while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) { 182 while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) {
183 /* Copy PDU contents (PDUs are bound to connection) */ 183 /* Copy PDU contents (PDUs are bound to connection) */
184 if ((pdu = get_pdu(conn, TRUE)) == NULL) { 184 if ((pdu = get_pdu(conn, TRUE)) == NULL) {
185 break; 185 break;
186 } 186 }
187 187
188 /* adjust CCB and clone PDU for new connection */ 188 /* adjust CCB and clone PDU for new connection */
189 TAILQ_REMOVE(&oldconn->ccbs_waiting, ccb, chain); 189 TAILQ_REMOVE(&oldconn->ccbs_waiting, ccb, chain);
190 190
191 opdu = ccb->pdu_waiting; 191 opdu = ccb->pdu_waiting;
192 KASSERT((opdu->flags & PDUF_INQUEUE) == 0); 192 KASSERT((opdu->flags & PDUF_INQUEUE) == 0);
193 193
194 *pdu = *opdu; 194 *pdu = *opdu;
195 195
196 /* restore overwritten back ptr */ 196 /* restore overwritten back ptr */
197 pdu->connection = conn; 197 pdu->connection = conn;
198 198
199 /* fixup saved UIO and IOVEC (regular one will be overwritten anyway) */ 199 /* fixup saved UIO and IOVEC (regular one will be overwritten anyway) */
200 pdu->save_uio.uio_iov = pdu->io_vec; 200 pdu->save_uio.uio_iov = pdu->io_vec;
201 pdu->save_iovec [0].iov_base = &pdu->pdu; 201 pdu->save_iovec [0].iov_base = &pdu->pdu;
202 202
203 if (conn->DataDigest && pdu->save_uio.uio_iovcnt > 1) { 203 if (conn->DataDigest && pdu->save_uio.uio_iovcnt > 1) {
204 if (pdu->save_iovec [2].iov_base == NULL) { 204 if (pdu->save_iovec [2].iov_base == NULL) {
205 pdu->save_iovec [2].iov_base = &pdu->data_digest; 205 pdu->save_iovec [2].iov_base = &pdu->data_digest;
206 pdu->save_uio.uio_iovcnt = 3; 206 pdu->save_uio.uio_iovcnt = 3;
207 } else { 207 } else {
208 pdu->save_iovec [3].iov_base = &pdu->data_digest; 208 pdu->save_iovec [3].iov_base = &pdu->data_digest;
209 pdu->save_uio.uio_iovcnt = 4; 209 pdu->save_uio.uio_iovcnt = 4;
210 } 210 }
211 } 211 }
212 pdu->save_iovec [0].iov_len = 212 pdu->save_iovec [0].iov_len =
213 (conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE; 213 (conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE;
214 214
215 /* link new PDU into old CCB */ 215 /* link new PDU into old CCB */
216 ccb->pdu_waiting = pdu; 216 ccb->pdu_waiting = pdu;
217 /* link new CCB into new connection */ 217 /* link new CCB into new connection */
218 ccb->connection = conn; 218 ccb->connection = conn;
219 /* reset timeouts */ 219 /* reset timeouts */
220 ccb->num_timeouts = 0; 220 ccb->num_timeouts = 0;
221 221
222 /* fixup reference counts */ 222 /* fixup reference counts */
223 oldconn->usecount--; 223 oldconn->usecount--;
224 atomic_inc_uint(&conn->usecount); 224 atomic_inc_uint(&conn->usecount);
225 225
226 DEBC(conn, 1, ("CCB %p: Copied PDU %p to %p\n", 226 DEBC(conn, 1, ("CCB %p: Copied PDU %p to %p\n",
227 ccb, opdu, pdu)); 227 ccb, opdu, pdu));
228 228
229 /* kill temp pointer that is now referenced by the new PDU */ 229 /* kill temp pointer that is now referenced by the new PDU */
230 opdu->temp_data = NULL; 230 opdu->temp_data = NULL;
231 231
232 /* and free the old PDU */ 232 /* and free the old PDU */
233 free_pdu(opdu); 233 free_pdu(opdu);
234 234
235 /* put ready CCB into waiting list of new connection */ 235 /* put ready CCB into waiting list of new connection */
236 mutex_enter(&conn->lock); 236 mutex_enter(&conn->lock);
237 suspend_ccb(ccb, TRUE); 237 suspend_ccb(ccb, TRUE);
238 mutex_exit(&conn->lock); 238 mutex_exit(&conn->lock);
239 } 239 }
240 240
241 if (pdu == NULL) { 241 if (pdu == NULL) {
242 DEBC(conn, 1, ("Error while copying PDUs in reassign_tasks!\n")); 242 DEBC(conn, 1, ("Error while copying PDUs in reassign_tasks!\n"));
243 /* give up recovering, the other connection is screwed up as well... */ 243 /* give up recovering, the other connection is screwed up as well... */
244 while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) { 244 while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) {
245 wake_ccb(ccb, oldconn->terminating); 245 wake_ccb(ccb, oldconn->terminating);
246 } 246 }
247 /* XXX some CCBs might have been moved to new connection, but how is the 247 /* XXX some CCBs might have been moved to new connection, but how is the
248 * new connection handled or killed ? */ 248 * new connection handled or killed ? */
249 return; 249 return;
250 } 250 }
251 251
252 TAILQ_FOREACH(ccb, &conn->ccbs_waiting, chain) { 252 TAILQ_FOREACH(ccb, &conn->ccbs_waiting, chain) {
253 if (!no_tm) { 253 if (!no_tm) {
254 rc = send_task_management(conn, ccb, NULL, TASK_REASSIGN); 254 rc = send_task_management(conn, ccb, NULL, TASK_REASSIGN);
255 } 255 }
256 /* if we get an error on reassign, restart the original request */ 256 /* if we get an error on reassign, restart the original request */
257 if (no_tm || rc) { 257 if (no_tm || rc) {
258 mutex_enter(&sess->lock); 258 mutex_enter(&sess->lock);
259 if (ccb->CmdSN < sess->ExpCmdSN) { 259 if (ccb->CmdSN < sess->ExpCmdSN) {
260 pdu = ccb->pdu_waiting; 260 pdu = ccb->pdu_waiting;
261 sn = get_sernum(sess, pdu); 261 sn = get_sernum(sess, pdu);
262 262
263 /* update CmdSN */ 263 /* update CmdSN */
264 DEBC(conn, 1, ("Resend Updating CmdSN - old %d, new %d\n", 264 DEBC(conn, 1, ("Resend Updating CmdSN - old %d, new %d\n",
265 ccb->CmdSN, sn)); 265 ccb->CmdSN, sn));
266 ccb->CmdSN = sn; 266 ccb->CmdSN = sn;
267 pdu->pdu.p.command.CmdSN = htonl(ccb->CmdSN); 267 pdu->pdu.p.command.CmdSN = htonl(ccb->CmdSN);
268 } 268 }
269 mutex_exit(&sess->lock); 269 mutex_exit(&sess->lock);
270 resend_pdu(ccb); 270 resend_pdu(ccb);
271 } else { 271 } else {
272 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 272 ccb_timeout_start(ccb, COMMAND_TIMEOUT);
273 } 273 }
274 DEBC(conn, 1, ("Reassign ccb %p, no_tm=%d, rc=%d\n", 274 DEBC(conn, 1, ("Reassign ccb %p, no_tm=%d, rc=%d\n",
275 ccb, no_tm, rc)); 275 ccb, no_tm, rc));
276 } 276 }
277} 277}
278 278
279 279
280/* 280/*
281 * iscsi_send_thread: 281 * iscsi_send_thread:
282 * This thread services the send queue, writing the PDUs to the socket. 282 * This thread services the send queue, writing the PDUs to the socket.
283 * It also handles the cleanup when the connection is terminated. 283 * It also handles the cleanup when the connection is terminated.
284 * 284 *
285 * Parameter: 285 * Parameter:
286 * par The connection this thread services 286 * par The connection this thread services
287 */ 287 */
288 288
289void 289void
290iscsi_send_thread(void *par) 290iscsi_send_thread(void *par)
291{ 291{
292 connection_t *conn = (connection_t *) par; 292 connection_t *conn = (connection_t *) par;
293 session_t *sess; 293 session_t *sess;
294 ccb_t *ccb, *nccb; 294 ccb_t *ccb, *nccb;
295 pdu_t *pdu; 295 pdu_t *pdu;
296 struct file *fp; 296 struct file *fp;
297 pdu_disp_t pdisp; 297 pdu_disp_t pdisp;
298 298
299 sess = conn->session; 299 sess = conn->session;
300 /* so cleanup thread knows there's someone left */ 300 /* so cleanup thread knows there's someone left */
301 iscsi_num_send_threads++; 301 iscsi_num_send_threads++;
302 302
303 do { 303 do {
304 mutex_enter(&conn->lock); 304 mutex_enter(&conn->lock);
305 while (!conn->terminating) { 305 while (!conn->terminating) {
306 while (!conn->terminating && 306 while (!conn->terminating &&
307 (pdu = TAILQ_FIRST(&conn->pdus_to_send)) != NULL) { 307 (pdu = TAILQ_FIRST(&conn->pdus_to_send)) != NULL) {
308 TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain); 308 TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain);
309 pdu->flags &= ~PDUF_INQUEUE; 309 pdu->flags &= ~PDUF_INQUEUE;
310 mutex_exit(&conn->lock); 310 mutex_exit(&conn->lock);
311 311
312 /* update ExpStatSN here to avoid discontinuities */ 312 /* update ExpStatSN here to avoid discontinuities */
313 /* and delays in updating target */ 313 /* and delays in updating target */
314 pdu->pdu.p.command.ExpStatSN = htonl(conn->StatSN_buf.ExpSN); 314 pdu->pdu.p.command.ExpStatSN = htonl(conn->StatSN_buf.ExpSN);
315 315
316 if (conn->HeaderDigest) 316 if (conn->HeaderDigest)
317 pdu->pdu.HeaderDigest = gen_digest(&pdu->pdu, BHS_SIZE); 317 pdu->pdu.HeaderDigest = gen_digest(&pdu->pdu, BHS_SIZE);
318 318
319 DEBC(conn, 99, ("Transmitting PDU CmdSN = %u, ExpStatSN = %u\n", 319 DEBC(conn, 99, ("Transmitting PDU CmdSN = %u, ExpStatSN = %u\n",
320 ntohl(pdu->pdu.p.command.CmdSN), 320 ntohl(pdu->pdu.p.command.CmdSN),
321 ntohl(pdu->pdu.p.command.ExpStatSN))); 321 ntohl(pdu->pdu.p.command.ExpStatSN)));
322 my_soo_write(conn, &pdu->uio); 322 my_soo_write(conn, &pdu->uio);
323 323
324 mutex_enter(&conn->lock); 324 mutex_enter(&conn->lock);
325 pdisp = pdu->disp; 325 pdisp = pdu->disp;
326 if (pdisp > PDUDISP_FREE) 326 if (pdisp > PDUDISP_FREE)
327 pdu->flags &= ~PDUF_BUSY; 327 pdu->flags &= ~PDUF_BUSY;
328 mutex_exit(&conn->lock); 328 mutex_exit(&conn->lock);
329 if (pdisp <= PDUDISP_FREE) 329 if (pdisp <= PDUDISP_FREE)
330 free_pdu(pdu); 330 free_pdu(pdu);
331 331
332 mutex_enter(&conn->lock); 332 mutex_enter(&conn->lock);
333 } 333 }
334 334
335 if (!conn->terminating) 335 if (!conn->terminating)
336 cv_wait(&conn->conn_cv, &conn->lock); 336 cv_wait(&conn->conn_cv, &conn->lock);
337 } 337 }
338 mutex_exit(&conn->lock); 338 mutex_exit(&conn->lock);
339 339
340 /* ------------------------------------------------------------------------ 340 /* ------------------------------------------------------------------------
341 * Here this thread takes over cleanup of the terminating connection. 341 * Here this thread takes over cleanup of the terminating connection.
342 * ------------------------------------------------------------------------ 342 * ------------------------------------------------------------------------
343 */ 343 */
344 connection_timeout_stop(conn); 344 connection_timeout_stop(conn);
345 conn->idle_timeout_val = CONNECTION_IDLE_TIMEOUT; 345 conn->idle_timeout_val = CONNECTION_IDLE_TIMEOUT;
346 346
347 fp = conn->sock; 347 fp = conn->sock;
348 348
349 /* 349 /*
350 * We shutdown the socket here to force the receive 350 * We shutdown the socket here to force the receive
351 * thread to wake up 351 * thread to wake up
352 */ 352 */
353 DEBC(conn, 1, ("Closing Socket %p\n", conn->sock)); 353 DEBC(conn, 1, ("Closing Socket %p\n", conn->sock));
354 solock(fp->f_socket); 354 solock(fp->f_socket);
355 soshutdown(fp->f_socket, SHUT_RDWR); 355 soshutdown(fp->f_socket, SHUT_RDWR);
356 sounlock(fp->f_socket); 356 sounlock(fp->f_socket);
357 357
358 /* wake up any non-reassignable waiting CCBs */ 358 /* wake up any non-reassignable waiting CCBs */
359 TAILQ_FOREACH_SAFE(ccb, &conn->ccbs_waiting, chain, nccb) { 359 TAILQ_FOREACH_SAFE(ccb, &conn->ccbs_waiting, chain, nccb) {
360 if (!(ccb->flags & CCBF_REASSIGN) || ccb->pdu_waiting == NULL) { 360 if (!(ccb->flags & CCBF_REASSIGN) || ccb->pdu_waiting == NULL) {
361 DEBC(conn, 1, ("Terminating CCB %p (t=%p)\n", 361 DEBC(conn, 1, ("Terminating CCB %p (t=%p)\n",
362 ccb,&ccb->timeout)); 362 ccb,&ccb->timeout));
363 wake_ccb(ccb, conn->terminating); 363 wake_ccb(ccb, conn->terminating);
364 } else { 364 } else {
365 ccb_timeout_stop(ccb); 365 ccb_timeout_stop(ccb);
366 ccb->num_timeouts = 0; 366 ccb->num_timeouts = 0;
367 } 367 }
368 } 368 }
369 369
370 /* clean out anything left in send queue */ 370 /* clean out anything left in send queue */
371 mutex_enter(&conn->lock); 371 mutex_enter(&conn->lock);
372 while ((pdu = TAILQ_FIRST(&conn->pdus_to_send)) != NULL) { 372 while ((pdu = TAILQ_FIRST(&conn->pdus_to_send)) != NULL) {
373 TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain); 373 TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain);
374 pdu->flags &= ~(PDUF_INQUEUE | PDUF_BUSY); 374 pdu->flags &= ~(PDUF_INQUEUE | PDUF_BUSY);
375 mutex_exit(&conn->lock); 375 mutex_exit(&conn->lock);
376 /* if it's not attached to a waiting CCB, free it */ 376 /* if it's not attached to a waiting CCB, free it */
377 if (pdu->owner == NULL || 377 if (pdu->owner == NULL ||
378 pdu->owner->pdu_waiting != pdu) { 378 pdu->owner->pdu_waiting != pdu) {
379 free_pdu(pdu); 379 free_pdu(pdu);
380 } 380 }
381 mutex_enter(&conn->lock); 381 mutex_enter(&conn->lock);
382 } 382 }
383 mutex_exit(&conn->lock); 383 mutex_exit(&conn->lock);
384 384
385 /* If there's another connection available, transfer pending tasks */ 385 /* If there's another connection available, transfer pending tasks */
386 if (sess->active_connections && 386 if (sess->active_connections &&
387 TAILQ_FIRST(&conn->ccbs_waiting) != NULL) { 387 TAILQ_FIRST(&conn->ccbs_waiting) != NULL) {
388  388
389 reassign_tasks(conn); 389 reassign_tasks(conn);
390 } else if (!conn->destroy && conn->Time2Wait) { 390 } else if (!conn->destroy && conn->Time2Wait) {
391 DEBC(conn, 1, ("Time2Wait\n")); 391 DEBC(conn, 1, ("Time2Wait\n"));
392 kpause("Time2Wait", false, conn->Time2Wait * hz, NULL); 392 kpause("Time2Wait", false, conn->Time2Wait * hz, NULL);
393 DEBC(conn, 1, ("Time2Wait\n")); 393 DEBC(conn, 1, ("Time2Wait\n"));
394 } 394 }
395 /* notify event handlers of connection shutdown */ 395 /* notify event handlers of connection shutdown */
396 DEBC(conn, 1, ("%s\n", (conn->destroy) ? "TERMINATED" : "RECOVER")); 396 DEBC(conn, 1, ("%s\n", (conn->destroy) ? "TERMINATED" : "RECOVER"));
397 add_event((conn->destroy) ? ISCSI_CONNECTION_TERMINATED 397 add_event((conn->destroy) ? ISCSI_CONNECTION_TERMINATED
398 : ISCSI_RECOVER_CONNECTION, 398 : ISCSI_RECOVER_CONNECTION,
399 sess->id, conn->id, conn->terminating); 399 sess->id, conn->id, conn->terminating);
400 400
401 DEBC(conn, 1, ("Waiting for conn_idle\n")); 401 DEBC(conn, 1, ("Waiting for conn_idle\n"));
402 mutex_enter(&conn->lock); 402 mutex_enter(&conn->lock);
403 if (!conn->destroy) 403 if (!conn->destroy)
404 cv_timedwait(&conn->idle_cv, &conn->lock, CONNECTION_IDLE_TIMEOUT); 404 cv_timedwait(&conn->idle_cv, &conn->lock, CONNECTION_IDLE_TIMEOUT);
405 mutex_exit(&conn->lock); 405 mutex_exit(&conn->lock);
406 DEBC(conn, 1, ("Waited for conn_idle, destroy = %d\n", conn->destroy)); 406 DEBC(conn, 1, ("Waited for conn_idle, destroy = %d\n", conn->destroy));
407 407
408 } while (!conn->destroy); 408 } while (!conn->destroy);
409 409
410 /* wake up anyone waiting for a PDU */ 410 /* wake up anyone waiting for a PDU */
411 mutex_enter(&conn->lock); 411 mutex_enter(&conn->lock);
412 cv_broadcast(&conn->conn_cv); 412 cv_broadcast(&conn->conn_cv);
413 mutex_exit(&conn->lock); 413 mutex_exit(&conn->lock);
414 414
415 /* wake up any waiting CCBs */ 415 /* wake up any waiting CCBs */
416 while ((ccb = TAILQ_FIRST(&conn->ccbs_waiting)) != NULL) { 416 while ((ccb = TAILQ_FIRST(&conn->ccbs_waiting)) != NULL) {
417 KASSERT(ccb->disp >= CCBDISP_NOWAIT); 417 KASSERT(ccb->disp >= CCBDISP_NOWAIT);
418 wake_ccb(ccb, conn->terminating); 418 wake_ccb(ccb, conn->terminating);
419 /* NOTE: wake_ccb will remove the CCB from the queue */ 419 /* NOTE: wake_ccb will remove the CCB from the queue */
420 } 420 }
421 421
422 add_connection_cleanup(conn); 422 add_connection_cleanup(conn);
423 423
424 conn->sendproc = NULL; 424 conn->sendproc = NULL;
425 DEBC(conn, 1, ("Send thread exits\n")); 425 DEBC(conn, 1, ("Send thread exits\n"));
426 iscsi_num_send_threads--; 426 iscsi_num_send_threads--;
427 kthread_exit(0); 427 kthread_exit(0);
428} 428}
429 429
430 430
431/* 431/*
432 * send_pdu: 432 * send_pdu:
433 * Enqueue a PDU to be sent, and handle its disposition as well as 433 * Enqueue a PDU to be sent, and handle its disposition as well as
434 * the disposition of its associated CCB. 434 * the disposition of its associated CCB.
435 * 435 *
436 * Parameter: 436 * Parameter:
437 * ccb The associated CCB. May be NULL if cdisp is CCBDISP_NOWAIT 437 * ccb The associated CCB. May be NULL if cdisp is CCBDISP_NOWAIT
438 * and pdisp is not PDUDISP_WAIT 438 * and pdisp is not PDUDISP_WAIT
439 * cdisp The CCB's disposition 439 * cdisp The CCB's disposition
440 * pdu The PDU 440 * pdu The PDU
441 * pdisp The PDU's disposition 441 * pdisp The PDU's disposition
442 */ 442 */
443 443
444STATIC void 444STATIC void
445send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_disp_t cdisp, pdu_disp_t pdisp) 445send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_disp_t cdisp, pdu_disp_t pdisp)
446{ 446{
447 connection_t *conn = pdu->connection; 447 connection_t *conn = pdu->connection;
448 ccb_disp_t prev_cdisp = 0; 448 ccb_disp_t prev_cdisp = 0;
449 449
450 if (ccb != NULL) { 450 if (ccb != NULL) {
451 prev_cdisp = ccb->disp; 451 prev_cdisp = ccb->disp;
452 pdu->pdu.InitiatorTaskTag = ccb->ITT; 452 pdu->pdu.InitiatorTaskTag = ccb->ITT;
453 pdu->owner = ccb; 453 pdu->owner = ccb;
454 if (cdisp != CCBDISP_NOWAIT) 454 if (cdisp != CCBDISP_NOWAIT)
455 ccb->disp = cdisp; 455 ccb->disp = cdisp;
456 } 456 }
457 457
458 pdu->disp = pdisp; 458 pdu->disp = pdisp;
459 459
460 DEBC(conn, 10, ("Send_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n", 460 DEBC(conn, 10, ("Send_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n",
461 ntohl(pdu->pdu.p.command.CmdSN), 461 ntohl(pdu->pdu.p.command.CmdSN),
462 conn->StatSN_buf.ExpSN, 462 conn->StatSN_buf.ExpSN,
463 ccb, pdu)); 463 ccb, pdu));
464 464
465 mutex_enter(&conn->lock); 465 mutex_enter(&conn->lock);
466 if (pdisp == PDUDISP_WAIT) { 466 if (pdisp == PDUDISP_WAIT) {
467 KASSERT(ccb != NULL); 467 KASSERT(ccb != NULL);
468 468
469 ccb->pdu_waiting = pdu; 469 ccb->pdu_waiting = pdu;
470 470
471 /* save UIO and IOVEC for retransmit */ 471 /* save UIO and IOVEC for retransmit */
472 pdu->save_uio = pdu->uio; 472 pdu->save_uio = pdu->uio;
473 memcpy(pdu->save_iovec, pdu->io_vec, sizeof(pdu->save_iovec)); 473 memcpy(pdu->save_iovec, pdu->io_vec, sizeof(pdu->save_iovec));
474 474
475 pdu->flags |= PDUF_BUSY; 475 pdu->flags |= PDUF_BUSY;
476 } 476 }
477 /* Enqueue for sending */ 477 /* Enqueue for sending */
478 pdu->flags |= PDUF_INQUEUE; 478 pdu->flags |= PDUF_INQUEUE;
479 479
480 if (pdu->flags & PDUF_PRIORITY) 480 if (pdu->flags & PDUF_PRIORITY)
481 TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain); 481 TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain);
482 else 482 else
483 TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain); 483 TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain);
484 484
485 cv_broadcast(&conn->conn_cv); 485 cv_broadcast(&conn->conn_cv);
486 486
487 if (cdisp != CCBDISP_NOWAIT) { 487 if (cdisp != CCBDISP_NOWAIT) {
488 KASSERT(ccb != NULL); 488 KASSERT(ccb != NULL);
489 KASSERTMSG(ccb->connection == conn, "conn mismatch %p != %p\n", ccb->connection, conn); 489 KASSERTMSG(ccb->connection == conn, "conn mismatch %p != %p\n", ccb->connection, conn);
490 490
491 if (prev_cdisp <= CCBDISP_NOWAIT) 491 if (prev_cdisp <= CCBDISP_NOWAIT)
492 suspend_ccb(ccb, TRUE); 492 suspend_ccb(ccb, TRUE);
493 493
494 mutex_exit(&conn->lock); 494 mutex_exit(&conn->lock);
495 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 495 ccb_timeout_start(ccb, COMMAND_TIMEOUT);
496 mutex_enter(&conn->lock); 496 mutex_enter(&conn->lock);
497 497
498 while (ccb->disp == CCBDISP_WAIT) { 498 while (ccb->disp == CCBDISP_WAIT) {
499 DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d waiting\n", 499 DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d waiting\n",
500 ccb, ccb->disp)); 500 ccb, ccb->disp));
501 cv_wait(&conn->ccb_cv, &conn->lock); 501 cv_wait(&conn->ccb_cv, &conn->lock);
502 DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d returned\n", 502 DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d returned\n",
503 ccb, ccb->disp)); 503 ccb, ccb->disp));
504 } 504 }
505 } 505 }
506 506
507 mutex_exit(&conn->lock); 507 mutex_exit(&conn->lock);
508} 508}
509 509
510 510
511/* 511/*
512 * resend_pdu: 512 * resend_pdu:
513 * Re-Enqueue a PDU that has apparently gotten lost. 513 * Re-Enqueue a PDU that has apparently gotten lost.
514 * 514 *
515 * Parameter: 515 * Parameter:
516 * ccb The associated CCB. 516 * ccb The associated CCB.
517 */ 517 */
518 518
519void 519void
520resend_pdu(ccb_t *ccb) 520resend_pdu(ccb_t *ccb)
521{ 521{
522 connection_t *conn = ccb->connection; 522 connection_t *conn = ccb->connection;
523 pdu_t *pdu = ccb->pdu_waiting; 523 pdu_t *pdu = ccb->pdu_waiting;
524 524
525 mutex_enter(&conn->lock); 525 mutex_enter(&conn->lock);
526 if (pdu == NULL || (pdu->flags & PDUF_BUSY)) { 526 if (pdu == NULL || (pdu->flags & PDUF_BUSY)) {
527 mutex_exit(&conn->lock); 527 mutex_exit(&conn->lock);
528 return; 528 return;
529 } 529 }
530 pdu->flags |= PDUF_BUSY; 530 pdu->flags |= PDUF_BUSY;
531 mutex_exit(&conn->lock); 531 mutex_exit(&conn->lock);
532 532
533 /* restore UIO and IOVEC */ 533 /* restore UIO and IOVEC */
534 pdu->uio = pdu->save_uio; 534 pdu->uio = pdu->save_uio;
535 memcpy(pdu->io_vec, pdu->save_iovec, sizeof(pdu->io_vec)); 535 memcpy(pdu->io_vec, pdu->save_iovec, sizeof(pdu->io_vec));
536 536
537 DEBC(conn, 8, ("ReSend_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n", 537 DEBC(conn, 8, ("ReSend_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n",
538 ntohl(pdu->pdu.p.command.CmdSN), 538 ntohl(pdu->pdu.p.command.CmdSN),
539 conn->StatSN_buf.ExpSN, 539 conn->StatSN_buf.ExpSN,
540 ccb, pdu)); 540 ccb, pdu));
541 541
542 mutex_enter(&conn->lock); 542 mutex_enter(&conn->lock);
543 /* Enqueue for sending */ 543 /* Enqueue for sending */
544 pdu->flags |= PDUF_INQUEUE; 544 pdu->flags |= PDUF_INQUEUE;
545 545
546 if (pdu->flags & PDUF_PRIORITY) { 546 if (pdu->flags & PDUF_PRIORITY) {
547 TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain); 547 TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain);
548 } else { 548 } else {
549 TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain); 549 TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain);
550 } 550 }
551 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 551 ccb_timeout_start(ccb, COMMAND_TIMEOUT);
552 cv_broadcast(&conn->conn_cv); 552 cv_broadcast(&conn->conn_cv);
553 mutex_exit(&conn->lock); 553 mutex_exit(&conn->lock);
554} 554}
555 555
556 556
557/* 557/*
558 * setup_tx_uio: 558 * setup_tx_uio:
559 * Initialize the uio structure for sending, including header, 559 * Initialize the uio structure for sending, including header,
560 * data (if present), padding, and Data Digest. 560 * data (if present), padding, and Data Digest.
561 * Header Digest is generated in send thread. 561 * Header Digest is generated in send thread.
562 * 562 *
563 * Parameter: 563 * Parameter:
564 * pdu The PDU 564 * pdu The PDU
565 * dsl The Data Segment Length 565 * dsl The Data Segment Length
566 * data The data pointer 566 * data The data pointer
567 * read TRUE if this is a read operation 567 * read TRUE if this is a read operation
568 */ 568 */
569 569
570STATIC void 570STATIC void
571setup_tx_uio(pdu_t *pdu, uint32_t dsl, void *data, bool read) 571setup_tx_uio(pdu_t *pdu, uint32_t dsl, void *data, bool read)
572{ 572{
573 static uint8_t pad_bytes[4] = { 0 }; 573 static uint8_t pad_bytes[4] = { 0 };
574 struct uio *uio; 574 struct uio *uio;
575 int i, pad, hlen; 575 int i, pad, hlen;
576 connection_t *conn = pdu->connection; 576 connection_t *conn = pdu->connection;
577 577
578 DEB(99, ("SetupTxUio: dlen = %d, dptr: %p, read: %d\n", 578 DEB(99, ("SetupTxUio: dlen = %d, dptr: %p, read: %d\n",
579 dsl, data, read)); 579 dsl, data, read));
580 580
581 if (!read && dsl) { 581 if (!read && dsl) {
582 hton3(dsl, pdu->pdu.DataSegmentLength); 582 hton3(dsl, pdu->pdu.DataSegmentLength);
583 } 583 }
584 hlen = (conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE; 584 hlen = (conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE;
585 585
586 pdu->io_vec[0].iov_base = &pdu->pdu; 586 pdu->io_vec[0].iov_base = &pdu->pdu;
587 pdu->io_vec[0].iov_len = hlen; 587 pdu->io_vec[0].iov_len = hlen;
588 588
589 uio = &pdu->uio; 589 uio = &pdu->uio;
590 590
591 uio->uio_iov = pdu->io_vec; 591 uio->uio_iov = pdu->io_vec;
592 uio->uio_iovcnt = 1; 592 uio->uio_iovcnt = 1;
593 uio->uio_rw = UIO_WRITE; 593 uio->uio_rw = UIO_WRITE;
594 uio->uio_resid = hlen; 594 uio->uio_resid = hlen;
595 UIO_SETUP_SYSSPACE(uio); 595 UIO_SETUP_SYSSPACE(uio);
596 596
597 if (!read && dsl) { 597 if (!read && dsl) {
598 uio->uio_iovcnt++; 598 uio->uio_iovcnt++;
599 pdu->io_vec[1].iov_base = data; 599 pdu->io_vec[1].iov_base = data;
600 pdu->io_vec[1].iov_len = dsl; 600 pdu->io_vec[1].iov_len = dsl;
601 uio->uio_resid += dsl; 601 uio->uio_resid += dsl;
602 602
603 /* Pad to next multiple of 4 */ 603 /* Pad to next multiple of 4 */
604 pad = uio->uio_resid & 0x03; 604 pad = uio->uio_resid & 0x03;
605 if (pad) { 605 if (pad) {
606 i = uio->uio_iovcnt++; 606 i = uio->uio_iovcnt++;
607 pad = 4 - pad; 607 pad = 4 - pad;
608 pdu->io_vec[i].iov_base = pad_bytes; 608 pdu->io_vec[i].iov_base = pad_bytes;
609 pdu->io_vec[i].iov_len = pad; 609 pdu->io_vec[i].iov_len = pad;
610 uio->uio_resid += pad; 610 uio->uio_resid += pad;
611 } 611 }
612 612
613 if (conn->DataDigest) { 613 if (conn->DataDigest) {
614 pdu->data_digest = gen_digest_2(data, dsl, pad_bytes, pad); 614 pdu->data_digest = gen_digest_2(data, dsl, pad_bytes, pad);
615 i = uio->uio_iovcnt++; 615 i = uio->uio_iovcnt++;
616 pdu->io_vec[i].iov_base = &pdu->data_digest; 616 pdu->io_vec[i].iov_base = &pdu->data_digest;
617 pdu->io_vec[i].iov_len = 4; 617 pdu->io_vec[i].iov_len = 4;
618 uio->uio_resid += 4; 618 uio->uio_resid += 4;
619 } 619 }
620 } 620 }
621} 621}
622 622
623/* 623/*
624 * init_login_pdu: 624 * init_login_pdu:
625 * Initialize the login PDU. 625 * Initialize the login PDU.
626 * 626 *
627 * Parameter: 627 * Parameter:
628 * conn The connection 628 * conn The connection
629 * ccb The CCB 629 * ccb The CCB
630 * pdu The PDU 630 * pdu The PDU
631 */ 631 */
632 632
633STATIC void 633STATIC void
634init_login_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, bool next) 634init_login_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, bool next)
635{ 635{
636 pdu_header_t *pdu = &ppdu->pdu; 636 pdu_header_t *pdu = &ppdu->pdu;
637 login_isid_t *isid = (login_isid_t *) & pdu->LUN; 637 login_isid_t *isid = (login_isid_t *) & pdu->LUN;
638 uint8_t c_phase; 638 uint8_t c_phase;
639 639
640 pdu->Opcode = IOP_Login_Request | OP_IMMEDIATE; 640 pdu->Opcode = IOP_Login_Request | OP_IMMEDIATE;
641 641
642 mutex_enter(&conn->session->lock); 642 mutex_enter(&conn->session->lock);
643 ccb->CmdSN = get_sernum(conn->session, ppdu); 643 ccb->CmdSN = get_sernum(conn->session, ppdu);
644 mutex_exit(&conn->session->lock); 644 mutex_exit(&conn->session->lock);
645 645
646 if (next) { 646 if (next) {
647 c_phase = (pdu->Flags >> CSG_SHIFT) & SG_MASK; 647 c_phase = (pdu->Flags >> CSG_SHIFT) & SG_MASK;
648 pdu->Flags = FLAG_TRANSIT | (c_phase << CSG_SHIFT) | 648 pdu->Flags = FLAG_TRANSIT | (c_phase << CSG_SHIFT) |
649 NEXT_PHASE(c_phase); 649 NEXT_PHASE(c_phase);
650 } 650 }
651 651
652 memcpy(isid, &iscsi_InitiatorISID, 6); 652 memcpy(isid, &iscsi_InitiatorISID, 6);
653 isid->TSIH = conn->session->TSIH; 653 isid->TSIH = conn->session->TSIH;
654 654
655 pdu->p.login_req.CID = htons(conn->id); 655 pdu->p.login_req.CID = htons(conn->id);
656 pdu->p.login_req.CmdSN = htonl(ccb->CmdSN); 656 pdu->p.login_req.CmdSN = htonl(ccb->CmdSN);
657} 657}
658 658
659 659
660/* 660/*
661 * negotiate_login: 661 * negotiate_login:
662 * Control login negotiation. 662 * Control login negotiation.
663 * 663 *
664 * Parameter: 664 * Parameter:
665 * conn The connection 665 * conn The connection
666 * rx_pdu The received login response PDU 666 * rx_pdu The received login response PDU
667 * tx_ccb The originally sent login CCB 667 * tx_ccb The originally sent login CCB
668 */ 668 */
669 669
670void 670void
671negotiate_login(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 671negotiate_login(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb)
672{ 672{
673 int rc; 673 int rc;
674 bool next = TRUE; 674 bool next = TRUE;
675 pdu_t *tx_pdu; 675 pdu_t *tx_pdu;
676 uint8_t c_phase; 676 uint8_t c_phase;
677 677
678 if (rx_pdu->pdu.Flags & FLAG_TRANSIT) 678 if (rx_pdu->pdu.Flags & FLAG_TRANSIT)
679 c_phase = rx_pdu->pdu.Flags & SG_MASK; 679 c_phase = rx_pdu->pdu.Flags & SG_MASK;
680 else 680 else
681 c_phase = (rx_pdu->pdu.Flags >> CSG_SHIFT) & SG_MASK; 681 c_phase = (rx_pdu->pdu.Flags >> CSG_SHIFT) & SG_MASK;
682 682
683 DEB(99, ("NegotiateLogin: Flags=%x Phase=%x\n", 683 DEB(99, ("NegotiateLogin: Flags=%x Phase=%x\n",
684 rx_pdu->pdu.Flags, c_phase)); 684 rx_pdu->pdu.Flags, c_phase));
685 685
686 if (c_phase == SG_FULL_FEATURE_PHASE) { 686 if (c_phase == SG_FULL_FEATURE_PHASE) {
687 session_t *sess = conn->session; 687 session_t *sess = conn->session;
688 688
689 if (!sess->TSIH) 689 if (!sess->TSIH)
690 sess->TSIH = ((login_isid_t *) &rx_pdu->pdu.LUN)->TSIH; 690 sess->TSIH = ((login_isid_t *) &rx_pdu->pdu.LUN)->TSIH;
691 691
692 if (rx_pdu->temp_data != NULL) 692 if (rx_pdu->temp_data != NULL)
693 assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, NULL); 693 assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, NULL);
694 694
695 /* negotiated values are now valid */ 695 /* negotiated values are now valid */
696 set_negotiated_parameters(tx_ccb); 696 set_negotiated_parameters(tx_ccb);
697 697
698 DEBC(conn, 5, ("Login Successful!\n")); 698 DEBC(conn, 5, ("Login Successful!\n"));
699 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 699 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS);
700 return; 700 return;
701 } 701 }
702 702
703 tx_pdu = get_pdu(conn, TRUE); 703 tx_pdu = get_pdu(conn, TRUE);
704 if (tx_pdu == NULL) 704 if (tx_pdu == NULL)
705 return; 705 return;
706 706
707 tx_pdu->pdu.Flags = c_phase << CSG_SHIFT; 707 tx_pdu->pdu.Flags = c_phase << CSG_SHIFT;
708 708
709 switch (c_phase) { 709 switch (c_phase) {
710 case SG_SECURITY_NEGOTIATION: 710 case SG_SECURITY_NEGOTIATION:
711 rc = assemble_security_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 711 rc = assemble_security_parameters(conn, tx_ccb, rx_pdu, tx_pdu);
712 if (rc < 0) 712 if (rc < 0)
713 next = FALSE; 713 next = FALSE;
714 break; 714 break;
715 715
716 case SG_LOGIN_OPERATIONAL_NEGOTIATION: 716 case SG_LOGIN_OPERATIONAL_NEGOTIATION:
717 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 717 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu);
718 break; 718 break;
719 719
720 default: 720 default:
721 DEBOUT(("Invalid phase %x in negotiate_login\n", c_phase)); 721 DEBOUT(("Invalid phase %x in negotiate_login\n", c_phase));
722 rc = ISCSI_STATUS_TARGET_ERROR; 722 rc = ISCSI_STATUS_TARGET_ERROR;
723 break; 723 break;
724 } 724 }
725 725
726 if (rc > 0) { 726 if (rc > 0) {
727 wake_ccb(tx_ccb, rc); 727 wake_ccb(tx_ccb, rc);
728 free_pdu(tx_pdu); 728 free_pdu(tx_pdu);
729 } else { 729 } else {
730 init_login_pdu(conn, tx_ccb, tx_pdu, next); 730 init_login_pdu(conn, tx_ccb, tx_pdu, next);
731 setup_tx_uio(tx_pdu, tx_pdu->temp_data_len, tx_pdu->temp_data, FALSE); 731 setup_tx_uio(tx_pdu, tx_pdu->temp_data_len, tx_pdu->temp_data, FALSE);
732 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 732 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE);
733 } 733 }
734} 734}
735 735
736 736
737/* 737/*
738 * init_text_pdu: 738 * init_text_pdu:
739 * Initialize the text PDU. 739 * Initialize the text PDU.
740 * 740 *
741 * Parameter: 741 * Parameter:
742 * conn The connection 742 * conn The connection
743 * ccb The transmit CCB 743 * ccb The transmit CCB
744 * ppdu The transmit PDU 744 * ppdu The transmit PDU
745 * rx_pdu The received PDU if this is an unsolicited negotiation 745 * rx_pdu The received PDU if this is an unsolicited negotiation
746 */ 746 */
747 747
748STATIC void 748STATIC void
749init_text_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, pdu_t *rx_pdu) 749init_text_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, pdu_t *rx_pdu)
750{ 750{
751 pdu_header_t *pdu = &ppdu->pdu; 751 pdu_header_t *pdu = &ppdu->pdu;
752 752
753 pdu->Opcode = IOP_Text_Request | OP_IMMEDIATE; 753 pdu->Opcode = IOP_Text_Request | OP_IMMEDIATE;
754 pdu->Flags = FLAG_FINAL; 754 pdu->Flags = FLAG_FINAL;
755 755
756 mutex_enter(&conn->session->lock); 756 mutex_enter(&conn->session->lock);
757 ccb->CmdSN = get_sernum(conn->session, ppdu); 757 ccb->CmdSN = get_sernum(conn->session, ppdu);
758 mutex_exit(&conn->session->lock); 758 mutex_exit(&conn->session->lock);
759 759
760 if (rx_pdu != NULL) { 760 if (rx_pdu != NULL) {
761 pdu->p.text_req.TargetTransferTag = 761 pdu->p.text_req.TargetTransferTag =
762 rx_pdu->pdu.p.text_rsp.TargetTransferTag; 762 rx_pdu->pdu.p.text_rsp.TargetTransferTag;
763 pdu->LUN = rx_pdu->pdu.LUN; 763 pdu->LUN = rx_pdu->pdu.LUN;
764 } else 764 } else
765 pdu->p.text_req.TargetTransferTag = 0xffffffff; 765 pdu->p.text_req.TargetTransferTag = 0xffffffff;
766 766
767 pdu->p.text_req.CmdSN = htonl(ccb->CmdSN); 767 pdu->p.text_req.CmdSN = htonl(ccb->CmdSN);
768} 768}
769 769
770 770
771/* 771/*
772 * acknowledge_text: 772 * acknowledge_text:
773 * Acknowledge a continued login or text response. 773 * Acknowledge a continued login or text response.
774 * 774 *
775 * Parameter: 775 * Parameter:
776 * conn The connection 776 * conn The connection
777 * rx_pdu The received login/text response PDU 777 * rx_pdu The received login/text response PDU
778 * tx_ccb The originally sent login/text request CCB 778 * tx_ccb The originally sent login/text request CCB
779 */ 779 */
780 780
781void 781void
782acknowledge_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 782acknowledge_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb)
783{ 783{
784 pdu_t *tx_pdu; 784 pdu_t *tx_pdu;
785 785
786 tx_pdu = get_pdu(conn, TRUE); 786 tx_pdu = get_pdu(conn, TRUE);
787 if (tx_pdu == NULL) 787 if (tx_pdu == NULL)
788 return; 788 return;
789 789
790 if (rx_pdu != NULL && 790 if (rx_pdu != NULL &&
791 (rx_pdu->pdu.Opcode & OPCODE_MASK) == IOP_Login_Request) 791 (rx_pdu->pdu.Opcode & OPCODE_MASK) == IOP_Login_Request)
792 init_login_pdu(conn, tx_ccb, tx_pdu, FALSE); 792 init_login_pdu(conn, tx_ccb, tx_pdu, FALSE);
793 else 793 else
794 init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu); 794 init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu);
795 795
796 setup_tx_uio(tx_pdu, 0, NULL, FALSE); 796 setup_tx_uio(tx_pdu, 0, NULL, FALSE);
797 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 797 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE);
798} 798}
799 799
800 800
801/* 801/*
802 * start_text_negotiation: 802 * start_text_negotiation:
803 * Handle target request to negotiate (via asynch event) 803 * Handle target request to negotiate (via asynch event)
804 * 804 *
805 * Parameter: 805 * Parameter:
806 * conn The connection 806 * conn The connection
807 */ 807 */
808 808
809void 809void
810start_text_negotiation(connection_t *conn) 810start_text_negotiation(connection_t *conn)
811{ 811{
812 pdu_t *pdu; 812 pdu_t *pdu;
813 ccb_t *ccb; 813 ccb_t *ccb;
814 814
815 ccb = get_ccb(conn, TRUE); 815 ccb = get_ccb(conn, TRUE);
816 if (ccb == NULL) 816 if (ccb == NULL)
817 return; 817 return;
818 pdu = get_pdu(conn, TRUE); 818 pdu = get_pdu(conn, TRUE);
819 if (pdu == NULL) { 819 if (pdu == NULL) {
820 free_ccb(ccb); 820 free_ccb(ccb);
821 return; 821 return;
822 } 822 }
823 823
824 if (init_text_parameters(conn, ccb)) { 824 if (init_text_parameters(conn, ccb)) {
825 free_ccb(ccb); 825 free_ccb(ccb);
826 free_pdu(pdu); 826 free_pdu(pdu);
827 return; 827 return;
828 } 828 }
829 829
830 init_text_pdu(conn, ccb, pdu, NULL); 830 init_text_pdu(conn, ccb, pdu, NULL);
831 setup_tx_uio(pdu, 0, NULL, FALSE); 831 setup_tx_uio(pdu, 0, NULL, FALSE);
832 send_pdu(ccb, pdu, CCBDISP_FREE, PDUDISP_WAIT); 832 send_pdu(ccb, pdu, CCBDISP_FREE, PDUDISP_WAIT);
833} 833}
834 834
835 835
836/* 836/*
837 * negotiate_text: 837 * negotiate_text:
838 * Handle received text negotiation. 838 * Handle received text negotiation.
839 * 839 *
840 * Parameter: 840 * Parameter:
841 * conn The connection 841 * conn The connection
842 * rx_pdu The received text response PDU 842 * rx_pdu The received text response PDU
843 * tx_ccb The original CCB 843 * tx_ccb The original CCB
844 */ 844 */
845 845
846void 846void
847negotiate_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 847negotiate_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb)
848{ 848{
849 int rc; 849 int rc;
850 pdu_t *tx_pdu; 850 pdu_t *tx_pdu;
851 851
852 if (tx_ccb->flags & CCBF_SENDTARGET) { 852 if (tx_ccb->flags & CCBF_SENDTARGET) {
853 if (!(rx_pdu->pdu.Flags & FLAG_FINAL)) { 853 if (!(rx_pdu->pdu.Flags & FLAG_FINAL)) {
854 handle_connection_error(conn, ISCSI_STATUS_PROTOCOL_ERROR, 854 handle_connection_error(conn, ISCSI_STATUS_PROTOCOL_ERROR,
855 LOGOUT_CONNECTION); 855 LOGOUT_CONNECTION);
856 return; 856 return;
857 } 857 }
858 /* transfer ownership of text to CCB */ 858 /* transfer ownership of text to CCB */
859 tx_ccb->text_data = rx_pdu->temp_data; 859 tx_ccb->text_data = rx_pdu->temp_data;
860 tx_ccb->text_len = rx_pdu->temp_data_len; 860 tx_ccb->text_len = rx_pdu->temp_data_len;
861 rx_pdu->temp_data = NULL; 861 rx_pdu->temp_data = NULL;
862 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 862 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS);
863 } else { 863 } else {
864 if (!(rx_pdu->pdu.Flags & FLAG_FINAL)) 864 if (!(rx_pdu->pdu.Flags & FLAG_FINAL))
865 tx_pdu = get_pdu(conn, TRUE); 865 tx_pdu = get_pdu(conn, TRUE);
866 else 866 else
867 tx_pdu = NULL; 867 tx_pdu = NULL;
868 868
869 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 869 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu);
870 if (rc) { 870 if (rc) {
871 if (tx_pdu != NULL) 871 if (tx_pdu != NULL)
872 free_pdu(tx_pdu); 872 free_pdu(tx_pdu);
873 873
874 handle_connection_error(conn, rc, LOGOUT_CONNECTION); 874 handle_connection_error(conn, rc, LOGOUT_CONNECTION);
875 } else if (tx_pdu != NULL) { 875 } else if (tx_pdu != NULL) {
876 init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu); 876 init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu);
877 setup_tx_uio(tx_pdu, tx_pdu->temp_data_len, 877 setup_tx_uio(tx_pdu, tx_pdu->temp_data_len,
878 tx_pdu->temp_data, FALSE); 878 tx_pdu->temp_data, FALSE);
879 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 879 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE);
880 } else { 880 } else {
881 set_negotiated_parameters(tx_ccb); 881 set_negotiated_parameters(tx_ccb);
882 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 882 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS);
883 } 883 }
884 } 884 }
885} 885}
886 886
887 887
888/* 888/*
889 * send_send_targets: 889 * send_send_targets:
890 * Send out a SendTargets text request. 890 * Send out a SendTargets text request.
891 * The result is stored in the fields in the session structure. 891 * The result is stored in the fields in the session structure.
892 * 892 *
893 * Parameter: 893 * Parameter:
894 * session The session 894 * session The session
895 * key The text key to use 895 * key The text key to use
896 * 896 *
897 * Returns: 0 on success, else an error code. 897 * Returns: 0 on success, else an error code.
898 */ 898 */
899 899
900int 900int
901send_send_targets(session_t *session, uint8_t *key) 901send_send_targets(session_t *session, uint8_t *key)
902{ 902{
903 ccb_t *ccb; 903 ccb_t *ccb;
904 pdu_t *pdu; 904 pdu_t *pdu;
905 int rc = 0; 905 int rc = 0;
906 connection_t *conn; 906 connection_t *conn;
907 907
908 DEB(9, ("Send_send_targets\n")); 908 DEB(9, ("Send_send_targets\n"));
909 909
910 conn = assign_connection(session, TRUE); 910 conn = assign_connection(session, TRUE);
911 if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) 911 if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE)
912 return (conn != NULL && conn->terminating) ? conn->terminating 912 return (conn != NULL && conn->terminating) ? conn->terminating
913 : ISCSI_STATUS_CONNECTION_FAILED; 913 : ISCSI_STATUS_CONNECTION_FAILED;
914 914
915 ccb = get_ccb(conn, TRUE); 915 ccb = get_ccb(conn, TRUE);
916 if (ccb == NULL) 916 if (ccb == NULL)
917 return conn->terminating; 917 return conn->terminating;
918 pdu = get_pdu(conn, TRUE); 918 pdu = get_pdu(conn, TRUE);
919 if (pdu == NULL) { 919 if (pdu == NULL) {
920 free_ccb(ccb); 920 free_ccb(ccb);
921 return conn->terminating; 921 return conn->terminating;
922 } 922 }
923 923
924 ccb->flags |= CCBF_SENDTARGET; 924 ccb->flags |= CCBF_SENDTARGET;
925 925
926 if ((rc = assemble_send_targets(pdu, key)) != 0) { 926 if ((rc = assemble_send_targets(pdu, key)) != 0) {
927 free_ccb(ccb); 927 free_ccb(ccb);
928 free_pdu(pdu); 928 free_pdu(pdu);
929 return rc; 929 return rc;
930 } 930 }
931 931
932 init_text_pdu(conn, ccb, pdu, NULL); 932 init_text_pdu(conn, ccb, pdu, NULL);
933 933
934 setup_tx_uio(pdu, pdu->temp_data_len, pdu->temp_data, FALSE); 934 setup_tx_uio(pdu, pdu->temp_data_len, pdu->temp_data, FALSE);
935 send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_WAIT); 935 send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_WAIT);
936 936
937 rc = ccb->status; 937 rc = ccb->status;
938 if (!rc) { 938 if (!rc) {
939 /* transfer ownership of data */ 939 /* transfer ownership of data */
940 session->target_list = ccb->text_data; 940 session->target_list = ccb->text_data;
941 session->target_list_len = ccb->text_len; 941 session->target_list_len = ccb->text_len;
942 ccb->text_data = NULL; 942 ccb->text_data = NULL;
943 } 943 }
944 free_ccb(ccb); 944 free_ccb(ccb);
945 return rc; 945 return rc;
946} 946}
947 947
948 948
949/* 949/*
950 * send_nop_out: 950 * send_nop_out:
951 * Send nop out request. 951 * Send nop out request.
952 * 952 *
953 * Parameter: 953 * Parameter:
954 * conn The connection 954 * conn The connection
955 * rx_pdu The received Nop-In PDU 955 * rx_pdu The received Nop-In PDU
956 * 956 *
957 * Returns: 0 on success, else an error code. 957 * Returns: 0 on success, else an error code.
958 */ 958 */
959 959
960int 960int
961send_nop_out(connection_t *conn, pdu_t *rx_pdu) 961send_nop_out(connection_t *conn, pdu_t *rx_pdu)
962{ 962{
963 session_t *sess; 963 session_t *sess;
964 ccb_t *ccb; 964 ccb_t *ccb;
965 pdu_t *ppdu; 965 pdu_t *ppdu;
966 pdu_header_t *pdu; 966 pdu_header_t *pdu;
967 uint32_t sn; 967 uint32_t sn;
968 968
969 if (rx_pdu != NULL) { 969 if (rx_pdu != NULL) {
970 ccb = NULL; 970 ccb = NULL;
971 ppdu = get_pdu(conn, TRUE); 971 ppdu = get_pdu(conn, TRUE);
972 if (ppdu == NULL) 972 if (ppdu == NULL)
973 return 1; 973 return 1;
974 } else { 974 } else {
975 ccb = get_ccb(conn, FALSE); 975 ccb = get_ccb(conn, FALSE);
976 if (ccb == NULL) { 976 if (ccb == NULL) {
977 DEBOUT(("Can't get CCB in send_nop_out\n")); 977 DEBOUT(("Can't get CCB in send_nop_out\n"));
978 return 1; 978 return 1;
979 } 979 }
980 ppdu = get_pdu(conn, FALSE); 980 ppdu = get_pdu(conn, FALSE);
981 if (ppdu == NULL) { 981 if (ppdu == NULL) {
982 free_ccb(ccb); 982 free_ccb(ccb);
983 DEBOUT(("Can't get PDU in send_nop_out\n")); 983 DEBOUT(("Can't get PDU in send_nop_out\n"));
984 return 1; 984 return 1;
985 } 985 }
986 } 986 }
987 987
988 pdu = &ppdu->pdu; 988 pdu = &ppdu->pdu;
989 pdu->Flags = FLAG_FINAL; 989 pdu->Flags = FLAG_FINAL;
990 pdu->Opcode = IOP_NOP_Out | OP_IMMEDIATE; 990 pdu->Opcode = IOP_NOP_Out | OP_IMMEDIATE;
991 991
992 sess = conn->session; 992 sess = conn->session;
993 993
994 mutex_enter(&sess->lock); 994 mutex_enter(&sess->lock);
995 sn = get_sernum(sess, ppdu); 995 sn = get_sernum(sess, ppdu);
996 mutex_exit(&sess->lock); 996 mutex_exit(&sess->lock);
997 997
998 if (rx_pdu != NULL) { 998 if (rx_pdu != NULL) {
999 pdu->p.nop_out.TargetTransferTag = 999 pdu->p.nop_out.TargetTransferTag =
1000 rx_pdu->pdu.p.nop_in.TargetTransferTag; 1000 rx_pdu->pdu.p.nop_in.TargetTransferTag;
1001 pdu->InitiatorTaskTag = rx_pdu->pdu.InitiatorTaskTag; 1001 pdu->InitiatorTaskTag = rx_pdu->pdu.InitiatorTaskTag;
1002 pdu->p.nop_out.CmdSN = htonl(sn); 1002 pdu->p.nop_out.CmdSN = htonl(sn);
1003 pdu->LUN = rx_pdu->pdu.LUN; 1003 pdu->LUN = rx_pdu->pdu.LUN;
1004 } else { 1004 } else {
1005 pdu->p.nop_out.TargetTransferTag = 0xffffffff; 1005 pdu->p.nop_out.TargetTransferTag = 0xffffffff;
1006 pdu->InitiatorTaskTag = 0xffffffff; 1006 pdu->InitiatorTaskTag = 0xffffffff;
1007 ccb->CmdSN = sn; 1007 ccb->CmdSN = sn;
1008 pdu->p.nop_out.CmdSN = htonl(sn); 1008 pdu->p.nop_out.CmdSN = htonl(sn);
1009 } 1009 }
1010 1010
1011 DEBC(conn, 10, ("Send NOP_Out CmdSN=%d, rx_pdu=%p\n", sn, rx_pdu)); 1011 DEBC(conn, 10, ("Send NOP_Out CmdSN=%d, rx_pdu=%p\n", sn, rx_pdu));
1012 1012
1013 setup_tx_uio(ppdu, 0, NULL, FALSE); 1013 setup_tx_uio(ppdu, 0, NULL, FALSE);
1014 send_pdu(ccb, ppdu, (rx_pdu != NULL) ? CCBDISP_NOWAIT : CCBDISP_FREE, 1014 send_pdu(ccb, ppdu, (rx_pdu != NULL) ? CCBDISP_NOWAIT : CCBDISP_FREE,
1015 PDUDISP_FREE); 1015 PDUDISP_FREE);
1016 return 0; 1016 return 0;
1017} 1017}
1018 1018
1019 1019
1020/* 1020/*
1021 * snack_missing: 1021 * snack_missing:
1022 * Send SNACK request for missing data. 1022 * Send SNACK request for missing data.
1023 * 1023 *
1024 * Parameter: 1024 * Parameter:
1025 * conn The connection 1025 * conn The connection
1026 * ccb The task's CCB (for Data NAK only) 1026 * ccb The task's CCB (for Data NAK only)
1027 * type The SNACK type 1027 * type The SNACK type
1028 * BegRun The BegRun field 1028 * BegRun The BegRun field
1029 * RunLength The RunLength field 1029 * RunLength The RunLength field
1030 */ 1030 */
1031 1031
1032void 1032void
1033snack_missing(connection_t *conn, ccb_t *ccb, uint8_t type, 1033snack_missing(connection_t *conn, ccb_t *ccb, uint8_t type,
1034 uint32_t BegRun, uint32_t RunLength) 1034 uint32_t BegRun, uint32_t RunLength)
1035{ 1035{
1036 pdu_t *ppdu; 1036 pdu_t *ppdu;
1037 pdu_header_t *pdu; 1037 pdu_header_t *pdu;
1038 1038
1039 ppdu = get_pdu(conn, TRUE); 1039 ppdu = get_pdu(conn, TRUE);
1040 if (ppdu == NULL) 1040 if (ppdu == NULL)
1041 return; 1041 return;
1042 pdu = &ppdu->pdu; 1042 pdu = &ppdu->pdu;
1043 pdu->Opcode = IOP_SNACK_Request; 1043 pdu->Opcode = IOP_SNACK_Request;
1044 pdu->Flags = FLAG_FINAL | type; 1044 pdu->Flags = FLAG_FINAL | type;
1045 1045
1046 pdu->InitiatorTaskTag = (type == SNACK_DATA_NAK) ? ccb->ITT : 0xffffffff; 1046 pdu->InitiatorTaskTag = (type == SNACK_DATA_NAK) ? ccb->ITT : 0xffffffff;
1047 pdu->p.snack.TargetTransferTag = 0xffffffff; 1047 pdu->p.snack.TargetTransferTag = 0xffffffff;
1048 pdu->p.snack.BegRun = htonl(BegRun); 1048 pdu->p.snack.BegRun = htonl(BegRun);
1049 pdu->p.snack.RunLength = htonl(RunLength); 1049 pdu->p.snack.RunLength = htonl(RunLength);
1050 1050
1051 ppdu->flags = PDUF_PRIORITY; 1051 ppdu->flags = PDUF_PRIORITY;
1052 1052
1053 setup_tx_uio(ppdu, 0, NULL, FALSE); 1053 setup_tx_uio(ppdu, 0, NULL, FALSE);
1054 send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE); 1054 send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE);
1055} 1055}
1056 1056
1057 1057
1058/* 1058/*
1059 * send_snack: 1059 * send_snack:
1060 * Send SNACK request. 1060 * Send SNACK request.
1061 * 1061 *
1062 * Parameter: 1062 * Parameter:
1063 * conn The connection 1063 * conn The connection
1064 * rx_pdu The received data in PDU 1064 * rx_pdu The received data in PDU
1065 * tx_ccb The original command CCB (required for Data ACK only) 1065 * tx_ccb The original command CCB (required for Data ACK only)
1066 * type The SNACK type 1066 * type The SNACK type
1067 * 1067 *
1068 * Returns: 0 on success, else an error code. 1068 * Returns: 0 on success, else an error code.
1069 */ 1069 */
1070 1070
1071void 1071void
1072send_snack(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb, uint8_t type) 1072send_snack(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb, uint8_t type)
1073{ 1073{
1074 pdu_t *ppdu; 1074 pdu_t *ppdu;
1075 pdu_header_t *pdu; 1075 pdu_header_t *pdu;
1076 1076
1077 ppdu = get_pdu(conn, TRUE); 1077 ppdu = get_pdu(conn, TRUE);
1078 if (ppdu == NULL) 1078 if (ppdu == NULL)
1079 return; 1079 return;
1080 pdu = &ppdu->pdu; 1080 pdu = &ppdu->pdu;
1081 pdu->Opcode = IOP_SNACK_Request; 1081 pdu->Opcode = IOP_SNACK_Request;
1082 pdu->Flags = FLAG_FINAL | type; 1082 pdu->Flags = FLAG_FINAL | type;
1083 1083
1084 switch (type) { 1084 switch (type) {
1085 case SNACK_DATA_NAK: 1085 case SNACK_DATA_NAK:
1086 pdu->InitiatorTaskTag = rx_pdu->pdu.InitiatorTaskTag; 1086 pdu->InitiatorTaskTag = rx_pdu->pdu.InitiatorTaskTag;
1087 pdu->p.snack.TargetTransferTag = 0xffffffff; 1087 pdu->p.snack.TargetTransferTag = 0xffffffff;
1088 pdu->p.snack.BegRun = rx_pdu->pdu.p.data_in.DataSN; 1088 pdu->p.snack.BegRun = rx_pdu->pdu.p.data_in.DataSN;
1089 pdu->p.snack.RunLength = htonl(1); 1089 pdu->p.snack.RunLength = htonl(1);
1090 break; 1090 break;
1091 1091
1092 case SNACK_STATUS_NAK: 1092 case SNACK_STATUS_NAK:
1093 pdu->InitiatorTaskTag = 0xffffffff; 1093 pdu->InitiatorTaskTag = 0xffffffff;
1094 pdu->p.snack.TargetTransferTag = 0xffffffff; 1094 pdu->p.snack.TargetTransferTag = 0xffffffff;
1095 pdu->p.snack.BegRun = rx_pdu->pdu.p.response.StatSN; 1095 pdu->p.snack.BegRun = rx_pdu->pdu.p.response.StatSN;
1096 pdu->p.snack.RunLength = htonl(1); 1096 pdu->p.snack.RunLength = htonl(1);
1097 break; 1097 break;
1098 1098
1099 case SNACK_DATA_ACK: 1099 case SNACK_DATA_ACK:
1100 pdu->InitiatorTaskTag = 0xffffffff; 1100 pdu->InitiatorTaskTag = 0xffffffff;
1101 pdu->p.snack.TargetTransferTag = 1101 pdu->p.snack.TargetTransferTag =
1102 rx_pdu->pdu.p.data_in.TargetTransferTag; 1102 rx_pdu->pdu.p.data_in.TargetTransferTag;
1103 pdu->p.snack.BegRun = tx_ccb->DataSN_buf.ExpSN; 1103 pdu->p.snack.BegRun = tx_ccb->DataSN_buf.ExpSN;
1104 pdu->p.snack.RunLength = 0; 1104 pdu->p.snack.RunLength = 0;
1105 break; 1105 break;
1106 1106
1107 default: 1107 default:
1108 DEBOUT(("Invalid type %d in send_snack\n", type)); 1108 DEBOUT(("Invalid type %d in send_snack\n", type));
1109 return; 1109 return;
1110 } 1110 }
1111 1111
1112 pdu->LUN = rx_pdu->pdu.LUN; 1112 pdu->LUN = rx_pdu->pdu.LUN;
1113 1113
1114 ppdu->flags = PDUF_PRIORITY; 1114 ppdu->flags = PDUF_PRIORITY;
1115 1115
1116 setup_tx_uio(ppdu, 0, NULL, FALSE); 1116 setup_tx_uio(ppdu, 0, NULL, FALSE);
1117 send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE); 1117 send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE);
1118} 1118}
1119 1119
1120 1120
1121/* 1121/*
1122 * send_login: 1122 * send_login:
1123 * Send login request. 1123 * Send login request.
1124 * 1124 *
1125 * Parameter: 1125 * Parameter:
1126 * conn The connection 1126 * conn The connection
1127 * par The login parameters (for negotiation) 1127 * par The login parameters (for negotiation)
1128 * 1128 *
1129 * Returns: 0 on success, else an error code. 1129 * Returns: 0 on success, else an error code.
1130 */ 1130 */
1131 1131
1132int 1132int
1133send_login(connection_t *conn) 1133send_login(connection_t *conn)
1134{ 1134{
1135 ccb_t *ccb; 1135 ccb_t *ccb;
1136 pdu_t *pdu; 1136 pdu_t *pdu;
1137 int rc; 1137 int rc;
1138 1138
1139 DEBC(conn, 9, ("Send_login\n")); 1139 DEBC(conn, 9, ("Send_login\n"));
1140 ccb = get_ccb(conn, TRUE); 1140 ccb = get_ccb(conn, TRUE);
1141 /* only if terminating (which couldn't possibly happen here, but...) */ 1141 /* only if terminating (which couldn't possibly happen here, but...) */
1142 if (ccb == NULL) 1142 if (ccb == NULL)
1143 return conn->terminating; 1143 return conn->terminating;
1144 pdu = get_pdu(conn, TRUE); 1144 pdu = get_pdu(conn, TRUE);
1145 if (pdu == NULL) { 1145 if (pdu == NULL) {
1146 free_ccb(ccb); 1146 free_ccb(ccb);
1147 return conn->terminating; 1147 return conn->terminating;
1148 } 1148 }
1149 1149
1150 if ((rc = assemble_login_parameters(conn, ccb, pdu)) <= 0) { 1150 if ((rc = assemble_login_parameters(conn, ccb, pdu)) <= 0) {
1151 init_login_pdu(conn, ccb, pdu, !rc); 1151 init_login_pdu(conn, ccb, pdu, !rc);
1152 setup_tx_uio(pdu, pdu->temp_data_len, pdu->temp_data, FALSE); 1152 setup_tx_uio(pdu, pdu->temp_data_len, pdu->temp_data, FALSE);
1153 send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_FREE); 1153 send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_FREE);
1154 rc = ccb->status; 1154 rc = ccb->status;
1155 } else { 1155 } else {
1156 free_pdu(pdu); 1156 free_pdu(pdu);
1157 } 1157 }
1158 free_ccb(ccb); 1158 free_ccb(ccb);
1159 return rc; 1159 return rc;
1160} 1160}
1161 1161
1162 1162
1163/* 1163/*
1164 * send_logout: 1164 * send_logout:
1165 * Send logout request. 1165 * Send logout request.
1166 * NOTE: This function does not wait for the logout to complete. 1166 * NOTE: This function does not wait for the logout to complete.
1167 * 1167 *
1168 * Parameter: 1168 * Parameter:
1169 * conn The connection 1169 * conn The connection
1170 * refconn The referenced connection 1170 * refconn The referenced connection
1171 * reason The reason code 1171 * reason The reason code
1172 * wait Wait for completion if TRUE 1172 * wait Wait for completion if TRUE
1173 * 1173 *
1174 * Returns: 0 on success (logout sent), else an error code. 1174 * Returns: 0 on success (logout sent), else an error code.
1175 */ 1175 */
1176 1176
1177int 1177int
1178send_logout(connection_t *conn, connection_t *refconn, int reason, 1178send_logout(connection_t *conn, connection_t *refconn, int reason,
1179 bool wait) 1179 bool wait)
1180{ 1180{
1181 ccb_t *ccb; 1181 ccb_t *ccb;
1182 pdu_t *ppdu; 1182 pdu_t *ppdu;
1183 pdu_header_t *pdu; 1183 pdu_header_t *pdu;
1184 1184
1185 DEBC(conn, 5, ("Send_logout\n")); 1185 DEBC(conn, 5, ("Send_logout\n"));
1186 ccb = get_ccb(conn, TRUE); 1186 ccb = get_ccb(conn, TRUE);
1187 /* can only happen if terminating... */ 1187 /* can only happen if terminating... */
1188 if (ccb == NULL) 1188 if (ccb == NULL)
1189 return conn->terminating; 1189 return conn->terminating;
1190 ppdu = get_pdu(conn, TRUE); 1190 ppdu = get_pdu(conn, TRUE);
1191 if (ppdu == NULL) { 1191 if (ppdu == NULL) {
1192 free_ccb(ccb); 1192 free_ccb(ccb);
1193 return conn->terminating; 1193 return conn->terminating;
1194 } 1194 }
1195 1195
1196 pdu = &ppdu->pdu; 1196 pdu = &ppdu->pdu;
1197 pdu->Opcode = IOP_Logout_Request | OP_IMMEDIATE; 1197 pdu->Opcode = IOP_Logout_Request | OP_IMMEDIATE;
1198 1198
1199 pdu->Flags = FLAG_FINAL | reason; 1199 pdu->Flags = FLAG_FINAL | reason;
1200 ccb->CmdSN = conn->session->CmdSN; 1200 ccb->CmdSN = conn->session->CmdSN;
1201 pdu->p.logout_req.CmdSN = htonl(ccb->CmdSN); 1201 pdu->p.logout_req.CmdSN = htonl(ccb->CmdSN);
1202 if (reason > 0) 1202 if (reason > 0)
1203 pdu->p.logout_req.CID = htons(refconn->id); 1203 pdu->p.logout_req.CID = htons(refconn->id);
1204 1204
1205 ccb->par = refconn; 1205 ccb->par = refconn;
1206 if (refconn != conn) { 1206 if (refconn != conn) {
1207 ccb->flags |= CCBF_OTHERCONN; 1207 ccb->flags |= CCBF_OTHERCONN;
1208 } else { 1208 } else {
1209 conn->state = ST_LOGOUT_SENT; 1209 conn->state = ST_LOGOUT_SENT;
1210 conn->loggedout = LOGOUT_SENT; 1210 conn->loggedout = LOGOUT_SENT;
1211 } 1211 }
1212 1212
1213 setup_tx_uio(ppdu, 0, NULL, FALSE); 1213 setup_tx_uio(ppdu, 0, NULL, FALSE);
1214 send_pdu(ccb, ppdu, (wait) ? CCBDISP_WAIT : CCBDISP_FREE, PDUDISP_FREE); 1214 send_pdu(ccb, ppdu, (wait) ? CCBDISP_WAIT : CCBDISP_FREE, PDUDISP_FREE);
1215 1215
1216 if (wait) { 1216 if (wait) {
1217 int rc = ccb->status; 1217 int rc = ccb->status;
1218 free_ccb (ccb); 1218 free_ccb (ccb);
1219 return rc; 1219 return rc;
1220 } 1220 }
1221 return 0; 1221 return 0;
1222} 1222}
1223 1223
1224 1224
1225/* 1225/*
1226 * send_task_management: 1226 * send_task_management:
1227 * Send task management request. 1227 * Send task management request.
1228 * 1228 *
1229 * Parameter: 1229 * Parameter:
1230 * conn The connection 1230 * conn The connection
1231 * ref_ccb The referenced command (NULL if none) 1231 * ref_ccb The referenced command (NULL if none)
1232 * xs The scsipi command structure (NULL if not a scsipi request) 1232 * xs The scsipi command structure (NULL if not a scsipi request)
1233 * function The function code 1233 * function The function code
1234 * 1234 *
1235 * Returns: 0 on success, else an error code. 1235 * Returns: 0 on success, else an error code.
1236 */ 1236 */
1237 1237
1238int 1238int
1239send_task_management(connection_t *conn, ccb_t *ref_ccb, struct scsipi_xfer *xs, 1239send_task_management(connection_t *conn, ccb_t *ref_ccb, struct scsipi_xfer *xs,
1240 int function) 1240 int function)
1241{ 1241{
1242 ccb_t *ccb; 1242 ccb_t *ccb;
1243 pdu_t *ppdu; 1243 pdu_t *ppdu;
1244 pdu_header_t *pdu; 1244 pdu_header_t *pdu;
1245 1245
1246 DEBC(conn, 5, ("Send_task_management, ref_ccb=%p, func = %d\n", 1246 DEBC(conn, 5, ("Send_task_management, ref_ccb=%p, func = %d\n",
1247 ref_ccb, function)); 1247 ref_ccb, function));
1248 1248
1249 if (function == TASK_REASSIGN && conn->session->ErrorRecoveryLevel < 2) 1249 if (function == TASK_REASSIGN && conn->session->ErrorRecoveryLevel < 2)
1250 return ISCSI_STATUS_CANT_REASSIGN; 1250 return ISCSI_STATUS_CANT_REASSIGN;
1251 1251
1252 ccb = get_ccb(conn, xs == NULL); 1252 ccb = get_ccb(conn, xs == NULL);
1253 /* can only happen if terminating... */ 1253 /* can only happen if terminating... */
1254 if (ccb == NULL) 1254 if (ccb == NULL) {
 1255 DEBC(conn, 0, ("send_task_management, ref_ccb=%p, xs=%p, term=%d. No CCB\n",
 1256 ref_ccb, xs, conn->terminating));
1255 return conn->terminating; 1257 return conn->terminating;
 1258 }
1256 ppdu = get_pdu(conn, xs == NULL); 1259 ppdu = get_pdu(conn, xs == NULL);
1257 if (ppdu == NULL) { 1260 if (ppdu == NULL) {
 1261 DEBC(conn, 0, ("send_task_management, ref_ccb=%p, xs=%p, term=%d. No PDU\n",
 1262 ref_ccb, xs, conn->terminating));
1258 free_ccb(ccb); 1263 free_ccb(ccb);
1259 return conn->terminating; 1264 return conn->terminating;
1260 } 1265 }
1261 1266
1262 ccb->xs = xs; 1267 ccb->xs = xs;
1263 1268
1264 pdu = &ppdu->pdu; 1269 pdu = &ppdu->pdu;
1265 pdu->Opcode = IOP_SCSI_Task_Management | OP_IMMEDIATE; 1270 pdu->Opcode = IOP_SCSI_Task_Management | OP_IMMEDIATE;
1266 pdu->Flags = FLAG_FINAL | function; 1271 pdu->Flags = FLAG_FINAL | function;
1267 1272
1268 ccb->CmdSN = conn->session->CmdSN; 1273 ccb->CmdSN = conn->session->CmdSN;
1269 pdu->p.task_req.CmdSN = htonl(ccb->CmdSN); 1274 pdu->p.task_req.CmdSN = htonl(ccb->CmdSN);
1270 1275
1271 if (ref_ccb != NULL) { 1276 if (ref_ccb != NULL) {
1272 pdu->p.task_req.ReferencedTaskTag = ref_ccb->ITT; 1277 pdu->p.task_req.ReferencedTaskTag = ref_ccb->ITT;
1273 pdu->p.task_req.RefCmdSN = htonl(ref_ccb->CmdSN); 1278 pdu->p.task_req.RefCmdSN = htonl(ref_ccb->CmdSN);
1274 pdu->p.task_req.ExpDataSN = htonl(ref_ccb->DataSN_buf.ExpSN); 1279 pdu->p.task_req.ExpDataSN = htonl(ref_ccb->DataSN_buf.ExpSN);
1275 } else 1280 } else
1276 pdu->p.task_req.ReferencedTaskTag = 0xffffffff; 1281 pdu->p.task_req.ReferencedTaskTag = 0xffffffff;
1277 1282
1278 ppdu->flags |= PDUF_PRIORITY; 1283 ppdu->flags |= PDUF_PRIORITY;
1279 1284
1280 setup_tx_uio(ppdu, 0, NULL, FALSE); 1285 setup_tx_uio(ppdu, 0, NULL, FALSE);
1281 send_pdu(ccb, ppdu, (xs) ? CCBDISP_SCSIPI : CCBDISP_WAIT, PDUDISP_FREE); 1286 send_pdu(ccb, ppdu, (xs) ? CCBDISP_SCSIPI : CCBDISP_WAIT, PDUDISP_FREE);
1282 1287
1283 if (xs == NULL) { 1288 if (xs == NULL) {
1284 int rc = ccb->status; 1289 int rc = ccb->status;
1285 free_ccb(ccb); 1290 free_ccb(ccb);
1286 return rc; 1291 return rc;
1287 } 1292 }
1288 return 0; 1293 return 0;
1289} 1294}
1290 1295
1291 1296
1292/* 1297/*
1293 * send_data_out: 1298 * send_data_out:
1294 * Send data to target in response to an R2T or as unsolicited data. 1299 * Send data to target in response to an R2T or as unsolicited data.
1295 * 1300 *
1296 * Parameter: 1301 * Parameter:
1297 * conn The connection 1302 * conn The connection
1298 * rx_pdu The received R2T PDU (NULL if unsolicited) 1303 * rx_pdu The received R2T PDU (NULL if unsolicited)
1299 * tx_ccb The originally sent command CCB 1304 * tx_ccb The originally sent command CCB
1300 * waitok Whether it's OK to wait for an available PDU or not 1305 * waitok Whether it's OK to wait for an available PDU or not
1301 */ 1306 */
1302 1307
1303int 1308int
1304send_data_out(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb, 1309send_data_out(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb,
1305 ccb_disp_t disp, bool waitok) 1310 ccb_disp_t disp, bool waitok)
1306{ 1311{
1307 pdu_header_t *pdu; 1312 pdu_header_t *pdu;
1308 uint32_t totlen, len, offs, sn; 1313 uint32_t totlen, len, offs, sn;
1309 pdu_t *tx_pdu; 1314 pdu_t *tx_pdu;
1310 1315
1311 KASSERT(conn->max_transfer != 0); 1316 KASSERT(conn->max_transfer != 0);
1312 1317
1313 if (rx_pdu) { 1318 if (rx_pdu) {
1314 offs = ntohl(rx_pdu->pdu.p.r2t.BufferOffset); 1319 offs = ntohl(rx_pdu->pdu.p.r2t.BufferOffset);
1315 totlen = ntohl(rx_pdu->pdu.p.r2t.DesiredDataTransferLength); 1320 totlen = ntohl(rx_pdu->pdu.p.r2t.DesiredDataTransferLength);
1316 } else { 1321 } else {
1317 offs = conn->max_firstimmed; 1322 offs = conn->max_firstimmed;
1318 totlen = min(conn->max_firstdata - offs, tx_ccb->data_len - offs); 1323 totlen = min(conn->max_firstdata - offs, tx_ccb->data_len - offs);
1319 } 1324 }
1320 sn = 0; 1325 sn = 0;
1321 1326
1322 while (totlen) { 1327 while (totlen) {
1323 len = min(totlen, conn->max_transfer); 1328 len = min(totlen, conn->max_transfer);
1324 1329
1325 tx_pdu = get_pdu(conn, waitok); 1330 tx_pdu = get_pdu(conn, waitok);
1326 if (tx_pdu == NULL) { 1331 if (tx_pdu == NULL) {
1327 DEBC(conn, 5, ("No PDU in send_data_out\n")); 1332 DEBC(conn, 5, ("No PDU in send_data_out\n"));
1328 1333
1329 tx_ccb->disp = disp; 1334 tx_ccb->disp = disp;
1330 tx_ccb->status = ISCSI_STATUS_NO_RESOURCES; 1335 tx_ccb->status = ISCSI_STATUS_NO_RESOURCES;
1331 handle_connection_error(conn, ISCSI_STATUS_NO_RESOURCES, NO_LOGOUT); 1336 handle_connection_error(conn, ISCSI_STATUS_NO_RESOURCES, NO_LOGOUT);
1332 1337
1333 return ISCSI_STATUS_NO_RESOURCES; 1338 return ISCSI_STATUS_NO_RESOURCES;
1334 } 1339 }
1335 1340
1336 totlen -= len; 1341 totlen -= len;
1337 pdu = &tx_pdu->pdu; 1342 pdu = &tx_pdu->pdu;
1338 pdu->Opcode = IOP_SCSI_Data_out; 1343 pdu->Opcode = IOP_SCSI_Data_out;
1339 if (!totlen) 1344 if (!totlen)
1340 pdu->Flags = FLAG_FINAL; 1345 pdu->Flags = FLAG_FINAL;
1341 1346
1342 if (rx_pdu != NULL) 1347 if (rx_pdu != NULL)
1343 pdu->p.data_out.TargetTransferTag = 1348 pdu->p.data_out.TargetTransferTag =
1344 rx_pdu->pdu.p.r2t.TargetTransferTag; 1349 rx_pdu->pdu.p.r2t.TargetTransferTag;
1345 else 1350 else
1346 pdu->p.data_out.TargetTransferTag = 0xffffffff; 1351 pdu->p.data_out.TargetTransferTag = 0xffffffff;
1347 pdu->p.data_out.BufferOffset = htonl(offs); 1352 pdu->p.data_out.BufferOffset = htonl(offs);
1348 pdu->p.data_out.DataSN = htonl(sn); 1353 pdu->p.data_out.DataSN = htonl(sn);
1349 1354
1350 DEBC(conn, 10, ("Send DataOut: DataSN %d, len %d offs %x totlen %d\n", 1355 DEBC(conn, 10, ("Send DataOut: DataSN %d, len %d offs %x totlen %d\n",
1351 sn, len, offs, totlen)); 1356 sn, len, offs, totlen));
1352 1357
1353 setup_tx_uio(tx_pdu, len, tx_ccb->data_ptr + offs, FALSE); 1358 setup_tx_uio(tx_pdu, len, tx_ccb->data_ptr + offs, FALSE);
1354 send_pdu(tx_ccb, tx_pdu, (totlen) ? CCBDISP_NOWAIT : disp, PDUDISP_FREE); 1359 send_pdu(tx_ccb, tx_pdu, (totlen) ? CCBDISP_NOWAIT : disp, PDUDISP_FREE);
1355 1360
1356 sn++; 1361 sn++;
1357 offs += len; 1362 offs += len;
1358 } 1363 }
1359 return 0; 1364 return 0;
1360} 1365}
1361 1366
1362 1367
1363/* 1368/*
1364 * send_command: 1369 * send_command:
1365 * Send a SCSI command request. 1370 * Send a SCSI command request.
1366 * 1371 *
1367 * Parameter: 1372 * Parameter:
1368 * CCB The CCB 1373 * CCB The CCB
1369 * disp The CCB disposition 1374 * disp The CCB disposition
1370 */ 1375 */
1371 1376
1372void 1377void
1373send_command(ccb_t *ccb, ccb_disp_t disp, bool waitok, bool immed) 1378send_command(ccb_t *ccb, ccb_disp_t disp, bool waitok, bool immed)
1374{ 1379{
1375 uint32_t totlen, len; 1380 uint32_t totlen, len;
1376 connection_t *conn = ccb->connection; 1381 connection_t *conn = ccb->connection;
1377 session_t *sess = ccb->session; 1382 session_t *sess = ccb->session;
1378 pdu_t *ppdu; 1383 pdu_t *ppdu;
1379 pdu_header_t *pdu; 1384 pdu_header_t *pdu;
1380 1385
1381 mutex_enter(&sess->lock); 1386 mutex_enter(&sess->lock);
1382 while (!sernum_in_window(sess)) { 1387 while (!sernum_in_window(sess)) {
1383 mutex_exit(&sess->lock); 1388 mutex_exit(&sess->lock);
1384 ccb->disp = disp; 1389 ccb->disp = disp;
1385 wake_ccb(ccb, ISCSI_STATUS_QUEUE_FULL); 1390 wake_ccb(ccb, ISCSI_STATUS_QUEUE_FULL);
1386 return; 1391 return;
1387 } 1392 }
1388 mutex_exit(&sess->lock); 1393 mutex_exit(&sess->lock);
1389 1394
1390 /* Don't confuse targets during (re-)negotations */ 1395 /* Don't confuse targets during (re-)negotations */
1391 if (conn->state != ST_FULL_FEATURE) { 1396 if (conn->state != ST_FULL_FEATURE) {
1392 DEBOUT(("Invalid connection for send_command, ccb = %p\n",ccb)); 1397 DEBOUT(("Invalid connection for send_command, ccb = %p\n",ccb));
1393 ccb->disp = disp; 1398 ccb->disp = disp;
1394 wake_ccb(ccb, ISCSI_STATUS_TARGET_BUSY); 1399 wake_ccb(ccb, ISCSI_STATUS_TARGET_BUSY);
1395 return; 1400 return;
1396 } 1401 }
1397 1402
1398 ppdu = get_pdu(conn, waitok); 1403 ppdu = get_pdu(conn, waitok);
1399 if (ppdu == NULL) { 1404 if (ppdu == NULL) {
1400 DEBOUT(("No PDU for send_command, ccb = %p\n",ccb)); 1405 DEBOUT(("No PDU for send_command, ccb = %p\n",ccb));
1401 ccb->disp = disp; 1406 ccb->disp = disp;
1402 wake_ccb(ccb, ISCSI_STATUS_NO_RESOURCES); 1407 wake_ccb(ccb, ISCSI_STATUS_NO_RESOURCES);
1403 return; 1408 return;
1404 } 1409 }
1405 1410
1406 totlen = len = ccb->data_len; 1411 totlen = len = ccb->data_len;
1407 1412
1408 pdu = &ppdu->pdu; 1413 pdu = &ppdu->pdu;
1409 pdu->LUN = htonq(ccb->lun); 1414 pdu->LUN = htonq(ccb->lun);
1410 memcpy(pdu->p.command.SCSI_CDB, ccb->cmd, ccb->cmdlen); 1415 memcpy(pdu->p.command.SCSI_CDB, ccb->cmd, ccb->cmdlen);
1411 pdu->Opcode = IOP_SCSI_Command; 1416 pdu->Opcode = IOP_SCSI_Command;
1412 if (immed) 1417 if (immed)
1413 pdu->Opcode |= OP_IMMEDIATE; 1418 pdu->Opcode |= OP_IMMEDIATE;
1414 pdu->p.command.ExpectedDataTransferLength = htonl(totlen); 1419 pdu->p.command.ExpectedDataTransferLength = htonl(totlen);
1415 1420
1416 if (totlen) { 1421 if (totlen) {
1417 if (ccb->data_in) { 1422 if (ccb->data_in) {
1418 pdu->Flags = FLAG_READ; 1423 pdu->Flags = FLAG_READ;
1419 totlen = 0; 1424 totlen = 0;
1420 } else { 1425 } else {
1421 pdu->Flags = FLAG_WRITE; 1426 pdu->Flags = FLAG_WRITE;
1422 /* immediate data we can send */ 1427 /* immediate data we can send */
1423 len = min(totlen, conn->max_firstimmed); 1428 len = min(totlen, conn->max_firstimmed);
1424 1429
1425 /* can we send more unsolicited data ? */ 1430 /* can we send more unsolicited data ? */
1426 totlen = conn->max_firstdata ? totlen - len : 0; 1431 totlen = conn->max_firstdata ? totlen - len : 0;
1427 } 1432 }
1428 } 1433 }
1429 if (!totlen) 1434 if (!totlen)
1430 pdu->Flags |= FLAG_FINAL; 1435 pdu->Flags |= FLAG_FINAL;
1431 pdu->Flags |= ccb->tag; 1436 pdu->Flags |= ccb->tag;
1432 1437
1433 if (ccb->data_in) 1438 if (ccb->data_in)
1434 init_sernum(&ccb->DataSN_buf); 1439 init_sernum(&ccb->DataSN_buf);
1435 1440
1436 ccb->sense_len_got = 0; 1441 ccb->sense_len_got = 0;
1437 ccb->xfer_len = 0; 1442 ccb->xfer_len = 0;
1438 ccb->residual = 0; 1443 ccb->residual = 0;
1439 ccb->flags |= CCBF_REASSIGN; 1444 ccb->flags |= CCBF_REASSIGN;
1440 1445
1441 mutex_enter(&sess->lock); 1446 mutex_enter(&sess->lock);
1442 ccb->CmdSN = get_sernum(sess, ppdu); 1447 ccb->CmdSN = get_sernum(sess, ppdu);
1443 mutex_exit(&sess->lock); 1448 mutex_exit(&sess->lock);
1444 1449
1445 pdu->p.command.CmdSN = htonl(ccb->CmdSN); 1450 pdu->p.command.CmdSN = htonl(ccb->CmdSN);
1446 1451
1447 DEBC(conn, 10, ("Send Command: CmdSN %d (%d), data_in %d, len %d, totlen %d\n", 1452 DEBC(conn, 10, ("Send Command: CmdSN %d (%d), data_in %d, len %d, totlen %d\n",
1448 ccb->CmdSN, sess->MaxCmdSN, ccb->data_in, len, totlen)); 1453 ccb->CmdSN, sess->MaxCmdSN, ccb->data_in, len, totlen));
1449 1454
1450 setup_tx_uio(ppdu, len, ccb->data_ptr, ccb->data_in); 1455 setup_tx_uio(ppdu, len, ccb->data_ptr, ccb->data_in);
1451 send_pdu(ccb, ppdu, (totlen) ? CCBDISP_DEFER : disp, PDUDISP_WAIT); 1456 send_pdu(ccb, ppdu, (totlen) ? CCBDISP_DEFER : disp, PDUDISP_WAIT);
1452 1457
1453 if (totlen) 1458 if (totlen)
1454 send_data_out(conn, NULL, ccb, disp, waitok); 1459 send_data_out(conn, NULL, ccb, disp, waitok);
1455} 1460}
1456 1461
1457 1462
1458/* 1463/*
1459 * send_run_xfer: 1464 * send_run_xfer:
1460 * Handle a SCSI command transfer request from scsipi. 1465 * Handle a SCSI command transfer request from scsipi.
1461 * 1466 *
1462 * Parameter: 1467 * Parameter:
1463 * session The session 1468 * session The session
1464 * xs The transfer parameters 1469 * xs The transfer parameters
1465 */ 1470 */
1466 1471
1467void 1472void
1468send_run_xfer(session_t *session, struct scsipi_xfer *xs) 1473send_run_xfer(session_t *session, struct scsipi_xfer *xs)
1469{ 1474{
1470 ccb_t *ccb; 1475 ccb_t *ccb;
1471 connection_t *conn; 1476 connection_t *conn;
1472 bool waitok; 1477 bool waitok;
1473 1478
1474 waitok = !(xs->xs_control & XS_CTL_NOSLEEP); 1479 waitok = !(xs->xs_control & XS_CTL_NOSLEEP);
1475 1480
1476 DEB(10, ("RunXfer: flags=%x, data=%p, datalen=%d, resid=%d, cmdlen=%d, " 1481 DEB(10, ("RunXfer: flags=%x, data=%p, datalen=%d, resid=%d, cmdlen=%d, "
1477 "waitok=%d\n", xs->xs_control, xs->data, xs->datalen, 1482 "waitok=%d\n", xs->xs_control, xs->data, xs->datalen,
1478 xs->resid, xs->cmdlen, waitok)); 1483 xs->resid, xs->cmdlen, waitok));
1479 1484
1480 conn = assign_connection(session, waitok); 1485 conn = assign_connection(session, waitok);
1481 1486
1482 if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) { 1487 if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) {
1483 xs->error = XS_SELTIMEOUT; 1488 xs->error = XS_SELTIMEOUT;
1484 DEBC(conn, 10, ("run_xfer on dead connection\n")); 1489 DEBC(conn, 10, ("run_xfer on dead connection\n"));
1485 scsipi_done(xs); 1490 scsipi_done(xs);
1486 unref_session(session); 1491 unref_session(session);
1487 return; 1492 return;
1488 } 1493 }
1489 1494
1490 if (xs->xs_control & XS_CTL_RESET) { 1495 if (xs->xs_control & XS_CTL_RESET) {
1491 if (send_task_management(conn, NULL, xs, TARGET_WARM_RESET)) { 1496 if (send_task_management(conn, NULL, xs, TARGET_WARM_RESET)) {
 1497 DEBC(conn, 0, ("send_task_management TARGET_WARM_RESET failed\n"));
1492 xs->error = XS_SELTIMEOUT; 1498 xs->error = XS_SELTIMEOUT;
1493 scsipi_done(xs); 1499 scsipi_done(xs);
1494 unref_session(session); 1500 unref_session(session);
1495 } 1501 }
1496 return; 1502 return;
1497 } 1503 }
1498 1504
1499 ccb = get_ccb(conn, waitok); 1505 ccb = get_ccb(conn, waitok);
1500 if (ccb == NULL) { 1506 if (ccb == NULL) {
1501 xs->error = XS_BUSY; 1507 xs->error = XS_BUSY;
1502 DEBC(conn, 5, ("No CCB in run_xfer, %d in use.\n", conn->usecount)); 1508 DEBC(conn, 5, ("No CCB in run_xfer, %d in use.\n", conn->usecount));
1503 scsipi_done(xs); 1509 scsipi_done(xs);
1504 unref_session(session); 1510 unref_session(session);
1505 return; 1511 return;
1506 } 1512 }
1507 /* copy parameters into CCB for easier access */ 1513 /* copy parameters into CCB for easier access */
1508 ccb->xs = xs; 1514 ccb->xs = xs;
1509 1515
1510 ccb->data_in = (xs->xs_control & XS_CTL_DATA_IN) != 0; 1516 ccb->data_in = (xs->xs_control & XS_CTL_DATA_IN) != 0;
1511 ccb->data_len = (uint32_t) xs->datalen; 1517 ccb->data_len = (uint32_t) xs->datalen;
1512 ccb->data_ptr = xs->data; 1518 ccb->data_ptr = xs->data;
1513 1519
1514 ccb->sense_len_req = sizeof(xs->sense.scsi_sense); 1520 ccb->sense_len_req = sizeof(xs->sense.scsi_sense);
1515 ccb->sense_ptr = &xs->sense; 1521 ccb->sense_ptr = &xs->sense;
1516 1522
1517 ccb->lun = ((uint64_t) (uint8_t) xs->xs_periph->periph_lun) << 48; 1523 ccb->lun = ((uint64_t) (uint8_t) xs->xs_periph->periph_lun) << 48;
1518 ccb->cmd = (uint8_t *) xs->cmd; 1524 ccb->cmd = (uint8_t *) xs->cmd;
1519 ccb->cmdlen = xs->cmdlen; 1525 ccb->cmdlen = xs->cmdlen;
1520 DEB(10, ("RunXfer: Periph_lun = %d, cmd[1] = %x, cmdlen = %d\n", 1526 DEB(10, ("RunXfer: Periph_lun = %d, cmd[1] = %x, cmdlen = %d\n",
1521 xs->xs_periph->periph_lun, ccb->cmd[1], xs->cmdlen)); 1527 xs->xs_periph->periph_lun, ccb->cmd[1], xs->cmdlen));
1522 1528
1523 ccb->ITT |= xs->xs_tag_id << 24; 1529 ccb->ITT |= xs->xs_tag_id << 24;
1524 switch (xs->xs_tag_type) { 1530 switch (xs->xs_tag_type) {
1525 case MSG_ORDERED_Q_TAG: 1531 case MSG_ORDERED_Q_TAG:
1526 ccb->tag = ATTR_ORDERED; 1532 ccb->tag = ATTR_ORDERED;
1527 break; 1533 break;
1528 case MSG_SIMPLE_Q_TAG: 1534 case MSG_SIMPLE_Q_TAG:
1529 ccb->tag = ATTR_SIMPLE; 1535 ccb->tag = ATTR_SIMPLE;
1530 break; 1536 break;
1531 case MSG_HEAD_OF_Q_TAG: 1537 case MSG_HEAD_OF_Q_TAG:
1532 ccb->tag = ATTR_HEAD_OF_QUEUE; 1538 ccb->tag = ATTR_HEAD_OF_QUEUE;
1533 break; 1539 break;
1534 default: 1540 default:
1535 ccb->tag = 0; 1541 ccb->tag = 0;
1536 break; 1542 break;
1537 } 1543 }
1538 1544
1539#ifdef LUN_1 1545#ifdef LUN_1
1540 ccb->lun += 0x1000000000000LL; 1546 ccb->lun += 0x1000000000000LL;
1541 ccb->cmd[1] += 0x10; 1547 ccb->cmd[1] += 0x10;
1542#endif 1548#endif
1543 send_command(ccb, CCBDISP_SCSIPI, waitok, FALSE); 1549 send_command(ccb, CCBDISP_SCSIPI, waitok, FALSE);
1544} 1550}
1545 1551
1546 1552
1547#ifndef ISCSI_MINIMAL 1553#ifndef ISCSI_MINIMAL
1548/* 1554/*
1549 * send_io_command: 1555 * send_io_command:
1550 * Handle a SCSI io command request from user space. 1556 * Handle a SCSI io command request from user space.
1551 * 1557 *
1552 * Parameter: 1558 * Parameter:
1553 * session The session 1559 * session The session
1554 * lun The LUN to use 1560 * lun The LUN to use
1555 * req The SCSI request block 1561 * req The SCSI request block
1556 * immed Immediate command if TRUE 1562 * immed Immediate command if TRUE
1557 * conn_id Assign to this connection ID if nonzero 1563 * conn_id Assign to this connection ID if nonzero
1558 */ 1564 */
1559 1565
1560int 1566int
1561send_io_command(session_t *session, uint64_t lun, scsireq_t *req, 1567send_io_command(session_t *session, uint64_t lun, scsireq_t *req,
1562 bool immed, uint32_t conn_id) 1568 bool immed, uint32_t conn_id)
1563{ 1569{
1564 ccb_t *ccb; 1570 ccb_t *ccb;
1565 connection_t *conn; 1571 connection_t *conn;
1566 int rc; 1572 int rc;
1567 1573
1568 DEB(9, ("IoCommand: lun=%x, datalen=%d, cmdlen=%d, immed=%d, cid=%d\n", 1574 DEB(9, ("IoCommand: lun=%x, datalen=%d, cmdlen=%d, immed=%d, cid=%d\n",
1569 (int) lun, (int) req->datalen, (int) req->cmdlen, immed, conn_id)); 1575 (int) lun, (int) req->datalen, (int) req->cmdlen, immed, conn_id));
1570 1576
1571 conn = (conn_id) ? find_connection(session, conn_id) 1577 conn = (conn_id) ? find_connection(session, conn_id)
1572 : assign_connection(session, TRUE); 1578 : assign_connection(session, TRUE);
1573 1579
1574 if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) { 1580 if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) {
1575 DEBOUT(("io_command on dead connection (state = %d)\n", 1581 DEBOUT(("io_command on dead connection (state = %d)\n",
1576 (conn != NULL) ? conn->state : -1)); 1582 (conn != NULL) ? conn->state : -1));
1577 return ISCSI_STATUS_INVALID_CONNECTION_ID; 1583 return ISCSI_STATUS_INVALID_CONNECTION_ID;
1578 } 1584 }
1579 1585
1580 ccb = get_ccb(conn, TRUE); 1586 ccb = get_ccb(conn, TRUE);
1581 if (ccb == NULL) { 1587 if (ccb == NULL) {
1582 DEBOUT(("No CCB in io_command\n")); 1588 DEBOUT(("No CCB in io_command\n"));
1583 return ISCSI_STATUS_NO_RESOURCES; 1589 return ISCSI_STATUS_NO_RESOURCES;
1584 } 1590 }
1585 1591
1586 ccb->data_in = (req->flags & SCCMD_READ) != 0; 1592 ccb->data_in = (req->flags & SCCMD_READ) != 0;
1587 ccb->data_len = (uint32_t) req->datalen; 1593 ccb->data_len = (uint32_t) req->datalen;
1588 ccb->data_ptr = req->databuf; 1594 ccb->data_ptr = req->databuf;
1589 1595
1590 ccb->sense_len_req = req->senselen; 1596 ccb->sense_len_req = req->senselen;
1591 ccb->sense_ptr = &req->sense; 1597 ccb->sense_ptr = &req->sense;
1592 1598
1593 ccb->lun = lun; 1599 ccb->lun = lun;
1594 ccb->cmd = (uint8_t *) req->cmd; 1600 ccb->cmd = (uint8_t *) req->cmd;
1595 ccb->cmdlen = req->cmdlen; 1601 ccb->cmdlen = req->cmdlen;
1596 DEBC(conn, 10, ("IoCommand: cmd[1] = %x, cmdlen = %d\n", 1602 DEBC(conn, 10, ("IoCommand: cmd[1] = %x, cmdlen = %d\n",
1597 ccb->cmd[1], ccb->cmdlen)); 1603 ccb->cmd[1], ccb->cmdlen));
1598 1604
1599 send_command(ccb, CCBDISP_WAIT, TRUE, immed); 1605 send_command(ccb, CCBDISP_WAIT, TRUE, immed);
1600 1606
1601 rc = ccb->status; 1607 rc = ccb->status;
1602 1608
1603 req->senselen_used = ccb->sense_len_got; 1609 req->senselen_used = ccb->sense_len_got;
1604 req->datalen_used = req->datalen - ccb->residual; 1610 req->datalen_used = req->datalen - ccb->residual;
1605 1611
1606 free_ccb(ccb); 1612 free_ccb(ccb);
1607 1613
1608 return rc; 1614 return rc;
1609} 1615}
1610#endif 1616#endif
1611 1617
1612 1618
1613/***************************************************************************** 1619/*****************************************************************************
1614 * Timeout handlers 1620 * Timeout handlers
1615 *****************************************************************************/ 1621 *****************************************************************************/
1616/* 1622/*
1617 * connection_timeout: 1623 * connection_timeout:
1618 * Handle prolonged silence on a connection by checking whether 1624 * Handle prolonged silence on a connection by checking whether
1619 * it's still alive. 1625 * it's still alive.
1620 * This has the side effect of discovering missing status or lost commands 1626 * This has the side effect of discovering missing status or lost commands
1621 * before those time out. 1627 * before those time out.
1622 * 1628 *
1623 * Parameter: 1629 * Parameter:
1624 * conn The connection 1630 * conn The connection
1625 */ 1631 */
1626 1632
1627void 1633void
1628connection_timeout(connection_t *conn) 1634connection_timeout(connection_t *conn)
1629{ 1635{
1630 1636
1631 if (++conn->num_timeouts > MAX_CONN_TIMEOUTS) 1637 if (++conn->num_timeouts > MAX_CONN_TIMEOUTS)
1632 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, NO_LOGOUT); 1638 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, NO_LOGOUT);
1633 else { 1639 else {
1634 if (conn->state == ST_FULL_FEATURE) 1640 if (conn->state == ST_FULL_FEATURE)
1635 send_nop_out(conn, NULL); 1641 send_nop_out(conn, NULL);
1636 1642
1637 connection_timeout_start(conn, CONNECTION_TIMEOUT); 1643 connection_timeout_start(conn, CONNECTION_TIMEOUT);
1638 } 1644 }
1639} 1645}
1640 1646
1641/* 1647/*
1642 * ccb_timeout: 1648 * ccb_timeout:
1643 * Handle timeout of a sent command. 1649 * Handle timeout of a sent command.
1644 * 1650 *
1645 * Parameter: 1651 * Parameter:
1646 * ccb The CCB 1652 * ccb The CCB
1647 */ 1653 */
1648 1654
1649void 1655void
1650ccb_timeout(ccb_t *ccb) 1656ccb_timeout(ccb_t *ccb)
1651{ 1657{
1652 connection_t *conn = ccb->connection; 1658 connection_t *conn = ccb->connection;
1653 1659
1654 ccb->total_tries++; 1660 ccb->total_tries++;
1655 1661
1656 DEBC(conn, 0, ("ccb_timeout: num=%d total=%d disp=%d\n", 1662 DEBC(conn, 0, ("ccb_timeout: num=%d total=%d disp=%d\n",
1657 ccb->num_timeouts+1, ccb->total_tries, ccb->disp)); 1663 ccb->num_timeouts+1, ccb->total_tries, ccb->disp));
1658 1664
1659 if (++ccb->num_timeouts > MAX_CCB_TIMEOUTS || 1665 if (++ccb->num_timeouts > MAX_CCB_TIMEOUTS ||
1660 ccb->total_tries > MAX_CCB_TRIES || 1666 ccb->total_tries > MAX_CCB_TRIES ||
1661 ccb->disp <= CCBDISP_FREE || 1667 ccb->disp <= CCBDISP_FREE ||
1662 !ccb->session->ErrorRecoveryLevel) { 1668 !ccb->session->ErrorRecoveryLevel) {
1663 1669
1664 wake_ccb(ccb, ISCSI_STATUS_TIMEOUT); 1670 wake_ccb(ccb, ISCSI_STATUS_TIMEOUT);
1665 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION); 1671 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION);
1666 } else { 1672 } else {
1667 if (ccb->data_in && ccb->xfer_len < ccb->data_len) { 1673 if (ccb->data_in && ccb->xfer_len < ccb->data_len) {
1668 /* request resend of all missing data */ 1674 /* request resend of all missing data */
1669 snack_missing(conn, ccb, SNACK_DATA_NAK, 0, 0); 1675 snack_missing(conn, ccb, SNACK_DATA_NAK, 0, 0);
1670 } else { 1676 } else {
1671 /* request resend of all missing status */ 1677 /* request resend of all missing status */
1672 snack_missing(conn, NULL, SNACK_STATUS_NAK, 0, 0); 1678 snack_missing(conn, NULL, SNACK_STATUS_NAK, 0, 0);
1673 } 1679 }
1674 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 1680 ccb_timeout_start(ccb, COMMAND_TIMEOUT);
1675 } 1681 }
1676} 1682}
1677 1683