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