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