iscsi_send.c revision 1.34 1 1.34 mlelstv /* $NetBSD: iscsi_send.c,v 1.34 2017/02/25 12:03:57 mlelstv 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.16 mlelstv #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.15 knakahar int ret;
59 1.15 knakahar #ifdef ISCSI_DEBUG
60 1.1 agc size_t resid = u->uio_resid;
61 1.16 mlelstv #endif
62 1.1 agc
63 1.16 mlelstv KASSERT(u->uio_resid != 0);
64 1.1 agc
65 1.24 mlelstv 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.16 mlelstv mutex_enter(&session->lock);
95 1.1 agc do {
96 1.31 mlelstv if (session->terminating ||
97 1.31 mlelstv (conn = session->mru_connection) == NULL) {
98 1.16 mlelstv 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.16 mlelstv cv_wait(&session->sess_cv, &session->lock);
113 1.1 agc next = TAILQ_FIRST(&session->conn_list);
114 1.1 agc } else {
115 1.16 mlelstv 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.16 mlelstv 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.17 mlelstv 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.16 mlelstv 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.22 mlelstv KASSERT((opdu->flags & PDUF_INQUEUE) == 0);
193 1.22 mlelstv
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.16 mlelstv 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.31 mlelstv mutex_enter(&conn->lock);
237 1.8 mlelstv suspend_ccb(ccb, TRUE);
238 1.31 mlelstv 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.16 mlelstv mutex_enter(&sess->lock);
259 1.1 agc if (ccb->CmdSN < sess->ExpCmdSN) {
260 1.1 agc pdu = ccb->pdu_waiting;
261 1.31 mlelstv 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.20 mlelstv ccb->CmdSN, sn));
266 1.17 mlelstv ccb->CmdSN = sn;
267 1.1 agc pdu->pdu.p.command.CmdSN = htonl(ccb->CmdSN);
268 1.1 agc }
269 1.16 mlelstv mutex_exit(&sess->lock);
270 1.1 agc resend_pdu(ccb);
271 1.1 agc } else {
272 1.18 mlelstv 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.30 mlelstv 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.16 mlelstv 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.30 mlelstv pdu->flags &= ~PDUF_INQUEUE;
310 1.16 mlelstv mutex_exit(&conn->lock);
311 1.1 agc
312 1.12 joerg /* update ExpStatSN here to avoid discontinuities */
313 1.12 joerg /* and delays in updating target */
314 1.12 joerg pdu->pdu.p.command.ExpStatSN = htonl(conn->StatSN_buf.ExpSN);
315 1.12 joerg
316 1.12 joerg if (conn->HeaderDigest)
317 1.12 joerg pdu->pdu.HeaderDigest = gen_digest(&pdu->pdu, BHS_SIZE);
318 1.31 mlelstv
319 1.31 mlelstv DEBC(conn, 99, ("Transmitting PDU CmdSN = %u, ExpStatSN = %u\n",
320 1.31 mlelstv ntohl(pdu->pdu.p.command.CmdSN),
321 1.31 mlelstv ntohl(pdu->pdu.p.command.ExpStatSN)));
322 1.12 joerg my_soo_write(conn, &pdu->uio);
323 1.1 agc
324 1.22 mlelstv mutex_enter(&conn->lock);
325 1.30 mlelstv pdisp = pdu->disp;
326 1.31 mlelstv if (pdisp > PDUDISP_FREE)
327 1.22 mlelstv pdu->flags &= ~PDUF_BUSY;
328 1.22 mlelstv mutex_exit(&conn->lock);
329 1.30 mlelstv if (pdisp <= PDUDISP_FREE)
330 1.1 agc free_pdu(pdu);
331 1.22 mlelstv
332 1.16 mlelstv mutex_enter(&conn->lock);
333 1.1 agc }
334 1.1 agc
335 1.16 mlelstv if (!conn->terminating)
336 1.16 mlelstv cv_wait(&conn->conn_cv, &conn->lock);
337 1.1 agc }
338 1.16 mlelstv 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.18 mlelstv 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.18 mlelstv 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.16 mlelstv 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.16 mlelstv 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.16 mlelstv mutex_enter(&conn->lock);
382 1.1 agc }
383 1.16 mlelstv 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.18 mlelstv
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.16 mlelstv 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.16 mlelstv mutex_enter(&conn->lock);
403 1.1 agc if (!conn->destroy)
404 1.16 mlelstv cv_timedwait(&conn->idle_cv, &conn->lock, CONNECTION_IDLE_TIMEOUT);
405 1.16 mlelstv 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.32 mlelstv mutex_enter(&conn->lock);
412 1.16 mlelstv cv_broadcast(&conn->conn_cv);
413 1.32 mlelstv mutex_exit(&conn->lock);
414 1.1 agc
415 1.1 agc /* wake up any waiting CCBs */
416 1.1 agc while ((ccb = TAILQ_FIRST(&conn->ccbs_waiting)) != NULL) {
417 1.16 mlelstv KASSERT(ccb->disp >= CCBDISP_NOWAIT);
418 1.8 mlelstv wake_ccb(ccb, conn->terminating);
419 1.1 agc /* NOTE: wake_ccb will remove the CCB from the queue */
420 1.1 agc }
421 1.1 agc
422 1.16 mlelstv add_connection_cleanup(conn);
423 1.1 agc
424 1.1 agc conn->sendproc = NULL;
425 1.8 mlelstv DEBC(conn, 1, ("Send thread exits\n"));
426 1.6 mlelstv iscsi_num_send_threads--;
427 1.1 agc kthread_exit(0);
428 1.1 agc }
429 1.1 agc
430 1.1 agc
431 1.1 agc /*
432 1.1 agc * send_pdu:
433 1.1 agc * Enqueue a PDU to be sent, and handle its disposition as well as
434 1.1 agc * the disposition of its associated CCB.
435 1.1 agc *
436 1.1 agc * Parameter:
437 1.1 agc * ccb The associated CCB. May be NULL if cdisp is CCBDISP_NOWAIT
438 1.1 agc * and pdisp is not PDUDISP_WAIT
439 1.1 agc * cdisp The CCB's disposition
440 1.1 agc * pdu The PDU
441 1.1 agc * pdisp The PDU's disposition
442 1.1 agc */
443 1.1 agc
444 1.1 agc STATIC void
445 1.1 agc send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_disp_t cdisp, pdu_disp_t pdisp)
446 1.1 agc {
447 1.1 agc connection_t *conn = pdu->connection;
448 1.1 agc ccb_disp_t prev_cdisp = 0;
449 1.1 agc
450 1.1 agc if (ccb != NULL) {
451 1.1 agc prev_cdisp = ccb->disp;
452 1.1 agc pdu->pdu.InitiatorTaskTag = ccb->ITT;
453 1.1 agc pdu->owner = ccb;
454 1.1 agc if (cdisp != CCBDISP_NOWAIT)
455 1.1 agc ccb->disp = cdisp;
456 1.1 agc }
457 1.1 agc
458 1.1 agc pdu->disp = pdisp;
459 1.1 agc
460 1.31 mlelstv DEBC(conn, 10, ("Send_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n",
461 1.31 mlelstv ntohl(pdu->pdu.p.command.CmdSN),
462 1.31 mlelstv conn->StatSN_buf.ExpSN,
463 1.31 mlelstv ccb, pdu));
464 1.1 agc
465 1.16 mlelstv mutex_enter(&conn->lock);
466 1.1 agc if (pdisp == PDUDISP_WAIT) {
467 1.32 mlelstv KASSERT(ccb != NULL);
468 1.32 mlelstv
469 1.1 agc ccb->pdu_waiting = pdu;
470 1.1 agc
471 1.1 agc /* save UIO and IOVEC for retransmit */
472 1.1 agc pdu->save_uio = pdu->uio;
473 1.1 agc memcpy(pdu->save_iovec, pdu->io_vec, sizeof(pdu->save_iovec));
474 1.1 agc
475 1.1 agc pdu->flags |= PDUF_BUSY;
476 1.1 agc }
477 1.1 agc /* Enqueue for sending */
478 1.1 agc pdu->flags |= PDUF_INQUEUE;
479 1.1 agc
480 1.1 agc if (pdu->flags & PDUF_PRIORITY)
481 1.1 agc TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain);
482 1.1 agc else
483 1.1 agc TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain);
484 1.1 agc
485 1.16 mlelstv cv_broadcast(&conn->conn_cv);
486 1.1 agc
487 1.1 agc if (cdisp != CCBDISP_NOWAIT) {
488 1.32 mlelstv KASSERT(ccb != NULL);
489 1.32 mlelstv KASSERTMSG(ccb->connection == conn, "conn mismatch %p != %p\n", ccb->connection, conn);
490 1.1 agc
491 1.1 agc if (prev_cdisp <= CCBDISP_NOWAIT)
492 1.8 mlelstv suspend_ccb(ccb, TRUE);
493 1.32 mlelstv
494 1.32 mlelstv mutex_exit(&conn->lock);
495 1.32 mlelstv ccb_timeout_start(ccb, COMMAND_TIMEOUT);
496 1.32 mlelstv mutex_enter(&conn->lock);
497 1.32 mlelstv
498 1.16 mlelstv while (ccb->disp == CCBDISP_WAIT) {
499 1.16 mlelstv DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d waiting\n",
500 1.16 mlelstv ccb, ccb->disp));
501 1.16 mlelstv cv_wait(&conn->ccb_cv, &conn->lock);
502 1.16 mlelstv DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d returned\n",
503 1.16 mlelstv ccb, ccb->disp));
504 1.16 mlelstv }
505 1.1 agc }
506 1.32 mlelstv
507 1.32 mlelstv mutex_exit(&conn->lock);
508 1.1 agc }
509 1.1 agc
510 1.1 agc
511 1.1 agc /*
512 1.1 agc * resend_pdu:
513 1.1 agc * Re-Enqueue a PDU that has apparently gotten lost.
514 1.1 agc *
515 1.1 agc * Parameter:
516 1.1 agc * ccb The associated CCB.
517 1.1 agc */
518 1.1 agc
519 1.1 agc void
520 1.1 agc resend_pdu(ccb_t *ccb)
521 1.1 agc {
522 1.1 agc connection_t *conn = ccb->connection;
523 1.1 agc pdu_t *pdu = ccb->pdu_waiting;
524 1.1 agc
525 1.16 mlelstv mutex_enter(&conn->lock);
526 1.1 agc if (pdu == NULL || (pdu->flags & PDUF_BUSY)) {
527 1.16 mlelstv mutex_exit(&conn->lock);
528 1.1 agc return;
529 1.1 agc }
530 1.1 agc pdu->flags |= PDUF_BUSY;
531 1.16 mlelstv mutex_exit(&conn->lock);
532 1.1 agc
533 1.1 agc /* restore UIO and IOVEC */
534 1.1 agc pdu->uio = pdu->save_uio;
535 1.1 agc memcpy(pdu->io_vec, pdu->save_iovec, sizeof(pdu->io_vec));
536 1.1 agc
537 1.31 mlelstv DEBC(conn, 8, ("ReSend_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n",
538 1.31 mlelstv ntohl(pdu->pdu.p.command.CmdSN),
539 1.31 mlelstv conn->StatSN_buf.ExpSN,
540 1.31 mlelstv ccb, pdu));
541 1.1 agc
542 1.16 mlelstv mutex_enter(&conn->lock);
543 1.1 agc /* Enqueue for sending */
544 1.1 agc pdu->flags |= PDUF_INQUEUE;
545 1.1 agc
546 1.1 agc if (pdu->flags & PDUF_PRIORITY) {
547 1.1 agc TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain);
548 1.1 agc } else {
549 1.1 agc TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain);
550 1.1 agc }
551 1.18 mlelstv ccb_timeout_start(ccb, COMMAND_TIMEOUT);
552 1.32 mlelstv cv_broadcast(&conn->conn_cv);
553 1.16 mlelstv mutex_exit(&conn->lock);
554 1.1 agc }
555 1.1 agc
556 1.1 agc
557 1.1 agc /*
558 1.1 agc * setup_tx_uio:
559 1.1 agc * Initialize the uio structure for sending, including header,
560 1.1 agc * data (if present), padding, and Data Digest.
561 1.1 agc * Header Digest is generated in send thread.
562 1.1 agc *
563 1.1 agc * Parameter:
564 1.1 agc * pdu The PDU
565 1.1 agc * dsl The Data Segment Length
566 1.1 agc * data The data pointer
567 1.1 agc * read TRUE if this is a read operation
568 1.1 agc */
569 1.1 agc
570 1.1 agc STATIC void
571 1.1 agc setup_tx_uio(pdu_t *pdu, uint32_t dsl, void *data, bool read)
572 1.1 agc {
573 1.1 agc static uint8_t pad_bytes[4] = { 0 };
574 1.1 agc struct uio *uio;
575 1.1 agc int i, pad, hlen;
576 1.1 agc connection_t *conn = pdu->connection;
577 1.1 agc
578 1.1 agc DEB(99, ("SetupTxUio: dlen = %d, dptr: %p, read: %d\n",
579 1.1 agc dsl, data, read));
580 1.1 agc
581 1.1 agc if (!read && dsl) {
582 1.1 agc hton3(dsl, pdu->pdu.DataSegmentLength);
583 1.1 agc }
584 1.1 agc hlen = (conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE;
585 1.1 agc
586 1.1 agc pdu->io_vec[0].iov_base = &pdu->pdu;
587 1.1 agc pdu->io_vec[0].iov_len = hlen;
588 1.1 agc
589 1.1 agc uio = &pdu->uio;
590 1.1 agc
591 1.1 agc uio->uio_iov = pdu->io_vec;
592 1.1 agc uio->uio_iovcnt = 1;
593 1.1 agc uio->uio_rw = UIO_WRITE;
594 1.1 agc uio->uio_resid = hlen;
595 1.1 agc UIO_SETUP_SYSSPACE(uio);
596 1.1 agc
597 1.1 agc if (!read && dsl) {
598 1.1 agc uio->uio_iovcnt++;
599 1.1 agc pdu->io_vec[1].iov_base = data;
600 1.1 agc pdu->io_vec[1].iov_len = dsl;
601 1.1 agc uio->uio_resid += dsl;
602 1.1 agc
603 1.1 agc /* Pad to next multiple of 4 */
604 1.1 agc pad = uio->uio_resid & 0x03;
605 1.1 agc if (pad) {
606 1.1 agc i = uio->uio_iovcnt++;
607 1.1 agc pad = 4 - pad;
608 1.1 agc pdu->io_vec[i].iov_base = pad_bytes;
609 1.1 agc pdu->io_vec[i].iov_len = pad;
610 1.1 agc uio->uio_resid += pad;
611 1.1 agc }
612 1.1 agc
613 1.1 agc if (conn->DataDigest) {
614 1.1 agc pdu->data_digest = gen_digest_2(data, dsl, pad_bytes, pad);
615 1.1 agc i = uio->uio_iovcnt++;
616 1.1 agc pdu->io_vec[i].iov_base = &pdu->data_digest;
617 1.1 agc pdu->io_vec[i].iov_len = 4;
618 1.1 agc uio->uio_resid += 4;
619 1.1 agc }
620 1.1 agc }
621 1.1 agc }
622 1.1 agc
623 1.1 agc /*
624 1.1 agc * init_login_pdu:
625 1.1 agc * Initialize the login PDU.
626 1.1 agc *
627 1.1 agc * Parameter:
628 1.1 agc * conn The connection
629 1.23 mlelstv * ccb The CCB
630 1.1 agc * pdu The PDU
631 1.1 agc */
632 1.1 agc
633 1.1 agc STATIC void
634 1.23 mlelstv init_login_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, bool next)
635 1.1 agc {
636 1.1 agc pdu_header_t *pdu = &ppdu->pdu;
637 1.1 agc login_isid_t *isid = (login_isid_t *) & pdu->LUN;
638 1.1 agc uint8_t c_phase;
639 1.1 agc
640 1.1 agc pdu->Opcode = IOP_Login_Request | OP_IMMEDIATE;
641 1.1 agc
642 1.28 mlelstv mutex_enter(&conn->session->lock);
643 1.31 mlelstv ccb->CmdSN = get_sernum(conn->session, ppdu);
644 1.28 mlelstv mutex_exit(&conn->session->lock);
645 1.23 mlelstv
646 1.1 agc if (next) {
647 1.1 agc c_phase = (pdu->Flags >> CSG_SHIFT) & SG_MASK;
648 1.1 agc pdu->Flags = FLAG_TRANSIT | (c_phase << CSG_SHIFT) |
649 1.1 agc NEXT_PHASE(c_phase);
650 1.1 agc }
651 1.1 agc
652 1.6 mlelstv memcpy(isid, &iscsi_InitiatorISID, 6);
653 1.1 agc isid->TSIH = conn->session->TSIH;
654 1.1 agc
655 1.1 agc pdu->p.login_req.CID = htons(conn->id);
656 1.23 mlelstv pdu->p.login_req.CmdSN = htonl(ccb->CmdSN);
657 1.1 agc }
658 1.1 agc
659 1.1 agc
660 1.1 agc /*
661 1.1 agc * negotiate_login:
662 1.1 agc * Control login negotiation.
663 1.1 agc *
664 1.1 agc * Parameter:
665 1.1 agc * conn The connection
666 1.1 agc * rx_pdu The received login response PDU
667 1.1 agc * tx_ccb The originally sent login CCB
668 1.1 agc */
669 1.1 agc
670 1.1 agc void
671 1.1 agc negotiate_login(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb)
672 1.1 agc {
673 1.1 agc int rc;
674 1.1 agc bool next = TRUE;
675 1.1 agc pdu_t *tx_pdu;
676 1.1 agc uint8_t c_phase;
677 1.1 agc
678 1.1 agc if (rx_pdu->pdu.Flags & FLAG_TRANSIT)
679 1.1 agc c_phase = rx_pdu->pdu.Flags & SG_MASK;
680 1.1 agc else
681 1.1 agc c_phase = (rx_pdu->pdu.Flags >> CSG_SHIFT) & SG_MASK;
682 1.1 agc
683 1.1 agc DEB(99, ("NegotiateLogin: Flags=%x Phase=%x\n",
684 1.1 agc rx_pdu->pdu.Flags, c_phase));
685 1.1 agc
686 1.1 agc if (c_phase == SG_FULL_FEATURE_PHASE) {
687 1.1 agc session_t *sess = conn->session;
688 1.1 agc
689 1.1 agc if (!sess->TSIH)
690 1.1 agc sess->TSIH = ((login_isid_t *) &rx_pdu->pdu.LUN)->TSIH;
691 1.1 agc
692 1.1 agc if (rx_pdu->temp_data != NULL)
693 1.1 agc assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, NULL);
694 1.1 agc
695 1.1 agc /* negotiated values are now valid */
696 1.1 agc set_negotiated_parameters(tx_ccb);
697 1.1 agc
698 1.1 agc DEBC(conn, 5, ("Login Successful!\n"));
699 1.8 mlelstv wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS);
700 1.1 agc return;
701 1.1 agc }
702 1.1 agc
703 1.8 mlelstv tx_pdu = get_pdu(conn, TRUE);
704 1.1 agc if (tx_pdu == NULL)
705 1.1 agc return;
706 1.1 agc
707 1.1 agc tx_pdu->pdu.Flags = c_phase << CSG_SHIFT;
708 1.1 agc
709 1.1 agc switch (c_phase) {
710 1.1 agc case SG_SECURITY_NEGOTIATION:
711 1.1 agc rc = assemble_security_parameters(conn, tx_ccb, rx_pdu, tx_pdu);
712 1.1 agc if (rc < 0)
713 1.1 agc next = FALSE;
714 1.1 agc break;
715 1.1 agc
716 1.1 agc case SG_LOGIN_OPERATIONAL_NEGOTIATION:
717 1.1 agc rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu);
718 1.1 agc break;
719 1.1 agc
720 1.1 agc default:
721 1.1 agc DEBOUT(("Invalid phase %x in negotiate_login\n", c_phase));
722 1.1 agc rc = ISCSI_STATUS_TARGET_ERROR;
723 1.1 agc break;
724 1.1 agc }
725 1.1 agc
726 1.1 agc if (rc > 0) {
727 1.8 mlelstv wake_ccb(tx_ccb, rc);
728 1.1 agc free_pdu(tx_pdu);
729 1.1 agc } else {
730 1.23 mlelstv init_login_pdu(conn, tx_ccb, tx_pdu, next);
731 1.1 agc setup_tx_uio(tx_pdu, tx_pdu->temp_data_len, tx_pdu->temp_data, FALSE);
732 1.1 agc send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE);
733 1.1 agc }
734 1.1 agc }
735 1.1 agc
736 1.1 agc
737 1.1 agc /*
738 1.1 agc * init_text_pdu:
739 1.1 agc * Initialize the text PDU.
740 1.1 agc *
741 1.1 agc * Parameter:
742 1.1 agc * conn The connection
743 1.23 mlelstv * ccb The transmit CCB
744 1.1 agc * ppdu The transmit PDU
745 1.1 agc * rx_pdu The received PDU if this is an unsolicited negotiation
746 1.1 agc */
747 1.1 agc
748 1.1 agc STATIC void
749 1.23 mlelstv init_text_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, pdu_t *rx_pdu)
750 1.1 agc {
751 1.1 agc pdu_header_t *pdu = &ppdu->pdu;
752 1.1 agc
753 1.1 agc pdu->Opcode = IOP_Text_Request | OP_IMMEDIATE;
754 1.1 agc pdu->Flags = FLAG_FINAL;
755 1.1 agc
756 1.28 mlelstv mutex_enter(&conn->session->lock);
757 1.31 mlelstv ccb->CmdSN = get_sernum(conn->session, ppdu);
758 1.28 mlelstv mutex_exit(&conn->session->lock);
759 1.23 mlelstv
760 1.1 agc if (rx_pdu != NULL) {
761 1.1 agc pdu->p.text_req.TargetTransferTag =
762 1.1 agc rx_pdu->pdu.p.text_rsp.TargetTransferTag;
763 1.1 agc pdu->LUN = rx_pdu->pdu.LUN;
764 1.1 agc } else
765 1.1 agc pdu->p.text_req.TargetTransferTag = 0xffffffff;
766 1.1 agc
767 1.23 mlelstv pdu->p.text_req.CmdSN = htonl(ccb->CmdSN);
768 1.1 agc }
769 1.1 agc
770 1.1 agc
771 1.1 agc /*
772 1.1 agc * acknowledge_text:
773 1.1 agc * Acknowledge a continued login or text response.
774 1.1 agc *
775 1.1 agc * Parameter:
776 1.1 agc * conn The connection
777 1.1 agc * rx_pdu The received login/text response PDU
778 1.1 agc * tx_ccb The originally sent login/text request CCB
779 1.1 agc */
780 1.1 agc
781 1.1 agc void
782 1.1 agc acknowledge_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb)
783 1.1 agc {
784 1.1 agc pdu_t *tx_pdu;
785 1.1 agc
786 1.8 mlelstv tx_pdu = get_pdu(conn, TRUE);
787 1.1 agc if (tx_pdu == NULL)
788 1.1 agc return;
789 1.1 agc
790 1.1 agc if (rx_pdu != NULL &&
791 1.1 agc (rx_pdu->pdu.Opcode & OPCODE_MASK) == IOP_Login_Request)
792 1.23 mlelstv init_login_pdu(conn, tx_ccb, tx_pdu, FALSE);
793 1.1 agc else
794 1.23 mlelstv init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu);
795 1.1 agc
796 1.1 agc setup_tx_uio(tx_pdu, 0, NULL, FALSE);
797 1.1 agc send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE);
798 1.1 agc }
799 1.1 agc
800 1.1 agc
801 1.1 agc /*
802 1.1 agc * start_text_negotiation:
803 1.1 agc * Handle target request to negotiate (via asynch event)
804 1.1 agc *
805 1.1 agc * Parameter:
806 1.1 agc * conn The connection
807 1.1 agc */
808 1.1 agc
809 1.1 agc void
810 1.1 agc start_text_negotiation(connection_t *conn)
811 1.1 agc {
812 1.1 agc pdu_t *pdu;
813 1.1 agc ccb_t *ccb;
814 1.1 agc
815 1.1 agc ccb = get_ccb(conn, TRUE);
816 1.3 mlelstv if (ccb == NULL)
817 1.3 mlelstv return;
818 1.8 mlelstv pdu = get_pdu(conn, TRUE);
819 1.3 mlelstv if (pdu == NULL) {
820 1.3 mlelstv free_ccb(ccb);
821 1.1 agc return;
822 1.3 mlelstv }
823 1.1 agc
824 1.1 agc if (init_text_parameters(conn, ccb)) {
825 1.1 agc free_ccb(ccb);
826 1.1 agc free_pdu(pdu);
827 1.1 agc return;
828 1.1 agc }
829 1.1 agc
830 1.23 mlelstv init_text_pdu(conn, ccb, pdu, NULL);
831 1.1 agc setup_tx_uio(pdu, 0, NULL, FALSE);
832 1.1 agc send_pdu(ccb, pdu, CCBDISP_FREE, PDUDISP_WAIT);
833 1.1 agc }
834 1.1 agc
835 1.1 agc
836 1.1 agc /*
837 1.1 agc * negotiate_text:
838 1.1 agc * Handle received text negotiation.
839 1.1 agc *
840 1.1 agc * Parameter:
841 1.1 agc * conn The connection
842 1.1 agc * rx_pdu The received text response PDU
843 1.1 agc * tx_ccb The original CCB
844 1.1 agc */
845 1.1 agc
846 1.1 agc void
847 1.1 agc negotiate_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb)
848 1.1 agc {
849 1.1 agc int rc;
850 1.1 agc pdu_t *tx_pdu;
851 1.1 agc
852 1.1 agc if (tx_ccb->flags & CCBF_SENDTARGET) {
853 1.1 agc if (!(rx_pdu->pdu.Flags & FLAG_FINAL)) {
854 1.1 agc handle_connection_error(conn, ISCSI_STATUS_PROTOCOL_ERROR,
855 1.1 agc LOGOUT_CONNECTION);
856 1.1 agc return;
857 1.1 agc }
858 1.1 agc /* transfer ownership of text to CCB */
859 1.1 agc tx_ccb->text_data = rx_pdu->temp_data;
860 1.1 agc tx_ccb->text_len = rx_pdu->temp_data_len;
861 1.1 agc rx_pdu->temp_data = NULL;
862 1.8 mlelstv wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS);
863 1.1 agc } else {
864 1.1 agc if (!(rx_pdu->pdu.Flags & FLAG_FINAL))
865 1.8 mlelstv tx_pdu = get_pdu(conn, TRUE);
866 1.1 agc else
867 1.1 agc tx_pdu = NULL;
868 1.1 agc
869 1.1 agc rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu);
870 1.1 agc if (rc) {
871 1.1 agc if (tx_pdu != NULL)
872 1.1 agc free_pdu(tx_pdu);
873 1.1 agc
874 1.1 agc handle_connection_error(conn, rc, LOGOUT_CONNECTION);
875 1.1 agc } else if (tx_pdu != NULL) {
876 1.23 mlelstv init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu);
877 1.32 mlelstv setup_tx_uio(tx_pdu, tx_pdu->temp_data_len,
878 1.32 mlelstv tx_pdu->temp_data, FALSE);
879 1.1 agc send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE);
880 1.1 agc } else {
881 1.1 agc set_negotiated_parameters(tx_ccb);
882 1.8 mlelstv wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS);
883 1.1 agc }
884 1.1 agc }
885 1.1 agc }
886 1.1 agc
887 1.1 agc
888 1.1 agc /*
889 1.1 agc * send_send_targets:
890 1.1 agc * Send out a SendTargets text request.
891 1.1 agc * The result is stored in the fields in the session structure.
892 1.1 agc *
893 1.1 agc * Parameter:
894 1.1 agc * session The session
895 1.1 agc * key The text key to use
896 1.1 agc *
897 1.1 agc * Returns: 0 on success, else an error code.
898 1.1 agc */
899 1.1 agc
900 1.1 agc int
901 1.1 agc send_send_targets(session_t *session, uint8_t *key)
902 1.1 agc {
903 1.1 agc ccb_t *ccb;
904 1.1 agc pdu_t *pdu;
905 1.1 agc int rc = 0;
906 1.1 agc connection_t *conn;
907 1.1 agc
908 1.1 agc DEB(9, ("Send_send_targets\n"));
909 1.1 agc
910 1.1 agc conn = assign_connection(session, TRUE);
911 1.1 agc if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE)
912 1.1 agc return (conn != NULL && conn->terminating) ? conn->terminating
913 1.1 agc : ISCSI_STATUS_CONNECTION_FAILED;
914 1.1 agc
915 1.1 agc ccb = get_ccb(conn, TRUE);
916 1.3 mlelstv if (ccb == NULL)
917 1.3 mlelstv return conn->terminating;
918 1.8 mlelstv pdu = get_pdu(conn, TRUE);
919 1.3 mlelstv if (pdu == NULL) {
920 1.3 mlelstv free_ccb(ccb);
921 1.1 agc return conn->terminating;
922 1.3 mlelstv }
923 1.1 agc
924 1.1 agc ccb->flags |= CCBF_SENDTARGET;
925 1.1 agc
926 1.1 agc if ((rc = assemble_send_targets(pdu, key)) != 0) {
927 1.1 agc free_ccb(ccb);
928 1.1 agc free_pdu(pdu);
929 1.1 agc return rc;
930 1.1 agc }
931 1.1 agc
932 1.23 mlelstv init_text_pdu(conn, ccb, pdu, NULL);
933 1.1 agc
934 1.1 agc setup_tx_uio(pdu, pdu->temp_data_len, pdu->temp_data, FALSE);
935 1.1 agc send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_WAIT);
936 1.1 agc
937 1.1 agc rc = ccb->status;
938 1.1 agc if (!rc) {
939 1.1 agc /* transfer ownership of data */
940 1.1 agc session->target_list = ccb->text_data;
941 1.1 agc session->target_list_len = ccb->text_len;
942 1.1 agc ccb->text_data = NULL;
943 1.1 agc }
944 1.1 agc free_ccb(ccb);
945 1.1 agc return rc;
946 1.1 agc }
947 1.1 agc
948 1.1 agc
949 1.1 agc /*
950 1.1 agc * send_nop_out:
951 1.1 agc * Send nop out request.
952 1.1 agc *
953 1.1 agc * Parameter:
954 1.1 agc * conn The connection
955 1.1 agc * rx_pdu The received Nop-In PDU
956 1.1 agc *
957 1.1 agc * Returns: 0 on success, else an error code.
958 1.1 agc */
959 1.1 agc
960 1.1 agc int
961 1.1 agc send_nop_out(connection_t *conn, pdu_t *rx_pdu)
962 1.1 agc {
963 1.31 mlelstv session_t *sess;
964 1.1 agc ccb_t *ccb;
965 1.1 agc pdu_t *ppdu;
966 1.1 agc pdu_header_t *pdu;
967 1.31 mlelstv uint32_t sn;
968 1.1 agc
969 1.1 agc if (rx_pdu != NULL) {
970 1.1 agc ccb = NULL;
971 1.8 mlelstv ppdu = get_pdu(conn, TRUE);
972 1.1 agc if (ppdu == NULL)
973 1.1 agc return 1;
974 1.1 agc } else {
975 1.1 agc ccb = get_ccb(conn, FALSE);
976 1.1 agc if (ccb == NULL) {
977 1.1 agc DEBOUT(("Can't get CCB in send_nop_out\n"));
978 1.1 agc return 1;
979 1.1 agc }
980 1.8 mlelstv ppdu = get_pdu(conn, FALSE);
981 1.1 agc if (ppdu == NULL) {
982 1.1 agc free_ccb(ccb);
983 1.1 agc DEBOUT(("Can't get PDU in send_nop_out\n"));
984 1.1 agc return 1;
985 1.1 agc }
986 1.1 agc }
987 1.1 agc
988 1.1 agc pdu = &ppdu->pdu;
989 1.1 agc pdu->Flags = FLAG_FINAL;
990 1.1 agc pdu->Opcode = IOP_NOP_Out | OP_IMMEDIATE;
991 1.1 agc
992 1.31 mlelstv sess = conn->session;
993 1.31 mlelstv
994 1.31 mlelstv mutex_enter(&sess->lock);
995 1.31 mlelstv sn = get_sernum(sess, ppdu);
996 1.31 mlelstv mutex_exit(&sess->lock);
997 1.31 mlelstv
998 1.1 agc if (rx_pdu != NULL) {
999 1.1 agc pdu->p.nop_out.TargetTransferTag =
1000 1.1 agc rx_pdu->pdu.p.nop_in.TargetTransferTag;
1001 1.1 agc pdu->InitiatorTaskTag = rx_pdu->pdu.InitiatorTaskTag;
1002 1.31 mlelstv pdu->p.nop_out.CmdSN = htonl(sn);
1003 1.1 agc pdu->LUN = rx_pdu->pdu.LUN;
1004 1.1 agc } else {
1005 1.1 agc pdu->p.nop_out.TargetTransferTag = 0xffffffff;
1006 1.31 mlelstv pdu->InitiatorTaskTag = 0xffffffff;
1007 1.31 mlelstv ccb->CmdSN = sn;
1008 1.31 mlelstv pdu->p.nop_out.CmdSN = htonl(sn);
1009 1.1 agc }
1010 1.1 agc
1011 1.31 mlelstv DEBC(conn, 10, ("Send NOP_Out CmdSN=%d, rx_pdu=%p\n", sn, rx_pdu));
1012 1.31 mlelstv
1013 1.1 agc setup_tx_uio(ppdu, 0, NULL, FALSE);
1014 1.1 agc send_pdu(ccb, ppdu, (rx_pdu != NULL) ? CCBDISP_NOWAIT : CCBDISP_FREE,
1015 1.1 agc PDUDISP_FREE);
1016 1.1 agc return 0;
1017 1.1 agc }
1018 1.1 agc
1019 1.1 agc
1020 1.1 agc /*
1021 1.1 agc * snack_missing:
1022 1.1 agc * Send SNACK request for missing data.
1023 1.1 agc *
1024 1.1 agc * Parameter:
1025 1.1 agc * conn The connection
1026 1.1 agc * ccb The task's CCB (for Data NAK only)
1027 1.1 agc * type The SNACK type
1028 1.1 agc * BegRun The BegRun field
1029 1.1 agc * RunLength The RunLength field
1030 1.1 agc */
1031 1.1 agc
1032 1.1 agc void
1033 1.1 agc snack_missing(connection_t *conn, ccb_t *ccb, uint8_t type,
1034 1.1 agc uint32_t BegRun, uint32_t RunLength)
1035 1.1 agc {
1036 1.1 agc pdu_t *ppdu;
1037 1.1 agc pdu_header_t *pdu;
1038 1.1 agc
1039 1.8 mlelstv ppdu = get_pdu(conn, TRUE);
1040 1.1 agc if (ppdu == NULL)
1041 1.1 agc return;
1042 1.1 agc pdu = &ppdu->pdu;
1043 1.1 agc pdu->Opcode = IOP_SNACK_Request;
1044 1.1 agc pdu->Flags = FLAG_FINAL | type;
1045 1.1 agc
1046 1.1 agc pdu->InitiatorTaskTag = (type == SNACK_DATA_NAK) ? ccb->ITT : 0xffffffff;
1047 1.1 agc pdu->p.snack.TargetTransferTag = 0xffffffff;
1048 1.1 agc pdu->p.snack.BegRun = htonl(BegRun);
1049 1.1 agc pdu->p.snack.RunLength = htonl(RunLength);
1050 1.1 agc
1051 1.1 agc ppdu->flags = PDUF_PRIORITY;
1052 1.1 agc
1053 1.1 agc setup_tx_uio(ppdu, 0, NULL, FALSE);
1054 1.1 agc send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE);
1055 1.1 agc }
1056 1.1 agc
1057 1.1 agc
1058 1.1 agc /*
1059 1.1 agc * send_snack:
1060 1.1 agc * Send SNACK request.
1061 1.1 agc *
1062 1.1 agc * Parameter:
1063 1.1 agc * conn The connection
1064 1.1 agc * rx_pdu The received data in PDU
1065 1.1 agc * tx_ccb The original command CCB (required for Data ACK only)
1066 1.1 agc * type The SNACK type
1067 1.1 agc *
1068 1.1 agc * Returns: 0 on success, else an error code.
1069 1.1 agc */
1070 1.1 agc
1071 1.1 agc void
1072 1.1 agc send_snack(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb, uint8_t type)
1073 1.1 agc {
1074 1.1 agc pdu_t *ppdu;
1075 1.1 agc pdu_header_t *pdu;
1076 1.1 agc
1077 1.8 mlelstv ppdu = get_pdu(conn, TRUE);
1078 1.1 agc if (ppdu == NULL)
1079 1.1 agc return;
1080 1.1 agc pdu = &ppdu->pdu;
1081 1.1 agc pdu->Opcode = IOP_SNACK_Request;
1082 1.1 agc pdu->Flags = FLAG_FINAL | type;
1083 1.1 agc
1084 1.1 agc switch (type) {
1085 1.1 agc case SNACK_DATA_NAK:
1086 1.1 agc pdu->InitiatorTaskTag = rx_pdu->pdu.InitiatorTaskTag;
1087 1.1 agc pdu->p.snack.TargetTransferTag = 0xffffffff;
1088 1.1 agc pdu->p.snack.BegRun = rx_pdu->pdu.p.data_in.DataSN;
1089 1.1 agc pdu->p.snack.RunLength = htonl(1);
1090 1.1 agc break;
1091 1.1 agc
1092 1.1 agc case SNACK_STATUS_NAK:
1093 1.1 agc pdu->InitiatorTaskTag = 0xffffffff;
1094 1.1 agc pdu->p.snack.TargetTransferTag = 0xffffffff;
1095 1.1 agc pdu->p.snack.BegRun = rx_pdu->pdu.p.response.StatSN;
1096 1.1 agc pdu->p.snack.RunLength = htonl(1);
1097 1.1 agc break;
1098 1.1 agc
1099 1.1 agc case SNACK_DATA_ACK:
1100 1.1 agc pdu->InitiatorTaskTag = 0xffffffff;
1101 1.1 agc pdu->p.snack.TargetTransferTag =
1102 1.1 agc rx_pdu->pdu.p.data_in.TargetTransferTag;
1103 1.1 agc pdu->p.snack.BegRun = tx_ccb->DataSN_buf.ExpSN;
1104 1.1 agc pdu->p.snack.RunLength = 0;
1105 1.1 agc break;
1106 1.1 agc
1107 1.1 agc default:
1108 1.1 agc DEBOUT(("Invalid type %d in send_snack\n", type));
1109 1.1 agc return;
1110 1.1 agc }
1111 1.1 agc
1112 1.1 agc pdu->LUN = rx_pdu->pdu.LUN;
1113 1.1 agc
1114 1.1 agc ppdu->flags = PDUF_PRIORITY;
1115 1.1 agc
1116 1.1 agc setup_tx_uio(ppdu, 0, NULL, FALSE);
1117 1.1 agc send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE);
1118 1.1 agc }
1119 1.1 agc
1120 1.1 agc
1121 1.1 agc /*
1122 1.1 agc * send_login:
1123 1.1 agc * Send login request.
1124 1.1 agc *
1125 1.1 agc * Parameter:
1126 1.1 agc * conn The connection
1127 1.1 agc * par The login parameters (for negotiation)
1128 1.1 agc *
1129 1.1 agc * Returns: 0 on success, else an error code.
1130 1.1 agc */
1131 1.1 agc
1132 1.1 agc int
1133 1.1 agc send_login(connection_t *conn)
1134 1.1 agc {
1135 1.1 agc ccb_t *ccb;
1136 1.1 agc pdu_t *pdu;
1137 1.1 agc int rc;
1138 1.1 agc
1139 1.1 agc DEBC(conn, 9, ("Send_login\n"));
1140 1.1 agc ccb = get_ccb(conn, TRUE);
1141 1.3 mlelstv /* only if terminating (which couldn't possibly happen here, but...) */
1142 1.3 mlelstv if (ccb == NULL)
1143 1.3 mlelstv return conn->terminating;
1144 1.8 mlelstv pdu = get_pdu(conn, TRUE);
1145 1.3 mlelstv if (pdu == NULL) {
1146 1.3 mlelstv free_ccb(ccb);
1147 1.1 agc return conn->terminating;
1148 1.1 agc }
1149 1.3 mlelstv
1150 1.4 martin if ((rc = assemble_login_parameters(conn, ccb, pdu)) <= 0) {
1151 1.23 mlelstv init_login_pdu(conn, ccb, pdu, !rc);
1152 1.1 agc setup_tx_uio(pdu, pdu->temp_data_len, pdu->temp_data, FALSE);
1153 1.1 agc send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_FREE);
1154 1.1 agc rc = ccb->status;
1155 1.1 agc } else {
1156 1.1 agc free_pdu(pdu);
1157 1.1 agc }
1158 1.1 agc free_ccb(ccb);
1159 1.1 agc return rc;
1160 1.1 agc }
1161 1.1 agc
1162 1.1 agc
1163 1.1 agc /*
1164 1.1 agc * send_logout:
1165 1.1 agc * Send logout request.
1166 1.1 agc * NOTE: This function does not wait for the logout to complete.
1167 1.1 agc *
1168 1.1 agc * Parameter:
1169 1.1 agc * conn The connection
1170 1.1 agc * refconn The referenced connection
1171 1.1 agc * reason The reason code
1172 1.1 agc * wait Wait for completion if TRUE
1173 1.1 agc *
1174 1.1 agc * Returns: 0 on success (logout sent), else an error code.
1175 1.1 agc */
1176 1.1 agc
1177 1.1 agc int
1178 1.1 agc send_logout(connection_t *conn, connection_t *refconn, int reason,
1179 1.1 agc bool wait)
1180 1.1 agc {
1181 1.1 agc ccb_t *ccb;
1182 1.1 agc pdu_t *ppdu;
1183 1.1 agc pdu_header_t *pdu;
1184 1.1 agc
1185 1.1 agc DEBC(conn, 5, ("Send_logout\n"));
1186 1.1 agc ccb = get_ccb(conn, TRUE);
1187 1.3 mlelstv /* can only happen if terminating... */
1188 1.3 mlelstv if (ccb == NULL)
1189 1.3 mlelstv return conn->terminating;
1190 1.8 mlelstv ppdu = get_pdu(conn, TRUE);
1191 1.3 mlelstv if (ppdu == NULL) {
1192 1.3 mlelstv free_ccb(ccb);
1193 1.1 agc return conn->terminating;
1194 1.3 mlelstv }
1195 1.1 agc
1196 1.1 agc pdu = &ppdu->pdu;
1197 1.1 agc pdu->Opcode = IOP_Logout_Request | OP_IMMEDIATE;
1198 1.1 agc
1199 1.1 agc pdu->Flags = FLAG_FINAL | reason;
1200 1.1 agc ccb->CmdSN = conn->session->CmdSN;
1201 1.1 agc pdu->p.logout_req.CmdSN = htonl(ccb->CmdSN);
1202 1.1 agc if (reason > 0)
1203 1.1 agc pdu->p.logout_req.CID = htons(refconn->id);
1204 1.1 agc
1205 1.1 agc ccb->par = refconn;
1206 1.1 agc if (refconn != conn) {
1207 1.1 agc ccb->flags |= CCBF_OTHERCONN;
1208 1.1 agc } else {
1209 1.1 agc conn->state = ST_LOGOUT_SENT;
1210 1.1 agc conn->loggedout = LOGOUT_SENT;
1211 1.1 agc }
1212 1.1 agc
1213 1.1 agc setup_tx_uio(ppdu, 0, NULL, FALSE);
1214 1.1 agc send_pdu(ccb, ppdu, (wait) ? CCBDISP_WAIT : CCBDISP_FREE, PDUDISP_FREE);
1215 1.1 agc
1216 1.1 agc if (wait) {
1217 1.1 agc int rc = ccb->status;
1218 1.1 agc free_ccb (ccb);
1219 1.1 agc return rc;
1220 1.1 agc }
1221 1.1 agc return 0;
1222 1.1 agc }
1223 1.1 agc
1224 1.1 agc
1225 1.1 agc /*
1226 1.1 agc * send_task_management:
1227 1.1 agc * Send task management request.
1228 1.1 agc *
1229 1.1 agc * Parameter:
1230 1.1 agc * conn The connection
1231 1.1 agc * ref_ccb The referenced command (NULL if none)
1232 1.1 agc * xs The scsipi command structure (NULL if not a scsipi request)
1233 1.1 agc * function The function code
1234 1.1 agc *
1235 1.1 agc * Returns: 0 on success, else an error code.
1236 1.1 agc */
1237 1.1 agc
1238 1.1 agc int
1239 1.1 agc send_task_management(connection_t *conn, ccb_t *ref_ccb, struct scsipi_xfer *xs,
1240 1.1 agc int function)
1241 1.1 agc {
1242 1.1 agc ccb_t *ccb;
1243 1.1 agc pdu_t *ppdu;
1244 1.1 agc pdu_header_t *pdu;
1245 1.1 agc
1246 1.1 agc DEBC(conn, 5, ("Send_task_management, ref_ccb=%p, func = %d\n",
1247 1.1 agc ref_ccb, function));
1248 1.1 agc
1249 1.1 agc if (function == TASK_REASSIGN && conn->session->ErrorRecoveryLevel < 2)
1250 1.1 agc return ISCSI_STATUS_CANT_REASSIGN;
1251 1.1 agc
1252 1.1 agc ccb = get_ccb(conn, xs == NULL);
1253 1.3 mlelstv /* can only happen if terminating... */
1254 1.3 mlelstv if (ccb == NULL)
1255 1.3 mlelstv return conn->terminating;
1256 1.19 mlelstv ppdu = get_pdu(conn, xs == NULL);
1257 1.3 mlelstv if (ppdu == NULL) {
1258 1.3 mlelstv free_ccb(ccb);
1259 1.1 agc return conn->terminating;
1260 1.3 mlelstv }
1261 1.1 agc
1262 1.1 agc ccb->xs = xs;
1263 1.1 agc
1264 1.1 agc pdu = &ppdu->pdu;
1265 1.1 agc pdu->Opcode = IOP_SCSI_Task_Management | OP_IMMEDIATE;
1266 1.1 agc pdu->Flags = FLAG_FINAL | function;
1267 1.1 agc
1268 1.1 agc ccb->CmdSN = conn->session->CmdSN;
1269 1.1 agc pdu->p.task_req.CmdSN = htonl(ccb->CmdSN);
1270 1.1 agc
1271 1.1 agc if (ref_ccb != NULL) {
1272 1.1 agc pdu->p.task_req.ReferencedTaskTag = ref_ccb->ITT;
1273 1.1 agc pdu->p.task_req.RefCmdSN = htonl(ref_ccb->CmdSN);
1274 1.1 agc pdu->p.task_req.ExpDataSN = htonl(ref_ccb->DataSN_buf.ExpSN);
1275 1.1 agc } else
1276 1.1 agc pdu->p.task_req.ReferencedTaskTag = 0xffffffff;
1277 1.1 agc
1278 1.1 agc ppdu->flags |= PDUF_PRIORITY;
1279 1.1 agc
1280 1.1 agc setup_tx_uio(ppdu, 0, NULL, FALSE);
1281 1.1 agc send_pdu(ccb, ppdu, (xs) ? CCBDISP_SCSIPI : CCBDISP_WAIT, PDUDISP_FREE);
1282 1.1 agc
1283 1.1 agc if (xs == NULL) {
1284 1.1 agc int rc = ccb->status;
1285 1.1 agc free_ccb(ccb);
1286 1.1 agc return rc;
1287 1.1 agc }
1288 1.1 agc return 0;
1289 1.1 agc }
1290 1.1 agc
1291 1.1 agc
1292 1.1 agc /*
1293 1.1 agc * send_data_out:
1294 1.1 agc * Send data to target in response to an R2T or as unsolicited data.
1295 1.1 agc *
1296 1.1 agc * Parameter:
1297 1.1 agc * conn The connection
1298 1.1 agc * rx_pdu The received R2T PDU (NULL if unsolicited)
1299 1.1 agc * tx_ccb The originally sent command CCB
1300 1.1 agc * waitok Whether it's OK to wait for an available PDU or not
1301 1.1 agc */
1302 1.1 agc
1303 1.1 agc int
1304 1.1 agc send_data_out(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb,
1305 1.1 agc ccb_disp_t disp, bool waitok)
1306 1.1 agc {
1307 1.1 agc pdu_header_t *pdu;
1308 1.1 agc uint32_t totlen, len, offs, sn;
1309 1.1 agc pdu_t *tx_pdu;
1310 1.1 agc
1311 1.16 mlelstv KASSERT(conn->max_transfer != 0);
1312 1.1 agc
1313 1.1 agc if (rx_pdu) {
1314 1.1 agc offs = ntohl(rx_pdu->pdu.p.r2t.BufferOffset);
1315 1.1 agc totlen = ntohl(rx_pdu->pdu.p.r2t.DesiredDataTransferLength);
1316 1.1 agc } else {
1317 1.1 agc offs = conn->max_firstimmed;
1318 1.1 agc totlen = min(conn->max_firstdata - offs, tx_ccb->data_len - offs);
1319 1.1 agc }
1320 1.1 agc sn = 0;
1321 1.1 agc
1322 1.1 agc while (totlen) {
1323 1.1 agc len = min(totlen, conn->max_transfer);
1324 1.1 agc
1325 1.8 mlelstv tx_pdu = get_pdu(conn, waitok);
1326 1.1 agc if (tx_pdu == NULL) {
1327 1.16 mlelstv DEBC(conn, 5, ("No PDU in send_data_out\n"));
1328 1.1 agc
1329 1.8 mlelstv tx_ccb->disp = disp;
1330 1.1 agc tx_ccb->status = ISCSI_STATUS_NO_RESOURCES;
1331 1.1 agc handle_connection_error(conn, ISCSI_STATUS_NO_RESOURCES, NO_LOGOUT);
1332 1.1 agc
1333 1.1 agc return ISCSI_STATUS_NO_RESOURCES;
1334 1.1 agc }
1335 1.1 agc
1336 1.1 agc totlen -= len;
1337 1.1 agc pdu = &tx_pdu->pdu;
1338 1.1 agc pdu->Opcode = IOP_SCSI_Data_out;
1339 1.1 agc if (!totlen)
1340 1.1 agc pdu->Flags = FLAG_FINAL;
1341 1.1 agc
1342 1.1 agc if (rx_pdu != NULL)
1343 1.1 agc pdu->p.data_out.TargetTransferTag =
1344 1.1 agc rx_pdu->pdu.p.r2t.TargetTransferTag;
1345 1.1 agc else
1346 1.1 agc pdu->p.data_out.TargetTransferTag = 0xffffffff;
1347 1.1 agc pdu->p.data_out.BufferOffset = htonl(offs);
1348 1.1 agc pdu->p.data_out.DataSN = htonl(sn);
1349 1.1 agc
1350 1.1 agc DEBC(conn, 10, ("Send DataOut: DataSN %d, len %d offs %x totlen %d\n",
1351 1.1 agc sn, len, offs, totlen));
1352 1.1 agc
1353 1.1 agc setup_tx_uio(tx_pdu, len, tx_ccb->data_ptr + offs, FALSE);
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.1 agc
1381 1.16 mlelstv mutex_enter(&sess->lock);
1382 1.31 mlelstv while (!sernum_in_window(sess)) {
1383 1.31 mlelstv mutex_exit(&sess->lock);
1384 1.31 mlelstv ccb->disp = disp;
1385 1.31 mlelstv wake_ccb(ccb, ISCSI_STATUS_QUEUE_FULL);
1386 1.31 mlelstv return;
1387 1.31 mlelstv }
1388 1.31 mlelstv mutex_exit(&sess->lock);
1389 1.8 mlelstv
1390 1.31 mlelstv /* Don't confuse targets during (re-)negotations */
1391 1.31 mlelstv if (conn->state != ST_FULL_FEATURE) {
1392 1.31 mlelstv DEBOUT(("Invalid connection for send_command, ccb = %p\n",ccb));
1393 1.8 mlelstv ccb->disp = disp;
1394 1.31 mlelstv wake_ccb(ccb, ISCSI_STATUS_TARGET_BUSY);
1395 1.31 mlelstv return;
1396 1.8 mlelstv }
1397 1.16 mlelstv
1398 1.19 mlelstv ppdu = get_pdu(conn, waitok);
1399 1.8 mlelstv if (ppdu == NULL) {
1400 1.16 mlelstv DEBOUT(("No PDU for send_command, ccb = %p\n",ccb));
1401 1.16 mlelstv 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.25 mlelstv 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.16 mlelstv mutex_enter(&sess->lock);
1442 1.31 mlelstv ccb->CmdSN = get_sernum(sess, ppdu);
1443 1.16 mlelstv 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.21 mlelstv DEBC(conn, 10, ("Send Command: CmdSN %d (%d), data_in %d, len %d, totlen %d\n",
1448 1.21 mlelstv 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.33 mlelstv unref_session(session);
1487 1.1 agc return;
1488 1.1 agc }
1489 1.1 agc
1490 1.1 agc if (xs->xs_control & XS_CTL_RESET) {
1491 1.1 agc if (send_task_management(conn, NULL, xs, TARGET_WARM_RESET)) {
1492 1.1 agc xs->error = XS_SELTIMEOUT;
1493 1.1 agc scsipi_done(xs);
1494 1.33 mlelstv unref_session(session);
1495 1.1 agc }
1496 1.1 agc return;
1497 1.1 agc }
1498 1.1 agc
1499 1.1 agc ccb = get_ccb(conn, waitok);
1500 1.1 agc if (ccb == NULL) {
1501 1.8 mlelstv xs->error = XS_BUSY;
1502 1.16 mlelstv DEBC(conn, 5, ("No CCB in run_xfer, %d in use.\n", conn->usecount));
1503 1.1 agc scsipi_done(xs);
1504 1.33 mlelstv unref_session(session);
1505 1.1 agc return;
1506 1.1 agc }
1507 1.1 agc /* copy parameters into CCB for easier access */
1508 1.1 agc ccb->xs = xs;
1509 1.1 agc
1510 1.1 agc ccb->data_in = (xs->xs_control & XS_CTL_DATA_IN) != 0;
1511 1.1 agc ccb->data_len = (uint32_t) xs->datalen;
1512 1.1 agc ccb->data_ptr = xs->data;
1513 1.1 agc
1514 1.1 agc ccb->sense_len_req = sizeof(xs->sense.scsi_sense);
1515 1.1 agc ccb->sense_ptr = &xs->sense;
1516 1.1 agc
1517 1.8 mlelstv ccb->lun = ((uint64_t) (uint8_t) xs->xs_periph->periph_lun) << 48;
1518 1.1 agc ccb->cmd = (uint8_t *) xs->cmd;
1519 1.1 agc ccb->cmdlen = xs->cmdlen;
1520 1.1 agc DEB(10, ("RunXfer: Periph_lun = %d, cmd[1] = %x, cmdlen = %d\n",
1521 1.1 agc xs->xs_periph->periph_lun, ccb->cmd[1], xs->cmdlen));
1522 1.1 agc
1523 1.25 mlelstv ccb->ITT |= xs->xs_tag_id << 24;
1524 1.25 mlelstv switch (xs->xs_tag_type) {
1525 1.25 mlelstv case MSG_ORDERED_Q_TAG:
1526 1.25 mlelstv ccb->tag = ATTR_ORDERED;
1527 1.25 mlelstv break;
1528 1.25 mlelstv case MSG_SIMPLE_Q_TAG:
1529 1.25 mlelstv ccb->tag = ATTR_SIMPLE;
1530 1.25 mlelstv break;
1531 1.25 mlelstv case MSG_HEAD_OF_Q_TAG:
1532 1.25 mlelstv ccb->tag = ATTR_HEAD_OF_QUEUE;
1533 1.25 mlelstv break;
1534 1.25 mlelstv default:
1535 1.25 mlelstv ccb->tag = 0;
1536 1.25 mlelstv break;
1537 1.25 mlelstv }
1538 1.25 mlelstv
1539 1.1 agc #ifdef LUN_1
1540 1.1 agc ccb->lun += 0x1000000000000LL;
1541 1.1 agc ccb->cmd[1] += 0x10;
1542 1.1 agc #endif
1543 1.1 agc send_command(ccb, CCBDISP_SCSIPI, waitok, FALSE);
1544 1.1 agc }
1545 1.1 agc
1546 1.1 agc
1547 1.1 agc #ifndef ISCSI_MINIMAL
1548 1.1 agc /*
1549 1.1 agc * send_io_command:
1550 1.1 agc * Handle a SCSI io command request from user space.
1551 1.1 agc *
1552 1.1 agc * Parameter:
1553 1.1 agc * session The session
1554 1.1 agc * lun The LUN to use
1555 1.1 agc * req The SCSI request block
1556 1.1 agc * immed Immediate command if TRUE
1557 1.1 agc * conn_id Assign to this connection ID if nonzero
1558 1.1 agc */
1559 1.1 agc
1560 1.1 agc int
1561 1.1 agc send_io_command(session_t *session, uint64_t lun, scsireq_t *req,
1562 1.1 agc bool immed, uint32_t conn_id)
1563 1.1 agc {
1564 1.1 agc ccb_t *ccb;
1565 1.1 agc connection_t *conn;
1566 1.1 agc int rc;
1567 1.1 agc
1568 1.1 agc DEB(9, ("IoCommand: lun=%x, datalen=%d, cmdlen=%d, immed=%d, cid=%d\n",
1569 1.1 agc (int) lun, (int) req->datalen, (int) req->cmdlen, immed, conn_id));
1570 1.1 agc
1571 1.1 agc conn = (conn_id) ? find_connection(session, conn_id)
1572 1.1 agc : assign_connection(session, TRUE);
1573 1.1 agc
1574 1.1 agc if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) {
1575 1.1 agc DEBOUT(("io_command on dead connection (state = %d)\n",
1576 1.1 agc (conn != NULL) ? conn->state : -1));
1577 1.1 agc return ISCSI_STATUS_INVALID_CONNECTION_ID;
1578 1.1 agc }
1579 1.1 agc
1580 1.1 agc ccb = get_ccb(conn, TRUE);
1581 1.1 agc if (ccb == NULL) {
1582 1.1 agc DEBOUT(("No CCB in io_command\n"));
1583 1.1 agc return ISCSI_STATUS_NO_RESOURCES;
1584 1.1 agc }
1585 1.1 agc
1586 1.1 agc ccb->data_in = (req->flags & SCCMD_READ) != 0;
1587 1.1 agc ccb->data_len = (uint32_t) req->datalen;
1588 1.1 agc ccb->data_ptr = req->databuf;
1589 1.1 agc
1590 1.1 agc ccb->sense_len_req = req->senselen;
1591 1.1 agc ccb->sense_ptr = &req->sense;
1592 1.1 agc
1593 1.1 agc ccb->lun = lun;
1594 1.1 agc ccb->cmd = (uint8_t *) req->cmd;
1595 1.1 agc ccb->cmdlen = req->cmdlen;
1596 1.1 agc DEBC(conn, 10, ("IoCommand: cmd[1] = %x, cmdlen = %d\n",
1597 1.1 agc ccb->cmd[1], ccb->cmdlen));
1598 1.1 agc
1599 1.1 agc send_command(ccb, CCBDISP_WAIT, TRUE, immed);
1600 1.1 agc
1601 1.1 agc rc = ccb->status;
1602 1.1 agc
1603 1.1 agc req->senselen_used = ccb->sense_len_got;
1604 1.1 agc req->datalen_used = req->datalen - ccb->residual;
1605 1.1 agc
1606 1.1 agc free_ccb(ccb);
1607 1.1 agc
1608 1.1 agc return rc;
1609 1.1 agc }
1610 1.1 agc #endif
1611 1.1 agc
1612 1.1 agc
1613 1.1 agc /*****************************************************************************
1614 1.1 agc * Timeout handlers
1615 1.1 agc *****************************************************************************/
1616 1.1 agc /*
1617 1.1 agc * connection_timeout:
1618 1.1 agc * Handle prolonged silence on a connection by checking whether
1619 1.1 agc * it's still alive.
1620 1.1 agc * This has the side effect of discovering missing status or lost commands
1621 1.1 agc * before those time out.
1622 1.1 agc *
1623 1.1 agc * Parameter:
1624 1.16 mlelstv * conn The connection
1625 1.1 agc */
1626 1.1 agc
1627 1.1 agc void
1628 1.16 mlelstv connection_timeout(connection_t *conn)
1629 1.1 agc {
1630 1.1 agc
1631 1.1 agc if (++conn->num_timeouts > MAX_CONN_TIMEOUTS)
1632 1.1 agc handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, NO_LOGOUT);
1633 1.1 agc else {
1634 1.1 agc if (conn->state == ST_FULL_FEATURE)
1635 1.1 agc send_nop_out(conn, NULL);
1636 1.1 agc
1637 1.18 mlelstv connection_timeout_start(conn, CONNECTION_TIMEOUT);
1638 1.1 agc }
1639 1.1 agc }
1640 1.1 agc
1641 1.1 agc /*
1642 1.1 agc * ccb_timeout:
1643 1.1 agc * Handle timeout of a sent command.
1644 1.1 agc *
1645 1.1 agc * Parameter:
1646 1.16 mlelstv * ccb The CCB
1647 1.1 agc */
1648 1.1 agc
1649 1.1 agc void
1650 1.16 mlelstv ccb_timeout(ccb_t *ccb)
1651 1.1 agc {
1652 1.1 agc connection_t *conn = ccb->connection;
1653 1.1 agc
1654 1.1 agc ccb->total_tries++;
1655 1.1 agc
1656 1.16 mlelstv DEBC(conn, 0, ("ccb_timeout: num=%d total=%d disp=%d\n",
1657 1.16 mlelstv ccb->num_timeouts+1, ccb->total_tries, ccb->disp));
1658 1.16 mlelstv
1659 1.1 agc if (++ccb->num_timeouts > MAX_CCB_TIMEOUTS ||
1660 1.1 agc ccb->total_tries > MAX_CCB_TRIES ||
1661 1.1 agc ccb->disp <= CCBDISP_FREE ||
1662 1.1 agc !ccb->session->ErrorRecoveryLevel) {
1663 1.3 mlelstv
1664 1.8 mlelstv wake_ccb(ccb, ISCSI_STATUS_TIMEOUT);
1665 1.3 mlelstv handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION);
1666 1.1 agc } else {
1667 1.1 agc if (ccb->data_in && ccb->xfer_len < ccb->data_len) {
1668 1.1 agc /* request resend of all missing data */
1669 1.1 agc snack_missing(conn, ccb, SNACK_DATA_NAK, 0, 0);
1670 1.1 agc } else {
1671 1.1 agc /* request resend of all missing status */
1672 1.1 agc snack_missing(conn, NULL, SNACK_STATUS_NAK, 0, 0);
1673 1.1 agc }
1674 1.18 mlelstv ccb_timeout_start(ccb, COMMAND_TIMEOUT);
1675 1.1 agc }
1676 1.1 agc }
1677 1.16 mlelstv
1678