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