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