2 * Copyright (c) 2012 The FreeBSD Foundation
5 * This software was developed by Edward Tomasz Napierala under sponsorship
6 * from the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
33 * CTL frontend for the iSCSI protocol.
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
39 #include <sys/param.h>
40 #include <sys/capability.h>
41 #include <sys/condvar.h>
43 #include <sys/kernel.h>
44 #include <sys/kthread.h>
46 #include <sys/malloc.h>
47 #include <sys/module.h>
48 #include <sys/mutex.h>
49 #include <sys/queue.h>
51 #include <sys/sysctl.h>
52 #include <sys/systm.h>
54 #include <sys/unistd.h>
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>
70 #include "../../dev/iscsi/icl.h"
71 #include "../../dev/iscsi/iscsi_proto.h"
72 #include "ctl_frontend_iscsi.h"
74 #ifdef ICL_KERNEL_PROXY
75 #include <sys/socketvar.h>
78 #ifdef ICL_KERNEL_PROXY
79 FEATURE(cfiscsi_kernel_proxy, "iSCSI target built with ICL_KERNEL_PROXY");
82 static MALLOC_DEFINE(M_CFISCSI, "cfiscsi", "Memory used for CTL iSCSI frontend");
83 static uma_zone_t cfiscsi_data_wait_zone;
85 SYSCTL_NODE(_kern_cam_ctl, OID_AUTO, iscsi, CTLFLAG_RD, 0,
86 "CAM Target Layer iSCSI Frontend");
88 TUNABLE_INT("kern.cam.ctl.iscsi.debug", &debug);
89 SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, debug, CTLFLAG_RWTUN,
90 &debug, 1, "Enable debug messages");
91 static int ping_timeout = 5;
92 TUNABLE_INT("kern.cam.ctl.iscsi.ping_timeout", &ping_timeout);
93 SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, ping_timeout, CTLFLAG_RWTUN,
94 &ping_timeout, 5, "Interval between ping (NOP-Out) requests, in seconds");
95 static int login_timeout = 60;
96 TUNABLE_INT("kern.cam.ctl.iscsi.login_timeout", &login_timeout);
97 SYSCTL_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");
99 static int maxcmdsn_delta = 256;
100 TUNABLE_INT("kern.cam.ctl.iscsi.maxcmdsn_delta", &maxcmdsn_delta);
101 SYSCTL_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");
105 #define CFISCSI_DEBUG(X, ...) \
108 printf("%s: " X "\n", \
109 __func__, ## __VA_ARGS__); \
113 #define CFISCSI_WARN(X, ...) \
116 printf("WARNING: %s: " X "\n", \
117 __func__, ## __VA_ARGS__); \
121 #define CFISCSI_SESSION_DEBUG(S, X, ...) \
124 printf("%s: %s (%s): " X "\n", \
125 __func__, S->cs_initiator_addr, \
126 S->cs_initiator_name, ## __VA_ARGS__); \
130 #define CFISCSI_SESSION_WARN(S, X, ...) \
133 printf("WARNING: %s (%s): " X "\n", \
134 S->cs_initiator_addr, \
135 S->cs_initiator_name, ## __VA_ARGS__); \
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)
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
149 int cfiscsi_init(void);
150 static void cfiscsi_online(void *arg);
151 static void cfiscsi_offline(void *arg);
152 static int cfiscsi_lun_enable(void *arg,
153 struct ctl_id target_id, int lun_id);
154 static int cfiscsi_lun_disable(void *arg,
155 struct ctl_id target_id, int lun_id);
156 static int cfiscsi_ioctl(struct cdev *dev,
157 u_long cmd, caddr_t addr, int flag, struct thread *td);
158 static int cfiscsi_devid(struct ctl_scsiio *ctsio, int alloc_len);
159 static void cfiscsi_datamove(union ctl_io *io);
160 static void cfiscsi_done(union ctl_io *io);
161 static uint32_t cfiscsi_map_lun(void *arg, uint32_t lun);
162 static bool cfiscsi_pdu_update_cmdsn(const struct icl_pdu *request);
163 static void cfiscsi_pdu_handle_nop_out(struct icl_pdu *request);
164 static void cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request);
165 static void cfiscsi_pdu_handle_task_request(struct icl_pdu *request);
166 static void cfiscsi_pdu_handle_data_out(struct icl_pdu *request);
167 static void cfiscsi_pdu_handle_logout_request(struct icl_pdu *request);
168 static void cfiscsi_session_terminate(struct cfiscsi_session *cs);
169 static struct cfiscsi_target *cfiscsi_target_find(struct cfiscsi_softc
170 *softc, const char *name);
171 static struct cfiscsi_target *cfiscsi_target_find_or_create(
172 struct cfiscsi_softc *softc, const char *name, const char *alias);
173 static void cfiscsi_target_release(struct cfiscsi_target *ct);
174 static void cfiscsi_session_delete(struct cfiscsi_session *cs);
176 static struct cfiscsi_softc cfiscsi_softc;
177 extern struct ctl_softc *control_softc;
179 static struct ctl_frontend cfiscsi_frontend =
182 .init = cfiscsi_init,
183 .ioctl = cfiscsi_ioctl,
185 CTL_FRONTEND_DECLARE(ctlcfiscsi, cfiscsi_frontend);
187 static struct icl_pdu *
188 cfiscsi_pdu_new_response(struct icl_pdu *request, int flags)
191 return (icl_pdu_new_bhs(request->ip_conn, flags));
195 cfiscsi_pdu_update_cmdsn(const struct icl_pdu *request)
197 const struct iscsi_bhs_scsi_command *bhssc;
198 struct cfiscsi_session *cs;
199 uint32_t cmdsn, expstatsn;
201 cs = PDU_SESSION(request);
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
214 * Data-Out PDUs don't contain CmdSN.
216 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
217 ISCSI_BHS_OPCODE_SCSI_DATA_OUT)
221 * We're only using fields common for all the request
222 * (initiator -> target) PDUs.
224 bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs;
225 cmdsn = ntohl(bhssc->bhssc_cmdsn);
226 expstatsn = ntohl(bhssc->bhssc_expstatsn);
228 CFISCSI_SESSION_LOCK(cs);
230 if (expstatsn != cs->cs_statsn) {
231 CFISCSI_SESSION_DEBUG(cs, "received PDU with ExpStatSN %d, "
232 "while current StatSN is %d", expstatsn,
238 * The target MUST silently ignore any non-immediate command outside
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);
248 if ((request->ip_bhs->bhs_opcode & ISCSI_BHS_OPCODE_IMMEDIATE) == 0)
251 CFISCSI_SESSION_UNLOCK(cs);
257 cfiscsi_pdu_handle(struct icl_pdu *request)
259 struct cfiscsi_session *cs;
262 cs = PDU_SESSION(request);
264 ignore = cfiscsi_pdu_update_cmdsn(request);
266 icl_pdu_free(request);
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.
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);
281 case ISCSI_BHS_OPCODE_SCSI_COMMAND:
282 cfiscsi_pdu_handle_scsi_command(request);
284 case ISCSI_BHS_OPCODE_TASK_REQUEST:
285 cfiscsi_pdu_handle_task_request(request);
287 case ISCSI_BHS_OPCODE_SCSI_DATA_OUT:
288 cfiscsi_pdu_handle_data_out(request);
290 case ISCSI_BHS_OPCODE_LOGOUT_REQUEST:
291 cfiscsi_pdu_handle_logout_request(request);
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);
304 cfiscsi_receive_callback(struct icl_pdu *request)
306 struct cfiscsi_session *cs;
308 cs = PDU_SESSION(request);
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;
315 icl_pdu_free(request);
316 cv_signal(&cs->cs_login_cv);
321 cfiscsi_pdu_handle(request);
325 cfiscsi_error_callback(struct icl_conn *ic)
327 struct cfiscsi_session *cs;
329 cs = CONN_SESSION(ic);
331 CFISCSI_SESSION_WARN(cs, "connection error; dropping connection");
332 cfiscsi_session_terminate(cs);
336 cfiscsi_pdu_prepare(struct icl_pdu *response)
338 struct cfiscsi_session *cs;
339 struct iscsi_bhs_scsi_response *bhssr;
340 bool advance_statsn = true;
342 cs = PDU_SESSION(response);
344 CFISCSI_SESSION_LOCK_ASSERT(cs);
347 * We're only using fields common for all the response
348 * (target -> initiator) PDUs.
350 bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs;
353 * 10.8.3: "The StatSN for this connection is not advanced
354 * after this PDU is sent."
356 if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_R2T)
357 advance_statsn = false;
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."
363 if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_NOP_IN &&
364 bhssr->bhssr_initiator_task_tag == 0xffffffff)
365 advance_statsn = false;
368 * See the comment below - StatSN is not meaningful and must
371 if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_SCSI_DATA_IN)
372 advance_statsn = false;
375 * 10.7.3: "The fields StatSN, Status, and Residual Count
376 * only have meaningful content if the S bit is set to 1."
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);
390 cfiscsi_pdu_queue(struct icl_pdu *response)
392 struct cfiscsi_session *cs;
394 cs = PDU_SESSION(response);
396 CFISCSI_SESSION_LOCK(cs);
397 cfiscsi_pdu_prepare(response);
398 icl_pdu_queue(response);
399 CFISCSI_SESSION_UNLOCK(cs);
403 cfiscsi_decode_lun(uint64_t encoded)
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.
413 memcpy(lun, &encoded, sizeof(lun));
414 switch (lun[0] & 0xC0) {
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",
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",
435 result = ((lun[0] & 0x3f) << 8) + lun[1];
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",
446 result = (lun[1] << 16) + (lun[2] << 8) + lun[3];
448 CFISCSI_WARN("unsupported LUN format 0x%jx",
458 cfiscsi_pdu_handle_nop_out(struct icl_pdu *request)
460 struct cfiscsi_session *cs;
461 struct iscsi_bhs_nop_out *bhsno;
462 struct iscsi_bhs_nop_in *bhsni;
463 struct icl_pdu *response;
468 cs = PDU_SESSION(request);
469 bhsno = (struct iscsi_bhs_nop_out *)request->ip_bhs;
471 if (bhsno->bhsno_initiator_task_tag == 0xffffffff) {
473 * Nothing to do, iscsi_pdu_update_statsn() already
474 * zeroed the timeout.
476 icl_pdu_free(request);
480 datasize = icl_pdu_data_segment_length(request);
482 data = malloc(datasize, M_CFISCSI, M_NOWAIT | M_ZERO);
484 CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
485 "dropping connection");
486 icl_pdu_free(request);
487 cfiscsi_session_terminate(cs);
490 icl_pdu_get_data(request, 0, data, datasize);
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);
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;
508 error = icl_pdu_append_data(response, data, datasize, M_NOWAIT);
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);
518 free(data, M_CFISCSI);
521 icl_pdu_free(request);
522 cfiscsi_pdu_queue(response);
526 cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request)
528 struct iscsi_bhs_scsi_command *bhssc;
529 struct cfiscsi_session *cs;
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);
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);
545 io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
547 CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io; "
548 "dropping connection");
549 icl_pdu_free(request);
550 cfiscsi_session_terminate(cs);
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->io_hdr.nexus.lun_map_fn = cfiscsi_map_lun;
561 io->io_hdr.nexus.lun_map_arg = cs;
562 io->scsiio.tag_num = bhssc->bhssc_initiator_task_tag;
563 switch ((bhssc->bhssc_flags & BHSSC_FLAGS_ATTR)) {
564 case BHSSC_FLAGS_ATTR_UNTAGGED:
565 io->scsiio.tag_type = CTL_TAG_UNTAGGED;
567 case BHSSC_FLAGS_ATTR_SIMPLE:
568 io->scsiio.tag_type = CTL_TAG_SIMPLE;
570 case BHSSC_FLAGS_ATTR_ORDERED:
571 io->scsiio.tag_type = CTL_TAG_ORDERED;
573 case BHSSC_FLAGS_ATTR_HOQ:
574 io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
576 case BHSSC_FLAGS_ATTR_ACA:
577 io->scsiio.tag_type = CTL_TAG_ACA;
580 io->scsiio.tag_type = CTL_TAG_UNTAGGED;
581 CFISCSI_SESSION_WARN(cs, "unhandled tag type %d",
582 bhssc->bhssc_flags & BHSSC_FLAGS_ATTR);
585 io->scsiio.cdb_len = sizeof(bhssc->bhssc_cdb); /* Which is 16. */
586 memcpy(io->scsiio.cdb, bhssc->bhssc_cdb, sizeof(bhssc->bhssc_cdb));
587 refcount_acquire(&cs->cs_outstanding_ctl_pdus);
588 error = ctl_queue(io);
589 if (error != CTL_RETVAL_COMPLETE) {
590 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d; "
591 "dropping connection", error);
593 refcount_release(&cs->cs_outstanding_ctl_pdus);
594 icl_pdu_free(request);
595 cfiscsi_session_terminate(cs);
600 cfiscsi_pdu_handle_task_request(struct icl_pdu *request)
602 struct iscsi_bhs_task_management_request *bhstmr;
603 struct iscsi_bhs_task_management_response *bhstmr2;
604 struct icl_pdu *response;
605 struct cfiscsi_session *cs;
609 cs = PDU_SESSION(request);
610 bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs;
611 io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
613 CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io;"
614 "dropping connection");
615 icl_pdu_free(request);
616 cfiscsi_session_terminate(cs);
620 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = request;
621 io->io_hdr.io_type = CTL_IO_TASK;
622 io->io_hdr.nexus.initid.id = cs->cs_ctl_initid;
623 io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
624 io->io_hdr.nexus.targ_target.id = 0;
625 io->io_hdr.nexus.targ_lun = cfiscsi_decode_lun(bhstmr->bhstmr_lun);
626 io->io_hdr.nexus.lun_map_fn = cfiscsi_map_lun;
627 io->io_hdr.nexus.lun_map_arg = cs;
628 io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */
630 switch (bhstmr->bhstmr_function & ~0x80) {
631 case BHSTMR_FUNCTION_ABORT_TASK:
633 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_ABORT_TASK");
635 io->taskio.task_action = CTL_TASK_ABORT_TASK;
636 io->taskio.tag_num = bhstmr->bhstmr_referenced_task_tag;
638 case BHSTMR_FUNCTION_LOGICAL_UNIT_RESET:
640 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_LOGICAL_UNIT_RESET");
642 io->taskio.task_action = CTL_TASK_LUN_RESET;
644 case BHSTMR_FUNCTION_TARGET_WARM_RESET:
646 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_TARGET_WARM_RESET");
648 io->taskio.task_action = CTL_TASK_TARGET_RESET;
651 CFISCSI_SESSION_DEBUG(cs, "unsupported function 0x%x",
652 bhstmr->bhstmr_function & ~0x80);
655 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
656 if (response == NULL) {
657 CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
658 "dropping connection");
659 icl_pdu_free(request);
660 cfiscsi_session_terminate(cs);
663 bhstmr2 = (struct iscsi_bhs_task_management_response *)
665 bhstmr2->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_RESPONSE;
666 bhstmr2->bhstmr_flags = 0x80;
667 bhstmr2->bhstmr_response =
668 BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED;
669 bhstmr2->bhstmr_initiator_task_tag =
670 bhstmr->bhstmr_initiator_task_tag;
671 icl_pdu_free(request);
672 cfiscsi_pdu_queue(response);
676 refcount_acquire(&cs->cs_outstanding_ctl_pdus);
677 error = ctl_queue(io);
678 if (error != CTL_RETVAL_COMPLETE) {
679 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d; "
680 "dropping connection", error);
682 refcount_release(&cs->cs_outstanding_ctl_pdus);
683 icl_pdu_free(request);
684 cfiscsi_session_terminate(cs);
689 cfiscsi_handle_data_segment(struct icl_pdu *request, struct cfiscsi_data_wait *cdw)
691 struct iscsi_bhs_data_out *bhsdo;
692 struct cfiscsi_session *cs;
693 struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
694 size_t copy_len, len, off, buffer_offset;
698 cs = PDU_SESSION(request);
700 KASSERT((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
701 ISCSI_BHS_OPCODE_SCSI_DATA_OUT ||
702 (request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
703 ISCSI_BHS_OPCODE_SCSI_COMMAND,
704 ("bad opcode 0x%x", request->ip_bhs->bhs_opcode));
707 * We're only using fields common for Data-Out and SCSI Command PDUs.
709 bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs;
711 io = cdw->cdw_ctl_io;
712 KASSERT((io->io_hdr.flags & CTL_FLAG_DATA_MASK) != CTL_FLAG_DATA_IN,
713 ("CTL_FLAG_DATA_IN"));
716 CFISCSI_SESSION_DEBUG(cs, "received %zd bytes out of %d",
717 request->ip_data_len, io->scsiio.kern_total_len);
720 if (io->scsiio.kern_sg_entries > 0) {
721 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
722 ctl_sg_count = io->scsiio.kern_sg_entries;
724 ctl_sglist = &ctl_sg_entry;
725 ctl_sglist->addr = io->scsiio.kern_data_ptr;
726 ctl_sglist->len = io->scsiio.kern_data_len;
730 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
731 ISCSI_BHS_OPCODE_SCSI_DATA_OUT)
732 buffer_offset = ntohl(bhsdo->bhsdo_buffer_offset);
735 len = icl_pdu_data_segment_length(request);
738 * Make sure the offset, as sent by the initiator, matches the offset
739 * we're supposed to be at in the scatter-gather list.
742 io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled ||
743 buffer_offset + len <=
744 io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled) {
745 CFISCSI_SESSION_WARN(cs, "received bad buffer offset %zd, "
746 "expected %zd; dropping connection", buffer_offset,
747 (size_t)io->scsiio.kern_rel_offset +
748 (size_t)io->scsiio.ext_data_filled);
749 ctl_set_data_phase_error(&io->scsiio);
750 cfiscsi_session_terminate(cs);
755 * This is the offset within the PDU data segment, as opposed
756 * to buffer_offset, which is the offset within the task (SCSI
759 off = io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled -
763 * Iterate over the scatter/gather segments, filling them with data
764 * from the PDU data segment. Note that this can get called multiple
765 * times for one SCSI command; the cdw structure holds state for the
766 * scatter/gather list.
769 KASSERT(cdw->cdw_sg_index < ctl_sg_count,
770 ("cdw->cdw_sg_index >= ctl_sg_count"));
771 if (cdw->cdw_sg_len == 0) {
772 cdw->cdw_sg_addr = ctl_sglist[cdw->cdw_sg_index].addr;
773 cdw->cdw_sg_len = ctl_sglist[cdw->cdw_sg_index].len;
775 KASSERT(off <= len, ("len > off"));
776 copy_len = len - off;
777 if (copy_len > cdw->cdw_sg_len)
778 copy_len = cdw->cdw_sg_len;
780 icl_pdu_get_data(request, off, cdw->cdw_sg_addr, copy_len);
781 cdw->cdw_sg_addr += copy_len;
782 cdw->cdw_sg_len -= copy_len;
784 io->scsiio.ext_data_filled += copy_len;
786 if (cdw->cdw_sg_len == 0) {
788 * End of current segment.
790 if (cdw->cdw_sg_index == ctl_sg_count - 1) {
792 * Last segment in scatter/gather list.
801 * End of PDU payload.
809 * In case of unsolicited data, it's possible that the buffer
810 * provided by CTL is smaller than negotiated FirstBurstLength.
811 * Just ignore the superfluous data; will ask for them with R2T
812 * on next call to cfiscsi_datamove().
814 * This obviously can only happen with SCSI Command PDU.
816 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
817 ISCSI_BHS_OPCODE_SCSI_COMMAND)
820 CFISCSI_SESSION_WARN(cs, "received too much data: got %zd bytes, "
821 "expected %zd; dropping connection",
822 icl_pdu_data_segment_length(request), off);
823 ctl_set_data_phase_error(&io->scsiio);
824 cfiscsi_session_terminate(cs);
828 if (io->scsiio.ext_data_filled == io->scsiio.kern_data_len &&
829 (bhsdo->bhsdo_flags & BHSDO_FLAGS_F) == 0) {
830 CFISCSI_SESSION_WARN(cs, "got the final packet without "
831 "the F flag; flags = 0x%x; dropping connection",
833 ctl_set_data_phase_error(&io->scsiio);
834 cfiscsi_session_terminate(cs);
838 if (io->scsiio.ext_data_filled != io->scsiio.kern_data_len &&
839 (bhsdo->bhsdo_flags & BHSDO_FLAGS_F) != 0) {
840 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
841 ISCSI_BHS_OPCODE_SCSI_DATA_OUT) {
842 CFISCSI_SESSION_WARN(cs, "got the final packet, but the "
843 "transmitted size was %zd bytes instead of %d; "
844 "dropping connection",
845 (size_t)io->scsiio.ext_data_filled,
846 io->scsiio.kern_data_len);
847 ctl_set_data_phase_error(&io->scsiio);
848 cfiscsi_session_terminate(cs);
852 * For SCSI Command PDU, this just means we need to
853 * solicit more data by sending R2T.
859 if (io->scsiio.ext_data_filled == io->scsiio.kern_data_len) {
861 CFISCSI_SESSION_DEBUG(cs, "no longer expecting Data-Out with target "
862 "transfer tag 0x%x", cdw->cdw_target_transfer_tag);
872 cfiscsi_pdu_handle_data_out(struct icl_pdu *request)
874 struct iscsi_bhs_data_out *bhsdo;
875 struct cfiscsi_session *cs;
876 struct cfiscsi_data_wait *cdw = NULL;
880 cs = PDU_SESSION(request);
881 bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs;
883 CFISCSI_SESSION_LOCK(cs);
884 TAILQ_FOREACH(cdw, &cs->cs_waiting_for_data_out, cdw_next) {
886 CFISCSI_SESSION_DEBUG(cs, "have ttt 0x%x, itt 0x%x; looking for "
887 "ttt 0x%x, itt 0x%x",
888 bhsdo->bhsdo_target_transfer_tag,
889 bhsdo->bhsdo_initiator_task_tag,
890 cdw->cdw_target_transfer_tag, cdw->cdw_initiator_task_tag));
892 if (bhsdo->bhsdo_target_transfer_tag ==
893 cdw->cdw_target_transfer_tag)
896 CFISCSI_SESSION_UNLOCK(cs);
898 CFISCSI_SESSION_WARN(cs, "data transfer tag 0x%x, initiator task tag "
899 "0x%x, not found; dropping connection",
900 bhsdo->bhsdo_target_transfer_tag, bhsdo->bhsdo_initiator_task_tag);
901 icl_pdu_free(request);
902 cfiscsi_session_terminate(cs);
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"));
910 done = cfiscsi_handle_data_segment(request, cdw);
912 CFISCSI_SESSION_LOCK(cs);
913 TAILQ_REMOVE(&cs->cs_waiting_for_data_out, cdw, cdw_next);
914 CFISCSI_SESSION_UNLOCK(cs);
915 uma_zfree(cfiscsi_data_wait_zone, cdw);
916 io->scsiio.be_move_done(io);
919 icl_pdu_free(request);
923 cfiscsi_pdu_handle_logout_request(struct icl_pdu *request)
925 struct iscsi_bhs_logout_request *bhslr;
926 struct iscsi_bhs_logout_response *bhslr2;
927 struct icl_pdu *response;
928 struct cfiscsi_session *cs;
930 cs = PDU_SESSION(request);
931 bhslr = (struct iscsi_bhs_logout_request *)request->ip_bhs;
932 switch (bhslr->bhslr_reason & 0x7f) {
933 case BHSLR_REASON_CLOSE_SESSION:
934 case BHSLR_REASON_CLOSE_CONNECTION:
935 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
936 if (response == NULL) {
937 CFISCSI_SESSION_DEBUG(cs, "failed to allocate memory");
938 icl_pdu_free(request);
939 cfiscsi_session_terminate(cs);
942 bhslr2 = (struct iscsi_bhs_logout_response *)response->ip_bhs;
943 bhslr2->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_RESPONSE;
944 bhslr2->bhslr_flags = 0x80;
945 bhslr2->bhslr_response = BHSLR_RESPONSE_CLOSED_SUCCESSFULLY;
946 bhslr2->bhslr_initiator_task_tag =
947 bhslr->bhslr_initiator_task_tag;
948 icl_pdu_free(request);
949 cfiscsi_pdu_queue(response);
950 cfiscsi_session_terminate(cs);
952 case BHSLR_REASON_REMOVE_FOR_RECOVERY:
953 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
954 if (response == NULL) {
955 CFISCSI_SESSION_WARN(cs,
956 "failed to allocate memory; dropping connection");
957 icl_pdu_free(request);
958 cfiscsi_session_terminate(cs);
961 bhslr2 = (struct iscsi_bhs_logout_response *)response->ip_bhs;
962 bhslr2->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_RESPONSE;
963 bhslr2->bhslr_flags = 0x80;
964 bhslr2->bhslr_response = BHSLR_RESPONSE_RECOVERY_NOT_SUPPORTED;
965 bhslr2->bhslr_initiator_task_tag =
966 bhslr->bhslr_initiator_task_tag;
967 icl_pdu_free(request);
968 cfiscsi_pdu_queue(response);
971 CFISCSI_SESSION_WARN(cs, "invalid reason 0%x; dropping connection",
972 bhslr->bhslr_reason);
973 icl_pdu_free(request);
974 cfiscsi_session_terminate(cs);
980 cfiscsi_callout(void *context)
983 struct iscsi_bhs_nop_in *bhsni;
984 struct cfiscsi_session *cs;
988 if (cs->cs_terminating)
991 callout_schedule(&cs->cs_callout, 1 * hz);
993 atomic_add_int(&cs->cs_timeout, 1);
995 #ifdef ICL_KERNEL_PROXY
996 if (cs->cs_waiting_for_ctld || cs->cs_login_phase) {
997 if (cs->cs_timeout > login_timeout) {
998 CFISCSI_SESSION_WARN(cs, "login timed out after "
999 "%d seconds; dropping connection", cs->cs_timeout);
1000 cfiscsi_session_terminate(cs);
1006 if (cs->cs_timeout >= ping_timeout) {
1007 CFISCSI_SESSION_WARN(cs, "no ping reply (NOP-Out) after %d seconds; "
1008 "dropping connection", ping_timeout);
1009 cfiscsi_session_terminate(cs);
1014 * If the ping was reset less than one second ago - which means
1015 * that we've received some PDU during the last second - assume
1016 * the traffic flows correctly and don't bother sending a NOP-Out.
1018 * (It's 2 - one for one second, and one for incrementing is_timeout
1019 * earlier in this routine.)
1021 if (cs->cs_timeout < 2)
1024 cp = icl_pdu_new_bhs(cs->cs_conn, M_NOWAIT);
1026 CFISCSI_SESSION_WARN(cs, "failed to allocate memory");
1029 bhsni = (struct iscsi_bhs_nop_in *)cp->ip_bhs;
1030 bhsni->bhsni_opcode = ISCSI_BHS_OPCODE_NOP_IN;
1031 bhsni->bhsni_flags = 0x80;
1032 bhsni->bhsni_initiator_task_tag = 0xffffffff;
1034 cfiscsi_pdu_queue(cp);
1038 cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs)
1040 struct cfiscsi_data_wait *cdw, *tmpcdw;
1045 io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
1047 CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io");
1051 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = NULL;
1052 io->io_hdr.io_type = CTL_IO_TASK;
1053 io->io_hdr.nexus.initid.id = cs->cs_ctl_initid;
1054 io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
1055 io->io_hdr.nexus.targ_target.id = 0;
1056 io->io_hdr.nexus.targ_lun = lun;
1057 io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */
1058 io->taskio.task_action = CTL_TASK_ABORT_TASK_SET;
1059 error = ctl_queue(io);
1060 if (error != CTL_RETVAL_COMPLETE) {
1061 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d", error);
1066 * CTL doesn't currently support CTL_TASK_ABORT_TASK_SET, so instead
1067 * just iterate over tasks that are waiting for something - data - and
1070 CFISCSI_SESSION_LOCK(cs);
1071 TAILQ_FOREACH_SAFE(cdw,
1072 &cs->cs_waiting_for_data_out, cdw_next, tmpcdw) {
1073 io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
1075 CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io");
1079 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = NULL;
1080 io->io_hdr.io_type = CTL_IO_TASK;
1081 io->io_hdr.nexus.initid.id = cs->cs_ctl_initid;
1082 io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
1083 io->io_hdr.nexus.targ_target.id = 0;
1084 //io->io_hdr.nexus.targ_lun = lun; /* Not needed? */
1085 io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */
1086 io->taskio.task_action = CTL_TASK_ABORT_TASK;
1087 io->taskio.tag_num = cdw->cdw_initiator_task_tag;
1088 error = ctl_queue(io);
1089 if (error != CTL_RETVAL_COMPLETE) {
1090 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d", error);
1095 CFISCSI_SESSION_DEBUG(cs, "removing csw for initiator task tag "
1096 "0x%x", cdw->cdw_initiator_task_tag);
1099 * Set nonzero port status; this prevents backends from
1100 * assuming that the data transfer actually succeeded
1101 * and writing uninitialized data to disk.
1103 cdw->cdw_ctl_io->scsiio.io_hdr.port_status = 42;
1104 cdw->cdw_ctl_io->scsiio.be_move_done(cdw->cdw_ctl_io);
1105 TAILQ_REMOVE(&cs->cs_waiting_for_data_out, cdw, cdw_next);
1106 uma_zfree(cfiscsi_data_wait_zone, cdw);
1108 CFISCSI_SESSION_UNLOCK(cs);
1112 * Wait for CTL to terminate all the tasks.
1115 refcount_acquire(&cs->cs_outstanding_ctl_pdus);
1116 last = refcount_release(&cs->cs_outstanding_ctl_pdus);
1119 CFISCSI_SESSION_WARN(cs, "waiting for CTL to terminate tasks, "
1120 "%d remaining", cs->cs_outstanding_ctl_pdus);
1121 pause("cfiscsi_terminate", 1);
1126 cfiscsi_maintenance_thread(void *arg)
1128 struct cfiscsi_session *cs;
1133 CFISCSI_SESSION_LOCK(cs);
1134 if (cs->cs_terminating == false)
1135 cv_wait(&cs->cs_maintenance_cv, &cs->cs_lock);
1136 CFISCSI_SESSION_UNLOCK(cs);
1138 if (cs->cs_terminating) {
1141 * We used to wait up to 30 seconds to deliver queued
1142 * PDUs to the initiator. We also tried hard to deliver
1143 * SCSI Responses for the aborted PDUs. We don't do
1144 * that anymore. We might need to revisit that.
1146 callout_drain(&cs->cs_callout);
1147 icl_conn_shutdown(cs->cs_conn);
1148 icl_conn_close(cs->cs_conn);
1151 * At this point ICL receive thread is no longer
1152 * running; no new tasks can be queued.
1154 cfiscsi_session_terminate_tasks(cs);
1155 cfiscsi_session_delete(cs);
1159 CFISCSI_SESSION_DEBUG(cs, "nothing to do");
1164 cfiscsi_session_terminate(struct cfiscsi_session *cs)
1167 if (cs->cs_terminating)
1169 cs->cs_terminating = true;
1170 cv_signal(&cs->cs_maintenance_cv);
1171 #ifdef ICL_KERNEL_PROXY
1172 cv_signal(&cs->cs_login_cv);
1177 cfiscsi_session_register_initiator(struct cfiscsi_session *cs)
1180 struct cfiscsi_softc *softc;
1182 KASSERT(cs->cs_ctl_initid == -1, ("already registered"));
1184 softc = &cfiscsi_softc;
1186 mtx_lock(&softc->lock);
1187 for (i = 0; i < softc->max_initiators; i++) {
1188 if (softc->ctl_initids[i] == 0)
1191 if (i == softc->max_initiators) {
1192 CFISCSI_SESSION_WARN(cs, "too many concurrent sessions (%d)",
1193 softc->max_initiators);
1194 mtx_unlock(&softc->lock);
1197 softc->ctl_initids[i] = 1;
1198 mtx_unlock(&softc->lock);
1201 CFISCSI_SESSION_DEBUG(cs, "adding initiator id %d, max %d",
1202 i, softc->max_initiators);
1204 cs->cs_ctl_initid = i;
1205 error = ctl_add_initiator(0x0, cs->cs_target->ct_port.targ_port, cs->cs_ctl_initid);
1207 CFISCSI_SESSION_WARN(cs, "ctl_add_initiator failed with error %d", error);
1208 mtx_lock(&softc->lock);
1209 softc->ctl_initids[cs->cs_ctl_initid] = 0;
1210 mtx_unlock(&softc->lock);
1211 cs->cs_ctl_initid = -1;
1219 cfiscsi_session_unregister_initiator(struct cfiscsi_session *cs)
1222 struct cfiscsi_softc *softc;
1224 if (cs->cs_ctl_initid == -1)
1227 softc = &cfiscsi_softc;
1229 error = ctl_remove_initiator(cs->cs_target->ct_port.targ_port, cs->cs_ctl_initid);
1231 CFISCSI_SESSION_WARN(cs, "ctl_remove_initiator failed with error %d",
1234 mtx_lock(&softc->lock);
1235 softc->ctl_initids[cs->cs_ctl_initid] = 0;
1236 mtx_unlock(&softc->lock);
1237 cs->cs_ctl_initid = -1;
1240 static struct cfiscsi_session *
1241 cfiscsi_session_new(struct cfiscsi_softc *softc)
1243 struct cfiscsi_session *cs;
1246 cs = malloc(sizeof(*cs), M_CFISCSI, M_NOWAIT | M_ZERO);
1248 CFISCSI_WARN("malloc failed");
1251 cs->cs_ctl_initid = -1;
1253 refcount_init(&cs->cs_outstanding_ctl_pdus, 0);
1254 TAILQ_INIT(&cs->cs_waiting_for_data_out);
1255 mtx_init(&cs->cs_lock, "cfiscsi_lock", NULL, MTX_DEF);
1256 cv_init(&cs->cs_maintenance_cv, "cfiscsi_mt");
1257 #ifdef ICL_KERNEL_PROXY
1258 cv_init(&cs->cs_login_cv, "cfiscsi_login");
1261 cs->cs_conn = icl_conn_new("cfiscsi", &cs->cs_lock);
1262 cs->cs_conn->ic_receive = cfiscsi_receive_callback;
1263 cs->cs_conn->ic_error = cfiscsi_error_callback;
1264 cs->cs_conn->ic_prv0 = cs;
1266 error = kthread_add(cfiscsi_maintenance_thread, cs, NULL, NULL, 0, 0, "cfiscsimt");
1268 CFISCSI_SESSION_WARN(cs, "kthread_add(9) failed with error %d", error);
1269 free(cs, M_CFISCSI);
1273 mtx_lock(&softc->lock);
1274 cs->cs_id = softc->last_session_id + 1;
1275 softc->last_session_id++;
1276 mtx_unlock(&softc->lock);
1278 mtx_lock(&softc->lock);
1279 TAILQ_INSERT_TAIL(&softc->sessions, cs, cs_next);
1280 mtx_unlock(&softc->lock);
1283 * Start pinging the initiator.
1285 callout_init(&cs->cs_callout, 1);
1286 callout_reset(&cs->cs_callout, 1 * hz, cfiscsi_callout, cs);
1292 cfiscsi_session_delete(struct cfiscsi_session *cs)
1294 struct cfiscsi_softc *softc;
1296 softc = &cfiscsi_softc;
1298 KASSERT(cs->cs_outstanding_ctl_pdus == 0,
1299 ("destroying session with outstanding CTL pdus"));
1300 KASSERT(TAILQ_EMPTY(&cs->cs_waiting_for_data_out),
1301 ("destroying session with non-empty queue"));
1303 cfiscsi_session_unregister_initiator(cs);
1304 if (cs->cs_target != NULL)
1305 cfiscsi_target_release(cs->cs_target);
1306 icl_conn_close(cs->cs_conn);
1307 icl_conn_free(cs->cs_conn);
1309 mtx_lock(&softc->lock);
1310 TAILQ_REMOVE(&softc->sessions, cs, cs_next);
1311 mtx_unlock(&softc->lock);
1313 free(cs, M_CFISCSI);
1319 struct cfiscsi_softc *softc;
1322 softc = &cfiscsi_softc;
1324 bzero(softc, sizeof(*softc));
1325 mtx_init(&softc->lock, "cfiscsi", NULL, MTX_DEF);
1327 #ifdef ICL_KERNEL_PROXY
1328 cv_init(&softc->accept_cv, "cfiscsi_accept");
1330 TAILQ_INIT(&softc->sessions);
1331 TAILQ_INIT(&softc->targets);
1333 softc->max_initiators = CTL_MAX_INIT_PER_PORT;
1335 cfiscsi_data_wait_zone = uma_zcreate("cfiscsi_data_wait",
1336 sizeof(struct cfiscsi_data_wait), NULL, NULL, NULL, NULL,
1342 #ifdef ICL_KERNEL_PROXY
1344 cfiscsi_accept(struct socket *so, struct sockaddr *sa, int portal_id)
1346 struct cfiscsi_session *cs;
1348 cs = cfiscsi_session_new(&cfiscsi_softc);
1350 CFISCSI_WARN("failed to create session");
1354 icl_conn_handoff_sock(cs->cs_conn, so);
1355 cs->cs_initiator_sa = sa;
1356 cs->cs_portal_id = portal_id;
1357 cs->cs_waiting_for_ctld = true;
1358 cv_signal(&cfiscsi_softc.accept_cv);
1363 cfiscsi_online(void *arg)
1365 struct cfiscsi_softc *softc;
1366 struct cfiscsi_target *ct;
1369 ct = (struct cfiscsi_target *)arg;
1370 softc = ct->ct_softc;
1372 mtx_lock(&softc->lock);
1373 if (ct->ct_online) {
1374 mtx_unlock(&softc->lock);
1378 online = softc->online++;
1379 mtx_unlock(&softc->lock);
1383 #ifdef ICL_KERNEL_PROXY
1384 if (softc->listener != NULL)
1385 icl_listen_free(softc->listener);
1386 softc->listener = icl_listen_new(cfiscsi_accept);
1391 cfiscsi_offline(void *arg)
1393 struct cfiscsi_softc *softc;
1394 struct cfiscsi_target *ct;
1395 struct cfiscsi_session *cs;
1398 ct = (struct cfiscsi_target *)arg;
1399 softc = ct->ct_softc;
1401 mtx_lock(&softc->lock);
1402 if (!ct->ct_online) {
1403 mtx_unlock(&softc->lock);
1407 online = --softc->online;
1409 TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1410 if (cs->cs_target == ct)
1411 cfiscsi_session_terminate(cs);
1413 mtx_unlock(&softc->lock);
1417 #ifdef ICL_KERNEL_PROXY
1418 icl_listen_free(softc->listener);
1419 softc->listener = NULL;
1424 cfiscsi_ioctl_handoff(struct ctl_iscsi *ci)
1426 struct cfiscsi_softc *softc;
1427 struct cfiscsi_session *cs;
1428 struct cfiscsi_target *ct;
1429 struct ctl_iscsi_handoff_params *cihp;
1432 cihp = (struct ctl_iscsi_handoff_params *)&(ci->data);
1433 softc = &cfiscsi_softc;
1435 CFISCSI_DEBUG("new connection from %s (%s) to %s",
1436 cihp->initiator_name, cihp->initiator_addr,
1439 ct = cfiscsi_target_find(softc, cihp->target_name);
1441 ci->status = CTL_ISCSI_ERROR;
1442 snprintf(ci->error_str, sizeof(ci->error_str),
1443 "%s: target not found", __func__);
1447 if (ct->ct_online == 0) {
1448 ci->status = CTL_ISCSI_ERROR;
1449 snprintf(ci->error_str, sizeof(ci->error_str),
1450 "%s: port offline", __func__);
1451 cfiscsi_target_release(ct);
1455 #ifdef ICL_KERNEL_PROXY
1456 if (cihp->socket > 0 && cihp->connection_id > 0) {
1457 snprintf(ci->error_str, sizeof(ci->error_str),
1458 "both socket and connection_id set");
1459 ci->status = CTL_ISCSI_ERROR;
1460 cfiscsi_target_release(ct);
1463 if (cihp->socket == 0) {
1464 mtx_lock(&cfiscsi_softc.lock);
1465 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
1466 if (cs->cs_id == cihp->socket)
1470 mtx_unlock(&cfiscsi_softc.lock);
1471 snprintf(ci->error_str, sizeof(ci->error_str),
1472 "connection not found");
1473 ci->status = CTL_ISCSI_ERROR;
1474 cfiscsi_target_release(ct);
1477 mtx_unlock(&cfiscsi_softc.lock);
1480 cs = cfiscsi_session_new(softc);
1482 ci->status = CTL_ISCSI_ERROR;
1483 snprintf(ci->error_str, sizeof(ci->error_str),
1484 "%s: cfiscsi_session_new failed", __func__);
1485 cfiscsi_target_release(ct);
1488 #ifdef ICL_KERNEL_PROXY
1494 * First PDU of Full Feature phase has the same CmdSN as the last
1495 * PDU from the Login Phase received from the initiator. Thus,
1498 cs->cs_portal_group_tag = cihp->portal_group_tag;
1499 cs->cs_cmdsn = cihp->cmdsn;
1500 cs->cs_statsn = cihp->statsn;
1501 cs->cs_max_data_segment_length = cihp->max_recv_data_segment_length;
1502 cs->cs_max_burst_length = cihp->max_burst_length;
1503 cs->cs_immediate_data = !!cihp->immediate_data;
1504 if (cihp->header_digest == CTL_ISCSI_DIGEST_CRC32C)
1505 cs->cs_conn->ic_header_crc32c = true;
1506 if (cihp->data_digest == CTL_ISCSI_DIGEST_CRC32C)
1507 cs->cs_conn->ic_data_crc32c = true;
1509 strlcpy(cs->cs_initiator_name,
1510 cihp->initiator_name, sizeof(cs->cs_initiator_name));
1511 strlcpy(cs->cs_initiator_addr,
1512 cihp->initiator_addr, sizeof(cs->cs_initiator_addr));
1513 strlcpy(cs->cs_initiator_alias,
1514 cihp->initiator_alias, sizeof(cs->cs_initiator_alias));
1516 #ifdef ICL_KERNEL_PROXY
1517 if (cihp->socket > 0) {
1519 error = icl_conn_handoff(cs->cs_conn, cihp->socket);
1521 cfiscsi_session_delete(cs);
1522 ci->status = CTL_ISCSI_ERROR;
1523 snprintf(ci->error_str, sizeof(ci->error_str),
1524 "%s: icl_conn_handoff failed with error %d",
1528 #ifdef ICL_KERNEL_PROXY
1533 * Register initiator with CTL.
1535 cfiscsi_session_register_initiator(cs);
1537 #ifdef ICL_KERNEL_PROXY
1538 cs->cs_login_phase = false;
1541 * First PDU of the Full Feature phase has likely already arrived.
1542 * We have to pick it up and execute properly.
1544 if (cs->cs_login_pdu != NULL) {
1545 CFISCSI_SESSION_DEBUG(cs, "picking up first PDU");
1546 cfiscsi_pdu_handle(cs->cs_login_pdu);
1547 cs->cs_login_pdu = NULL;
1551 ci->status = CTL_ISCSI_OK;
1555 cfiscsi_ioctl_list(struct ctl_iscsi *ci)
1557 struct ctl_iscsi_list_params *cilp;
1558 struct cfiscsi_session *cs;
1559 struct cfiscsi_softc *softc;
1563 cilp = (struct ctl_iscsi_list_params *)&(ci->data);
1564 softc = &cfiscsi_softc;
1566 sb = sbuf_new(NULL, NULL, cilp->alloc_len, SBUF_FIXEDLEN);
1568 ci->status = CTL_ISCSI_ERROR;
1569 snprintf(ci->error_str, sizeof(ci->error_str),
1570 "Unable to allocate %d bytes for iSCSI session list",
1575 sbuf_printf(sb, "<ctlislist>\n");
1576 mtx_lock(&softc->lock);
1577 TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1578 #ifdef ICL_KERNEL_PROXY
1579 if (cs->cs_target == NULL)
1582 error = sbuf_printf(sb, "<connection id=\"%d\">"
1583 "<initiator>%s</initiator>"
1584 "<initiator_addr>%s</initiator_addr>"
1585 "<initiator_alias>%s</initiator_alias>"
1586 "<target>%s</target>"
1587 "<target_alias>%s</target_alias>"
1588 "<header_digest>%s</header_digest>"
1589 "<data_digest>%s</data_digest>"
1590 "<max_data_segment_length>%zd</max_data_segment_length>"
1591 "<immediate_data>%d</immediate_data>"
1595 cs->cs_initiator_name, cs->cs_initiator_addr, cs->cs_initiator_alias,
1596 cs->cs_target->ct_name, cs->cs_target->ct_alias,
1597 cs->cs_conn->ic_header_crc32c ? "CRC32C" : "None",
1598 cs->cs_conn->ic_data_crc32c ? "CRC32C" : "None",
1599 cs->cs_max_data_segment_length,
1600 cs->cs_immediate_data,
1601 cs->cs_conn->ic_iser);
1605 mtx_unlock(&softc->lock);
1606 error = sbuf_printf(sb, "</ctlislist>\n");
1609 ci->status = CTL_ISCSI_LIST_NEED_MORE_SPACE;
1610 snprintf(ci->error_str, sizeof(ci->error_str),
1611 "Out of space, %d bytes is too small", cilp->alloc_len);
1616 error = copyout(sbuf_data(sb), cilp->conn_xml, sbuf_len(sb) + 1);
1617 cilp->fill_len = sbuf_len(sb) + 1;
1618 ci->status = CTL_ISCSI_OK;
1623 cfiscsi_ioctl_terminate(struct ctl_iscsi *ci)
1625 struct icl_pdu *response;
1626 struct iscsi_bhs_asynchronous_message *bhsam;
1627 struct ctl_iscsi_terminate_params *citp;
1628 struct cfiscsi_session *cs;
1629 struct cfiscsi_softc *softc;
1632 citp = (struct ctl_iscsi_terminate_params *)&(ci->data);
1633 softc = &cfiscsi_softc;
1635 mtx_lock(&softc->lock);
1636 TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1637 if (citp->all == 0 && cs->cs_id != citp->connection_id &&
1638 strcmp(cs->cs_initiator_name, citp->initiator_name) != 0 &&
1639 strcmp(cs->cs_initiator_addr, citp->initiator_addr) != 0)
1642 response = icl_pdu_new_bhs(cs->cs_conn, M_NOWAIT);
1643 if (response == NULL) {
1645 * Oh well. Just terminate the connection.
1648 bhsam = (struct iscsi_bhs_asynchronous_message *)
1650 bhsam->bhsam_opcode = ISCSI_BHS_OPCODE_ASYNC_MESSAGE;
1651 bhsam->bhsam_flags = 0x80;
1652 bhsam->bhsam_0xffffffff = 0xffffffff;
1653 bhsam->bhsam_async_event =
1654 BHSAM_EVENT_TARGET_TERMINATES_SESSION;
1655 cfiscsi_pdu_queue(response);
1657 cfiscsi_session_terminate(cs);
1660 mtx_unlock(&softc->lock);
1663 ci->status = CTL_ISCSI_SESSION_NOT_FOUND;
1664 snprintf(ci->error_str, sizeof(ci->error_str),
1665 "No matching connections found");
1669 ci->status = CTL_ISCSI_OK;
1673 cfiscsi_ioctl_logout(struct ctl_iscsi *ci)
1675 struct icl_pdu *response;
1676 struct iscsi_bhs_asynchronous_message *bhsam;
1677 struct ctl_iscsi_logout_params *cilp;
1678 struct cfiscsi_session *cs;
1679 struct cfiscsi_softc *softc;
1682 cilp = (struct ctl_iscsi_logout_params *)&(ci->data);
1683 softc = &cfiscsi_softc;
1685 mtx_lock(&softc->lock);
1686 TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1687 if (cilp->all == 0 && cs->cs_id != cilp->connection_id &&
1688 strcmp(cs->cs_initiator_name, cilp->initiator_name) != 0 &&
1689 strcmp(cs->cs_initiator_addr, cilp->initiator_addr) != 0)
1692 response = icl_pdu_new_bhs(cs->cs_conn, M_NOWAIT);
1693 if (response == NULL) {
1694 ci->status = CTL_ISCSI_ERROR;
1695 snprintf(ci->error_str, sizeof(ci->error_str),
1696 "Unable to allocate memory");
1697 mtx_unlock(&softc->lock);
1701 (struct iscsi_bhs_asynchronous_message *)response->ip_bhs;
1702 bhsam->bhsam_opcode = ISCSI_BHS_OPCODE_ASYNC_MESSAGE;
1703 bhsam->bhsam_flags = 0x80;
1704 bhsam->bhsam_async_event = BHSAM_EVENT_TARGET_REQUESTS_LOGOUT;
1705 bhsam->bhsam_parameter3 = htons(10);
1706 cfiscsi_pdu_queue(response);
1709 mtx_unlock(&softc->lock);
1712 ci->status = CTL_ISCSI_SESSION_NOT_FOUND;
1713 snprintf(ci->error_str, sizeof(ci->error_str),
1714 "No matching connections found");
1718 ci->status = CTL_ISCSI_OK;
1721 #ifdef ICL_KERNEL_PROXY
1723 cfiscsi_ioctl_listen(struct ctl_iscsi *ci)
1725 struct ctl_iscsi_listen_params *cilp;
1726 struct sockaddr *sa;
1729 cilp = (struct ctl_iscsi_listen_params *)&(ci->data);
1731 if (cfiscsi_softc.listener == NULL) {
1732 CFISCSI_DEBUG("no listener");
1733 snprintf(ci->error_str, sizeof(ci->error_str), "no listener");
1734 ci->status = CTL_ISCSI_ERROR;
1738 error = getsockaddr(&sa, (void *)cilp->addr, cilp->addrlen);
1740 CFISCSI_DEBUG("getsockaddr, error %d", error);
1741 snprintf(ci->error_str, sizeof(ci->error_str), "getsockaddr failed");
1742 ci->status = CTL_ISCSI_ERROR;
1746 error = icl_listen_add(cfiscsi_softc.listener, cilp->iser, cilp->domain,
1747 cilp->socktype, cilp->protocol, sa, cilp->portal_id);
1750 CFISCSI_DEBUG("icl_listen_add, error %d", error);
1751 snprintf(ci->error_str, sizeof(ci->error_str),
1752 "icl_listen_add failed, error %d", error);
1753 ci->status = CTL_ISCSI_ERROR;
1757 ci->status = CTL_ISCSI_OK;
1761 cfiscsi_ioctl_accept(struct ctl_iscsi *ci)
1763 struct ctl_iscsi_accept_params *ciap;
1764 struct cfiscsi_session *cs;
1767 ciap = (struct ctl_iscsi_accept_params *)&(ci->data);
1769 mtx_lock(&cfiscsi_softc.lock);
1771 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
1772 if (cs->cs_waiting_for_ctld)
1777 error = cv_wait_sig(&cfiscsi_softc.accept_cv, &cfiscsi_softc.lock);
1779 mtx_unlock(&cfiscsi_softc.lock);
1780 snprintf(ci->error_str, sizeof(ci->error_str), "interrupted");
1781 ci->status = CTL_ISCSI_ERROR;
1785 mtx_unlock(&cfiscsi_softc.lock);
1787 cs->cs_waiting_for_ctld = false;
1788 cs->cs_login_phase = true;
1790 ciap->connection_id = cs->cs_id;
1791 ciap->portal_id = cs->cs_portal_id;
1792 ciap->initiator_addrlen = cs->cs_initiator_sa->sa_len;
1793 error = copyout(cs->cs_initiator_sa, ciap->initiator_addr,
1794 cs->cs_initiator_sa->sa_len);
1796 snprintf(ci->error_str, sizeof(ci->error_str),
1797 "copyout failed with error %d", error);
1798 ci->status = CTL_ISCSI_ERROR;
1802 ci->status = CTL_ISCSI_OK;
1806 cfiscsi_ioctl_send(struct ctl_iscsi *ci)
1808 struct ctl_iscsi_send_params *cisp;
1809 struct cfiscsi_session *cs;
1815 cisp = (struct ctl_iscsi_send_params *)&(ci->data);
1817 mtx_lock(&cfiscsi_softc.lock);
1818 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
1819 if (cs->cs_id == cisp->connection_id)
1823 mtx_unlock(&cfiscsi_softc.lock);
1824 snprintf(ci->error_str, sizeof(ci->error_str), "connection not found");
1825 ci->status = CTL_ISCSI_ERROR;
1828 mtx_unlock(&cfiscsi_softc.lock);
1831 if (cs->cs_login_phase == false)
1835 if (cs->cs_terminating) {
1836 snprintf(ci->error_str, sizeof(ci->error_str), "connection is terminating");
1837 ci->status = CTL_ISCSI_ERROR;
1841 datalen = cisp->data_segment_len;
1845 //if (datalen > CFISCSI_MAX_DATA_SEGMENT_LENGTH) {
1846 if (datalen > 65535) {
1847 snprintf(ci->error_str, sizeof(ci->error_str), "data segment too big");
1848 ci->status = CTL_ISCSI_ERROR;
1852 data = malloc(datalen, M_CFISCSI, M_WAITOK);
1853 error = copyin(cisp->data_segment, data, datalen);
1855 free(data, M_CFISCSI);
1856 snprintf(ci->error_str, sizeof(ci->error_str), "copyin error %d", error);
1857 ci->status = CTL_ISCSI_ERROR;
1862 ip = icl_pdu_new_bhs(cs->cs_conn, M_WAITOK);
1863 memcpy(ip->ip_bhs, cisp->bhs, sizeof(*ip->ip_bhs));
1865 icl_pdu_append_data(ip, data, datalen, M_WAITOK);
1866 free(data, M_CFISCSI);
1868 CFISCSI_SESSION_LOCK(cs);
1870 CFISCSI_SESSION_UNLOCK(cs);
1871 ci->status = CTL_ISCSI_OK;
1875 cfiscsi_ioctl_receive(struct ctl_iscsi *ci)
1877 struct ctl_iscsi_receive_params *cirp;
1878 struct cfiscsi_session *cs;
1883 cirp = (struct ctl_iscsi_receive_params *)&(ci->data);
1885 mtx_lock(&cfiscsi_softc.lock);
1886 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
1887 if (cs->cs_id == cirp->connection_id)
1891 mtx_unlock(&cfiscsi_softc.lock);
1892 snprintf(ci->error_str, sizeof(ci->error_str),
1893 "connection not found");
1894 ci->status = CTL_ISCSI_ERROR;
1897 mtx_unlock(&cfiscsi_softc.lock);
1900 if (is->is_login_phase == false)
1904 CFISCSI_SESSION_LOCK(cs);
1905 while (cs->cs_login_pdu == NULL && cs->cs_terminating == false) {
1906 error = cv_wait_sig(&cs->cs_login_cv, &cs->cs_lock);
1908 CFISCSI_SESSION_UNLOCK(cs);
1909 snprintf(ci->error_str, sizeof(ci->error_str),
1910 "interrupted by signal");
1911 ci->status = CTL_ISCSI_ERROR;
1916 if (cs->cs_terminating) {
1917 CFISCSI_SESSION_UNLOCK(cs);
1918 snprintf(ci->error_str, sizeof(ci->error_str),
1919 "connection terminating");
1920 ci->status = CTL_ISCSI_ERROR;
1923 ip = cs->cs_login_pdu;
1924 cs->cs_login_pdu = NULL;
1925 CFISCSI_SESSION_UNLOCK(cs);
1927 if (ip->ip_data_len > cirp->data_segment_len) {
1929 snprintf(ci->error_str, sizeof(ci->error_str),
1930 "data segment too big");
1931 ci->status = CTL_ISCSI_ERROR;
1935 copyout(ip->ip_bhs, cirp->bhs, sizeof(*ip->ip_bhs));
1936 if (ip->ip_data_len > 0) {
1937 data = malloc(ip->ip_data_len, M_CFISCSI, M_WAITOK);
1938 icl_pdu_get_data(ip, 0, data, ip->ip_data_len);
1939 copyout(data, cirp->data_segment, ip->ip_data_len);
1940 free(data, M_CFISCSI);
1944 ci->status = CTL_ISCSI_OK;
1947 #endif /* !ICL_KERNEL_PROXY */
1950 cfiscsi_ioctl_port_create(struct ctl_req *req)
1952 struct cfiscsi_target *ct;
1953 struct ctl_port *port;
1954 const char *target, *alias, *tag;
1958 ctl_init_opts(&opts, req->num_args, req->kern_args);
1959 target = ctl_get_opt(&opts, "cfiscsi_target");
1960 alias = ctl_get_opt(&opts, "cfiscsi_target_alias");
1961 tag = ctl_get_opt(&opts, "cfiscsi_portal_group_tag");
1962 if (target == NULL || tag == NULL) {
1963 ctl_free_opts(&opts);
1964 req->status = CTL_LUN_ERROR;
1965 snprintf(req->error_str, sizeof(req->error_str),
1966 "Missing required argument");
1969 ct = cfiscsi_target_find_or_create(&cfiscsi_softc, target, alias);
1971 ctl_free_opts(&opts);
1972 req->status = CTL_LUN_ERROR;
1973 snprintf(req->error_str, sizeof(req->error_str),
1974 "failed to create target \"%s\"", target);
1977 if (ct->ct_state == CFISCSI_TARGET_STATE_ACTIVE) {
1978 cfiscsi_target_release(ct);
1979 ctl_free_opts(&opts);
1980 req->status = CTL_LUN_ERROR;
1981 snprintf(req->error_str, sizeof(req->error_str),
1982 "target \"%s\" already exist", target);
1985 port = &ct->ct_port;
1986 if (ct->ct_state == CFISCSI_TARGET_STATE_DYING)
1989 port->frontend = &cfiscsi_frontend;
1990 port->port_type = CTL_PORT_ISCSI;
1991 /* XXX KDM what should the real number be here? */
1992 port->num_requested_ctl_io = 4096;
1993 port->port_name = "iscsi";
1994 port->virtual_port = strtoul(tag, NULL, 0);
1995 port->port_online = cfiscsi_online;
1996 port->port_offline = cfiscsi_offline;
1997 port->onoff_arg = ct;
1998 port->lun_enable = cfiscsi_lun_enable;
1999 port->lun_disable = cfiscsi_lun_disable;
2000 port->targ_lun_arg = ct;
2001 port->devid = cfiscsi_devid;
2002 port->fe_datamove = cfiscsi_datamove;
2003 port->fe_done = cfiscsi_done;
2005 /* XXX KDM what should we report here? */
2006 /* XXX These should probably be fetched from CTL. */
2007 port->max_targets = 1;
2008 port->max_target_id = 15;
2010 port->options = opts;
2013 retval = ctl_port_register(port, /*master_SC*/ 1);
2015 ctl_free_opts(&port->options);
2016 cfiscsi_target_release(ct);
2017 req->status = CTL_LUN_ERROR;
2018 snprintf(req->error_str, sizeof(req->error_str),
2019 "ctl_frontend_register() failed with error %d", retval);
2023 ct->ct_state = CFISCSI_TARGET_STATE_ACTIVE;
2024 req->status = CTL_LUN_OK;
2025 memcpy(req->kern_args[0].kvalue, &port->targ_port,
2026 sizeof(port->targ_port)); //XXX
2030 cfiscsi_ioctl_port_remove(struct ctl_req *req)
2032 struct cfiscsi_target *ct;
2036 ctl_init_opts(&opts, req->num_args, req->kern_args);
2037 target = ctl_get_opt(&opts, "cfiscsi_target");
2038 if (target == NULL) {
2039 ctl_free_opts(&opts);
2040 req->status = CTL_LUN_ERROR;
2041 snprintf(req->error_str, sizeof(req->error_str),
2042 "Missing required argument");
2045 ct = cfiscsi_target_find(&cfiscsi_softc, target);
2047 ctl_free_opts(&opts);
2048 req->status = CTL_LUN_ERROR;
2049 snprintf(req->error_str, sizeof(req->error_str),
2050 "can't find target \"%s\"", target);
2053 if (ct->ct_state != CFISCSI_TARGET_STATE_ACTIVE) {
2054 ctl_free_opts(&opts);
2055 req->status = CTL_LUN_ERROR;
2056 snprintf(req->error_str, sizeof(req->error_str),
2057 "target \"%s\" is already dying", target);
2060 ctl_free_opts(&opts);
2062 ct->ct_state = CFISCSI_TARGET_STATE_DYING;
2063 ctl_port_offline(&ct->ct_port);
2064 cfiscsi_target_release(ct);
2065 cfiscsi_target_release(ct);
2069 cfiscsi_ioctl(struct cdev *dev,
2070 u_long cmd, caddr_t addr, int flag, struct thread *td)
2072 struct ctl_iscsi *ci;
2073 struct ctl_req *req;
2075 if (cmd == CTL_PORT_REQ) {
2076 req = (struct ctl_req *)addr;
2077 switch (req->reqtype) {
2078 case CTL_REQ_CREATE:
2079 cfiscsi_ioctl_port_create(req);
2081 case CTL_REQ_REMOVE:
2082 cfiscsi_ioctl_port_remove(req);
2085 req->status = CTL_LUN_ERROR;
2086 snprintf(req->error_str, sizeof(req->error_str),
2087 "Unsupported request type %d", req->reqtype);
2092 if (cmd != CTL_ISCSI)
2095 ci = (struct ctl_iscsi *)addr;
2097 case CTL_ISCSI_HANDOFF:
2098 cfiscsi_ioctl_handoff(ci);
2100 case CTL_ISCSI_LIST:
2101 cfiscsi_ioctl_list(ci);
2103 case CTL_ISCSI_TERMINATE:
2104 cfiscsi_ioctl_terminate(ci);
2106 case CTL_ISCSI_LOGOUT:
2107 cfiscsi_ioctl_logout(ci);
2109 #ifdef ICL_KERNEL_PROXY
2110 case CTL_ISCSI_LISTEN:
2111 cfiscsi_ioctl_listen(ci);
2113 case CTL_ISCSI_ACCEPT:
2114 cfiscsi_ioctl_accept(ci);
2116 case CTL_ISCSI_SEND:
2117 cfiscsi_ioctl_send(ci);
2119 case CTL_ISCSI_RECEIVE:
2120 cfiscsi_ioctl_receive(ci);
2123 case CTL_ISCSI_LISTEN:
2124 case CTL_ISCSI_ACCEPT:
2125 case CTL_ISCSI_SEND:
2126 case CTL_ISCSI_RECEIVE:
2127 ci->status = CTL_ISCSI_ERROR;
2128 snprintf(ci->error_str, sizeof(ci->error_str),
2129 "%s: CTL compiled without ICL_KERNEL_PROXY",
2132 #endif /* !ICL_KERNEL_PROXY */
2134 ci->status = CTL_ISCSI_ERROR;
2135 snprintf(ci->error_str, sizeof(ci->error_str),
2136 "%s: invalid iSCSI request type %d", __func__, ci->type);
2144 cfiscsi_devid(struct ctl_scsiio *ctsio, int alloc_len)
2146 struct cfiscsi_session *cs;
2147 struct scsi_vpd_device_id *devid_ptr;
2148 struct scsi_vpd_id_descriptor *desc, *desc1, *desc2, *desc3, *desc4;
2149 struct scsi_vpd_id_descriptor *desc5;
2150 struct scsi_vpd_id_t10 *t10id;
2151 struct ctl_lun *lun;
2152 const struct icl_pdu *request;
2155 size_t data_len, devid_len, wwnn_len, wwpn_len, lun_name_len;
2157 lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
2158 request = ctsio->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2159 cs = PDU_SESSION(request);
2161 wwpn_len = strlen(cs->cs_target->ct_name);
2162 wwpn_len += strlen(",t,0x0001");
2163 wwpn_len += 1; /* '\0' */
2164 if ((wwpn_len % 4) != 0)
2165 wwpn_len += (4 - (wwpn_len % 4));
2167 wwnn_len = strlen(cs->cs_target->ct_name);
2168 wwnn_len += 1; /* '\0' */
2169 if ((wwnn_len % 4) != 0)
2170 wwnn_len += (4 - (wwnn_len % 4));
2173 devid_len = CTL_DEVID_MIN_LEN;
2176 devid_len = max(CTL_DEVID_MIN_LEN,
2177 strnlen(lun->be_lun->device_id, CTL_DEVID_LEN));
2178 lun_name_len = strlen(cs->cs_target->ct_name);
2179 lun_name_len += strlen(",lun,XXXXXXXX");
2180 lun_name_len += 1; /* '\0' */
2181 if ((lun_name_len % 4) != 0)
2182 lun_name_len += (4 - (lun_name_len % 4));
2185 data_len = sizeof(struct scsi_vpd_device_id) +
2186 sizeof(struct scsi_vpd_id_descriptor) +
2187 sizeof(struct scsi_vpd_id_t10) + devid_len +
2188 sizeof(struct scsi_vpd_id_descriptor) + lun_name_len +
2189 sizeof(struct scsi_vpd_id_descriptor) + wwnn_len +
2190 sizeof(struct scsi_vpd_id_descriptor) + wwpn_len +
2191 sizeof(struct scsi_vpd_id_descriptor) +
2192 sizeof(struct scsi_vpd_id_rel_trgt_port_id) +
2193 sizeof(struct scsi_vpd_id_descriptor) +
2194 sizeof(struct scsi_vpd_id_trgt_port_grp_id);
2196 ctsio->kern_data_ptr = malloc(data_len, M_CTL, M_WAITOK | M_ZERO);
2197 devid_ptr = (struct scsi_vpd_device_id *)ctsio->kern_data_ptr;
2198 ctsio->kern_sg_entries = 0;
2200 if (data_len < alloc_len) {
2201 ctsio->residual = alloc_len - data_len;
2202 ctsio->kern_data_len = data_len;
2203 ctsio->kern_total_len = data_len;
2205 ctsio->residual = 0;
2206 ctsio->kern_data_len = alloc_len;
2207 ctsio->kern_total_len = alloc_len;
2209 ctsio->kern_data_resid = 0;
2210 ctsio->kern_rel_offset = 0;
2211 ctsio->kern_sg_entries = 0;
2213 desc = (struct scsi_vpd_id_descriptor *)devid_ptr->desc_list;
2214 t10id = (struct scsi_vpd_id_t10 *)&desc->identifier[0];
2215 desc1 = (struct scsi_vpd_id_descriptor *)(&desc->identifier[0] +
2216 sizeof(struct scsi_vpd_id_t10) + devid_len);
2217 desc2 = (struct scsi_vpd_id_descriptor *)(&desc1->identifier[0] +
2219 desc3 = (struct scsi_vpd_id_descriptor *)(&desc2->identifier[0] +
2221 desc4 = (struct scsi_vpd_id_descriptor *)(&desc3->identifier[0] +
2223 desc5 = (struct scsi_vpd_id_descriptor *)(&desc4->identifier[0] +
2224 sizeof(struct scsi_vpd_id_rel_trgt_port_id));
2227 devid_ptr->device = (SID_QUAL_LU_CONNECTED << 5) |
2228 lun->be_lun->lun_type;
2230 devid_ptr->device = (SID_QUAL_LU_OFFLINE << 5) | T_DIRECT;
2232 devid_ptr->page_code = SVPD_DEVICE_ID;
2234 scsi_ulto2b(data_len - 4, devid_ptr->length);
2237 * We're using a LUN association here. i.e., this device ID is a
2238 * per-LUN identifier.
2240 desc->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_ASCII;
2241 desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_LUN | SVPD_ID_TYPE_T10;
2242 desc->length = sizeof(*t10id) + devid_len;
2243 if (lun == NULL || (val = ctl_get_opt(&lun->be_lun->options,
2244 "vendor")) == NULL) {
2245 strncpy((char *)t10id->vendor, CTL_VENDOR, sizeof(t10id->vendor));
2247 memset(t10id->vendor, ' ', sizeof(t10id->vendor));
2248 strncpy(t10id->vendor, val,
2249 min(sizeof(t10id->vendor), strlen(val)));
2253 * If we've actually got a backend, copy the device id from the
2254 * per-LUN data. Otherwise, set it to all spaces.
2258 * Copy the backend's LUN ID.
2260 strncpy((char *)t10id->vendor_spec_id,
2261 (char *)lun->be_lun->device_id, devid_len);
2264 * No backend, set this to spaces.
2266 memset(t10id->vendor_spec_id, 0x20, devid_len);
2270 * desc1 is for the unique LUN name.
2272 * XXX: According to SPC-3, LUN must report the same ID through
2273 * all the ports. The code below, however, reports the
2274 * ID only via iSCSI.
2276 desc1->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_UTF8;
2277 desc1->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_LUN |
2278 SVPD_ID_TYPE_SCSI_NAME;
2279 desc1->length = lun_name_len;
2282 * Find the per-target LUN number.
2284 for (i = 0; i < CTL_MAX_LUNS; i++) {
2285 if (cs->cs_target->ct_luns[i] == lun->lun)
2288 KASSERT(i < CTL_MAX_LUNS,
2289 ("lun %jd not found", (uintmax_t)lun->lun));
2290 ret = snprintf(desc1->identifier, lun_name_len, "%s,lun,%d",
2291 cs->cs_target->ct_name, i);
2292 KASSERT(ret > 0 && ret <= lun_name_len, ("bad snprintf"));
2294 KASSERT(lun_name_len == 0, ("no lun, but lun_name_len != 0"));
2298 * desc2 is for the Target Name.
2300 desc2->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_UTF8;
2301 desc2->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_TARGET |
2302 SVPD_ID_TYPE_SCSI_NAME;
2303 desc2->length = wwnn_len;
2304 snprintf(desc2->identifier, wwnn_len, "%s", cs->cs_target->ct_name);
2307 * desc3 is for the WWPN which is a port asscociation.
2309 desc3->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_UTF8;
2310 desc3->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT |
2311 SVPD_ID_TYPE_SCSI_NAME;
2312 desc3->length = wwpn_len;
2313 snprintf(desc3->identifier, wwpn_len, "%s,t,0x%4.4x",
2314 cs->cs_target->ct_name, cs->cs_portal_group_tag);
2317 * desc3 is for the Relative Target Port(type 4h) identifier
2319 desc4->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_BINARY;
2320 desc4->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT |
2321 SVPD_ID_TYPE_RELTARG;
2323 desc4->identifier[3] = 1;
2326 * desc4 is for the Target Port Group(type 5h) identifier
2328 desc5->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_BINARY;
2329 desc5->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT |
2330 SVPD_ID_TYPE_TPORTGRP;
2332 desc5->identifier[3] = 1;
2334 ctsio->scsi_status = SCSI_STATUS_OK;
2336 ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
2337 ctsio->be_move_done = ctl_config_move_done;
2338 ctl_datamove((union ctl_io *)ctsio);
2340 return (CTL_RETVAL_COMPLETE);
2344 cfiscsi_target_hold(struct cfiscsi_target *ct)
2347 refcount_acquire(&ct->ct_refcount);
2351 cfiscsi_target_release(struct cfiscsi_target *ct)
2353 struct cfiscsi_softc *softc;
2355 softc = ct->ct_softc;
2356 mtx_lock(&softc->lock);
2357 if (refcount_release(&ct->ct_refcount)) {
2358 TAILQ_REMOVE(&softc->targets, ct, ct_next);
2359 mtx_unlock(&softc->lock);
2360 if (ct->ct_state != CFISCSI_TARGET_STATE_INVALID) {
2361 ct->ct_state = CFISCSI_TARGET_STATE_INVALID;
2362 if (ctl_port_deregister(&ct->ct_port) != 0)
2363 printf("%s: ctl_port_deregister() failed\n",
2366 free(ct, M_CFISCSI);
2370 mtx_unlock(&softc->lock);
2373 static struct cfiscsi_target *
2374 cfiscsi_target_find(struct cfiscsi_softc *softc, const char *name)
2376 struct cfiscsi_target *ct;
2378 mtx_lock(&softc->lock);
2379 TAILQ_FOREACH(ct, &softc->targets, ct_next) {
2380 if (strcmp(name, ct->ct_name) != 0 ||
2381 ct->ct_state != CFISCSI_TARGET_STATE_ACTIVE)
2383 cfiscsi_target_hold(ct);
2384 mtx_unlock(&softc->lock);
2387 mtx_unlock(&softc->lock);
2392 static struct cfiscsi_target *
2393 cfiscsi_target_find_or_create(struct cfiscsi_softc *softc, const char *name,
2396 struct cfiscsi_target *ct, *newct;
2399 if (name[0] == '\0' || strlen(name) >= CTL_ISCSI_NAME_LEN)
2402 newct = malloc(sizeof(*newct), M_CFISCSI, M_WAITOK | M_ZERO);
2404 mtx_lock(&softc->lock);
2405 TAILQ_FOREACH(ct, &softc->targets, ct_next) {
2406 if (strcmp(name, ct->ct_name) != 0 ||
2407 ct->ct_state == CFISCSI_TARGET_STATE_INVALID)
2409 cfiscsi_target_hold(ct);
2410 mtx_unlock(&softc->lock);
2411 free(newct, M_CFISCSI);
2415 for (i = 0; i < CTL_MAX_LUNS; i++)
2416 newct->ct_luns[i] = -1;
2418 strlcpy(newct->ct_name, name, sizeof(newct->ct_name));
2420 strlcpy(newct->ct_alias, alias, sizeof(newct->ct_alias));
2421 refcount_init(&newct->ct_refcount, 1);
2422 newct->ct_softc = softc;
2423 TAILQ_INSERT_TAIL(&softc->targets, newct, ct_next);
2424 mtx_unlock(&softc->lock);
2430 * Takes LUN from the target space and returns LUN from the CTL space.
2433 cfiscsi_map_lun(void *arg, uint32_t lun)
2435 struct cfiscsi_session *cs;
2439 if (lun >= CTL_MAX_LUNS) {
2440 CFISCSI_DEBUG("requested lun number %d is higher "
2441 "than maximum %d", lun, CTL_MAX_LUNS - 1);
2442 return (0xffffffff);
2445 if (cs->cs_target->ct_luns[lun] < 0)
2446 return (0xffffffff);
2448 return (cs->cs_target->ct_luns[lun]);
2452 cfiscsi_target_set_lun(struct cfiscsi_target *ct,
2453 unsigned long lun_id, unsigned long ctl_lun_id)
2456 if (lun_id >= CTL_MAX_LUNS) {
2457 CFISCSI_WARN("requested lun number %ld is higher "
2458 "than maximum %d", lun_id, CTL_MAX_LUNS - 1);
2462 if (ct->ct_luns[lun_id] >= 0) {
2464 * CTL calls cfiscsi_lun_enable() twice for each LUN - once
2465 * when the LUN is created, and a second time just before
2466 * the port is brought online; don't emit warnings
2469 if (ct->ct_luns[lun_id] == ctl_lun_id)
2471 CFISCSI_WARN("lun %ld already allocated", lun_id);
2476 CFISCSI_DEBUG("adding mapping for lun %ld, target %s "
2477 "to ctl lun %ld", lun_id, ct->ct_name, ctl_lun_id);
2480 ct->ct_luns[lun_id] = ctl_lun_id;
2486 cfiscsi_lun_enable(void *arg, struct ctl_id target_id, int lun_id)
2488 struct cfiscsi_softc *softc;
2489 struct cfiscsi_target *ct;
2490 const char *target = NULL;
2491 const char *lun = NULL;
2494 ct = (struct cfiscsi_target *)arg;
2495 softc = ct->ct_softc;
2497 target = ctl_get_opt(&control_softc->ctl_luns[lun_id]->be_lun->options,
2499 lun = ctl_get_opt(&control_softc->ctl_luns[lun_id]->be_lun->options,
2502 if (target == NULL && lun == NULL)
2505 if (target == NULL || lun == NULL) {
2506 CFISCSI_WARN("lun added with cfiscsi_target, but without "
2507 "cfiscsi_lun, or the other way around; ignoring");
2511 if (strcmp(target, ct->ct_name) != 0)
2514 tmp = strtoul(lun, NULL, 10);
2515 cfiscsi_target_set_lun(ct, tmp, lun_id);
2520 cfiscsi_lun_disable(void *arg, struct ctl_id target_id, int lun_id)
2522 struct cfiscsi_softc *softc;
2523 struct cfiscsi_target *ct;
2526 ct = (struct cfiscsi_target *)arg;
2527 softc = ct->ct_softc;
2529 mtx_lock(&softc->lock);
2530 for (i = 0; i < CTL_MAX_LUNS; i++) {
2531 if (ct->ct_luns[i] < 0)
2533 if (ct->ct_luns[i] != lun_id)
2535 ct->ct_luns[lun_id] = -1;
2538 mtx_unlock(&softc->lock);
2543 cfiscsi_datamove_in(union ctl_io *io)
2545 struct cfiscsi_session *cs;
2546 struct icl_pdu *request, *response;
2547 const struct iscsi_bhs_scsi_command *bhssc;
2548 struct iscsi_bhs_data_in *bhsdi;
2549 struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
2550 size_t len, expected_len, sg_len, buffer_offset;
2551 const char *sg_addr;
2552 int ctl_sg_count, error, i;
2554 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2555 cs = PDU_SESSION(request);
2557 bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs;
2558 KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
2559 ISCSI_BHS_OPCODE_SCSI_COMMAND,
2560 ("bhssc->bhssc_opcode != ISCSI_BHS_OPCODE_SCSI_COMMAND"));
2562 if (io->scsiio.kern_sg_entries > 0) {
2563 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
2564 ctl_sg_count = io->scsiio.kern_sg_entries;
2566 ctl_sglist = &ctl_sg_entry;
2567 ctl_sglist->addr = io->scsiio.kern_data_ptr;
2568 ctl_sglist->len = io->scsiio.kern_data_len;
2573 * This is the total amount of data to be transferred within the current
2574 * SCSI command. We need to record it so that we can properly report
2575 * underflow/underflow.
2577 PDU_TOTAL_TRANSFER_LEN(request) = io->scsiio.kern_total_len;
2580 * This is the offset within the current SCSI command; for the first
2581 * call to cfiscsi_datamove() it will be 0, and for subsequent ones
2582 * it will be the sum of lengths of previous ones.
2584 buffer_offset = io->scsiio.kern_rel_offset;
2587 * This is the transfer length expected by the initiator. In theory,
2588 * it could be different from the correct amount of data from the SCSI
2589 * point of view, even if that doesn't make any sense.
2591 expected_len = ntohl(bhssc->bhssc_expected_data_transfer_length);
2593 if (expected_len != io->scsiio.kern_total_len) {
2594 CFISCSI_SESSION_DEBUG(cs, "expected transfer length %zd, "
2595 "actual length %zd", expected_len,
2596 (size_t)io->scsiio.kern_total_len);
2600 if (buffer_offset >= expected_len) {
2602 CFISCSI_SESSION_DEBUG(cs, "buffer_offset = %zd, "
2603 "already sent the expected len", buffer_offset);
2605 io->scsiio.be_move_done(io);
2615 if (response == NULL) {
2616 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
2617 if (response == 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);
2625 bhsdi = (struct iscsi_bhs_data_in *)response->ip_bhs;
2626 bhsdi->bhsdi_opcode = ISCSI_BHS_OPCODE_SCSI_DATA_IN;
2627 bhsdi->bhsdi_initiator_task_tag =
2628 bhssc->bhssc_initiator_task_tag;
2629 bhsdi->bhsdi_datasn = htonl(PDU_EXPDATASN(request));
2630 PDU_EXPDATASN(request)++;
2631 bhsdi->bhsdi_buffer_offset = htonl(buffer_offset);
2634 KASSERT(i < ctl_sg_count, ("i >= ctl_sg_count"));
2636 sg_addr = ctl_sglist[i].addr;
2637 sg_len = ctl_sglist[i].len;
2638 KASSERT(sg_len > 0, ("sg_len <= 0"));
2644 * Truncate to maximum data segment length.
2646 KASSERT(response->ip_data_len < cs->cs_max_data_segment_length,
2647 ("ip_data_len %zd >= max_data_segment_length %zd",
2648 response->ip_data_len, cs->cs_max_data_segment_length));
2649 if (response->ip_data_len + len >
2650 cs->cs_max_data_segment_length) {
2651 len = cs->cs_max_data_segment_length -
2652 response->ip_data_len;
2653 KASSERT(len <= sg_len, ("len %zd > sg_len %zd",
2658 * Truncate to expected data transfer length.
2660 KASSERT(buffer_offset + response->ip_data_len < expected_len,
2661 ("buffer_offset %zd + ip_data_len %zd >= expected_len %zd",
2662 buffer_offset, response->ip_data_len, expected_len));
2663 if (buffer_offset + response->ip_data_len + len > expected_len) {
2664 CFISCSI_SESSION_DEBUG(cs, "truncating from %zd "
2665 "to expected data transfer length %zd",
2666 buffer_offset + response->ip_data_len + len, expected_len);
2667 len = expected_len - (buffer_offset + response->ip_data_len);
2668 KASSERT(len <= sg_len, ("len %zd > sg_len %zd",
2672 error = icl_pdu_append_data(response, sg_addr, len, M_NOWAIT);
2674 CFISCSI_SESSION_WARN(cs, "failed to "
2675 "allocate memory; dropping connection");
2676 icl_pdu_free(response);
2677 ctl_set_busy(&io->scsiio);
2678 io->scsiio.be_move_done(io);
2679 cfiscsi_session_terminate(cs);
2685 KASSERT(buffer_offset + request->ip_data_len <= expected_len,
2686 ("buffer_offset %zd + ip_data_len %zd > expected_len %zd",
2687 buffer_offset, request->ip_data_len, expected_len));
2688 if (buffer_offset + request->ip_data_len == expected_len) {
2690 * Already have the amount of data the initiator wanted.
2697 * End of scatter-gather segment;
2698 * proceed to the next one...
2700 if (i == ctl_sg_count - 1) {
2702 * ... unless this was the last one.
2709 if (response->ip_data_len == cs->cs_max_data_segment_length) {
2711 * Can't stuff more data into the current PDU;
2712 * queue it. Note that's not enough to check
2713 * for kern_data_resid == 0 instead; there
2714 * may be several Data-In PDUs for the final
2715 * call to cfiscsi_datamove(), and we want
2716 * to set the F flag only on the last of them.
2718 buffer_offset += response->ip_data_len;
2719 if (buffer_offset == io->scsiio.kern_total_len ||
2720 buffer_offset == expected_len)
2721 bhsdi->bhsdi_flags |= BHSDI_FLAGS_F;
2722 cfiscsi_pdu_queue(response);
2727 if (response != NULL) {
2728 buffer_offset += response->ip_data_len;
2729 if (buffer_offset == io->scsiio.kern_total_len ||
2730 buffer_offset == expected_len)
2731 bhsdi->bhsdi_flags |= BHSDI_FLAGS_F;
2732 KASSERT(response->ip_data_len > 0, ("sending empty Data-In"));
2733 cfiscsi_pdu_queue(response);
2736 io->scsiio.be_move_done(io);
2740 cfiscsi_datamove_out(union ctl_io *io)
2742 struct cfiscsi_session *cs;
2743 struct icl_pdu *request, *response;
2744 const struct iscsi_bhs_scsi_command *bhssc;
2745 struct iscsi_bhs_r2t *bhsr2t;
2746 struct cfiscsi_data_wait *cdw;
2747 uint32_t target_transfer_tag;
2750 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2751 cs = PDU_SESSION(request);
2753 bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs;
2754 KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
2755 ISCSI_BHS_OPCODE_SCSI_COMMAND,
2756 ("bhssc->bhssc_opcode != ISCSI_BHS_OPCODE_SCSI_COMMAND"));
2759 * We need to record it so that we can properly report
2760 * underflow/underflow.
2762 PDU_TOTAL_TRANSFER_LEN(request) = io->scsiio.kern_total_len;
2765 * We hadn't received anything during this datamove yet.
2767 io->scsiio.ext_data_filled = 0;
2769 target_transfer_tag =
2770 atomic_fetchadd_32(&cs->cs_target_transfer_tag, 1);
2773 CFISCSI_SESSION_DEBUG(cs, "expecting Data-Out with initiator "
2774 "task tag 0x%x, target transfer tag 0x%x",
2775 bhssc->bhssc_initiator_task_tag, target_transfer_tag);
2777 cdw = uma_zalloc(cfiscsi_data_wait_zone, M_NOWAIT | M_ZERO);
2779 CFISCSI_SESSION_WARN(cs, "failed to "
2780 "allocate memory; dropping connection");
2781 ctl_set_busy(&io->scsiio);
2782 io->scsiio.be_move_done(io);
2783 cfiscsi_session_terminate(cs);
2786 cdw->cdw_ctl_io = io;
2787 cdw->cdw_target_transfer_tag = target_transfer_tag;
2788 cdw->cdw_initiator_task_tag = bhssc->bhssc_initiator_task_tag;
2790 if (cs->cs_immediate_data && io->scsiio.kern_rel_offset <
2791 icl_pdu_data_segment_length(request)) {
2792 done = cfiscsi_handle_data_segment(request, cdw);
2794 uma_zfree(cfiscsi_data_wait_zone, cdw);
2795 io->scsiio.be_move_done(io);
2800 CFISCSI_SESSION_LOCK(cs);
2801 TAILQ_INSERT_TAIL(&cs->cs_waiting_for_data_out, cdw, cdw_next);
2802 CFISCSI_SESSION_UNLOCK(cs);
2805 * XXX: We should limit the number of outstanding R2T PDUs
2806 * per task to MaxOutstandingR2T.
2808 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
2809 if (response == NULL) {
2810 CFISCSI_SESSION_WARN(cs, "failed to "
2811 "allocate memory; dropping connection");
2812 ctl_set_busy(&io->scsiio);
2813 io->scsiio.be_move_done(io);
2814 cfiscsi_session_terminate(cs);
2817 bhsr2t = (struct iscsi_bhs_r2t *)response->ip_bhs;
2818 bhsr2t->bhsr2t_opcode = ISCSI_BHS_OPCODE_R2T;
2819 bhsr2t->bhsr2t_flags = 0x80;
2820 bhsr2t->bhsr2t_lun = bhssc->bhssc_lun;
2821 bhsr2t->bhsr2t_initiator_task_tag = bhssc->bhssc_initiator_task_tag;
2822 bhsr2t->bhsr2t_target_transfer_tag = target_transfer_tag;
2824 * XXX: Here we assume that cfiscsi_datamove() won't ever
2825 * be running concurrently on several CPUs for a given
2828 bhsr2t->bhsr2t_r2tsn = htonl(PDU_R2TSN(request));
2829 PDU_R2TSN(request)++;
2831 * This is the offset within the current SCSI command;
2832 * i.e. for the first call of datamove(), it will be 0,
2833 * and for subsequent ones it will be the sum of lengths
2836 * The ext_data_filled is to account for unsolicited
2837 * (immediate) data that might have already arrived.
2839 bhsr2t->bhsr2t_buffer_offset =
2840 htonl(io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled);
2842 * This is the total length (sum of S/G lengths) this call
2843 * to cfiscsi_datamove() is supposed to handle.
2845 * XXX: Limit it to MaxBurstLength.
2847 bhsr2t->bhsr2t_desired_data_transfer_length =
2848 htonl(io->scsiio.kern_data_len - io->scsiio.ext_data_filled);
2849 cfiscsi_pdu_queue(response);
2853 cfiscsi_datamove(union ctl_io *io)
2856 if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN)
2857 cfiscsi_datamove_in(io);
2859 cfiscsi_datamove_out(io);
2863 cfiscsi_scsi_command_done(union ctl_io *io)
2865 struct icl_pdu *request, *response;
2866 struct iscsi_bhs_scsi_command *bhssc;
2867 struct iscsi_bhs_scsi_response *bhssr;
2869 struct cfiscsi_data_wait *cdw;
2871 struct cfiscsi_session *cs;
2872 uint16_t sense_length;
2874 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2875 cs = PDU_SESSION(request);
2876 bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs;
2877 KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
2878 ISCSI_BHS_OPCODE_SCSI_COMMAND,
2879 ("replying to wrong opcode 0x%x", bhssc->bhssc_opcode));
2881 //CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x",
2882 // bhssc->bhssc_initiator_task_tag);
2885 CFISCSI_SESSION_LOCK(cs);
2886 TAILQ_FOREACH(cdw, &cs->cs_waiting_for_data_out, cdw_next)
2887 KASSERT(bhssc->bhssc_initiator_task_tag !=
2888 cdw->cdw_initiator_task_tag, ("dangling cdw"));
2889 CFISCSI_SESSION_UNLOCK(cs);
2893 * Do not return status for aborted commands.
2894 * There are exceptions, but none supported by CTL yet.
2896 if (io->io_hdr.status == CTL_CMD_ABORTED) {
2898 icl_pdu_free(request);
2902 response = cfiscsi_pdu_new_response(request, M_WAITOK);
2903 bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs;
2904 bhssr->bhssr_opcode = ISCSI_BHS_OPCODE_SCSI_RESPONSE;
2905 bhssr->bhssr_flags = 0x80;
2907 * XXX: We don't deal with bidirectional under/overflows;
2908 * does anything actually support those?
2910 if (PDU_TOTAL_TRANSFER_LEN(request) <
2911 ntohl(bhssc->bhssc_expected_data_transfer_length)) {
2912 bhssr->bhssr_flags |= BHSSR_FLAGS_RESIDUAL_UNDERFLOW;
2913 bhssr->bhssr_residual_count =
2914 htonl(ntohl(bhssc->bhssc_expected_data_transfer_length) -
2915 PDU_TOTAL_TRANSFER_LEN(request));
2916 //CFISCSI_SESSION_DEBUG(cs, "underflow; residual count %d",
2917 // ntohl(bhssr->bhssr_residual_count));
2918 } else if (PDU_TOTAL_TRANSFER_LEN(request) >
2919 ntohl(bhssc->bhssc_expected_data_transfer_length)) {
2920 bhssr->bhssr_flags |= BHSSR_FLAGS_RESIDUAL_OVERFLOW;
2921 bhssr->bhssr_residual_count =
2922 htonl(PDU_TOTAL_TRANSFER_LEN(request) -
2923 ntohl(bhssc->bhssc_expected_data_transfer_length));
2924 //CFISCSI_SESSION_DEBUG(cs, "overflow; residual count %d",
2925 // ntohl(bhssr->bhssr_residual_count));
2927 bhssr->bhssr_response = BHSSR_RESPONSE_COMMAND_COMPLETED;
2928 bhssr->bhssr_status = io->scsiio.scsi_status;
2929 bhssr->bhssr_initiator_task_tag = bhssc->bhssc_initiator_task_tag;
2930 bhssr->bhssr_expdatasn = htonl(PDU_EXPDATASN(request));
2932 if (io->scsiio.sense_len > 0) {
2934 CFISCSI_SESSION_DEBUG(cs, "returning %d bytes of sense data",
2935 io->scsiio.sense_len);
2937 sense_length = htons(io->scsiio.sense_len);
2938 icl_pdu_append_data(response,
2939 &sense_length, sizeof(sense_length), M_WAITOK);
2940 icl_pdu_append_data(response,
2941 &io->scsiio.sense_data, io->scsiio.sense_len, M_WAITOK);
2945 icl_pdu_free(request);
2946 cfiscsi_pdu_queue(response);
2950 cfiscsi_task_management_done(union ctl_io *io)
2952 struct icl_pdu *request, *response;
2953 struct iscsi_bhs_task_management_request *bhstmr;
2954 struct iscsi_bhs_task_management_response *bhstmr2;
2955 struct cfiscsi_data_wait *cdw, *tmpcdw;
2956 struct cfiscsi_session *cs;
2958 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2959 cs = PDU_SESSION(request);
2960 bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs;
2961 KASSERT((bhstmr->bhstmr_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
2962 ISCSI_BHS_OPCODE_TASK_REQUEST,
2963 ("replying to wrong opcode 0x%x", bhstmr->bhstmr_opcode));
2966 CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x; referenced task tag 0x%x",
2967 bhstmr->bhstmr_initiator_task_tag,
2968 bhstmr->bhstmr_referenced_task_tag);
2971 if ((bhstmr->bhstmr_function & ~0x80) ==
2972 BHSTMR_FUNCTION_ABORT_TASK) {
2974 * Make sure we no longer wait for Data-Out for this command.
2976 CFISCSI_SESSION_LOCK(cs);
2977 TAILQ_FOREACH_SAFE(cdw,
2978 &cs->cs_waiting_for_data_out, cdw_next, tmpcdw) {
2979 if (bhstmr->bhstmr_referenced_task_tag !=
2980 cdw->cdw_initiator_task_tag)
2984 CFISCSI_SESSION_DEBUG(cs, "removing csw for initiator task "
2985 "tag 0x%x", bhstmr->bhstmr_initiator_task_tag);
2987 TAILQ_REMOVE(&cs->cs_waiting_for_data_out,
2989 cdw->cdw_ctl_io->scsiio.be_move_done(cdw->cdw_ctl_io);
2990 uma_zfree(cfiscsi_data_wait_zone, cdw);
2992 CFISCSI_SESSION_UNLOCK(cs);
2995 response = cfiscsi_pdu_new_response(request, M_WAITOK);
2996 bhstmr2 = (struct iscsi_bhs_task_management_response *)
2998 bhstmr2->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_RESPONSE;
2999 bhstmr2->bhstmr_flags = 0x80;
3000 if (io->io_hdr.status == CTL_SUCCESS) {
3001 bhstmr2->bhstmr_response = BHSTMR_RESPONSE_FUNCTION_COMPLETE;
3004 * XXX: How to figure out what exactly went wrong? iSCSI spec
3005 * expects us to provide detailed error, e.g. "Task does
3006 * not exist" or "LUN does not exist".
3008 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED");
3009 bhstmr2->bhstmr_response =
3010 BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED;
3012 bhstmr2->bhstmr_initiator_task_tag = bhstmr->bhstmr_initiator_task_tag;
3015 icl_pdu_free(request);
3016 cfiscsi_pdu_queue(response);
3020 cfiscsi_done(union ctl_io *io)
3022 struct icl_pdu *request;
3023 struct cfiscsi_session *cs;
3025 KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE),
3026 ("invalid CTL status %#x", io->io_hdr.status));
3028 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
3029 if (request == NULL) {
3031 * Implicit task termination has just completed; nothing to do.
3036 cs = PDU_SESSION(request);
3037 refcount_release(&cs->cs_outstanding_ctl_pdus);
3039 switch (request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) {
3040 case ISCSI_BHS_OPCODE_SCSI_COMMAND:
3041 cfiscsi_scsi_command_done(io);
3043 case ISCSI_BHS_OPCODE_TASK_REQUEST:
3044 cfiscsi_task_management_done(io);
3047 panic("cfiscsi_done called with wrong opcode 0x%x",
3048 request->ip_bhs->bhs_opcode);