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