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