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/capsicum.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 <cam/ctl/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_info(void *arg, struct sbuf *sb);
153 static int cfiscsi_lun_enable(void *arg,
154 struct ctl_id target_id, int lun_id);
155 static int cfiscsi_lun_disable(void *arg,
156 struct ctl_id target_id, int lun_id);
157 static int cfiscsi_ioctl(struct cdev *dev,
158 u_long cmd, caddr_t addr, int flag, struct thread *td);
159 static void cfiscsi_datamove(union ctl_io *io);
160 static void cfiscsi_datamove_in(union ctl_io *io);
161 static void cfiscsi_datamove_out(union ctl_io *io);
162 static void cfiscsi_done(union ctl_io *io);
163 static bool cfiscsi_pdu_update_cmdsn(const struct icl_pdu *request);
164 static void cfiscsi_pdu_handle_nop_out(struct icl_pdu *request);
165 static void cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request);
166 static void cfiscsi_pdu_handle_task_request(struct icl_pdu *request);
167 static void cfiscsi_pdu_handle_data_out(struct icl_pdu *request);
168 static void cfiscsi_pdu_handle_logout_request(struct icl_pdu *request);
169 static void cfiscsi_session_terminate(struct cfiscsi_session *cs);
170 static struct cfiscsi_target *cfiscsi_target_find(struct cfiscsi_softc
171 *softc, const char *name, uint16_t tag);
172 static struct cfiscsi_target *cfiscsi_target_find_or_create(
173 struct cfiscsi_softc *softc, const char *name, const char *alias,
175 static void cfiscsi_target_release(struct cfiscsi_target *ct);
176 static void cfiscsi_session_delete(struct cfiscsi_session *cs);
178 static struct cfiscsi_softc cfiscsi_softc;
179 extern struct ctl_softc *control_softc;
181 static struct ctl_frontend cfiscsi_frontend =
184 .init = cfiscsi_init,
185 .ioctl = cfiscsi_ioctl,
187 CTL_FRONTEND_DECLARE(ctlcfiscsi, cfiscsi_frontend);
188 MODULE_DEPEND(ctlcfiscsi, icl, 1, 1, 1);
190 static struct icl_pdu *
191 cfiscsi_pdu_new_response(struct icl_pdu *request, int flags)
194 return (icl_pdu_new(request->ip_conn, flags));
198 cfiscsi_pdu_update_cmdsn(const struct icl_pdu *request)
200 const struct iscsi_bhs_scsi_command *bhssc;
201 struct cfiscsi_session *cs;
202 uint32_t cmdsn, expstatsn;
204 cs = PDU_SESSION(request);
207 * Every incoming PDU - not just NOP-Out - resets the ping timer.
208 * The purpose of the timeout is to reset the connection when it stalls;
209 * we don't want this to happen when NOP-In or NOP-Out ends up delayed
217 * Data-Out PDUs don't contain CmdSN.
219 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
220 ISCSI_BHS_OPCODE_SCSI_DATA_OUT)
224 * We're only using fields common for all the request
225 * (initiator -> target) PDUs.
227 bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs;
228 cmdsn = ntohl(bhssc->bhssc_cmdsn);
229 expstatsn = ntohl(bhssc->bhssc_expstatsn);
231 CFISCSI_SESSION_LOCK(cs);
233 if (expstatsn != cs->cs_statsn) {
234 CFISCSI_SESSION_DEBUG(cs, "received PDU with ExpStatSN %d, "
235 "while current StatSN is %d", expstatsn,
240 if ((request->ip_bhs->bhs_opcode & ISCSI_BHS_OPCODE_IMMEDIATE) == 0) {
242 * The target MUST silently ignore any non-immediate command
243 * outside of this range.
245 if (ISCSI_SNLT(cmdsn, cs->cs_cmdsn) ||
246 ISCSI_SNGT(cmdsn, cs->cs_cmdsn + maxcmdsn_delta)) {
247 CFISCSI_SESSION_UNLOCK(cs);
248 CFISCSI_SESSION_WARN(cs, "received PDU with CmdSN %u, "
249 "while expected %u", cmdsn, cs->cs_cmdsn);
254 * We don't support multiple connections now, so any
255 * discontinuity in CmdSN means lost PDUs. Since we don't
256 * support PDU retransmission -- terminate the connection.
258 if (cmdsn != cs->cs_cmdsn) {
259 CFISCSI_SESSION_UNLOCK(cs);
260 CFISCSI_SESSION_WARN(cs, "received PDU with CmdSN %u, "
261 "while expected %u; dropping connection",
262 cmdsn, cs->cs_cmdsn);
263 cfiscsi_session_terminate(cs);
269 CFISCSI_SESSION_UNLOCK(cs);
275 cfiscsi_pdu_handle(struct icl_pdu *request)
277 struct cfiscsi_session *cs;
280 cs = PDU_SESSION(request);
282 ignore = cfiscsi_pdu_update_cmdsn(request);
284 icl_pdu_free(request);
289 * Handle the PDU; this includes e.g. receiving the remaining
290 * part of PDU and submitting the SCSI command to CTL
291 * or queueing a reply. The handling routine is responsible
292 * for freeing the PDU when it's no longer needed.
294 switch (request->ip_bhs->bhs_opcode &
295 ~ISCSI_BHS_OPCODE_IMMEDIATE) {
296 case ISCSI_BHS_OPCODE_NOP_OUT:
297 cfiscsi_pdu_handle_nop_out(request);
299 case ISCSI_BHS_OPCODE_SCSI_COMMAND:
300 cfiscsi_pdu_handle_scsi_command(request);
302 case ISCSI_BHS_OPCODE_TASK_REQUEST:
303 cfiscsi_pdu_handle_task_request(request);
305 case ISCSI_BHS_OPCODE_SCSI_DATA_OUT:
306 cfiscsi_pdu_handle_data_out(request);
308 case ISCSI_BHS_OPCODE_LOGOUT_REQUEST:
309 cfiscsi_pdu_handle_logout_request(request);
312 CFISCSI_SESSION_WARN(cs, "received PDU with unsupported "
313 "opcode 0x%x; dropping connection",
314 request->ip_bhs->bhs_opcode);
315 icl_pdu_free(request);
316 cfiscsi_session_terminate(cs);
322 cfiscsi_receive_callback(struct icl_pdu *request)
324 struct cfiscsi_session *cs;
326 cs = PDU_SESSION(request);
328 #ifdef ICL_KERNEL_PROXY
329 if (cs->cs_waiting_for_ctld || cs->cs_login_phase) {
330 if (cs->cs_login_pdu == NULL)
331 cs->cs_login_pdu = request;
333 icl_pdu_free(request);
334 cv_signal(&cs->cs_login_cv);
339 cfiscsi_pdu_handle(request);
343 cfiscsi_error_callback(struct icl_conn *ic)
345 struct cfiscsi_session *cs;
347 cs = CONN_SESSION(ic);
349 CFISCSI_SESSION_WARN(cs, "connection error; dropping connection");
350 cfiscsi_session_terminate(cs);
354 cfiscsi_pdu_prepare(struct icl_pdu *response)
356 struct cfiscsi_session *cs;
357 struct iscsi_bhs_scsi_response *bhssr;
358 bool advance_statsn = true;
360 cs = PDU_SESSION(response);
362 CFISCSI_SESSION_LOCK_ASSERT(cs);
365 * We're only using fields common for all the response
366 * (target -> initiator) PDUs.
368 bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs;
371 * 10.8.3: "The StatSN for this connection is not advanced
372 * after this PDU is sent."
374 if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_R2T)
375 advance_statsn = false;
378 * 10.19.2: "However, when the Initiator Task Tag is set to 0xffffffff,
379 * StatSN for the connection is not advanced after this PDU is sent."
381 if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_NOP_IN &&
382 bhssr->bhssr_initiator_task_tag == 0xffffffff)
383 advance_statsn = false;
386 * See the comment below - StatSN is not meaningful and must
389 if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_SCSI_DATA_IN &&
390 (bhssr->bhssr_flags & BHSDI_FLAGS_S) == 0)
391 advance_statsn = false;
394 * 10.7.3: "The fields StatSN, Status, and Residual Count
395 * only have meaningful content if the S bit is set to 1."
397 if (bhssr->bhssr_opcode != ISCSI_BHS_OPCODE_SCSI_DATA_IN ||
398 (bhssr->bhssr_flags & BHSDI_FLAGS_S))
399 bhssr->bhssr_statsn = htonl(cs->cs_statsn);
400 bhssr->bhssr_expcmdsn = htonl(cs->cs_cmdsn);
401 bhssr->bhssr_maxcmdsn = htonl(cs->cs_cmdsn + maxcmdsn_delta);
410 cfiscsi_pdu_queue(struct icl_pdu *response)
412 struct cfiscsi_session *cs;
414 cs = PDU_SESSION(response);
416 CFISCSI_SESSION_LOCK(cs);
417 cfiscsi_pdu_prepare(response);
418 icl_pdu_queue(response);
419 CFISCSI_SESSION_UNLOCK(cs);
423 cfiscsi_decode_lun(uint64_t encoded)
429 * The LUN field in iSCSI PDUs may look like an ordinary 64 bit number,
430 * but is in fact an evil, multidimensional structure defined
431 * in SCSI Architecture Model 5 (SAM-5), section 4.6.
433 memcpy(lun, &encoded, sizeof(lun));
434 switch (lun[0] & 0xC0) {
436 if ((lun[0] & 0x3f) != 0 || lun[2] != 0 || lun[3] != 0 ||
437 lun[4] != 0 || lun[5] != 0 || lun[6] != 0 || lun[7] != 0) {
438 CFISCSI_WARN("malformed LUN "
439 "(peripheral device addressing method): 0x%jx",
447 if (lun[2] != 0 || lun[3] != 0 || lun[4] != 0 || lun[5] != 0 ||
448 lun[6] != 0 || lun[7] != 0) {
449 CFISCSI_WARN("malformed LUN "
450 "(flat address space addressing method): 0x%jx",
455 result = ((lun[0] & 0x3f) << 8) + lun[1];
458 if (lun[0] != 0xD2 || lun[4] != 0 || lun[5] != 0 ||
459 lun[6] != 0 || lun[7] != 0) {
460 CFISCSI_WARN("malformed LUN (extended flat "
461 "address space addressing method): 0x%jx",
466 result = (lun[1] << 16) + (lun[2] << 8) + lun[3];
468 CFISCSI_WARN("unsupported LUN format 0x%jx",
478 cfiscsi_pdu_handle_nop_out(struct icl_pdu *request)
480 struct cfiscsi_session *cs;
481 struct iscsi_bhs_nop_out *bhsno;
482 struct iscsi_bhs_nop_in *bhsni;
483 struct icl_pdu *response;
488 cs = PDU_SESSION(request);
489 bhsno = (struct iscsi_bhs_nop_out *)request->ip_bhs;
491 if (bhsno->bhsno_initiator_task_tag == 0xffffffff) {
493 * Nothing to do, iscsi_pdu_update_statsn() already
494 * zeroed the timeout.
496 icl_pdu_free(request);
500 datasize = icl_pdu_data_segment_length(request);
502 data = malloc(datasize, M_CFISCSI, M_NOWAIT | M_ZERO);
504 CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
505 "dropping connection");
506 icl_pdu_free(request);
507 cfiscsi_session_terminate(cs);
510 icl_pdu_get_data(request, 0, data, datasize);
513 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
514 if (response == NULL) {
515 CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
516 "droppping connection");
517 free(data, M_CFISCSI);
518 icl_pdu_free(request);
519 cfiscsi_session_terminate(cs);
522 bhsni = (struct iscsi_bhs_nop_in *)response->ip_bhs;
523 bhsni->bhsni_opcode = ISCSI_BHS_OPCODE_NOP_IN;
524 bhsni->bhsni_flags = 0x80;
525 bhsni->bhsni_initiator_task_tag = bhsno->bhsno_initiator_task_tag;
526 bhsni->bhsni_target_transfer_tag = 0xffffffff;
528 error = icl_pdu_append_data(response, data, datasize, M_NOWAIT);
530 CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
531 "dropping connection");
532 free(data, M_CFISCSI);
533 icl_pdu_free(request);
534 icl_pdu_free(response);
535 cfiscsi_session_terminate(cs);
538 free(data, M_CFISCSI);
541 icl_pdu_free(request);
542 cfiscsi_pdu_queue(response);
546 cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request)
548 struct iscsi_bhs_scsi_command *bhssc;
549 struct cfiscsi_session *cs;
553 cs = PDU_SESSION(request);
554 bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs;
555 //CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x",
556 // bhssc->bhssc_initiator_task_tag);
558 if (request->ip_data_len > 0 && cs->cs_immediate_data == false) {
559 CFISCSI_SESSION_WARN(cs, "unsolicited data with "
560 "ImmediateData=No; dropping connection");
561 icl_pdu_free(request);
562 cfiscsi_session_terminate(cs);
565 io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
567 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = request;
568 io->io_hdr.io_type = CTL_IO_SCSI;
569 io->io_hdr.nexus.initid.id = cs->cs_ctl_initid;
570 io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
571 io->io_hdr.nexus.targ_target.id = 0;
572 io->io_hdr.nexus.targ_lun = cfiscsi_decode_lun(bhssc->bhssc_lun);
573 io->scsiio.tag_num = bhssc->bhssc_initiator_task_tag;
574 switch ((bhssc->bhssc_flags & BHSSC_FLAGS_ATTR)) {
575 case BHSSC_FLAGS_ATTR_UNTAGGED:
576 io->scsiio.tag_type = CTL_TAG_UNTAGGED;
578 case BHSSC_FLAGS_ATTR_SIMPLE:
579 io->scsiio.tag_type = CTL_TAG_SIMPLE;
581 case BHSSC_FLAGS_ATTR_ORDERED:
582 io->scsiio.tag_type = CTL_TAG_ORDERED;
584 case BHSSC_FLAGS_ATTR_HOQ:
585 io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
587 case BHSSC_FLAGS_ATTR_ACA:
588 io->scsiio.tag_type = CTL_TAG_ACA;
591 io->scsiio.tag_type = CTL_TAG_UNTAGGED;
592 CFISCSI_SESSION_WARN(cs, "unhandled tag type %d",
593 bhssc->bhssc_flags & BHSSC_FLAGS_ATTR);
596 io->scsiio.cdb_len = sizeof(bhssc->bhssc_cdb); /* Which is 16. */
597 memcpy(io->scsiio.cdb, bhssc->bhssc_cdb, sizeof(bhssc->bhssc_cdb));
598 refcount_acquire(&cs->cs_outstanding_ctl_pdus);
599 error = ctl_queue(io);
600 if (error != CTL_RETVAL_COMPLETE) {
601 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d; "
602 "dropping connection", error);
604 refcount_release(&cs->cs_outstanding_ctl_pdus);
605 icl_pdu_free(request);
606 cfiscsi_session_terminate(cs);
611 cfiscsi_pdu_handle_task_request(struct icl_pdu *request)
613 struct iscsi_bhs_task_management_request *bhstmr;
614 struct iscsi_bhs_task_management_response *bhstmr2;
615 struct icl_pdu *response;
616 struct cfiscsi_session *cs;
620 cs = PDU_SESSION(request);
621 bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs;
622 io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
624 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = request;
625 io->io_hdr.io_type = CTL_IO_TASK;
626 io->io_hdr.nexus.initid.id = cs->cs_ctl_initid;
627 io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
628 io->io_hdr.nexus.targ_target.id = 0;
629 io->io_hdr.nexus.targ_lun = cfiscsi_decode_lun(bhstmr->bhstmr_lun);
630 io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */
632 switch (bhstmr->bhstmr_function & ~0x80) {
633 case BHSTMR_FUNCTION_ABORT_TASK:
635 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_ABORT_TASK");
637 io->taskio.task_action = CTL_TASK_ABORT_TASK;
638 io->taskio.tag_num = bhstmr->bhstmr_referenced_task_tag;
640 case BHSTMR_FUNCTION_ABORT_TASK_SET:
642 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_ABORT_TASK_SET");
644 io->taskio.task_action = CTL_TASK_ABORT_TASK_SET;
646 case BHSTMR_FUNCTION_LOGICAL_UNIT_RESET:
648 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_LOGICAL_UNIT_RESET");
650 io->taskio.task_action = CTL_TASK_LUN_RESET;
652 case BHSTMR_FUNCTION_TARGET_WARM_RESET:
654 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_TARGET_WARM_RESET");
656 io->taskio.task_action = CTL_TASK_TARGET_RESET;
659 CFISCSI_SESSION_DEBUG(cs, "unsupported function 0x%x",
660 bhstmr->bhstmr_function & ~0x80);
663 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
664 if (response == NULL) {
665 CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
666 "dropping connection");
667 icl_pdu_free(request);
668 cfiscsi_session_terminate(cs);
671 bhstmr2 = (struct iscsi_bhs_task_management_response *)
673 bhstmr2->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_RESPONSE;
674 bhstmr2->bhstmr_flags = 0x80;
675 bhstmr2->bhstmr_response =
676 BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED;
677 bhstmr2->bhstmr_initiator_task_tag =
678 bhstmr->bhstmr_initiator_task_tag;
679 icl_pdu_free(request);
680 cfiscsi_pdu_queue(response);
684 refcount_acquire(&cs->cs_outstanding_ctl_pdus);
685 error = ctl_queue(io);
686 if (error != CTL_RETVAL_COMPLETE) {
687 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d; "
688 "dropping connection", error);
690 refcount_release(&cs->cs_outstanding_ctl_pdus);
691 icl_pdu_free(request);
692 cfiscsi_session_terminate(cs);
697 cfiscsi_handle_data_segment(struct icl_pdu *request, struct cfiscsi_data_wait *cdw)
699 struct iscsi_bhs_data_out *bhsdo;
700 struct cfiscsi_session *cs;
701 struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
702 size_t copy_len, len, off, buffer_offset;
706 cs = PDU_SESSION(request);
708 KASSERT((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
709 ISCSI_BHS_OPCODE_SCSI_DATA_OUT ||
710 (request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
711 ISCSI_BHS_OPCODE_SCSI_COMMAND,
712 ("bad opcode 0x%x", request->ip_bhs->bhs_opcode));
715 * We're only using fields common for Data-Out and SCSI Command PDUs.
717 bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs;
719 io = cdw->cdw_ctl_io;
720 KASSERT((io->io_hdr.flags & CTL_FLAG_DATA_MASK) != CTL_FLAG_DATA_IN,
721 ("CTL_FLAG_DATA_IN"));
724 CFISCSI_SESSION_DEBUG(cs, "received %zd bytes out of %d",
725 request->ip_data_len, io->scsiio.kern_total_len);
728 if (io->scsiio.kern_sg_entries > 0) {
729 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
730 ctl_sg_count = io->scsiio.kern_sg_entries;
732 ctl_sglist = &ctl_sg_entry;
733 ctl_sglist->addr = io->scsiio.kern_data_ptr;
734 ctl_sglist->len = io->scsiio.kern_data_len;
738 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
739 ISCSI_BHS_OPCODE_SCSI_DATA_OUT)
740 buffer_offset = ntohl(bhsdo->bhsdo_buffer_offset);
743 len = icl_pdu_data_segment_length(request);
746 * Make sure the offset, as sent by the initiator, matches the offset
747 * we're supposed to be at in the scatter-gather list.
750 io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled ||
751 buffer_offset + len <=
752 io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled) {
753 CFISCSI_SESSION_WARN(cs, "received bad buffer offset %zd, "
754 "expected %zd; dropping connection", buffer_offset,
755 (size_t)io->scsiio.kern_rel_offset +
756 (size_t)io->scsiio.ext_data_filled);
757 ctl_set_data_phase_error(&io->scsiio);
758 cfiscsi_session_terminate(cs);
763 * This is the offset within the PDU data segment, as opposed
764 * to buffer_offset, which is the offset within the task (SCSI
767 off = io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled -
771 * Iterate over the scatter/gather segments, filling them with data
772 * from the PDU data segment. Note that this can get called multiple
773 * times for one SCSI command; the cdw structure holds state for the
774 * scatter/gather list.
777 KASSERT(cdw->cdw_sg_index < ctl_sg_count,
778 ("cdw->cdw_sg_index >= ctl_sg_count"));
779 if (cdw->cdw_sg_len == 0) {
780 cdw->cdw_sg_addr = ctl_sglist[cdw->cdw_sg_index].addr;
781 cdw->cdw_sg_len = ctl_sglist[cdw->cdw_sg_index].len;
783 KASSERT(off <= len, ("len > off"));
784 copy_len = len - off;
785 if (copy_len > cdw->cdw_sg_len)
786 copy_len = cdw->cdw_sg_len;
788 icl_pdu_get_data(request, off, cdw->cdw_sg_addr, copy_len);
789 cdw->cdw_sg_addr += copy_len;
790 cdw->cdw_sg_len -= copy_len;
792 io->scsiio.ext_data_filled += copy_len;
794 if (cdw->cdw_sg_len == 0) {
796 * End of current segment.
798 if (cdw->cdw_sg_index == ctl_sg_count - 1) {
800 * Last segment in scatter/gather list.
809 * End of PDU payload.
817 * In case of unsolicited data, it's possible that the buffer
818 * provided by CTL is smaller than negotiated FirstBurstLength.
819 * Just ignore the superfluous data; will ask for them with R2T
820 * on next call to cfiscsi_datamove().
822 * This obviously can only happen with SCSI Command PDU.
824 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
825 ISCSI_BHS_OPCODE_SCSI_COMMAND)
828 CFISCSI_SESSION_WARN(cs, "received too much data: got %zd bytes, "
829 "expected %zd; dropping connection",
830 icl_pdu_data_segment_length(request), off);
831 ctl_set_data_phase_error(&io->scsiio);
832 cfiscsi_session_terminate(cs);
836 if (io->scsiio.ext_data_filled == cdw->cdw_r2t_end &&
837 (bhsdo->bhsdo_flags & BHSDO_FLAGS_F) == 0) {
838 CFISCSI_SESSION_WARN(cs, "got the final packet without "
839 "the F flag; flags = 0x%x; dropping connection",
841 ctl_set_data_phase_error(&io->scsiio);
842 cfiscsi_session_terminate(cs);
846 if (io->scsiio.ext_data_filled != cdw->cdw_r2t_end &&
847 (bhsdo->bhsdo_flags & BHSDO_FLAGS_F) != 0) {
848 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
849 ISCSI_BHS_OPCODE_SCSI_DATA_OUT) {
850 CFISCSI_SESSION_WARN(cs, "got the final packet, but the "
851 "transmitted size was %zd bytes instead of %d; "
852 "dropping connection",
853 (size_t)io->scsiio.ext_data_filled,
855 ctl_set_data_phase_error(&io->scsiio);
856 cfiscsi_session_terminate(cs);
860 * For SCSI Command PDU, this just means we need to
861 * solicit more data by sending R2T.
867 if (io->scsiio.ext_data_filled == cdw->cdw_r2t_end) {
869 CFISCSI_SESSION_DEBUG(cs, "no longer expecting Data-Out with target "
870 "transfer tag 0x%x", cdw->cdw_target_transfer_tag);
880 cfiscsi_pdu_handle_data_out(struct icl_pdu *request)
882 struct iscsi_bhs_data_out *bhsdo;
883 struct cfiscsi_session *cs;
884 struct cfiscsi_data_wait *cdw = NULL;
888 cs = PDU_SESSION(request);
889 bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs;
891 CFISCSI_SESSION_LOCK(cs);
892 TAILQ_FOREACH(cdw, &cs->cs_waiting_for_data_out, cdw_next) {
894 CFISCSI_SESSION_DEBUG(cs, "have ttt 0x%x, itt 0x%x; looking for "
895 "ttt 0x%x, itt 0x%x",
896 bhsdo->bhsdo_target_transfer_tag,
897 bhsdo->bhsdo_initiator_task_tag,
898 cdw->cdw_target_transfer_tag, cdw->cdw_initiator_task_tag));
900 if (bhsdo->bhsdo_target_transfer_tag ==
901 cdw->cdw_target_transfer_tag)
904 CFISCSI_SESSION_UNLOCK(cs);
906 CFISCSI_SESSION_WARN(cs, "data transfer tag 0x%x, initiator task tag "
907 "0x%x, not found; dropping connection",
908 bhsdo->bhsdo_target_transfer_tag, bhsdo->bhsdo_initiator_task_tag);
909 icl_pdu_free(request);
910 cfiscsi_session_terminate(cs);
914 if (cdw->cdw_datasn != ntohl(bhsdo->bhsdo_datasn)) {
915 CFISCSI_SESSION_WARN(cs, "received Data-Out PDU with "
916 "DataSN %u, while expected %u; dropping connection",
917 ntohl(bhsdo->bhsdo_datasn), cdw->cdw_datasn);
918 icl_pdu_free(request);
919 cfiscsi_session_terminate(cs);
924 io = cdw->cdw_ctl_io;
925 KASSERT((io->io_hdr.flags & CTL_FLAG_DATA_MASK) != CTL_FLAG_DATA_IN,
926 ("CTL_FLAG_DATA_IN"));
928 done = cfiscsi_handle_data_segment(request, cdw);
930 CFISCSI_SESSION_LOCK(cs);
931 TAILQ_REMOVE(&cs->cs_waiting_for_data_out, cdw, cdw_next);
932 CFISCSI_SESSION_UNLOCK(cs);
933 done = (io->scsiio.ext_data_filled != cdw->cdw_r2t_end ||
934 io->scsiio.ext_data_filled == io->scsiio.kern_data_len);
935 uma_zfree(cfiscsi_data_wait_zone, cdw);
937 io->scsiio.be_move_done(io);
939 cfiscsi_datamove_out(io);
942 icl_pdu_free(request);
946 cfiscsi_pdu_handle_logout_request(struct icl_pdu *request)
948 struct iscsi_bhs_logout_request *bhslr;
949 struct iscsi_bhs_logout_response *bhslr2;
950 struct icl_pdu *response;
951 struct cfiscsi_session *cs;
953 cs = PDU_SESSION(request);
954 bhslr = (struct iscsi_bhs_logout_request *)request->ip_bhs;
955 switch (bhslr->bhslr_reason & 0x7f) {
956 case BHSLR_REASON_CLOSE_SESSION:
957 case BHSLR_REASON_CLOSE_CONNECTION:
958 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
959 if (response == NULL) {
960 CFISCSI_SESSION_DEBUG(cs, "failed to allocate memory");
961 icl_pdu_free(request);
962 cfiscsi_session_terminate(cs);
965 bhslr2 = (struct iscsi_bhs_logout_response *)response->ip_bhs;
966 bhslr2->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_RESPONSE;
967 bhslr2->bhslr_flags = 0x80;
968 bhslr2->bhslr_response = BHSLR_RESPONSE_CLOSED_SUCCESSFULLY;
969 bhslr2->bhslr_initiator_task_tag =
970 bhslr->bhslr_initiator_task_tag;
971 icl_pdu_free(request);
972 cfiscsi_pdu_queue(response);
973 cfiscsi_session_terminate(cs);
975 case BHSLR_REASON_REMOVE_FOR_RECOVERY:
976 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
977 if (response == NULL) {
978 CFISCSI_SESSION_WARN(cs,
979 "failed to allocate memory; dropping connection");
980 icl_pdu_free(request);
981 cfiscsi_session_terminate(cs);
984 bhslr2 = (struct iscsi_bhs_logout_response *)response->ip_bhs;
985 bhslr2->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_RESPONSE;
986 bhslr2->bhslr_flags = 0x80;
987 bhslr2->bhslr_response = BHSLR_RESPONSE_RECOVERY_NOT_SUPPORTED;
988 bhslr2->bhslr_initiator_task_tag =
989 bhslr->bhslr_initiator_task_tag;
990 icl_pdu_free(request);
991 cfiscsi_pdu_queue(response);
994 CFISCSI_SESSION_WARN(cs, "invalid reason 0%x; dropping connection",
995 bhslr->bhslr_reason);
996 icl_pdu_free(request);
997 cfiscsi_session_terminate(cs);
1003 cfiscsi_callout(void *context)
1006 struct iscsi_bhs_nop_in *bhsni;
1007 struct cfiscsi_session *cs;
1011 if (cs->cs_terminating)
1014 callout_schedule(&cs->cs_callout, 1 * hz);
1016 atomic_add_int(&cs->cs_timeout, 1);
1018 #ifdef ICL_KERNEL_PROXY
1019 if (cs->cs_waiting_for_ctld || cs->cs_login_phase) {
1020 if (login_timeout > 0 && cs->cs_timeout > login_timeout) {
1021 CFISCSI_SESSION_WARN(cs, "login timed out after "
1022 "%d seconds; dropping connection", cs->cs_timeout);
1023 cfiscsi_session_terminate(cs);
1029 if (ping_timeout <= 0) {
1031 * Pings are disabled. Don't send NOP-In in this case;
1032 * user might have disabled pings to work around problems
1033 * with certain initiators that can't properly handle
1034 * NOP-In, such as iPXE. Reset the timeout, to avoid
1035 * triggering reconnection, should the user decide to
1042 if (cs->cs_timeout >= ping_timeout) {
1043 CFISCSI_SESSION_WARN(cs, "no ping reply (NOP-Out) after %d seconds; "
1044 "dropping connection", ping_timeout);
1045 cfiscsi_session_terminate(cs);
1050 * If the ping was reset less than one second ago - which means
1051 * that we've received some PDU during the last second - assume
1052 * the traffic flows correctly and don't bother sending a NOP-Out.
1054 * (It's 2 - one for one second, and one for incrementing is_timeout
1055 * earlier in this routine.)
1057 if (cs->cs_timeout < 2)
1060 cp = icl_pdu_new(cs->cs_conn, M_NOWAIT);
1062 CFISCSI_SESSION_WARN(cs, "failed to allocate memory");
1065 bhsni = (struct iscsi_bhs_nop_in *)cp->ip_bhs;
1066 bhsni->bhsni_opcode = ISCSI_BHS_OPCODE_NOP_IN;
1067 bhsni->bhsni_flags = 0x80;
1068 bhsni->bhsni_initiator_task_tag = 0xffffffff;
1070 cfiscsi_pdu_queue(cp);
1074 cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs)
1076 struct cfiscsi_data_wait *cdw;
1078 int error, last, wait;
1080 if (cs->cs_target == NULL)
1081 return; /* No target yet, so nothing to do. */
1082 io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
1084 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = cs;
1085 io->io_hdr.io_type = CTL_IO_TASK;
1086 io->io_hdr.nexus.initid.id = cs->cs_ctl_initid;
1087 io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
1088 io->io_hdr.nexus.targ_target.id = 0;
1089 io->io_hdr.nexus.targ_lun = 0;
1090 io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */
1091 io->taskio.task_action = CTL_TASK_I_T_NEXUS_RESET;
1092 wait = cs->cs_outstanding_ctl_pdus;
1093 refcount_acquire(&cs->cs_outstanding_ctl_pdus);
1094 error = ctl_queue(io);
1095 if (error != CTL_RETVAL_COMPLETE) {
1096 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d", error);
1097 refcount_release(&cs->cs_outstanding_ctl_pdus);
1101 CFISCSI_SESSION_LOCK(cs);
1102 while ((cdw = TAILQ_FIRST(&cs->cs_waiting_for_data_out)) != NULL) {
1103 TAILQ_REMOVE(&cs->cs_waiting_for_data_out, cdw, cdw_next);
1104 CFISCSI_SESSION_UNLOCK(cs);
1106 * Set nonzero port status; this prevents backends from
1107 * assuming that the data transfer actually succeeded
1108 * and writing uninitialized data to disk.
1110 cdw->cdw_ctl_io->scsiio.io_hdr.port_status = 42;
1111 cdw->cdw_ctl_io->scsiio.be_move_done(cdw->cdw_ctl_io);
1112 uma_zfree(cfiscsi_data_wait_zone, cdw);
1113 CFISCSI_SESSION_LOCK(cs);
1115 CFISCSI_SESSION_UNLOCK(cs);
1118 * Wait for CTL to terminate all the tasks.
1121 CFISCSI_SESSION_WARN(cs,
1122 "waiting for CTL to terminate %d tasks", wait);
1124 refcount_acquire(&cs->cs_outstanding_ctl_pdus);
1125 last = refcount_release(&cs->cs_outstanding_ctl_pdus);
1128 tsleep(__DEVOLATILE(void *, &cs->cs_outstanding_ctl_pdus),
1129 0, "cfiscsi_terminate", hz / 100);
1132 CFISCSI_SESSION_WARN(cs, "tasks terminated");
1136 cfiscsi_maintenance_thread(void *arg)
1138 struct cfiscsi_session *cs;
1143 CFISCSI_SESSION_LOCK(cs);
1144 if (cs->cs_terminating == false)
1145 cv_wait(&cs->cs_maintenance_cv, &cs->cs_lock);
1146 CFISCSI_SESSION_UNLOCK(cs);
1148 if (cs->cs_terminating) {
1151 * We used to wait up to 30 seconds to deliver queued
1152 * PDUs to the initiator. We also tried hard to deliver
1153 * SCSI Responses for the aborted PDUs. We don't do
1154 * that anymore. We might need to revisit that.
1156 callout_drain(&cs->cs_callout);
1157 icl_conn_close(cs->cs_conn);
1160 * At this point ICL receive thread is no longer
1161 * running; no new tasks can be queued.
1163 cfiscsi_session_terminate_tasks(cs);
1164 cfiscsi_session_delete(cs);
1168 CFISCSI_SESSION_DEBUG(cs, "nothing to do");
1173 cfiscsi_session_terminate(struct cfiscsi_session *cs)
1176 if (cs->cs_terminating)
1178 cs->cs_terminating = true;
1179 cv_signal(&cs->cs_maintenance_cv);
1180 #ifdef ICL_KERNEL_PROXY
1181 cv_signal(&cs->cs_login_cv);
1186 cfiscsi_session_register_initiator(struct cfiscsi_session *cs)
1188 struct cfiscsi_target *ct;
1192 KASSERT(cs->cs_ctl_initid == -1, ("already registered"));
1195 name = strdup(cs->cs_initiator_id, M_CTL);
1196 i = ctl_add_initiator(&ct->ct_port, -1, 0, name);
1198 CFISCSI_SESSION_WARN(cs, "ctl_add_initiator failed with error %d",
1200 cs->cs_ctl_initid = -1;
1203 cs->cs_ctl_initid = i;
1205 CFISCSI_SESSION_DEBUG(cs, "added initiator id %d", i);
1212 cfiscsi_session_unregister_initiator(struct cfiscsi_session *cs)
1216 if (cs->cs_ctl_initid == -1)
1219 error = ctl_remove_initiator(&cs->cs_target->ct_port, cs->cs_ctl_initid);
1221 CFISCSI_SESSION_WARN(cs, "ctl_remove_initiator failed with error %d",
1224 cs->cs_ctl_initid = -1;
1227 static struct cfiscsi_session *
1228 cfiscsi_session_new(struct cfiscsi_softc *softc)
1230 struct cfiscsi_session *cs;
1233 cs = malloc(sizeof(*cs), M_CFISCSI, M_NOWAIT | M_ZERO);
1235 CFISCSI_WARN("malloc failed");
1238 cs->cs_ctl_initid = -1;
1240 refcount_init(&cs->cs_outstanding_ctl_pdus, 0);
1241 TAILQ_INIT(&cs->cs_waiting_for_data_out);
1242 mtx_init(&cs->cs_lock, "cfiscsi_lock", NULL, MTX_DEF);
1243 cv_init(&cs->cs_maintenance_cv, "cfiscsi_mt");
1244 #ifdef ICL_KERNEL_PROXY
1245 cv_init(&cs->cs_login_cv, "cfiscsi_login");
1248 cs->cs_conn = icl_conn_new("cfiscsi", &cs->cs_lock);
1249 cs->cs_conn->ic_receive = cfiscsi_receive_callback;
1250 cs->cs_conn->ic_error = cfiscsi_error_callback;
1251 cs->cs_conn->ic_prv0 = cs;
1253 error = kthread_add(cfiscsi_maintenance_thread, cs, NULL, NULL, 0, 0, "cfiscsimt");
1255 CFISCSI_SESSION_WARN(cs, "kthread_add(9) failed with error %d", error);
1256 free(cs, M_CFISCSI);
1260 mtx_lock(&softc->lock);
1261 cs->cs_id = ++softc->last_session_id;
1262 TAILQ_INSERT_TAIL(&softc->sessions, cs, cs_next);
1263 mtx_unlock(&softc->lock);
1266 * Start pinging the initiator.
1268 callout_init(&cs->cs_callout, 1);
1269 callout_reset(&cs->cs_callout, 1 * hz, cfiscsi_callout, cs);
1275 cfiscsi_session_delete(struct cfiscsi_session *cs)
1277 struct cfiscsi_softc *softc;
1279 softc = &cfiscsi_softc;
1281 KASSERT(cs->cs_outstanding_ctl_pdus == 0,
1282 ("destroying session with outstanding CTL pdus"));
1283 KASSERT(TAILQ_EMPTY(&cs->cs_waiting_for_data_out),
1284 ("destroying session with non-empty queue"));
1286 cfiscsi_session_unregister_initiator(cs);
1287 if (cs->cs_target != NULL)
1288 cfiscsi_target_release(cs->cs_target);
1289 icl_conn_close(cs->cs_conn);
1290 icl_conn_free(cs->cs_conn);
1292 mtx_lock(&softc->lock);
1293 TAILQ_REMOVE(&softc->sessions, cs, cs_next);
1294 cv_signal(&softc->sessions_cv);
1295 mtx_unlock(&softc->lock);
1297 free(cs, M_CFISCSI);
1303 struct cfiscsi_softc *softc;
1306 softc = &cfiscsi_softc;
1308 bzero(softc, sizeof(*softc));
1309 mtx_init(&softc->lock, "cfiscsi", NULL, MTX_DEF);
1311 cv_init(&softc->sessions_cv, "cfiscsi_sessions");
1312 #ifdef ICL_KERNEL_PROXY
1313 cv_init(&softc->accept_cv, "cfiscsi_accept");
1315 TAILQ_INIT(&softc->sessions);
1316 TAILQ_INIT(&softc->targets);
1318 cfiscsi_data_wait_zone = uma_zcreate("cfiscsi_data_wait",
1319 sizeof(struct cfiscsi_data_wait), NULL, NULL, NULL, NULL,
1325 #ifdef ICL_KERNEL_PROXY
1327 cfiscsi_accept(struct socket *so, struct sockaddr *sa, int portal_id)
1329 struct cfiscsi_session *cs;
1331 cs = cfiscsi_session_new(&cfiscsi_softc);
1333 CFISCSI_WARN("failed to create session");
1337 icl_conn_handoff_sock(cs->cs_conn, so);
1338 cs->cs_initiator_sa = sa;
1339 cs->cs_portal_id = portal_id;
1340 cs->cs_waiting_for_ctld = true;
1341 cv_signal(&cfiscsi_softc.accept_cv);
1346 cfiscsi_online(void *arg)
1348 struct cfiscsi_softc *softc;
1349 struct cfiscsi_target *ct;
1352 ct = (struct cfiscsi_target *)arg;
1353 softc = ct->ct_softc;
1355 mtx_lock(&softc->lock);
1356 if (ct->ct_online) {
1357 mtx_unlock(&softc->lock);
1361 online = softc->online++;
1362 mtx_unlock(&softc->lock);
1366 #ifdef ICL_KERNEL_PROXY
1367 if (softc->listener != NULL)
1368 icl_listen_free(softc->listener);
1369 softc->listener = icl_listen_new(cfiscsi_accept);
1374 cfiscsi_offline(void *arg)
1376 struct cfiscsi_softc *softc;
1377 struct cfiscsi_target *ct;
1378 struct cfiscsi_session *cs;
1381 ct = (struct cfiscsi_target *)arg;
1382 softc = ct->ct_softc;
1384 mtx_lock(&softc->lock);
1385 if (!ct->ct_online) {
1386 mtx_unlock(&softc->lock);
1390 online = --softc->online;
1392 TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1393 if (cs->cs_target == ct)
1394 cfiscsi_session_terminate(cs);
1397 TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1398 if (cs->cs_target == ct)
1402 cv_wait(&softc->sessions_cv, &softc->lock);
1403 } while (cs != NULL && ct->ct_online == 0);
1404 mtx_unlock(&softc->lock);
1408 #ifdef ICL_KERNEL_PROXY
1409 icl_listen_free(softc->listener);
1410 softc->listener = NULL;
1415 cfiscsi_info(void *arg, struct sbuf *sb)
1417 struct cfiscsi_target *ct = (struct cfiscsi_target *)arg;
1420 retval = sbuf_printf(sb, "\t<cfiscsi_state>%d</cfiscsi_state>\n",
1426 cfiscsi_ioctl_handoff(struct ctl_iscsi *ci)
1428 struct cfiscsi_softc *softc;
1429 struct cfiscsi_session *cs, *cs2;
1430 struct cfiscsi_target *ct;
1431 struct ctl_iscsi_handoff_params *cihp;
1434 cihp = (struct ctl_iscsi_handoff_params *)&(ci->data);
1435 softc = &cfiscsi_softc;
1437 CFISCSI_DEBUG("new connection from %s (%s) to %s",
1438 cihp->initiator_name, cihp->initiator_addr,
1441 ct = cfiscsi_target_find(softc, cihp->target_name,
1442 cihp->portal_group_tag);
1444 ci->status = CTL_ISCSI_ERROR;
1445 snprintf(ci->error_str, sizeof(ci->error_str),
1446 "%s: target not found", __func__);
1450 #ifdef ICL_KERNEL_PROXY
1451 if (cihp->socket > 0 && cihp->connection_id > 0) {
1452 snprintf(ci->error_str, sizeof(ci->error_str),
1453 "both socket and connection_id set");
1454 ci->status = CTL_ISCSI_ERROR;
1455 cfiscsi_target_release(ct);
1458 if (cihp->socket == 0) {
1459 mtx_lock(&cfiscsi_softc.lock);
1460 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
1461 if (cs->cs_id == cihp->connection_id)
1465 mtx_unlock(&cfiscsi_softc.lock);
1466 snprintf(ci->error_str, sizeof(ci->error_str),
1467 "connection not found");
1468 ci->status = CTL_ISCSI_ERROR;
1469 cfiscsi_target_release(ct);
1472 mtx_unlock(&cfiscsi_softc.lock);
1475 cs = cfiscsi_session_new(softc);
1477 ci->status = CTL_ISCSI_ERROR;
1478 snprintf(ci->error_str, sizeof(ci->error_str),
1479 "%s: cfiscsi_session_new failed", __func__);
1480 cfiscsi_target_release(ct);
1483 #ifdef ICL_KERNEL_PROXY
1488 * First PDU of Full Feature phase has the same CmdSN as the last
1489 * PDU from the Login Phase received from the initiator. Thus,
1492 cs->cs_cmdsn = cihp->cmdsn;
1493 cs->cs_statsn = cihp->statsn;
1494 cs->cs_max_data_segment_length = cihp->max_recv_data_segment_length;
1495 cs->cs_max_burst_length = cihp->max_burst_length;
1496 cs->cs_immediate_data = !!cihp->immediate_data;
1497 if (cihp->header_digest == CTL_ISCSI_DIGEST_CRC32C)
1498 cs->cs_conn->ic_header_crc32c = true;
1499 if (cihp->data_digest == CTL_ISCSI_DIGEST_CRC32C)
1500 cs->cs_conn->ic_data_crc32c = true;
1502 strlcpy(cs->cs_initiator_name,
1503 cihp->initiator_name, sizeof(cs->cs_initiator_name));
1504 strlcpy(cs->cs_initiator_addr,
1505 cihp->initiator_addr, sizeof(cs->cs_initiator_addr));
1506 strlcpy(cs->cs_initiator_alias,
1507 cihp->initiator_alias, sizeof(cs->cs_initiator_alias));
1508 memcpy(cs->cs_initiator_isid,
1509 cihp->initiator_isid, sizeof(cs->cs_initiator_isid));
1510 snprintf(cs->cs_initiator_id, sizeof(cs->cs_initiator_id),
1511 "%s,i,0x%02x%02x%02x%02x%02x%02x", cs->cs_initiator_name,
1512 cihp->initiator_isid[0], cihp->initiator_isid[1],
1513 cihp->initiator_isid[2], cihp->initiator_isid[3],
1514 cihp->initiator_isid[4], cihp->initiator_isid[5]);
1516 mtx_lock(&softc->lock);
1517 if (ct->ct_online == 0) {
1518 mtx_unlock(&softc->lock);
1519 cfiscsi_session_terminate(cs);
1520 cfiscsi_target_release(ct);
1521 ci->status = CTL_ISCSI_ERROR;
1522 snprintf(ci->error_str, sizeof(ci->error_str),
1523 "%s: port offline", __func__);
1527 mtx_unlock(&softc->lock);
1529 refcount_acquire(&cs->cs_outstanding_ctl_pdus);
1531 if (!cs->cs_terminating) {
1532 mtx_lock(&softc->lock);
1533 TAILQ_FOREACH(cs2, &softc->sessions, cs_next) {
1534 if (cs2 != cs && cs2->cs_tasks_aborted == false &&
1535 cs->cs_target == cs2->cs_target &&
1536 strcmp(cs->cs_initiator_id, cs2->cs_initiator_id) == 0) {
1537 cfiscsi_session_terminate(cs2);
1538 mtx_unlock(&softc->lock);
1539 pause("cfiscsi_reinstate", 1);
1543 mtx_unlock(&softc->lock);
1547 * Register initiator with CTL.
1549 cfiscsi_session_register_initiator(cs);
1551 #ifdef ICL_KERNEL_PROXY
1552 if (cihp->socket > 0) {
1554 error = icl_conn_handoff(cs->cs_conn, cihp->socket);
1556 cfiscsi_session_terminate(cs);
1557 refcount_release(&cs->cs_outstanding_ctl_pdus);
1558 ci->status = CTL_ISCSI_ERROR;
1559 snprintf(ci->error_str, sizeof(ci->error_str),
1560 "%s: icl_conn_handoff failed with error %d",
1564 #ifdef ICL_KERNEL_PROXY
1568 #ifdef ICL_KERNEL_PROXY
1569 cs->cs_login_phase = false;
1572 * First PDU of the Full Feature phase has likely already arrived.
1573 * We have to pick it up and execute properly.
1575 if (cs->cs_login_pdu != NULL) {
1576 CFISCSI_SESSION_DEBUG(cs, "picking up first PDU");
1577 cfiscsi_pdu_handle(cs->cs_login_pdu);
1578 cs->cs_login_pdu = NULL;
1582 refcount_release(&cs->cs_outstanding_ctl_pdus);
1583 ci->status = CTL_ISCSI_OK;
1587 cfiscsi_ioctl_list(struct ctl_iscsi *ci)
1589 struct ctl_iscsi_list_params *cilp;
1590 struct cfiscsi_session *cs;
1591 struct cfiscsi_softc *softc;
1595 cilp = (struct ctl_iscsi_list_params *)&(ci->data);
1596 softc = &cfiscsi_softc;
1598 sb = sbuf_new(NULL, NULL, cilp->alloc_len, SBUF_FIXEDLEN);
1600 ci->status = CTL_ISCSI_ERROR;
1601 snprintf(ci->error_str, sizeof(ci->error_str),
1602 "Unable to allocate %d bytes for iSCSI session list",
1607 sbuf_printf(sb, "<ctlislist>\n");
1608 mtx_lock(&softc->lock);
1609 TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1610 #ifdef ICL_KERNEL_PROXY
1611 if (cs->cs_target == NULL)
1614 error = sbuf_printf(sb, "<connection id=\"%d\">"
1615 "<initiator>%s</initiator>"
1616 "<initiator_addr>%s</initiator_addr>"
1617 "<initiator_alias>%s</initiator_alias>"
1618 "<target>%s</target>"
1619 "<target_alias>%s</target_alias>"
1620 "<target_portal_group_tag>%u</target_portal_group_tag>"
1621 "<header_digest>%s</header_digest>"
1622 "<data_digest>%s</data_digest>"
1623 "<max_data_segment_length>%zd</max_data_segment_length>"
1624 "<immediate_data>%d</immediate_data>"
1628 cs->cs_initiator_name, cs->cs_initiator_addr, cs->cs_initiator_alias,
1629 cs->cs_target->ct_name, cs->cs_target->ct_alias,
1630 cs->cs_target->ct_tag,
1631 cs->cs_conn->ic_header_crc32c ? "CRC32C" : "None",
1632 cs->cs_conn->ic_data_crc32c ? "CRC32C" : "None",
1633 cs->cs_max_data_segment_length,
1634 cs->cs_immediate_data,
1635 cs->cs_conn->ic_iser);
1639 mtx_unlock(&softc->lock);
1640 error = sbuf_printf(sb, "</ctlislist>\n");
1643 ci->status = CTL_ISCSI_LIST_NEED_MORE_SPACE;
1644 snprintf(ci->error_str, sizeof(ci->error_str),
1645 "Out of space, %d bytes is too small", cilp->alloc_len);
1650 error = copyout(sbuf_data(sb), cilp->conn_xml, sbuf_len(sb) + 1);
1651 cilp->fill_len = sbuf_len(sb) + 1;
1652 ci->status = CTL_ISCSI_OK;
1657 cfiscsi_ioctl_terminate(struct ctl_iscsi *ci)
1659 struct icl_pdu *response;
1660 struct iscsi_bhs_asynchronous_message *bhsam;
1661 struct ctl_iscsi_terminate_params *citp;
1662 struct cfiscsi_session *cs;
1663 struct cfiscsi_softc *softc;
1666 citp = (struct ctl_iscsi_terminate_params *)&(ci->data);
1667 softc = &cfiscsi_softc;
1669 mtx_lock(&softc->lock);
1670 TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1671 if (citp->all == 0 && cs->cs_id != citp->connection_id &&
1672 strcmp(cs->cs_initiator_name, citp->initiator_name) != 0 &&
1673 strcmp(cs->cs_initiator_addr, citp->initiator_addr) != 0)
1676 response = icl_pdu_new(cs->cs_conn, M_NOWAIT);
1677 if (response == NULL) {
1679 * Oh well. Just terminate the connection.
1682 bhsam = (struct iscsi_bhs_asynchronous_message *)
1684 bhsam->bhsam_opcode = ISCSI_BHS_OPCODE_ASYNC_MESSAGE;
1685 bhsam->bhsam_flags = 0x80;
1686 bhsam->bhsam_0xffffffff = 0xffffffff;
1687 bhsam->bhsam_async_event =
1688 BHSAM_EVENT_TARGET_TERMINATES_SESSION;
1689 cfiscsi_pdu_queue(response);
1691 cfiscsi_session_terminate(cs);
1694 mtx_unlock(&softc->lock);
1697 ci->status = CTL_ISCSI_SESSION_NOT_FOUND;
1698 snprintf(ci->error_str, sizeof(ci->error_str),
1699 "No matching connections found");
1703 ci->status = CTL_ISCSI_OK;
1707 cfiscsi_ioctl_logout(struct ctl_iscsi *ci)
1709 struct icl_pdu *response;
1710 struct iscsi_bhs_asynchronous_message *bhsam;
1711 struct ctl_iscsi_logout_params *cilp;
1712 struct cfiscsi_session *cs;
1713 struct cfiscsi_softc *softc;
1716 cilp = (struct ctl_iscsi_logout_params *)&(ci->data);
1717 softc = &cfiscsi_softc;
1719 mtx_lock(&softc->lock);
1720 TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
1721 if (cilp->all == 0 && cs->cs_id != cilp->connection_id &&
1722 strcmp(cs->cs_initiator_name, cilp->initiator_name) != 0 &&
1723 strcmp(cs->cs_initiator_addr, cilp->initiator_addr) != 0)
1726 response = icl_pdu_new(cs->cs_conn, M_NOWAIT);
1727 if (response == NULL) {
1728 ci->status = CTL_ISCSI_ERROR;
1729 snprintf(ci->error_str, sizeof(ci->error_str),
1730 "Unable to allocate memory");
1731 mtx_unlock(&softc->lock);
1735 (struct iscsi_bhs_asynchronous_message *)response->ip_bhs;
1736 bhsam->bhsam_opcode = ISCSI_BHS_OPCODE_ASYNC_MESSAGE;
1737 bhsam->bhsam_flags = 0x80;
1738 bhsam->bhsam_async_event = BHSAM_EVENT_TARGET_REQUESTS_LOGOUT;
1739 bhsam->bhsam_parameter3 = htons(10);
1740 cfiscsi_pdu_queue(response);
1743 mtx_unlock(&softc->lock);
1746 ci->status = CTL_ISCSI_SESSION_NOT_FOUND;
1747 snprintf(ci->error_str, sizeof(ci->error_str),
1748 "No matching connections found");
1752 ci->status = CTL_ISCSI_OK;
1755 #ifdef ICL_KERNEL_PROXY
1757 cfiscsi_ioctl_listen(struct ctl_iscsi *ci)
1759 struct ctl_iscsi_listen_params *cilp;
1760 struct sockaddr *sa;
1763 cilp = (struct ctl_iscsi_listen_params *)&(ci->data);
1765 if (cfiscsi_softc.listener == NULL) {
1766 CFISCSI_DEBUG("no listener");
1767 snprintf(ci->error_str, sizeof(ci->error_str), "no listener");
1768 ci->status = CTL_ISCSI_ERROR;
1772 error = getsockaddr(&sa, (void *)cilp->addr, cilp->addrlen);
1774 CFISCSI_DEBUG("getsockaddr, error %d", error);
1775 snprintf(ci->error_str, sizeof(ci->error_str), "getsockaddr failed");
1776 ci->status = CTL_ISCSI_ERROR;
1780 error = icl_listen_add(cfiscsi_softc.listener, cilp->iser, cilp->domain,
1781 cilp->socktype, cilp->protocol, sa, cilp->portal_id);
1784 CFISCSI_DEBUG("icl_listen_add, error %d", error);
1785 snprintf(ci->error_str, sizeof(ci->error_str),
1786 "icl_listen_add failed, error %d", error);
1787 ci->status = CTL_ISCSI_ERROR;
1791 ci->status = CTL_ISCSI_OK;
1795 cfiscsi_ioctl_accept(struct ctl_iscsi *ci)
1797 struct ctl_iscsi_accept_params *ciap;
1798 struct cfiscsi_session *cs;
1801 ciap = (struct ctl_iscsi_accept_params *)&(ci->data);
1803 mtx_lock(&cfiscsi_softc.lock);
1805 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
1806 if (cs->cs_waiting_for_ctld)
1811 error = cv_wait_sig(&cfiscsi_softc.accept_cv, &cfiscsi_softc.lock);
1813 mtx_unlock(&cfiscsi_softc.lock);
1814 snprintf(ci->error_str, sizeof(ci->error_str), "interrupted");
1815 ci->status = CTL_ISCSI_ERROR;
1819 mtx_unlock(&cfiscsi_softc.lock);
1821 cs->cs_waiting_for_ctld = false;
1822 cs->cs_login_phase = true;
1824 ciap->connection_id = cs->cs_id;
1825 ciap->portal_id = cs->cs_portal_id;
1826 ciap->initiator_addrlen = cs->cs_initiator_sa->sa_len;
1827 error = copyout(cs->cs_initiator_sa, ciap->initiator_addr,
1828 cs->cs_initiator_sa->sa_len);
1830 snprintf(ci->error_str, sizeof(ci->error_str),
1831 "copyout failed with error %d", error);
1832 ci->status = CTL_ISCSI_ERROR;
1836 ci->status = CTL_ISCSI_OK;
1840 cfiscsi_ioctl_send(struct ctl_iscsi *ci)
1842 struct ctl_iscsi_send_params *cisp;
1843 struct cfiscsi_session *cs;
1849 cisp = (struct ctl_iscsi_send_params *)&(ci->data);
1851 mtx_lock(&cfiscsi_softc.lock);
1852 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
1853 if (cs->cs_id == cisp->connection_id)
1857 mtx_unlock(&cfiscsi_softc.lock);
1858 snprintf(ci->error_str, sizeof(ci->error_str), "connection not found");
1859 ci->status = CTL_ISCSI_ERROR;
1862 mtx_unlock(&cfiscsi_softc.lock);
1865 if (cs->cs_login_phase == false)
1869 if (cs->cs_terminating) {
1870 snprintf(ci->error_str, sizeof(ci->error_str), "connection is terminating");
1871 ci->status = CTL_ISCSI_ERROR;
1875 datalen = cisp->data_segment_len;
1879 //if (datalen > CFISCSI_MAX_DATA_SEGMENT_LENGTH) {
1880 if (datalen > 65535) {
1881 snprintf(ci->error_str, sizeof(ci->error_str), "data segment too big");
1882 ci->status = CTL_ISCSI_ERROR;
1886 data = malloc(datalen, M_CFISCSI, M_WAITOK);
1887 error = copyin(cisp->data_segment, data, datalen);
1889 free(data, M_CFISCSI);
1890 snprintf(ci->error_str, sizeof(ci->error_str), "copyin error %d", error);
1891 ci->status = CTL_ISCSI_ERROR;
1896 ip = icl_pdu_new(cs->cs_conn, M_WAITOK);
1897 memcpy(ip->ip_bhs, cisp->bhs, sizeof(*ip->ip_bhs));
1899 icl_pdu_append_data(ip, data, datalen, M_WAITOK);
1900 free(data, M_CFISCSI);
1902 CFISCSI_SESSION_LOCK(cs);
1904 CFISCSI_SESSION_UNLOCK(cs);
1905 ci->status = CTL_ISCSI_OK;
1909 cfiscsi_ioctl_receive(struct ctl_iscsi *ci)
1911 struct ctl_iscsi_receive_params *cirp;
1912 struct cfiscsi_session *cs;
1917 cirp = (struct ctl_iscsi_receive_params *)&(ci->data);
1919 mtx_lock(&cfiscsi_softc.lock);
1920 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
1921 if (cs->cs_id == cirp->connection_id)
1925 mtx_unlock(&cfiscsi_softc.lock);
1926 snprintf(ci->error_str, sizeof(ci->error_str),
1927 "connection not found");
1928 ci->status = CTL_ISCSI_ERROR;
1931 mtx_unlock(&cfiscsi_softc.lock);
1934 if (is->is_login_phase == false)
1938 CFISCSI_SESSION_LOCK(cs);
1939 while (cs->cs_login_pdu == NULL && cs->cs_terminating == false) {
1940 error = cv_wait_sig(&cs->cs_login_cv, &cs->cs_lock);
1942 CFISCSI_SESSION_UNLOCK(cs);
1943 snprintf(ci->error_str, sizeof(ci->error_str),
1944 "interrupted by signal");
1945 ci->status = CTL_ISCSI_ERROR;
1950 if (cs->cs_terminating) {
1951 CFISCSI_SESSION_UNLOCK(cs);
1952 snprintf(ci->error_str, sizeof(ci->error_str),
1953 "connection terminating");
1954 ci->status = CTL_ISCSI_ERROR;
1957 ip = cs->cs_login_pdu;
1958 cs->cs_login_pdu = NULL;
1959 CFISCSI_SESSION_UNLOCK(cs);
1961 if (ip->ip_data_len > cirp->data_segment_len) {
1963 snprintf(ci->error_str, sizeof(ci->error_str),
1964 "data segment too big");
1965 ci->status = CTL_ISCSI_ERROR;
1969 copyout(ip->ip_bhs, cirp->bhs, sizeof(*ip->ip_bhs));
1970 if (ip->ip_data_len > 0) {
1971 data = malloc(ip->ip_data_len, M_CFISCSI, M_WAITOK);
1972 icl_pdu_get_data(ip, 0, data, ip->ip_data_len);
1973 copyout(data, cirp->data_segment, ip->ip_data_len);
1974 free(data, M_CFISCSI);
1978 ci->status = CTL_ISCSI_OK;
1981 #endif /* !ICL_KERNEL_PROXY */
1984 cfiscsi_ioctl_port_create(struct ctl_req *req)
1986 struct cfiscsi_target *ct;
1987 struct ctl_port *port;
1988 const char *target, *alias, *tags;
1989 struct scsi_vpd_id_descriptor *desc;
1991 int retval, len, idlen;
1994 ctl_init_opts(&opts, req->num_args, req->kern_args);
1995 target = ctl_get_opt(&opts, "cfiscsi_target");
1996 alias = ctl_get_opt(&opts, "cfiscsi_target_alias");
1997 tags = ctl_get_opt(&opts, "cfiscsi_portal_group_tag");
1998 if (target == NULL || tags == NULL) {
1999 req->status = CTL_LUN_ERROR;
2000 snprintf(req->error_str, sizeof(req->error_str),
2001 "Missing required argument");
2002 ctl_free_opts(&opts);
2005 tag = strtol(tags, (char **)NULL, 10);
2006 ct = cfiscsi_target_find_or_create(&cfiscsi_softc, target, alias, tag);
2008 req->status = CTL_LUN_ERROR;
2009 snprintf(req->error_str, sizeof(req->error_str),
2010 "failed to create target \"%s\"", target);
2011 ctl_free_opts(&opts);
2014 if (ct->ct_state == CFISCSI_TARGET_STATE_ACTIVE) {
2015 req->status = CTL_LUN_ERROR;
2016 snprintf(req->error_str, sizeof(req->error_str),
2017 "target \"%s\" already exists", target);
2018 cfiscsi_target_release(ct);
2019 ctl_free_opts(&opts);
2022 port = &ct->ct_port;
2023 if (ct->ct_state == CFISCSI_TARGET_STATE_DYING)
2026 port->frontend = &cfiscsi_frontend;
2027 port->port_type = CTL_PORT_ISCSI;
2028 /* XXX KDM what should the real number be here? */
2029 port->num_requested_ctl_io = 4096;
2030 port->port_name = "iscsi";
2031 port->physical_port = tag;
2032 port->virtual_port = ct->ct_target_id;
2033 port->port_online = cfiscsi_online;
2034 port->port_offline = cfiscsi_offline;
2035 port->port_info = cfiscsi_info;
2036 port->onoff_arg = ct;
2037 port->lun_enable = cfiscsi_lun_enable;
2038 port->lun_disable = cfiscsi_lun_disable;
2039 port->targ_lun_arg = ct;
2040 port->fe_datamove = cfiscsi_datamove;
2041 port->fe_done = cfiscsi_done;
2043 /* XXX KDM what should we report here? */
2044 /* XXX These should probably be fetched from CTL. */
2045 port->max_targets = 1;
2046 port->max_target_id = 15;
2048 port->options = opts;
2051 /* Generate Port ID. */
2052 idlen = strlen(target) + strlen(",t,0x0001") + 1;
2053 idlen = roundup2(idlen, 4);
2054 len = sizeof(struct scsi_vpd_device_id) + idlen;
2055 port->port_devid = malloc(sizeof(struct ctl_devid) + len,
2056 M_CTL, M_WAITOK | M_ZERO);
2057 port->port_devid->len = len;
2058 desc = (struct scsi_vpd_id_descriptor *)port->port_devid->data;
2059 desc->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_UTF8;
2060 desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT |
2061 SVPD_ID_TYPE_SCSI_NAME;
2062 desc->length = idlen;
2063 snprintf(desc->identifier, idlen, "%s,t,0x%4.4x", target, tag);
2065 /* Generate Target ID. */
2066 idlen = strlen(target) + 1;
2067 idlen = roundup2(idlen, 4);
2068 len = sizeof(struct scsi_vpd_device_id) + idlen;
2069 port->target_devid = malloc(sizeof(struct ctl_devid) + len,
2070 M_CTL, M_WAITOK | M_ZERO);
2071 port->target_devid->len = len;
2072 desc = (struct scsi_vpd_id_descriptor *)port->target_devid->data;
2073 desc->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_UTF8;
2074 desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_TARGET |
2075 SVPD_ID_TYPE_SCSI_NAME;
2076 desc->length = idlen;
2077 strlcpy(desc->identifier, target, idlen);
2079 retval = ctl_port_register(port);
2081 ctl_free_opts(&port->options);
2082 cfiscsi_target_release(ct);
2083 free(port->port_devid, M_CFISCSI);
2084 free(port->target_devid, M_CFISCSI);
2085 req->status = CTL_LUN_ERROR;
2086 snprintf(req->error_str, sizeof(req->error_str),
2087 "ctl_port_register() failed with error %d", retval);
2091 ct->ct_state = CFISCSI_TARGET_STATE_ACTIVE;
2092 req->status = CTL_LUN_OK;
2093 memcpy(req->kern_args[0].kvalue, &port->targ_port,
2094 sizeof(port->targ_port)); //XXX
2098 cfiscsi_ioctl_port_remove(struct ctl_req *req)
2100 struct cfiscsi_target *ct;
2101 const char *target, *tags;
2105 ctl_init_opts(&opts, req->num_args, req->kern_args);
2106 target = ctl_get_opt(&opts, "cfiscsi_target");
2107 tags = ctl_get_opt(&opts, "cfiscsi_portal_group_tag");
2108 if (target == NULL || tags == NULL) {
2109 ctl_free_opts(&opts);
2110 req->status = CTL_LUN_ERROR;
2111 snprintf(req->error_str, sizeof(req->error_str),
2112 "Missing required argument");
2115 tag = strtol(tags, (char **)NULL, 10);
2116 ct = cfiscsi_target_find(&cfiscsi_softc, target, tag);
2118 ctl_free_opts(&opts);
2119 req->status = CTL_LUN_ERROR;
2120 snprintf(req->error_str, sizeof(req->error_str),
2121 "can't find target \"%s\"", target);
2124 if (ct->ct_state != CFISCSI_TARGET_STATE_ACTIVE) {
2125 ctl_free_opts(&opts);
2126 req->status = CTL_LUN_ERROR;
2127 snprintf(req->error_str, sizeof(req->error_str),
2128 "target \"%s\" is already dying", target);
2131 ctl_free_opts(&opts);
2133 ct->ct_state = CFISCSI_TARGET_STATE_DYING;
2134 ctl_port_offline(&ct->ct_port);
2135 cfiscsi_target_release(ct);
2136 cfiscsi_target_release(ct);
2137 req->status = CTL_LUN_OK;
2141 cfiscsi_ioctl(struct cdev *dev,
2142 u_long cmd, caddr_t addr, int flag, struct thread *td)
2144 struct ctl_iscsi *ci;
2145 struct ctl_req *req;
2147 if (cmd == CTL_PORT_REQ) {
2148 req = (struct ctl_req *)addr;
2149 switch (req->reqtype) {
2150 case CTL_REQ_CREATE:
2151 cfiscsi_ioctl_port_create(req);
2153 case CTL_REQ_REMOVE:
2154 cfiscsi_ioctl_port_remove(req);
2157 req->status = CTL_LUN_ERROR;
2158 snprintf(req->error_str, sizeof(req->error_str),
2159 "Unsupported request type %d", req->reqtype);
2164 if (cmd != CTL_ISCSI)
2167 ci = (struct ctl_iscsi *)addr;
2169 case CTL_ISCSI_HANDOFF:
2170 cfiscsi_ioctl_handoff(ci);
2172 case CTL_ISCSI_LIST:
2173 cfiscsi_ioctl_list(ci);
2175 case CTL_ISCSI_TERMINATE:
2176 cfiscsi_ioctl_terminate(ci);
2178 case CTL_ISCSI_LOGOUT:
2179 cfiscsi_ioctl_logout(ci);
2181 #ifdef ICL_KERNEL_PROXY
2182 case CTL_ISCSI_LISTEN:
2183 cfiscsi_ioctl_listen(ci);
2185 case CTL_ISCSI_ACCEPT:
2186 cfiscsi_ioctl_accept(ci);
2188 case CTL_ISCSI_SEND:
2189 cfiscsi_ioctl_send(ci);
2191 case CTL_ISCSI_RECEIVE:
2192 cfiscsi_ioctl_receive(ci);
2195 case CTL_ISCSI_LISTEN:
2196 case CTL_ISCSI_ACCEPT:
2197 case CTL_ISCSI_SEND:
2198 case CTL_ISCSI_RECEIVE:
2199 ci->status = CTL_ISCSI_ERROR;
2200 snprintf(ci->error_str, sizeof(ci->error_str),
2201 "%s: CTL compiled without ICL_KERNEL_PROXY",
2204 #endif /* !ICL_KERNEL_PROXY */
2206 ci->status = CTL_ISCSI_ERROR;
2207 snprintf(ci->error_str, sizeof(ci->error_str),
2208 "%s: invalid iSCSI request type %d", __func__, ci->type);
2216 cfiscsi_target_hold(struct cfiscsi_target *ct)
2219 refcount_acquire(&ct->ct_refcount);
2223 cfiscsi_target_release(struct cfiscsi_target *ct)
2225 struct cfiscsi_softc *softc;
2227 softc = ct->ct_softc;
2228 mtx_lock(&softc->lock);
2229 if (refcount_release(&ct->ct_refcount)) {
2230 TAILQ_REMOVE(&softc->targets, ct, ct_next);
2231 mtx_unlock(&softc->lock);
2232 if (ct->ct_state != CFISCSI_TARGET_STATE_INVALID) {
2233 ct->ct_state = CFISCSI_TARGET_STATE_INVALID;
2234 if (ctl_port_deregister(&ct->ct_port) != 0)
2235 printf("%s: ctl_port_deregister() failed\n",
2238 free(ct, M_CFISCSI);
2242 mtx_unlock(&softc->lock);
2245 static struct cfiscsi_target *
2246 cfiscsi_target_find(struct cfiscsi_softc *softc, const char *name, uint16_t tag)
2248 struct cfiscsi_target *ct;
2250 mtx_lock(&softc->lock);
2251 TAILQ_FOREACH(ct, &softc->targets, ct_next) {
2252 if (ct->ct_tag != tag ||
2253 strcmp(name, ct->ct_name) != 0 ||
2254 ct->ct_state != CFISCSI_TARGET_STATE_ACTIVE)
2256 cfiscsi_target_hold(ct);
2257 mtx_unlock(&softc->lock);
2260 mtx_unlock(&softc->lock);
2265 static struct cfiscsi_target *
2266 cfiscsi_target_find_or_create(struct cfiscsi_softc *softc, const char *name,
2267 const char *alias, uint16_t tag)
2269 struct cfiscsi_target *ct, *newct;
2271 if (name[0] == '\0' || strlen(name) >= CTL_ISCSI_NAME_LEN)
2274 newct = malloc(sizeof(*newct), M_CFISCSI, M_WAITOK | M_ZERO);
2276 mtx_lock(&softc->lock);
2277 TAILQ_FOREACH(ct, &softc->targets, ct_next) {
2278 if (ct->ct_tag != tag ||
2279 strcmp(name, ct->ct_name) != 0 ||
2280 ct->ct_state == CFISCSI_TARGET_STATE_INVALID)
2282 cfiscsi_target_hold(ct);
2283 mtx_unlock(&softc->lock);
2284 free(newct, M_CFISCSI);
2288 strlcpy(newct->ct_name, name, sizeof(newct->ct_name));
2290 strlcpy(newct->ct_alias, alias, sizeof(newct->ct_alias));
2291 newct->ct_tag = tag;
2292 refcount_init(&newct->ct_refcount, 1);
2293 newct->ct_softc = softc;
2294 if (TAILQ_EMPTY(&softc->targets))
2295 softc->last_target_id = 0;
2296 newct->ct_target_id = ++softc->last_target_id;
2297 TAILQ_INSERT_TAIL(&softc->targets, newct, ct_next);
2298 mtx_unlock(&softc->lock);
2304 cfiscsi_lun_enable(void *arg, struct ctl_id target_id, int lun_id)
2311 cfiscsi_lun_disable(void *arg, struct ctl_id target_id, int lun_id)
2318 cfiscsi_datamove_in(union ctl_io *io)
2320 struct cfiscsi_session *cs;
2321 struct icl_pdu *request, *response;
2322 const struct iscsi_bhs_scsi_command *bhssc;
2323 struct iscsi_bhs_data_in *bhsdi;
2324 struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
2325 size_t len, expected_len, sg_len, buffer_offset;
2326 const char *sg_addr;
2327 int ctl_sg_count, error, i;
2329 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2330 cs = PDU_SESSION(request);
2332 bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs;
2333 KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
2334 ISCSI_BHS_OPCODE_SCSI_COMMAND,
2335 ("bhssc->bhssc_opcode != ISCSI_BHS_OPCODE_SCSI_COMMAND"));
2337 if (io->scsiio.kern_sg_entries > 0) {
2338 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
2339 ctl_sg_count = io->scsiio.kern_sg_entries;
2341 ctl_sglist = &ctl_sg_entry;
2342 ctl_sglist->addr = io->scsiio.kern_data_ptr;
2343 ctl_sglist->len = io->scsiio.kern_data_len;
2348 * This is the total amount of data to be transferred within the current
2349 * SCSI command. We need to record it so that we can properly report
2350 * underflow/underflow.
2352 PDU_TOTAL_TRANSFER_LEN(request) = io->scsiio.kern_total_len;
2355 * This is the offset within the current SCSI command; for the first
2356 * call to cfiscsi_datamove() it will be 0, and for subsequent ones
2357 * it will be the sum of lengths of previous ones.
2359 buffer_offset = io->scsiio.kern_rel_offset;
2362 * This is the transfer length expected by the initiator. In theory,
2363 * it could be different from the correct amount of data from the SCSI
2364 * point of view, even if that doesn't make any sense.
2366 expected_len = ntohl(bhssc->bhssc_expected_data_transfer_length);
2368 if (expected_len != io->scsiio.kern_total_len) {
2369 CFISCSI_SESSION_DEBUG(cs, "expected transfer length %zd, "
2370 "actual length %zd", expected_len,
2371 (size_t)io->scsiio.kern_total_len);
2375 if (buffer_offset >= expected_len) {
2377 CFISCSI_SESSION_DEBUG(cs, "buffer_offset = %zd, "
2378 "already sent the expected len", buffer_offset);
2380 io->scsiio.be_move_done(io);
2390 if (response == NULL) {
2391 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
2392 if (response == NULL) {
2393 CFISCSI_SESSION_WARN(cs, "failed to "
2394 "allocate memory; dropping connection");
2395 ctl_set_busy(&io->scsiio);
2396 io->scsiio.be_move_done(io);
2397 cfiscsi_session_terminate(cs);
2400 bhsdi = (struct iscsi_bhs_data_in *)response->ip_bhs;
2401 bhsdi->bhsdi_opcode = ISCSI_BHS_OPCODE_SCSI_DATA_IN;
2402 bhsdi->bhsdi_initiator_task_tag =
2403 bhssc->bhssc_initiator_task_tag;
2404 bhsdi->bhsdi_datasn = htonl(PDU_EXPDATASN(request));
2405 PDU_EXPDATASN(request)++;
2406 bhsdi->bhsdi_buffer_offset = htonl(buffer_offset);
2409 KASSERT(i < ctl_sg_count, ("i >= ctl_sg_count"));
2411 sg_addr = ctl_sglist[i].addr;
2412 sg_len = ctl_sglist[i].len;
2413 KASSERT(sg_len > 0, ("sg_len <= 0"));
2419 * Truncate to maximum data segment length.
2421 KASSERT(response->ip_data_len < cs->cs_max_data_segment_length,
2422 ("ip_data_len %zd >= max_data_segment_length %zd",
2423 response->ip_data_len, cs->cs_max_data_segment_length));
2424 if (response->ip_data_len + len >
2425 cs->cs_max_data_segment_length) {
2426 len = cs->cs_max_data_segment_length -
2427 response->ip_data_len;
2428 KASSERT(len <= sg_len, ("len %zd > sg_len %zd",
2433 * Truncate to expected data transfer length.
2435 KASSERT(buffer_offset + response->ip_data_len < expected_len,
2436 ("buffer_offset %zd + ip_data_len %zd >= expected_len %zd",
2437 buffer_offset, response->ip_data_len, expected_len));
2438 if (buffer_offset + response->ip_data_len + len > expected_len) {
2439 CFISCSI_SESSION_DEBUG(cs, "truncating from %zd "
2440 "to expected data transfer length %zd",
2441 buffer_offset + response->ip_data_len + len, expected_len);
2442 len = expected_len - (buffer_offset + response->ip_data_len);
2443 KASSERT(len <= sg_len, ("len %zd > sg_len %zd",
2447 error = icl_pdu_append_data(response, sg_addr, len, M_NOWAIT);
2449 CFISCSI_SESSION_WARN(cs, "failed to "
2450 "allocate memory; dropping connection");
2451 icl_pdu_free(response);
2452 ctl_set_busy(&io->scsiio);
2453 io->scsiio.be_move_done(io);
2454 cfiscsi_session_terminate(cs);
2460 KASSERT(buffer_offset + response->ip_data_len <= expected_len,
2461 ("buffer_offset %zd + ip_data_len %zd > expected_len %zd",
2462 buffer_offset, response->ip_data_len, expected_len));
2463 if (buffer_offset + response->ip_data_len == expected_len) {
2465 * Already have the amount of data the initiator wanted.
2472 * End of scatter-gather segment;
2473 * proceed to the next one...
2475 if (i == ctl_sg_count - 1) {
2477 * ... unless this was the last one.
2484 if (response->ip_data_len == cs->cs_max_data_segment_length) {
2486 * Can't stuff more data into the current PDU;
2487 * queue it. Note that's not enough to check
2488 * for kern_data_resid == 0 instead; there
2489 * may be several Data-In PDUs for the final
2490 * call to cfiscsi_datamove(), and we want
2491 * to set the F flag only on the last of them.
2493 buffer_offset += response->ip_data_len;
2494 if (buffer_offset == io->scsiio.kern_total_len ||
2495 buffer_offset == expected_len) {
2496 buffer_offset -= response->ip_data_len;
2499 cfiscsi_pdu_queue(response);
2504 if (response != NULL) {
2505 buffer_offset += response->ip_data_len;
2506 if (buffer_offset == io->scsiio.kern_total_len ||
2507 buffer_offset == expected_len) {
2508 bhsdi->bhsdi_flags |= BHSDI_FLAGS_F;
2509 if (io->io_hdr.status == CTL_SUCCESS) {
2510 bhsdi->bhsdi_flags |= BHSDI_FLAGS_S;
2511 if (PDU_TOTAL_TRANSFER_LEN(request) <
2512 ntohl(bhssc->bhssc_expected_data_transfer_length)) {
2513 bhsdi->bhsdi_flags |= BHSSR_FLAGS_RESIDUAL_UNDERFLOW;
2514 bhsdi->bhsdi_residual_count =
2515 htonl(ntohl(bhssc->bhssc_expected_data_transfer_length) -
2516 PDU_TOTAL_TRANSFER_LEN(request));
2517 } else if (PDU_TOTAL_TRANSFER_LEN(request) >
2518 ntohl(bhssc->bhssc_expected_data_transfer_length)) {
2519 bhsdi->bhsdi_flags |= BHSSR_FLAGS_RESIDUAL_OVERFLOW;
2520 bhsdi->bhsdi_residual_count =
2521 htonl(PDU_TOTAL_TRANSFER_LEN(request) -
2522 ntohl(bhssc->bhssc_expected_data_transfer_length));
2524 bhsdi->bhsdi_status = io->scsiio.scsi_status;
2525 io->io_hdr.flags |= CTL_FLAG_STATUS_SENT;
2528 KASSERT(response->ip_data_len > 0, ("sending empty Data-In"));
2529 cfiscsi_pdu_queue(response);
2532 io->scsiio.be_move_done(io);
2536 cfiscsi_datamove_out(union ctl_io *io)
2538 struct cfiscsi_session *cs;
2539 struct icl_pdu *request, *response;
2540 const struct iscsi_bhs_scsi_command *bhssc;
2541 struct iscsi_bhs_r2t *bhsr2t;
2542 struct cfiscsi_data_wait *cdw;
2543 struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
2544 uint32_t expected_len, r2t_off, r2t_len;
2545 uint32_t target_transfer_tag;
2548 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2549 cs = PDU_SESSION(request);
2551 bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs;
2552 KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
2553 ISCSI_BHS_OPCODE_SCSI_COMMAND,
2554 ("bhssc->bhssc_opcode != ISCSI_BHS_OPCODE_SCSI_COMMAND"));
2557 * We need to record it so that we can properly report
2558 * underflow/underflow.
2560 PDU_TOTAL_TRANSFER_LEN(request) = io->scsiio.kern_total_len;
2563 * Report write underflow as error since CTL and backends don't
2564 * really support it, and SCSI does not tell how to do it right.
2566 expected_len = ntohl(bhssc->bhssc_expected_data_transfer_length);
2567 if (io->scsiio.kern_rel_offset + io->scsiio.kern_data_len >
2569 io->scsiio.io_hdr.port_status = 43;
2570 io->scsiio.be_move_done(io);
2574 target_transfer_tag =
2575 atomic_fetchadd_32(&cs->cs_target_transfer_tag, 1);
2578 CFISCSI_SESSION_DEBUG(cs, "expecting Data-Out with initiator "
2579 "task tag 0x%x, target transfer tag 0x%x",
2580 bhssc->bhssc_initiator_task_tag, target_transfer_tag);
2582 cdw = uma_zalloc(cfiscsi_data_wait_zone, M_NOWAIT | M_ZERO);
2584 CFISCSI_SESSION_WARN(cs, "failed to "
2585 "allocate memory; dropping connection");
2586 ctl_set_busy(&io->scsiio);
2587 io->scsiio.be_move_done(io);
2588 cfiscsi_session_terminate(cs);
2591 cdw->cdw_ctl_io = io;
2592 cdw->cdw_target_transfer_tag = target_transfer_tag;
2593 cdw->cdw_initiator_task_tag = bhssc->bhssc_initiator_task_tag;
2594 cdw->cdw_r2t_end = io->scsiio.kern_data_len;
2595 cdw->cdw_datasn = 0;
2597 /* Set initial data pointer for the CDW respecting ext_data_filled. */
2598 if (io->scsiio.kern_sg_entries > 0) {
2599 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
2601 ctl_sglist = &ctl_sg_entry;
2602 ctl_sglist->addr = io->scsiio.kern_data_ptr;
2603 ctl_sglist->len = io->scsiio.kern_data_len;
2605 cdw->cdw_sg_index = 0;
2606 cdw->cdw_sg_addr = ctl_sglist[cdw->cdw_sg_index].addr;
2607 cdw->cdw_sg_len = ctl_sglist[cdw->cdw_sg_index].len;
2608 r2t_off = io->scsiio.ext_data_filled;
2609 while (r2t_off > 0) {
2610 if (r2t_off >= cdw->cdw_sg_len) {
2611 r2t_off -= cdw->cdw_sg_len;
2612 cdw->cdw_sg_index++;
2613 cdw->cdw_sg_addr = ctl_sglist[cdw->cdw_sg_index].addr;
2614 cdw->cdw_sg_len = ctl_sglist[cdw->cdw_sg_index].len;
2617 cdw->cdw_sg_addr += r2t_off;
2618 cdw->cdw_sg_len -= r2t_off;
2622 if (cs->cs_immediate_data &&
2623 io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled <
2624 icl_pdu_data_segment_length(request)) {
2625 done = cfiscsi_handle_data_segment(request, cdw);
2627 uma_zfree(cfiscsi_data_wait_zone, cdw);
2628 io->scsiio.be_move_done(io);
2633 r2t_off = io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled;
2634 r2t_len = MIN(io->scsiio.kern_data_len - io->scsiio.ext_data_filled,
2635 cs->cs_max_burst_length);
2636 cdw->cdw_r2t_end = io->scsiio.ext_data_filled + r2t_len;
2638 CFISCSI_SESSION_LOCK(cs);
2639 TAILQ_INSERT_TAIL(&cs->cs_waiting_for_data_out, cdw, cdw_next);
2640 CFISCSI_SESSION_UNLOCK(cs);
2643 * XXX: We should limit the number of outstanding R2T PDUs
2644 * per task to MaxOutstandingR2T.
2646 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
2647 if (response == NULL) {
2648 CFISCSI_SESSION_WARN(cs, "failed to "
2649 "allocate memory; dropping connection");
2650 ctl_set_busy(&io->scsiio);
2651 io->scsiio.be_move_done(io);
2652 cfiscsi_session_terminate(cs);
2655 bhsr2t = (struct iscsi_bhs_r2t *)response->ip_bhs;
2656 bhsr2t->bhsr2t_opcode = ISCSI_BHS_OPCODE_R2T;
2657 bhsr2t->bhsr2t_flags = 0x80;
2658 bhsr2t->bhsr2t_lun = bhssc->bhssc_lun;
2659 bhsr2t->bhsr2t_initiator_task_tag = bhssc->bhssc_initiator_task_tag;
2660 bhsr2t->bhsr2t_target_transfer_tag = target_transfer_tag;
2662 * XXX: Here we assume that cfiscsi_datamove() won't ever
2663 * be running concurrently on several CPUs for a given
2666 bhsr2t->bhsr2t_r2tsn = htonl(PDU_R2TSN(request));
2667 PDU_R2TSN(request)++;
2669 * This is the offset within the current SCSI command;
2670 * i.e. for the first call of datamove(), it will be 0,
2671 * and for subsequent ones it will be the sum of lengths
2674 * The ext_data_filled is to account for unsolicited
2675 * (immediate) data that might have already arrived.
2677 bhsr2t->bhsr2t_buffer_offset = htonl(r2t_off);
2679 * This is the total length (sum of S/G lengths) this call
2680 * to cfiscsi_datamove() is supposed to handle, limited by
2683 bhsr2t->bhsr2t_desired_data_transfer_length = htonl(r2t_len);
2684 cfiscsi_pdu_queue(response);
2688 cfiscsi_datamove(union ctl_io *io)
2691 if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN)
2692 cfiscsi_datamove_in(io);
2694 /* We hadn't received anything during this datamove yet. */
2695 io->scsiio.ext_data_filled = 0;
2696 cfiscsi_datamove_out(io);
2701 cfiscsi_scsi_command_done(union ctl_io *io)
2703 struct icl_pdu *request, *response;
2704 struct iscsi_bhs_scsi_command *bhssc;
2705 struct iscsi_bhs_scsi_response *bhssr;
2707 struct cfiscsi_data_wait *cdw;
2709 struct cfiscsi_session *cs;
2710 uint16_t sense_length;
2712 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2713 cs = PDU_SESSION(request);
2714 bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs;
2715 KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
2716 ISCSI_BHS_OPCODE_SCSI_COMMAND,
2717 ("replying to wrong opcode 0x%x", bhssc->bhssc_opcode));
2719 //CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x",
2720 // bhssc->bhssc_initiator_task_tag);
2723 CFISCSI_SESSION_LOCK(cs);
2724 TAILQ_FOREACH(cdw, &cs->cs_waiting_for_data_out, cdw_next)
2725 KASSERT(bhssc->bhssc_initiator_task_tag !=
2726 cdw->cdw_initiator_task_tag, ("dangling cdw"));
2727 CFISCSI_SESSION_UNLOCK(cs);
2731 * Do not return status for aborted commands.
2732 * There are exceptions, but none supported by CTL yet.
2734 if (((io->io_hdr.flags & CTL_FLAG_ABORT) &&
2735 (io->io_hdr.flags & CTL_FLAG_ABORT_STATUS) == 0) ||
2736 (io->io_hdr.flags & CTL_FLAG_STATUS_SENT)) {
2738 icl_pdu_free(request);
2742 response = cfiscsi_pdu_new_response(request, M_WAITOK);
2743 bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs;
2744 bhssr->bhssr_opcode = ISCSI_BHS_OPCODE_SCSI_RESPONSE;
2745 bhssr->bhssr_flags = 0x80;
2747 * XXX: We don't deal with bidirectional under/overflows;
2748 * does anything actually support those?
2750 if (PDU_TOTAL_TRANSFER_LEN(request) <
2751 ntohl(bhssc->bhssc_expected_data_transfer_length)) {
2752 bhssr->bhssr_flags |= BHSSR_FLAGS_RESIDUAL_UNDERFLOW;
2753 bhssr->bhssr_residual_count =
2754 htonl(ntohl(bhssc->bhssc_expected_data_transfer_length) -
2755 PDU_TOTAL_TRANSFER_LEN(request));
2756 //CFISCSI_SESSION_DEBUG(cs, "underflow; residual count %d",
2757 // ntohl(bhssr->bhssr_residual_count));
2758 } else if (PDU_TOTAL_TRANSFER_LEN(request) >
2759 ntohl(bhssc->bhssc_expected_data_transfer_length)) {
2760 bhssr->bhssr_flags |= BHSSR_FLAGS_RESIDUAL_OVERFLOW;
2761 bhssr->bhssr_residual_count =
2762 htonl(PDU_TOTAL_TRANSFER_LEN(request) -
2763 ntohl(bhssc->bhssc_expected_data_transfer_length));
2764 //CFISCSI_SESSION_DEBUG(cs, "overflow; residual count %d",
2765 // ntohl(bhssr->bhssr_residual_count));
2767 bhssr->bhssr_response = BHSSR_RESPONSE_COMMAND_COMPLETED;
2768 bhssr->bhssr_status = io->scsiio.scsi_status;
2769 bhssr->bhssr_initiator_task_tag = bhssc->bhssc_initiator_task_tag;
2770 bhssr->bhssr_expdatasn = htonl(PDU_EXPDATASN(request));
2772 if (io->scsiio.sense_len > 0) {
2774 CFISCSI_SESSION_DEBUG(cs, "returning %d bytes of sense data",
2775 io->scsiio.sense_len);
2777 sense_length = htons(io->scsiio.sense_len);
2778 icl_pdu_append_data(response,
2779 &sense_length, sizeof(sense_length), M_WAITOK);
2780 icl_pdu_append_data(response,
2781 &io->scsiio.sense_data, io->scsiio.sense_len, M_WAITOK);
2785 icl_pdu_free(request);
2786 cfiscsi_pdu_queue(response);
2790 cfiscsi_task_management_done(union ctl_io *io)
2792 struct icl_pdu *request, *response;
2793 struct iscsi_bhs_task_management_request *bhstmr;
2794 struct iscsi_bhs_task_management_response *bhstmr2;
2795 struct cfiscsi_data_wait *cdw, *tmpcdw;
2796 struct cfiscsi_session *cs;
2798 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2799 cs = PDU_SESSION(request);
2800 bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs;
2801 KASSERT((bhstmr->bhstmr_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
2802 ISCSI_BHS_OPCODE_TASK_REQUEST,
2803 ("replying to wrong opcode 0x%x", bhstmr->bhstmr_opcode));
2806 CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x; referenced task tag 0x%x",
2807 bhstmr->bhstmr_initiator_task_tag,
2808 bhstmr->bhstmr_referenced_task_tag);
2811 if ((bhstmr->bhstmr_function & ~0x80) ==
2812 BHSTMR_FUNCTION_ABORT_TASK) {
2814 * Make sure we no longer wait for Data-Out for this command.
2816 CFISCSI_SESSION_LOCK(cs);
2817 TAILQ_FOREACH_SAFE(cdw,
2818 &cs->cs_waiting_for_data_out, cdw_next, tmpcdw) {
2819 if (bhstmr->bhstmr_referenced_task_tag !=
2820 cdw->cdw_initiator_task_tag)
2824 CFISCSI_SESSION_DEBUG(cs, "removing csw for initiator task "
2825 "tag 0x%x", bhstmr->bhstmr_initiator_task_tag);
2827 TAILQ_REMOVE(&cs->cs_waiting_for_data_out,
2829 cdw->cdw_ctl_io->scsiio.be_move_done(cdw->cdw_ctl_io);
2830 uma_zfree(cfiscsi_data_wait_zone, cdw);
2832 CFISCSI_SESSION_UNLOCK(cs);
2835 response = cfiscsi_pdu_new_response(request, M_WAITOK);
2836 bhstmr2 = (struct iscsi_bhs_task_management_response *)
2838 bhstmr2->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_RESPONSE;
2839 bhstmr2->bhstmr_flags = 0x80;
2840 if (io->io_hdr.status == CTL_SUCCESS) {
2841 bhstmr2->bhstmr_response = BHSTMR_RESPONSE_FUNCTION_COMPLETE;
2844 * XXX: How to figure out what exactly went wrong? iSCSI spec
2845 * expects us to provide detailed error, e.g. "Task does
2846 * not exist" or "LUN does not exist".
2848 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED");
2849 bhstmr2->bhstmr_response =
2850 BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED;
2852 bhstmr2->bhstmr_initiator_task_tag = bhstmr->bhstmr_initiator_task_tag;
2855 icl_pdu_free(request);
2856 cfiscsi_pdu_queue(response);
2860 cfiscsi_done(union ctl_io *io)
2862 struct icl_pdu *request;
2863 struct cfiscsi_session *cs;
2865 KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE),
2866 ("invalid CTL status %#x", io->io_hdr.status));
2868 if (io->io_hdr.io_type == CTL_IO_TASK &&
2869 io->taskio.task_action == CTL_TASK_I_T_NEXUS_RESET) {
2871 * Implicit task termination has just completed; nothing to do.
2873 cs = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2874 cs->cs_tasks_aborted = true;
2875 refcount_release(&cs->cs_outstanding_ctl_pdus);
2876 wakeup(__DEVOLATILE(void *, &cs->cs_outstanding_ctl_pdus));
2881 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
2882 cs = PDU_SESSION(request);
2883 refcount_release(&cs->cs_outstanding_ctl_pdus);
2885 switch (request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) {
2886 case ISCSI_BHS_OPCODE_SCSI_COMMAND:
2887 cfiscsi_scsi_command_done(io);
2889 case ISCSI_BHS_OPCODE_TASK_REQUEST:
2890 cfiscsi_task_management_done(io);
2893 panic("cfiscsi_done called with wrong opcode 0x%x",
2894 request->ip_bhs->bhs_opcode);