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