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