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 57 #include <sys/thread2.h> 58 #include <sys/mutex2.h> 59 #include <sys/mplock2.h> 60 61 #include <bus/cam/cam.h> 62 #include <bus/cam/cam_ccb.h> 63 #include <bus/cam/cam_sim.h> 64 #include <bus/cam/cam_xpt_sim.h> 65 #include <bus/cam/cam_periph.h> 66 67 #include <dev/disk/iscsi/initiator/iscsi.h> 68 #include <dev/disk/iscsi/initiator/iscsivar.h> 69 70 static void 71 _async(isc_session_t *sp, pduq_t *pq) 72 { 73 debug_called(8); 74 75 iscsi_async(sp, pq); 76 77 pdu_free(sp->isc, pq); 78 } 79 80 static void 81 _reject(isc_session_t *sp, pduq_t *pq) 82 { 83 pduq_t *opq; 84 pdu_t *pdu; 85 reject_t *reject; 86 int itt; 87 88 debug_called(8); 89 pdu = mtod(pq->mp, pdu_t *); 90 itt = pdu->ipdu.bhs.itt; 91 reject = &pq->pdu.ipdu.reject; 92 sdebug(2, "itt=%x reason=0x%x", ntohl(itt), reject->reason); 93 opq = i_search_hld(sp, itt, 0); 94 if(opq != NULL) 95 iscsi_reject(sp, opq, pq); 96 else { 97 switch(pq->pdu.ipdu.bhs.opcode) { 98 case ISCSI_LOGOUT_CMD: // XXX: wasabi does this - can't figure out why 99 sdebug(2, "ISCSI_LOGOUT_CMD ..."); 100 break; 101 default: 102 xdebug("%d] we lost something itt=%x", 103 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt)); 104 } 105 } 106 pdu_free(sp->isc, pq); 107 } 108 109 static void 110 _r2t(isc_session_t *sp, pduq_t *pq) 111 { 112 pduq_t *opq; 113 114 debug_called(8); 115 opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1); 116 if(opq != NULL) { 117 iscsi_r2t(sp, opq, pq); 118 } 119 else { 120 r2t_t *r2t = &pq->pdu.ipdu.r2t; 121 122 xdebug("%d] we lost something itt=%x r2tSN=%d bo=%x ddtl=%x", 123 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt), 124 ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl)); 125 } 126 pdu_free(sp->isc, pq); 127 } 128 129 static void 130 _scsi_rsp(isc_session_t *sp, pduq_t *pq) 131 { 132 pduq_t *opq; 133 134 debug_called(8); 135 opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 0); 136 debug(5, "itt=%x pq=%p opq=%p", ntohl(pq->pdu.ipdu.bhs.itt), pq, opq); 137 if(opq != NULL) 138 iscsi_done(sp, opq, pq); 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 145 static 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 */ 167 static 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 196 static 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 261 int 262 i_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(sp->hdrDigest) 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(sp->dataDigest) 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 304 int 305 isc_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 iscsi_lock_ex(&sp->io_mtx); 325 sp->flags |= ISC_OQNOTEMPTY; 326 if(sp->flags & ISC_OWAITING) 327 wakeup(&sp->flags); 328 iscsi_unlock_ex(&sp->io_mtx); 329 330 return error; 331 } 332 /* 333 | called when a fullPhase is restarted 334 */ 335 static void 336 ism_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 iscsi_lock_ex(&sp->io_mtx); 349 if(sp->flags & ISC_OWAITING) { 350 wakeup(&sp->flags); 351 } 352 iscsi_unlock_ex(&sp->io_mtx); 353 354 sdebug(2, "restarted lastcmd=0x%x", lastcmd); 355 } 356 357 int 358 ism_fullfeature(struct cdev *dev, int flag) 359 { 360 isc_session_t *sp = (isc_session_t *)dev->si_drv2; 361 int error; 362 363 sdebug(2, "flag=%d", flag); 364 365 error = 0; 366 switch(flag) { 367 case 0: // stop 368 sp->flags &= ~ISC_FFPHASE; 369 break; 370 case 1: // start 371 error = ic_fullfeature(dev); 372 break; 373 case 2: // restart 374 ism_restart(sp); 375 break; 376 } 377 return error; 378 } 379 380 void 381 ism_recv(isc_session_t *sp, pduq_t *pq) 382 { 383 bhs_t *bhs; 384 int statSN; 385 386 debug_called(8); 387 388 bhs = &pq->pdu.ipdu.bhs; 389 statSN = ntohl(bhs->OpcodeSpecificFields[1]); 390 #if 0 391 { 392 /* 393 | this code is only for debugging. 394 */ 395 sn_t *sn = &sp->sn; 396 if(sp->cws == 0) { 397 if((sp->flags & ISC_STALLED) == 0) { 398 sdebug(4, "window closed: max=0x%x exp=0x%x opcode=0x%x cmd=0x%x cws=%d.", 399 sn->maxCmd, sn->expCmd, bhs->opcode, sn->cmd, sp->cws); 400 sp->flags |= ISC_STALLED; 401 } else 402 if(sp->flags & ISC_STALLED) { 403 sdebug(4, "window opened: max=0x%x exp=0x%x opcode=0x%x cmd=0x%x cws=%d.", 404 sn->maxCmd, sn->expCmd, bhs->opcode, sn->cmd, sp->cws); 405 sp->flags &= ~ISC_STALLED;; 406 } 407 } 408 } 409 #endif 410 411 #ifdef notyet 412 if(sp->sn.expCmd != sn->cmd) { 413 sdebug(1, "we lost something ... exp=0x%x cmd=0x%x", 414 sn->expCmd, sn->cmd); 415 } 416 #endif 417 sdebug(5, "opcode=0x%x itt=0x%x stat#0x%x maxcmd=0x%0x", 418 bhs->opcode, ntohl(bhs->itt), statSN, sp->sn.maxCmd); 419 420 switch(bhs->opcode) { 421 case ISCSI_READ_DATA: { 422 data_in_t *cmd = &pq->pdu.ipdu.data_in; 423 424 if(cmd->S == 0) 425 break; 426 } 427 428 default: 429 if(statSN > (sp->sn.stat + 1)) { 430 sdebug(1, "we lost some rec=0x%x exp=0x%x", 431 statSN, sp->sn.stat); 432 // XXX: must do some error recovery here. 433 } 434 sp->sn.stat = statSN; 435 } 436 437 switch(bhs->opcode) { 438 case ISCSI_LOGIN_RSP: 439 case ISCSI_TEXT_RSP: 440 case ISCSI_LOGOUT_RSP: 441 i_nqueue_rsp(sp, pq); 442 wakeup(&sp->rsp); 443 sdebug(3, "wakeup rsp"); 444 break; 445 446 case ISCSI_NOP_IN: _nop_in(sp, pq); break; 447 case ISCSI_SCSI_RSP: _scsi_rsp(sp, pq); break; 448 case ISCSI_READ_DATA: _read_data(sp, pq); break; 449 case ISCSI_R2T: _r2t(sp, pq); break; 450 case ISCSI_REJECT: _reject(sp, pq); break; 451 case ISCSI_ASYNC: _async(sp, pq); break; 452 453 case ISCSI_TASK_RSP: 454 default: 455 sdebug(1, "opcode=0x%x itt=0x%x not implemented yet", 456 bhs->opcode, ntohl(bhs->itt)); 457 break; 458 } 459 } 460 461 /* 462 | go through the out queues looking for work 463 | if either nothing to do, or window is closed 464 | return. 465 */ 466 static int 467 proc_out(isc_session_t *sp) 468 { 469 sn_t *sn = &sp->sn; 470 pduq_t *pq; 471 int error, ndone; 472 int which; 473 474 debug_called(8); 475 error = ndone = 0; 476 477 while(sp->flags & ISC_LINK_UP) { 478 pdu_t *pp; 479 bhs_t *bhs; 480 /* 481 | check if there is outstanding work in: 482 | 1- the Immediate queue 483 | 2- the R2T queue 484 | 3- the cmd queue, only if the command window allows it. 485 */ 486 which = BIT(0) | BIT(1); 487 if(SNA_GT(sn->cmd, sn->maxCmd) == 0) // if(sn->maxCmd - sn->smc + 1) > 0 488 which |= BIT(2); 489 490 sdebug(4, "which=%d sn->maxCmd=%d sn->cmd=%d", which, sn->maxCmd, sn->cmd); 491 492 if((pq = i_dqueue_snd(sp, which)) == NULL) 493 break; 494 sdebug(4, "pq=%p", pq); 495 496 pp = &pq->pdu; 497 bhs = &pp->ipdu.bhs; 498 switch(bhs->opcode) { 499 case ISCSI_SCSI_CMD: 500 sn->itt++; 501 bhs->itt = htonl(sn->itt); 502 503 case ISCSI_LOGIN_CMD: 504 case ISCSI_TEXT_CMD: 505 case ISCSI_LOGOUT_CMD: 506 case ISCSI_SNACK: 507 case ISCSI_NOP_OUT: 508 case ISCSI_TASK_CMD: 509 bhs->CmdSN = htonl(sn->cmd); 510 if(bhs->I == 0) 511 sn->cmd++; 512 513 case ISCSI_WRITE_DATA: 514 bhs->ExpStSN = htonl(sn->stat); 515 break; 516 517 default: 518 // XXX: can this happen? 519 xdebug("bad opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)", 520 bhs->opcode, 521 sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt); 522 // XXX: and now? 523 } 524 525 sdebug(4, "opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)", 526 bhs->opcode, 527 sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt); 528 529 if(pq->ccb) 530 i_nqueue_hld(sp, pq); 531 532 if((error = isc_sendPDU(sp, pq)) == 0) { 533 ndone++; 534 if(pq->ccb == NULL) 535 pdu_free(sp->isc, pq); 536 } 537 else { 538 xdebug("error=%d ndone=%d opcode=0x%x ccb=%p itt=%x", 539 error, ndone, bhs->opcode, pq->ccb, ntohl(bhs->itt)); 540 if(pq->ccb) 541 i_remove_hld(sp, pq); 542 switch(error) { 543 case EPIPE: 544 sp->flags &= ~ISC_LINK_UP; 545 546 case EAGAIN: 547 xdebug("requed"); 548 i_rqueue_pdu(sp, pq); 549 break; 550 551 default: 552 if(pq->ccb) { 553 xdebug("back to cam"); 554 pq->ccb->ccb_h.status |= CAM_REQUEUE_REQ; // some better error? 555 XPT_DONE(sp->isc, pq->ccb); 556 pdu_free(sp->isc, pq); 557 } 558 else 559 xdebug("we lost it!"); 560 } 561 } 562 } 563 return error; 564 } 565 566 /* 567 | survives link breakdowns. 568 */ 569 static void 570 ism_proc(void *vp) 571 { 572 isc_session_t *sp = (isc_session_t *)vp; 573 int error; 574 575 get_mplock(); 576 debug_called(8); 577 578 sdebug(3, "started sp->flags=%x", sp->flags); 579 do { 580 if((sp->flags & ISC_HOLD) == 0) { 581 error = proc_out(sp); 582 if(error) { 583 sdebug(3, "error=%d", error); 584 } 585 } 586 iscsi_lock_ex(&sp->io_mtx); 587 if((sp->flags & ISC_LINK_UP) == 0) { 588 wakeup(&sp->soc); 589 } 590 591 if((sp->flags & (ISC_OQNOTEMPTY | ISC_SM_RUN)) == ISC_SM_RUN) { 592 sp->flags |= ISC_OWAITING; 593 if(issleep(&sp->flags, &sp->io_mtx, 0, "iscproc", hz*30) == EWOULDBLOCK) { 594 if(sp->flags & ISC_CON_RUNNING) 595 _nop_out(sp); 596 } 597 sp->flags &= ~ISC_OWAITING; 598 } 599 sp->flags &= ~ISC_OQNOTEMPTY; 600 iscsi_unlock_ex(&sp->io_mtx); 601 } while(sp->flags & ISC_SM_RUN); 602 603 sp->flags &= ~ISC_SM_RUNNING; 604 sdebug(3, "dropped ISC_SM_RUNNING"); 605 606 wakeup(sp); 607 608 debug(3, "terminated sp=%p sp->sid=%d", sp, sp->sid); 609 610 rel_mplock(); 611 } 612 613 #if 0 614 static int 615 isc_dump_options(SYSCTL_HANDLER_ARGS) 616 { 617 int error; 618 isc_session_t *sp; 619 char buf[1024], *bp; 620 621 sp = (isc_session_t *)arg1; 622 bp = buf; 623 ksprintf(bp, "targetname='%s'", sp->opt.targetName); 624 bp += strlen(bp); 625 ksprintf(bp, " targetname='%s'", sp->opt.targetAddress); 626 error = SYSCTL_OUT(req, buf, strlen(buf)); 627 return error; 628 } 629 #endif 630 631 static int 632 isc_dump_stats(SYSCTL_HANDLER_ARGS) 633 { 634 isc_session_t *sp; 635 struct isc_softc *sc; 636 char buf[1024], *bp; 637 int error, n; 638 639 sp = (isc_session_t *)arg1; 640 sc = sp->isc; 641 642 bp = buf; 643 n = sizeof(buf); 644 ksnprintf(bp, n, "recv=%d sent=%d", sp->stats.nrecv, sp->stats.nsent); 645 bp += strlen(bp); 646 n -= strlen(bp); 647 ksnprintf(bp, n, " flags=0x%08x pdus-alloc=%d pdus-max=%d", 648 sp->flags, sc->npdu_alloc, sc->npdu_max); 649 bp += strlen(bp); 650 n -= strlen(bp); 651 ksnprintf(bp, n, " cws=%d cmd=%x exp=%x max=%x stat=%x itt=%x", 652 sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt); 653 error = SYSCTL_OUT(req, buf, strlen(buf)); 654 return error; 655 } 656 657 static int 658 isc_sysctl_targetName(SYSCTL_HANDLER_ARGS) 659 { 660 char buf[128], **cp; 661 int error; 662 663 cp = (char **)arg1; 664 ksnprintf(buf, sizeof(buf), "%s", *cp); 665 error = SYSCTL_OUT(req, buf, strlen(buf)); 666 return error; 667 } 668 static int 669 isc_sysctl_targetAddress(SYSCTL_HANDLER_ARGS) 670 { 671 char buf[128], **cp; 672 int error; 673 674 cp = (char **)arg1; 675 ksnprintf(buf, sizeof(buf), "%s", *cp); 676 error = SYSCTL_OUT(req, buf, strlen(buf)); 677 return error; 678 } 679 static void 680 isc_add_sysctls(isc_session_t *sp) 681 { 682 debug_called(8); 683 sdebug(6, "sid=%d %s", sp->sid, sp->dev->si_name); 684 685 sysctl_ctx_init(&sp->clist); 686 sp->oid = SYSCTL_ADD_NODE(&sp->clist, 687 SYSCTL_CHILDREN(sp->isc->oid), 688 OID_AUTO, 689 sp->dev->si_name+5, // iscsi0 690 CTLFLAG_RD, 691 0, 692 "initiator"); 693 SYSCTL_ADD_PROC(&sp->clist, 694 SYSCTL_CHILDREN(sp->oid), 695 OID_AUTO, 696 "targetname", 697 CTLFLAG_RD, 698 (void *)&sp->opt.targetName, 0, 699 isc_sysctl_targetName, "A", "target name"); 700 701 SYSCTL_ADD_PROC(&sp->clist, 702 SYSCTL_CHILDREN(sp->oid), 703 OID_AUTO, 704 "targeaddress", 705 CTLFLAG_RD, 706 (void *)&sp->opt.targetAddress, 0, 707 isc_sysctl_targetAddress, "A", "target address"); 708 709 SYSCTL_ADD_PROC(&sp->clist, 710 SYSCTL_CHILDREN(sp->oid), 711 OID_AUTO, 712 "stats", 713 CTLFLAG_RD, 714 (void *)sp, 0, 715 isc_dump_stats, "A", "statistics"); 716 717 SYSCTL_ADD_INT(&sp->clist, 718 SYSCTL_CHILDREN(sp->oid), 719 OID_AUTO, 720 "douio", 721 CTLFLAG_RW, 722 &sp->douio, 0, "enable uio on read"); 723 } 724 725 void 726 ism_stop(isc_session_t *sp) 727 { 728 struct isc_softc *sc = sp->isc; 729 cdev_t dev; 730 731 debug_called(8); 732 sdebug(2, "terminating"); 733 /* 734 | first stop the receiver 735 */ 736 isc_stop_receiver(sp); 737 738 /* 739 | now stop the xmitter 740 */ 741 sp->flags &= ~ISC_SM_RUN; 742 while(sp->flags & ISC_SM_RUNNING) { 743 sdebug(2, "waiting for ism to stop"); 744 wakeup(&sp->flags); 745 tsleep(sp, 0, "-", hz); 746 } 747 sdebug(2, "ism stopped"); 748 sp->flags &= ~ISC_FFPHASE; 749 750 iscsi_cleanup(sp); 751 752 (void)i_pdu_flush(sp); 753 754 ic_lost_target(sp, sp->sid); 755 756 lockmgr(&sc->lock, LK_EXCLUSIVE); 757 TAILQ_REMOVE(&sc->isc_sess, sp, sp_link); 758 sc->nsess--; 759 lockmgr(&sc->lock, LK_RELEASE); 760 761 dev = sp->dev; 762 sp->dev = NULL; 763 764 release_dev(dev); 765 destroy_dev(dev); 766 767 mtx_uninit(&sp->rsp_mtx); 768 mtx_uninit(&sp->rsv_mtx); 769 mtx_uninit(&sp->hld_mtx); 770 mtx_uninit(&sp->snd_mtx); 771 mtx_uninit(&sp->io_mtx); 772 773 i_freeopt(&sp->opt); 774 sc->sessions[sp->sid] = NULL; 775 776 if(sysctl_ctx_free(&sp->clist)) 777 xdebug("sysctl_ctx_free failed"); 778 779 kfree(sp, M_ISCSI); 780 } 781 782 int 783 ism_start(isc_session_t *sp) 784 { 785 debug_called(8); 786 /* 787 | now is a good time to do some initialization 788 */ 789 TAILQ_INIT(&sp->rsp); 790 TAILQ_INIT(&sp->rsv); 791 TAILQ_INIT(&sp->csnd); 792 TAILQ_INIT(&sp->isnd); 793 TAILQ_INIT(&sp->wsnd); 794 TAILQ_INIT(&sp->hld); 795 796 mtx_init(&sp->rsv_mtx); 797 mtx_init(&sp->rsp_mtx); 798 mtx_init(&sp->snd_mtx); 799 mtx_init(&sp->hld_mtx); 800 801 mtx_init(&sp->io_mtx); 802 803 isc_add_sysctls(sp); 804 805 sp->flags |= ISC_SM_RUN; 806 sp->flags |= ISC_SM_RUNNING; 807 808 debug(4, "starting ism_proc: sp->sid=%d", sp->sid); 809 return kthread_create(ism_proc, sp, &sp->stp, "ism_%d", sp->sid); 810 } 811