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