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