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