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