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