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