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