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