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