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