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