]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/iscsi/iscsi.c
MFC r368207,368607:
[FreeBSD/stable/10.git] / sys / dev / iscsi / iscsi.c
1 /*-
2  * Copyright (c) 2012 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Edward Tomasz Napierala under sponsorship
6  * from the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/condvar.h>
36 #include <sys/conf.h>
37 #include <sys/eventhandler.h>
38 #include <sys/file.h>
39 #include <sys/kernel.h>
40 #include <sys/kthread.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/mutex.h>
44 #include <sys/module.h>
45 #include <sys/sysctl.h>
46 #include <sys/systm.h>
47 #include <sys/sx.h>
48 #include <vm/uma.h>
49
50 #include <cam/cam.h>
51 #include <cam/cam_ccb.h>
52 #include <cam/cam_xpt.h>
53 #include <cam/cam_debug.h>
54 #include <cam/cam_sim.h>
55 #include <cam/cam_xpt_sim.h>
56 #include <cam/cam_xpt_periph.h>
57 #include <cam/cam_periph.h>
58 #include <cam/scsi/scsi_all.h>
59 #include <cam/scsi/scsi_message.h>
60
61 #include <dev/iscsi/icl.h>
62 #include <dev/iscsi/iscsi_ioctl.h>
63 #include <dev/iscsi/iscsi_proto.h>
64 #include <dev/iscsi/iscsi.h>
65
66 #ifdef ICL_KERNEL_PROXY
67 #include <sys/socketvar.h>
68 #endif
69
70 #ifdef ICL_KERNEL_PROXY
71 FEATURE(iscsi_kernel_proxy, "iSCSI initiator built with ICL_KERNEL_PROXY");
72 #endif
73
74 /*
75  * XXX: This is global so the iscsi_unload() can access it.
76  *      Think about how to do this properly.
77  */
78 static struct iscsi_softc       *sc;
79
80 SYSCTL_NODE(_kern, OID_AUTO, iscsi, CTLFLAG_RD, 0, "iSCSI initiator");
81 static int debug = 1;
82 TUNABLE_INT("kern.iscsi.debug", &debug);
83 SYSCTL_INT(_kern_iscsi, OID_AUTO, debug, CTLFLAG_RWTUN,
84     &debug, 0, "Enable debug messages");
85 static int ping_timeout = 5;
86 TUNABLE_INT("kern.iscsi.ping_timeout", &ping_timeout);
87 SYSCTL_INT(_kern_iscsi, OID_AUTO, ping_timeout, CTLFLAG_RWTUN, &ping_timeout,
88     0, "Timeout for ping (NOP-Out) requests, in seconds");
89 static int iscsid_timeout = 60;
90 TUNABLE_INT("kern.iscsi.iscsid_timeout", &iscsid_timeout);
91 SYSCTL_INT(_kern_iscsi, OID_AUTO, iscsid_timeout, CTLFLAG_RWTUN, &iscsid_timeout,
92     0, "Time to wait for iscsid(8) to handle reconnection, in seconds");
93 static int login_timeout = 60;
94 TUNABLE_INT("kern.iscsi.login_timeout", &login_timeout);
95 SYSCTL_INT(_kern_iscsi, OID_AUTO, login_timeout, CTLFLAG_RWTUN, &login_timeout,
96     0, "Time to wait for iscsid(8) to finish Login Phase, in seconds");
97 static int maxtags = 255;
98 TUNABLE_INT("kern.iscsi.maxtags", &maxtags);
99 SYSCTL_INT(_kern_iscsi, OID_AUTO, maxtags, CTLFLAG_RWTUN, &maxtags,
100     0, "Max number of IO requests queued");
101 static int fail_on_disconnection = 0;
102 TUNABLE_INT("kern.iscsi.fail_on_disconnection", &fail_on_disconnection);
103 SYSCTL_INT(_kern_iscsi, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN,
104     &fail_on_disconnection, 0, "Destroy CAM SIM on connection failure");
105 static int fail_on_shutdown = 1;
106 SYSCTL_INT(_kern_iscsi, OID_AUTO, fail_on_shutdown, CTLFLAG_RWTUN,
107     &fail_on_shutdown, 0, "Fail disconnected sessions on shutdown");
108
109 static MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI initiator");
110 static uma_zone_t iscsi_outstanding_zone;
111
112 #define CONN_SESSION(X) ((struct iscsi_session *)X->ic_prv0)
113 #define PDU_SESSION(X)  (CONN_SESSION(X->ip_conn))
114
115 #define ISCSI_DEBUG(X, ...)                                             \
116         do {                                                            \
117                 if (debug > 1)                                          \
118                         printf("%s: " X "\n", __func__, ## __VA_ARGS__);\
119         } while (0)
120
121 #define ISCSI_WARN(X, ...)                                              \
122         do {                                                            \
123                 if (debug > 0) {                                        \
124                         printf("WARNING: %s: " X "\n",                  \
125                             __func__, ## __VA_ARGS__);                  \
126                 }                                                       \
127         } while (0)
128
129 #define ISCSI_SESSION_DEBUG(S, X, ...)                                  \
130         do {                                                            \
131                 if (debug > 1) {                                        \
132                         printf("%s: %s (%s): " X "\n",                  \
133                             __func__, S->is_conf.isc_target_addr,       \
134                             S->is_conf.isc_target, ## __VA_ARGS__);     \
135                 }                                                       \
136         } while (0)
137
138 #define ISCSI_SESSION_WARN(S, X, ...)                                   \
139         do {                                                            \
140                 if (debug > 0) {                                        \
141                         printf("WARNING: %s (%s): " X "\n",             \
142                             S->is_conf.isc_target_addr,                 \
143                             S->is_conf.isc_target, ## __VA_ARGS__);     \
144                 }                                                       \
145         } while (0)
146
147 #define ISCSI_SESSION_LOCK(X)           mtx_lock(&X->is_lock)
148 #define ISCSI_SESSION_UNLOCK(X)         mtx_unlock(&X->is_lock)
149 #define ISCSI_SESSION_LOCK_ASSERT(X)    mtx_assert(&X->is_lock, MA_OWNED)
150 #define ISCSI_SESSION_LOCK_ASSERT_NOT(X) mtx_assert(&X->is_lock, MA_NOTOWNED)
151
152 static int      iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg,
153                     int mode, struct thread *td);
154
155 static struct cdevsw iscsi_cdevsw = {
156      .d_version = D_VERSION,
157      .d_ioctl   = iscsi_ioctl,
158      .d_name    = "iscsi",
159 };
160
161 static void     iscsi_pdu_queue_locked(struct icl_pdu *request);
162 static void     iscsi_pdu_queue(struct icl_pdu *request);
163 static void     iscsi_pdu_update_statsn(const struct icl_pdu *response);
164 static void     iscsi_pdu_handle_nop_in(struct icl_pdu *response);
165 static void     iscsi_pdu_handle_scsi_response(struct icl_pdu *response);
166 static void     iscsi_pdu_handle_task_response(struct icl_pdu *response);
167 static void     iscsi_pdu_handle_data_in(struct icl_pdu *response);
168 static void     iscsi_pdu_handle_logout_response(struct icl_pdu *response);
169 static void     iscsi_pdu_handle_r2t(struct icl_pdu *response);
170 static void     iscsi_pdu_handle_async_message(struct icl_pdu *response);
171 static void     iscsi_pdu_handle_reject(struct icl_pdu *response);
172 static void     iscsi_session_reconnect(struct iscsi_session *is);
173 static void     iscsi_session_terminate(struct iscsi_session *is);
174 static void     iscsi_action(struct cam_sim *sim, union ccb *ccb);
175 static void     iscsi_poll(struct cam_sim *sim);
176 static struct iscsi_outstanding *iscsi_outstanding_find(struct iscsi_session *is,
177                     uint32_t initiator_task_tag);
178 static struct iscsi_outstanding *iscsi_outstanding_add(struct iscsi_session *is,
179                     uint32_t initiator_task_tag, union ccb *ccb);
180 static void     iscsi_outstanding_remove(struct iscsi_session *is,
181                     struct iscsi_outstanding *io);
182
183 static bool
184 iscsi_pdu_prepare(struct icl_pdu *request)
185 {
186         struct iscsi_session *is;
187         struct iscsi_bhs_scsi_command *bhssc;
188
189         is = PDU_SESSION(request);
190
191         ISCSI_SESSION_LOCK_ASSERT(is);
192
193         /*
194          * We're only using fields common for all the request
195          * (initiator -> target) PDUs.
196          */
197         bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs;
198
199         /*
200          * Data-Out PDU does not contain CmdSN.
201          */
202         if (bhssc->bhssc_opcode != ISCSI_BHS_OPCODE_SCSI_DATA_OUT) {
203                 if (ISCSI_SNGT(is->is_cmdsn, is->is_maxcmdsn) &&
204                     (bhssc->bhssc_opcode & ISCSI_BHS_OPCODE_IMMEDIATE) == 0) {
205                         /*
206                          * Current MaxCmdSN prevents us from sending any more
207                          * SCSI Command PDUs to the target; postpone the PDU.
208                          * It will get resent by either iscsi_pdu_queue(),
209                          * or by maintenance thread.
210                          */
211 #if 0
212                         ISCSI_SESSION_DEBUG(is, "postponing send, CmdSN %u, "
213                             "ExpCmdSN %u, MaxCmdSN %u, opcode 0x%x",
214                             is->is_cmdsn, is->is_expcmdsn, is->is_maxcmdsn,
215                             bhssc->bhssc_opcode);
216 #endif
217                         return (true);
218                 }
219                 bhssc->bhssc_cmdsn = htonl(is->is_cmdsn);
220                 if ((bhssc->bhssc_opcode & ISCSI_BHS_OPCODE_IMMEDIATE) == 0)
221                         is->is_cmdsn++;
222         }
223         bhssc->bhssc_expstatsn = htonl(is->is_statsn + 1);
224
225         return (false);
226 }
227
228 static void
229 iscsi_session_send_postponed(struct iscsi_session *is)
230 {
231         struct icl_pdu *request;
232         bool postpone;
233
234         ISCSI_SESSION_LOCK_ASSERT(is);
235
236         if (STAILQ_EMPTY(&is->is_postponed))
237                 return;
238         while ((request = STAILQ_FIRST(&is->is_postponed)) != NULL) {
239                 postpone = iscsi_pdu_prepare(request);
240                 if (postpone)
241                         return;
242                 STAILQ_REMOVE_HEAD(&is->is_postponed, ip_next);
243                 icl_pdu_queue(request);
244         }
245         xpt_release_simq(is->is_sim, 1);
246 }
247
248 static void
249 iscsi_pdu_queue_locked(struct icl_pdu *request)
250 {
251         struct iscsi_session *is;
252         bool postpone;
253
254         is = PDU_SESSION(request);
255         ISCSI_SESSION_LOCK_ASSERT(is);
256         iscsi_session_send_postponed(is);
257         postpone = iscsi_pdu_prepare(request);
258         if (postpone) {
259                 if (STAILQ_EMPTY(&is->is_postponed))
260                         xpt_freeze_simq(is->is_sim, 1);
261                 STAILQ_INSERT_TAIL(&is->is_postponed, request, ip_next);
262                 return;
263         }
264         icl_pdu_queue(request);
265 }
266
267 static void
268 iscsi_pdu_queue(struct icl_pdu *request)
269 {
270         struct iscsi_session *is;
271
272         is = PDU_SESSION(request);
273         ISCSI_SESSION_LOCK(is);
274         iscsi_pdu_queue_locked(request);
275         ISCSI_SESSION_UNLOCK(is);
276 }
277
278 static void
279 iscsi_session_logout(struct iscsi_session *is)
280 {
281         struct icl_pdu *request;
282         struct iscsi_bhs_logout_request *bhslr;
283
284         request = icl_pdu_new(is->is_conn, M_NOWAIT);
285         if (request == NULL)
286                 return;
287
288         bhslr = (struct iscsi_bhs_logout_request *)request->ip_bhs;
289         bhslr->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_REQUEST;
290         bhslr->bhslr_reason = BHSLR_REASON_CLOSE_SESSION;
291         iscsi_pdu_queue_locked(request);
292 }
293
294 static void
295 iscsi_session_terminate_task(struct iscsi_session *is,
296     struct iscsi_outstanding *io, cam_status status)
297 {
298
299         if (io->io_ccb != NULL) {
300                 io->io_ccb->ccb_h.status &= ~(CAM_SIM_QUEUED | CAM_STATUS_MASK);
301                 io->io_ccb->ccb_h.status |= status;
302                 if ((io->io_ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
303                         io->io_ccb->ccb_h.status |= CAM_DEV_QFRZN;
304                         xpt_freeze_devq(io->io_ccb->ccb_h.path, 1);
305                         ISCSI_SESSION_DEBUG(is, "freezing devq");
306                 }
307                 xpt_done(io->io_ccb);
308         }
309         iscsi_outstanding_remove(is, io);
310 }
311
312 static void
313 iscsi_session_terminate_tasks(struct iscsi_session *is, cam_status status)
314 {
315         struct iscsi_outstanding *io, *tmp;
316
317         ISCSI_SESSION_LOCK_ASSERT(is);
318
319         TAILQ_FOREACH_SAFE(io, &is->is_outstanding, io_next, tmp) {
320                 iscsi_session_terminate_task(is, io, status);
321         }
322 }
323
324 static void
325 iscsi_session_cleanup(struct iscsi_session *is, bool destroy_sim)
326 {
327         struct icl_pdu *pdu;
328
329         ISCSI_SESSION_LOCK_ASSERT(is);
330
331         /*
332          * Don't queue any new PDUs.
333          */
334         if (is->is_sim != NULL && is->is_simq_frozen == false) {
335                 ISCSI_SESSION_DEBUG(is, "freezing");
336                 xpt_freeze_simq(is->is_sim, 1);
337                 is->is_simq_frozen = true;
338         }
339
340         /*
341          * Remove postponed PDUs.
342          */
343         if (!STAILQ_EMPTY(&is->is_postponed))
344                 xpt_release_simq(is->is_sim, 1);
345         while ((pdu = STAILQ_FIRST(&is->is_postponed)) != NULL) {
346                 STAILQ_REMOVE_HEAD(&is->is_postponed, ip_next);
347                 icl_pdu_free(pdu);
348         }
349
350         if (destroy_sim == false) {
351                 /*
352                  * Terminate SCSI tasks, asking CAM to requeue them.
353                  */
354                 iscsi_session_terminate_tasks(is, CAM_REQUEUE_REQ);
355                 return;
356         }
357
358         iscsi_session_terminate_tasks(is, CAM_DEV_NOT_THERE);
359
360         if (is->is_sim == NULL)
361                 return;
362
363         ISCSI_SESSION_DEBUG(is, "deregistering SIM");
364         xpt_async(AC_LOST_DEVICE, is->is_path, NULL);
365
366         if (is->is_simq_frozen) {
367                 xpt_release_simq(is->is_sim, 1);
368                 is->is_simq_frozen = false;
369         }
370
371         xpt_free_path(is->is_path);
372         is->is_path = NULL;
373         xpt_bus_deregister(cam_sim_path(is->is_sim));
374         cam_sim_free(is->is_sim, TRUE /*free_devq*/);
375         is->is_sim = NULL;
376         is->is_devq = NULL;
377 }
378
379 static void
380 iscsi_maintenance_thread_reconnect(struct iscsi_session *is)
381 {
382
383         icl_conn_close(is->is_conn);
384
385         ISCSI_SESSION_LOCK(is);
386
387         is->is_connected = false;
388         is->is_reconnecting = false;
389         is->is_login_phase = false;
390
391 #ifdef ICL_KERNEL_PROXY
392         if (is->is_login_pdu != NULL) {
393                 icl_pdu_free(is->is_login_pdu);
394                 is->is_login_pdu = NULL;
395         }
396         cv_signal(&is->is_login_cv);
397 #endif
398  
399         if (fail_on_disconnection) {
400                 ISCSI_SESSION_DEBUG(is, "connection failed, destroying devices");
401                 iscsi_session_cleanup(is, true);
402         } else {
403                 iscsi_session_cleanup(is, false);
404         }
405  
406         KASSERT(TAILQ_EMPTY(&is->is_outstanding),
407             ("destroying session with active tasks"));
408         KASSERT(STAILQ_EMPTY(&is->is_postponed),
409             ("destroying session with postponed PDUs"));
410
411         /*
412          * Request immediate reconnection from iscsid(8).
413          */
414         //ISCSI_SESSION_DEBUG(is, "waking up iscsid(8)");
415         is->is_waiting_for_iscsid = true;
416         strlcpy(is->is_reason, "Waiting for iscsid(8)", sizeof(is->is_reason));
417         is->is_timeout = 0;
418         ISCSI_SESSION_UNLOCK(is);
419         cv_signal(&is->is_softc->sc_cv);
420 }
421
422 static void
423 iscsi_maintenance_thread_terminate(struct iscsi_session *is)
424 {
425         struct iscsi_softc *sc;
426
427         sc = is->is_softc;
428         sx_xlock(&sc->sc_lock);
429         TAILQ_REMOVE(&sc->sc_sessions, is, is_next);
430         sx_xunlock(&sc->sc_lock);
431
432         icl_conn_close(is->is_conn);
433         callout_drain(&is->is_callout);
434
435         ISCSI_SESSION_LOCK(is);
436
437         KASSERT(is->is_terminating, ("is_terminating == false"));
438
439 #ifdef ICL_KERNEL_PROXY
440         if (is->is_login_pdu != NULL) {
441                 icl_pdu_free(is->is_login_pdu);
442                 is->is_login_pdu = NULL;
443         }
444         cv_signal(&is->is_login_cv);
445 #endif
446
447         iscsi_session_cleanup(is, true);
448
449         KASSERT(TAILQ_EMPTY(&is->is_outstanding),
450             ("destroying session with active tasks"));
451         KASSERT(STAILQ_EMPTY(&is->is_postponed),
452             ("destroying session with postponed PDUs"));
453
454         ISCSI_SESSION_UNLOCK(is);
455
456         icl_conn_free(is->is_conn);
457         mtx_destroy(&is->is_lock);
458         cv_destroy(&is->is_maintenance_cv);
459 #ifdef ICL_KERNEL_PROXY
460         cv_destroy(&is->is_login_cv);
461 #endif
462
463         ISCSI_SESSION_DEBUG(is, "terminated");
464         free(is, M_ISCSI);
465
466         /*
467          * The iscsi_unload() routine might be waiting.
468          */
469         cv_signal(&sc->sc_cv);
470 }
471
472 static void
473 iscsi_maintenance_thread(void *arg)
474 {
475         struct iscsi_session *is = arg;
476
477         ISCSI_SESSION_LOCK(is);
478         for (;;) {
479                 if (is->is_reconnecting == false &&
480                     is->is_terminating == false &&
481                     (STAILQ_EMPTY(&is->is_postponed) ||
482                      ISCSI_SNGT(is->is_cmdsn, is->is_maxcmdsn)))
483                         cv_wait(&is->is_maintenance_cv, &is->is_lock);
484
485                 /* Terminate supersedes reconnect. */
486                 if (is->is_terminating) {
487                         ISCSI_SESSION_UNLOCK(is);
488                         iscsi_maintenance_thread_terminate(is);
489                         kthread_exit();
490                         return;
491                 }
492
493                 if (is->is_reconnecting) {
494                         ISCSI_SESSION_UNLOCK(is);
495                         iscsi_maintenance_thread_reconnect(is);
496                         ISCSI_SESSION_LOCK(is);
497                         continue;
498                 }
499
500                 iscsi_session_send_postponed(is);
501         }
502         ISCSI_SESSION_UNLOCK(is);
503 }
504
505 static void
506 iscsi_session_reconnect(struct iscsi_session *is)
507 {
508
509         /*
510          * XXX: We can't use locking here, because
511          *      it's being called from various contexts.
512          *      Hope it doesn't break anything.
513          */
514         if (is->is_reconnecting)
515                 return;
516
517         is->is_reconnecting = true;
518         cv_signal(&is->is_maintenance_cv);
519 }
520
521 static void
522 iscsi_session_terminate(struct iscsi_session *is)
523 {
524
525         if (is->is_terminating)
526                 return;
527
528         is->is_terminating = true;
529
530 #if 0
531         iscsi_session_logout(is);
532 #endif
533         cv_signal(&is->is_maintenance_cv);
534 }
535
536 static void
537 iscsi_callout(void *context)
538 {
539         struct icl_pdu *request;
540         struct iscsi_bhs_nop_out *bhsno;
541         struct iscsi_session *is;
542         bool reconnect_needed = false;
543
544         is = context;
545
546         ISCSI_SESSION_LOCK(is);
547         if (is->is_terminating) {
548                 ISCSI_SESSION_UNLOCK(is);
549                 return;
550         }
551
552         callout_schedule(&is->is_callout, 1 * hz);
553
554         is->is_timeout++;
555
556         if (is->is_waiting_for_iscsid) {
557                 if (iscsid_timeout > 0 && is->is_timeout > iscsid_timeout) {
558                         ISCSI_SESSION_WARN(is, "timed out waiting for iscsid(8) "
559                             "for %d seconds; reconnecting",
560                             is->is_timeout);
561                         reconnect_needed = true;
562                 }
563                 goto out;
564         }
565
566         if (is->is_login_phase) {
567                 if (login_timeout > 0 && is->is_timeout > login_timeout) {
568                         ISCSI_SESSION_WARN(is, "login timed out after %d seconds; "
569                             "reconnecting", is->is_timeout);
570                         reconnect_needed = true;
571                 }
572                 goto out;
573         }
574
575         if (ping_timeout <= 0) {
576                 /*
577                  * Pings are disabled.  Don't send NOP-Out in this case.
578                  * Reset the timeout, to avoid triggering reconnection,
579                  * should the user decide to reenable them.
580                  */
581                 is->is_timeout = 0;
582                 goto out;
583         }
584
585         if (is->is_timeout >= ping_timeout) {
586                 ISCSI_SESSION_WARN(is, "no ping reply (NOP-In) after %d seconds; "
587                     "reconnecting", ping_timeout);
588                 reconnect_needed = true;
589                 goto out;
590         }
591
592         ISCSI_SESSION_UNLOCK(is);
593
594         /*
595          * If the ping was reset less than one second ago - which means
596          * that we've received some PDU during the last second - assume
597          * the traffic flows correctly and don't bother sending a NOP-Out.
598          *
599          * (It's 2 - one for one second, and one for incrementing is_timeout
600          * earlier in this routine.)
601          */
602         if (is->is_timeout < 2)
603                 return;
604
605         request = icl_pdu_new(is->is_conn, M_NOWAIT);
606         if (request == NULL) {
607                 ISCSI_SESSION_WARN(is, "failed to allocate PDU");
608                 return;
609         }
610         bhsno = (struct iscsi_bhs_nop_out *)request->ip_bhs;
611         bhsno->bhsno_opcode = ISCSI_BHS_OPCODE_NOP_OUT |
612             ISCSI_BHS_OPCODE_IMMEDIATE;
613         bhsno->bhsno_flags = 0x80;
614         bhsno->bhsno_target_transfer_tag = 0xffffffff;
615         iscsi_pdu_queue(request);
616         return;
617
618 out:
619         if (is->is_terminating) {
620                 ISCSI_SESSION_UNLOCK(is);
621                 return;
622         }
623
624         ISCSI_SESSION_UNLOCK(is);
625
626         if (reconnect_needed)
627                 iscsi_session_reconnect(is);
628 }
629
630 static void
631 iscsi_pdu_update_statsn(const struct icl_pdu *response)
632 {
633         const struct iscsi_bhs_data_in *bhsdi;
634         struct iscsi_session *is;
635         uint32_t expcmdsn, maxcmdsn, statsn;
636
637         is = PDU_SESSION(response);
638
639         ISCSI_SESSION_LOCK_ASSERT(is);
640
641         /*
642          * We're only using fields common for all the response
643          * (target -> initiator) PDUs.
644          */
645         bhsdi = (const struct iscsi_bhs_data_in *)response->ip_bhs;
646         /*
647          * Ok, I lied.  In case of Data-In, "The fields StatSN, Status,
648          * and Residual Count only have meaningful content if the S bit
649          * is set to 1", so we also need to check the bit specific for
650          * Data-In PDU.
651          */
652         if (bhsdi->bhsdi_opcode != ISCSI_BHS_OPCODE_SCSI_DATA_IN ||
653             (bhsdi->bhsdi_flags & BHSDI_FLAGS_S) != 0) {
654                 statsn = ntohl(bhsdi->bhsdi_statsn);
655                 if (statsn != is->is_statsn && statsn != (is->is_statsn + 1)) {
656                         /* XXX: This is normal situation for MCS */
657                         ISCSI_SESSION_WARN(is, "PDU 0x%x StatSN %u != "
658                             "session ExpStatSN %u (or + 1); reconnecting",
659                             bhsdi->bhsdi_opcode, statsn, is->is_statsn);
660                         iscsi_session_reconnect(is);
661                 }
662                 if (ISCSI_SNGT(statsn, is->is_statsn))
663                         is->is_statsn = statsn;
664         }
665
666         expcmdsn = ntohl(bhsdi->bhsdi_expcmdsn);
667         maxcmdsn = ntohl(bhsdi->bhsdi_maxcmdsn);
668
669         if (ISCSI_SNLT(maxcmdsn + 1, expcmdsn)) {
670                 ISCSI_SESSION_DEBUG(is,
671                     "PDU MaxCmdSN %u + 1 < PDU ExpCmdSN %u; ignoring",
672                     maxcmdsn, expcmdsn);
673         } else {
674                 if (ISCSI_SNGT(maxcmdsn, is->is_maxcmdsn)) {
675                         is->is_maxcmdsn = maxcmdsn;
676
677                         /*
678                          * Command window increased; kick the maintanance thread
679                          * to send out postponed commands.
680                          */
681                         if (!STAILQ_EMPTY(&is->is_postponed))
682                                 cv_signal(&is->is_maintenance_cv);
683                 } else if (ISCSI_SNLT(maxcmdsn, is->is_maxcmdsn)) {
684                         /* XXX: This is normal situation for MCS */
685                         ISCSI_SESSION_DEBUG(is,
686                             "PDU MaxCmdSN %u < session MaxCmdSN %u; ignoring",
687                             maxcmdsn, is->is_maxcmdsn);
688                 }
689
690                 if (ISCSI_SNGT(expcmdsn, is->is_expcmdsn)) {
691                         is->is_expcmdsn = expcmdsn;
692                 } else if (ISCSI_SNLT(expcmdsn, is->is_expcmdsn)) {
693                         /* XXX: This is normal situation for MCS */
694                         ISCSI_SESSION_DEBUG(is,
695                             "PDU ExpCmdSN %u < session ExpCmdSN %u; ignoring",
696                             expcmdsn, is->is_expcmdsn);
697                 }
698         }
699
700         /*
701          * Every incoming PDU - not just NOP-In - resets the ping timer.
702          * The purpose of the timeout is to reset the connection when it stalls;
703          * we don't want this to happen when NOP-In or NOP-Out ends up delayed
704          * in some queue.
705          */
706         is->is_timeout = 0;
707 }
708
709 static void
710 iscsi_receive_callback(struct icl_pdu *response)
711 {
712         struct iscsi_session *is;
713
714         is = PDU_SESSION(response);
715
716         ISCSI_SESSION_LOCK(is);
717
718 #ifdef ICL_KERNEL_PROXY
719         if (is->is_login_phase) {
720                 if (is->is_login_pdu == NULL)
721                         is->is_login_pdu = response;
722                 else
723                         icl_pdu_free(response);
724                 ISCSI_SESSION_UNLOCK(is);
725                 cv_signal(&is->is_login_cv);
726                 return;
727         }
728 #endif
729
730         iscsi_pdu_update_statsn(response);
731         
732         /*
733          * The handling routine is responsible for freeing the PDU
734          * when it's no longer needed.
735          */
736         switch (response->ip_bhs->bhs_opcode) {
737         case ISCSI_BHS_OPCODE_NOP_IN:
738                 iscsi_pdu_handle_nop_in(response);
739                 ISCSI_SESSION_UNLOCK(is);
740                 break;
741         case ISCSI_BHS_OPCODE_SCSI_RESPONSE:
742                 iscsi_pdu_handle_scsi_response(response);
743                 /* Session lock dropped inside. */
744                 ISCSI_SESSION_LOCK_ASSERT_NOT(is);
745                 break;
746         case ISCSI_BHS_OPCODE_TASK_RESPONSE:
747                 iscsi_pdu_handle_task_response(response);
748                 ISCSI_SESSION_UNLOCK(is);
749                 break;
750         case ISCSI_BHS_OPCODE_SCSI_DATA_IN:
751                 iscsi_pdu_handle_data_in(response);
752                 /* Session lock dropped inside. */
753                 ISCSI_SESSION_LOCK_ASSERT_NOT(is);
754                 break;
755         case ISCSI_BHS_OPCODE_LOGOUT_RESPONSE:
756                 iscsi_pdu_handle_logout_response(response);
757                 ISCSI_SESSION_UNLOCK(is);
758                 break;
759         case ISCSI_BHS_OPCODE_R2T:
760                 iscsi_pdu_handle_r2t(response);
761                 ISCSI_SESSION_UNLOCK(is);
762                 break;
763         case ISCSI_BHS_OPCODE_ASYNC_MESSAGE:
764                 iscsi_pdu_handle_async_message(response);
765                 ISCSI_SESSION_UNLOCK(is);
766                 break;
767         case ISCSI_BHS_OPCODE_REJECT:
768                 iscsi_pdu_handle_reject(response);
769                 ISCSI_SESSION_UNLOCK(is);
770                 break;
771         default:
772                 ISCSI_SESSION_WARN(is, "received PDU with unsupported "
773                     "opcode 0x%x; reconnecting",
774                     response->ip_bhs->bhs_opcode);
775                 iscsi_session_reconnect(is);
776                 ISCSI_SESSION_UNLOCK(is);
777                 icl_pdu_free(response);
778         }
779 }
780
781 static void
782 iscsi_error_callback(struct icl_conn *ic)
783 {
784         struct iscsi_session *is;
785
786         is = CONN_SESSION(ic);
787
788         ISCSI_SESSION_WARN(is, "connection error; reconnecting");
789         iscsi_session_reconnect(is);
790 }
791
792 static void
793 iscsi_pdu_handle_nop_in(struct icl_pdu *response)
794 {
795         struct iscsi_session *is;
796         struct iscsi_bhs_nop_out *bhsno;
797         struct iscsi_bhs_nop_in *bhsni;
798         struct icl_pdu *request;
799         void *data = NULL;
800         size_t datasize;
801         int error;
802
803         is = PDU_SESSION(response);
804         bhsni = (struct iscsi_bhs_nop_in *)response->ip_bhs;
805
806         if (bhsni->bhsni_target_transfer_tag == 0xffffffff) {
807                 /*
808                  * Nothing to do; iscsi_pdu_update_statsn() already
809                  * zeroed the timeout.
810                  */
811                 icl_pdu_free(response);
812                 return;
813         }
814
815         datasize = icl_pdu_data_segment_length(response);
816         if (datasize > 0) {
817                 data = malloc(datasize, M_ISCSI, M_NOWAIT | M_ZERO);
818                 if (data == NULL) {
819                         ISCSI_SESSION_WARN(is, "failed to allocate memory; "
820                             "reconnecting");
821                         icl_pdu_free(response);
822                         iscsi_session_reconnect(is);
823                         return;
824                 }
825                 icl_pdu_get_data(response, 0, data, datasize);
826         }
827
828         request = icl_pdu_new(response->ip_conn, M_NOWAIT);
829         if (request == NULL) {
830                 ISCSI_SESSION_WARN(is, "failed to allocate memory; "
831                     "reconnecting");
832                 free(data, M_ISCSI);
833                 icl_pdu_free(response);
834                 iscsi_session_reconnect(is);
835                 return;
836         }
837         bhsno = (struct iscsi_bhs_nop_out *)request->ip_bhs;
838         bhsno->bhsno_opcode = ISCSI_BHS_OPCODE_NOP_OUT |
839             ISCSI_BHS_OPCODE_IMMEDIATE;
840         bhsno->bhsno_flags = 0x80;
841         bhsno->bhsno_initiator_task_tag = 0xffffffff;
842         bhsno->bhsno_target_transfer_tag = bhsni->bhsni_target_transfer_tag;
843         if (datasize > 0) {
844                 error = icl_pdu_append_data(request, data, datasize, M_NOWAIT);
845                 if (error != 0) {
846                         ISCSI_SESSION_WARN(is, "failed to allocate memory; "
847                             "reconnecting");
848                         free(data, M_ISCSI);
849                         icl_pdu_free(request);
850                         icl_pdu_free(response);
851                         iscsi_session_reconnect(is);
852                         return;
853                 }
854                 free(data, M_ISCSI);
855         }
856
857         icl_pdu_free(response);
858         iscsi_pdu_queue_locked(request);
859 }
860
861 static void
862 iscsi_pdu_handle_scsi_response(struct icl_pdu *response)
863 {
864         struct iscsi_bhs_scsi_response *bhssr;
865         struct iscsi_outstanding *io;
866         struct iscsi_session *is;
867         union ccb *ccb;
868         struct ccb_scsiio *csio;
869         size_t data_segment_len, received;
870         uint16_t sense_len;
871
872         is = PDU_SESSION(response);
873
874         bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs;
875         io = iscsi_outstanding_find(is, bhssr->bhssr_initiator_task_tag);
876         if (io == NULL || io->io_ccb == NULL) {
877                 ISCSI_SESSION_WARN(is, "bad itt 0x%x", bhssr->bhssr_initiator_task_tag);
878                 icl_pdu_free(response);
879                 iscsi_session_reconnect(is);
880                 ISCSI_SESSION_UNLOCK(is);
881                 return;
882         }
883
884         ccb = io->io_ccb;
885         received = io->io_received;
886         iscsi_outstanding_remove(is, io);
887         ISCSI_SESSION_UNLOCK(is);
888
889         if (bhssr->bhssr_response != BHSSR_RESPONSE_COMMAND_COMPLETED) {
890                 ISCSI_SESSION_WARN(is, "service response 0x%x", bhssr->bhssr_response);
891                 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
892                         xpt_freeze_devq(ccb->ccb_h.path, 1);
893                         ISCSI_SESSION_DEBUG(is, "freezing devq");
894                 }
895                 ccb->ccb_h.status = CAM_REQ_CMP_ERR | CAM_DEV_QFRZN;
896         } else if (bhssr->bhssr_status == 0) {
897                 ccb->ccb_h.status = CAM_REQ_CMP;
898         } else {
899                 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
900                         xpt_freeze_devq(ccb->ccb_h.path, 1);
901                         ISCSI_SESSION_DEBUG(is, "freezing devq");
902                 }
903                 ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_DEV_QFRZN;
904                 ccb->csio.scsi_status = bhssr->bhssr_status;
905         }
906
907         csio = &ccb->csio;
908         data_segment_len = icl_pdu_data_segment_length(response);
909         if (data_segment_len > 0) {
910                 if (data_segment_len < sizeof(sense_len)) {
911                         ISCSI_SESSION_WARN(is, "truncated data segment (%zd bytes)",
912                             data_segment_len);
913                         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
914                                 xpt_freeze_devq(ccb->ccb_h.path, 1);
915                                 ISCSI_SESSION_DEBUG(is, "freezing devq");
916                         }
917                         ccb->ccb_h.status = CAM_REQ_CMP_ERR | CAM_DEV_QFRZN;
918                         goto out;
919                 }
920                 icl_pdu_get_data(response, 0, &sense_len, sizeof(sense_len));
921                 sense_len = ntohs(sense_len);
922 #if 0
923                 ISCSI_SESSION_DEBUG(is, "sense_len %d, data len %zd",
924                     sense_len, data_segment_len);
925 #endif
926                 if (sizeof(sense_len) + sense_len > data_segment_len) {
927                         ISCSI_SESSION_WARN(is, "truncated data segment "
928                             "(%zd bytes, should be %zd)",
929                             data_segment_len, sizeof(sense_len) + sense_len);
930                         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
931                                 xpt_freeze_devq(ccb->ccb_h.path, 1);
932                                 ISCSI_SESSION_DEBUG(is, "freezing devq");
933                         }
934                         ccb->ccb_h.status = CAM_REQ_CMP_ERR | CAM_DEV_QFRZN;
935                         goto out;
936                 } else if (sizeof(sense_len) + sense_len < data_segment_len)
937                         ISCSI_SESSION_WARN(is, "oversize data segment "
938                             "(%zd bytes, should be %zd)",
939                             data_segment_len, sizeof(sense_len) + sense_len);
940                 if (sense_len > csio->sense_len) {
941                         ISCSI_SESSION_DEBUG(is, "truncating sense from %d to %d",
942                             sense_len, csio->sense_len);
943                         sense_len = csio->sense_len;
944                 }
945                 icl_pdu_get_data(response, sizeof(sense_len), &csio->sense_data, sense_len);
946                 csio->sense_resid = csio->sense_len - sense_len;
947                 ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
948         }
949
950 out:
951         if (bhssr->bhssr_flags & BHSSR_FLAGS_RESIDUAL_UNDERFLOW)
952                 csio->resid = ntohl(bhssr->bhssr_residual_count);
953
954         if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
955                 KASSERT(received <= csio->dxfer_len,
956                     ("received > csio->dxfer_len"));
957                 if (received < csio->dxfer_len) {
958                         if (csio->resid != csio->dxfer_len - received) {
959                                 ISCSI_SESSION_WARN(is, "underflow mismatch: "
960                                     "target indicates %d, we calculated %zd",
961                                     csio->resid, csio->dxfer_len - received);
962                         }
963                         csio->resid = csio->dxfer_len - received;
964                 }
965         }
966
967         xpt_done(ccb);
968         icl_pdu_free(response);
969 }
970
971 static void
972 iscsi_pdu_handle_task_response(struct icl_pdu *response)
973 {
974         struct iscsi_bhs_task_management_response *bhstmr;
975         struct iscsi_outstanding *io, *aio;
976         struct iscsi_session *is;
977
978         is = PDU_SESSION(response);
979
980         bhstmr = (struct iscsi_bhs_task_management_response *)response->ip_bhs;
981         io = iscsi_outstanding_find(is, bhstmr->bhstmr_initiator_task_tag);
982         if (io == NULL || io->io_ccb != NULL) {
983                 ISCSI_SESSION_WARN(is, "bad itt 0x%x",
984                     bhstmr->bhstmr_initiator_task_tag);
985                 icl_pdu_free(response);
986                 iscsi_session_reconnect(is);
987                 return;
988         }
989
990         if (bhstmr->bhstmr_response != BHSTMR_RESPONSE_FUNCTION_COMPLETE) {
991                 ISCSI_SESSION_WARN(is, "task response 0x%x",
992                     bhstmr->bhstmr_response);
993         } else {
994                 aio = iscsi_outstanding_find(is, io->io_datasn);
995                 if (aio != NULL && aio->io_ccb != NULL)
996                         iscsi_session_terminate_task(is, aio, CAM_REQ_ABORTED);
997         }
998
999         iscsi_outstanding_remove(is, io);
1000         icl_pdu_free(response);
1001 }
1002
1003 static void
1004 iscsi_pdu_handle_data_in(struct icl_pdu *response)
1005 {
1006         struct iscsi_bhs_data_in *bhsdi;
1007         struct iscsi_outstanding *io;
1008         struct iscsi_session *is;
1009         union ccb *ccb;
1010         struct ccb_scsiio *csio;
1011         size_t data_segment_len, received, oreceived;
1012         
1013         is = PDU_SESSION(response);
1014         bhsdi = (struct iscsi_bhs_data_in *)response->ip_bhs;
1015         io = iscsi_outstanding_find(is, bhsdi->bhsdi_initiator_task_tag);
1016         if (io == NULL || io->io_ccb == NULL) {
1017                 ISCSI_SESSION_WARN(is, "bad itt 0x%x", bhsdi->bhsdi_initiator_task_tag);
1018                 icl_pdu_free(response);
1019                 iscsi_session_reconnect(is);
1020                 ISCSI_SESSION_UNLOCK(is);
1021                 return;
1022         }
1023
1024         data_segment_len = icl_pdu_data_segment_length(response);
1025         if (data_segment_len == 0) {
1026                 /*
1027                  * "The sending of 0 length data segments should be avoided,
1028                  * but initiators and targets MUST be able to properly receive
1029                  * 0 length data segments."
1030                  */
1031                 ISCSI_SESSION_UNLOCK(is);
1032                 icl_pdu_free(response);
1033                 return;
1034         }
1035
1036         /*
1037          * We need to track this for security reasons - without it, malicious target
1038          * could respond to SCSI READ without sending Data-In PDUs, which would result
1039          * in read operation on the initiator side returning random kernel data.
1040          */
1041         if (ntohl(bhsdi->bhsdi_buffer_offset) != io->io_received) {
1042                 ISCSI_SESSION_WARN(is, "data out of order; expected offset %zd, got %zd",
1043                     io->io_received, (size_t)ntohl(bhsdi->bhsdi_buffer_offset));
1044                 icl_pdu_free(response);
1045                 iscsi_session_reconnect(is);
1046                 ISCSI_SESSION_UNLOCK(is);
1047                 return;
1048         }
1049
1050         ccb = io->io_ccb;
1051         csio = &ccb->csio;
1052
1053         if (io->io_received + data_segment_len > csio->dxfer_len) {
1054                 ISCSI_SESSION_WARN(is, "oversize data segment (%zd bytes "
1055                     "at offset %zd, buffer is %d)",
1056                     data_segment_len, io->io_received, csio->dxfer_len);
1057                 icl_pdu_free(response);
1058                 iscsi_session_reconnect(is);
1059                 ISCSI_SESSION_UNLOCK(is);
1060                 return;
1061         }
1062
1063         oreceived = io->io_received;
1064         io->io_received += data_segment_len;
1065         received = io->io_received;
1066         if ((bhsdi->bhsdi_flags & BHSDI_FLAGS_S) != 0)
1067                 iscsi_outstanding_remove(is, io);
1068         ISCSI_SESSION_UNLOCK(is);
1069
1070         icl_pdu_get_data(response, 0, csio->data_ptr + oreceived, data_segment_len);
1071
1072         /*
1073          * XXX: Check DataSN.
1074          * XXX: Check F.
1075          */
1076         if ((bhsdi->bhsdi_flags & BHSDI_FLAGS_S) == 0) {
1077                 /*
1078                  * Nothing more to do.
1079                  */
1080                 icl_pdu_free(response);
1081                 return;
1082         }
1083
1084         //ISCSI_SESSION_DEBUG(is, "got S flag; status 0x%x", bhsdi->bhsdi_status);
1085         if (bhsdi->bhsdi_status == 0) {
1086                 ccb->ccb_h.status = CAM_REQ_CMP;
1087         } else {
1088                 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
1089                         xpt_freeze_devq(ccb->ccb_h.path, 1);
1090                         ISCSI_SESSION_DEBUG(is, "freezing devq");
1091                 }
1092                 ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_DEV_QFRZN;
1093                 csio->scsi_status = bhsdi->bhsdi_status;
1094         }
1095
1096         if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1097                 KASSERT(received <= csio->dxfer_len,
1098                     ("received > csio->dxfer_len"));
1099                 if (received < csio->dxfer_len) {
1100                         csio->resid = ntohl(bhsdi->bhsdi_residual_count);
1101                         if (csio->resid != csio->dxfer_len - received) {
1102                                 ISCSI_SESSION_WARN(is, "underflow mismatch: "
1103                                     "target indicates %d, we calculated %zd",
1104                                     csio->resid, csio->dxfer_len - received);
1105                         }
1106                         csio->resid = csio->dxfer_len - received;
1107                 }
1108         }
1109
1110         xpt_done(ccb);
1111         icl_pdu_free(response);
1112 }
1113
1114 static void
1115 iscsi_pdu_handle_logout_response(struct icl_pdu *response)
1116 {
1117
1118         ISCSI_SESSION_DEBUG(PDU_SESSION(response), "logout response");
1119         icl_pdu_free(response);
1120 }
1121
1122 static void
1123 iscsi_pdu_handle_r2t(struct icl_pdu *response)
1124 {
1125         struct icl_pdu *request;
1126         struct iscsi_session *is;
1127         struct iscsi_bhs_r2t *bhsr2t;
1128         struct iscsi_bhs_data_out *bhsdo;
1129         struct iscsi_outstanding *io;
1130         struct ccb_scsiio *csio;
1131         size_t off, len, total_len;
1132         int error;
1133
1134         is = PDU_SESSION(response);
1135
1136         bhsr2t = (struct iscsi_bhs_r2t *)response->ip_bhs;
1137         io = iscsi_outstanding_find(is, bhsr2t->bhsr2t_initiator_task_tag);
1138         if (io == NULL || io->io_ccb == NULL) {
1139                 ISCSI_SESSION_WARN(is, "bad itt 0x%x; reconnecting",
1140                     bhsr2t->bhsr2t_initiator_task_tag);
1141                 icl_pdu_free(response);
1142                 iscsi_session_reconnect(is);
1143                 return;
1144         }
1145
1146         csio = &io->io_ccb->csio;
1147
1148         if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_OUT) {
1149                 ISCSI_SESSION_WARN(is, "received R2T for read command; reconnecting");
1150                 icl_pdu_free(response);
1151                 iscsi_session_reconnect(is);
1152                 return;
1153         }
1154
1155         /*
1156          * XXX: Verify R2TSN.
1157          */
1158
1159         io->io_datasn = 0;
1160
1161         off = ntohl(bhsr2t->bhsr2t_buffer_offset);
1162         if (off > csio->dxfer_len) {
1163                 ISCSI_SESSION_WARN(is, "target requested invalid offset "
1164                     "%zd, buffer is is %d; reconnecting", off, csio->dxfer_len);
1165                 icl_pdu_free(response);
1166                 iscsi_session_reconnect(is);
1167                 return;
1168         }
1169
1170         total_len = ntohl(bhsr2t->bhsr2t_desired_data_transfer_length);
1171         if (total_len == 0 || total_len > csio->dxfer_len) {
1172                 ISCSI_SESSION_WARN(is, "target requested invalid length "
1173                     "%zd, buffer is %d; reconnecting", total_len, csio->dxfer_len);
1174                 icl_pdu_free(response);
1175                 iscsi_session_reconnect(is);
1176                 return;
1177         }
1178
1179         //ISCSI_SESSION_DEBUG(is, "r2t; off %zd, len %zd", off, total_len);
1180
1181         for (;;) {
1182                 len = total_len;
1183
1184                 if (len > is->is_max_data_segment_length)
1185                         len = is->is_max_data_segment_length;
1186
1187                 if (off + len > csio->dxfer_len) {
1188                         ISCSI_SESSION_WARN(is, "target requested invalid "
1189                             "length/offset %zd, buffer is %d; reconnecting",
1190                             off + len, csio->dxfer_len);
1191                         icl_pdu_free(response);
1192                         iscsi_session_reconnect(is);
1193                         return;
1194                 }
1195
1196                 request = icl_pdu_new(response->ip_conn, M_NOWAIT);
1197                 if (request == NULL) {
1198                         icl_pdu_free(response);
1199                         iscsi_session_reconnect(is);
1200                         return;
1201                 }
1202
1203                 bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs;
1204                 bhsdo->bhsdo_opcode = ISCSI_BHS_OPCODE_SCSI_DATA_OUT;
1205                 bhsdo->bhsdo_lun = bhsr2t->bhsr2t_lun;
1206                 bhsdo->bhsdo_initiator_task_tag =
1207                     bhsr2t->bhsr2t_initiator_task_tag;
1208                 bhsdo->bhsdo_target_transfer_tag =
1209                     bhsr2t->bhsr2t_target_transfer_tag;
1210                 bhsdo->bhsdo_datasn = htonl(io->io_datasn++);
1211                 bhsdo->bhsdo_buffer_offset = htonl(off);
1212                 error = icl_pdu_append_data(request, csio->data_ptr + off, len,
1213                     M_NOWAIT);
1214                 if (error != 0) {
1215                         ISCSI_SESSION_WARN(is, "failed to allocate memory; "
1216                             "reconnecting");
1217                         icl_pdu_free(request);
1218                         icl_pdu_free(response);
1219                         iscsi_session_reconnect(is);
1220                         return;
1221                 }
1222
1223                 off += len;
1224                 total_len -= len;
1225
1226                 if (total_len == 0) {
1227                         bhsdo->bhsdo_flags |= BHSDO_FLAGS_F;
1228                         //ISCSI_SESSION_DEBUG(is, "setting F, off %zd", off);
1229                 } else {
1230                         //ISCSI_SESSION_DEBUG(is, "not finished, off %zd", off);
1231                 }
1232
1233                 iscsi_pdu_queue_locked(request);
1234
1235                 if (total_len == 0)
1236                         break;
1237         }
1238
1239         icl_pdu_free(response);
1240 }
1241
1242 static void
1243 iscsi_pdu_handle_async_message(struct icl_pdu *response)
1244 {
1245         struct iscsi_bhs_asynchronous_message *bhsam;
1246         struct iscsi_session *is;
1247
1248         is = PDU_SESSION(response);
1249         bhsam = (struct iscsi_bhs_asynchronous_message *)response->ip_bhs;
1250         switch (bhsam->bhsam_async_event) {
1251         case BHSAM_EVENT_TARGET_REQUESTS_LOGOUT:
1252                 ISCSI_SESSION_WARN(is, "target requests logout; removing session");
1253                 iscsi_session_logout(is);
1254                 iscsi_session_terminate(is);
1255                 break;
1256         case BHSAM_EVENT_TARGET_TERMINATES_CONNECTION:
1257                 ISCSI_SESSION_WARN(is, "target indicates it will drop drop the connection");
1258                 break;
1259         case BHSAM_EVENT_TARGET_TERMINATES_SESSION:
1260                 ISCSI_SESSION_WARN(is, "target indicates it will drop drop the session");
1261                 break;
1262         default:
1263                 /*
1264                  * XXX: Technically, we're obligated to also handle
1265                  *      parameter renegotiation.
1266                  */
1267                 ISCSI_SESSION_WARN(is, "ignoring AsyncEvent %d", bhsam->bhsam_async_event);
1268                 break;
1269         }
1270
1271         icl_pdu_free(response);
1272 }
1273
1274 static void
1275 iscsi_pdu_handle_reject(struct icl_pdu *response)
1276 {
1277         struct iscsi_bhs_reject *bhsr;
1278         struct iscsi_session *is;
1279
1280         is = PDU_SESSION(response);
1281         bhsr = (struct iscsi_bhs_reject *)response->ip_bhs;
1282         ISCSI_SESSION_WARN(is, "received Reject PDU, reason 0x%x; protocol error?",
1283             bhsr->bhsr_reason);
1284
1285         icl_pdu_free(response);
1286 }
1287
1288 static int
1289 iscsi_ioctl_daemon_wait(struct iscsi_softc *sc,
1290     struct iscsi_daemon_request *request)
1291 {
1292         struct iscsi_session *is;
1293         int error;
1294
1295         sx_slock(&sc->sc_lock);
1296         for (;;) {
1297                 TAILQ_FOREACH(is, &sc->sc_sessions, is_next) {
1298                         ISCSI_SESSION_LOCK(is);
1299                         if (is->is_waiting_for_iscsid)
1300                                 break;
1301                         ISCSI_SESSION_UNLOCK(is);
1302                 }
1303
1304                 if (is == NULL) {
1305                         /*
1306                          * No session requires attention from iscsid(8); wait.
1307                          */
1308                         error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock);
1309                         if (error != 0) {
1310                                 sx_sunlock(&sc->sc_lock);
1311                                 return (error);
1312                         }
1313                         continue;
1314                 }
1315
1316                 is->is_waiting_for_iscsid = false;
1317                 is->is_login_phase = true;
1318                 is->is_reason[0] = '\0';
1319                 ISCSI_SESSION_UNLOCK(is);
1320
1321                 request->idr_session_id = is->is_id;
1322                 memcpy(&request->idr_isid, &is->is_isid,
1323                     sizeof(request->idr_isid));
1324                 request->idr_tsih = 0;  /* New or reinstated session. */
1325                 memcpy(&request->idr_conf, &is->is_conf,
1326                     sizeof(request->idr_conf));
1327
1328                 sx_sunlock(&sc->sc_lock);
1329                 return (0);
1330         }
1331 }
1332
1333 static int
1334 iscsi_ioctl_daemon_handoff(struct iscsi_softc *sc,
1335     struct iscsi_daemon_handoff *handoff)
1336 {
1337         struct iscsi_session *is;
1338         int error;
1339
1340         sx_slock(&sc->sc_lock);
1341
1342         /*
1343          * Find the session to hand off socket to.
1344          */
1345         TAILQ_FOREACH(is, &sc->sc_sessions, is_next) {
1346                 if (is->is_id == handoff->idh_session_id)
1347                         break;
1348         }
1349         if (is == NULL) {
1350                 sx_sunlock(&sc->sc_lock);
1351                 return (ESRCH);
1352         }
1353         ISCSI_SESSION_LOCK(is);
1354         if (is->is_conf.isc_discovery || is->is_terminating) {
1355                 ISCSI_SESSION_UNLOCK(is);
1356                 sx_sunlock(&sc->sc_lock);
1357                 return (EINVAL);
1358         }
1359         if (is->is_connected) {
1360                 /*
1361                  * This might have happened because another iscsid(8)
1362                  * instance handed off the connection in the meantime.
1363                  * Just return.
1364                  */
1365                 ISCSI_SESSION_WARN(is, "handoff on already connected "
1366                     "session");
1367                 ISCSI_SESSION_UNLOCK(is);
1368                 sx_sunlock(&sc->sc_lock);
1369                 return (EBUSY);
1370         }
1371
1372         strlcpy(is->is_target_alias, handoff->idh_target_alias,
1373             sizeof(is->is_target_alias));
1374         is->is_tsih = handoff->idh_tsih;
1375         is->is_statsn = handoff->idh_statsn;
1376         is->is_initial_r2t = handoff->idh_initial_r2t;
1377         is->is_immediate_data = handoff->idh_immediate_data;
1378         is->is_max_data_segment_length = handoff->idh_max_data_segment_length;
1379         is->is_max_burst_length = handoff->idh_max_burst_length;
1380         is->is_first_burst_length = handoff->idh_first_burst_length;
1381
1382         if (handoff->idh_header_digest == ISCSI_DIGEST_CRC32C)
1383                 is->is_conn->ic_header_crc32c = true;
1384         else
1385                 is->is_conn->ic_header_crc32c = false;
1386         if (handoff->idh_data_digest == ISCSI_DIGEST_CRC32C)
1387                 is->is_conn->ic_data_crc32c = true;
1388         else
1389                 is->is_conn->ic_data_crc32c = false;
1390
1391         is->is_cmdsn = 0;
1392         is->is_expcmdsn = 0;
1393         is->is_maxcmdsn = 0;
1394         is->is_waiting_for_iscsid = false;
1395         is->is_login_phase = false;
1396         is->is_timeout = 0;
1397         is->is_connected = true;
1398         is->is_reason[0] = '\0';
1399
1400         ISCSI_SESSION_UNLOCK(is);
1401
1402 #ifdef ICL_KERNEL_PROXY
1403         if (handoff->idh_socket != 0) {
1404 #endif
1405                 /*
1406                  * Handoff without using ICL proxy.
1407                  */
1408                 error = icl_conn_handoff(is->is_conn, handoff->idh_socket);
1409                 if (error != 0) {
1410                         sx_sunlock(&sc->sc_lock);
1411                         iscsi_session_terminate(is);
1412                         return (error);
1413                 }
1414 #ifdef ICL_KERNEL_PROXY
1415         }
1416 #endif
1417
1418         sx_sunlock(&sc->sc_lock);
1419
1420         if (is->is_sim != NULL) {
1421                 /*
1422                  * When reconnecting, there already is SIM allocated for the session.
1423                  */
1424                 KASSERT(is->is_simq_frozen, ("reconnect without frozen simq"));
1425                 ISCSI_SESSION_LOCK(is);
1426                 ISCSI_SESSION_DEBUG(is, "releasing");
1427                 xpt_release_simq(is->is_sim, 1);
1428                 is->is_simq_frozen = false;
1429                 ISCSI_SESSION_UNLOCK(is);
1430
1431         } else {
1432                 ISCSI_SESSION_LOCK(is);
1433                 is->is_devq = cam_simq_alloc(maxtags);
1434                 if (is->is_devq == NULL) {
1435                         ISCSI_SESSION_WARN(is, "failed to allocate simq");
1436                         iscsi_session_terminate(is);
1437                         return (ENOMEM);
1438                 }
1439
1440                 is->is_sim = cam_sim_alloc(iscsi_action, iscsi_poll, "iscsi",
1441                     is, is->is_id /* unit */, &is->is_lock,
1442                     1, maxtags, is->is_devq);
1443                 if (is->is_sim == NULL) {
1444                         ISCSI_SESSION_UNLOCK(is);
1445                         ISCSI_SESSION_WARN(is, "failed to allocate SIM");
1446                         cam_simq_free(is->is_devq);
1447                         iscsi_session_terminate(is);
1448                         return (ENOMEM);
1449                 }
1450
1451                 error = xpt_bus_register(is->is_sim, NULL, 0);
1452                 if (error != 0) {
1453                         ISCSI_SESSION_UNLOCK(is);
1454                         ISCSI_SESSION_WARN(is, "failed to register bus");
1455                         iscsi_session_terminate(is);
1456                         return (ENOMEM);
1457                 }
1458
1459                 error = xpt_create_path(&is->is_path, /*periph*/NULL,
1460                     cam_sim_path(is->is_sim), CAM_TARGET_WILDCARD,
1461                     CAM_LUN_WILDCARD);
1462                 if (error != CAM_REQ_CMP) {
1463                         ISCSI_SESSION_UNLOCK(is);
1464                         ISCSI_SESSION_WARN(is, "failed to create path");
1465                         iscsi_session_terminate(is);
1466                         return (ENOMEM);
1467                 }
1468                 ISCSI_SESSION_UNLOCK(is);
1469         }
1470
1471         return (0);
1472 }
1473
1474 static int
1475 iscsi_ioctl_daemon_fail(struct iscsi_softc *sc,
1476     struct iscsi_daemon_fail *fail)
1477 {
1478         struct iscsi_session *is;
1479
1480         sx_slock(&sc->sc_lock);
1481
1482         TAILQ_FOREACH(is, &sc->sc_sessions, is_next) {
1483                 if (is->is_id == fail->idf_session_id)
1484                         break;
1485         }
1486         if (is == NULL) {
1487                 sx_sunlock(&sc->sc_lock);
1488                 return (ESRCH);
1489         }
1490         ISCSI_SESSION_LOCK(is);
1491         ISCSI_SESSION_DEBUG(is, "iscsid(8) failed: %s",
1492             fail->idf_reason);
1493         strlcpy(is->is_reason, fail->idf_reason, sizeof(is->is_reason));
1494         //is->is_waiting_for_iscsid = false;
1495         //is->is_login_phase = true;
1496         //iscsi_session_reconnect(is);
1497         ISCSI_SESSION_UNLOCK(is);
1498         sx_sunlock(&sc->sc_lock);
1499
1500         return (0);
1501 }
1502
1503 #ifdef ICL_KERNEL_PROXY
1504 static int
1505 iscsi_ioctl_daemon_connect(struct iscsi_softc *sc,
1506     struct iscsi_daemon_connect *idc)
1507 {
1508         struct iscsi_session *is;
1509         struct sockaddr *from_sa, *to_sa;
1510         int error;
1511
1512         sx_slock(&sc->sc_lock);
1513         TAILQ_FOREACH(is, &sc->sc_sessions, is_next) {
1514                 if (is->is_id == idc->idc_session_id)
1515                         break;
1516         }
1517         if (is == NULL) {
1518                 sx_sunlock(&sc->sc_lock);
1519                 return (ESRCH);
1520         }
1521         sx_sunlock(&sc->sc_lock);
1522
1523         if (idc->idc_from_addrlen > 0) {
1524                 error = getsockaddr(&from_sa, (void *)idc->idc_from_addr, idc->idc_from_addrlen);
1525                 if (error != 0) {
1526                         ISCSI_SESSION_WARN(is,
1527                             "getsockaddr failed with error %d", error);
1528                         return (error);
1529                 }
1530         } else {
1531                 from_sa = NULL;
1532         }
1533         error = getsockaddr(&to_sa, (void *)idc->idc_to_addr, idc->idc_to_addrlen);
1534         if (error != 0) {
1535                 ISCSI_SESSION_WARN(is, "getsockaddr failed with error %d",
1536                     error);
1537                 free(from_sa, M_SONAME);
1538                 return (error);
1539         }
1540
1541         ISCSI_SESSION_LOCK(is);
1542         is->is_waiting_for_iscsid = false;
1543         is->is_login_phase = true;
1544         is->is_timeout = 0;
1545         ISCSI_SESSION_UNLOCK(is);
1546
1547         error = icl_conn_connect(is->is_conn, idc->idc_iser, idc->idc_domain,
1548             idc->idc_socktype, idc->idc_protocol, from_sa, to_sa);
1549         free(from_sa, M_SONAME);
1550         free(to_sa, M_SONAME);
1551
1552         /*
1553          * Digests are always disabled during login phase.
1554          */
1555         is->is_conn->ic_header_crc32c = false;
1556         is->is_conn->ic_data_crc32c = false;
1557
1558         return (error);
1559 }
1560
1561 static int
1562 iscsi_ioctl_daemon_send(struct iscsi_softc *sc,
1563     struct iscsi_daemon_send *ids)
1564 {
1565         struct iscsi_session *is;
1566         struct icl_pdu *ip;
1567         size_t datalen;
1568         void *data;
1569         int error;
1570
1571         sx_slock(&sc->sc_lock);
1572         TAILQ_FOREACH(is, &sc->sc_sessions, is_next) {
1573                 if (is->is_id == ids->ids_session_id)
1574                         break;
1575         }
1576         if (is == NULL) {
1577                 sx_sunlock(&sc->sc_lock);
1578                 return (ESRCH);
1579         }
1580         sx_sunlock(&sc->sc_lock);
1581
1582         if (is->is_login_phase == false)
1583                 return (EBUSY);
1584
1585         if (is->is_terminating || is->is_reconnecting)
1586                 return (EIO);
1587
1588         datalen = ids->ids_data_segment_len;
1589         if (datalen > ISCSI_MAX_DATA_SEGMENT_LENGTH)
1590                 return (EINVAL);
1591         if (datalen > 0) {
1592                 data = malloc(datalen, M_ISCSI, M_WAITOK);
1593                 error = copyin(ids->ids_data_segment, data, datalen);
1594                 if (error != 0) {
1595                         free(data, M_ISCSI);
1596                         return (error);
1597                 }
1598         }
1599
1600         ip = icl_pdu_new(is->is_conn, M_WAITOK);
1601         memcpy(ip->ip_bhs, ids->ids_bhs, sizeof(*ip->ip_bhs));
1602         if (datalen > 0) {
1603                 error = icl_pdu_append_data(ip, data, datalen, M_WAITOK);
1604                 KASSERT(error == 0, ("icl_pdu_append_data(..., M_WAITOK) failed"));
1605                 free(data, M_ISCSI);
1606         }
1607         icl_pdu_queue(ip);
1608
1609         return (0);
1610 }
1611
1612 static int
1613 iscsi_ioctl_daemon_receive(struct iscsi_softc *sc,
1614     struct iscsi_daemon_receive *idr)
1615 {
1616         struct iscsi_session *is;
1617         struct icl_pdu *ip;
1618         void *data;
1619
1620         sx_slock(&sc->sc_lock);
1621         TAILQ_FOREACH(is, &sc->sc_sessions, is_next) {
1622                 if (is->is_id == idr->idr_session_id)
1623                         break;
1624         }
1625         if (is == NULL) {
1626                 sx_sunlock(&sc->sc_lock);
1627                 return (ESRCH);
1628         }
1629         sx_sunlock(&sc->sc_lock);
1630
1631         if (is->is_login_phase == false)
1632                 return (EBUSY);
1633
1634         ISCSI_SESSION_LOCK(is);
1635         while (is->is_login_pdu == NULL &&
1636             is->is_terminating == false &&
1637             is->is_reconnecting == false)
1638                 cv_wait(&is->is_login_cv, &is->is_lock);
1639         if (is->is_terminating || is->is_reconnecting) {
1640                 ISCSI_SESSION_UNLOCK(is);
1641                 return (EIO);
1642         }
1643         ip = is->is_login_pdu;
1644         is->is_login_pdu = NULL;
1645         ISCSI_SESSION_UNLOCK(is);
1646
1647         if (ip->ip_data_len > idr->idr_data_segment_len) {
1648                 icl_pdu_free(ip);
1649                 return (EMSGSIZE);
1650         }
1651
1652         copyout(ip->ip_bhs, idr->idr_bhs, sizeof(*ip->ip_bhs));
1653         if (ip->ip_data_len > 0) {
1654                 data = malloc(ip->ip_data_len, M_ISCSI, M_WAITOK);
1655                 icl_pdu_get_data(ip, 0, data, ip->ip_data_len);
1656                 copyout(data, idr->idr_data_segment, ip->ip_data_len);
1657                 free(data, M_ISCSI);
1658         }
1659
1660         icl_pdu_free(ip);
1661
1662         return (0);
1663 }
1664 #endif /* ICL_KERNEL_PROXY */
1665
1666 static void
1667 iscsi_sanitize_session_conf(struct iscsi_session_conf *isc)
1668 {
1669         /*
1670          * Just make sure all the fields are null-terminated.
1671          *
1672          * XXX: This is not particularly secure.  We should
1673          *      create our own conf and then copy in relevant
1674          *      fields.
1675          */
1676         isc->isc_initiator[ISCSI_NAME_LEN - 1] = '\0';
1677         isc->isc_initiator_addr[ISCSI_ADDR_LEN - 1] = '\0';
1678         isc->isc_initiator_alias[ISCSI_ALIAS_LEN - 1] = '\0';
1679         isc->isc_target[ISCSI_NAME_LEN - 1] = '\0';
1680         isc->isc_target_addr[ISCSI_ADDR_LEN - 1] = '\0';
1681         isc->isc_user[ISCSI_NAME_LEN - 1] = '\0';
1682         isc->isc_secret[ISCSI_SECRET_LEN - 1] = '\0';
1683         isc->isc_mutual_user[ISCSI_NAME_LEN - 1] = '\0';
1684         isc->isc_mutual_secret[ISCSI_SECRET_LEN - 1] = '\0';
1685 }
1686
1687 static bool
1688 iscsi_valid_session_conf(const struct iscsi_session_conf *isc)
1689 {
1690
1691         if (isc->isc_initiator[0] == '\0') {
1692                 ISCSI_DEBUG("empty isc_initiator");
1693                 return (false);
1694         }
1695
1696         if (isc->isc_target_addr[0] == '\0') {
1697                 ISCSI_DEBUG("empty isc_target_addr");
1698                 return (false);
1699         }
1700
1701         if (isc->isc_discovery != 0 && isc->isc_target[0] != 0) {
1702                 ISCSI_DEBUG("non-empty isc_target for discovery session");
1703                 return (false);
1704         }
1705
1706         if (isc->isc_discovery == 0 && isc->isc_target[0] == 0) {
1707                 ISCSI_DEBUG("empty isc_target for non-discovery session");
1708                 return (false);
1709         }
1710
1711         return (true);
1712 }
1713
1714 static int
1715 iscsi_ioctl_session_add(struct iscsi_softc *sc, struct iscsi_session_add *isa)
1716 {
1717         struct iscsi_session *is;
1718         const struct iscsi_session *is2;
1719         int error;
1720
1721         iscsi_sanitize_session_conf(&isa->isa_conf);
1722         if (iscsi_valid_session_conf(&isa->isa_conf) == false)
1723                 return (EINVAL);
1724
1725         is = malloc(sizeof(*is), M_ISCSI, M_ZERO | M_WAITOK);
1726         memcpy(&is->is_conf, &isa->isa_conf, sizeof(is->is_conf));
1727
1728         sx_xlock(&sc->sc_lock);
1729
1730         /*
1731          * Prevent duplicates.
1732          */
1733         TAILQ_FOREACH(is2, &sc->sc_sessions, is_next) {
1734                 if (!!is->is_conf.isc_discovery !=
1735                     !!is2->is_conf.isc_discovery)
1736                         continue;
1737
1738                 if (strcmp(is->is_conf.isc_target_addr,
1739                     is2->is_conf.isc_target_addr) != 0)
1740                         continue;
1741
1742                 if (is->is_conf.isc_discovery == 0 &&
1743                     strcmp(is->is_conf.isc_target,
1744                     is2->is_conf.isc_target) != 0)
1745                         continue;
1746
1747                 sx_xunlock(&sc->sc_lock);
1748                 free(is, M_ISCSI);
1749                 return (EBUSY);
1750         }
1751
1752         is->is_conn = icl_conn_new("iscsi", &is->is_lock);
1753         is->is_conn->ic_receive = iscsi_receive_callback;
1754         is->is_conn->ic_error = iscsi_error_callback;
1755         is->is_conn->ic_prv0 = is;
1756         TAILQ_INIT(&is->is_outstanding);
1757         STAILQ_INIT(&is->is_postponed);
1758         mtx_init(&is->is_lock, "iscsi_lock", NULL, MTX_DEF);
1759         cv_init(&is->is_maintenance_cv, "iscsi_mt");
1760 #ifdef ICL_KERNEL_PROXY
1761         cv_init(&is->is_login_cv, "iscsi_login");
1762 #endif
1763
1764         is->is_softc = sc;
1765         sc->sc_last_session_id++;
1766         is->is_id = sc->sc_last_session_id;
1767         is->is_isid[0] = 0x80; /* RFC 3720, 10.12.5: 10b, "Random" ISID. */
1768         arc4rand(&is->is_isid[1], 5, 0);
1769         is->is_tsih = 0;
1770         callout_init(&is->is_callout, 1);
1771
1772         error = kthread_add(iscsi_maintenance_thread, is, NULL, NULL, 0, 0, "iscsimt");
1773         if (error != 0) {
1774                 ISCSI_SESSION_WARN(is, "kthread_add(9) failed with error %d", error);
1775                 sx_xunlock(&sc->sc_lock);
1776                 return (error);
1777         }
1778
1779         callout_reset(&is->is_callout, 1 * hz, iscsi_callout, is);
1780         TAILQ_INSERT_TAIL(&sc->sc_sessions, is, is_next);
1781
1782         /*
1783          * Trigger immediate reconnection.
1784          */
1785         ISCSI_SESSION_LOCK(is);
1786         is->is_waiting_for_iscsid = true;
1787         strlcpy(is->is_reason, "Waiting for iscsid(8)", sizeof(is->is_reason));
1788         ISCSI_SESSION_UNLOCK(is);
1789         cv_signal(&sc->sc_cv);
1790
1791         sx_xunlock(&sc->sc_lock);
1792
1793         return (0);
1794 }
1795
1796 static bool
1797 iscsi_session_conf_matches(unsigned int id1, const struct iscsi_session_conf *c1,
1798     unsigned int id2, const struct iscsi_session_conf *c2)
1799 {
1800
1801         if (id2 != 0 && id2 != id1)
1802                 return (false);
1803         if (c2->isc_target[0] != '\0' &&
1804             strcmp(c1->isc_target, c2->isc_target) != 0)
1805                 return (false);
1806         if (c2->isc_target_addr[0] != '\0' &&
1807             strcmp(c1->isc_target_addr, c2->isc_target_addr) != 0)
1808                 return (false);
1809         return (true);
1810 }
1811
1812 static int
1813 iscsi_ioctl_session_remove(struct iscsi_softc *sc,
1814     struct iscsi_session_remove *isr)
1815 {
1816         struct iscsi_session *is, *tmp;
1817         bool found = false;
1818
1819         iscsi_sanitize_session_conf(&isr->isr_conf);
1820
1821         sx_xlock(&sc->sc_lock);
1822         TAILQ_FOREACH_SAFE(is, &sc->sc_sessions, is_next, tmp) {
1823                 ISCSI_SESSION_LOCK(is);
1824                 if (iscsi_session_conf_matches(is->is_id, &is->is_conf,
1825                     isr->isr_session_id, &isr->isr_conf)) {
1826                         found = true;
1827                         iscsi_session_logout(is);
1828                         iscsi_session_terminate(is);
1829                 }
1830                 ISCSI_SESSION_UNLOCK(is);
1831         }
1832         sx_xunlock(&sc->sc_lock);
1833
1834         if (!found)
1835                 return (ESRCH);
1836
1837         return (0);
1838 }
1839
1840 static int
1841 iscsi_ioctl_session_list(struct iscsi_softc *sc, struct iscsi_session_list *isl)
1842 {
1843         int error;
1844         unsigned int i = 0;
1845         struct iscsi_session *is;
1846         struct iscsi_session_state iss;
1847
1848         sx_slock(&sc->sc_lock);
1849         TAILQ_FOREACH(is, &sc->sc_sessions, is_next) {
1850                 if (i >= isl->isl_nentries) {
1851                         sx_sunlock(&sc->sc_lock);
1852                         return (EMSGSIZE);
1853                 }
1854                 memset(&iss, 0, sizeof(iss));
1855                 memcpy(&iss.iss_conf, &is->is_conf, sizeof(iss.iss_conf));
1856                 iss.iss_id = is->is_id;
1857                 strlcpy(iss.iss_target_alias, is->is_target_alias, sizeof(iss.iss_target_alias));
1858                 strlcpy(iss.iss_reason, is->is_reason, sizeof(iss.iss_reason));
1859
1860                 if (is->is_conn->ic_header_crc32c)
1861                         iss.iss_header_digest = ISCSI_DIGEST_CRC32C;
1862                 else
1863                         iss.iss_header_digest = ISCSI_DIGEST_NONE;
1864
1865                 if (is->is_conn->ic_data_crc32c)
1866                         iss.iss_data_digest = ISCSI_DIGEST_CRC32C;
1867                 else
1868                         iss.iss_data_digest = ISCSI_DIGEST_NONE;
1869
1870                 iss.iss_max_data_segment_length = is->is_max_data_segment_length;
1871                 iss.iss_immediate_data = is->is_immediate_data;
1872                 iss.iss_connected = is->is_connected;
1873         
1874                 error = copyout(&iss, isl->isl_pstates + i, sizeof(iss));
1875                 if (error != 0) {
1876                         sx_sunlock(&sc->sc_lock);
1877                         return (error);
1878                 }
1879                 i++;
1880         }
1881         sx_sunlock(&sc->sc_lock);
1882
1883         isl->isl_nentries = i;
1884
1885         return (0);
1886 }
1887
1888 static int
1889 iscsi_ioctl_session_modify(struct iscsi_softc *sc,
1890     struct iscsi_session_modify *ism)
1891 {
1892         struct iscsi_session *is;
1893
1894         iscsi_sanitize_session_conf(&ism->ism_conf);
1895         if (iscsi_valid_session_conf(&ism->ism_conf) == false)
1896                 return (EINVAL);
1897
1898         sx_xlock(&sc->sc_lock);
1899         TAILQ_FOREACH(is, &sc->sc_sessions, is_next) {
1900                 ISCSI_SESSION_LOCK(is);
1901                 if (is->is_id == ism->ism_session_id)
1902                         break;
1903                 ISCSI_SESSION_UNLOCK(is);
1904         }
1905         if (is == NULL) {
1906                 sx_xunlock(&sc->sc_lock);
1907                 return (ESRCH);
1908         }
1909         sx_xunlock(&sc->sc_lock);
1910
1911         memcpy(&is->is_conf, &ism->ism_conf, sizeof(is->is_conf));
1912         ISCSI_SESSION_UNLOCK(is);
1913
1914         iscsi_session_reconnect(is);
1915
1916         return (0);
1917 }
1918
1919 static int
1920 iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode,
1921     struct thread *td)
1922 {
1923         struct iscsi_softc *sc;
1924
1925         sc = dev->si_drv1;
1926
1927         switch (cmd) {
1928         case ISCSIDWAIT:
1929                 return (iscsi_ioctl_daemon_wait(sc,
1930                     (struct iscsi_daemon_request *)arg));
1931         case ISCSIDHANDOFF:
1932                 return (iscsi_ioctl_daemon_handoff(sc,
1933                     (struct iscsi_daemon_handoff *)arg));
1934         case ISCSIDFAIL:
1935                 return (iscsi_ioctl_daemon_fail(sc,
1936                     (struct iscsi_daemon_fail *)arg));
1937 #ifdef ICL_KERNEL_PROXY
1938         case ISCSIDCONNECT:
1939                 return (iscsi_ioctl_daemon_connect(sc,
1940                     (struct iscsi_daemon_connect *)arg));
1941         case ISCSIDSEND:
1942                 return (iscsi_ioctl_daemon_send(sc,
1943                     (struct iscsi_daemon_send *)arg));
1944         case ISCSIDRECEIVE:
1945                 return (iscsi_ioctl_daemon_receive(sc,
1946                     (struct iscsi_daemon_receive *)arg));
1947 #endif /* ICL_KERNEL_PROXY */
1948         case ISCSISADD:
1949                 return (iscsi_ioctl_session_add(sc,
1950                     (struct iscsi_session_add *)arg));
1951         case ISCSISREMOVE:
1952                 return (iscsi_ioctl_session_remove(sc,
1953                     (struct iscsi_session_remove *)arg));
1954         case ISCSISLIST:
1955                 return (iscsi_ioctl_session_list(sc,
1956                     (struct iscsi_session_list *)arg));
1957         case ISCSISMODIFY:
1958                 return (iscsi_ioctl_session_modify(sc,
1959                     (struct iscsi_session_modify *)arg));
1960         default:
1961                 return (EINVAL);
1962         }
1963 }
1964
1965 static uint64_t
1966 iscsi_encode_lun(uint32_t lun)
1967 {
1968         uint8_t encoded[8];
1969         uint64_t result;
1970
1971         memset(encoded, 0, sizeof(encoded));
1972
1973         if (lun < 256) {
1974                 /*
1975                  * Peripheral device addressing.
1976                  */
1977                 encoded[1] = lun;
1978         } else if (lun < 16384) {
1979                 /*
1980                  * Flat space addressing.
1981                  */
1982                 encoded[0] = 0x40;
1983                 encoded[0] |= (lun >> 8) & 0x3f;
1984                 encoded[1] = lun & 0xff;
1985         } else {
1986                 /*
1987                  * Extended flat space addressing.
1988                  */
1989                 encoded[0] = 0xd2;
1990                 encoded[1] = lun >> 16;
1991                 encoded[2] = lun >> 8;
1992                 encoded[3] = lun;
1993         }
1994
1995         memcpy(&result, encoded, sizeof(result));
1996         return (result);
1997 }
1998
1999 static struct iscsi_outstanding *
2000 iscsi_outstanding_find(struct iscsi_session *is, uint32_t initiator_task_tag)
2001 {
2002         struct iscsi_outstanding *io;
2003
2004         ISCSI_SESSION_LOCK_ASSERT(is);
2005
2006         TAILQ_FOREACH(io, &is->is_outstanding, io_next) {
2007                 if (io->io_initiator_task_tag == initiator_task_tag)
2008                         return (io);
2009         }
2010         return (NULL);
2011 }
2012
2013 static struct iscsi_outstanding *
2014 iscsi_outstanding_find_ccb(struct iscsi_session *is, union ccb *ccb)
2015 {
2016         struct iscsi_outstanding *io;
2017
2018         ISCSI_SESSION_LOCK_ASSERT(is);
2019
2020         TAILQ_FOREACH(io, &is->is_outstanding, io_next) {
2021                 if (io->io_ccb == ccb)
2022                         return (io);
2023         }
2024         return (NULL);
2025 }
2026
2027 static struct iscsi_outstanding *
2028 iscsi_outstanding_add(struct iscsi_session *is,
2029     uint32_t initiator_task_tag, union ccb *ccb)
2030 {
2031         struct iscsi_outstanding *io;
2032
2033         ISCSI_SESSION_LOCK_ASSERT(is);
2034
2035         KASSERT(iscsi_outstanding_find(is, initiator_task_tag) == NULL,
2036             ("initiator_task_tag 0x%x already added", initiator_task_tag));
2037
2038         io = uma_zalloc(iscsi_outstanding_zone, M_NOWAIT | M_ZERO);
2039         if (io == NULL) {
2040                 ISCSI_SESSION_WARN(is, "failed to allocate %zd bytes", sizeof(*io));
2041                 return (NULL);
2042         }
2043         io->io_initiator_task_tag = initiator_task_tag;
2044         io->io_ccb = ccb;
2045         TAILQ_INSERT_TAIL(&is->is_outstanding, io, io_next);
2046         return (io);
2047 }
2048
2049 static void
2050 iscsi_outstanding_remove(struct iscsi_session *is, struct iscsi_outstanding *io)
2051 {
2052
2053         ISCSI_SESSION_LOCK_ASSERT(is);
2054
2055         TAILQ_REMOVE(&is->is_outstanding, io, io_next);
2056         uma_zfree(iscsi_outstanding_zone, io);
2057 }
2058
2059 static void
2060 iscsi_action_abort(struct iscsi_session *is, union ccb *ccb)
2061 {
2062         struct icl_pdu *request;
2063         struct iscsi_bhs_task_management_request *bhstmr;
2064         struct ccb_abort *cab = &ccb->cab;
2065         struct iscsi_outstanding *io, *aio;
2066
2067         ISCSI_SESSION_LOCK_ASSERT(is);
2068
2069 #if 0
2070         KASSERT(is->is_login_phase == false, ("%s called during Login Phase", __func__));
2071 #else
2072         if (is->is_login_phase) {
2073                 ccb->ccb_h.status = CAM_REQ_ABORTED;
2074                 xpt_done(ccb);
2075                 return;
2076         }
2077 #endif
2078
2079         aio = iscsi_outstanding_find_ccb(is, cab->abort_ccb);
2080         if (aio == NULL) {
2081                 ccb->ccb_h.status = CAM_REQ_CMP;
2082                 xpt_done(ccb);
2083                 return;
2084         }
2085
2086         request = icl_pdu_new(is->is_conn, M_NOWAIT);
2087         if (request == NULL) {
2088                 ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
2089                 xpt_done(ccb);
2090                 return;
2091         }
2092
2093         bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs;
2094         bhstmr->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_REQUEST;
2095         bhstmr->bhstmr_function = 0x80 | BHSTMR_FUNCTION_ABORT_TASK;
2096
2097         bhstmr->bhstmr_lun = iscsi_encode_lun(ccb->ccb_h.target_lun);
2098         bhstmr->bhstmr_initiator_task_tag = is->is_initiator_task_tag;
2099         is->is_initiator_task_tag++;
2100         bhstmr->bhstmr_referenced_task_tag = aio->io_initiator_task_tag;
2101
2102         io = iscsi_outstanding_add(is, bhstmr->bhstmr_initiator_task_tag, NULL);
2103         if (io == NULL) {
2104                 icl_pdu_free(request);
2105                 ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
2106                 xpt_done(ccb);
2107                 return;
2108         }
2109         io->io_datasn = aio->io_initiator_task_tag;
2110         iscsi_pdu_queue_locked(request);
2111 }
2112
2113 static void
2114 iscsi_action_scsiio(struct iscsi_session *is, union ccb *ccb)
2115 {
2116         struct icl_pdu *request;
2117         struct iscsi_bhs_scsi_command *bhssc;
2118         struct ccb_scsiio *csio;
2119         struct iscsi_outstanding *io;
2120         size_t len;
2121         int error;
2122
2123         ISCSI_SESSION_LOCK_ASSERT(is);
2124
2125 #if 0
2126         KASSERT(is->is_login_phase == false, ("%s called during Login Phase", __func__));
2127 #else
2128         if (is->is_login_phase) {
2129                 ISCSI_SESSION_DEBUG(is, "called during login phase");
2130                 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
2131                         xpt_freeze_devq(ccb->ccb_h.path, 1);
2132                         ISCSI_SESSION_DEBUG(is, "freezing devq");
2133                 }
2134                 ccb->ccb_h.status = CAM_REQ_ABORTED | CAM_DEV_QFRZN;
2135                 xpt_done(ccb);
2136                 return;
2137         }
2138 #endif
2139
2140         request = icl_pdu_new(is->is_conn, M_NOWAIT);
2141         if (request == NULL) {
2142                 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
2143                         xpt_freeze_devq(ccb->ccb_h.path, 1);
2144                         ISCSI_SESSION_DEBUG(is, "freezing devq");
2145                 }
2146                 ccb->ccb_h.status = CAM_RESRC_UNAVAIL | CAM_DEV_QFRZN;
2147                 xpt_done(ccb);
2148                 return;
2149         }
2150
2151         csio = &ccb->csio;
2152         bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs;
2153         bhssc->bhssc_opcode = ISCSI_BHS_OPCODE_SCSI_COMMAND;
2154         bhssc->bhssc_flags |= BHSSC_FLAGS_F;
2155         switch (csio->ccb_h.flags & CAM_DIR_MASK) {
2156         case CAM_DIR_IN:
2157                 bhssc->bhssc_flags |= BHSSC_FLAGS_R;
2158                 break;
2159         case CAM_DIR_OUT:
2160                 bhssc->bhssc_flags |= BHSSC_FLAGS_W;
2161                 break;
2162         }
2163
2164         if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
2165                 switch (csio->tag_action) {
2166                 case MSG_HEAD_OF_Q_TAG:
2167                         bhssc->bhssc_flags |= BHSSC_FLAGS_ATTR_HOQ;
2168                         break;
2169                 case MSG_ORDERED_Q_TAG:
2170                         bhssc->bhssc_flags |= BHSSC_FLAGS_ATTR_ORDERED;
2171                         break;
2172                 case MSG_ACA_TASK:
2173                         bhssc->bhssc_flags |= BHSSC_FLAGS_ATTR_ACA;
2174                         break;
2175                 case MSG_SIMPLE_Q_TAG:
2176                 default:
2177                         bhssc->bhssc_flags |= BHSSC_FLAGS_ATTR_SIMPLE;
2178                         break;
2179                 }
2180         } else
2181                 bhssc->bhssc_flags |= BHSSC_FLAGS_ATTR_UNTAGGED;
2182
2183         bhssc->bhssc_lun = iscsi_encode_lun(csio->ccb_h.target_lun);
2184         bhssc->bhssc_initiator_task_tag = is->is_initiator_task_tag;
2185         is->is_initiator_task_tag++;
2186         bhssc->bhssc_expected_data_transfer_length = htonl(csio->dxfer_len);
2187         KASSERT(csio->cdb_len <= sizeof(bhssc->bhssc_cdb),
2188             ("unsupported CDB size %zd", (size_t)csio->cdb_len));
2189
2190         if (csio->ccb_h.flags & CAM_CDB_POINTER)
2191                 memcpy(&bhssc->bhssc_cdb, csio->cdb_io.cdb_ptr, csio->cdb_len);
2192         else
2193                 memcpy(&bhssc->bhssc_cdb, csio->cdb_io.cdb_bytes, csio->cdb_len);
2194
2195         io = iscsi_outstanding_add(is, bhssc->bhssc_initiator_task_tag, ccb);
2196         if (io == NULL) {
2197                 icl_pdu_free(request);
2198                 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
2199                         xpt_freeze_devq(ccb->ccb_h.path, 1);
2200                         ISCSI_SESSION_DEBUG(is, "freezing devq");
2201                 }
2202                 ccb->ccb_h.status = CAM_RESRC_UNAVAIL | CAM_DEV_QFRZN;
2203                 xpt_done(ccb);
2204                 return;
2205         }
2206
2207         if (is->is_immediate_data &&
2208             (csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
2209                 len = csio->dxfer_len;
2210                 //ISCSI_SESSION_DEBUG(is, "adding %zd of immediate data", len);
2211                 if (len > is->is_first_burst_length) {
2212                         ISCSI_SESSION_DEBUG(is, "len %zd -> %zd", len, is->is_first_burst_length);
2213                         len = is->is_first_burst_length;
2214                 }
2215                 if (len > is->is_max_data_segment_length) {
2216                         ISCSI_SESSION_DEBUG(is, "len %zd -> %zd", len, is->is_max_data_segment_length);
2217                         len = is->is_max_data_segment_length;
2218                 }
2219
2220                 error = icl_pdu_append_data(request, csio->data_ptr, len, M_NOWAIT);
2221                 if (error != 0) {
2222                         icl_pdu_free(request);
2223                         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
2224                                 xpt_freeze_devq(ccb->ccb_h.path, 1);
2225                                 ISCSI_SESSION_DEBUG(is, "freezing devq");
2226                         }
2227                         ccb->ccb_h.status = CAM_RESRC_UNAVAIL | CAM_DEV_QFRZN;
2228                         xpt_done(ccb);
2229                         return;
2230                 }
2231         }
2232         iscsi_pdu_queue_locked(request);
2233 }
2234
2235 static void
2236 iscsi_action(struct cam_sim *sim, union ccb *ccb)
2237 {
2238         struct iscsi_session *is;
2239
2240         is = cam_sim_softc(sim);
2241
2242         ISCSI_SESSION_LOCK_ASSERT(is);
2243
2244         if (is->is_terminating ||
2245             (is->is_connected == false && fail_on_disconnection)) {
2246                 ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2247                 xpt_done(ccb);
2248                 return;
2249         }
2250
2251         switch (ccb->ccb_h.func_code) {
2252         case XPT_PATH_INQ:
2253         {
2254                 struct ccb_pathinq *cpi = &ccb->cpi;
2255
2256                 cpi->version_num = 1;
2257                 cpi->hba_inquiry = PI_TAG_ABLE;
2258                 cpi->target_sprt = 0;
2259                 //cpi->hba_misc = PIM_NOBUSRESET;
2260                 cpi->hba_misc = 0;
2261                 cpi->hba_eng_cnt = 0;
2262                 cpi->max_target = 0;
2263                 cpi->max_lun = 255;
2264                 //cpi->initiator_id = 0; /* XXX */
2265                 cpi->initiator_id = 64; /* XXX */
2266                 strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
2267                 strlcpy(cpi->hba_vid, "iSCSI", HBA_IDLEN);
2268                 strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
2269                 cpi->unit_number = cam_sim_unit(sim);
2270                 cpi->bus_id = cam_sim_bus(sim);
2271                 cpi->base_transfer_speed = 150000; /* XXX */
2272                 cpi->transport = XPORT_ISCSI;
2273                 cpi->transport_version = 0;
2274                 cpi->protocol = PROTO_SCSI;
2275                 cpi->protocol_version = SCSI_REV_SPC3;
2276                 cpi->maxio = MAXPHYS;
2277                 cpi->ccb_h.status = CAM_REQ_CMP;
2278                 break;
2279         }
2280         case XPT_GET_TRAN_SETTINGS:
2281         {
2282                 struct ccb_trans_settings       *cts;
2283                 struct ccb_trans_settings_scsi  *scsi;
2284
2285                 cts = &ccb->cts;
2286                 scsi = &cts->proto_specific.scsi;
2287
2288                 cts->protocol = PROTO_SCSI;
2289                 cts->protocol_version = SCSI_REV_SPC3;
2290                 cts->transport = XPORT_ISCSI;
2291                 cts->transport_version = 0;
2292                 scsi->valid = CTS_SCSI_VALID_TQ;
2293                 scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
2294                 cts->ccb_h.status = CAM_REQ_CMP;
2295                 break;
2296         }
2297         case XPT_CALC_GEOMETRY:
2298                 cam_calc_geometry(&ccb->ccg, /*extended*/1);
2299                 ccb->ccb_h.status = CAM_REQ_CMP;
2300                 break;
2301 #if 0
2302         /*
2303          * XXX: What's the point?
2304          */
2305         case XPT_RESET_BUS:
2306         case XPT_TERM_IO:
2307                 ISCSI_SESSION_DEBUG(is, "faking success for reset, abort, or term_io");
2308                 ccb->ccb_h.status = CAM_REQ_CMP;
2309                 break;
2310 #endif
2311         case XPT_ABORT:
2312                 iscsi_action_abort(is, ccb);
2313                 return;
2314         case XPT_SCSI_IO:
2315                 iscsi_action_scsiio(is, ccb);
2316                 return;
2317         default:
2318 #if 0
2319                 ISCSI_SESSION_DEBUG(is, "got unsupported code 0x%x", ccb->ccb_h.func_code);
2320 #endif
2321                 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
2322                 break;
2323         }
2324         xpt_done(ccb);
2325 }
2326
2327 static void
2328 iscsi_poll(struct cam_sim *sim)
2329 {
2330
2331         KASSERT(0, ("%s: you're not supposed to be here", __func__));
2332 }
2333
2334 static void
2335 iscsi_terminate_sessions(struct iscsi_softc *sc)
2336 {
2337         struct iscsi_session *is;
2338
2339         sx_slock(&sc->sc_lock);
2340         TAILQ_FOREACH(is, &sc->sc_sessions, is_next)
2341                 iscsi_session_terminate(is);
2342         while(!TAILQ_EMPTY(&sc->sc_sessions)) {
2343                 ISCSI_DEBUG("waiting for sessions to terminate");
2344                 cv_wait(&sc->sc_cv, &sc->sc_lock);
2345         }
2346         ISCSI_DEBUG("all sessions terminated");
2347         sx_sunlock(&sc->sc_lock);
2348 }
2349
2350 static void
2351 iscsi_shutdown_pre(struct iscsi_softc *sc)
2352 {
2353         struct iscsi_session *is;
2354
2355         if (!fail_on_shutdown)
2356                 return;
2357
2358         /*
2359          * If we have any sessions waiting for reconnection, request
2360          * maintenance thread to fail them immediately instead of waiting
2361          * for reconnect timeout.
2362          *
2363          * This prevents LUNs with mounted filesystems that are supported
2364          * by disconnected iSCSI sessions from hanging, however it will
2365          * fail all queued BIOs.
2366          */
2367         ISCSI_DEBUG("forcing failing all disconnected sessions due to shutdown");
2368
2369         fail_on_disconnection = 1;
2370
2371         sx_slock(&sc->sc_lock);
2372         TAILQ_FOREACH(is, &sc->sc_sessions, is_next) {
2373                 ISCSI_SESSION_LOCK(is);
2374                 if (!is->is_connected) {
2375                         ISCSI_SESSION_DEBUG(is, "force failing disconnected session early");
2376                         iscsi_session_reconnect(is);
2377                 }
2378                 ISCSI_SESSION_UNLOCK(is);
2379         }
2380         sx_sunlock(&sc->sc_lock);
2381 }
2382
2383 static void
2384 iscsi_shutdown_post(struct iscsi_softc *sc)
2385 {
2386
2387         if (panicstr == NULL) {
2388                 ISCSI_DEBUG("removing all sessions due to shutdown");
2389                 iscsi_terminate_sessions(sc);
2390         }
2391 }
2392
2393 static int
2394 iscsi_load(void)
2395 {
2396         int error;
2397
2398         sc = malloc(sizeof(*sc), M_ISCSI, M_ZERO | M_WAITOK);
2399         sx_init(&sc->sc_lock, "iscsi");
2400         TAILQ_INIT(&sc->sc_sessions);
2401         cv_init(&sc->sc_cv, "iscsi_cv");
2402
2403         iscsi_outstanding_zone = uma_zcreate("iscsi_outstanding",
2404             sizeof(struct iscsi_outstanding), NULL, NULL, NULL, NULL,
2405             UMA_ALIGN_PTR, 0);
2406
2407         error = make_dev_p(MAKEDEV_CHECKNAME, &sc->sc_cdev, &iscsi_cdevsw,
2408             NULL, UID_ROOT, GID_WHEEL, 0600, "iscsi");
2409         if (error != 0) {
2410                 ISCSI_WARN("failed to create device node, error %d", error);
2411                 return (error);
2412         }
2413         sc->sc_cdev->si_drv1 = sc;
2414
2415         sc->sc_shutdown_pre_eh = EVENTHANDLER_REGISTER(shutdown_pre_sync,
2416             iscsi_shutdown_pre, sc, SHUTDOWN_PRI_FIRST);
2417         /*
2418          * shutdown_post_sync needs to run after filesystem shutdown and before
2419          * CAM shutdown - otherwise when rebooting with an iSCSI session that is
2420          * disconnected but has outstanding requests, dashutdown() will hang on
2421          * cam_periph_runccb().
2422          */
2423         sc->sc_shutdown_post_eh = EVENTHANDLER_REGISTER(shutdown_post_sync,
2424             iscsi_shutdown_post, sc, SHUTDOWN_PRI_DEFAULT - 1);
2425
2426         return (0);
2427 }
2428
2429 static int
2430 iscsi_unload(void)
2431 {
2432
2433         if (sc->sc_cdev != NULL) {
2434                 ISCSI_DEBUG("removing device node");
2435                 destroy_dev(sc->sc_cdev);
2436                 ISCSI_DEBUG("device node removed");
2437         }
2438
2439         if (sc->sc_shutdown_pre_eh != NULL)
2440                 EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->sc_shutdown_pre_eh);
2441         if (sc->sc_shutdown_post_eh != NULL)
2442                 EVENTHANDLER_DEREGISTER(shutdown_post_sync, sc->sc_shutdown_post_eh);
2443
2444         iscsi_terminate_sessions(sc);
2445
2446         uma_zdestroy(iscsi_outstanding_zone);
2447         sx_destroy(&sc->sc_lock);
2448         cv_destroy(&sc->sc_cv);
2449         free(sc, M_ISCSI);
2450         return (0);
2451 }
2452
2453 static int
2454 iscsi_quiesce(void)
2455 {
2456         sx_slock(&sc->sc_lock);
2457         if (!TAILQ_EMPTY(&sc->sc_sessions)) {
2458                 sx_sunlock(&sc->sc_lock);
2459                 return (EBUSY);
2460         }
2461         sx_sunlock(&sc->sc_lock);
2462         return (0);
2463 }
2464
2465 static int
2466 iscsi_modevent(module_t mod, int what, void *arg)
2467 {
2468         int error;
2469
2470         switch (what) {
2471         case MOD_LOAD:
2472                 error = iscsi_load();
2473                 break;
2474         case MOD_UNLOAD:
2475                 error = iscsi_unload();
2476                 break;
2477         case MOD_QUIESCE:
2478                 error = iscsi_quiesce();
2479                 break;
2480         default:
2481                 error = EINVAL;
2482                 break;
2483         }
2484         return (error);
2485 }
2486
2487 moduledata_t iscsi_data = {
2488         "iscsi",
2489         iscsi_modevent,
2490         0
2491 };
2492
2493 DECLARE_MODULE(iscsi, iscsi_data, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
2494 MODULE_DEPEND(iscsi, cam, 1, 1, 1);
2495 MODULE_DEPEND(iscsi, icl, 1, 1, 1);