]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/cam/ctl/ctl_frontend_iscsi.c
Unify ATIO/INOT CCBs requeuing.
[FreeBSD/FreeBSD.git] / sys / cam / ctl / ctl_frontend_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  * $FreeBSD$
30  */
31
32 /*
33  * CTL frontend for the iSCSI protocol.
34  */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 #include <sys/param.h>
40 #include <sys/capsicum.h>
41 #include <sys/condvar.h>
42 #include <sys/endian.h>
43 #include <sys/file.h>
44 #include <sys/kernel.h>
45 #include <sys/kthread.h>
46 #include <sys/lock.h>
47 #include <sys/malloc.h>
48 #include <sys/module.h>
49 #include <sys/mutex.h>
50 #include <sys/queue.h>
51 #include <sys/sbuf.h>
52 #include <sys/socket.h>
53 #include <sys/sysctl.h>
54 #include <sys/systm.h>
55 #include <sys/uio.h>
56 #include <sys/unistd.h>
57 #include <vm/uma.h>
58
59 #include <cam/scsi/scsi_all.h>
60 #include <cam/scsi/scsi_da.h>
61 #include <cam/ctl/ctl_io.h>
62 #include <cam/ctl/ctl.h>
63 #include <cam/ctl/ctl_backend.h>
64 #include <cam/ctl/ctl_error.h>
65 #include <cam/ctl/ctl_frontend.h>
66 #include <cam/ctl/ctl_debug.h>
67 #include <cam/ctl/ctl_ha.h>
68 #include <cam/ctl/ctl_ioctl.h>
69 #include <cam/ctl/ctl_private.h>
70
71 #include <dev/iscsi/icl.h>
72 #include <dev/iscsi/icl_wrappers.h>
73 #include <dev/iscsi/iscsi_proto.h>
74 #include <cam/ctl/ctl_frontend_iscsi.h>
75
76 #ifdef ICL_KERNEL_PROXY
77 #include <sys/socketvar.h>
78 #endif
79
80 #ifdef ICL_KERNEL_PROXY
81 FEATURE(cfiscsi_kernel_proxy, "iSCSI target built with ICL_KERNEL_PROXY");
82 #endif
83
84 static MALLOC_DEFINE(M_CFISCSI, "cfiscsi", "Memory used for CTL iSCSI frontend");
85 static uma_zone_t cfiscsi_data_wait_zone;
86
87 SYSCTL_NODE(_kern_cam_ctl, OID_AUTO, iscsi, CTLFLAG_RD, 0,
88     "CAM Target Layer iSCSI Frontend");
89 static int debug = 1;
90 SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, debug, CTLFLAG_RWTUN,
91     &debug, 1, "Enable debug messages");
92 static int ping_timeout = 5;
93 SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, ping_timeout, CTLFLAG_RWTUN,
94     &ping_timeout, 5, "Interval between ping (NOP-Out) requests, in seconds");
95 static int login_timeout = 60;
96 SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, login_timeout, CTLFLAG_RWTUN,
97     &login_timeout, 60, "Time to wait for ctld(8) to finish Login Phase, in seconds");
98 static int maxtags = 256;
99 SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, maxtags, CTLFLAG_RWTUN,
100     &maxtags, 0, "Max number of requests queued by initiator");
101
102 #define CFISCSI_DEBUG(X, ...)                                           \
103         do {                                                            \
104                 if (debug > 1) {                                        \
105                         printf("%s: " X "\n",                           \
106                             __func__, ## __VA_ARGS__);                  \
107                 }                                                       \
108         } while (0)
109
110 #define CFISCSI_WARN(X, ...)                                            \
111         do {                                                            \
112                 if (debug > 0) {                                        \
113                         printf("WARNING: %s: " X "\n",                  \
114                             __func__, ## __VA_ARGS__);                  \
115                 }                                                       \
116         } while (0)
117
118 #define CFISCSI_SESSION_DEBUG(S, X, ...)                                \
119         do {                                                            \
120                 if (debug > 1) {                                        \
121                         printf("%s: %s (%s): " X "\n",                  \
122                             __func__, S->cs_initiator_addr,             \
123                             S->cs_initiator_name, ## __VA_ARGS__);      \
124                 }                                                       \
125         } while (0)
126
127 #define CFISCSI_SESSION_WARN(S, X, ...)                                 \
128         do  {                                                           \
129                 if (debug > 0) {                                        \
130                         printf("WARNING: %s (%s): " X "\n",             \
131                             S->cs_initiator_addr,                       \
132                             S->cs_initiator_name, ## __VA_ARGS__);      \
133                 }                                                       \
134         } while (0)
135
136 #define CFISCSI_SESSION_LOCK(X)         mtx_lock(&X->cs_lock)
137 #define CFISCSI_SESSION_UNLOCK(X)       mtx_unlock(&X->cs_lock)
138 #define CFISCSI_SESSION_LOCK_ASSERT(X)  mtx_assert(&X->cs_lock, MA_OWNED)
139
140 #define CONN_SESSION(X)                 ((struct cfiscsi_session *)(X)->ic_prv0)
141 #define PDU_SESSION(X)                  CONN_SESSION((X)->ip_conn)
142 #define PDU_EXPDATASN(X)                (X)->ip_prv0
143 #define PDU_TOTAL_TRANSFER_LEN(X)       (X)->ip_prv1
144 #define PDU_R2TSN(X)                    (X)->ip_prv2
145
146 static int      cfiscsi_init(void);
147 static int      cfiscsi_shutdown(void);
148 static void     cfiscsi_online(void *arg);
149 static void     cfiscsi_offline(void *arg);
150 static int      cfiscsi_info(void *arg, struct sbuf *sb);
151 static int      cfiscsi_ioctl(struct cdev *dev,
152                     u_long cmd, caddr_t addr, int flag, struct thread *td);
153 static void     cfiscsi_datamove(union ctl_io *io);
154 static void     cfiscsi_datamove_in(union ctl_io *io);
155 static void     cfiscsi_datamove_out(union ctl_io *io);
156 static void     cfiscsi_done(union ctl_io *io);
157 static bool     cfiscsi_pdu_update_cmdsn(const struct icl_pdu *request);
158 static void     cfiscsi_pdu_handle_nop_out(struct icl_pdu *request);
159 static void     cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request);
160 static void     cfiscsi_pdu_handle_task_request(struct icl_pdu *request);
161 static void     cfiscsi_pdu_handle_data_out(struct icl_pdu *request);
162 static void     cfiscsi_pdu_handle_logout_request(struct icl_pdu *request);
163 static void     cfiscsi_session_terminate(struct cfiscsi_session *cs);
164 static struct cfiscsi_data_wait *cfiscsi_data_wait_new(
165                     struct cfiscsi_session *cs, union ctl_io *io,
166                     uint32_t initiator_task_tag,
167                     uint32_t *target_transfer_tagp);
168 static void     cfiscsi_data_wait_free(struct cfiscsi_session *cs,
169                     struct cfiscsi_data_wait *cdw);
170 static struct cfiscsi_target    *cfiscsi_target_find(struct cfiscsi_softc
171                     *softc, const char *name, uint16_t tag);
172 static struct cfiscsi_target    *cfiscsi_target_find_or_create(
173     struct cfiscsi_softc *softc, const char *name, const char *alias,
174     uint16_t tag);
175 static void     cfiscsi_target_release(struct cfiscsi_target *ct);
176 static void     cfiscsi_session_delete(struct cfiscsi_session *cs);
177
178 static struct cfiscsi_softc cfiscsi_softc;
179
180 static struct ctl_frontend cfiscsi_frontend =
181 {
182         .name = "iscsi",
183         .init = cfiscsi_init,
184         .ioctl = cfiscsi_ioctl,
185         .shutdown = cfiscsi_shutdown,
186 };
187 CTL_FRONTEND_DECLARE(ctlcfiscsi, cfiscsi_frontend);
188 MODULE_DEPEND(ctlcfiscsi, icl, 1, 1, 1);
189
190 static struct icl_pdu *
191 cfiscsi_pdu_new_response(struct icl_pdu *request, int flags)
192 {
193
194         return (icl_pdu_new(request->ip_conn, flags));
195 }
196
197 static bool
198 cfiscsi_pdu_update_cmdsn(const struct icl_pdu *request)
199 {
200         const struct iscsi_bhs_scsi_command *bhssc;
201         struct cfiscsi_session *cs;
202         uint32_t cmdsn, expstatsn;
203
204         cs = PDU_SESSION(request);
205
206         /*
207          * Every incoming PDU - not just NOP-Out - resets the ping timer.
208          * The purpose of the timeout is to reset the connection when it stalls;
209          * we don't want this to happen when NOP-In or NOP-Out ends up delayed
210          * in some queue.
211          *
212          * XXX: Locking?
213          */
214         cs->cs_timeout = 0;
215
216         /*
217          * Data-Out PDUs don't contain CmdSN.
218          */
219         if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
220             ISCSI_BHS_OPCODE_SCSI_DATA_OUT)
221                 return (false);
222
223         /*
224          * We're only using fields common for all the request
225          * (initiator -> target) PDUs.
226          */
227         bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs;
228         cmdsn = ntohl(bhssc->bhssc_cmdsn);
229         expstatsn = ntohl(bhssc->bhssc_expstatsn);
230
231         CFISCSI_SESSION_LOCK(cs);
232 #if 0
233         if (expstatsn != cs->cs_statsn) {
234                 CFISCSI_SESSION_DEBUG(cs, "received PDU with ExpStatSN %d, "
235                     "while current StatSN is %d", expstatsn,
236                     cs->cs_statsn);
237         }
238 #endif
239
240         if ((request->ip_bhs->bhs_opcode & ISCSI_BHS_OPCODE_IMMEDIATE) == 0) {
241                 /*
242                  * The target MUST silently ignore any non-immediate command
243                  * outside of this range.
244                  */
245                 if (ISCSI_SNLT(cmdsn, cs->cs_cmdsn) ||
246                     ISCSI_SNGT(cmdsn, cs->cs_cmdsn - 1 + maxtags)) {
247                         CFISCSI_SESSION_UNLOCK(cs);
248                         CFISCSI_SESSION_WARN(cs, "received PDU with CmdSN %u, "
249                             "while expected %u", cmdsn, cs->cs_cmdsn);
250                         return (true);
251                 }
252
253                 /*
254                  * We don't support multiple connections now, so any
255                  * discontinuity in CmdSN means lost PDUs.  Since we don't
256                  * support PDU retransmission -- terminate the connection.
257                  */
258                 if (cmdsn != cs->cs_cmdsn) {
259                         CFISCSI_SESSION_UNLOCK(cs);
260                         CFISCSI_SESSION_WARN(cs, "received PDU with CmdSN %u, "
261                             "while expected %u; dropping connection",
262                             cmdsn, cs->cs_cmdsn);
263                         cfiscsi_session_terminate(cs);
264                         return (true);
265                 }
266                 cs->cs_cmdsn++;
267         }
268
269         CFISCSI_SESSION_UNLOCK(cs);
270
271         return (false);
272 }
273
274 static void
275 cfiscsi_pdu_handle(struct icl_pdu *request)
276 {
277         struct cfiscsi_session *cs;
278         bool ignore;
279
280         cs = PDU_SESSION(request);
281
282         ignore = cfiscsi_pdu_update_cmdsn(request);
283         if (ignore) {
284                 icl_pdu_free(request);
285                 return;
286         }
287
288         /*
289          * Handle the PDU; this includes e.g. receiving the remaining
290          * part of PDU and submitting the SCSI command to CTL
291          * or queueing a reply.  The handling routine is responsible
292          * for freeing the PDU when it's no longer needed.
293          */
294         switch (request->ip_bhs->bhs_opcode &
295             ~ISCSI_BHS_OPCODE_IMMEDIATE) {
296         case ISCSI_BHS_OPCODE_NOP_OUT:
297                 cfiscsi_pdu_handle_nop_out(request);
298                 break;
299         case ISCSI_BHS_OPCODE_SCSI_COMMAND:
300                 cfiscsi_pdu_handle_scsi_command(request);
301                 break;
302         case ISCSI_BHS_OPCODE_TASK_REQUEST:
303                 cfiscsi_pdu_handle_task_request(request);
304                 break;
305         case ISCSI_BHS_OPCODE_SCSI_DATA_OUT:
306                 cfiscsi_pdu_handle_data_out(request);
307                 break;
308         case ISCSI_BHS_OPCODE_LOGOUT_REQUEST:
309                 cfiscsi_pdu_handle_logout_request(request);
310                 break;
311         default:
312                 CFISCSI_SESSION_WARN(cs, "received PDU with unsupported "
313                     "opcode 0x%x; dropping connection",
314                     request->ip_bhs->bhs_opcode);
315                 icl_pdu_free(request);
316                 cfiscsi_session_terminate(cs);
317         }
318
319 }
320
321 static void
322 cfiscsi_receive_callback(struct icl_pdu *request)
323 {
324         struct cfiscsi_session *cs;
325
326         cs = PDU_SESSION(request);
327
328 #ifdef ICL_KERNEL_PROXY
329         if (cs->cs_waiting_for_ctld || cs->cs_login_phase) {
330                 if (cs->cs_login_pdu == NULL)
331                         cs->cs_login_pdu = request;
332                 else
333                         icl_pdu_free(request);
334                 cv_signal(&cs->cs_login_cv);
335                 return;
336         }
337 #endif
338
339         cfiscsi_pdu_handle(request);
340 }
341
342 static void
343 cfiscsi_error_callback(struct icl_conn *ic)
344 {
345         struct cfiscsi_session *cs;
346
347         cs = CONN_SESSION(ic);
348
349         CFISCSI_SESSION_WARN(cs, "connection error; dropping connection");
350         cfiscsi_session_terminate(cs);
351 }
352
353 static int
354 cfiscsi_pdu_prepare(struct icl_pdu *response)
355 {
356         struct cfiscsi_session *cs;
357         struct iscsi_bhs_scsi_response *bhssr;
358         bool advance_statsn = true;
359
360         cs = PDU_SESSION(response);
361
362         CFISCSI_SESSION_LOCK_ASSERT(cs);
363
364         /*
365          * We're only using fields common for all the response
366          * (target -> initiator) PDUs.
367          */
368         bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs;
369
370         /*
371          * 10.8.3: "The StatSN for this connection is not advanced
372          * after this PDU is sent."
373          */
374         if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_R2T)
375                 advance_statsn = false;
376
377         /*
378          * 10.19.2: "However, when the Initiator Task Tag is set to 0xffffffff,
379          * StatSN for the connection is not advanced after this PDU is sent."
380          */
381         if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_NOP_IN && 
382             bhssr->bhssr_initiator_task_tag == 0xffffffff)
383                 advance_statsn = false;
384
385         /*
386          * See the comment below - StatSN is not meaningful and must
387          * not be advanced.
388          */
389         if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_SCSI_DATA_IN &&
390             (bhssr->bhssr_flags & BHSDI_FLAGS_S) == 0)
391                 advance_statsn = false;
392
393         /*
394          * 10.7.3: "The fields StatSN, Status, and Residual Count
395          * only have meaningful content if the S bit is set to 1."
396          */
397         if (bhssr->bhssr_opcode != ISCSI_BHS_OPCODE_SCSI_DATA_IN ||
398             (bhssr->bhssr_flags & BHSDI_FLAGS_S))
399                 bhssr->bhssr_statsn = htonl(cs->cs_statsn);
400         bhssr->bhssr_expcmdsn = htonl(cs->cs_cmdsn);
401         bhssr->bhssr_maxcmdsn = htonl(cs->cs_cmdsn - 1 +
402             imax(0, maxtags - cs->cs_outstanding_ctl_pdus));
403
404         if (advance_statsn)
405                 cs->cs_statsn++;
406
407         return (0);
408 }
409
410 static void
411 cfiscsi_pdu_queue(struct icl_pdu *response)
412 {
413         struct cfiscsi_session *cs;
414
415         cs = PDU_SESSION(response);
416
417         CFISCSI_SESSION_LOCK(cs);
418         cfiscsi_pdu_prepare(response);
419         icl_pdu_queue(response);
420         CFISCSI_SESSION_UNLOCK(cs);
421 }
422
423 static void
424 cfiscsi_pdu_handle_nop_out(struct icl_pdu *request)
425 {
426         struct cfiscsi_session *cs;
427         struct iscsi_bhs_nop_out *bhsno;
428         struct iscsi_bhs_nop_in *bhsni;
429         struct icl_pdu *response;
430         void *data = NULL;
431         size_t datasize;
432         int error;
433
434         cs = PDU_SESSION(request);
435         bhsno = (struct iscsi_bhs_nop_out *)request->ip_bhs;
436
437         if (bhsno->bhsno_initiator_task_tag == 0xffffffff) {
438                 /*
439                  * Nothing to do, iscsi_pdu_update_statsn() already
440                  * zeroed the timeout.
441                  */
442                 icl_pdu_free(request);
443                 return;
444         }
445
446         datasize = icl_pdu_data_segment_length(request);
447         if (datasize > 0) {
448                 data = malloc(datasize, M_CFISCSI, M_NOWAIT | M_ZERO);
449                 if (data == NULL) {
450                         CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
451                             "dropping connection");
452                         icl_pdu_free(request);
453                         cfiscsi_session_terminate(cs);
454                         return;
455                 }
456                 icl_pdu_get_data(request, 0, data, datasize);
457         }
458
459         response = cfiscsi_pdu_new_response(request, M_NOWAIT);
460         if (response == NULL) {
461                 CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
462                     "droppping connection");
463                 free(data, M_CFISCSI);
464                 icl_pdu_free(request);
465                 cfiscsi_session_terminate(cs);
466                 return;
467         }
468         bhsni = (struct iscsi_bhs_nop_in *)response->ip_bhs;
469         bhsni->bhsni_opcode = ISCSI_BHS_OPCODE_NOP_IN;
470         bhsni->bhsni_flags = 0x80;
471         bhsni->bhsni_initiator_task_tag = bhsno->bhsno_initiator_task_tag;
472         bhsni->bhsni_target_transfer_tag = 0xffffffff;
473         if (datasize > 0) {
474                 error = icl_pdu_append_data(response, data, datasize, M_NOWAIT);
475                 if (error != 0) {
476                         CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
477                             "dropping connection");
478                         free(data, M_CFISCSI);
479                         icl_pdu_free(request);
480                         icl_pdu_free(response);
481                         cfiscsi_session_terminate(cs);
482                         return;
483                 }
484                 free(data, M_CFISCSI);
485         }
486
487         icl_pdu_free(request);
488         cfiscsi_pdu_queue(response);
489 }
490
491 static void
492 cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request)
493 {
494         struct iscsi_bhs_scsi_command *bhssc;
495         struct cfiscsi_session *cs;
496         union ctl_io *io;
497         int error;
498
499         cs = PDU_SESSION(request);
500         bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs;
501         //CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x",
502         //    bhssc->bhssc_initiator_task_tag);
503
504         if (request->ip_data_len > 0 && cs->cs_immediate_data == false) {
505                 CFISCSI_SESSION_WARN(cs, "unsolicited data with "
506                     "ImmediateData=No; dropping connection");
507                 icl_pdu_free(request);
508                 cfiscsi_session_terminate(cs);
509                 return;
510         }
511         io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
512         ctl_zero_io(io);
513         io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = request;
514         io->io_hdr.io_type = CTL_IO_SCSI;
515         io->io_hdr.nexus.initid = cs->cs_ctl_initid;
516         io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
517         io->io_hdr.nexus.targ_lun = ctl_decode_lun(be64toh(bhssc->bhssc_lun));
518         io->scsiio.tag_num = bhssc->bhssc_initiator_task_tag;
519         switch ((bhssc->bhssc_flags & BHSSC_FLAGS_ATTR)) {
520         case BHSSC_FLAGS_ATTR_UNTAGGED:
521                 io->scsiio.tag_type = CTL_TAG_UNTAGGED;
522                 break;
523         case BHSSC_FLAGS_ATTR_SIMPLE:
524                 io->scsiio.tag_type = CTL_TAG_SIMPLE;
525                 break;
526         case BHSSC_FLAGS_ATTR_ORDERED:
527                 io->scsiio.tag_type = CTL_TAG_ORDERED;
528                 break;
529         case BHSSC_FLAGS_ATTR_HOQ:
530                 io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
531                 break;
532         case BHSSC_FLAGS_ATTR_ACA:
533                 io->scsiio.tag_type = CTL_TAG_ACA;
534                 break;
535         default:
536                 io->scsiio.tag_type = CTL_TAG_UNTAGGED;
537                 CFISCSI_SESSION_WARN(cs, "unhandled tag type %d",
538                     bhssc->bhssc_flags & BHSSC_FLAGS_ATTR);
539                 break;
540         }
541         io->scsiio.cdb_len = sizeof(bhssc->bhssc_cdb); /* Which is 16. */
542         memcpy(io->scsiio.cdb, bhssc->bhssc_cdb, sizeof(bhssc->bhssc_cdb));
543         refcount_acquire(&cs->cs_outstanding_ctl_pdus);
544         error = ctl_queue(io);
545         if (error != CTL_RETVAL_COMPLETE) {
546                 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d; "
547                     "dropping connection", error);
548                 ctl_free_io(io);
549                 refcount_release(&cs->cs_outstanding_ctl_pdus);
550                 icl_pdu_free(request);
551                 cfiscsi_session_terminate(cs);
552         }
553 }
554
555 static void
556 cfiscsi_pdu_handle_task_request(struct icl_pdu *request)
557 {
558         struct iscsi_bhs_task_management_request *bhstmr;
559         struct iscsi_bhs_task_management_response *bhstmr2;
560         struct icl_pdu *response;
561         struct cfiscsi_session *cs;
562         union ctl_io *io;
563         int error;
564
565         cs = PDU_SESSION(request);
566         bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs;
567         io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
568         ctl_zero_io(io);
569         io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = request;
570         io->io_hdr.io_type = CTL_IO_TASK;
571         io->io_hdr.nexus.initid = cs->cs_ctl_initid;
572         io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
573         io->io_hdr.nexus.targ_lun = ctl_decode_lun(be64toh(bhstmr->bhstmr_lun));
574         io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */
575
576         switch (bhstmr->bhstmr_function & ~0x80) {
577         case BHSTMR_FUNCTION_ABORT_TASK:
578 #if 0
579                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_ABORT_TASK");
580 #endif
581                 io->taskio.task_action = CTL_TASK_ABORT_TASK;
582                 io->taskio.tag_num = bhstmr->bhstmr_referenced_task_tag;
583                 break;
584         case BHSTMR_FUNCTION_ABORT_TASK_SET:
585 #if 0
586                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_ABORT_TASK_SET");
587 #endif
588                 io->taskio.task_action = CTL_TASK_ABORT_TASK_SET;
589                 break;
590         case BHSTMR_FUNCTION_CLEAR_TASK_SET:
591 #if 0
592                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_CLEAR_TASK_SET");
593 #endif
594                 io->taskio.task_action = CTL_TASK_CLEAR_TASK_SET;
595                 break;
596         case BHSTMR_FUNCTION_LOGICAL_UNIT_RESET:
597 #if 0
598                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_LOGICAL_UNIT_RESET");
599 #endif
600                 io->taskio.task_action = CTL_TASK_LUN_RESET;
601                 break;
602         case BHSTMR_FUNCTION_TARGET_WARM_RESET:
603 #if 0
604                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_TARGET_WARM_RESET");
605 #endif
606                 io->taskio.task_action = CTL_TASK_TARGET_RESET;
607                 break;
608         case BHSTMR_FUNCTION_TARGET_COLD_RESET:
609 #if 0
610                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_TARGET_COLD_RESET");
611 #endif
612                 io->taskio.task_action = CTL_TASK_TARGET_RESET;
613                 break;
614         case BHSTMR_FUNCTION_QUERY_TASK:
615 #if 0
616                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_QUERY_TASK");
617 #endif
618                 io->taskio.task_action = CTL_TASK_QUERY_TASK;
619                 io->taskio.tag_num = bhstmr->bhstmr_referenced_task_tag;
620                 break;
621         case BHSTMR_FUNCTION_QUERY_TASK_SET:
622 #if 0
623                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_QUERY_TASK_SET");
624 #endif
625                 io->taskio.task_action = CTL_TASK_QUERY_TASK_SET;
626                 break;
627         case BHSTMR_FUNCTION_I_T_NEXUS_RESET:
628 #if 0
629                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_I_T_NEXUS_RESET");
630 #endif
631                 io->taskio.task_action = CTL_TASK_I_T_NEXUS_RESET;
632                 break;
633         case BHSTMR_FUNCTION_QUERY_ASYNC_EVENT:
634 #if 0
635                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_QUERY_ASYNC_EVENT");
636 #endif
637                 io->taskio.task_action = CTL_TASK_QUERY_ASYNC_EVENT;
638                 break;
639         default:
640                 CFISCSI_SESSION_DEBUG(cs, "unsupported function 0x%x",
641                     bhstmr->bhstmr_function & ~0x80);
642                 ctl_free_io(io);
643
644                 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
645                 if (response == NULL) {
646                         CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
647                             "dropping connection");
648                         icl_pdu_free(request);
649                         cfiscsi_session_terminate(cs);
650                         return;
651                 }
652                 bhstmr2 = (struct iscsi_bhs_task_management_response *)
653                     response->ip_bhs;
654                 bhstmr2->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_RESPONSE;
655                 bhstmr2->bhstmr_flags = 0x80;
656                 bhstmr2->bhstmr_response =
657                     BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED;
658                 bhstmr2->bhstmr_initiator_task_tag =
659                     bhstmr->bhstmr_initiator_task_tag;
660                 icl_pdu_free(request);
661                 cfiscsi_pdu_queue(response);
662                 return;
663         }
664
665         refcount_acquire(&cs->cs_outstanding_ctl_pdus);
666         error = ctl_queue(io);
667         if (error != CTL_RETVAL_COMPLETE) {
668                 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d; "
669                     "dropping connection", error);
670                 ctl_free_io(io);
671                 refcount_release(&cs->cs_outstanding_ctl_pdus);
672                 icl_pdu_free(request);
673                 cfiscsi_session_terminate(cs);
674         }
675 }
676
677 static bool
678 cfiscsi_handle_data_segment(struct icl_pdu *request, struct cfiscsi_data_wait *cdw)
679 {
680         struct iscsi_bhs_data_out *bhsdo;
681         struct cfiscsi_session *cs;
682         struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
683         size_t copy_len, len, off, buffer_offset;
684         int ctl_sg_count;
685         union ctl_io *io;
686
687         cs = PDU_SESSION(request);
688
689         KASSERT((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
690             ISCSI_BHS_OPCODE_SCSI_DATA_OUT ||
691             (request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
692             ISCSI_BHS_OPCODE_SCSI_COMMAND,
693             ("bad opcode 0x%x", request->ip_bhs->bhs_opcode));
694
695         /*
696          * We're only using fields common for Data-Out and SCSI Command PDUs.
697          */
698         bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs;
699
700         io = cdw->cdw_ctl_io;
701         KASSERT((io->io_hdr.flags & CTL_FLAG_DATA_MASK) != CTL_FLAG_DATA_IN,
702             ("CTL_FLAG_DATA_IN"));
703
704 #if 0
705         CFISCSI_SESSION_DEBUG(cs, "received %zd bytes out of %d",
706             request->ip_data_len, io->scsiio.kern_total_len);
707 #endif
708
709         if (io->scsiio.kern_sg_entries > 0) {
710                 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
711                 ctl_sg_count = io->scsiio.kern_sg_entries;
712         } else {
713                 ctl_sglist = &ctl_sg_entry;
714                 ctl_sglist->addr = io->scsiio.kern_data_ptr;
715                 ctl_sglist->len = io->scsiio.kern_data_len;
716                 ctl_sg_count = 1;
717         }
718
719         if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
720             ISCSI_BHS_OPCODE_SCSI_DATA_OUT)
721                 buffer_offset = ntohl(bhsdo->bhsdo_buffer_offset);
722         else
723                 buffer_offset = 0;
724         len = icl_pdu_data_segment_length(request);
725
726         /*
727          * Make sure the offset, as sent by the initiator, matches the offset
728          * we're supposed to be at in the scatter-gather list.
729          */
730         if (buffer_offset >
731             io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled ||
732             buffer_offset + len <=
733             io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled) {
734                 CFISCSI_SESSION_WARN(cs, "received bad buffer offset %zd, "
735                     "expected %zd; dropping connection", buffer_offset,
736                     (size_t)io->scsiio.kern_rel_offset +
737                     (size_t)io->scsiio.ext_data_filled);
738                 ctl_set_data_phase_error(&io->scsiio);
739                 cfiscsi_session_terminate(cs);
740                 return (true);
741         }
742
743         /*
744          * This is the offset within the PDU data segment, as opposed
745          * to buffer_offset, which is the offset within the task (SCSI
746          * command).
747          */
748         off = io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled -
749             buffer_offset;
750
751         /*
752          * Iterate over the scatter/gather segments, filling them with data
753          * from the PDU data segment.  Note that this can get called multiple
754          * times for one SCSI command; the cdw structure holds state for the
755          * scatter/gather list.
756          */
757         for (;;) {
758                 KASSERT(cdw->cdw_sg_index < ctl_sg_count,
759                     ("cdw->cdw_sg_index >= ctl_sg_count"));
760                 if (cdw->cdw_sg_len == 0) {
761                         cdw->cdw_sg_addr = ctl_sglist[cdw->cdw_sg_index].addr;
762                         cdw->cdw_sg_len = ctl_sglist[cdw->cdw_sg_index].len;
763                 }
764                 KASSERT(off <= len, ("len > off"));
765                 copy_len = len - off;
766                 if (copy_len > cdw->cdw_sg_len)
767                         copy_len = cdw->cdw_sg_len;
768
769                 icl_pdu_get_data(request, off, cdw->cdw_sg_addr, copy_len);
770                 cdw->cdw_sg_addr += copy_len;
771                 cdw->cdw_sg_len -= copy_len;
772                 off += copy_len;
773                 io->scsiio.ext_data_filled += copy_len;
774                 io->scsiio.kern_data_resid -= copy_len;
775
776                 if (cdw->cdw_sg_len == 0) {
777                         /*
778                          * End of current segment.
779                          */
780                         if (cdw->cdw_sg_index == ctl_sg_count - 1) {
781                                 /*
782                                  * Last segment in scatter/gather list.
783                                  */
784                                 break;
785                         }
786                         cdw->cdw_sg_index++;
787                 }
788
789                 if (off == len) {
790                         /*
791                          * End of PDU payload.
792                          */
793                         break;
794                 }
795         }
796
797         if (len > off) {
798                 /*
799                  * In case of unsolicited data, it's possible that the buffer
800                  * provided by CTL is smaller than negotiated FirstBurstLength.
801                  * Just ignore the superfluous data; will ask for them with R2T
802                  * on next call to cfiscsi_datamove().
803                  *
804                  * This obviously can only happen with SCSI Command PDU. 
805                  */
806                 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
807                     ISCSI_BHS_OPCODE_SCSI_COMMAND)
808                         return (true);
809
810                 CFISCSI_SESSION_WARN(cs, "received too much data: got %zd bytes, "
811                     "expected %zd; dropping connection",
812                     icl_pdu_data_segment_length(request), off);
813                 ctl_set_data_phase_error(&io->scsiio);
814                 cfiscsi_session_terminate(cs);
815                 return (true);
816         }
817
818         if (io->scsiio.ext_data_filled == cdw->cdw_r2t_end &&
819             (bhsdo->bhsdo_flags & BHSDO_FLAGS_F) == 0) {
820                 CFISCSI_SESSION_WARN(cs, "got the final packet without "
821                     "the F flag; flags = 0x%x; dropping connection",
822                     bhsdo->bhsdo_flags);
823                 ctl_set_data_phase_error(&io->scsiio);
824                 cfiscsi_session_terminate(cs);
825                 return (true);
826         }
827
828         if (io->scsiio.ext_data_filled != cdw->cdw_r2t_end &&
829             (bhsdo->bhsdo_flags & BHSDO_FLAGS_F) != 0) {
830                 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
831                     ISCSI_BHS_OPCODE_SCSI_DATA_OUT) {
832                         CFISCSI_SESSION_WARN(cs, "got the final packet, but the "
833                             "transmitted size was %zd bytes instead of %d; "
834                             "dropping connection",
835                             (size_t)io->scsiio.ext_data_filled,
836                             cdw->cdw_r2t_end);
837                         ctl_set_data_phase_error(&io->scsiio);
838                         cfiscsi_session_terminate(cs);
839                         return (true);
840                 } else {
841                         /*
842                          * For SCSI Command PDU, this just means we need to
843                          * solicit more data by sending R2T.
844                          */
845                         return (false);
846                 }
847         }
848
849         if (io->scsiio.ext_data_filled == cdw->cdw_r2t_end) {
850 #if 0
851                 CFISCSI_SESSION_DEBUG(cs, "no longer expecting Data-Out with target "
852                     "transfer tag 0x%x", cdw->cdw_target_transfer_tag);
853 #endif
854
855                 return (true);
856         }
857
858         return (false);
859 }
860
861 static void
862 cfiscsi_pdu_handle_data_out(struct icl_pdu *request)
863 {
864         struct iscsi_bhs_data_out *bhsdo;
865         struct cfiscsi_session *cs;
866         struct cfiscsi_data_wait *cdw = NULL;
867         union ctl_io *io;
868         bool done;
869
870         cs = PDU_SESSION(request);
871         bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs;
872
873         CFISCSI_SESSION_LOCK(cs);
874         TAILQ_FOREACH(cdw, &cs->cs_waiting_for_data_out, cdw_next) {
875 #if 0
876                 CFISCSI_SESSION_DEBUG(cs, "have ttt 0x%x, itt 0x%x; looking for "
877                     "ttt 0x%x, itt 0x%x",
878                     bhsdo->bhsdo_target_transfer_tag,
879                     bhsdo->bhsdo_initiator_task_tag,
880                     cdw->cdw_target_transfer_tag, cdw->cdw_initiator_task_tag));
881 #endif
882                 if (bhsdo->bhsdo_target_transfer_tag ==
883                     cdw->cdw_target_transfer_tag)
884                         break;
885         }
886         CFISCSI_SESSION_UNLOCK(cs);
887         if (cdw == NULL) {
888                 CFISCSI_SESSION_WARN(cs, "data transfer tag 0x%x, initiator task tag "
889                     "0x%x, not found; dropping connection",
890                     bhsdo->bhsdo_target_transfer_tag, bhsdo->bhsdo_initiator_task_tag);
891                 icl_pdu_free(request);
892                 cfiscsi_session_terminate(cs);
893                 return;
894         }
895
896         if (cdw->cdw_datasn != ntohl(bhsdo->bhsdo_datasn)) {
897                 CFISCSI_SESSION_WARN(cs, "received Data-Out PDU with "
898                     "DataSN %u, while expected %u; dropping connection",
899                     ntohl(bhsdo->bhsdo_datasn), cdw->cdw_datasn);
900                 icl_pdu_free(request);
901                 cfiscsi_session_terminate(cs);
902                 return;
903         }
904         cdw->cdw_datasn++;
905
906         io = cdw->cdw_ctl_io;
907         KASSERT((io->io_hdr.flags & CTL_FLAG_DATA_MASK) != CTL_FLAG_DATA_IN,
908             ("CTL_FLAG_DATA_IN"));
909
910         done = cfiscsi_handle_data_segment(request, cdw);
911         if (done) {
912                 CFISCSI_SESSION_LOCK(cs);
913                 TAILQ_REMOVE(&cs->cs_waiting_for_data_out, cdw, cdw_next);
914                 CFISCSI_SESSION_UNLOCK(cs);
915                 done = (io->scsiio.ext_data_filled != cdw->cdw_r2t_end ||
916                     io->scsiio.ext_data_filled == io->scsiio.kern_data_len);
917                 cfiscsi_data_wait_free(cs, cdw);
918                 io->io_hdr.flags &= ~CTL_FLAG_DMA_INPROG;
919                 if (done)
920                         io->scsiio.be_move_done(io);
921                 else
922                         cfiscsi_datamove_out(io);
923         }
924
925         icl_pdu_free(request);
926 }
927
928 static void
929 cfiscsi_pdu_handle_logout_request(struct icl_pdu *request)
930 {
931         struct iscsi_bhs_logout_request *bhslr;
932         struct iscsi_bhs_logout_response *bhslr2;
933         struct icl_pdu *response;
934         struct cfiscsi_session *cs;
935
936         cs = PDU_SESSION(request);
937         bhslr = (struct iscsi_bhs_logout_request *)request->ip_bhs;
938         switch (bhslr->bhslr_reason & 0x7f) {
939         case BHSLR_REASON_CLOSE_SESSION:
940         case BHSLR_REASON_CLOSE_CONNECTION:
941                 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
942                 if (response == NULL) {
943                         CFISCSI_SESSION_DEBUG(cs, "failed to allocate memory");
944                         icl_pdu_free(request);
945                         cfiscsi_session_terminate(cs);
946                         return;
947                 }
948                 bhslr2 = (struct iscsi_bhs_logout_response *)response->ip_bhs;
949                 bhslr2->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_RESPONSE;
950                 bhslr2->bhslr_flags = 0x80;
951                 bhslr2->bhslr_response = BHSLR_RESPONSE_CLOSED_SUCCESSFULLY;
952                 bhslr2->bhslr_initiator_task_tag =
953                     bhslr->bhslr_initiator_task_tag;
954                 icl_pdu_free(request);
955                 cfiscsi_pdu_queue(response);
956                 cfiscsi_session_terminate(cs);
957                 break;
958         case BHSLR_REASON_REMOVE_FOR_RECOVERY:
959                 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
960                 if (response == NULL) {
961                         CFISCSI_SESSION_WARN(cs,
962                             "failed to allocate memory; dropping connection");
963                         icl_pdu_free(request);
964                         cfiscsi_session_terminate(cs);
965                         return;
966                 }
967                 bhslr2 = (struct iscsi_bhs_logout_response *)response->ip_bhs;
968                 bhslr2->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_RESPONSE;
969                 bhslr2->bhslr_flags = 0x80;
970                 bhslr2->bhslr_response = BHSLR_RESPONSE_RECOVERY_NOT_SUPPORTED;
971                 bhslr2->bhslr_initiator_task_tag =
972                     bhslr->bhslr_initiator_task_tag;
973                 icl_pdu_free(request);
974                 cfiscsi_pdu_queue(response);
975                 break;
976         default:
977                 CFISCSI_SESSION_WARN(cs, "invalid reason 0%x; dropping connection",
978                     bhslr->bhslr_reason);
979                 icl_pdu_free(request);
980                 cfiscsi_session_terminate(cs);
981                 break;
982         }
983 }
984
985 static void
986 cfiscsi_callout(void *context)
987 {
988         struct icl_pdu *cp;
989         struct iscsi_bhs_nop_in *bhsni;
990         struct cfiscsi_session *cs;
991
992         cs = context;
993
994         if (cs->cs_terminating) 
995                 return;
996
997         callout_schedule(&cs->cs_callout, 1 * hz);
998
999         atomic_add_int(&cs->cs_timeout, 1);
1000
1001 #ifdef ICL_KERNEL_PROXY
1002         if (cs->cs_waiting_for_ctld || cs->cs_login_phase) {
1003                 if (login_timeout > 0 && cs->cs_timeout > login_timeout) {
1004                         CFISCSI_SESSION_WARN(cs, "login timed out after "
1005                             "%d seconds; dropping connection", cs->cs_timeout);
1006                         cfiscsi_session_terminate(cs);
1007                 }
1008                 return;
1009         }
1010 #endif
1011
1012         if (ping_timeout <= 0) {
1013                 /*
1014                  * Pings are disabled.  Don't send NOP-In in this case;
1015                  * user might have disabled pings to work around problems
1016                  * with certain initiators that can't properly handle
1017                  * NOP-In, such as iPXE.  Reset the timeout, to avoid
1018                  * triggering reconnection, should the user decide to
1019                  * reenable them.
1020                  */
1021                 cs->cs_timeout = 0;
1022                 return;
1023         }
1024
1025         if (cs->cs_timeout >= ping_timeout) {
1026                 CFISCSI_SESSION_WARN(cs, "no ping reply (NOP-Out) after %d seconds; "
1027                     "dropping connection",  ping_timeout);
1028                 cfiscsi_session_terminate(cs);
1029                 return;
1030         }
1031
1032         /*
1033          * If the ping was reset less than one second ago - which means
1034          * that we've received some PDU during the last second - assume
1035          * the traffic flows correctly and don't bother sending a NOP-Out.
1036          *
1037          * (It's 2 - one for one second, and one for incrementing is_timeout
1038          * earlier in this routine.)
1039          */
1040         if (cs->cs_timeout < 2)
1041                 return;
1042
1043         cp = icl_pdu_new(cs->cs_conn, M_NOWAIT);
1044         if (cp == NULL) {
1045                 CFISCSI_SESSION_WARN(cs, "failed to allocate memory");
1046                 return;
1047         }
1048         bhsni = (struct iscsi_bhs_nop_in *)cp->ip_bhs;
1049         bhsni->bhsni_opcode = ISCSI_BHS_OPCODE_NOP_IN;
1050         bhsni->bhsni_flags = 0x80;
1051         bhsni->bhsni_initiator_task_tag = 0xffffffff;
1052
1053         cfiscsi_pdu_queue(cp);
1054 }
1055
1056 static struct cfiscsi_data_wait *
1057 cfiscsi_data_wait_new(struct cfiscsi_session *cs, union ctl_io *io,
1058     uint32_t initiator_task_tag, uint32_t *target_transfer_tagp)
1059 {
1060         struct cfiscsi_data_wait *cdw;
1061         int error;
1062
1063         cdw = uma_zalloc(cfiscsi_data_wait_zone, M_NOWAIT | M_ZERO);
1064         if (cdw == NULL) {
1065                 CFISCSI_SESSION_WARN(cs,
1066                     "failed to allocate %zd bytes", sizeof(*cdw));
1067                 return (NULL);
1068         }
1069
1070         error = icl_conn_transfer_setup(cs->cs_conn, io, target_transfer_tagp,
1071             &cdw->cdw_icl_prv);
1072         if (error != 0) {
1073                 CFISCSI_SESSION_WARN(cs,
1074                     "icl_conn_transfer_setup() failed with error %d", error);
1075                 uma_zfree(cfiscsi_data_wait_zone, cdw);
1076                 return (NULL);
1077         }
1078
1079         cdw->cdw_ctl_io = io;
1080         cdw->cdw_target_transfer_tag = *target_transfer_tagp;
1081         cdw->cdw_initiator_task_tag = initiator_task_tag;
1082
1083         return (cdw);
1084 }
1085
1086 static void
1087 cfiscsi_data_wait_free(struct cfiscsi_session *cs,
1088     struct cfiscsi_data_wait *cdw)
1089 {
1090
1091         icl_conn_transfer_done(cs->cs_conn, cdw->cdw_icl_prv);
1092         uma_zfree(cfiscsi_data_wait_zone, cdw);
1093 }
1094
1095 static void
1096 cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs)
1097 {
1098         struct cfiscsi_data_wait *cdw;
1099         union ctl_io *io;
1100         int error, last, wait;
1101
1102         if (cs->cs_target == NULL)
1103                 return;         /* No target yet, so nothing to do. */
1104         io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
1105         ctl_zero_io(io);
1106         io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = cs;
1107         io->io_hdr.io_type = CTL_IO_TASK;
1108         io->io_hdr.nexus.initid = cs->cs_ctl_initid;
1109         io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
1110         io->io_hdr.nexus.targ_lun = 0;
1111         io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */
1112         io->taskio.task_action = CTL_TASK_I_T_NEXUS_RESET;
1113         wait = cs->cs_outstanding_ctl_pdus;
1114         refcount_acquire(&cs->cs_outstanding_ctl_pdus);
1115         error = ctl_queue(io);
1116         if (error != CTL_RETVAL_COMPLETE) {
1117                 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d", error);
1118                 refcount_release(&cs->cs_outstanding_ctl_pdus);
1119                 ctl_free_io(io);
1120         }
1121
1122         CFISCSI_SESSION_LOCK(cs);
1123         while ((cdw = TAILQ_FIRST(&cs->cs_waiting_for_data_out)) != NULL) {
1124                 TAILQ_REMOVE(&cs->cs_waiting_for_data_out, cdw, cdw_next);
1125                 CFISCSI_SESSION_UNLOCK(cs);
1126                 /*
1127                  * Set nonzero port status; this prevents backends from
1128                  * assuming that the data transfer actually succeeded
1129                  * and writing uninitialized data to disk.
1130                  */
1131                 cdw->cdw_ctl_io->io_hdr.flags &= ~CTL_FLAG_DMA_INPROG;
1132                 cdw->cdw_ctl_io->scsiio.io_hdr.port_status = 42;
1133                 cdw->cdw_ctl_io->scsiio.be_move_done(cdw->cdw_ctl_io);
1134                 cfiscsi_data_wait_free(cs, cdw);
1135                 CFISCSI_SESSION_LOCK(cs);
1136         }
1137         CFISCSI_SESSION_UNLOCK(cs);
1138
1139         /*
1140          * Wait for CTL to terminate all the tasks.
1141          */
1142         if (wait > 0)
1143                 CFISCSI_SESSION_WARN(cs,
1144                     "waiting for CTL to terminate %d tasks", wait);
1145         for (;;) {
1146                 refcount_acquire(&cs->cs_outstanding_ctl_pdus);
1147                 last = refcount_release(&cs->cs_outstanding_ctl_pdus);
1148                 if (last != 0)
1149                         break;
1150                 tsleep(__DEVOLATILE(void *, &cs->cs_outstanding_ctl_pdus),
1151                     0, "cfiscsi_terminate", hz / 100);
1152         }
1153         if (wait > 0)
1154                 CFISCSI_SESSION_WARN(cs, "tasks terminated");
1155 }
1156
1157 static void
1158 cfiscsi_maintenance_thread(void *arg)
1159 {
1160         struct cfiscsi_session *cs;
1161
1162         cs = arg;
1163
1164         for (;;) {
1165                 CFISCSI_SESSION_LOCK(cs);
1166                 if (cs->cs_terminating == false)
1167                         cv_wait(&cs->cs_maintenance_cv, &cs->cs_lock);
1168                 CFISCSI_SESSION_UNLOCK(cs);
1169
1170                 if (cs->cs_terminating) {
1171
1172                         /*
1173                          * We used to wait up to 30 seconds to deliver queued
1174                          * PDUs to the initiator.  We also tried hard to deliver
1175                          * SCSI Responses for the aborted PDUs.  We don't do
1176                          * that anymore.  We might need to revisit that.
1177                          */
1178                         callout_drain(&cs->cs_callout);
1179                         icl_conn_close(cs->cs_conn);
1180
1181                         /*
1182                          * At this point ICL receive thread is no longer
1183                          * running; no new tasks can be queued.
1184                          */
1185                         cfiscsi_session_terminate_tasks(cs);
1186                         cfiscsi_session_delete(cs);
1187                         kthread_exit();
1188                         return;
1189                 }
1190                 CFISCSI_SESSION_DEBUG(cs, "nothing to do");
1191         }
1192 }
1193
1194 static void
1195 cfiscsi_session_terminate(struct cfiscsi_session *cs)
1196 {
1197
1198         if (cs->cs_terminating)
1199                 return;
1200         cs->cs_terminating = true;
1201         cv_signal(&cs->cs_maintenance_cv);
1202 #ifdef ICL_KERNEL_PROXY
1203         cv_signal(&cs->cs_login_cv);
1204 #endif
1205 }
1206
1207 static int
1208 cfiscsi_session_register_initiator(struct cfiscsi_session *cs)
1209 {
1210         struct cfiscsi_target *ct;
1211         char *name;
1212         int i;
1213
1214         KASSERT(cs->cs_ctl_initid == -1, ("already registered"));
1215
1216         ct = cs->cs_target;
1217         name = strdup(cs->cs_initiator_id, M_CTL);
1218         i = ctl_add_initiator(&ct->ct_port, -1, 0, name);
1219         if (i < 0) {
1220                 CFISCSI_SESSION_WARN(cs, "ctl_add_initiator failed with error %d",
1221                     i);
1222                 cs->cs_ctl_initid = -1;
1223                 return (1);
1224         }
1225         cs->cs_ctl_initid = i;
1226 #if 0
1227         CFISCSI_SESSION_DEBUG(cs, "added initiator id %d", i);
1228 #endif
1229
1230         return (0);
1231 }
1232
1233 static void
1234 cfiscsi_session_unregister_initiator(struct cfiscsi_session *cs)
1235 {
1236         int error;
1237
1238         if (cs->cs_ctl_initid == -1)
1239                 return;
1240
1241         error = ctl_remove_initiator(&cs->cs_target->ct_port, cs->cs_ctl_initid);
1242         if (error != 0) {
1243                 CFISCSI_SESSION_WARN(cs, "ctl_remove_initiator failed with error %d",
1244                     error);
1245         }
1246         cs->cs_ctl_initid = -1;
1247 }
1248
1249 static struct cfiscsi_session *
1250 cfiscsi_session_new(struct cfiscsi_softc *softc, const char *offload)
1251 {
1252         struct cfiscsi_session *cs;
1253         int error;
1254
1255         cs = malloc(sizeof(*cs), M_CFISCSI, M_NOWAIT | M_ZERO);
1256         if (cs == NULL) {
1257                 CFISCSI_WARN("malloc failed");
1258                 return (NULL);
1259         }
1260         cs->cs_ctl_initid = -1;
1261
1262         refcount_init(&cs->cs_outstanding_ctl_pdus, 0);
1263         TAILQ_INIT(&cs->cs_waiting_for_data_out);
1264         mtx_init(&cs->cs_lock, "cfiscsi_lock", NULL, MTX_DEF);
1265         cv_init(&cs->cs_maintenance_cv, "cfiscsi_mt");
1266 #ifdef ICL_KERNEL_PROXY
1267         cv_init(&cs->cs_login_cv, "cfiscsi_login");
1268 #endif
1269
1270         cs->cs_conn = icl_new_conn(offload, false, "cfiscsi", &cs->cs_lock);
1271         if (cs->cs_conn == NULL) {
1272                 free(cs, M_CFISCSI);
1273                 return (NULL);
1274         }
1275         cs->cs_conn->ic_receive = cfiscsi_receive_callback;
1276         cs->cs_conn->ic_error = cfiscsi_error_callback;
1277         cs->cs_conn->ic_prv0 = cs;
1278
1279         error = kthread_add(cfiscsi_maintenance_thread, cs, NULL, NULL, 0, 0, "cfiscsimt");
1280         if (error != 0) {
1281                 CFISCSI_SESSION_WARN(cs, "kthread_add(9) failed with error %d", error);
1282                 free(cs, M_CFISCSI);
1283                 return (NULL);
1284         }
1285
1286         mtx_lock(&softc->lock);
1287         cs->cs_id = ++softc->last_session_id;
1288         TAILQ_INSERT_TAIL(&softc->sessions, cs, cs_next);
1289         mtx_unlock(&softc->lock);
1290
1291         /*
1292          * Start pinging the initiator.
1293          */
1294         callout_init(&cs->cs_callout, 1);
1295         callout_reset(&cs->cs_callout, 1 * hz, cfiscsi_callout, cs);
1296
1297         return (cs);
1298 }
1299
1300 static void
1301 cfiscsi_session_delete(struct cfiscsi_session *cs)
1302 {
1303         struct cfiscsi_softc *softc;
1304
1305         softc = &cfiscsi_softc;
1306
1307         KASSERT(cs->cs_outstanding_ctl_pdus == 0,
1308             ("destroying session with outstanding CTL pdus"));
1309         KASSERT(TAILQ_EMPTY(&cs->cs_waiting_for_data_out),
1310             ("destroying session with non-empty queue"));
1311
1312         cfiscsi_session_unregister_initiator(cs);
1313         if (cs->cs_target != NULL)
1314                 cfiscsi_target_release(cs->cs_target);
1315         icl_conn_close(cs->cs_conn);
1316         icl_conn_free(cs->cs_conn);
1317
1318         mtx_lock(&softc->lock);
1319         TAILQ_REMOVE(&softc->sessions, cs, cs_next);
1320         cv_signal(&softc->sessions_cv);
1321         mtx_unlock(&softc->lock);
1322
1323         free(cs, M_CFISCSI);
1324 }
1325
1326 static int
1327 cfiscsi_init(void)
1328 {
1329         struct cfiscsi_softc *softc;
1330
1331         softc = &cfiscsi_softc;
1332         bzero(softc, sizeof(*softc));
1333         mtx_init(&softc->lock, "cfiscsi", NULL, MTX_DEF);
1334
1335         cv_init(&softc->sessions_cv, "cfiscsi_sessions");
1336 #ifdef ICL_KERNEL_PROXY
1337         cv_init(&softc->accept_cv, "cfiscsi_accept");
1338 #endif
1339         TAILQ_INIT(&softc->sessions);
1340         TAILQ_INIT(&softc->targets);
1341
1342         cfiscsi_data_wait_zone = uma_zcreate("cfiscsi_data_wait",
1343             sizeof(struct cfiscsi_data_wait), NULL, NULL, NULL, NULL,
1344             UMA_ALIGN_PTR, 0);
1345
1346         return (0);
1347 }
1348
1349 static int
1350 cfiscsi_shutdown(void)
1351 {
1352         struct cfiscsi_softc *softc = &cfiscsi_softc;
1353
1354         if (!TAILQ_EMPTY(&softc->sessions) || !TAILQ_EMPTY(&softc->targets))
1355                 return (EBUSY);
1356
1357         uma_zdestroy(cfiscsi_data_wait_zone);
1358 #ifdef ICL_KERNEL_PROXY
1359         cv_destroy(&softc->accept_cv);
1360 #endif
1361         cv_destroy(&softc->sessions_cv);
1362         mtx_destroy(&softc->lock);
1363         return (0);
1364 }
1365
1366 #ifdef ICL_KERNEL_PROXY
1367 static void
1368 cfiscsi_accept(struct socket *so, struct sockaddr *sa, int portal_id)
1369 {
1370         struct cfiscsi_session *cs;
1371
1372         cs = cfiscsi_session_new(&cfiscsi_softc, NULL);
1373         if (cs == NULL) {
1374                 CFISCSI_WARN("failed to create session");
1375                 return;
1376         }
1377
1378         icl_conn_handoff_sock(cs->cs_conn, so);
1379         cs->cs_initiator_sa = sa;
1380         cs->cs_portal_id = portal_id;
1381         cs->cs_waiting_for_ctld = true;
1382         cv_signal(&cfiscsi_softc.accept_cv);
1383 }
1384 #endif
1385
1386 static void
1387 cfiscsi_online(void *arg)
1388 {
1389         struct cfiscsi_softc *softc;
1390         struct cfiscsi_target *ct;
1391         int online;
1392
1393         ct = (struct cfiscsi_target *)arg;
1394         softc = ct->ct_softc;
1395
1396         mtx_lock(&softc->lock);
1397         if (ct->ct_online) {
1398                 mtx_unlock(&softc->lock);
1399                 return;
1400         }
1401         ct->ct_online = 1;
1402         online = softc->online++;
1403         mtx_unlock(&softc->lock);
1404         if (online > 0)
1405                 return;
1406
1407 #ifdef ICL_KERNEL_PROXY
1408         if (softc->listener != NULL)
1409                 icl_listen_free(softc->listener);
1410         softc->listener = icl_listen_new(cfiscsi_accept);
1411 #endif
1412 }
1413
1414 static void
1415 cfiscsi_offline(void *arg)
1416 {
1417         struct cfiscsi_softc *softc;
1418         struct cfiscsi_target *ct;
1419         struct cfiscsi_session *cs;
1420         int online;
1421
1422         ct = (struct cfiscsi_target *)arg;
1423         softc = ct->ct_softc;
1424
1425         mtx_lock(&softc->lock);
1426         if (!ct->ct_online) {
1427                 mtx_unlock(&softc->lock);
1428                 return;
1429         }
1430         ct->ct_online = 0;
1431         online = --softc->online;
1432
1433         TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1434                 if (cs->cs_target == ct)
1435                         cfiscsi_session_terminate(cs);
1436         }
1437         do {
1438                 TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1439                         if (cs->cs_target == ct)
1440                                 break;
1441                 }
1442                 if (cs != NULL)
1443                         cv_wait(&softc->sessions_cv, &softc->lock);
1444         } while (cs != NULL && ct->ct_online == 0);
1445         mtx_unlock(&softc->lock);
1446         if (online > 0)
1447                 return;
1448
1449 #ifdef ICL_KERNEL_PROXY
1450         icl_listen_free(softc->listener);
1451         softc->listener = NULL;
1452 #endif
1453 }
1454
1455 static int
1456 cfiscsi_info(void *arg, struct sbuf *sb)
1457 {
1458         struct cfiscsi_target *ct = (struct cfiscsi_target *)arg;
1459         int retval;
1460
1461         retval = sbuf_printf(sb, "\t<cfiscsi_state>%d</cfiscsi_state>\n",
1462             ct->ct_state);
1463         return (retval);
1464 }
1465
1466 static void
1467 cfiscsi_ioctl_handoff(struct ctl_iscsi *ci)
1468 {
1469         struct cfiscsi_softc *softc;
1470         struct cfiscsi_session *cs, *cs2;
1471         struct cfiscsi_target *ct;
1472         struct ctl_iscsi_handoff_params *cihp;
1473         int error;
1474
1475         cihp = (struct ctl_iscsi_handoff_params *)&(ci->data);
1476         softc = &cfiscsi_softc;
1477
1478         CFISCSI_DEBUG("new connection from %s (%s) to %s",
1479             cihp->initiator_name, cihp->initiator_addr,
1480             cihp->target_name);
1481
1482         ct = cfiscsi_target_find(softc, cihp->target_name,
1483             cihp->portal_group_tag);
1484         if (ct == NULL) {
1485                 ci->status = CTL_ISCSI_ERROR;
1486                 snprintf(ci->error_str, sizeof(ci->error_str),
1487                     "%s: target not found", __func__);
1488                 return;
1489         }
1490
1491 #ifdef ICL_KERNEL_PROXY
1492         if (cihp->socket > 0 && cihp->connection_id > 0) {
1493                 snprintf(ci->error_str, sizeof(ci->error_str),
1494                     "both socket and connection_id set");
1495                 ci->status = CTL_ISCSI_ERROR;
1496                 cfiscsi_target_release(ct);
1497                 return;
1498         }
1499         if (cihp->socket == 0) {
1500                 mtx_lock(&cfiscsi_softc.lock);
1501                 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
1502                         if (cs->cs_id == cihp->connection_id)
1503                                 break;
1504                 }
1505                 if (cs == NULL) {
1506                         mtx_unlock(&cfiscsi_softc.lock);
1507                         snprintf(ci->error_str, sizeof(ci->error_str),
1508                             "connection not found");
1509                         ci->status = CTL_ISCSI_ERROR;
1510                         cfiscsi_target_release(ct);
1511                         return;
1512                 }
1513                 mtx_unlock(&cfiscsi_softc.lock);
1514         } else {
1515 #endif
1516                 cs = cfiscsi_session_new(softc, cihp->offload);
1517                 if (cs == NULL) {
1518                         ci->status = CTL_ISCSI_ERROR;
1519                         snprintf(ci->error_str, sizeof(ci->error_str),
1520                             "%s: cfiscsi_session_new failed", __func__);
1521                         cfiscsi_target_release(ct);
1522                         return;
1523                 }
1524 #ifdef ICL_KERNEL_PROXY
1525         }
1526 #endif
1527
1528         /*
1529          * First PDU of Full Feature phase has the same CmdSN as the last
1530          * PDU from the Login Phase received from the initiator.  Thus,
1531          * the -1 below.
1532          */
1533         cs->cs_cmdsn = cihp->cmdsn;
1534         cs->cs_statsn = cihp->statsn;
1535         cs->cs_max_recv_data_segment_length = cihp->max_recv_data_segment_length;
1536         cs->cs_max_send_data_segment_length = cihp->max_send_data_segment_length;
1537         cs->cs_max_burst_length = cihp->max_burst_length;
1538         cs->cs_first_burst_length = cihp->first_burst_length;
1539         cs->cs_immediate_data = !!cihp->immediate_data;
1540         if (cihp->header_digest == CTL_ISCSI_DIGEST_CRC32C)
1541                 cs->cs_conn->ic_header_crc32c = true;
1542         if (cihp->data_digest == CTL_ISCSI_DIGEST_CRC32C)
1543                 cs->cs_conn->ic_data_crc32c = true;
1544
1545         strlcpy(cs->cs_initiator_name,
1546             cihp->initiator_name, sizeof(cs->cs_initiator_name));
1547         strlcpy(cs->cs_initiator_addr,
1548             cihp->initiator_addr, sizeof(cs->cs_initiator_addr));
1549         strlcpy(cs->cs_initiator_alias,
1550             cihp->initiator_alias, sizeof(cs->cs_initiator_alias));
1551         memcpy(cs->cs_initiator_isid,
1552             cihp->initiator_isid, sizeof(cs->cs_initiator_isid));
1553         snprintf(cs->cs_initiator_id, sizeof(cs->cs_initiator_id),
1554             "%s,i,0x%02x%02x%02x%02x%02x%02x", cs->cs_initiator_name,
1555             cihp->initiator_isid[0], cihp->initiator_isid[1],
1556             cihp->initiator_isid[2], cihp->initiator_isid[3],
1557             cihp->initiator_isid[4], cihp->initiator_isid[5]);
1558
1559         mtx_lock(&softc->lock);
1560         if (ct->ct_online == 0) {
1561                 mtx_unlock(&softc->lock);
1562                 cfiscsi_session_terminate(cs);
1563                 cfiscsi_target_release(ct);
1564                 ci->status = CTL_ISCSI_ERROR;
1565                 snprintf(ci->error_str, sizeof(ci->error_str),
1566                     "%s: port offline", __func__);
1567                 return;
1568         }
1569         cs->cs_target = ct;
1570         mtx_unlock(&softc->lock);
1571
1572         refcount_acquire(&cs->cs_outstanding_ctl_pdus);
1573 restart:
1574         if (!cs->cs_terminating) {
1575                 mtx_lock(&softc->lock);
1576                 TAILQ_FOREACH(cs2, &softc->sessions, cs_next) {
1577                         if (cs2 != cs && cs2->cs_tasks_aborted == false &&
1578                             cs->cs_target == cs2->cs_target &&
1579                             strcmp(cs->cs_initiator_id, cs2->cs_initiator_id) == 0) {
1580                                 if (strcmp(cs->cs_initiator_addr,
1581                                     cs2->cs_initiator_addr) != 0) {
1582                                         CFISCSI_SESSION_WARN(cs2,
1583                                             "session reinstatement from "
1584                                             "different address %s",
1585                                             cs->cs_initiator_addr);
1586                                 } else {
1587                                         CFISCSI_SESSION_DEBUG(cs2,
1588                                             "session reinstatement");
1589                                 }
1590                                 cfiscsi_session_terminate(cs2);
1591                                 mtx_unlock(&softc->lock);
1592                                 pause("cfiscsi_reinstate", 1);
1593                                 goto restart;
1594                         }
1595                 }
1596                 mtx_unlock(&softc->lock);
1597         }
1598
1599         /*
1600          * Register initiator with CTL.
1601          */
1602         cfiscsi_session_register_initiator(cs);
1603
1604 #ifdef ICL_KERNEL_PROXY
1605         if (cihp->socket > 0) {
1606 #endif
1607                 error = icl_conn_handoff(cs->cs_conn, cihp->socket);
1608                 if (error != 0) {
1609                         cfiscsi_session_terminate(cs);
1610                         refcount_release(&cs->cs_outstanding_ctl_pdus);
1611                         ci->status = CTL_ISCSI_ERROR;
1612                         snprintf(ci->error_str, sizeof(ci->error_str),
1613                             "%s: icl_conn_handoff failed with error %d",
1614                             __func__, error);
1615                         return;
1616                 }
1617 #ifdef ICL_KERNEL_PROXY
1618         }
1619 #endif
1620
1621 #ifdef ICL_KERNEL_PROXY
1622         cs->cs_login_phase = false;
1623
1624         /*
1625          * First PDU of the Full Feature phase has likely already arrived.
1626          * We have to pick it up and execute properly.
1627          */
1628         if (cs->cs_login_pdu != NULL) {
1629                 CFISCSI_SESSION_DEBUG(cs, "picking up first PDU");
1630                 cfiscsi_pdu_handle(cs->cs_login_pdu);
1631                 cs->cs_login_pdu = NULL;
1632         }
1633 #endif
1634
1635         refcount_release(&cs->cs_outstanding_ctl_pdus);
1636         ci->status = CTL_ISCSI_OK;
1637 }
1638
1639 static void
1640 cfiscsi_ioctl_list(struct ctl_iscsi *ci)
1641 {
1642         struct ctl_iscsi_list_params *cilp;
1643         struct cfiscsi_session *cs;
1644         struct cfiscsi_softc *softc;
1645         struct sbuf *sb;
1646         int error;
1647
1648         cilp = (struct ctl_iscsi_list_params *)&(ci->data);
1649         softc = &cfiscsi_softc;
1650
1651         sb = sbuf_new(NULL, NULL, cilp->alloc_len, SBUF_FIXEDLEN);
1652         if (sb == NULL) {
1653                 ci->status = CTL_ISCSI_ERROR;
1654                 snprintf(ci->error_str, sizeof(ci->error_str),
1655                     "Unable to allocate %d bytes for iSCSI session list",
1656                     cilp->alloc_len);
1657                 return;
1658         }
1659
1660         sbuf_printf(sb, "<ctlislist>\n");
1661         mtx_lock(&softc->lock);
1662         TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1663 #ifdef ICL_KERNEL_PROXY
1664                 if (cs->cs_target == NULL)
1665                         continue;
1666 #endif
1667                 error = sbuf_printf(sb, "<connection id=\"%d\">"
1668                     "<initiator>%s</initiator>"
1669                     "<initiator_addr>%s</initiator_addr>"
1670                     "<initiator_alias>%s</initiator_alias>"
1671                     "<target>%s</target>"
1672                     "<target_alias>%s</target_alias>"
1673                     "<target_portal_group_tag>%u</target_portal_group_tag>"
1674                     "<header_digest>%s</header_digest>"
1675                     "<data_digest>%s</data_digest>"
1676                     "<max_recv_data_segment_length>%d</max_recv_data_segment_length>"
1677                     "<max_send_data_segment_length>%d</max_send_data_segment_length>"
1678                     "<max_burst_length>%d</max_burst_length>"
1679                     "<first_burst_length>%d</first_burst_length>"
1680                     "<immediate_data>%d</immediate_data>"
1681                     "<iser>%d</iser>"
1682                     "<offload>%s</offload>"
1683                     "</connection>\n",
1684                     cs->cs_id,
1685                     cs->cs_initiator_name, cs->cs_initiator_addr, cs->cs_initiator_alias,
1686                     cs->cs_target->ct_name, cs->cs_target->ct_alias,
1687                     cs->cs_target->ct_tag,
1688                     cs->cs_conn->ic_header_crc32c ? "CRC32C" : "None",
1689                     cs->cs_conn->ic_data_crc32c ? "CRC32C" : "None",
1690                     cs->cs_max_recv_data_segment_length,
1691                     cs->cs_max_send_data_segment_length,
1692                     cs->cs_max_burst_length,
1693                     cs->cs_first_burst_length,
1694                     cs->cs_immediate_data,
1695                     cs->cs_conn->ic_iser,
1696                     cs->cs_conn->ic_offload);
1697                 if (error != 0)
1698                         break;
1699         }
1700         mtx_unlock(&softc->lock);
1701         error = sbuf_printf(sb, "</ctlislist>\n");
1702         if (error != 0) {
1703                 sbuf_delete(sb);
1704                 ci->status = CTL_ISCSI_LIST_NEED_MORE_SPACE;
1705                 snprintf(ci->error_str, sizeof(ci->error_str),
1706                     "Out of space, %d bytes is too small", cilp->alloc_len);
1707                 return;
1708         }
1709         sbuf_finish(sb);
1710
1711         error = copyout(sbuf_data(sb), cilp->conn_xml, sbuf_len(sb) + 1);
1712         cilp->fill_len = sbuf_len(sb) + 1;
1713         ci->status = CTL_ISCSI_OK;
1714         sbuf_delete(sb);
1715 }
1716
1717 static void
1718 cfiscsi_ioctl_logout(struct ctl_iscsi *ci)
1719 {
1720         struct icl_pdu *response;
1721         struct iscsi_bhs_asynchronous_message *bhsam;
1722         struct ctl_iscsi_logout_params *cilp;
1723         struct cfiscsi_session *cs;
1724         struct cfiscsi_softc *softc;
1725         int found = 0;
1726
1727         cilp = (struct ctl_iscsi_logout_params *)&(ci->data);
1728         softc = &cfiscsi_softc;
1729
1730         mtx_lock(&softc->lock);
1731         TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1732                 if (cilp->all == 0 && cs->cs_id != cilp->connection_id &&
1733                     strcmp(cs->cs_initiator_name, cilp->initiator_name) != 0 &&
1734                     strcmp(cs->cs_initiator_addr, cilp->initiator_addr) != 0)
1735                         continue;
1736
1737                 response = icl_pdu_new(cs->cs_conn, M_NOWAIT);
1738                 if (response == NULL) {
1739                         ci->status = CTL_ISCSI_ERROR;
1740                         snprintf(ci->error_str, sizeof(ci->error_str),
1741                             "Unable to allocate memory");
1742                         mtx_unlock(&softc->lock);
1743                         return;
1744                 }
1745                 bhsam =
1746                     (struct iscsi_bhs_asynchronous_message *)response->ip_bhs;
1747                 bhsam->bhsam_opcode = ISCSI_BHS_OPCODE_ASYNC_MESSAGE;
1748                 bhsam->bhsam_flags = 0x80;
1749                 bhsam->bhsam_async_event = BHSAM_EVENT_TARGET_REQUESTS_LOGOUT;
1750                 bhsam->bhsam_parameter3 = htons(10);
1751                 cfiscsi_pdu_queue(response);
1752                 found++;
1753         }
1754         mtx_unlock(&softc->lock);
1755
1756         if (found == 0) {
1757                 ci->status = CTL_ISCSI_SESSION_NOT_FOUND;
1758                 snprintf(ci->error_str, sizeof(ci->error_str),
1759                     "No matching connections found");
1760                 return;
1761         }
1762
1763         ci->status = CTL_ISCSI_OK;
1764 }
1765
1766 static void
1767 cfiscsi_ioctl_terminate(struct ctl_iscsi *ci)
1768 {
1769         struct icl_pdu *response;
1770         struct iscsi_bhs_asynchronous_message *bhsam;
1771         struct ctl_iscsi_terminate_params *citp;
1772         struct cfiscsi_session *cs;
1773         struct cfiscsi_softc *softc;
1774         int found = 0;
1775
1776         citp = (struct ctl_iscsi_terminate_params *)&(ci->data);
1777         softc = &cfiscsi_softc;
1778
1779         mtx_lock(&softc->lock);
1780         TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1781                 if (citp->all == 0 && cs->cs_id != citp->connection_id &&
1782                     strcmp(cs->cs_initiator_name, citp->initiator_name) != 0 &&
1783                     strcmp(cs->cs_initiator_addr, citp->initiator_addr) != 0)
1784                         continue;
1785
1786                 response = icl_pdu_new(cs->cs_conn, M_NOWAIT);
1787                 if (response == NULL) {
1788                         /*
1789                          * Oh well.  Just terminate the connection.
1790                          */
1791                 } else {
1792                         bhsam = (struct iscsi_bhs_asynchronous_message *)
1793                             response->ip_bhs;
1794                         bhsam->bhsam_opcode = ISCSI_BHS_OPCODE_ASYNC_MESSAGE;
1795                         bhsam->bhsam_flags = 0x80;
1796                         bhsam->bhsam_0xffffffff = 0xffffffff;
1797                         bhsam->bhsam_async_event =
1798                             BHSAM_EVENT_TARGET_TERMINATES_SESSION;
1799                         cfiscsi_pdu_queue(response);
1800                 }
1801                 cfiscsi_session_terminate(cs);
1802                 found++;
1803         }
1804         mtx_unlock(&softc->lock);
1805
1806         if (found == 0) {
1807                 ci->status = CTL_ISCSI_SESSION_NOT_FOUND;
1808                 snprintf(ci->error_str, sizeof(ci->error_str),
1809                     "No matching connections found");
1810                 return;
1811         }
1812
1813         ci->status = CTL_ISCSI_OK;
1814 }
1815
1816 static void
1817 cfiscsi_ioctl_limits(struct ctl_iscsi *ci)
1818 {
1819         struct ctl_iscsi_limits_params *cilp;
1820         struct icl_drv_limits idl;
1821         int error;
1822
1823         cilp = (struct ctl_iscsi_limits_params *)&(ci->data);
1824
1825         error = icl_limits(cilp->offload, false, &idl);
1826         if (error != 0) {
1827                 ci->status = CTL_ISCSI_ERROR;
1828                 snprintf(ci->error_str, sizeof(ci->error_str),
1829                         "%s: icl_limits failed with error %d",
1830                         __func__, error);
1831                 return;
1832         }
1833
1834         cilp->max_recv_data_segment_length =
1835             idl.idl_max_recv_data_segment_length;
1836         cilp->max_send_data_segment_length =
1837             idl.idl_max_send_data_segment_length;
1838         cilp->max_burst_length = idl.idl_max_burst_length;
1839         cilp->first_burst_length = idl.idl_first_burst_length;
1840
1841         ci->status = CTL_ISCSI_OK;
1842 }
1843
1844 #ifdef ICL_KERNEL_PROXY
1845 static void
1846 cfiscsi_ioctl_listen(struct ctl_iscsi *ci)
1847 {
1848         struct ctl_iscsi_listen_params *cilp;
1849         struct sockaddr *sa;
1850         int error;
1851
1852         cilp = (struct ctl_iscsi_listen_params *)&(ci->data);
1853
1854         if (cfiscsi_softc.listener == NULL) {
1855                 CFISCSI_DEBUG("no listener");
1856                 snprintf(ci->error_str, sizeof(ci->error_str), "no listener");
1857                 ci->status = CTL_ISCSI_ERROR;
1858                 return;
1859         }
1860
1861         error = getsockaddr(&sa, (void *)cilp->addr, cilp->addrlen);
1862         if (error != 0) {
1863                 CFISCSI_DEBUG("getsockaddr, error %d", error);
1864                 snprintf(ci->error_str, sizeof(ci->error_str), "getsockaddr failed");
1865                 ci->status = CTL_ISCSI_ERROR;
1866                 return;
1867         }
1868
1869         error = icl_listen_add(cfiscsi_softc.listener, cilp->iser, cilp->domain,
1870             cilp->socktype, cilp->protocol, sa, cilp->portal_id);
1871         if (error != 0) {
1872                 free(sa, M_SONAME);
1873                 CFISCSI_DEBUG("icl_listen_add, error %d", error);
1874                 snprintf(ci->error_str, sizeof(ci->error_str),
1875                     "icl_listen_add failed, error %d", error);
1876                 ci->status = CTL_ISCSI_ERROR;
1877                 return;
1878         }
1879
1880         ci->status = CTL_ISCSI_OK;
1881 }
1882
1883 static void
1884 cfiscsi_ioctl_accept(struct ctl_iscsi *ci)
1885 {
1886         struct ctl_iscsi_accept_params *ciap;
1887         struct cfiscsi_session *cs;
1888         int error;
1889
1890         ciap = (struct ctl_iscsi_accept_params *)&(ci->data);
1891
1892         mtx_lock(&cfiscsi_softc.lock);
1893         for (;;) {
1894                 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
1895                         if (cs->cs_waiting_for_ctld)
1896                                 break;
1897                 }
1898                 if (cs != NULL)
1899                         break;
1900                 error = cv_wait_sig(&cfiscsi_softc.accept_cv, &cfiscsi_softc.lock);
1901                 if (error != 0) {
1902                         mtx_unlock(&cfiscsi_softc.lock);
1903                         snprintf(ci->error_str, sizeof(ci->error_str), "interrupted");
1904                         ci->status = CTL_ISCSI_ERROR;
1905                         return;
1906                 }
1907         }
1908         mtx_unlock(&cfiscsi_softc.lock);
1909
1910         cs->cs_waiting_for_ctld = false;
1911         cs->cs_login_phase = true;
1912
1913         ciap->connection_id = cs->cs_id;
1914         ciap->portal_id = cs->cs_portal_id;
1915         ciap->initiator_addrlen = cs->cs_initiator_sa->sa_len;
1916         error = copyout(cs->cs_initiator_sa, ciap->initiator_addr,
1917             cs->cs_initiator_sa->sa_len);
1918         if (error != 0) {
1919                 snprintf(ci->error_str, sizeof(ci->error_str),
1920                     "copyout failed with error %d", error);
1921                 ci->status = CTL_ISCSI_ERROR;
1922                 return;
1923         }
1924
1925         ci->status = CTL_ISCSI_OK;
1926 }
1927
1928 static void
1929 cfiscsi_ioctl_send(struct ctl_iscsi *ci)
1930 {
1931         struct ctl_iscsi_send_params *cisp;
1932         struct cfiscsi_session *cs;
1933         struct icl_pdu *ip;
1934         size_t datalen;
1935         void *data;
1936         int error;
1937
1938         cisp = (struct ctl_iscsi_send_params *)&(ci->data);
1939
1940         mtx_lock(&cfiscsi_softc.lock);
1941         TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
1942                 if (cs->cs_id == cisp->connection_id)
1943                         break;
1944         }
1945         if (cs == NULL) {
1946                 mtx_unlock(&cfiscsi_softc.lock);
1947                 snprintf(ci->error_str, sizeof(ci->error_str), "connection not found");
1948                 ci->status = CTL_ISCSI_ERROR;
1949                 return;
1950         }
1951         mtx_unlock(&cfiscsi_softc.lock);
1952
1953 #if 0
1954         if (cs->cs_login_phase == false)
1955                 return (EBUSY);
1956 #endif
1957
1958         if (cs->cs_terminating) {
1959                 snprintf(ci->error_str, sizeof(ci->error_str), "connection is terminating");
1960                 ci->status = CTL_ISCSI_ERROR;
1961                 return;
1962         }
1963
1964         datalen = cisp->data_segment_len;
1965         /*
1966          * XXX
1967          */
1968         //if (datalen > CFISCSI_MAX_DATA_SEGMENT_LENGTH) {
1969         if (datalen > 65535) {
1970                 snprintf(ci->error_str, sizeof(ci->error_str), "data segment too big");
1971                 ci->status = CTL_ISCSI_ERROR;
1972                 return;
1973         }
1974         if (datalen > 0) {
1975                 data = malloc(datalen, M_CFISCSI, M_WAITOK);
1976                 error = copyin(cisp->data_segment, data, datalen);
1977                 if (error != 0) {
1978                         free(data, M_CFISCSI);
1979                         snprintf(ci->error_str, sizeof(ci->error_str), "copyin error %d", error);
1980                         ci->status = CTL_ISCSI_ERROR;
1981                         return;
1982                 }
1983         }
1984
1985         ip = icl_pdu_new(cs->cs_conn, M_WAITOK);
1986         memcpy(ip->ip_bhs, cisp->bhs, sizeof(*ip->ip_bhs));
1987         if (datalen > 0) {
1988                 icl_pdu_append_data(ip, data, datalen, M_WAITOK);
1989                 free(data, M_CFISCSI);
1990         }
1991         CFISCSI_SESSION_LOCK(cs);
1992         icl_pdu_queue(ip);
1993         CFISCSI_SESSION_UNLOCK(cs);
1994         ci->status = CTL_ISCSI_OK;
1995 }
1996
1997 static void
1998 cfiscsi_ioctl_receive(struct ctl_iscsi *ci)
1999 {
2000         struct ctl_iscsi_receive_params *cirp;
2001         struct cfiscsi_session *cs;
2002         struct icl_pdu *ip;
2003         void *data;
2004         int error;
2005
2006         cirp = (struct ctl_iscsi_receive_params *)&(ci->data);
2007
2008         mtx_lock(&cfiscsi_softc.lock);
2009         TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
2010                 if (cs->cs_id == cirp->connection_id)
2011                         break;
2012         }
2013         if (cs == NULL) {
2014                 mtx_unlock(&cfiscsi_softc.lock);
2015                 snprintf(ci->error_str, sizeof(ci->error_str),
2016                     "connection not found");
2017                 ci->status = CTL_ISCSI_ERROR;
2018                 return;
2019         }
2020         mtx_unlock(&cfiscsi_softc.lock);
2021
2022 #if 0
2023         if (is->is_login_phase == false)
2024                 return (EBUSY);
2025 #endif
2026
2027         CFISCSI_SESSION_LOCK(cs);
2028         while (cs->cs_login_pdu == NULL && cs->cs_terminating == false) {
2029                 error = cv_wait_sig(&cs->cs_login_cv, &cs->cs_lock);
2030                 if (error != 0) {
2031                         CFISCSI_SESSION_UNLOCK(cs);
2032                         snprintf(ci->error_str, sizeof(ci->error_str),
2033                             "interrupted by signal");
2034                         ci->status = CTL_ISCSI_ERROR;
2035                         return;
2036                 }
2037         }
2038
2039         if (cs->cs_terminating) {
2040                 CFISCSI_SESSION_UNLOCK(cs);
2041                 snprintf(ci->error_str, sizeof(ci->error_str),
2042                     "connection terminating");
2043                 ci->status = CTL_ISCSI_ERROR;
2044                 return;
2045         }
2046         ip = cs->cs_login_pdu;
2047         cs->cs_login_pdu = NULL;
2048         CFISCSI_SESSION_UNLOCK(cs);
2049
2050         if (ip->ip_data_len > cirp->data_segment_len) {
2051                 icl_pdu_free(ip);
2052                 snprintf(ci->error_str, sizeof(ci->error_str),
2053                     "data segment too big");
2054                 ci->status = CTL_ISCSI_ERROR;
2055                 return;
2056         }
2057
2058         copyout(ip->ip_bhs, cirp->bhs, sizeof(*ip->ip_bhs));
2059         if (ip->ip_data_len > 0) {
2060                 data = malloc(ip->ip_data_len, M_CFISCSI, M_WAITOK);
2061                 icl_pdu_get_data(ip, 0, data, ip->ip_data_len);
2062                 copyout(data, cirp->data_segment, ip->ip_data_len);
2063                 free(data, M_CFISCSI);
2064         }
2065
2066         icl_pdu_free(ip);
2067         ci->status = CTL_ISCSI_OK;
2068 }
2069
2070 #endif /* !ICL_KERNEL_PROXY */
2071
2072 static void
2073 cfiscsi_ioctl_port_create(struct ctl_req *req)
2074 {
2075         struct cfiscsi_target *ct;
2076         struct ctl_port *port;
2077         const char *target, *alias, *tags;
2078         struct scsi_vpd_id_descriptor *desc;
2079         ctl_options_t opts;
2080         int retval, len, idlen;
2081         uint16_t tag;
2082
2083         ctl_init_opts(&opts, req->num_args, req->kern_args);
2084         target = ctl_get_opt(&opts, "cfiscsi_target");
2085         alias = ctl_get_opt(&opts, "cfiscsi_target_alias");
2086         tags = ctl_get_opt(&opts, "cfiscsi_portal_group_tag");
2087         if (target == NULL || tags == NULL) {
2088                 req->status = CTL_LUN_ERROR;
2089                 snprintf(req->error_str, sizeof(req->error_str),
2090                     "Missing required argument");
2091                 ctl_free_opts(&opts);
2092                 return;
2093         }
2094         tag = strtol(tags, (char **)NULL, 10);
2095         ct = cfiscsi_target_find_or_create(&cfiscsi_softc, target, alias, tag);
2096         if (ct == NULL) {
2097                 req->status = CTL_LUN_ERROR;
2098                 snprintf(req->error_str, sizeof(req->error_str),
2099                     "failed to create target \"%s\"", target);
2100                 ctl_free_opts(&opts);
2101                 return;
2102         }
2103         if (ct->ct_state == CFISCSI_TARGET_STATE_ACTIVE) {
2104                 req->status = CTL_LUN_ERROR;
2105                 snprintf(req->error_str, sizeof(req->error_str),
2106                     "target \"%s\" for portal group tag %u already exists",
2107                     target, tag);
2108                 cfiscsi_target_release(ct);
2109                 ctl_free_opts(&opts);
2110                 return;
2111         }
2112         port = &ct->ct_port;
2113         // WAT
2114         if (ct->ct_state == CFISCSI_TARGET_STATE_DYING)
2115                 goto done;
2116
2117         port->frontend = &cfiscsi_frontend;
2118         port->port_type = CTL_PORT_ISCSI;
2119         /* XXX KDM what should the real number be here? */
2120         port->num_requested_ctl_io = 4096;
2121         port->port_name = "iscsi";
2122         port->physical_port = tag;
2123         port->virtual_port = ct->ct_target_id;
2124         port->port_online = cfiscsi_online;
2125         port->port_offline = cfiscsi_offline;
2126         port->port_info = cfiscsi_info;
2127         port->onoff_arg = ct;
2128         port->fe_datamove = cfiscsi_datamove;
2129         port->fe_done = cfiscsi_done;
2130         port->targ_port = -1;
2131
2132         port->options = opts;
2133         STAILQ_INIT(&opts);
2134
2135         /* Generate Port ID. */
2136         idlen = strlen(target) + strlen(",t,0x0001") + 1;
2137         idlen = roundup2(idlen, 4);
2138         len = sizeof(struct scsi_vpd_device_id) + idlen;
2139         port->port_devid = malloc(sizeof(struct ctl_devid) + len,
2140             M_CTL, M_WAITOK | M_ZERO);
2141         port->port_devid->len = len;
2142         desc = (struct scsi_vpd_id_descriptor *)port->port_devid->data;
2143         desc->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_UTF8;
2144         desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT |
2145             SVPD_ID_TYPE_SCSI_NAME;
2146         desc->length = idlen;
2147         snprintf(desc->identifier, idlen, "%s,t,0x%4.4x", target, tag);
2148
2149         /* Generate Target ID. */
2150         idlen = strlen(target) + 1;
2151         idlen = roundup2(idlen, 4);
2152         len = sizeof(struct scsi_vpd_device_id) + idlen;
2153         port->target_devid = malloc(sizeof(struct ctl_devid) + len,
2154             M_CTL, M_WAITOK | M_ZERO);
2155         port->target_devid->len = len;
2156         desc = (struct scsi_vpd_id_descriptor *)port->target_devid->data;
2157         desc->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_UTF8;
2158         desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_TARGET |
2159             SVPD_ID_TYPE_SCSI_NAME;
2160         desc->length = idlen;
2161         strlcpy(desc->identifier, target, idlen);
2162
2163         retval = ctl_port_register(port);
2164         if (retval != 0) {
2165                 ctl_free_opts(&port->options);
2166                 cfiscsi_target_release(ct);
2167                 free(port->port_devid, M_CFISCSI);
2168                 free(port->target_devid, M_CFISCSI);
2169                 req->status = CTL_LUN_ERROR;
2170                 snprintf(req->error_str, sizeof(req->error_str),
2171                     "ctl_port_register() failed with error %d", retval);
2172                 return;
2173         }
2174 done:
2175         ct->ct_state = CFISCSI_TARGET_STATE_ACTIVE;
2176         req->status = CTL_LUN_OK;
2177         memcpy(req->kern_args[0].kvalue, &port->targ_port,
2178             sizeof(port->targ_port)); //XXX
2179 }
2180
2181 static void
2182 cfiscsi_ioctl_port_remove(struct ctl_req *req)
2183 {
2184         struct cfiscsi_target *ct;
2185         const char *target, *tags;
2186         ctl_options_t opts;
2187         uint16_t tag;
2188
2189         ctl_init_opts(&opts, req->num_args, req->kern_args);
2190         target = ctl_get_opt(&opts, "cfiscsi_target");
2191         tags = ctl_get_opt(&opts, "cfiscsi_portal_group_tag");
2192         if (target == NULL || tags == NULL) {
2193                 ctl_free_opts(&opts);
2194                 req->status = CTL_LUN_ERROR;
2195                 snprintf(req->error_str, sizeof(req->error_str),
2196                     "Missing required argument");
2197                 return;
2198         }
2199         tag = strtol(tags, (char **)NULL, 10);
2200         ct = cfiscsi_target_find(&cfiscsi_softc, target, tag);
2201         if (ct == NULL) {
2202                 ctl_free_opts(&opts);
2203                 req->status = CTL_LUN_ERROR;
2204                 snprintf(req->error_str, sizeof(req->error_str),
2205                     "can't find target \"%s\"", target);
2206                 return;
2207         }
2208         if (ct->ct_state != CFISCSI_TARGET_STATE_ACTIVE) {
2209                 ctl_free_opts(&opts);
2210                 req->status = CTL_LUN_ERROR;
2211                 snprintf(req->error_str, sizeof(req->error_str),
2212                     "target \"%s\" is already dying", target);
2213                 return;
2214         }
2215         ctl_free_opts(&opts);
2216
2217         ct->ct_state = CFISCSI_TARGET_STATE_DYING;
2218         ctl_port_offline(&ct->ct_port);
2219         cfiscsi_target_release(ct);
2220         cfiscsi_target_release(ct);
2221         req->status = CTL_LUN_OK;
2222 }
2223
2224 static int
2225 cfiscsi_ioctl(struct cdev *dev,
2226     u_long cmd, caddr_t addr, int flag, struct thread *td)
2227 {
2228         struct ctl_iscsi *ci;
2229         struct ctl_req *req;
2230
2231         if (cmd == CTL_PORT_REQ) {
2232                 req = (struct ctl_req *)addr;
2233                 switch (req->reqtype) {
2234                 case CTL_REQ_CREATE:
2235                         cfiscsi_ioctl_port_create(req);
2236                         break;
2237                 case CTL_REQ_REMOVE:
2238                         cfiscsi_ioctl_port_remove(req);
2239                         break;
2240                 default:
2241                         req->status = CTL_LUN_ERROR;
2242                         snprintf(req->error_str, sizeof(req->error_str),
2243                             "Unsupported request type %d", req->reqtype);
2244                 }
2245                 return (0);
2246         }
2247
2248         if (cmd != CTL_ISCSI)
2249                 return (ENOTTY);
2250
2251         ci = (struct ctl_iscsi *)addr;
2252         switch (ci->type) {
2253         case CTL_ISCSI_HANDOFF:
2254                 cfiscsi_ioctl_handoff(ci);
2255                 break;
2256         case CTL_ISCSI_LIST:
2257                 cfiscsi_ioctl_list(ci);
2258                 break;
2259         case CTL_ISCSI_LOGOUT:
2260                 cfiscsi_ioctl_logout(ci);
2261                 break;
2262         case CTL_ISCSI_TERMINATE:
2263                 cfiscsi_ioctl_terminate(ci);
2264                 break;
2265         case CTL_ISCSI_LIMITS:
2266                 cfiscsi_ioctl_limits(ci);
2267                 break;
2268 #ifdef ICL_KERNEL_PROXY
2269         case CTL_ISCSI_LISTEN:
2270                 cfiscsi_ioctl_listen(ci);
2271                 break;
2272         case CTL_ISCSI_ACCEPT:
2273                 cfiscsi_ioctl_accept(ci);
2274                 break;
2275         case CTL_ISCSI_SEND:
2276                 cfiscsi_ioctl_send(ci);
2277                 break;
2278         case CTL_ISCSI_RECEIVE:
2279                 cfiscsi_ioctl_receive(ci);
2280                 break;
2281 #else
2282         case CTL_ISCSI_LISTEN:
2283         case CTL_ISCSI_ACCEPT:
2284         case CTL_ISCSI_SEND:
2285         case CTL_ISCSI_RECEIVE:
2286                 ci->status = CTL_ISCSI_ERROR;
2287                 snprintf(ci->error_str, sizeof(ci->error_str),
2288                     "%s: CTL compiled without ICL_KERNEL_PROXY",
2289                     __func__);
2290                 break;
2291 #endif /* !ICL_KERNEL_PROXY */
2292         default:
2293                 ci->status = CTL_ISCSI_ERROR;
2294                 snprintf(ci->error_str, sizeof(ci->error_str),
2295                     "%s: invalid iSCSI request type %d", __func__, ci->type);
2296                 break;
2297         }
2298
2299         return (0);
2300 }
2301
2302 static void
2303 cfiscsi_target_hold(struct cfiscsi_target *ct)
2304 {
2305
2306         refcount_acquire(&ct->ct_refcount);
2307 }
2308
2309 static void
2310 cfiscsi_target_release(struct cfiscsi_target *ct)
2311 {
2312         struct cfiscsi_softc *softc;
2313
2314         softc = ct->ct_softc;
2315         mtx_lock(&softc->lock);
2316         if (refcount_release(&ct->ct_refcount)) {
2317                 TAILQ_REMOVE(&softc->targets, ct, ct_next);
2318                 mtx_unlock(&softc->lock);
2319                 if (ct->ct_state != CFISCSI_TARGET_STATE_INVALID) {
2320                         ct->ct_state = CFISCSI_TARGET_STATE_INVALID;
2321                         if (ctl_port_deregister(&ct->ct_port) != 0)
2322                                 printf("%s: ctl_port_deregister() failed\n",
2323                                     __func__);
2324                 }
2325                 free(ct, M_CFISCSI);
2326
2327                 return;
2328         }
2329         mtx_unlock(&softc->lock);
2330 }
2331
2332 static struct cfiscsi_target *
2333 cfiscsi_target_find(struct cfiscsi_softc *softc, const char *name, uint16_t tag)
2334 {
2335         struct cfiscsi_target *ct;
2336
2337         mtx_lock(&softc->lock);
2338         TAILQ_FOREACH(ct, &softc->targets, ct_next) {
2339                 if (ct->ct_tag != tag ||
2340                     strcmp(name, ct->ct_name) != 0 ||
2341                     ct->ct_state != CFISCSI_TARGET_STATE_ACTIVE)
2342                         continue;
2343                 cfiscsi_target_hold(ct);
2344                 mtx_unlock(&softc->lock);
2345                 return (ct);
2346         }
2347         mtx_unlock(&softc->lock);
2348
2349         return (NULL);
2350 }
2351
2352 static struct cfiscsi_target *
2353 cfiscsi_target_find_or_create(struct cfiscsi_softc *softc, const char *name,
2354     const char *alias, uint16_t tag)
2355 {
2356         struct cfiscsi_target *ct, *newct;
2357
2358         if (name[0] == '\0' || strlen(name) >= CTL_ISCSI_NAME_LEN)
2359                 return (NULL);
2360
2361         newct = malloc(sizeof(*newct), M_CFISCSI, M_WAITOK | M_ZERO);
2362
2363         mtx_lock(&softc->lock);
2364         TAILQ_FOREACH(ct, &softc->targets, ct_next) {
2365                 if (ct->ct_tag != tag ||
2366                     strcmp(name, ct->ct_name) != 0 ||
2367                     ct->ct_state == CFISCSI_TARGET_STATE_INVALID)
2368                         continue;
2369                 cfiscsi_target_hold(ct);
2370                 mtx_unlock(&softc->lock);
2371                 free(newct, M_CFISCSI);
2372                 return (ct);
2373         }
2374
2375         strlcpy(newct->ct_name, name, sizeof(newct->ct_name));
2376         if (alias != NULL)
2377                 strlcpy(newct->ct_alias, alias, sizeof(newct->ct_alias));
2378         newct->ct_tag = tag;
2379         refcount_init(&newct->ct_refcount, 1);
2380         newct->ct_softc = softc;
2381         if (TAILQ_EMPTY(&softc->targets))
2382                 softc->last_target_id = 0;
2383         newct->ct_target_id = ++softc->last_target_id;
2384         TAILQ_INSERT_TAIL(&softc->targets, newct, ct_next);
2385         mtx_unlock(&softc->lock);
2386
2387         return (newct);
2388 }
2389
2390 static void
2391 cfiscsi_datamove_in(union ctl_io *io)
2392 {
2393         struct cfiscsi_session *cs;
2394         struct icl_pdu *request, *response;
2395         const struct iscsi_bhs_scsi_command *bhssc;
2396         struct iscsi_bhs_data_in *bhsdi;
2397         struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
2398         size_t len, expected_len, sg_len, buffer_offset;
2399         const char *sg_addr;
2400         int ctl_sg_count, error, i;
2401
2402         request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2403         cs = PDU_SESSION(request);
2404
2405         bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs;
2406         KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
2407             ISCSI_BHS_OPCODE_SCSI_COMMAND,
2408             ("bhssc->bhssc_opcode != ISCSI_BHS_OPCODE_SCSI_COMMAND"));
2409
2410         if (io->scsiio.kern_sg_entries > 0) {
2411                 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
2412                 ctl_sg_count = io->scsiio.kern_sg_entries;
2413         } else {
2414                 ctl_sglist = &ctl_sg_entry;
2415                 ctl_sglist->addr = io->scsiio.kern_data_ptr;
2416                 ctl_sglist->len = io->scsiio.kern_data_len;
2417                 ctl_sg_count = 1;
2418         }
2419
2420         /*
2421          * This is the total amount of data to be transferred within the current
2422          * SCSI command.  We need to record it so that we can properly report
2423          * underflow/underflow.
2424          */
2425         PDU_TOTAL_TRANSFER_LEN(request) = io->scsiio.kern_total_len;
2426
2427         /*
2428          * This is the offset within the current SCSI command; for the first
2429          * call to cfiscsi_datamove() it will be 0, and for subsequent ones
2430          * it will be the sum of lengths of previous ones.
2431          */
2432         buffer_offset = io->scsiio.kern_rel_offset;
2433
2434         /*
2435          * This is the transfer length expected by the initiator.  In theory,
2436          * it could be different from the correct amount of data from the SCSI
2437          * point of view, even if that doesn't make any sense.
2438          */
2439         expected_len = ntohl(bhssc->bhssc_expected_data_transfer_length);
2440 #if 0
2441         if (expected_len != io->scsiio.kern_total_len) {
2442                 CFISCSI_SESSION_DEBUG(cs, "expected transfer length %zd, "
2443                     "actual length %zd", expected_len,
2444                     (size_t)io->scsiio.kern_total_len);
2445         }
2446 #endif
2447
2448         if (buffer_offset >= expected_len) {
2449 #if 0
2450                 CFISCSI_SESSION_DEBUG(cs, "buffer_offset = %zd, "
2451                     "already sent the expected len", buffer_offset);
2452 #endif
2453                 io->scsiio.be_move_done(io);
2454                 return;
2455         }
2456
2457         i = 0;
2458         sg_addr = NULL;
2459         sg_len = 0;
2460         response = NULL;
2461         bhsdi = NULL;
2462         for (;;) {
2463                 if (response == NULL) {
2464                         response = cfiscsi_pdu_new_response(request, M_NOWAIT);
2465                         if (response == NULL) {
2466                                 CFISCSI_SESSION_WARN(cs, "failed to "
2467                                     "allocate memory; dropping connection");
2468                                 ctl_set_busy(&io->scsiio);
2469                                 io->scsiio.be_move_done(io);
2470                                 cfiscsi_session_terminate(cs);
2471                                 return;
2472                         }
2473                         bhsdi = (struct iscsi_bhs_data_in *)response->ip_bhs;
2474                         bhsdi->bhsdi_opcode = ISCSI_BHS_OPCODE_SCSI_DATA_IN;
2475                         bhsdi->bhsdi_initiator_task_tag =
2476                             bhssc->bhssc_initiator_task_tag;
2477                         bhsdi->bhsdi_target_transfer_tag = 0xffffffff;
2478                         bhsdi->bhsdi_datasn = htonl(PDU_EXPDATASN(request));
2479                         PDU_EXPDATASN(request)++;
2480                         bhsdi->bhsdi_buffer_offset = htonl(buffer_offset);
2481                 }
2482
2483                 KASSERT(i < ctl_sg_count, ("i >= ctl_sg_count"));
2484                 if (sg_len == 0) {
2485                         sg_addr = ctl_sglist[i].addr;
2486                         sg_len = ctl_sglist[i].len;
2487                         KASSERT(sg_len > 0, ("sg_len <= 0"));
2488                 }
2489
2490                 len = sg_len;
2491
2492                 /*
2493                  * Truncate to maximum data segment length.
2494                  */
2495                 KASSERT(response->ip_data_len < cs->cs_max_send_data_segment_length,
2496                     ("ip_data_len %zd >= max_send_data_segment_length %d",
2497                     response->ip_data_len, cs->cs_max_send_data_segment_length));
2498                 if (response->ip_data_len + len >
2499                     cs->cs_max_send_data_segment_length) {
2500                         len = cs->cs_max_send_data_segment_length -
2501                             response->ip_data_len;
2502                         KASSERT(len <= sg_len, ("len %zd > sg_len %zd",
2503                             len, sg_len));
2504                 }
2505
2506                 /*
2507                  * Truncate to expected data transfer length.
2508                  */
2509                 KASSERT(buffer_offset + response->ip_data_len < expected_len,
2510                     ("buffer_offset %zd + ip_data_len %zd >= expected_len %zd",
2511                     buffer_offset, response->ip_data_len, expected_len));
2512                 if (buffer_offset + response->ip_data_len + len > expected_len) {
2513                         CFISCSI_SESSION_DEBUG(cs, "truncating from %zd "
2514                             "to expected data transfer length %zd",
2515                             buffer_offset + response->ip_data_len + len, expected_len);
2516                         len = expected_len - (buffer_offset + response->ip_data_len);
2517                         KASSERT(len <= sg_len, ("len %zd > sg_len %zd",
2518                             len, sg_len));
2519                 }
2520
2521                 error = icl_pdu_append_data(response, sg_addr, len, M_NOWAIT);
2522                 if (error != 0) {
2523                         CFISCSI_SESSION_WARN(cs, "failed to "
2524                             "allocate memory; dropping connection");
2525                         icl_pdu_free(response);
2526                         ctl_set_busy(&io->scsiio);
2527                         io->scsiio.be_move_done(io);
2528                         cfiscsi_session_terminate(cs);
2529                         return;
2530                 }
2531                 sg_addr += len;
2532                 sg_len -= len;
2533                 io->scsiio.kern_data_resid -= len;
2534
2535                 KASSERT(buffer_offset + response->ip_data_len <= expected_len,
2536                     ("buffer_offset %zd + ip_data_len %zd > expected_len %zd",
2537                     buffer_offset, response->ip_data_len, expected_len));
2538                 if (buffer_offset + response->ip_data_len == expected_len) {
2539                         /*
2540                          * Already have the amount of data the initiator wanted.
2541                          */
2542                         break;
2543                 }
2544
2545                 if (sg_len == 0) {
2546                         /*
2547                          * End of scatter-gather segment;
2548                          * proceed to the next one...
2549                          */
2550                         if (i == ctl_sg_count - 1) {
2551                                 /*
2552                                  * ... unless this was the last one.
2553                                  */
2554                                 break;
2555                         }
2556                         i++;
2557                 }
2558
2559                 if (response->ip_data_len == cs->cs_max_send_data_segment_length) {
2560                         /*
2561                          * Can't stuff more data into the current PDU;
2562                          * queue it.  Note that's not enough to check
2563                          * for kern_data_resid == 0 instead; there
2564                          * may be several Data-In PDUs for the final
2565                          * call to cfiscsi_datamove(), and we want
2566                          * to set the F flag only on the last of them.
2567                          */
2568                         buffer_offset += response->ip_data_len;
2569                         if (buffer_offset == io->scsiio.kern_total_len ||
2570                             buffer_offset == expected_len) {
2571                                 buffer_offset -= response->ip_data_len;
2572                                 break;
2573                         }
2574                         cfiscsi_pdu_queue(response);
2575                         response = NULL;
2576                         bhsdi = NULL;
2577                 }
2578         }
2579         if (response != NULL) {
2580                 buffer_offset += response->ip_data_len;
2581                 if (buffer_offset == io->scsiio.kern_total_len ||
2582                     buffer_offset == expected_len) {
2583                         bhsdi->bhsdi_flags |= BHSDI_FLAGS_F;
2584                         if (io->io_hdr.status == CTL_SUCCESS) {
2585                                 bhsdi->bhsdi_flags |= BHSDI_FLAGS_S;
2586                                 if (PDU_TOTAL_TRANSFER_LEN(request) <
2587                                     ntohl(bhssc->bhssc_expected_data_transfer_length)) {
2588                                         bhsdi->bhsdi_flags |= BHSSR_FLAGS_RESIDUAL_UNDERFLOW;
2589                                         bhsdi->bhsdi_residual_count =
2590                                             htonl(ntohl(bhssc->bhssc_expected_data_transfer_length) -
2591                                             PDU_TOTAL_TRANSFER_LEN(request));
2592                                 } else if (PDU_TOTAL_TRANSFER_LEN(request) >
2593                                     ntohl(bhssc->bhssc_expected_data_transfer_length)) {
2594                                         bhsdi->bhsdi_flags |= BHSSR_FLAGS_RESIDUAL_OVERFLOW;
2595                                         bhsdi->bhsdi_residual_count =
2596                                             htonl(PDU_TOTAL_TRANSFER_LEN(request) -
2597                                             ntohl(bhssc->bhssc_expected_data_transfer_length));
2598                                 }
2599                                 bhsdi->bhsdi_status = io->scsiio.scsi_status;
2600                                 io->io_hdr.flags |= CTL_FLAG_STATUS_SENT;
2601                         }
2602                 }
2603                 KASSERT(response->ip_data_len > 0, ("sending empty Data-In"));
2604                 cfiscsi_pdu_queue(response);
2605         }
2606
2607         io->scsiio.be_move_done(io);
2608 }
2609
2610 static void
2611 cfiscsi_datamove_out(union ctl_io *io)
2612 {
2613         struct cfiscsi_session *cs;
2614         struct icl_pdu *request, *response;
2615         const struct iscsi_bhs_scsi_command *bhssc;
2616         struct iscsi_bhs_r2t *bhsr2t;
2617         struct cfiscsi_data_wait *cdw;
2618         struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
2619         uint32_t expected_len, datamove_len, r2t_off, r2t_len;
2620         uint32_t target_transfer_tag;
2621         bool done;
2622
2623         request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2624         cs = PDU_SESSION(request);
2625
2626         bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs;
2627         KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
2628             ISCSI_BHS_OPCODE_SCSI_COMMAND,
2629             ("bhssc->bhssc_opcode != ISCSI_BHS_OPCODE_SCSI_COMMAND"));
2630
2631         /*
2632          * We need to record it so that we can properly report
2633          * underflow/underflow.
2634          */
2635         PDU_TOTAL_TRANSFER_LEN(request) = io->scsiio.kern_total_len;
2636
2637         /*
2638          * Complete write underflow.  Not a single byte to read.  Return.
2639          */
2640         expected_len = ntohl(bhssc->bhssc_expected_data_transfer_length);
2641         if (io->scsiio.kern_rel_offset >= expected_len) {
2642                 io->scsiio.be_move_done(io);
2643                 return;
2644         }
2645         datamove_len = MIN(io->scsiio.kern_data_len,
2646             expected_len - io->scsiio.kern_rel_offset);
2647
2648         target_transfer_tag =
2649             atomic_fetchadd_32(&cs->cs_target_transfer_tag, 1);
2650         cdw = cfiscsi_data_wait_new(cs, io, bhssc->bhssc_initiator_task_tag,
2651             &target_transfer_tag);
2652         if (cdw == NULL) {
2653                 CFISCSI_SESSION_WARN(cs, "failed to "
2654                     "allocate memory; dropping connection");
2655                 ctl_set_busy(&io->scsiio);
2656                 io->scsiio.be_move_done(io);
2657                 cfiscsi_session_terminate(cs);
2658                 return;
2659         }
2660 #if 0
2661         CFISCSI_SESSION_DEBUG(cs, "expecting Data-Out with initiator "
2662             "task tag 0x%x, target transfer tag 0x%x",
2663             bhssc->bhssc_initiator_task_tag, target_transfer_tag);
2664 #endif
2665
2666         cdw->cdw_ctl_io = io;
2667         cdw->cdw_target_transfer_tag = target_transfer_tag;
2668         cdw->cdw_initiator_task_tag = bhssc->bhssc_initiator_task_tag;
2669         cdw->cdw_r2t_end = datamove_len;
2670         cdw->cdw_datasn = 0;
2671
2672         /* Set initial data pointer for the CDW respecting ext_data_filled. */
2673         if (io->scsiio.kern_sg_entries > 0) {
2674                 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
2675         } else {
2676                 ctl_sglist = &ctl_sg_entry;
2677                 ctl_sglist->addr = io->scsiio.kern_data_ptr;
2678                 ctl_sglist->len = datamove_len;
2679         }
2680         cdw->cdw_sg_index = 0;
2681         cdw->cdw_sg_addr = ctl_sglist[cdw->cdw_sg_index].addr;
2682         cdw->cdw_sg_len = ctl_sglist[cdw->cdw_sg_index].len;
2683         r2t_off = io->scsiio.ext_data_filled;
2684         while (r2t_off > 0) {
2685                 if (r2t_off >= cdw->cdw_sg_len) {
2686                         r2t_off -= cdw->cdw_sg_len;
2687                         cdw->cdw_sg_index++;
2688                         cdw->cdw_sg_addr = ctl_sglist[cdw->cdw_sg_index].addr;
2689                         cdw->cdw_sg_len = ctl_sglist[cdw->cdw_sg_index].len;
2690                         continue;
2691                 }
2692                 cdw->cdw_sg_addr += r2t_off;
2693                 cdw->cdw_sg_len -= r2t_off;
2694                 r2t_off = 0;
2695         }
2696
2697         if (cs->cs_immediate_data &&
2698             io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled <
2699             icl_pdu_data_segment_length(request)) {
2700                 done = cfiscsi_handle_data_segment(request, cdw);
2701                 if (done) {
2702                         cfiscsi_data_wait_free(cs, cdw);
2703                         io->scsiio.be_move_done(io);
2704                         return;
2705                 }
2706         }
2707
2708         r2t_off = io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled;
2709         r2t_len = MIN(datamove_len - io->scsiio.ext_data_filled,
2710             cs->cs_max_burst_length);
2711         cdw->cdw_r2t_end = io->scsiio.ext_data_filled + r2t_len;
2712
2713         CFISCSI_SESSION_LOCK(cs);
2714         TAILQ_INSERT_TAIL(&cs->cs_waiting_for_data_out, cdw, cdw_next);
2715         CFISCSI_SESSION_UNLOCK(cs);
2716
2717         /*
2718          * XXX: We should limit the number of outstanding R2T PDUs
2719          *      per task to MaxOutstandingR2T.
2720          */
2721         response = cfiscsi_pdu_new_response(request, M_NOWAIT);
2722         if (response == NULL) {
2723                 CFISCSI_SESSION_WARN(cs, "failed to "
2724                     "allocate memory; dropping connection");
2725                 ctl_set_busy(&io->scsiio);
2726                 io->scsiio.be_move_done(io);
2727                 cfiscsi_session_terminate(cs);
2728                 return;
2729         }
2730         io->io_hdr.flags |= CTL_FLAG_DMA_INPROG;
2731         bhsr2t = (struct iscsi_bhs_r2t *)response->ip_bhs;
2732         bhsr2t->bhsr2t_opcode = ISCSI_BHS_OPCODE_R2T;
2733         bhsr2t->bhsr2t_flags = 0x80;
2734         bhsr2t->bhsr2t_lun = bhssc->bhssc_lun;
2735         bhsr2t->bhsr2t_initiator_task_tag = bhssc->bhssc_initiator_task_tag;
2736         bhsr2t->bhsr2t_target_transfer_tag = target_transfer_tag;
2737         /*
2738          * XXX: Here we assume that cfiscsi_datamove() won't ever
2739          *      be running concurrently on several CPUs for a given
2740          *      command.
2741          */
2742         bhsr2t->bhsr2t_r2tsn = htonl(PDU_R2TSN(request));
2743         PDU_R2TSN(request)++;
2744         /*
2745          * This is the offset within the current SCSI command;
2746          * i.e. for the first call of datamove(), it will be 0,
2747          * and for subsequent ones it will be the sum of lengths
2748          * of previous ones.
2749          *
2750          * The ext_data_filled is to account for unsolicited
2751          * (immediate) data that might have already arrived.
2752          */
2753         bhsr2t->bhsr2t_buffer_offset = htonl(r2t_off);
2754         /*
2755          * This is the total length (sum of S/G lengths) this call
2756          * to cfiscsi_datamove() is supposed to handle, limited by
2757          * MaxBurstLength.
2758          */
2759         bhsr2t->bhsr2t_desired_data_transfer_length = htonl(r2t_len);
2760         cfiscsi_pdu_queue(response);
2761 }
2762
2763 static void
2764 cfiscsi_datamove(union ctl_io *io)
2765 {
2766
2767         if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN)
2768                 cfiscsi_datamove_in(io);
2769         else {
2770                 /* We hadn't received anything during this datamove yet. */
2771                 io->scsiio.ext_data_filled = 0;
2772                 cfiscsi_datamove_out(io);
2773         }
2774 }
2775
2776 static void
2777 cfiscsi_scsi_command_done(union ctl_io *io)
2778 {
2779         struct icl_pdu *request, *response;
2780         struct iscsi_bhs_scsi_command *bhssc;
2781         struct iscsi_bhs_scsi_response *bhssr;
2782 #ifdef DIAGNOSTIC
2783         struct cfiscsi_data_wait *cdw;
2784 #endif
2785         struct cfiscsi_session *cs;
2786         uint16_t sense_length;
2787
2788         request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2789         cs = PDU_SESSION(request);
2790         bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs;
2791         KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
2792             ISCSI_BHS_OPCODE_SCSI_COMMAND,
2793             ("replying to wrong opcode 0x%x", bhssc->bhssc_opcode));
2794
2795         //CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x",
2796         //    bhssc->bhssc_initiator_task_tag);
2797
2798 #ifdef DIAGNOSTIC
2799         CFISCSI_SESSION_LOCK(cs);
2800         TAILQ_FOREACH(cdw, &cs->cs_waiting_for_data_out, cdw_next)
2801                 KASSERT(bhssc->bhssc_initiator_task_tag !=
2802                     cdw->cdw_initiator_task_tag, ("dangling cdw"));
2803         CFISCSI_SESSION_UNLOCK(cs);
2804 #endif
2805
2806         /*
2807          * Do not return status for aborted commands.
2808          * There are exceptions, but none supported by CTL yet.
2809          */
2810         if (((io->io_hdr.flags & CTL_FLAG_ABORT) &&
2811              (io->io_hdr.flags & CTL_FLAG_ABORT_STATUS) == 0) ||
2812             (io->io_hdr.flags & CTL_FLAG_STATUS_SENT)) {
2813                 ctl_free_io(io);
2814                 icl_pdu_free(request);
2815                 return;
2816         }
2817
2818         response = cfiscsi_pdu_new_response(request, M_WAITOK);
2819         bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs;
2820         bhssr->bhssr_opcode = ISCSI_BHS_OPCODE_SCSI_RESPONSE;
2821         bhssr->bhssr_flags = 0x80;
2822         /*
2823          * XXX: We don't deal with bidirectional under/overflows;
2824          *      does anything actually support those?
2825          */
2826         if (PDU_TOTAL_TRANSFER_LEN(request) <
2827             ntohl(bhssc->bhssc_expected_data_transfer_length)) {
2828                 bhssr->bhssr_flags |= BHSSR_FLAGS_RESIDUAL_UNDERFLOW;
2829                 bhssr->bhssr_residual_count =
2830                     htonl(ntohl(bhssc->bhssc_expected_data_transfer_length) -
2831                     PDU_TOTAL_TRANSFER_LEN(request));
2832                 //CFISCSI_SESSION_DEBUG(cs, "underflow; residual count %d",
2833                 //    ntohl(bhssr->bhssr_residual_count));
2834         } else if (PDU_TOTAL_TRANSFER_LEN(request) > 
2835             ntohl(bhssc->bhssc_expected_data_transfer_length)) {
2836                 bhssr->bhssr_flags |= BHSSR_FLAGS_RESIDUAL_OVERFLOW;
2837                 bhssr->bhssr_residual_count =
2838                     htonl(PDU_TOTAL_TRANSFER_LEN(request) -
2839                     ntohl(bhssc->bhssc_expected_data_transfer_length));
2840                 //CFISCSI_SESSION_DEBUG(cs, "overflow; residual count %d",
2841                 //    ntohl(bhssr->bhssr_residual_count));
2842         }
2843         bhssr->bhssr_response = BHSSR_RESPONSE_COMMAND_COMPLETED;
2844         bhssr->bhssr_status = io->scsiio.scsi_status;
2845         bhssr->bhssr_initiator_task_tag = bhssc->bhssc_initiator_task_tag;
2846         bhssr->bhssr_expdatasn = htonl(PDU_EXPDATASN(request));
2847
2848         if (io->scsiio.sense_len > 0) {
2849 #if 0
2850                 CFISCSI_SESSION_DEBUG(cs, "returning %d bytes of sense data",
2851                     io->scsiio.sense_len);
2852 #endif
2853                 sense_length = htons(io->scsiio.sense_len);
2854                 icl_pdu_append_data(response,
2855                     &sense_length, sizeof(sense_length), M_WAITOK);
2856                 icl_pdu_append_data(response,
2857                     &io->scsiio.sense_data, io->scsiio.sense_len, M_WAITOK);
2858         }
2859
2860         ctl_free_io(io);
2861         icl_pdu_free(request);
2862         cfiscsi_pdu_queue(response);
2863 }
2864
2865 static void
2866 cfiscsi_task_management_done(union ctl_io *io)
2867 {
2868         struct icl_pdu *request, *response;
2869         struct iscsi_bhs_task_management_request *bhstmr;
2870         struct iscsi_bhs_task_management_response *bhstmr2;
2871         struct cfiscsi_data_wait *cdw, *tmpcdw;
2872         struct cfiscsi_session *cs, *tcs;
2873         struct cfiscsi_softc *softc;
2874         int cold_reset = 0;
2875
2876         request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2877         cs = PDU_SESSION(request);
2878         bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs;
2879         KASSERT((bhstmr->bhstmr_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
2880             ISCSI_BHS_OPCODE_TASK_REQUEST,
2881             ("replying to wrong opcode 0x%x", bhstmr->bhstmr_opcode));
2882
2883 #if 0
2884         CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x; referenced task tag 0x%x",
2885             bhstmr->bhstmr_initiator_task_tag,
2886             bhstmr->bhstmr_referenced_task_tag);
2887 #endif
2888
2889         if ((bhstmr->bhstmr_function & ~0x80) ==
2890             BHSTMR_FUNCTION_ABORT_TASK) {
2891                 /*
2892                  * Make sure we no longer wait for Data-Out for this command.
2893                  */
2894                 CFISCSI_SESSION_LOCK(cs);
2895                 TAILQ_FOREACH_SAFE(cdw,
2896                     &cs->cs_waiting_for_data_out, cdw_next, tmpcdw) {
2897                         if (bhstmr->bhstmr_referenced_task_tag !=
2898                             cdw->cdw_initiator_task_tag)
2899                                 continue;
2900
2901 #if 0
2902                         CFISCSI_SESSION_DEBUG(cs, "removing csw for initiator task "
2903                             "tag 0x%x", bhstmr->bhstmr_initiator_task_tag);
2904 #endif
2905                         TAILQ_REMOVE(&cs->cs_waiting_for_data_out,
2906                             cdw, cdw_next);
2907                         io->io_hdr.flags &= ~CTL_FLAG_DMA_INPROG;
2908                         cdw->cdw_ctl_io->scsiio.io_hdr.port_status = 43;
2909                         cdw->cdw_ctl_io->scsiio.be_move_done(cdw->cdw_ctl_io);
2910                         cfiscsi_data_wait_free(cs, cdw);
2911                 }
2912                 CFISCSI_SESSION_UNLOCK(cs);
2913         }
2914         if ((bhstmr->bhstmr_function & ~0x80) ==
2915             BHSTMR_FUNCTION_TARGET_COLD_RESET &&
2916             io->io_hdr.status == CTL_SUCCESS)
2917                 cold_reset = 1;
2918
2919         response = cfiscsi_pdu_new_response(request, M_WAITOK);
2920         bhstmr2 = (struct iscsi_bhs_task_management_response *)
2921             response->ip_bhs;
2922         bhstmr2->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_RESPONSE;
2923         bhstmr2->bhstmr_flags = 0x80;
2924         switch (io->taskio.task_status) {
2925         case CTL_TASK_FUNCTION_COMPLETE:
2926                 bhstmr2->bhstmr_response = BHSTMR_RESPONSE_FUNCTION_COMPLETE;
2927                 break;
2928         case CTL_TASK_FUNCTION_SUCCEEDED:
2929                 bhstmr2->bhstmr_response = BHSTMR_RESPONSE_FUNCTION_SUCCEEDED;
2930                 break;
2931         case CTL_TASK_LUN_DOES_NOT_EXIST:
2932                 bhstmr2->bhstmr_response = BHSTMR_RESPONSE_LUN_DOES_NOT_EXIST;
2933                 break;
2934         case CTL_TASK_FUNCTION_NOT_SUPPORTED:
2935         default:
2936                 bhstmr2->bhstmr_response = BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED;
2937                 break;
2938         }
2939         memcpy(bhstmr2->bhstmr_additional_reponse_information,
2940             io->taskio.task_resp, sizeof(io->taskio.task_resp));
2941         bhstmr2->bhstmr_initiator_task_tag = bhstmr->bhstmr_initiator_task_tag;
2942
2943         ctl_free_io(io);
2944         icl_pdu_free(request);
2945         cfiscsi_pdu_queue(response);
2946
2947         if (cold_reset) {
2948                 softc = cs->cs_target->ct_softc;
2949                 mtx_lock(&softc->lock);
2950                 TAILQ_FOREACH(tcs, &softc->sessions, cs_next) {
2951                         if (tcs->cs_target == cs->cs_target)
2952                                 cfiscsi_session_terminate(tcs);
2953                 }
2954                 mtx_unlock(&softc->lock);
2955         }
2956 }
2957
2958 static void
2959 cfiscsi_done(union ctl_io *io)
2960 {
2961         struct icl_pdu *request;
2962         struct cfiscsi_session *cs;
2963
2964         KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE),
2965                 ("invalid CTL status %#x", io->io_hdr.status));
2966
2967         if (io->io_hdr.io_type == CTL_IO_TASK &&
2968             io->taskio.task_action == CTL_TASK_I_T_NEXUS_RESET) {
2969                 /*
2970                  * Implicit task termination has just completed; nothing to do.
2971                  */
2972                 cs = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2973                 cs->cs_tasks_aborted = true;
2974                 refcount_release(&cs->cs_outstanding_ctl_pdus);
2975                 wakeup(__DEVOLATILE(void *, &cs->cs_outstanding_ctl_pdus));
2976                 ctl_free_io(io);
2977                 return;
2978         }
2979
2980         request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2981         cs = PDU_SESSION(request);
2982
2983         switch (request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) {
2984         case ISCSI_BHS_OPCODE_SCSI_COMMAND:
2985                 cfiscsi_scsi_command_done(io);
2986                 break;
2987         case ISCSI_BHS_OPCODE_TASK_REQUEST:
2988                 cfiscsi_task_management_done(io);
2989                 break;
2990         default:
2991                 panic("cfiscsi_done called with wrong opcode 0x%x",
2992                     request->ip_bhs->bhs_opcode);
2993         }
2994
2995         refcount_release(&cs->cs_outstanding_ctl_pdus);
2996 }