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