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