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