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