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