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