1 /*- 2 * Copyright (c) 2005-2008 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 * $FreeBSD: src/sys/dev/iscsi/initiator/isc_sm.c,v 1.3 2008/11/25 07:17:11 scottl Exp $ 27 */ 28 /* 29 | iSCSI - Session Manager 30 | $Id: isc_sm.c,v 1.30 2007/04/22 09:53:09 danny Exp danny $ 31 */ 32 33 #include "opt_iscsi_initiator.h" 34 35 #include <sys/param.h> 36 #include <sys/kernel.h> 37 #include <sys/conf.h> 38 #include <sys/systm.h> 39 #include <sys/malloc.h> 40 #include <sys/ctype.h> 41 #include <sys/errno.h> 42 #include <sys/sysctl.h> 43 #include <sys/file.h> 44 #include <sys/uio.h> 45 #include <sys/socketvar.h> 46 #include <sys/socket.h> 47 #include <sys/protosw.h> 48 #include <sys/proc.h> 49 #include <sys/ioccom.h> 50 #include <sys/queue.h> 51 #include <sys/kthread.h> 52 #include <sys/syslog.h> 53 #include <sys/mbuf.h> 54 #include <sys/bus.h> 55 #include <sys/eventhandler.h> 56 #include <sys/mutex.h> 57 #include <sys/mutex2.h> 58 59 #include <bus/cam/cam.h> 60 #include <bus/cam/cam_ccb.h> 61 #include <bus/cam/cam_sim.h> 62 #include <bus/cam/cam_xpt_sim.h> 63 #include <bus/cam/cam_periph.h> 64 65 #include <dev/disk/iscsi/initiator/iscsi.h> 66 #include <dev/disk/iscsi/initiator/iscsivar.h> 67 68 static 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 78 static 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 107 static 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 127 static 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 else 138 xdebug("%d] we lost something itt=%x", 139 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt)); 140 pdu_free(sp->isc, pq); 141 } 142 143 static void 144 _read_data(isc_session_t *sp, pduq_t *pq) 145 { 146 pduq_t *opq; 147 148 debug_called(8); 149 opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1); 150 if(opq != NULL) { 151 if(scsi_decap(sp, opq, pq) != 1) { 152 i_remove_hld(sp, opq); // done 153 pdu_free(sp->isc, opq); 154 } 155 } 156 else 157 xdebug("%d] we lost something itt=%x", 158 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt)); 159 pdu_free(sp->isc, pq); 160 } 161 /* 162 | this is a kludge, 163 | the jury is not back with a veredict, user or kernel 164 */ 165 static void 166 _nop_out(isc_session_t *sp) 167 { 168 pduq_t *pq; 169 nop_out_t *nop_out; 170 171 debug_called(8); 172 173 sdebug(4, "cws=%d", sp->cws); 174 if(sp->cws == 0) { 175 /* 176 | only send a nop if window is closed. 177 */ 178 if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) 179 // I guess we ran out of resources 180 return; 181 nop_out = &pq->pdu.ipdu.nop_out; 182 nop_out->opcode = ISCSI_NOP_OUT; 183 nop_out->itt = htonl(sp->sn.itt); 184 nop_out->ttt = -1; 185 nop_out->I = 1; 186 nop_out->F = 1; 187 if(isc_qout(sp, pq) != 0) { 188 sdebug(1, "failed"); 189 pdu_free(sp->isc, pq); 190 } 191 } 192 } 193 194 static void 195 _nop_in(isc_session_t *sp, pduq_t *pq) 196 { 197 pdu_t *pp = &pq->pdu; 198 nop_in_t *nop_in = &pp->ipdu.nop_in; 199 bhs_t *bhs = &pp->ipdu.bhs; 200 201 debug_called(8); 202 203 sdebug(5, "itt=%x ttt=%x", htonl(nop_in->itt), htonl(nop_in->ttt)); 204 if(nop_in->itt == -1) { 205 if(pp->ds_len != 0) { 206 /* 207 | according to RFC 3720 this should be zero 208 | what to do if not? 209 */ 210 xdebug("%d] dslen not zero", sp->sid); 211 } 212 if(nop_in->ttt != -1) { 213 nop_out_t *nop_out; 214 /* 215 | target wants a nop_out 216 */ 217 bhs->opcode = ISCSI_NOP_OUT; 218 bhs->I = 1; 219 bhs->F = 1; 220 /* 221 | we are reusing the pdu, so bhs->ttt == nop_in->ttt; 222 | and need to zero out 'Reserved' 223 | small cludge here. 224 */ 225 nop_out = &pp->ipdu.nop_out; 226 nop_out->sn.maxcmd = 0; 227 memset(nop_out->mbz, 0, sizeof(nop_out->mbz)); 228 (void)isc_qout(sp, pq); //XXX: should check return? 229 return; 230 } 231 //else { 232 // just making noise? 233 // see 10.9.1: target does not want and answer. 234 //} 235 236 } else 237 if(nop_in->ttt == -1) { 238 /* 239 | it is an answer to a nop_in from us 240 */ 241 if(nop_in->itt != -1) { 242 #ifdef ISC_WAIT4PING 243 // XXX: MUTEX please 244 if(sp->flags & ISC_WAIT4PING) { 245 i_nqueue_rsp(sp, pq); 246 wakeup(&sp->rsp); 247 return; 248 } 249 #endif 250 } 251 } 252 /* 253 | drop it 254 */ 255 pdu_free(sp->isc, pq); 256 return; 257 } 258 259 int 260 i_prepPDU(isc_session_t *sp, pduq_t *pq) 261 { 262 size_t len, n; 263 pdu_t *pp = &pq->pdu; 264 bhs_t *bhp = &pp->ipdu.bhs; 265 266 len = sizeof(bhs_t); 267 if(pp->ahs_len) { 268 len += pp->ahs_len; 269 bhp->AHSLength = pp->ahs_len / 4; 270 } 271 if(sp->hdrDigest) 272 len += 4; 273 if(pp->ds_len) { 274 n = pp->ds_len; 275 len += n; 276 #if BYTE_ORDER == LITTLE_ENDIAN 277 bhp->DSLength = ((n & 0x00ff0000) >> 16) 278 | (n & 0x0000ff00) 279 | ((n & 0x000000ff) << 16); 280 #else 281 bhp->DSLength = n; 282 #endif 283 if(len & 03) { 284 n = 4 - (len & 03); 285 len += n; 286 } 287 if(sp->dataDigest) 288 len += 4; 289 } 290 291 pq->len = len; 292 len -= sizeof(bhs_t); 293 if(sp->opt.maxBurstLength && (len > sp->opt.maxBurstLength)) { 294 xdebug("%d] pdu len=%zd > %d", 295 sp->sid, len, sp->opt.maxBurstLength); 296 // XXX: when this happens it used to hang ... 297 return E2BIG; 298 } 299 return 0; 300 } 301 302 int 303 isc_qout(isc_session_t *sp, pduq_t *pq) 304 { 305 int error = 0; 306 307 debug_called(8); 308 309 if(pq->len == 0 && (error = i_prepPDU(sp, pq))) 310 return error; 311 312 if(pq->pdu.ipdu.bhs.I) 313 i_nqueue_isnd(sp, pq); 314 else 315 if(pq->pdu.ipdu.data_out.opcode == ISCSI_WRITE_DATA) 316 i_nqueue_wsnd(sp, pq); 317 else 318 i_nqueue_csnd(sp, pq); 319 320 sdebug(5, "enqued: pq=%p", pq); 321 322 iscsi_lock_ex(&sp->io_mtx); 323 sp->flags |= ISC_OQNOTEMPTY; 324 if(sp->flags & ISC_OWAITING) 325 wakeup(&sp->flags); 326 iscsi_unlock_ex(&sp->io_mtx); 327 328 return error; 329 } 330 /* 331 | called when a fullPhase is restarted 332 */ 333 static void 334 ism_restart(isc_session_t *sp) 335 { 336 int lastcmd; 337 338 sdebug(2, "restart ..."); 339 lastcmd = iscsi_requeue(sp); 340 #if 0 341 if(lastcmd != sp->sn.cmd) { 342 sdebug(1, "resetting CmdSN to=%d (from %d)", lastcmd, sp->sn.cmd); 343 sp->sn.cmd = lastcmd; 344 } 345 #endif 346 iscsi_lock_ex(&sp->io_mtx); 347 if(sp->flags & ISC_OWAITING) { 348 wakeup(&sp->flags); 349 } 350 iscsi_unlock_ex(&sp->io_mtx); 351 352 sdebug(2, "restarted lastcmd=0x%x", lastcmd); 353 } 354 355 int 356 ism_fullfeature(struct cdev *dev, int flag) 357 { 358 isc_session_t *sp = (isc_session_t *)dev->si_drv2; 359 int error; 360 361 sdebug(2, "flag=%d", flag); 362 363 error = 0; 364 switch(flag) { 365 case 0: // stop 366 sp->flags &= ~ISC_FFPHASE; 367 break; 368 case 1: // start 369 error = ic_fullfeature(dev); 370 break; 371 case 2: // restart 372 ism_restart(sp); 373 break; 374 } 375 return error; 376 } 377 378 void 379 ism_recv(isc_session_t *sp, pduq_t *pq) 380 { 381 bhs_t *bhs; 382 int statSN; 383 384 debug_called(8); 385 386 bhs = &pq->pdu.ipdu.bhs; 387 statSN = ntohl(bhs->OpcodeSpecificFields[1]); 388 #if 0 389 { 390 /* 391 | this code is only for debugging. 392 */ 393 sn_t *sn = &sp->sn; 394 if(sp->cws == 0) { 395 if((sp->flags & ISC_STALLED) == 0) { 396 sdebug(4, "window closed: max=0x%x exp=0x%x opcode=0x%x cmd=0x%x cws=%d.", 397 sn->maxCmd, sn->expCmd, bhs->opcode, sn->cmd, sp->cws); 398 sp->flags |= ISC_STALLED; 399 } else 400 if(sp->flags & ISC_STALLED) { 401 sdebug(4, "window opened: max=0x%x exp=0x%x opcode=0x%x cmd=0x%x cws=%d.", 402 sn->maxCmd, sn->expCmd, bhs->opcode, sn->cmd, sp->cws); 403 sp->flags &= ~ISC_STALLED;; 404 } 405 } 406 } 407 #endif 408 409 #ifdef notyet 410 if(sp->sn.expCmd != sn->cmd) { 411 sdebug(1, "we lost something ... exp=0x%x cmd=0x%x", 412 sn->expCmd, sn->cmd); 413 } 414 #endif 415 sdebug(5, "opcode=0x%x itt=0x%x stat#0x%x maxcmd=0x%0x", 416 bhs->opcode, ntohl(bhs->itt), statSN, sp->sn.maxCmd); 417 418 switch(bhs->opcode) { 419 case ISCSI_READ_DATA: { 420 data_in_t *cmd = &pq->pdu.ipdu.data_in; 421 422 if(cmd->S == 0) 423 break; 424 } 425 426 default: 427 if(statSN > (sp->sn.stat + 1)) { 428 sdebug(1, "we lost some rec=0x%x exp=0x%x", 429 statSN, sp->sn.stat); 430 // XXX: must do some error recovery here. 431 } 432 sp->sn.stat = statSN; 433 } 434 435 switch(bhs->opcode) { 436 case ISCSI_LOGIN_RSP: 437 case ISCSI_TEXT_RSP: 438 case ISCSI_LOGOUT_RSP: 439 i_nqueue_rsp(sp, pq); 440 wakeup(&sp->rsp); 441 sdebug(3, "wakeup rsp"); 442 break; 443 444 case ISCSI_NOP_IN: _nop_in(sp, pq); break; 445 case ISCSI_SCSI_RSP: _scsi_rsp(sp, pq); break; 446 case ISCSI_READ_DATA: _read_data(sp, pq); break; 447 case ISCSI_R2T: _r2t(sp, pq); break; 448 case ISCSI_REJECT: _reject(sp, pq); break; 449 case ISCSI_ASYNC: _async(sp, pq); break; 450 451 case ISCSI_TASK_RSP: 452 default: 453 sdebug(1, "opcode=0x%x itt=0x%x not implemented yet", 454 bhs->opcode, ntohl(bhs->itt)); 455 break; 456 } 457 } 458 459 /* 460 | go through the out queues looking for work 461 | if either nothing to do, or window is closed 462 | return. 463 */ 464 static int 465 proc_out(isc_session_t *sp) 466 { 467 sn_t *sn = &sp->sn; 468 pduq_t *pq; 469 int error, ndone; 470 int which; 471 472 debug_called(8); 473 error = ndone = 0; 474 475 while(sp->flags & ISC_LINK_UP) { 476 pdu_t *pp; 477 bhs_t *bhs; 478 /* 479 | check if there is outstanding work in: 480 | 1- the Immediate queue 481 | 2- the R2T queue 482 | 3- the cmd queue, only if the command window allows it. 483 */ 484 which = BIT(0) | BIT(1); 485 if(SNA_GT(sn->cmd, sn->maxCmd) == 0) // if(sn->maxCmd - sn->smc + 1) > 0 486 which |= BIT(2); 487 488 sdebug(4, "which=%d sn->maxCmd=%d sn->cmd=%d", which, sn->maxCmd, sn->cmd); 489 490 if((pq = i_dqueue_snd(sp, which)) == NULL) 491 break; 492 sdebug(4, "pq=%p", pq); 493 494 pp = &pq->pdu; 495 bhs = &pp->ipdu.bhs; 496 switch(bhs->opcode) { 497 case ISCSI_SCSI_CMD: 498 sn->itt++; 499 bhs->itt = htonl(sn->itt); 500 501 case ISCSI_LOGIN_CMD: 502 case ISCSI_TEXT_CMD: 503 case ISCSI_LOGOUT_CMD: 504 case ISCSI_SNACK: 505 case ISCSI_NOP_OUT: 506 case ISCSI_TASK_CMD: 507 bhs->CmdSN = htonl(sn->cmd); 508 if(bhs->I == 0) 509 sn->cmd++; 510 511 case ISCSI_WRITE_DATA: 512 bhs->ExpStSN = htonl(sn->stat); 513 break; 514 515 default: 516 // XXX: can this happen? 517 xdebug("bad opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)", 518 bhs->opcode, 519 sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt); 520 // XXX: and now? 521 } 522 523 sdebug(4, "opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)", 524 bhs->opcode, 525 sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt); 526 527 if(pq->ccb) 528 i_nqueue_hld(sp, pq); 529 530 if((error = isc_sendPDU(sp, pq)) == 0) { 531 ndone++; 532 if(pq->ccb == NULL) 533 pdu_free(sp->isc, pq); 534 } 535 else { 536 xdebug("error=%d ndone=%d opcode=0x%x ccb=%p itt=%x", 537 error, ndone, bhs->opcode, pq->ccb, ntohl(bhs->itt)); 538 if(pq->ccb) 539 i_remove_hld(sp, pq); 540 switch(error) { 541 case EPIPE: 542 sp->flags &= ~ISC_LINK_UP; 543 544 case EAGAIN: 545 xdebug("requed"); 546 i_rqueue_pdu(sp, pq); 547 break; 548 549 default: 550 if(pq->ccb) { 551 xdebug("back to cam"); 552 pq->ccb->ccb_h.status |= CAM_REQUEUE_REQ; // some better error? 553 XPT_DONE(sp->isc, pq->ccb); 554 pdu_free(sp->isc, pq); 555 } 556 else 557 xdebug("we lost it!"); 558 } 559 } 560 } 561 return error; 562 } 563 564 /* 565 | survives link breakdowns. 566 */ 567 static void 568 ism_proc(void *vp) 569 { 570 isc_session_t *sp = (isc_session_t *)vp; 571 int error; 572 573 debug_called(8); 574 575 sdebug(3, "started sp->flags=%x", sp->flags); 576 do { 577 if((sp->flags & ISC_HOLD) == 0) { 578 error = proc_out(sp); 579 if(error) { 580 sdebug(3, "error=%d", error); 581 } 582 } 583 iscsi_lock_ex(&sp->io_mtx); 584 if((sp->flags & ISC_LINK_UP) == 0) { 585 wakeup(&sp->soc); 586 } 587 588 if((sp->flags & (ISC_OQNOTEMPTY | ISC_SM_RUN)) == ISC_SM_RUN) { 589 sp->flags |= ISC_OWAITING; 590 if(issleep(&sp->flags, &sp->io_mtx, 0, "iscproc", hz*30) == EWOULDBLOCK) { 591 if(sp->flags & ISC_CON_RUNNING) 592 _nop_out(sp); 593 } 594 sp->flags &= ~ISC_OWAITING; 595 } 596 sp->flags &= ~ISC_OQNOTEMPTY; 597 iscsi_unlock_ex(&sp->io_mtx); 598 } while(sp->flags & ISC_SM_RUN); 599 600 sp->flags &= ~ISC_SM_RUNNING; 601 sdebug(3, "dropped ISC_SM_RUNNING"); 602 603 wakeup(sp); 604 605 debug(3, "terminated sp=%p sp->sid=%d", sp, sp->sid); 606 607 kthread_exit(); 608 } 609 610 #if 0 611 static int 612 isc_dump_options(SYSCTL_HANDLER_ARGS) 613 { 614 int error; 615 isc_session_t *sp; 616 char buf[1024], *bp; 617 618 sp = (isc_session_t *)arg1; 619 bp = buf; 620 ksprintf(bp, "targetname='%s'", sp->opt.targetName); 621 bp += strlen(bp); 622 ksprintf(bp, " targetname='%s'", sp->opt.targetAddress); 623 error = SYSCTL_OUT(req, buf, strlen(buf)); 624 return error; 625 } 626 #endif 627 628 static int 629 isc_dump_stats(SYSCTL_HANDLER_ARGS) 630 { 631 isc_session_t *sp; 632 struct isc_softc *sc; 633 char buf[1024], *bp; 634 int error, n; 635 636 sp = (isc_session_t *)arg1; 637 sc = sp->isc; 638 639 bp = buf; 640 n = sizeof(buf); 641 ksnprintf(bp, n, "recv=%d sent=%d", sp->stats.nrecv, sp->stats.nsent); 642 bp += strlen(bp); 643 n -= strlen(bp); 644 ksnprintf(bp, n, " flags=0x%08x pdus-alloc=%d pdus-max=%d", 645 sp->flags, sc->npdu_alloc, sc->npdu_max); 646 bp += strlen(bp); 647 n -= strlen(bp); 648 ksnprintf(bp, n, " cws=%d cmd=%x exp=%x max=%x stat=%x itt=%x", 649 sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt); 650 error = SYSCTL_OUT(req, buf, strlen(buf)); 651 return error; 652 } 653 654 static int 655 isc_sysctl_targetName(SYSCTL_HANDLER_ARGS) 656 { 657 char buf[128], **cp; 658 int error; 659 660 cp = (char **)arg1; 661 ksnprintf(buf, sizeof(buf), "%s", *cp); 662 error = SYSCTL_OUT(req, buf, strlen(buf)); 663 return error; 664 } 665 static int 666 isc_sysctl_targetAddress(SYSCTL_HANDLER_ARGS) 667 { 668 char buf[128], **cp; 669 int error; 670 671 cp = (char **)arg1; 672 ksnprintf(buf, sizeof(buf), "%s", *cp); 673 error = SYSCTL_OUT(req, buf, strlen(buf)); 674 return error; 675 } 676 static void 677 isc_add_sysctls(isc_session_t *sp) 678 { 679 debug_called(8); 680 sdebug(6, "sid=%d %s", sp->sid, sp->dev->si_name); 681 682 sysctl_ctx_init(&sp->clist); 683 sp->oid = SYSCTL_ADD_NODE(&sp->clist, 684 SYSCTL_CHILDREN(sp->isc->oid), 685 OID_AUTO, 686 sp->dev->si_name+5, // iscsi0 687 CTLFLAG_RD, 688 0, 689 "initiator"); 690 SYSCTL_ADD_PROC(&sp->clist, 691 SYSCTL_CHILDREN(sp->oid), 692 OID_AUTO, 693 "targetname", 694 CTLFLAG_RD, 695 (void *)&sp->opt.targetName, 0, 696 isc_sysctl_targetName, "A", "target name"); 697 698 SYSCTL_ADD_PROC(&sp->clist, 699 SYSCTL_CHILDREN(sp->oid), 700 OID_AUTO, 701 "targeaddress", 702 CTLFLAG_RD, 703 (void *)&sp->opt.targetAddress, 0, 704 isc_sysctl_targetAddress, "A", "target address"); 705 706 SYSCTL_ADD_PROC(&sp->clist, 707 SYSCTL_CHILDREN(sp->oid), 708 OID_AUTO, 709 "stats", 710 CTLFLAG_RD, 711 (void *)sp, 0, 712 isc_dump_stats, "A", "statistics"); 713 714 SYSCTL_ADD_INT(&sp->clist, 715 SYSCTL_CHILDREN(sp->oid), 716 OID_AUTO, 717 "douio", 718 CTLFLAG_RW, 719 &sp->douio, 0, "enable uio on read"); 720 } 721 722 void 723 ism_stop(isc_session_t *sp) 724 { 725 struct isc_softc *sc = sp->isc; 726 cdev_t dev; 727 728 debug_called(8); 729 sdebug(2, "terminating"); 730 /* 731 | first stop the receiver 732 */ 733 isc_stop_receiver(sp); 734 735 /* 736 | now stop the xmitter 737 */ 738 sp->flags &= ~ISC_SM_RUN; 739 while(sp->flags & ISC_SM_RUNNING) { 740 sdebug(2, "waiting for ism to stop"); 741 wakeup(&sp->flags); 742 tsleep(sp, 0, "-", hz); 743 } 744 sdebug(2, "ism stopped"); 745 sp->flags &= ~ISC_FFPHASE; 746 747 iscsi_cleanup(sp); 748 749 (void)i_pdu_flush(sp); 750 751 ic_lost_target(sp, sp->sid); 752 753 lockmgr(&sc->lock, LK_EXCLUSIVE); 754 TAILQ_REMOVE(&sc->isc_sess, sp, sp_link); 755 sc->nsess--; 756 lockmgr(&sc->lock, LK_RELEASE); 757 758 dev = sp->dev; 759 sp->dev = NULL; 760 761 release_dev(dev); 762 destroy_dev(dev); 763 764 mtx_uninit(&sp->rsp_mtx); 765 mtx_uninit(&sp->rsv_mtx); 766 mtx_uninit(&sp->hld_mtx); 767 mtx_uninit(&sp->snd_mtx); 768 mtx_uninit(&sp->io_mtx); 769 770 i_freeopt(&sp->opt); 771 sc->sessions[sp->sid] = NULL; 772 773 if(sysctl_ctx_free(&sp->clist)) 774 xdebug("sysctl_ctx_free failed"); 775 776 kfree(sp, M_ISCSI); 777 } 778 779 int 780 ism_start(isc_session_t *sp) 781 { 782 debug_called(8); 783 /* 784 | now is a good time to do some initialization 785 */ 786 TAILQ_INIT(&sp->rsp); 787 TAILQ_INIT(&sp->rsv); 788 TAILQ_INIT(&sp->csnd); 789 TAILQ_INIT(&sp->isnd); 790 TAILQ_INIT(&sp->wsnd); 791 TAILQ_INIT(&sp->hld); 792 793 mtx_init(&sp->rsv_mtx); 794 mtx_init(&sp->rsp_mtx); 795 mtx_init(&sp->snd_mtx); 796 mtx_init(&sp->hld_mtx); 797 798 mtx_init(&sp->io_mtx); 799 800 isc_add_sysctls(sp); 801 802 sp->flags |= ISC_SM_RUN; 803 sp->flags |= ISC_SM_RUNNING; 804 805 debug(4, "starting ism_proc: sp->sid=%d", sp->sid); 806 return kthread_create(ism_proc, sp, &sp->stp, "ism_%d", sp->sid); 807 } 808