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