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