1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29/* 30 | iSCSI - Session Manager 31 | $Id: isc_sm.c 743 2009-08-08 10:54:53Z danny $ 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD$"); 36 37#include "opt_iscsi_initiator.h" 38 39#include <sys/param.h> 40#include <sys/kernel.h> 41#include <sys/conf.h> 42#include <sys/systm.h> 43#include <sys/malloc.h> 44#include <sys/ctype.h> 45#include <sys/errno.h> 46#include <sys/sysctl.h> 47#include <sys/file.h> 48#include <sys/uio.h> 49#include <sys/socketvar.h> 50#include <sys/socket.h> 51#include <sys/protosw.h> 52#include <sys/proc.h> 53#include <sys/ioccom.h> 54#include <sys/queue.h> 55#include <sys/kthread.h> 56#include <sys/syslog.h> 57#include <sys/mbuf.h> 58#include <sys/bus.h> 59#include <sys/sbuf.h> 60#include <sys/sx.h> 61#include <vm/uma.h> 62 63#include <cam/cam.h> 64#include <cam/cam_ccb.h> 65#include <cam/cam_sim.h> 66#include <cam/cam_xpt_sim.h> 67#include <cam/cam_periph.h> 68 69#include <dev/iscsi_initiator/iscsi.h> 70#include <dev/iscsi_initiator/iscsivar.h> 71 72static void 73_async(isc_session_t *sp, pduq_t *pq) 74{ 75 debug_called(8); 76 77 iscsi_async(sp, pq); 78 79 pdu_free(sp->isc, pq); 80} 81 82static void 83_reject(isc_session_t *sp, pduq_t *pq) 84{ 85 pduq_t *opq; 86 pdu_t *pdu; 87 reject_t *reject; 88 int itt; 89 90 debug_called(8); 91 pdu = mtod(pq->mp, pdu_t *); 92 itt = pdu->ipdu.bhs.itt; 93 reject = &pq->pdu.ipdu.reject; 94 sdebug(2, "itt=%x reason=0x%x", ntohl(itt), reject->reason); 95 opq = i_search_hld(sp, itt, 0); 96 if(opq != NULL) 97 iscsi_reject(sp, opq, pq); 98 else { 99 switch(pq->pdu.ipdu.bhs.opcode) { 100 case ISCSI_LOGOUT_CMD: // XXX: wasabi does this - can't figure out why 101 sdebug(2, "ISCSI_LOGOUT_CMD ..."); 102 break; 103 default: 104 xdebug("%d] we lost something itt=%x", 105 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt)); 106 } 107 } 108 pdu_free(sp->isc, pq); 109} 110 111static void 112_r2t(isc_session_t *sp, pduq_t *pq) 113{ 114 pduq_t *opq; 115 116 debug_called(8); 117 opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1); 118 if(opq != NULL) { 119 iscsi_r2t(sp, opq, pq); 120 } 121 else { 122 r2t_t *r2t = &pq->pdu.ipdu.r2t; 123 124 xdebug("%d] we lost something itt=%x r2tSN=%d bo=%x ddtl=%x", 125 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt), 126 ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl)); 127 } 128 pdu_free(sp->isc, pq); 129} 130 131static void 132_scsi_rsp(isc_session_t *sp, pduq_t *pq) 133{ 134 pduq_t *opq; 135 136 debug_called(8); 137 opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 0); 138 debug(5, "itt=%x pq=%p opq=%p", ntohl(pq->pdu.ipdu.bhs.itt), pq, opq); 139 if(opq != NULL) { 140 iscsi_done(sp, opq, pq); 141 i_acked_hld(sp, &pq->pdu); 142 } 143 else 144 xdebug("%d] we lost something itt=%x", 145 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt)); 146 pdu_free(sp->isc, pq); 147} 148 149static void 150_read_data(isc_session_t *sp, pduq_t *pq) 151{ 152 pduq_t *opq; 153 154 debug_called(8); 155 opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1); 156 if(opq != NULL) { 157 if(scsi_decap(sp, opq, pq) != 1) { 158 i_remove_hld(sp, opq); // done 159 pdu_free(sp->isc, opq); 160 } 161 } 162 else 163 xdebug("%d] we lost something itt=%x", 164 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt)); 165 pdu_free(sp->isc, pq); 166} 167/* 168 | this is a kludge, 169 | the jury is not back with a veredict, user or kernel 170 */ 171static void 172_nop_out(isc_session_t *sp) 173{ 174 pduq_t *pq; 175 nop_out_t *nop_out; 176 177 debug_called(8); 178 179 sdebug(4, "cws=%d", sp->cws); 180 if(sp->cws == 0) { 181 /* 182 | only send a nop if window is closed. 183 */ 184 if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) 185 // I guess we ran out of resources 186 return; 187 nop_out = &pq->pdu.ipdu.nop_out; 188 nop_out->opcode = ISCSI_NOP_OUT; 189 nop_out->itt = htonl(sp->sn.itt); 190 nop_out->ttt = -1; 191 nop_out->I = 1; 192 nop_out->F = 1; 193 if(isc_qout(sp, pq) != 0) { 194 sdebug(1, "failed"); 195 pdu_free(sp->isc, pq); 196 } 197 } 198} 199 200static void 201_nop_in(isc_session_t *sp, pduq_t *pq) 202{ 203 pdu_t *pp = &pq->pdu; 204 nop_in_t *nop_in = &pp->ipdu.nop_in; 205 bhs_t *bhs = &pp->ipdu.bhs; 206 207 debug_called(8); 208 209 sdebug(5, "itt=%x ttt=%x", htonl(nop_in->itt), htonl(nop_in->ttt)); 210 if(nop_in->itt == -1) { 211 if(pp->ds_len != 0) { 212 /* 213 | according to RFC 3720 this should be zero 214 | what to do if not? 215 */ 216 xdebug("%d] dslen not zero", sp->sid); 217 } 218 if(nop_in->ttt != -1) { 219 nop_out_t *nop_out; 220 /* 221 | target wants a nop_out 222 */ 223 bhs->opcode = ISCSI_NOP_OUT; 224 bhs->I = 1; 225 bhs->F = 1; 226 /* 227 | we are reusing the pdu, so bhs->ttt == nop_in->ttt; 228 | and need to zero out 'Reserved' 229 | small cludge here. 230 */ 231 nop_out = &pp->ipdu.nop_out; 232 nop_out->sn.maxcmd = 0; 233 memset(nop_out->mbz, 0, sizeof(nop_out->mbz)); 234 (void)isc_qout(sp, pq); //XXX: should check return? 235 return; 236 } 237 //else { 238 // just making noise? 239 // see 10.9.1: target does not want and answer. 240 //} 241 242 } else 243 if(nop_in->ttt == -1) { 244 /* 245 | it is an answer to a nop_in from us 246 */ 247 if(nop_in->itt != -1) { 248#ifdef ISC_WAIT4PING 249 // XXX: MUTEX please 250 if(sp->flags & ISC_WAIT4PING) { 251 i_nqueue_rsp(sp, pq); 252 wakeup(&sp->rsp); 253 return; 254 } 255#endif 256 } 257 } 258 /* 259 | drop it 260 */ 261 pdu_free(sp->isc, pq); 262 return; 263} 264 265int 266i_prepPDU(isc_session_t *sp, pduq_t *pq) 267{ 268 size_t len, n; 269 pdu_t *pp = &pq->pdu; 270 bhs_t *bhp = &pp->ipdu.bhs; 271 272 len = sizeof(bhs_t); 273 if(pp->ahs_len) { 274 len += pp->ahs_len; 275 bhp->AHSLength = pp->ahs_len / 4; 276 } 277 if(ISOK2DIG(sp->hdrDigest, pp)) 278 len += 4; 279 if(pp->ds_len) { 280 n = pp->ds_len; 281 len += n; 282#if BYTE_ORDER == LITTLE_ENDIAN 283 bhp->DSLength = ((n & 0x00ff0000) >> 16) 284 | (n & 0x0000ff00) 285 | ((n & 0x000000ff) << 16); 286#else 287 bhp->DSLength = n; 288#endif 289 if(len & 03) { 290 n = 4 - (len & 03); 291 len += n; 292 } 293 if(ISOK2DIG(sp->dataDigest, pp)) 294 len += 4; 295 } 296 297 pq->len = len; 298 len -= sizeof(bhs_t); 299 if(sp->opt.maxBurstLength && (len > sp->opt.maxBurstLength)) { 300 xdebug("%d] pdu len=%zd > %d", 301 sp->sid, len, sp->opt.maxBurstLength); 302 // XXX: when this happens it used to hang ... 303 return E2BIG; 304 } 305 return 0; 306} 307 308int 309isc_qout(isc_session_t *sp, pduq_t *pq) 310{ 311 int error = 0; 312 313 debug_called(8); 314 315 if(pq->len == 0 && (error = i_prepPDU(sp, pq))) 316 return error; 317 318 if(pq->pdu.ipdu.bhs.I) 319 i_nqueue_isnd(sp, pq); 320 else 321 if(pq->pdu.ipdu.data_out.opcode == ISCSI_WRITE_DATA) 322 i_nqueue_wsnd(sp, pq); 323 else 324 i_nqueue_csnd(sp, pq); 325 326 sdebug(5, "enqued: pq=%p", pq); 327 328 mtx_lock(&sp->io_mtx); 329 sp->flags |= ISC_OQNOTEMPTY; 330 if(sp->flags & ISC_OWAITING) 331 wakeup(&sp->flags); 332 mtx_unlock(&sp->io_mtx); 333 334 return error; 335} 336/* 337 | called when a fullPhase is restarted 338 */ 339void 340ism_restart(isc_session_t *sp) 341{ 342 int lastcmd; 343 344 sdebug(2, "restart ..."); 345 lastcmd = iscsi_requeue(sp); 346#if 0 347 if(lastcmd != sp->sn.cmd) { 348 sdebug(1, "resetting CmdSN to=%d (from %d)", lastcmd, sp->sn.cmd); 349 sp->sn.cmd = lastcmd; 350 } 351#endif 352 mtx_lock(&sp->io_mtx); 353 if(sp->flags & ISC_OWAITING) { 354 wakeup(&sp->flags); 355 } 356 mtx_unlock(&sp->io_mtx); 357 358 sdebug(2, "restarted sn.cmd=0x%x lastcmd=0x%x", sp->sn.cmd, lastcmd); 359} 360 361void 362ism_recv(isc_session_t *sp, pduq_t *pq) 363{ 364 bhs_t *bhs; 365 int statSN; 366 367 debug_called(8); 368 369 bhs = &pq->pdu.ipdu.bhs; 370 statSN = ntohl(bhs->OpcodeSpecificFields[1]); 371 372#ifdef notyet 373 if(sp->sn.expCmd != sn->cmd) { 374 sdebug(1, "we lost something ... exp=0x%x cmd=0x%x", 375 sn->expCmd, sn->cmd); 376 } 377#endif 378 sdebug(5, "opcode=0x%x itt=0x%x stat#0x%x maxcmd=0x%0x", 379 bhs->opcode, ntohl(bhs->itt), statSN, sp->sn.maxCmd); 380 381 switch(bhs->opcode) { 382 case ISCSI_READ_DATA: { 383 data_in_t *cmd = &pq->pdu.ipdu.data_in; 384 385 if(cmd->S == 0) 386 break; 387 } 388 389 default: 390 if(statSN > (sp->sn.stat + 1)) { 391 sdebug(1, "we lost some rec=0x%x exp=0x%x", 392 statSN, sp->sn.stat); 393 // XXX: must do some error recovery here. 394 } 395 sp->sn.stat = statSN; 396 } 397 398 switch(bhs->opcode) { 399 case ISCSI_LOGIN_RSP: 400 case ISCSI_TEXT_RSP: 401 case ISCSI_LOGOUT_RSP: 402 i_nqueue_rsp(sp, pq); 403 wakeup(&sp->rsp); 404 sdebug(3, "wakeup rsp"); 405 break; 406 407 case ISCSI_NOP_IN: _nop_in(sp, pq); break; 408 case ISCSI_SCSI_RSP: _scsi_rsp(sp, pq); break; 409 case ISCSI_READ_DATA: _read_data(sp, pq); break; 410 case ISCSI_R2T: _r2t(sp, pq); break; 411 case ISCSI_REJECT: _reject(sp, pq); break; 412 case ISCSI_ASYNC: _async(sp, pq); break; 413 414 case ISCSI_TASK_RSP: 415 default: 416 sdebug(1, "opcode=0x%x itt=0x%x not implemented yet", 417 bhs->opcode, ntohl(bhs->itt)); 418 break; 419 } 420} 421 422/* 423 | go through the out queues looking for work 424 | if either nothing to do, or window is closed 425 | return. 426 */ 427static int 428proc_out(isc_session_t *sp) 429{ 430 sn_t *sn = &sp->sn; 431 pduq_t *pq; 432 int error, which; 433 434 debug_called(8); 435 error = 0; 436 437 while(sp->flags & ISC_LINK_UP) { 438 pdu_t *pp; 439 bhs_t *bhs; 440 /* 441 | check if there is outstanding work in: 442 | 1- the Immediate queue 443 | 2- the R2T queue 444 | 3- the cmd queue, only if the command window allows it. 445 */ 446 which = BIT(0) | BIT(1); 447 if(SNA_GT(sn->cmd, sn->maxCmd) == 0) // if(sn->maxCmd - sn->smc + 1) > 0 448 which |= BIT(2); 449 450 sdebug(4, "which=%d sn->maxCmd=%d sn->cmd=%d", which, sn->maxCmd, sn->cmd); 451 452 if((pq = i_dqueue_snd(sp, which)) == NULL) 453 break; 454 sdebug(4, "pq=%p", pq); 455 456 pp = &pq->pdu; 457 bhs = &pp->ipdu.bhs; 458 switch(bhs->opcode) { 459 case ISCSI_SCSI_CMD: 460 sn->itt++; 461 bhs->itt = htonl(sn->itt); 462 463 case ISCSI_LOGIN_CMD: 464 case ISCSI_TEXT_CMD: 465 case ISCSI_LOGOUT_CMD: 466 case ISCSI_SNACK: 467 case ISCSI_NOP_OUT: 468 case ISCSI_TASK_CMD: 469 bhs->CmdSN = htonl(sn->cmd); 470 if(bhs->I == 0) 471 sn->cmd++; 472 473 case ISCSI_WRITE_DATA: 474 bhs->ExpStSN = htonl(sn->stat + 1); 475 break; 476 477 default: 478 // XXX: can this happen? 479 xdebug("bad opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)", 480 bhs->opcode, 481 sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt); 482 // XXX: and now? 483 } 484 485 sdebug(4, "opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)", 486 bhs->opcode, 487 sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt); 488 489 if(bhs->opcode != ISCSI_NOP_OUT) 490 /* 491 | enqued till ack is received 492 | note: sosend(...) does not mean the packet left 493 | the host so that freeing resources has to wait 494 */ 495 i_nqueue_hld(sp, pq); 496 497 error = isc_sendPDU(sp, pq); 498 if(bhs->opcode == ISCSI_NOP_OUT) 499 pdu_free(sp->isc, pq); 500 if(error) { 501 xdebug("error=%d opcode=0x%x ccb=%p itt=%x", 502 error, bhs->opcode, pq->ccb, ntohl(bhs->itt)); 503 i_remove_hld(sp, pq); 504 switch(error) { 505 case EPIPE: 506 sp->flags &= ~ISC_LINK_UP; 507 508 case EAGAIN: 509 xdebug("requed"); 510 i_rqueue_pdu(sp, pq); 511 break; 512 513 default: 514 if(pq->ccb) { 515 xdebug("back to cam"); 516 pq->ccb->ccb_h.status |= CAM_REQUEUE_REQ; // some better error? 517 XPT_DONE(sp, pq->ccb); 518 pdu_free(sp->isc, pq); 519 } 520 else 521 xdebug("we lost it!"); 522 } 523 } 524 } 525 return error; 526} 527 528/* 529 | survives link breakdowns. 530 */ 531static void 532ism_out(void *vp) 533{ 534 isc_session_t *sp = (isc_session_t *)vp; 535 int error; 536 537 debug_called(8); 538 539 sp->flags |= ISC_SM_RUNNING; 540 sdebug(3, "started sp->flags=%x", sp->flags); 541 do { 542 if((sp->flags & ISC_HOLD) == 0) { 543 error = proc_out(sp); 544 if(error) { 545 sdebug(3, "error=%d", error); 546 } 547 } 548 mtx_lock(&sp->io_mtx); 549 if((sp->flags & ISC_LINK_UP) == 0) { 550 sdebug(3, "ISC_LINK_UP==0, sp->flags=%x ", sp->flags); 551 if(sp->soc != NULL) 552 sdebug(3, "so_state=%x", sp->soc->so_state); 553 wakeup(&sp->soc); 554 } 555 556 if(!(sp->flags & ISC_OQNOTEMPTY)) { 557 sp->flags |= ISC_OWAITING; 558 if(msleep(&sp->flags, &sp->io_mtx, PRIBIO, "isc_proc", hz*30) == EWOULDBLOCK) { 559 if(sp->flags & ISC_CON_RUNNING) 560 _nop_out(sp); 561 } 562 sp->flags &= ~ISC_OWAITING; 563 } 564 sp->flags &= ~ISC_OQNOTEMPTY; 565 mtx_unlock(&sp->io_mtx); 566 } while(sp->flags & ISC_SM_RUN); 567 568 sp->flags &= ~ISC_SM_RUNNING; 569 sdebug(3, "dropped ISC_SM_RUNNING"); 570 571 wakeup(&sp->soc); 572 wakeup(sp); // XXX: do we need this one? 573 574#if __FreeBSD_version >= 700000 575 destroy_dev(sp->dev); 576#endif 577 578 debug(3, "terminated sp=%p sp->sid=%d", sp, sp->sid); 579 580#if __FreeBSD_version >= 800000 581 kproc_exit(0); 582#else 583 kthread_exit(0); 584#endif 585} 586 587#if 0 588static int 589isc_dump_options(SYSCTL_HANDLER_ARGS) 590{ 591 int error; 592 isc_session_t *sp; 593 struct sbuf sb; 594 595 sbuf_new_for_sysctl(&sb, NULL, 128, req); 596 597 sp = (isc_session_t *)arg1; 598 sbuf_printf(&sb, "targetname='%s'", sp->opt.targetName); 599 sbuf_printf(&sb, " targetaddress='%s'", sp->opt.targetAddress); 600 error = sbuf_finish(&sb); 601 sbuf_delete(&sb); 602 return error; 603} 604#endif 605 606static int 607isc_dump_stats(SYSCTL_HANDLER_ARGS) 608{ 609 isc_session_t *sp; 610 struct isc_softc *sc; 611 int error; 612 struct sbuf sb; 613 614 sp = (isc_session_t *)arg1; 615 sc = sp->isc; 616 617 sbuf_new_for_sysctl(&sb, NULL, 128, req); 618 619 sbuf_printf(&sb, "recv=%d sent=%d", sp->stats.nrecv, sp->stats.nsent); 620 sbuf_printf(&sb, " flags=0x%08x pdus-alloc=%d pdus-max=%d", 621 sp->flags, sc->npdu_alloc, sc->npdu_max); 622 sbuf_printf(&sb, " cws=%d cmd=%x exp=%x max=%x stat=%x itt=%x", 623 sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt); 624 error = sbuf_finish(&sb); 625 sbuf_delete(&sb); 626 return error; 627} 628 629static void 630isc_add_sysctls(isc_session_t *sp) 631{ 632 debug_called(8); 633 sdebug(6, "sid=%d %s", sp->sid, devtoname(sp->dev)); 634 635 sysctl_ctx_init(&sp->clist); 636 sp->oid = SYSCTL_ADD_NODE(&sp->clist, 637 SYSCTL_CHILDREN(sp->isc->oid), 638 OID_AUTO, 639 devtoname(sp->dev) + 5, // iscsi0 640 CTLFLAG_RD, 641 0, 642 "initiator"); 643 SYSCTL_ADD_PROC(&sp->clist, 644 SYSCTL_CHILDREN(sp->oid), 645 OID_AUTO, 646 "targetname", 647 CTLTYPE_STRING | CTLFLAG_RD, 648 (void *)&sp->opt.targetName, 0, 649 sysctl_handle_string, "A", "target name"); 650 651 SYSCTL_ADD_PROC(&sp->clist, 652 SYSCTL_CHILDREN(sp->oid), 653 OID_AUTO, 654 "targeaddress", 655 CTLTYPE_STRING | CTLFLAG_RD, 656 (void *)&sp->opt.targetAddress, 0, 657 sysctl_handle_string, "A", "target address"); 658 659 SYSCTL_ADD_PROC(&sp->clist, 660 SYSCTL_CHILDREN(sp->oid), 661 OID_AUTO, 662 "stats", 663 CTLTYPE_STRING | CTLFLAG_RD, 664 (void *)sp, 0, 665 isc_dump_stats, "A", "statistics"); 666 667 SYSCTL_ADD_INT(&sp->clist, 668 SYSCTL_CHILDREN(sp->oid), 669 OID_AUTO, 670 "douio", 671 CTLFLAG_RW, 672 &sp->douio, 0, "enable uio on read"); 673} 674 675void 676ism_stop(isc_session_t *sp) 677{ 678 struct isc_softc *sc = sp->isc; 679 int n; 680 681 debug_called(8); 682 sdebug(2, "terminating"); 683 /* 684 | first stop the receiver 685 */ 686 isc_stop_receiver(sp); 687 /* 688 | now stop the xmitter 689 */ 690 n = 5; 691 sp->flags &= ~ISC_SM_RUN; 692 while(n-- && (sp->flags & ISC_SM_RUNNING)) { 693 sdebug(2, "n=%d", n); 694 wakeup(&sp->flags); 695 tsleep(sp, PRIBIO, "-", 5*hz); 696 } 697 sdebug(2, "final n=%d", n); 698 sp->flags &= ~ISC_FFPHASE; 699 700 iscsi_cleanup(sp); 701 702 (void)i_pdu_flush(sp); 703 704 ic_destroy(sp); 705 706 sx_xlock(&sc->unit_sx); 707 free_unr(sc->unit, sp->sid); 708 sx_xunlock(&sc->unit_sx); 709 710 mtx_lock(&sc->isc_mtx); 711 TAILQ_REMOVE(&sc->isc_sess, sp, sp_link); 712 sc->nsess--; 713 mtx_unlock(&sc->isc_mtx); 714 715#if __FreeBSD_version < 700000 716 destroy_dev(sp->dev); 717#endif 718 719 mtx_destroy(&sp->rsp_mtx); 720 mtx_destroy(&sp->rsv_mtx); 721 mtx_destroy(&sp->hld_mtx); 722 mtx_destroy(&sp->snd_mtx); 723 mtx_destroy(&sp->io_mtx); 724 725 i_freeopt(&sp->opt); 726 727 if(sysctl_ctx_free(&sp->clist)) 728 xdebug("sysctl_ctx_free failed"); 729 730 free(sp, M_ISCSI); 731} 732 733int 734ism_start(isc_session_t *sp) 735{ 736 debug_called(8); 737 /* 738 | now is a good time to do some initialization 739 */ 740 TAILQ_INIT(&sp->rsp); 741 TAILQ_INIT(&sp->rsv); 742 TAILQ_INIT(&sp->csnd); 743 TAILQ_INIT(&sp->isnd); 744 TAILQ_INIT(&sp->wsnd); 745 TAILQ_INIT(&sp->hld); 746 747 mtx_init(&sp->rsv_mtx, "iscsi-rsv", NULL, MTX_DEF); 748 mtx_init(&sp->rsp_mtx, "iscsi-rsp", NULL, MTX_DEF); 749 mtx_init(&sp->snd_mtx, "iscsi-snd", NULL, MTX_DEF); 750 mtx_init(&sp->hld_mtx, "iscsi-hld", NULL, MTX_DEF); 751 mtx_init(&sp->io_mtx, "iscsi-io", NULL, MTX_DEF); 752 753 isc_add_sysctls(sp); 754 755 sp->flags |= ISC_SM_RUN; 756 757 debug(4, "starting ism_proc: sp->sid=%d", sp->sid); 758 759#if __FreeBSD_version >= 800000 760 return kproc_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid); 761#else 762 return kthread_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid); 763#endif 764} 765