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