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