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