iscsi.c revision 270888
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 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: stable/10/sys/dev/iscsi/iscsi.c 270888 2014-08-31 20:21:08Z trasz $"); 33 34#include <sys/param.h> 35#include <sys/condvar.h> 36#include <sys/conf.h> 37#include <sys/eventhandler.h> 38#include <sys/file.h> 39#include <sys/kernel.h> 40#include <sys/kthread.h> 41#include <sys/lock.h> 42#include <sys/malloc.h> 43#include <sys/mutex.h> 44#include <sys/module.h> 45#include <sys/sysctl.h> 46#include <sys/systm.h> 47#include <sys/sx.h> 48#include <vm/uma.h> 49 50#include <cam/cam.h> 51#include <cam/cam_ccb.h> 52#include <cam/cam_xpt.h> 53#include <cam/cam_debug.h> 54#include <cam/cam_sim.h> 55#include <cam/cam_xpt_sim.h> 56#include <cam/cam_xpt_periph.h> 57#include <cam/cam_periph.h> 58#include <cam/scsi/scsi_all.h> 59#include <cam/scsi/scsi_message.h> 60 61#include "iscsi_ioctl.h" 62#include "iscsi.h" 63#include "icl.h" 64#include "iscsi_proto.h" 65 66#ifdef ICL_KERNEL_PROXY 67#include <sys/socketvar.h> 68#endif 69 70#ifdef ICL_KERNEL_PROXY 71FEATURE(iscsi_kernel_proxy, "iSCSI initiator built with ICL_KERNEL_PROXY"); 72#endif 73 74/* 75 * XXX: This is global so the iscsi_unload() can access it. 76 * Think about how to do this properly. 77 */ 78static struct iscsi_softc *sc; 79 80SYSCTL_NODE(_kern, OID_AUTO, iscsi, CTLFLAG_RD, 0, "iSCSI initiator"); 81static int debug = 1; 82TUNABLE_INT("kern.iscsi.debug", &debug); 83SYSCTL_INT(_kern_iscsi, OID_AUTO, debug, CTLFLAG_RWTUN, 84 &debug, 0, "Enable debug messages"); 85static int ping_timeout = 5; 86TUNABLE_INT("kern.iscsi.ping_timeout", &ping_timeout); 87SYSCTL_INT(_kern_iscsi, OID_AUTO, ping_timeout, CTLFLAG_RWTUN, &ping_timeout, 88 0, "Timeout for ping (NOP-Out) requests, in seconds"); 89static int iscsid_timeout = 60; 90TUNABLE_INT("kern.iscsi.iscsid_timeout", &iscsid_timeout); 91SYSCTL_INT(_kern_iscsi, OID_AUTO, iscsid_timeout, CTLFLAG_RWTUN, &iscsid_timeout, 92 0, "Time to wait for iscsid(8) to handle reconnection, in seconds"); 93static int login_timeout = 60; 94TUNABLE_INT("kern.iscsi.login_timeout", &login_timeout); 95SYSCTL_INT(_kern_iscsi, OID_AUTO, login_timeout, CTLFLAG_RWTUN, &login_timeout, 96 0, "Time to wait for iscsid(8) to finish Login Phase, in seconds"); 97static int maxtags = 255; 98TUNABLE_INT("kern.iscsi.maxtags", &maxtags); 99SYSCTL_INT(_kern_iscsi, OID_AUTO, maxtags, CTLFLAG_RWTUN, &maxtags, 100 0, "Max number of IO requests queued"); 101static int fail_on_disconnection = 0; 102TUNABLE_INT("kern.iscsi.fail_on_disconnection", &fail_on_disconnection); 103SYSCTL_INT(_kern_iscsi, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN, 104 &fail_on_disconnection, 0, "Destroy CAM SIM on connection failure"); 105 106static MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI initiator"); 107static uma_zone_t iscsi_outstanding_zone; 108 109#define CONN_SESSION(X) ((struct iscsi_session *)X->ic_prv0) 110#define PDU_SESSION(X) (CONN_SESSION(X->ip_conn)) 111 112#define ISCSI_DEBUG(X, ...) \ 113 do { \ 114 if (debug > 1) \ 115 printf("%s: " X "\n", __func__, ## __VA_ARGS__);\ 116 } while (0) 117 118#define ISCSI_WARN(X, ...) \ 119 do { \ 120 if (debug > 0) { \ 121 printf("WARNING: %s: " X "\n", \ 122 __func__, ## __VA_ARGS__); \ 123 } \ 124 } while (0) 125 126#define ISCSI_SESSION_DEBUG(S, X, ...) \ 127 do { \ 128 if (debug > 1) { \ 129 printf("%s: %s (%s): " X "\n", \ 130 __func__, S->is_conf.isc_target_addr, \ 131 S->is_conf.isc_target, ## __VA_ARGS__); \ 132 } \ 133 } while (0) 134 135#define ISCSI_SESSION_WARN(S, X, ...) \ 136 do { \ 137 if (debug > 0) { \ 138 printf("WARNING: %s (%s): " X "\n", \ 139 S->is_conf.isc_target_addr, \ 140 S->is_conf.isc_target, ## __VA_ARGS__); \ 141 } \ 142 } while (0) 143 144#define ISCSI_SESSION_LOCK(X) mtx_lock(&X->is_lock) 145#define ISCSI_SESSION_UNLOCK(X) mtx_unlock(&X->is_lock) 146#define ISCSI_SESSION_LOCK_ASSERT(X) mtx_assert(&X->is_lock, MA_OWNED) 147 148static int iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, 149 int mode, struct thread *td); 150 151static struct cdevsw iscsi_cdevsw = { 152 .d_version = D_VERSION, 153 .d_ioctl = iscsi_ioctl, 154 .d_name = "iscsi", 155}; 156 157static void iscsi_pdu_queue_locked(struct icl_pdu *request); 158static void iscsi_pdu_queue(struct icl_pdu *request); 159static void iscsi_pdu_update_statsn(const struct icl_pdu *response); 160static void iscsi_pdu_handle_nop_in(struct icl_pdu *response); 161static void iscsi_pdu_handle_scsi_response(struct icl_pdu *response); 162static void iscsi_pdu_handle_task_response(struct icl_pdu *response); 163static void iscsi_pdu_handle_data_in(struct icl_pdu *response); 164static void iscsi_pdu_handle_logout_response(struct icl_pdu *response); 165static void iscsi_pdu_handle_r2t(struct icl_pdu *response); 166static void iscsi_pdu_handle_async_message(struct icl_pdu *response); 167static void iscsi_pdu_handle_reject(struct icl_pdu *response); 168static void iscsi_session_reconnect(struct iscsi_session *is); 169static void iscsi_session_terminate(struct iscsi_session *is); 170static void iscsi_action(struct cam_sim *sim, union ccb *ccb); 171static void iscsi_poll(struct cam_sim *sim); 172static struct iscsi_outstanding *iscsi_outstanding_find(struct iscsi_session *is, 173 uint32_t initiator_task_tag); 174static struct iscsi_outstanding *iscsi_outstanding_add(struct iscsi_session *is, 175 uint32_t initiator_task_tag, union ccb *ccb); 176static void iscsi_outstanding_remove(struct iscsi_session *is, 177 struct iscsi_outstanding *io); 178 179static bool 180iscsi_pdu_prepare(struct icl_pdu *request) 181{ 182 struct iscsi_session *is; 183 struct iscsi_bhs_scsi_command *bhssc; 184 185 is = PDU_SESSION(request); 186 187 ISCSI_SESSION_LOCK_ASSERT(is); 188 189 /* 190 * We're only using fields common for all the request 191 * (initiator -> target) PDUs. 192 */ 193 bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs; 194 195 /* 196 * Data-Out PDU does not contain CmdSN. 197 */ 198 if (bhssc->bhssc_opcode != ISCSI_BHS_OPCODE_SCSI_DATA_OUT) { 199 if (is->is_cmdsn > is->is_maxcmdsn && 200 (bhssc->bhssc_opcode & ISCSI_BHS_OPCODE_IMMEDIATE) == 0) { 201 /* 202 * Current MaxCmdSN prevents us from sending any more 203 * SCSI Command PDUs to the target; postpone the PDU. 204 * It will get resent by either iscsi_pdu_queue(), 205 * or by maintenance thread. 206 */ 207#if 0 208 ISCSI_SESSION_DEBUG(is, "postponing send, CmdSN %d, ExpCmdSN %d, MaxCmdSN %d, opcode 0x%x", 209 is->is_cmdsn, is->is_expcmdsn, is->is_maxcmdsn, bhssc->bhssc_opcode); 210#endif 211 return (true); 212 } 213 bhssc->bhssc_cmdsn = htonl(is->is_cmdsn); 214 if ((bhssc->bhssc_opcode & ISCSI_BHS_OPCODE_IMMEDIATE) == 0) 215 is->is_cmdsn++; 216 } 217 bhssc->bhssc_expstatsn = htonl(is->is_statsn + 1); 218 219 return (false); 220} 221 222static void 223iscsi_session_send_postponed(struct iscsi_session *is) 224{ 225 struct icl_pdu *request; 226 bool postpone; 227 228 ISCSI_SESSION_LOCK_ASSERT(is); 229 230 while (!STAILQ_EMPTY(&is->is_postponed)) { 231 request = STAILQ_FIRST(&is->is_postponed); 232 postpone = iscsi_pdu_prepare(request); 233 if (postpone) 234 break; 235 STAILQ_REMOVE_HEAD(&is->is_postponed, ip_next); 236 icl_pdu_queue(request); 237 } 238} 239 240static void 241iscsi_pdu_queue_locked(struct icl_pdu *request) 242{ 243 struct iscsi_session *is; 244 bool postpone; 245 246 is = PDU_SESSION(request); 247 ISCSI_SESSION_LOCK_ASSERT(is); 248 iscsi_session_send_postponed(is); 249 postpone = iscsi_pdu_prepare(request); 250 if (postpone) { 251 STAILQ_INSERT_TAIL(&is->is_postponed, request, ip_next); 252 return; 253 } 254 icl_pdu_queue(request); 255} 256 257static void 258iscsi_pdu_queue(struct icl_pdu *request) 259{ 260 struct iscsi_session *is; 261 262 is = PDU_SESSION(request); 263 ISCSI_SESSION_LOCK(is); 264 iscsi_pdu_queue_locked(request); 265 ISCSI_SESSION_UNLOCK(is); 266} 267 268static void 269iscsi_session_logout(struct iscsi_session *is) 270{ 271 struct icl_pdu *request; 272 struct iscsi_bhs_logout_request *bhslr; 273 274 request = icl_pdu_new_bhs(is->is_conn, M_NOWAIT); 275 if (request == NULL) 276 return; 277 278 bhslr = (struct iscsi_bhs_logout_request *)request->ip_bhs; 279 bhslr->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_REQUEST; 280 bhslr->bhslr_reason = BHSLR_REASON_CLOSE_SESSION; 281 iscsi_pdu_queue_locked(request); 282} 283 284static void 285iscsi_session_terminate_task(struct iscsi_session *is, 286 struct iscsi_outstanding *io, bool requeue) 287{ 288 289 if (io->io_ccb != NULL) { 290 io->io_ccb->ccb_h.status &= ~(CAM_SIM_QUEUED | CAM_STATUS_MASK); 291 if (requeue) 292 io->io_ccb->ccb_h.status |= CAM_REQUEUE_REQ; 293 else 294 io->io_ccb->ccb_h.status |= CAM_REQ_ABORTED; 295 if ((io->io_ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 296 io->io_ccb->ccb_h.status |= CAM_DEV_QFRZN; 297 xpt_freeze_devq(io->io_ccb->ccb_h.path, 1); 298 ISCSI_SESSION_DEBUG(is, "freezing devq"); 299 } 300 xpt_done(io->io_ccb); 301 } 302 iscsi_outstanding_remove(is, io); 303} 304 305static void 306iscsi_session_terminate_tasks(struct iscsi_session *is, bool requeue) 307{ 308 struct iscsi_outstanding *io, *tmp; 309 310 ISCSI_SESSION_LOCK_ASSERT(is); 311 312 TAILQ_FOREACH_SAFE(io, &is->is_outstanding, io_next, tmp) { 313 iscsi_session_terminate_task(is, io, requeue); 314 } 315} 316 317static void 318iscsi_session_cleanup(struct iscsi_session *is, bool destroy_sim) 319{ 320 struct icl_pdu *pdu; 321 322 ISCSI_SESSION_LOCK_ASSERT(is); 323 324 /* 325 * Don't queue any new PDUs. 326 */ 327 if (is->is_sim != NULL && is->is_simq_frozen == false) { 328 ISCSI_SESSION_DEBUG(is, "freezing"); 329 xpt_freeze_simq(is->is_sim, 1); 330 is->is_simq_frozen = true; 331 } 332 333 /* 334 * Remove postponed PDUs. 335 */ 336 while (!STAILQ_EMPTY(&is->is_postponed)) { 337 pdu = STAILQ_FIRST(&is->is_postponed); 338 STAILQ_REMOVE_HEAD(&is->is_postponed, ip_next); 339 icl_pdu_free(pdu); 340 } 341 342 if (destroy_sim == false) { 343 /* 344 * Terminate SCSI tasks, asking CAM to requeue them. 345 */ 346 iscsi_session_terminate_tasks(is, true); 347 return; 348 } 349 350 iscsi_session_terminate_tasks(is, false); 351 352 if (is->is_sim == NULL) 353 return; 354 355 ISCSI_SESSION_DEBUG(is, "deregistering SIM"); 356 xpt_async(AC_LOST_DEVICE, is->is_path, NULL); 357 358 if (is->is_simq_frozen) { 359 xpt_release_simq(is->is_sim, 1); 360 is->is_simq_frozen = false; 361 } 362 363 xpt_free_path(is->is_path); 364 is->is_path = NULL; 365 xpt_bus_deregister(cam_sim_path(is->is_sim)); 366 cam_sim_free(is->is_sim, TRUE /*free_devq*/); 367 is->is_sim = NULL; 368 is->is_devq = NULL; 369} 370 371static void 372iscsi_maintenance_thread_reconnect(struct iscsi_session *is) 373{ 374 375 icl_conn_shutdown(is->is_conn); 376 icl_conn_close(is->is_conn); 377 378 ISCSI_SESSION_LOCK(is); 379 380 is->is_connected = false; 381 is->is_reconnecting = false; 382 is->is_login_phase = false; 383 384#ifdef ICL_KERNEL_PROXY 385 if (is->is_login_pdu != NULL) { 386 icl_pdu_free(is->is_login_pdu); 387 is->is_login_pdu = NULL; 388 } 389 cv_signal(&is->is_login_cv); 390#endif 391 392 if (fail_on_disconnection) { 393 ISCSI_SESSION_DEBUG(is, "connection failed, destroying devices"); 394 iscsi_session_cleanup(is, true); 395 } else { 396 iscsi_session_cleanup(is, false); 397 } 398 399 KASSERT(TAILQ_EMPTY(&is->is_outstanding), 400 ("destroying session with active tasks")); 401 KASSERT(STAILQ_EMPTY(&is->is_postponed), 402 ("destroying session with postponed PDUs")); 403 404 /* 405 * Request immediate reconnection from iscsid(8). 406 */ 407 //ISCSI_SESSION_DEBUG(is, "waking up iscsid(8)"); 408 is->is_waiting_for_iscsid = true; 409 strlcpy(is->is_reason, "Waiting for iscsid(8)", sizeof(is->is_reason)); 410 is->is_timeout = 0; 411 ISCSI_SESSION_UNLOCK(is); 412 cv_signal(&is->is_softc->sc_cv); 413} 414 415static void 416iscsi_maintenance_thread_terminate(struct iscsi_session *is) 417{ 418 struct iscsi_softc *sc; 419 420 sc = is->is_softc; 421 sx_xlock(&sc->sc_lock); 422 TAILQ_REMOVE(&sc->sc_sessions, is, is_next); 423 sx_xunlock(&sc->sc_lock); 424 425 icl_conn_close(is->is_conn); 426 427 ISCSI_SESSION_LOCK(is); 428 429 KASSERT(is->is_terminating, ("is_terminating == false")); 430 431#ifdef ICL_KERNEL_PROXY 432 if (is->is_login_pdu != NULL) { 433 icl_pdu_free(is->is_login_pdu); 434 is->is_login_pdu = NULL; 435 } 436 cv_signal(&is->is_login_cv); 437#endif 438 439 callout_drain(&is->is_callout); 440 441 iscsi_session_cleanup(is, true); 442 443 KASSERT(TAILQ_EMPTY(&is->is_outstanding), 444 ("destroying session with active tasks")); 445 KASSERT(STAILQ_EMPTY(&is->is_postponed), 446 ("destroying session with postponed PDUs")); 447 448 ISCSI_SESSION_UNLOCK(is); 449 450 icl_conn_free(is->is_conn); 451 mtx_destroy(&is->is_lock); 452 cv_destroy(&is->is_maintenance_cv); 453#ifdef ICL_KERNEL_PROXY 454 cv_destroy(&is->is_login_cv); 455#endif 456 ISCSI_SESSION_DEBUG(is, "terminated"); 457 free(is, M_ISCSI); 458 459 /* 460 * The iscsi_unload() routine might be waiting. 461 */ 462 cv_signal(&sc->sc_cv); 463} 464 465static void 466iscsi_maintenance_thread(void *arg) 467{ 468 struct iscsi_session *is; 469 470 is = arg; 471 472 for (;;) { 473 ISCSI_SESSION_LOCK(is); 474 if (is->is_reconnecting == false && 475 is->is_terminating == false && 476 STAILQ_EMPTY(&is->is_postponed)) 477 cv_wait(&is->is_maintenance_cv, &is->is_lock); 478 479 if (is->is_reconnecting) { 480 ISCSI_SESSION_UNLOCK(is); 481 iscsi_maintenance_thread_reconnect(is); 482 continue; 483 } 484 485 if (is->is_terminating) { 486 ISCSI_SESSION_UNLOCK(is); 487 iscsi_maintenance_thread_terminate(is); 488 kthread_exit(); 489 return; 490 } 491 492 iscsi_session_send_postponed(is); 493 ISCSI_SESSION_UNLOCK(is); 494 } 495} 496 497static void 498iscsi_session_reconnect(struct iscsi_session *is) 499{ 500 501 /* 502 * XXX: We can't use locking here, because 503 * it's being called from various contexts. 504 * Hope it doesn't break anything. 505 */ 506 if (is->is_reconnecting) 507 return; 508 509 is->is_reconnecting = true; 510 cv_signal(&is->is_maintenance_cv); 511} 512 513static void 514iscsi_session_terminate(struct iscsi_session *is) 515{ 516 if (is->is_terminating) 517 return; 518 519 is->is_terminating = true; 520 521#if 0 522 iscsi_session_logout(is); 523#endif 524 cv_signal(&is->is_maintenance_cv); 525} 526 527static void 528iscsi_callout(void *context) 529{ 530 struct icl_pdu *request; 531 struct iscsi_bhs_nop_out *bhsno; 532 struct iscsi_session *is; 533 bool reconnect_needed = false; 534 535 is = context; 536 537 if (is->is_terminating) 538 return; 539 540 callout_schedule(&is->is_callout, 1 * hz); 541 542 ISCSI_SESSION_LOCK(is); 543 is->is_timeout++; 544 545 if (is->is_waiting_for_iscsid) { 546 if (is->is_timeout > iscsid_timeout) { 547 ISCSI_SESSION_WARN(is, "timed out waiting for iscsid(8) " 548 "for %d seconds; reconnecting", 549 is->is_timeout); 550 reconnect_needed = true; 551 } 552 goto out; 553 } 554 555 if (is->is_login_phase) { 556 if (is->is_timeout > login_timeout) { 557 ISCSI_SESSION_WARN(is, "login timed out after %d seconds; " 558 "reconnecting", is->is_timeout); 559 reconnect_needed = true; 560 } 561 goto out; 562 } 563 564 if (is->is_timeout >= ping_timeout) { 565 ISCSI_SESSION_WARN(is, "no ping reply (NOP-In) after %d seconds; " 566 "reconnecting", ping_timeout); 567 reconnect_needed = true; 568 goto out; 569 } 570 571 ISCSI_SESSION_UNLOCK(is); 572 573 /* 574 * If the ping was reset less than one second ago - which means 575 * that we've received some PDU during the last second - assume 576 * the traffic flows correctly and don't bother sending a NOP-Out. 577 * 578 * (It's 2 - one for one second, and one for incrementing is_timeout 579 * earlier in this routine.) 580 */ 581 if (is->is_timeout < 2) 582 return; 583 584 request = icl_pdu_new_bhs(is->is_conn, M_NOWAIT); 585 if (request == NULL) { 586 ISCSI_SESSION_WARN(is, "failed to allocate PDU"); 587 return; 588 } 589 bhsno = (struct iscsi_bhs_nop_out *)request->ip_bhs; 590 bhsno->bhsno_opcode = ISCSI_BHS_OPCODE_NOP_OUT | 591 ISCSI_BHS_OPCODE_IMMEDIATE; 592 bhsno->bhsno_flags = 0x80; 593 bhsno->bhsno_target_transfer_tag = 0xffffffff; 594 iscsi_pdu_queue(request); 595 return; 596 597out: 598 ISCSI_SESSION_UNLOCK(is); 599 600 if (reconnect_needed) 601 iscsi_session_reconnect(is); 602} 603 604static void 605iscsi_pdu_update_statsn(const struct icl_pdu *response) 606{ 607 const struct iscsi_bhs_data_in *bhsdi; 608 struct iscsi_session *is; 609 uint32_t expcmdsn, maxcmdsn; 610 611 is = PDU_SESSION(response); 612 613 ISCSI_SESSION_LOCK_ASSERT(is); 614 615 /* 616 * We're only using fields common for all the response 617 * (target -> initiator) PDUs. 618 */ 619 bhsdi = (const struct iscsi_bhs_data_in *)response->ip_bhs; 620 /* 621 * Ok, I lied. In case of Data-In, "The fields StatSN, Status, 622 * and Residual Count only have meaningful content if the S bit 623 * is set to 1", so we also need to check the bit specific for 624 * Data-In PDU. 625 */ 626 if (bhsdi->bhsdi_opcode != ISCSI_BHS_OPCODE_SCSI_DATA_IN || 627 (bhsdi->bhsdi_flags & BHSDI_FLAGS_S) != 0) { 628 if (ntohl(bhsdi->bhsdi_statsn) < is->is_statsn) { 629 ISCSI_SESSION_WARN(is, 630 "PDU StatSN %d >= session StatSN %d, opcode 0x%x", 631 is->is_statsn, ntohl(bhsdi->bhsdi_statsn), 632 bhsdi->bhsdi_opcode); 633 } 634 is->is_statsn = ntohl(bhsdi->bhsdi_statsn); 635 } 636 637 expcmdsn = ntohl(bhsdi->bhsdi_expcmdsn); 638 maxcmdsn = ntohl(bhsdi->bhsdi_maxcmdsn); 639 640 /* 641 * XXX: Compare using Serial Arithmetic Sense. 642 */ 643 if (maxcmdsn + 1 < expcmdsn) { 644 ISCSI_SESSION_DEBUG(is, "PDU MaxCmdSN %d + 1 < PDU ExpCmdSN %d; ignoring", 645 maxcmdsn, expcmdsn); 646 } else { 647 if (maxcmdsn > is->is_maxcmdsn) { 648 is->is_maxcmdsn = maxcmdsn; 649 650 /* 651 * Command window increased; kick the maintanance thread 652 * to send out postponed commands. 653 */ 654 if (!STAILQ_EMPTY(&is->is_postponed)) 655 cv_signal(&is->is_maintenance_cv); 656 } else if (maxcmdsn < is->is_maxcmdsn) { 657 ISCSI_SESSION_DEBUG(is, "PDU MaxCmdSN %d < session MaxCmdSN %d; ignoring", 658 maxcmdsn, is->is_maxcmdsn); 659 } 660 661 if (expcmdsn > is->is_expcmdsn) { 662 is->is_expcmdsn = expcmdsn; 663 } else if (expcmdsn < is->is_expcmdsn) { 664 ISCSI_SESSION_DEBUG(is, "PDU ExpCmdSN %d < session ExpCmdSN %d; ignoring", 665 expcmdsn, is->is_expcmdsn); 666 } 667 } 668 669 /* 670 * Every incoming PDU - not just NOP-In - resets the ping timer. 671 * The purpose of the timeout is to reset the connection when it stalls; 672 * we don't want this to happen when NOP-In or NOP-Out ends up delayed 673 * in some queue. 674 */ 675 is->is_timeout = 0; 676} 677 678static void 679iscsi_receive_callback(struct icl_pdu *response) 680{ 681 struct iscsi_session *is; 682 683 is = PDU_SESSION(response); 684 685 ISCSI_SESSION_LOCK(is); 686 687#ifdef ICL_KERNEL_PROXY 688 if (is->is_login_phase) { 689 if (is->is_login_pdu == NULL) 690 is->is_login_pdu = response; 691 else 692 icl_pdu_free(response); 693 ISCSI_SESSION_UNLOCK(is); 694 cv_signal(&is->is_login_cv); 695 return; 696 } 697#endif 698 699 iscsi_pdu_update_statsn(response); 700 701 /* 702 * The handling routine is responsible for freeing the PDU 703 * when it's no longer needed. 704 */ 705 switch (response->ip_bhs->bhs_opcode) { 706 case ISCSI_BHS_OPCODE_NOP_IN: 707 iscsi_pdu_handle_nop_in(response); 708 break; 709 case ISCSI_BHS_OPCODE_SCSI_RESPONSE: 710 iscsi_pdu_handle_scsi_response(response); 711 break; 712 case ISCSI_BHS_OPCODE_TASK_RESPONSE: 713 iscsi_pdu_handle_task_response(response); 714 break; 715 case ISCSI_BHS_OPCODE_SCSI_DATA_IN: 716 iscsi_pdu_handle_data_in(response); 717 break; 718 case ISCSI_BHS_OPCODE_LOGOUT_RESPONSE: 719 iscsi_pdu_handle_logout_response(response); 720 break; 721 case ISCSI_BHS_OPCODE_R2T: 722 iscsi_pdu_handle_r2t(response); 723 break; 724 case ISCSI_BHS_OPCODE_ASYNC_MESSAGE: 725 iscsi_pdu_handle_async_message(response); 726 break; 727 case ISCSI_BHS_OPCODE_REJECT: 728 iscsi_pdu_handle_reject(response); 729 break; 730 default: 731 ISCSI_SESSION_WARN(is, "received PDU with unsupported " 732 "opcode 0x%x; reconnecting", 733 response->ip_bhs->bhs_opcode); 734 iscsi_session_reconnect(is); 735 icl_pdu_free(response); 736 } 737 738 ISCSI_SESSION_UNLOCK(is); 739} 740 741static void 742iscsi_error_callback(struct icl_conn *ic) 743{ 744 struct iscsi_session *is; 745 746 is = CONN_SESSION(ic); 747 748 ISCSI_SESSION_WARN(is, "connection error; reconnecting"); 749 iscsi_session_reconnect(is); 750} 751 752static void 753iscsi_pdu_handle_nop_in(struct icl_pdu *response) 754{ 755 struct iscsi_session *is; 756 struct iscsi_bhs_nop_out *bhsno; 757 struct iscsi_bhs_nop_in *bhsni; 758 struct icl_pdu *request; 759 void *data = NULL; 760 size_t datasize; 761 int error; 762 763 is = PDU_SESSION(response); 764 bhsni = (struct iscsi_bhs_nop_in *)response->ip_bhs; 765 766 if (bhsni->bhsni_target_transfer_tag == 0xffffffff) { 767 /* 768 * Nothing to do; iscsi_pdu_update_statsn() already 769 * zeroed the timeout. 770 */ 771 icl_pdu_free(response); 772 return; 773 } 774 775 datasize = icl_pdu_data_segment_length(response); 776 if (datasize > 0) { 777 data = malloc(datasize, M_ISCSI, M_NOWAIT | M_ZERO); 778 if (data == NULL) { 779 ISCSI_SESSION_WARN(is, "failed to allocate memory; " 780 "reconnecting"); 781 icl_pdu_free(response); 782 iscsi_session_reconnect(is); 783 return; 784 } 785 icl_pdu_get_data(response, 0, data, datasize); 786 } 787 788 request = icl_pdu_new_bhs(response->ip_conn, M_NOWAIT); 789 if (request == NULL) { 790 ISCSI_SESSION_WARN(is, "failed to allocate memory; " 791 "reconnecting"); 792 free(data, M_ISCSI); 793 icl_pdu_free(response); 794 iscsi_session_reconnect(is); 795 return; 796 } 797 bhsno = (struct iscsi_bhs_nop_out *)request->ip_bhs; 798 bhsno->bhsno_opcode = ISCSI_BHS_OPCODE_NOP_OUT | 799 ISCSI_BHS_OPCODE_IMMEDIATE; 800 bhsno->bhsno_flags = 0x80; 801 bhsno->bhsno_initiator_task_tag = 0xffffffff; 802 bhsno->bhsno_target_transfer_tag = bhsni->bhsni_target_transfer_tag; 803 if (datasize > 0) { 804 error = icl_pdu_append_data(request, data, datasize, M_NOWAIT); 805 if (error != 0) { 806 ISCSI_SESSION_WARN(is, "failed to allocate memory; " 807 "reconnecting"); 808 free(data, M_ISCSI); 809 icl_pdu_free(request); 810 icl_pdu_free(response); 811 iscsi_session_reconnect(is); 812 return; 813 } 814 free(data, M_ISCSI); 815 } 816 817 icl_pdu_free(response); 818 iscsi_pdu_queue_locked(request); 819} 820 821static void 822iscsi_pdu_handle_scsi_response(struct icl_pdu *response) 823{ 824 struct iscsi_bhs_scsi_response *bhssr; 825 struct iscsi_outstanding *io; 826 struct iscsi_session *is; 827 struct ccb_scsiio *csio; 828 size_t data_segment_len; 829 uint16_t sense_len; 830 831 is = PDU_SESSION(response); 832 833 bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs; 834 io = iscsi_outstanding_find(is, bhssr->bhssr_initiator_task_tag); 835 if (io == NULL || io->io_ccb == NULL) { 836 ISCSI_SESSION_WARN(is, "bad itt 0x%x", bhssr->bhssr_initiator_task_tag); 837 icl_pdu_free(response); 838 iscsi_session_reconnect(is); 839 return; 840 } 841 842 if (bhssr->bhssr_response != BHSSR_RESPONSE_COMMAND_COMPLETED) { 843 ISCSI_SESSION_WARN(is, "service response 0x%x", bhssr->bhssr_response); 844 if ((io->io_ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 845 xpt_freeze_devq(io->io_ccb->ccb_h.path, 1); 846 ISCSI_SESSION_DEBUG(is, "freezing devq"); 847 } 848 io->io_ccb->ccb_h.status = CAM_REQ_CMP_ERR | CAM_DEV_QFRZN; 849 } else if (bhssr->bhssr_status == 0) { 850 io->io_ccb->ccb_h.status = CAM_REQ_CMP; 851 } else { 852 if ((io->io_ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 853 xpt_freeze_devq(io->io_ccb->ccb_h.path, 1); 854 ISCSI_SESSION_DEBUG(is, "freezing devq"); 855 } 856 io->io_ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_DEV_QFRZN; 857 io->io_ccb->csio.scsi_status = bhssr->bhssr_status; 858 } 859 860 if (bhssr->bhssr_flags & BHSSR_FLAGS_RESIDUAL_OVERFLOW) { 861 ISCSI_SESSION_WARN(is, "target indicated residual overflow"); 862 icl_pdu_free(response); 863 iscsi_session_reconnect(is); 864 return; 865 } 866 867 csio = &io->io_ccb->csio; 868 869 data_segment_len = icl_pdu_data_segment_length(response); 870 if (data_segment_len > 0) { 871 if (data_segment_len < sizeof(sense_len)) { 872 ISCSI_SESSION_WARN(is, "truncated data segment (%zd bytes)", 873 data_segment_len); 874 if ((io->io_ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 875 xpt_freeze_devq(io->io_ccb->ccb_h.path, 1); 876 ISCSI_SESSION_DEBUG(is, "freezing devq"); 877 } 878 io->io_ccb->ccb_h.status = CAM_REQ_CMP_ERR | CAM_DEV_QFRZN; 879 goto out; 880 } 881 icl_pdu_get_data(response, 0, &sense_len, sizeof(sense_len)); 882 sense_len = ntohs(sense_len); 883#if 0 884 ISCSI_SESSION_DEBUG(is, "sense_len %d, data len %zd", 885 sense_len, data_segment_len); 886#endif 887 if (sizeof(sense_len) + sense_len > data_segment_len) { 888 ISCSI_SESSION_WARN(is, "truncated data segment " 889 "(%zd bytes, should be %zd)", 890 data_segment_len, sizeof(sense_len) + sense_len); 891 if ((io->io_ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 892 xpt_freeze_devq(io->io_ccb->ccb_h.path, 1); 893 ISCSI_SESSION_DEBUG(is, "freezing devq"); 894 } 895 io->io_ccb->ccb_h.status = CAM_REQ_CMP_ERR | CAM_DEV_QFRZN; 896 goto out; 897 } else if (sizeof(sense_len) + sense_len < data_segment_len) 898 ISCSI_SESSION_WARN(is, "oversize data segment " 899 "(%zd bytes, should be %zd)", 900 data_segment_len, sizeof(sense_len) + sense_len); 901 if (sense_len > csio->sense_len) { 902 ISCSI_SESSION_DEBUG(is, "truncating sense from %d to %d", 903 sense_len, csio->sense_len); 904 sense_len = csio->sense_len; 905 } 906 icl_pdu_get_data(response, sizeof(sense_len), &csio->sense_data, sense_len); 907 csio->sense_resid = csio->sense_len - sense_len; 908 io->io_ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 909 } 910 911out: 912 if (bhssr->bhssr_flags & BHSSR_FLAGS_RESIDUAL_UNDERFLOW) 913 csio->resid = ntohl(bhssr->bhssr_residual_count); 914 915 if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 916 KASSERT(io->io_received <= csio->dxfer_len, 917 ("io->io_received > csio->dxfer_len")); 918 if (io->io_received < csio->dxfer_len) { 919 if (csio->resid != csio->dxfer_len - io->io_received) { 920 ISCSI_SESSION_WARN(is, "underflow mismatch: " 921 "target indicates %d, we calculated %zd", 922 csio->resid, 923 csio->dxfer_len - io->io_received); 924 } 925 csio->resid = csio->dxfer_len - io->io_received; 926 } 927 } 928 929 xpt_done(io->io_ccb); 930 iscsi_outstanding_remove(is, io); 931 icl_pdu_free(response); 932} 933 934static void 935iscsi_pdu_handle_task_response(struct icl_pdu *response) 936{ 937 struct iscsi_bhs_task_management_response *bhstmr; 938 struct iscsi_outstanding *io, *aio; 939 struct iscsi_session *is; 940 941 is = PDU_SESSION(response); 942 943 bhstmr = (struct iscsi_bhs_task_management_response *)response->ip_bhs; 944 io = iscsi_outstanding_find(is, bhstmr->bhstmr_initiator_task_tag); 945 if (io == NULL || io->io_ccb != NULL) { 946 ISCSI_SESSION_WARN(is, "bad itt 0x%x", 947 bhstmr->bhstmr_initiator_task_tag); 948 icl_pdu_free(response); 949 iscsi_session_reconnect(is); 950 return; 951 } 952 953 if (bhstmr->bhstmr_response != BHSTMR_RESPONSE_FUNCTION_COMPLETE) { 954 ISCSI_SESSION_WARN(is, "task response 0x%x", 955 bhstmr->bhstmr_response); 956 } else { 957 aio = iscsi_outstanding_find(is, io->io_datasn); 958 if (aio != NULL && aio->io_ccb != NULL) 959 iscsi_session_terminate_task(is, aio, false); 960 } 961 962 iscsi_outstanding_remove(is, io); 963 icl_pdu_free(response); 964} 965 966static void 967iscsi_pdu_handle_data_in(struct icl_pdu *response) 968{ 969 struct iscsi_bhs_data_in *bhsdi; 970 struct iscsi_outstanding *io; 971 struct iscsi_session *is; 972 struct ccb_scsiio *csio; 973 size_t data_segment_len; 974 975 is = PDU_SESSION(response); 976 bhsdi = (struct iscsi_bhs_data_in *)response->ip_bhs; 977 io = iscsi_outstanding_find(is, bhsdi->bhsdi_initiator_task_tag); 978 if (io == NULL || io->io_ccb == NULL) { 979 ISCSI_SESSION_WARN(is, "bad itt 0x%x", bhsdi->bhsdi_initiator_task_tag); 980 icl_pdu_free(response); 981 iscsi_session_reconnect(is); 982 return; 983 } 984 985 data_segment_len = icl_pdu_data_segment_length(response); 986 if (data_segment_len == 0) { 987 /* 988 * "The sending of 0 length data segments should be avoided, 989 * but initiators and targets MUST be able to properly receive 990 * 0 length data segments." 991 */ 992 icl_pdu_free(response); 993 return; 994 } 995 996 /* 997 * We need to track this for security reasons - without it, malicious target 998 * could respond to SCSI READ without sending Data-In PDUs, which would result 999 * in read operation on the initiator side returning random kernel data. 1000 */ 1001 if (ntohl(bhsdi->bhsdi_buffer_offset) != io->io_received) { 1002 ISCSI_SESSION_WARN(is, "data out of order; expected offset %zd, got %zd", 1003 io->io_received, (size_t)ntohl(bhsdi->bhsdi_buffer_offset)); 1004 icl_pdu_free(response); 1005 iscsi_session_reconnect(is); 1006 return; 1007 } 1008 1009 csio = &io->io_ccb->csio; 1010 1011 if (io->io_received + data_segment_len > csio->dxfer_len) { 1012 ISCSI_SESSION_WARN(is, "oversize data segment (%zd bytes " 1013 "at offset %zd, buffer is %d)", 1014 data_segment_len, io->io_received, csio->dxfer_len); 1015 icl_pdu_free(response); 1016 iscsi_session_reconnect(is); 1017 return; 1018 } 1019 1020 icl_pdu_get_data(response, 0, csio->data_ptr + io->io_received, data_segment_len); 1021 io->io_received += data_segment_len; 1022 1023 /* 1024 * XXX: Check DataSN. 1025 * XXX: Check F. 1026 */ 1027 if ((bhsdi->bhsdi_flags & BHSDI_FLAGS_S) == 0) { 1028 /* 1029 * Nothing more to do. 1030 */ 1031 icl_pdu_free(response); 1032 return; 1033 } 1034 1035 //ISCSI_SESSION_DEBUG(is, "got S flag; status 0x%x", bhsdi->bhsdi_status); 1036 if (bhsdi->bhsdi_status == 0) { 1037 io->io_ccb->ccb_h.status = CAM_REQ_CMP; 1038 } else { 1039 if ((io->io_ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 1040 xpt_freeze_devq(io->io_ccb->ccb_h.path, 1); 1041 ISCSI_SESSION_DEBUG(is, "freezing devq"); 1042 } 1043 io->io_ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_DEV_QFRZN; 1044 csio->scsi_status = bhsdi->bhsdi_status; 1045 } 1046 1047 if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1048 KASSERT(io->io_received <= csio->dxfer_len, 1049 ("io->io_received > csio->dxfer_len")); 1050 if (io->io_received < csio->dxfer_len) { 1051 csio->resid = ntohl(bhsdi->bhsdi_residual_count); 1052 if (csio->resid != csio->dxfer_len - io->io_received) { 1053 ISCSI_SESSION_WARN(is, "underflow mismatch: " 1054 "target indicates %d, we calculated %zd", 1055 csio->resid, 1056 csio->dxfer_len - io->io_received); 1057 } 1058 csio->resid = csio->dxfer_len - io->io_received; 1059 } 1060 } 1061 1062 xpt_done(io->io_ccb); 1063 iscsi_outstanding_remove(is, io); 1064 icl_pdu_free(response); 1065} 1066 1067static void 1068iscsi_pdu_handle_logout_response(struct icl_pdu *response) 1069{ 1070 1071 ISCSI_SESSION_DEBUG(PDU_SESSION(response), "logout response"); 1072 icl_pdu_free(response); 1073} 1074 1075static void 1076iscsi_pdu_handle_r2t(struct icl_pdu *response) 1077{ 1078 struct icl_pdu *request; 1079 struct iscsi_session *is; 1080 struct iscsi_bhs_r2t *bhsr2t; 1081 struct iscsi_bhs_data_out *bhsdo; 1082 struct iscsi_outstanding *io; 1083 struct ccb_scsiio *csio; 1084 size_t off, len, total_len; 1085 int error; 1086 1087 is = PDU_SESSION(response); 1088 1089 bhsr2t = (struct iscsi_bhs_r2t *)response->ip_bhs; 1090 io = iscsi_outstanding_find(is, bhsr2t->bhsr2t_initiator_task_tag); 1091 if (io == NULL || io->io_ccb == NULL) { 1092 ISCSI_SESSION_WARN(is, "bad itt 0x%x; reconnecting", 1093 bhsr2t->bhsr2t_initiator_task_tag); 1094 icl_pdu_free(response); 1095 iscsi_session_reconnect(is); 1096 return; 1097 } 1098 1099 csio = &io->io_ccb->csio; 1100 1101 if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_OUT) { 1102 ISCSI_SESSION_WARN(is, "received R2T for read command; reconnecting"); 1103 icl_pdu_free(response); 1104 iscsi_session_reconnect(is); 1105 return; 1106 } 1107 1108 /* 1109 * XXX: Verify R2TSN. 1110 */ 1111 1112 io->io_datasn = 0; 1113 1114 off = ntohl(bhsr2t->bhsr2t_buffer_offset); 1115 if (off > csio->dxfer_len) { 1116 ISCSI_SESSION_WARN(is, "target requested invalid offset " 1117 "%zd, buffer is is %d; reconnecting", off, csio->dxfer_len); 1118 icl_pdu_free(response); 1119 iscsi_session_reconnect(is); 1120 return; 1121 } 1122 1123 total_len = ntohl(bhsr2t->bhsr2t_desired_data_transfer_length); 1124 if (total_len == 0 || total_len > csio->dxfer_len) { 1125 ISCSI_SESSION_WARN(is, "target requested invalid length " 1126 "%zd, buffer is %d; reconnecting", total_len, csio->dxfer_len); 1127 icl_pdu_free(response); 1128 iscsi_session_reconnect(is); 1129 return; 1130 } 1131 1132 //ISCSI_SESSION_DEBUG(is, "r2t; off %zd, len %zd", off, total_len); 1133 1134 for (;;) { 1135 len = total_len; 1136 1137 if (len > is->is_max_data_segment_length) 1138 len = is->is_max_data_segment_length; 1139 1140 if (off + len > csio->dxfer_len) { 1141 ISCSI_SESSION_WARN(is, "target requested invalid " 1142 "length/offset %zd, buffer is %d; reconnecting", 1143 off + len, csio->dxfer_len); 1144 icl_pdu_free(response); 1145 iscsi_session_reconnect(is); 1146 return; 1147 } 1148 1149 request = icl_pdu_new_bhs(response->ip_conn, M_NOWAIT); 1150 if (request == NULL) { 1151 icl_pdu_free(response); 1152 iscsi_session_reconnect(is); 1153 return; 1154 } 1155 1156 bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs; 1157 bhsdo->bhsdo_opcode = ISCSI_BHS_OPCODE_SCSI_DATA_OUT; 1158 bhsdo->bhsdo_lun = bhsr2t->bhsr2t_lun; 1159 bhsdo->bhsdo_initiator_task_tag = 1160 bhsr2t->bhsr2t_initiator_task_tag; 1161 bhsdo->bhsdo_target_transfer_tag = 1162 bhsr2t->bhsr2t_target_transfer_tag; 1163 bhsdo->bhsdo_datasn = htonl(io->io_datasn++); 1164 bhsdo->bhsdo_buffer_offset = htonl(off); 1165 error = icl_pdu_append_data(request, csio->data_ptr + off, len, 1166 M_NOWAIT); 1167 if (error != 0) { 1168 ISCSI_SESSION_WARN(is, "failed to allocate memory; " 1169 "reconnecting"); 1170 icl_pdu_free(request); 1171 icl_pdu_free(response); 1172 iscsi_session_reconnect(is); 1173 return; 1174 } 1175 1176 off += len; 1177 total_len -= len; 1178 1179 if (total_len == 0) { 1180 bhsdo->bhsdo_flags |= BHSDO_FLAGS_F; 1181 //ISCSI_SESSION_DEBUG(is, "setting F, off %zd", off); 1182 } else { 1183 //ISCSI_SESSION_DEBUG(is, "not finished, off %zd", off); 1184 } 1185 1186 iscsi_pdu_queue_locked(request); 1187 1188 if (total_len == 0) 1189 break; 1190 } 1191 1192 icl_pdu_free(response); 1193} 1194 1195static void 1196iscsi_pdu_handle_async_message(struct icl_pdu *response) 1197{ 1198 struct iscsi_bhs_asynchronous_message *bhsam; 1199 struct iscsi_session *is; 1200 1201 is = PDU_SESSION(response); 1202 bhsam = (struct iscsi_bhs_asynchronous_message *)response->ip_bhs; 1203 switch (bhsam->bhsam_async_event) { 1204 case BHSAM_EVENT_TARGET_REQUESTS_LOGOUT: 1205 ISCSI_SESSION_WARN(is, "target requests logout; removing session"); 1206 iscsi_session_logout(is); 1207 iscsi_session_terminate(is); 1208 break; 1209 case BHSAM_EVENT_TARGET_TERMINATES_CONNECTION: 1210 ISCSI_SESSION_WARN(is, "target indicates it will drop drop the connection"); 1211 break; 1212 case BHSAM_EVENT_TARGET_TERMINATES_SESSION: 1213 ISCSI_SESSION_WARN(is, "target indicates it will drop drop the session"); 1214 break; 1215 default: 1216 /* 1217 * XXX: Technically, we're obligated to also handle 1218 * parameter renegotiation. 1219 */ 1220 ISCSI_SESSION_WARN(is, "ignoring AsyncEvent %d", bhsam->bhsam_async_event); 1221 break; 1222 } 1223 1224 icl_pdu_free(response); 1225} 1226 1227static void 1228iscsi_pdu_handle_reject(struct icl_pdu *response) 1229{ 1230 struct iscsi_bhs_reject *bhsr; 1231 struct iscsi_session *is; 1232 1233 is = PDU_SESSION(response); 1234 bhsr = (struct iscsi_bhs_reject *)response->ip_bhs; 1235 ISCSI_SESSION_WARN(is, "received Reject PDU, reason 0x%x; protocol error?", 1236 bhsr->bhsr_reason); 1237 1238 icl_pdu_free(response); 1239} 1240 1241static int 1242iscsi_ioctl_daemon_wait(struct iscsi_softc *sc, 1243 struct iscsi_daemon_request *request) 1244{ 1245 struct iscsi_session *is; 1246 int error; 1247 1248 sx_slock(&sc->sc_lock); 1249 for (;;) { 1250 TAILQ_FOREACH(is, &sc->sc_sessions, is_next) { 1251 ISCSI_SESSION_LOCK(is); 1252 if (is->is_waiting_for_iscsid) 1253 break; 1254 ISCSI_SESSION_UNLOCK(is); 1255 } 1256 1257 if (is == NULL) { 1258 /* 1259 * No session requires attention from iscsid(8); wait. 1260 */ 1261 error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock); 1262 if (error != 0) { 1263 sx_sunlock(&sc->sc_lock); 1264 return (error); 1265 } 1266 continue; 1267 } 1268 1269 is->is_waiting_for_iscsid = false; 1270 is->is_login_phase = true; 1271 is->is_reason[0] = '\0'; 1272 ISCSI_SESSION_UNLOCK(is); 1273 1274 request->idr_session_id = is->is_id; 1275 memcpy(&request->idr_isid, &is->is_isid, 1276 sizeof(request->idr_isid)); 1277 request->idr_tsih = 0; /* New or reinstated session. */ 1278 memcpy(&request->idr_conf, &is->is_conf, 1279 sizeof(request->idr_conf)); 1280 1281 sx_sunlock(&sc->sc_lock); 1282 return (0); 1283 } 1284} 1285 1286static int 1287iscsi_ioctl_daemon_handoff(struct iscsi_softc *sc, 1288 struct iscsi_daemon_handoff *handoff) 1289{ 1290 struct iscsi_session *is; 1291 int error; 1292 1293 sx_slock(&sc->sc_lock); 1294 1295 /* 1296 * Find the session to hand off socket to. 1297 */ 1298 TAILQ_FOREACH(is, &sc->sc_sessions, is_next) { 1299 if (is->is_id == handoff->idh_session_id) 1300 break; 1301 } 1302 if (is == NULL) { 1303 sx_sunlock(&sc->sc_lock); 1304 return (ESRCH); 1305 } 1306 ISCSI_SESSION_LOCK(is); 1307 if (is->is_conf.isc_discovery || is->is_terminating) { 1308 ISCSI_SESSION_UNLOCK(is); 1309 sx_sunlock(&sc->sc_lock); 1310 return (EINVAL); 1311 } 1312 if (is->is_connected) { 1313 /* 1314 * This might have happened because another iscsid(8) 1315 * instance handed off the connection in the meantime. 1316 * Just return. 1317 */ 1318 ISCSI_SESSION_WARN(is, "handoff on already connected " 1319 "session"); 1320 ISCSI_SESSION_UNLOCK(is); 1321 sx_sunlock(&sc->sc_lock); 1322 return (EBUSY); 1323 } 1324 1325 strlcpy(is->is_target_alias, handoff->idh_target_alias, 1326 sizeof(is->is_target_alias)); 1327 is->is_tsih = handoff->idh_tsih; 1328 is->is_statsn = handoff->idh_statsn; 1329 is->is_initial_r2t = handoff->idh_initial_r2t; 1330 is->is_immediate_data = handoff->idh_immediate_data; 1331 is->is_max_data_segment_length = handoff->idh_max_data_segment_length; 1332 is->is_max_burst_length = handoff->idh_max_burst_length; 1333 is->is_first_burst_length = handoff->idh_first_burst_length; 1334 1335 if (handoff->idh_header_digest == ISCSI_DIGEST_CRC32C) 1336 is->is_conn->ic_header_crc32c = true; 1337 else 1338 is->is_conn->ic_header_crc32c = false; 1339 if (handoff->idh_data_digest == ISCSI_DIGEST_CRC32C) 1340 is->is_conn->ic_data_crc32c = true; 1341 else 1342 is->is_conn->ic_data_crc32c = false; 1343 1344 is->is_cmdsn = 0; 1345 is->is_expcmdsn = 0; 1346 is->is_maxcmdsn = 0; 1347 is->is_waiting_for_iscsid = false; 1348 is->is_login_phase = false; 1349 is->is_timeout = 0; 1350 is->is_connected = true; 1351 is->is_reason[0] = '\0'; 1352 1353 ISCSI_SESSION_UNLOCK(is); 1354 1355#ifdef ICL_KERNEL_PROXY 1356 if (handoff->idh_socket != 0) { 1357#endif 1358 /* 1359 * Handoff without using ICL proxy. 1360 */ 1361 error = icl_conn_handoff(is->is_conn, handoff->idh_socket); 1362 if (error != 0) { 1363 sx_sunlock(&sc->sc_lock); 1364 iscsi_session_terminate(is); 1365 return (error); 1366 } 1367#ifdef ICL_KERNEL_PROXY 1368 } 1369#endif 1370 1371 sx_sunlock(&sc->sc_lock); 1372 1373 if (is->is_sim != NULL) { 1374 /* 1375 * When reconnecting, there already is SIM allocated for the session. 1376 */ 1377 KASSERT(is->is_simq_frozen, ("reconnect without frozen simq")); 1378 ISCSI_SESSION_LOCK(is); 1379 ISCSI_SESSION_DEBUG(is, "releasing"); 1380 xpt_release_simq(is->is_sim, 1); 1381 is->is_simq_frozen = false; 1382 ISCSI_SESSION_UNLOCK(is); 1383 1384 } else { 1385 ISCSI_SESSION_LOCK(is); 1386 is->is_devq = cam_simq_alloc(maxtags); 1387 if (is->is_devq == NULL) { 1388 ISCSI_SESSION_WARN(is, "failed to allocate simq"); 1389 iscsi_session_terminate(is); 1390 return (ENOMEM); 1391 } 1392 1393 is->is_sim = cam_sim_alloc(iscsi_action, iscsi_poll, "iscsi", 1394 is, is->is_id /* unit */, &is->is_lock, 1395 1, maxtags, is->is_devq); 1396 if (is->is_sim == NULL) { 1397 ISCSI_SESSION_UNLOCK(is); 1398 ISCSI_SESSION_WARN(is, "failed to allocate SIM"); 1399 cam_simq_free(is->is_devq); 1400 iscsi_session_terminate(is); 1401 return (ENOMEM); 1402 } 1403 1404 error = xpt_bus_register(is->is_sim, NULL, 0); 1405 if (error != 0) { 1406 ISCSI_SESSION_UNLOCK(is); 1407 ISCSI_SESSION_WARN(is, "failed to register bus"); 1408 iscsi_session_terminate(is); 1409 return (ENOMEM); 1410 } 1411 1412 error = xpt_create_path(&is->is_path, /*periph*/NULL, 1413 cam_sim_path(is->is_sim), CAM_TARGET_WILDCARD, 1414 CAM_LUN_WILDCARD); 1415 if (error != CAM_REQ_CMP) { 1416 ISCSI_SESSION_UNLOCK(is); 1417 ISCSI_SESSION_WARN(is, "failed to create path"); 1418 iscsi_session_terminate(is); 1419 return (ENOMEM); 1420 } 1421 ISCSI_SESSION_UNLOCK(is); 1422 } 1423 1424 return (0); 1425} 1426 1427static int 1428iscsi_ioctl_daemon_fail(struct iscsi_softc *sc, 1429 struct iscsi_daemon_fail *fail) 1430{ 1431 struct iscsi_session *is; 1432 1433 sx_slock(&sc->sc_lock); 1434 1435 TAILQ_FOREACH(is, &sc->sc_sessions, is_next) { 1436 if (is->is_id == fail->idf_session_id) 1437 break; 1438 } 1439 if (is == NULL) { 1440 sx_sunlock(&sc->sc_lock); 1441 return (ESRCH); 1442 } 1443 ISCSI_SESSION_LOCK(is); 1444 ISCSI_SESSION_DEBUG(is, "iscsid(8) failed: %s", 1445 fail->idf_reason); 1446 strlcpy(is->is_reason, fail->idf_reason, sizeof(is->is_reason)); 1447 //is->is_waiting_for_iscsid = false; 1448 //is->is_login_phase = true; 1449 //iscsi_session_reconnect(is); 1450 ISCSI_SESSION_UNLOCK(is); 1451 sx_sunlock(&sc->sc_lock); 1452 1453 return (0); 1454} 1455 1456#ifdef ICL_KERNEL_PROXY 1457static int 1458iscsi_ioctl_daemon_connect(struct iscsi_softc *sc, 1459 struct iscsi_daemon_connect *idc) 1460{ 1461 struct iscsi_session *is; 1462 struct sockaddr *from_sa, *to_sa; 1463 int error; 1464 1465 sx_slock(&sc->sc_lock); 1466 TAILQ_FOREACH(is, &sc->sc_sessions, is_next) { 1467 if (is->is_id == idc->idc_session_id) 1468 break; 1469 } 1470 if (is == NULL) { 1471 sx_sunlock(&sc->sc_lock); 1472 return (ESRCH); 1473 } 1474 sx_sunlock(&sc->sc_lock); 1475 1476 if (idc->idc_from_addrlen > 0) { 1477 error = getsockaddr(&from_sa, (void *)idc->idc_from_addr, idc->idc_from_addrlen); 1478 if (error != 0) { 1479 ISCSI_SESSION_WARN(is, 1480 "getsockaddr failed with error %d", error); 1481 return (error); 1482 } 1483 } else { 1484 from_sa = NULL; 1485 } 1486 error = getsockaddr(&to_sa, (void *)idc->idc_to_addr, idc->idc_to_addrlen); 1487 if (error != 0) { 1488 ISCSI_SESSION_WARN(is, "getsockaddr failed with error %d", 1489 error); 1490 free(from_sa, M_SONAME); 1491 return (error); 1492 } 1493 1494 ISCSI_SESSION_LOCK(is); 1495 is->is_waiting_for_iscsid = false; 1496 is->is_login_phase = true; 1497 is->is_timeout = 0; 1498 ISCSI_SESSION_UNLOCK(is); 1499 1500 error = icl_conn_connect(is->is_conn, idc->idc_iser, idc->idc_domain, 1501 idc->idc_socktype, idc->idc_protocol, from_sa, to_sa); 1502 free(from_sa, M_SONAME); 1503 free(to_sa, M_SONAME); 1504 1505 /* 1506 * Digests are always disabled during login phase. 1507 */ 1508 is->is_conn->ic_header_crc32c = false; 1509 is->is_conn->ic_data_crc32c = false; 1510 1511 return (error); 1512} 1513 1514static int 1515iscsi_ioctl_daemon_send(struct iscsi_softc *sc, 1516 struct iscsi_daemon_send *ids) 1517{ 1518 struct iscsi_session *is; 1519 struct icl_pdu *ip; 1520 size_t datalen; 1521 void *data; 1522 int error; 1523 1524 sx_slock(&sc->sc_lock); 1525 TAILQ_FOREACH(is, &sc->sc_sessions, is_next) { 1526 if (is->is_id == ids->ids_session_id) 1527 break; 1528 } 1529 if (is == NULL) { 1530 sx_sunlock(&sc->sc_lock); 1531 return (ESRCH); 1532 } 1533 sx_sunlock(&sc->sc_lock); 1534 1535 if (is->is_login_phase == false) 1536 return (EBUSY); 1537 1538 if (is->is_terminating || is->is_reconnecting) 1539 return (EIO); 1540 1541 datalen = ids->ids_data_segment_len; 1542 if (datalen > ISCSI_MAX_DATA_SEGMENT_LENGTH) 1543 return (EINVAL); 1544 if (datalen > 0) { 1545 data = malloc(datalen, M_ISCSI, M_WAITOK); 1546 error = copyin(ids->ids_data_segment, data, datalen); 1547 if (error != 0) { 1548 free(data, M_ISCSI); 1549 return (error); 1550 } 1551 } 1552 1553 ip = icl_pdu_new_bhs(is->is_conn, M_WAITOK); 1554 memcpy(ip->ip_bhs, ids->ids_bhs, sizeof(*ip->ip_bhs)); 1555 if (datalen > 0) { 1556 error = icl_pdu_append_data(ip, data, datalen, M_WAITOK); 1557 KASSERT(error == 0, ("icl_pdu_append_data(..., M_WAITOK) failed")); 1558 free(data, M_ISCSI); 1559 } 1560 icl_pdu_queue(ip); 1561 1562 return (0); 1563} 1564 1565static int 1566iscsi_ioctl_daemon_receive(struct iscsi_softc *sc, 1567 struct iscsi_daemon_receive *idr) 1568{ 1569 struct iscsi_session *is; 1570 struct icl_pdu *ip; 1571 void *data; 1572 1573 sx_slock(&sc->sc_lock); 1574 TAILQ_FOREACH(is, &sc->sc_sessions, is_next) { 1575 if (is->is_id == idr->idr_session_id) 1576 break; 1577 } 1578 if (is == NULL) { 1579 sx_sunlock(&sc->sc_lock); 1580 return (ESRCH); 1581 } 1582 sx_sunlock(&sc->sc_lock); 1583 1584 if (is->is_login_phase == false) 1585 return (EBUSY); 1586 1587 ISCSI_SESSION_LOCK(is); 1588 while (is->is_login_pdu == NULL && 1589 is->is_terminating == false && 1590 is->is_reconnecting == false) 1591 cv_wait(&is->is_login_cv, &is->is_lock); 1592 if (is->is_terminating || is->is_reconnecting) { 1593 ISCSI_SESSION_UNLOCK(is); 1594 return (EIO); 1595 } 1596 ip = is->is_login_pdu; 1597 is->is_login_pdu = NULL; 1598 ISCSI_SESSION_UNLOCK(is); 1599 1600 if (ip->ip_data_len > idr->idr_data_segment_len) { 1601 icl_pdu_free(ip); 1602 return (EMSGSIZE); 1603 } 1604 1605 copyout(ip->ip_bhs, idr->idr_bhs, sizeof(*ip->ip_bhs)); 1606 if (ip->ip_data_len > 0) { 1607 data = malloc(ip->ip_data_len, M_ISCSI, M_WAITOK); 1608 icl_pdu_get_data(ip, 0, data, ip->ip_data_len); 1609 copyout(data, idr->idr_data_segment, ip->ip_data_len); 1610 free(data, M_ISCSI); 1611 } 1612 1613 icl_pdu_free(ip); 1614 1615 return (0); 1616} 1617#endif /* ICL_KERNEL_PROXY */ 1618 1619static void 1620iscsi_sanitize_session_conf(struct iscsi_session_conf *isc) 1621{ 1622 /* 1623 * Just make sure all the fields are null-terminated. 1624 * 1625 * XXX: This is not particularly secure. We should 1626 * create our own conf and then copy in relevant 1627 * fields. 1628 */ 1629 isc->isc_initiator[ISCSI_NAME_LEN - 1] = '\0'; 1630 isc->isc_initiator_addr[ISCSI_ADDR_LEN - 1] = '\0'; 1631 isc->isc_initiator_alias[ISCSI_ALIAS_LEN - 1] = '\0'; 1632 isc->isc_target[ISCSI_NAME_LEN - 1] = '\0'; 1633 isc->isc_target_addr[ISCSI_ADDR_LEN - 1] = '\0'; 1634 isc->isc_user[ISCSI_NAME_LEN - 1] = '\0'; 1635 isc->isc_secret[ISCSI_SECRET_LEN - 1] = '\0'; 1636 isc->isc_mutual_user[ISCSI_NAME_LEN - 1] = '\0'; 1637 isc->isc_mutual_secret[ISCSI_SECRET_LEN - 1] = '\0'; 1638} 1639 1640static bool 1641iscsi_valid_session_conf(const struct iscsi_session_conf *isc) 1642{ 1643 1644 if (isc->isc_initiator[0] == '\0') { 1645 ISCSI_DEBUG("empty isc_initiator"); 1646 return (false); 1647 } 1648 1649 if (isc->isc_target_addr[0] == '\0') { 1650 ISCSI_DEBUG("empty isc_target_addr"); 1651 return (false); 1652 } 1653 1654 if (isc->isc_discovery != 0 && isc->isc_target[0] != 0) { 1655 ISCSI_DEBUG("non-empty isc_target for discovery session"); 1656 return (false); 1657 } 1658 1659 if (isc->isc_discovery == 0 && isc->isc_target[0] == 0) { 1660 ISCSI_DEBUG("empty isc_target for non-discovery session"); 1661 return (false); 1662 } 1663 1664 return (true); 1665} 1666 1667static int 1668iscsi_ioctl_session_add(struct iscsi_softc *sc, struct iscsi_session_add *isa) 1669{ 1670 struct iscsi_session *is; 1671 const struct iscsi_session *is2; 1672 int error; 1673 1674 iscsi_sanitize_session_conf(&isa->isa_conf); 1675 if (iscsi_valid_session_conf(&isa->isa_conf) == false) 1676 return (EINVAL); 1677 1678 is = malloc(sizeof(*is), M_ISCSI, M_ZERO | M_WAITOK); 1679 memcpy(&is->is_conf, &isa->isa_conf, sizeof(is->is_conf)); 1680 1681 sx_xlock(&sc->sc_lock); 1682 1683 /* 1684 * Prevent duplicates. 1685 */ 1686 TAILQ_FOREACH(is2, &sc->sc_sessions, is_next) { 1687 if (!!is->is_conf.isc_discovery != 1688 !!is2->is_conf.isc_discovery) 1689 continue; 1690 1691 if (strcmp(is->is_conf.isc_target_addr, 1692 is2->is_conf.isc_target_addr) != 0) 1693 continue; 1694 1695 if (is->is_conf.isc_discovery == 0 && 1696 strcmp(is->is_conf.isc_target, 1697 is2->is_conf.isc_target) != 0) 1698 continue; 1699 1700 sx_xunlock(&sc->sc_lock); 1701 free(is, M_ISCSI); 1702 return (EBUSY); 1703 } 1704 1705 is->is_conn = icl_conn_new("iscsi", &is->is_lock); 1706 is->is_conn->ic_receive = iscsi_receive_callback; 1707 is->is_conn->ic_error = iscsi_error_callback; 1708 is->is_conn->ic_prv0 = is; 1709 TAILQ_INIT(&is->is_outstanding); 1710 STAILQ_INIT(&is->is_postponed); 1711 mtx_init(&is->is_lock, "iscsi_lock", NULL, MTX_DEF); 1712 cv_init(&is->is_maintenance_cv, "iscsi_mt"); 1713#ifdef ICL_KERNEL_PROXY 1714 cv_init(&is->is_login_cv, "iscsi_login"); 1715#endif 1716 1717 is->is_softc = sc; 1718 sc->sc_last_session_id++; 1719 is->is_id = sc->sc_last_session_id; 1720 is->is_isid[0] = 0x80; /* RFC 3720, 10.12.5: 10b, "Random" ISID. */ 1721 arc4rand(&is->is_isid[1], 5, 0); 1722 is->is_tsih = 0; 1723 callout_init(&is->is_callout, 1); 1724 callout_reset(&is->is_callout, 1 * hz, iscsi_callout, is); 1725 TAILQ_INSERT_TAIL(&sc->sc_sessions, is, is_next); 1726 1727 error = kthread_add(iscsi_maintenance_thread, is, NULL, NULL, 0, 0, "iscsimt"); 1728 if (error != 0) { 1729 ISCSI_SESSION_WARN(is, "kthread_add(9) failed with error %d", error); 1730 return (error); 1731 } 1732 1733 /* 1734 * Trigger immediate reconnection. 1735 */ 1736 ISCSI_SESSION_LOCK(is); 1737 is->is_waiting_for_iscsid = true; 1738 strlcpy(is->is_reason, "Waiting for iscsid(8)", sizeof(is->is_reason)); 1739 ISCSI_SESSION_UNLOCK(is); 1740 cv_signal(&sc->sc_cv); 1741 1742 sx_xunlock(&sc->sc_lock); 1743 1744 return (0); 1745} 1746 1747static bool 1748iscsi_session_conf_matches(unsigned int id1, const struct iscsi_session_conf *c1, 1749 unsigned int id2, const struct iscsi_session_conf *c2) 1750{ 1751 if (id2 == 0 && c2->isc_target[0] == '\0' && 1752 c2->isc_target_addr[0] == '\0') 1753 return (true); 1754 if (id2 != 0 && id2 == id1) 1755 return (true); 1756 if (c2->isc_target[0] != '\0' && 1757 strcmp(c1->isc_target, c2->isc_target) == 0) 1758 return (true); 1759 if (c2->isc_target_addr[0] != '\0' && 1760 strcmp(c1->isc_target_addr, c2->isc_target_addr) == 0) 1761 return (true); 1762 return (false); 1763} 1764 1765static int 1766iscsi_ioctl_session_remove(struct iscsi_softc *sc, 1767 struct iscsi_session_remove *isr) 1768{ 1769 struct iscsi_session *is, *tmp; 1770 bool found = false; 1771 1772 iscsi_sanitize_session_conf(&isr->isr_conf); 1773 1774 sx_xlock(&sc->sc_lock); 1775 TAILQ_FOREACH_SAFE(is, &sc->sc_sessions, is_next, tmp) { 1776 ISCSI_SESSION_LOCK(is); 1777 if (iscsi_session_conf_matches(is->is_id, &is->is_conf, 1778 isr->isr_session_id, &isr->isr_conf)) { 1779 found = true; 1780 iscsi_session_logout(is); 1781 iscsi_session_terminate(is); 1782 } 1783 ISCSI_SESSION_UNLOCK(is); 1784 } 1785 sx_xunlock(&sc->sc_lock); 1786 1787 if (!found) 1788 return (ESRCH); 1789 1790 return (0); 1791} 1792 1793static int 1794iscsi_ioctl_session_list(struct iscsi_softc *sc, struct iscsi_session_list *isl) 1795{ 1796 int error; 1797 unsigned int i = 0; 1798 struct iscsi_session *is; 1799 struct iscsi_session_state iss; 1800 1801 sx_slock(&sc->sc_lock); 1802 TAILQ_FOREACH(is, &sc->sc_sessions, is_next) { 1803 if (i >= isl->isl_nentries) { 1804 sx_sunlock(&sc->sc_lock); 1805 return (EMSGSIZE); 1806 } 1807 memset(&iss, 0, sizeof(iss)); 1808 memcpy(&iss.iss_conf, &is->is_conf, sizeof(iss.iss_conf)); 1809 iss.iss_id = is->is_id; 1810 strlcpy(iss.iss_target_alias, is->is_target_alias, sizeof(iss.iss_target_alias)); 1811 strlcpy(iss.iss_reason, is->is_reason, sizeof(iss.iss_reason)); 1812 1813 if (is->is_conn->ic_header_crc32c) 1814 iss.iss_header_digest = ISCSI_DIGEST_CRC32C; 1815 else 1816 iss.iss_header_digest = ISCSI_DIGEST_NONE; 1817 1818 if (is->is_conn->ic_data_crc32c) 1819 iss.iss_data_digest = ISCSI_DIGEST_CRC32C; 1820 else 1821 iss.iss_data_digest = ISCSI_DIGEST_NONE; 1822 1823 iss.iss_max_data_segment_length = is->is_max_data_segment_length; 1824 iss.iss_immediate_data = is->is_immediate_data; 1825 iss.iss_connected = is->is_connected; 1826 1827 error = copyout(&iss, isl->isl_pstates + i, sizeof(iss)); 1828 if (error != 0) { 1829 sx_sunlock(&sc->sc_lock); 1830 return (error); 1831 } 1832 i++; 1833 } 1834 sx_sunlock(&sc->sc_lock); 1835 1836 isl->isl_nentries = i; 1837 1838 return (0); 1839} 1840 1841static int 1842iscsi_ioctl_session_modify(struct iscsi_softc *sc, 1843 struct iscsi_session_modify *ism) 1844{ 1845 struct iscsi_session *is; 1846 1847 iscsi_sanitize_session_conf(&ism->ism_conf); 1848 if (iscsi_valid_session_conf(&ism->ism_conf) == false) 1849 return (EINVAL); 1850 1851 sx_xlock(&sc->sc_lock); 1852 TAILQ_FOREACH(is, &sc->sc_sessions, is_next) { 1853 ISCSI_SESSION_LOCK(is); 1854 if (is->is_id == ism->ism_session_id) 1855 break; 1856 ISCSI_SESSION_UNLOCK(is); 1857 } 1858 if (is == NULL) { 1859 sx_xunlock(&sc->sc_lock); 1860 return (ESRCH); 1861 } 1862 sx_xunlock(&sc->sc_lock); 1863 1864 memcpy(&is->is_conf, &ism->ism_conf, sizeof(is->is_conf)); 1865 ISCSI_SESSION_UNLOCK(is); 1866 1867 iscsi_session_reconnect(is); 1868 1869 return (0); 1870} 1871 1872static int 1873iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, 1874 struct thread *td) 1875{ 1876 struct iscsi_softc *sc; 1877 1878 sc = dev->si_drv1; 1879 1880 switch (cmd) { 1881 case ISCSIDWAIT: 1882 return (iscsi_ioctl_daemon_wait(sc, 1883 (struct iscsi_daemon_request *)arg)); 1884 case ISCSIDHANDOFF: 1885 return (iscsi_ioctl_daemon_handoff(sc, 1886 (struct iscsi_daemon_handoff *)arg)); 1887 case ISCSIDFAIL: 1888 return (iscsi_ioctl_daemon_fail(sc, 1889 (struct iscsi_daemon_fail *)arg)); 1890#ifdef ICL_KERNEL_PROXY 1891 case ISCSIDCONNECT: 1892 return (iscsi_ioctl_daemon_connect(sc, 1893 (struct iscsi_daemon_connect *)arg)); 1894 case ISCSIDSEND: 1895 return (iscsi_ioctl_daemon_send(sc, 1896 (struct iscsi_daemon_send *)arg)); 1897 case ISCSIDRECEIVE: 1898 return (iscsi_ioctl_daemon_receive(sc, 1899 (struct iscsi_daemon_receive *)arg)); 1900#endif /* ICL_KERNEL_PROXY */ 1901 case ISCSISADD: 1902 return (iscsi_ioctl_session_add(sc, 1903 (struct iscsi_session_add *)arg)); 1904 case ISCSISREMOVE: 1905 return (iscsi_ioctl_session_remove(sc, 1906 (struct iscsi_session_remove *)arg)); 1907 case ISCSISLIST: 1908 return (iscsi_ioctl_session_list(sc, 1909 (struct iscsi_session_list *)arg)); 1910 case ISCSISMODIFY: 1911 return (iscsi_ioctl_session_modify(sc, 1912 (struct iscsi_session_modify *)arg)); 1913 default: 1914 return (EINVAL); 1915 } 1916} 1917 1918static uint64_t 1919iscsi_encode_lun(uint32_t lun) 1920{ 1921 uint8_t encoded[8]; 1922 uint64_t result; 1923 1924 memset(encoded, 0, sizeof(encoded)); 1925 1926 if (lun < 256) { 1927 /* 1928 * Peripheral device addressing. 1929 */ 1930 encoded[1] = lun; 1931 } else if (lun < 16384) { 1932 /* 1933 * Flat space addressing. 1934 */ 1935 encoded[0] = 0x40; 1936 encoded[0] |= (lun >> 8) & 0x3f; 1937 encoded[1] = lun & 0xff; 1938 } else { 1939 /* 1940 * Extended flat space addressing. 1941 */ 1942 encoded[0] = 0xd2; 1943 encoded[1] = lun >> 16; 1944 encoded[2] = lun >> 8; 1945 encoded[3] = lun; 1946 } 1947 1948 memcpy(&result, encoded, sizeof(result)); 1949 return (result); 1950} 1951 1952static struct iscsi_outstanding * 1953iscsi_outstanding_find(struct iscsi_session *is, uint32_t initiator_task_tag) 1954{ 1955 struct iscsi_outstanding *io; 1956 1957 ISCSI_SESSION_LOCK_ASSERT(is); 1958 1959 TAILQ_FOREACH(io, &is->is_outstanding, io_next) { 1960 if (io->io_initiator_task_tag == initiator_task_tag) 1961 return (io); 1962 } 1963 return (NULL); 1964} 1965 1966static struct iscsi_outstanding * 1967iscsi_outstanding_find_ccb(struct iscsi_session *is, union ccb *ccb) 1968{ 1969 struct iscsi_outstanding *io; 1970 1971 ISCSI_SESSION_LOCK_ASSERT(is); 1972 1973 TAILQ_FOREACH(io, &is->is_outstanding, io_next) { 1974 if (io->io_ccb == ccb) 1975 return (io); 1976 } 1977 return (NULL); 1978} 1979 1980static struct iscsi_outstanding * 1981iscsi_outstanding_add(struct iscsi_session *is, 1982 uint32_t initiator_task_tag, union ccb *ccb) 1983{ 1984 struct iscsi_outstanding *io; 1985 1986 ISCSI_SESSION_LOCK_ASSERT(is); 1987 1988 KASSERT(iscsi_outstanding_find(is, initiator_task_tag) == NULL, 1989 ("initiator_task_tag 0x%x already added", initiator_task_tag)); 1990 1991 io = uma_zalloc(iscsi_outstanding_zone, M_NOWAIT | M_ZERO); 1992 if (io == NULL) { 1993 ISCSI_SESSION_WARN(is, "failed to allocate %zd bytes", sizeof(*io)); 1994 return (NULL); 1995 } 1996 io->io_initiator_task_tag = initiator_task_tag; 1997 io->io_ccb = ccb; 1998 TAILQ_INSERT_TAIL(&is->is_outstanding, io, io_next); 1999 return (io); 2000} 2001 2002static void 2003iscsi_outstanding_remove(struct iscsi_session *is, struct iscsi_outstanding *io) 2004{ 2005 2006 ISCSI_SESSION_LOCK_ASSERT(is); 2007 2008 TAILQ_REMOVE(&is->is_outstanding, io, io_next); 2009 uma_zfree(iscsi_outstanding_zone, io); 2010} 2011 2012static void 2013iscsi_action_abort(struct iscsi_session *is, union ccb *ccb) 2014{ 2015 struct icl_pdu *request; 2016 struct iscsi_bhs_task_management_request *bhstmr; 2017 struct ccb_abort *cab = &ccb->cab; 2018 struct iscsi_outstanding *io, *aio; 2019 2020 ISCSI_SESSION_LOCK_ASSERT(is); 2021 2022#if 0 2023 KASSERT(is->is_login_phase == false, ("%s called during Login Phase", __func__)); 2024#else 2025 if (is->is_login_phase) { 2026 ccb->ccb_h.status = CAM_REQ_ABORTED; 2027 xpt_done(ccb); 2028 return; 2029 } 2030#endif 2031 2032 aio = iscsi_outstanding_find_ccb(is, cab->abort_ccb); 2033 if (aio == NULL) { 2034 ccb->ccb_h.status = CAM_REQ_CMP; 2035 xpt_done(ccb); 2036 return; 2037 } 2038 2039 request = icl_pdu_new_bhs(is->is_conn, M_NOWAIT); 2040 if (request == NULL) { 2041 ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 2042 xpt_done(ccb); 2043 return; 2044 } 2045 2046 bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs; 2047 bhstmr->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_REQUEST; 2048 bhstmr->bhstmr_function = 0x80 | BHSTMR_FUNCTION_ABORT_TASK; 2049 2050 bhstmr->bhstmr_lun = iscsi_encode_lun(ccb->ccb_h.target_lun); 2051 bhstmr->bhstmr_initiator_task_tag = is->is_initiator_task_tag; 2052 is->is_initiator_task_tag++; 2053 bhstmr->bhstmr_referenced_task_tag = aio->io_initiator_task_tag; 2054 2055 io = iscsi_outstanding_add(is, bhstmr->bhstmr_initiator_task_tag, NULL); 2056 if (io == NULL) { 2057 icl_pdu_free(request); 2058 ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 2059 xpt_done(ccb); 2060 return; 2061 } 2062 io->io_datasn = aio->io_initiator_task_tag; 2063 iscsi_pdu_queue_locked(request); 2064} 2065 2066static void 2067iscsi_action_scsiio(struct iscsi_session *is, union ccb *ccb) 2068{ 2069 struct icl_pdu *request; 2070 struct iscsi_bhs_scsi_command *bhssc; 2071 struct ccb_scsiio *csio; 2072 struct iscsi_outstanding *io; 2073 size_t len; 2074 int error; 2075 2076 ISCSI_SESSION_LOCK_ASSERT(is); 2077 2078#if 0 2079 KASSERT(is->is_login_phase == false, ("%s called during Login Phase", __func__)); 2080#else 2081 if (is->is_login_phase) { 2082 ISCSI_SESSION_DEBUG(is, "called during login phase"); 2083 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 2084 xpt_freeze_devq(ccb->ccb_h.path, 1); 2085 ISCSI_SESSION_DEBUG(is, "freezing devq"); 2086 } 2087 ccb->ccb_h.status = CAM_REQ_ABORTED | CAM_DEV_QFRZN; 2088 xpt_done(ccb); 2089 return; 2090 } 2091#endif 2092 2093 request = icl_pdu_new_bhs(is->is_conn, M_NOWAIT); 2094 if (request == NULL) { 2095 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 2096 xpt_freeze_devq(ccb->ccb_h.path, 1); 2097 ISCSI_SESSION_DEBUG(is, "freezing devq"); 2098 } 2099 ccb->ccb_h.status = CAM_RESRC_UNAVAIL | CAM_DEV_QFRZN; 2100 xpt_done(ccb); 2101 return; 2102 } 2103 2104 csio = &ccb->csio; 2105 bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs; 2106 bhssc->bhssc_opcode = ISCSI_BHS_OPCODE_SCSI_COMMAND; 2107 bhssc->bhssc_flags |= BHSSC_FLAGS_F; 2108 switch (csio->ccb_h.flags & CAM_DIR_MASK) { 2109 case CAM_DIR_IN: 2110 bhssc->bhssc_flags |= BHSSC_FLAGS_R; 2111 break; 2112 case CAM_DIR_OUT: 2113 bhssc->bhssc_flags |= BHSSC_FLAGS_W; 2114 break; 2115 } 2116 2117 if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) { 2118 switch (csio->tag_action) { 2119 case MSG_HEAD_OF_Q_TAG: 2120 bhssc->bhssc_flags |= BHSSC_FLAGS_ATTR_HOQ; 2121 break; 2122 case MSG_ORDERED_Q_TAG: 2123 bhssc->bhssc_flags |= BHSSC_FLAGS_ATTR_ORDERED; 2124 break; 2125 case MSG_ACA_TASK: 2126 bhssc->bhssc_flags |= BHSSC_FLAGS_ATTR_ACA; 2127 break; 2128 case MSG_SIMPLE_Q_TAG: 2129 default: 2130 bhssc->bhssc_flags |= BHSSC_FLAGS_ATTR_SIMPLE; 2131 break; 2132 } 2133 } else 2134 bhssc->bhssc_flags |= BHSSC_FLAGS_ATTR_UNTAGGED; 2135 2136 bhssc->bhssc_lun = iscsi_encode_lun(csio->ccb_h.target_lun); 2137 bhssc->bhssc_initiator_task_tag = is->is_initiator_task_tag; 2138 is->is_initiator_task_tag++; 2139 bhssc->bhssc_expected_data_transfer_length = htonl(csio->dxfer_len); 2140 KASSERT(csio->cdb_len <= sizeof(bhssc->bhssc_cdb), 2141 ("unsupported CDB size %zd", (size_t)csio->cdb_len)); 2142 2143 if (csio->ccb_h.flags & CAM_CDB_POINTER) 2144 memcpy(&bhssc->bhssc_cdb, csio->cdb_io.cdb_ptr, csio->cdb_len); 2145 else 2146 memcpy(&bhssc->bhssc_cdb, csio->cdb_io.cdb_bytes, csio->cdb_len); 2147 2148 io = iscsi_outstanding_add(is, bhssc->bhssc_initiator_task_tag, ccb); 2149 if (io == NULL) { 2150 icl_pdu_free(request); 2151 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 2152 xpt_freeze_devq(ccb->ccb_h.path, 1); 2153 ISCSI_SESSION_DEBUG(is, "freezing devq"); 2154 } 2155 ccb->ccb_h.status = CAM_RESRC_UNAVAIL | CAM_DEV_QFRZN; 2156 xpt_done(ccb); 2157 return; 2158 } 2159 2160 if (is->is_immediate_data && 2161 (csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { 2162 len = csio->dxfer_len; 2163 //ISCSI_SESSION_DEBUG(is, "adding %zd of immediate data", len); 2164 if (len > is->is_first_burst_length) { 2165 ISCSI_SESSION_DEBUG(is, "len %zd -> %zd", len, is->is_first_burst_length); 2166 len = is->is_first_burst_length; 2167 } 2168 2169 error = icl_pdu_append_data(request, csio->data_ptr, len, M_NOWAIT); 2170 if (error != 0) { 2171 icl_pdu_free(request); 2172 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 2173 xpt_freeze_devq(ccb->ccb_h.path, 1); 2174 ISCSI_SESSION_DEBUG(is, "freezing devq"); 2175 } 2176 ccb->ccb_h.status = CAM_RESRC_UNAVAIL | CAM_DEV_QFRZN; 2177 xpt_done(ccb); 2178 return; 2179 } 2180 } 2181 iscsi_pdu_queue_locked(request); 2182} 2183 2184static void 2185iscsi_action(struct cam_sim *sim, union ccb *ccb) 2186{ 2187 struct iscsi_session *is; 2188 2189 is = cam_sim_softc(sim); 2190 2191 ISCSI_SESSION_LOCK_ASSERT(is); 2192 2193 if (is->is_terminating || 2194 (is->is_connected == false && fail_on_disconnection)) { 2195 ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2196 xpt_done(ccb); 2197 return; 2198 } 2199 2200 switch (ccb->ccb_h.func_code) { 2201 case XPT_PATH_INQ: 2202 { 2203 struct ccb_pathinq *cpi = &ccb->cpi; 2204 2205 cpi->version_num = 1; 2206 cpi->hba_inquiry = PI_TAG_ABLE; 2207 cpi->target_sprt = 0; 2208 //cpi->hba_misc = PIM_NOBUSRESET; 2209 cpi->hba_misc = 0; 2210 cpi->hba_eng_cnt = 0; 2211 cpi->max_target = 0; 2212 cpi->max_lun = 255; 2213 //cpi->initiator_id = 0; /* XXX */ 2214 cpi->initiator_id = 64; /* XXX */ 2215 strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 2216 strlcpy(cpi->hba_vid, "iSCSI", HBA_IDLEN); 2217 strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 2218 cpi->unit_number = cam_sim_unit(sim); 2219 cpi->bus_id = cam_sim_bus(sim); 2220 cpi->base_transfer_speed = 150000; /* XXX */ 2221 cpi->transport = XPORT_ISCSI; 2222 cpi->transport_version = 0; 2223 cpi->protocol = PROTO_SCSI; 2224 cpi->protocol_version = SCSI_REV_SPC3; 2225 cpi->maxio = MAXPHYS; 2226 cpi->ccb_h.status = CAM_REQ_CMP; 2227 break; 2228 } 2229 case XPT_GET_TRAN_SETTINGS: 2230 { 2231 struct ccb_trans_settings *cts; 2232 struct ccb_trans_settings_scsi *scsi; 2233 2234 cts = &ccb->cts; 2235 scsi = &cts->proto_specific.scsi; 2236 2237 cts->protocol = PROTO_SCSI; 2238 cts->protocol_version = SCSI_REV_SPC3; 2239 cts->transport = XPORT_ISCSI; 2240 cts->transport_version = 0; 2241 scsi->valid = CTS_SCSI_VALID_TQ; 2242 scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 2243 cts->ccb_h.status = CAM_REQ_CMP; 2244 break; 2245 } 2246 case XPT_CALC_GEOMETRY: 2247 cam_calc_geometry(&ccb->ccg, /*extended*/1); 2248 ccb->ccb_h.status = CAM_REQ_CMP; 2249 break; 2250#if 0 2251 /* 2252 * XXX: What's the point? 2253 */ 2254 case XPT_RESET_BUS: 2255 case XPT_TERM_IO: 2256 ISCSI_SESSION_DEBUG(is, "faking success for reset, abort, or term_io"); 2257 ccb->ccb_h.status = CAM_REQ_CMP; 2258 break; 2259#endif 2260 case XPT_ABORT: 2261 iscsi_action_abort(is, ccb); 2262 return; 2263 case XPT_SCSI_IO: 2264 iscsi_action_scsiio(is, ccb); 2265 return; 2266 default: 2267#if 0 2268 ISCSI_SESSION_DEBUG(is, "got unsupported code 0x%x", ccb->ccb_h.func_code); 2269#endif 2270 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 2271 break; 2272 } 2273 xpt_done(ccb); 2274} 2275 2276static void 2277iscsi_poll(struct cam_sim *sim) 2278{ 2279 2280 KASSERT(0, ("%s: you're not supposed to be here", __func__)); 2281} 2282 2283static void 2284iscsi_shutdown(struct iscsi_softc *sc) 2285{ 2286 struct iscsi_session *is; 2287 2288 ISCSI_DEBUG("removing all sessions due to shutdown"); 2289 2290 sx_slock(&sc->sc_lock); 2291 TAILQ_FOREACH(is, &sc->sc_sessions, is_next) 2292 iscsi_session_terminate(is); 2293 sx_sunlock(&sc->sc_lock); 2294} 2295 2296static int 2297iscsi_load(void) 2298{ 2299 int error; 2300 2301 sc = malloc(sizeof(*sc), M_ISCSI, M_ZERO | M_WAITOK); 2302 sx_init(&sc->sc_lock, "iscsi"); 2303 TAILQ_INIT(&sc->sc_sessions); 2304 cv_init(&sc->sc_cv, "iscsi_cv"); 2305 2306 iscsi_outstanding_zone = uma_zcreate("iscsi_outstanding", 2307 sizeof(struct iscsi_outstanding), NULL, NULL, NULL, NULL, 2308 UMA_ALIGN_PTR, 0); 2309 2310 error = make_dev_p(MAKEDEV_CHECKNAME, &sc->sc_cdev, &iscsi_cdevsw, 2311 NULL, UID_ROOT, GID_WHEEL, 0600, "iscsi"); 2312 if (error != 0) { 2313 ISCSI_WARN("failed to create device node, error %d", error); 2314 return (error); 2315 } 2316 sc->sc_cdev->si_drv1 = sc; 2317 2318 /* 2319 * Note that this needs to get run before dashutdown(). Otherwise, 2320 * when rebooting with iSCSI session with outstanding requests, 2321 * but disconnected, dashutdown() will hang on cam_periph_runccb(). 2322 */ 2323 sc->sc_shutdown_eh = EVENTHANDLER_REGISTER(shutdown_post_sync, 2324 iscsi_shutdown, sc, SHUTDOWN_PRI_FIRST); 2325 2326 return (0); 2327} 2328 2329static int 2330iscsi_unload(void) 2331{ 2332 struct iscsi_session *is, *tmp; 2333 2334 if (sc->sc_cdev != NULL) { 2335 ISCSI_DEBUG("removing device node"); 2336 destroy_dev(sc->sc_cdev); 2337 ISCSI_DEBUG("device node removed"); 2338 } 2339 2340 if (sc->sc_shutdown_eh != NULL) 2341 EVENTHANDLER_DEREGISTER(shutdown_post_sync, sc->sc_shutdown_eh); 2342 2343 sx_slock(&sc->sc_lock); 2344 TAILQ_FOREACH_SAFE(is, &sc->sc_sessions, is_next, tmp) 2345 iscsi_session_terminate(is); 2346 while(!TAILQ_EMPTY(&sc->sc_sessions)) { 2347 ISCSI_DEBUG("waiting for sessions to terminate"); 2348 cv_wait(&sc->sc_cv, &sc->sc_lock); 2349 } 2350 ISCSI_DEBUG("all sessions terminated"); 2351 sx_sunlock(&sc->sc_lock); 2352 2353 uma_zdestroy(iscsi_outstanding_zone); 2354 sx_destroy(&sc->sc_lock); 2355 cv_destroy(&sc->sc_cv); 2356 free(sc, M_ISCSI); 2357 return (0); 2358} 2359 2360static int 2361iscsi_quiesce(void) 2362{ 2363 sx_slock(&sc->sc_lock); 2364 if (!TAILQ_EMPTY(&sc->sc_sessions)) { 2365 sx_sunlock(&sc->sc_lock); 2366 return (EBUSY); 2367 } 2368 sx_sunlock(&sc->sc_lock); 2369 return (0); 2370} 2371 2372static int 2373iscsi_modevent(module_t mod, int what, void *arg) 2374{ 2375 int error; 2376 2377 switch (what) { 2378 case MOD_LOAD: 2379 error = iscsi_load(); 2380 break; 2381 case MOD_UNLOAD: 2382 error = iscsi_unload(); 2383 break; 2384 case MOD_QUIESCE: 2385 error = iscsi_quiesce(); 2386 break; 2387 default: 2388 error = EINVAL; 2389 break; 2390 } 2391 return (error); 2392} 2393 2394moduledata_t iscsi_data = { 2395 "iscsi", 2396 iscsi_modevent, 2397 0 2398}; 2399 2400DECLARE_MODULE(iscsi, iscsi_data, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 2401MODULE_DEPEND(iscsi, cam, 1, 1, 1); 2402MODULE_DEPEND(iscsi, icl, 1, 1, 1); 2403