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