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