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