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