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