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_soc.c,v 1.6 2009/06/25 18:46:30 kib Exp $ 27 */ 28 /* 29 | iSCSI 30 | $Id: isc_soc.c,v 1.26 2007/05/19 06:09:01 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/user.h> 55 #include <signal.h> 56 #include <sys/eventhandler.h> 57 #include <sys/socketops.h> 58 59 #include <sys/thread2.h> 60 #include <sys/mutex2.h> 61 #include <sys/mplock2.h> 62 63 #include <bus/cam/cam.h> 64 #include <bus/cam/cam_ccb.h> 65 66 #include <dev/disk/iscsi/initiator/iscsi.h> 67 #include <dev/disk/iscsi/initiator/iscsivar.h> 68 69 #ifndef NO_USE_MBUF 70 #define USE_MBUF 71 #endif 72 73 #ifdef USE_MBUF 74 75 static int ou_refcnt = 0; 76 77 /* 78 | function for counting refs on external storage for mbuf 79 */ 80 static void 81 ext_ref(void *arg) 82 { 83 pduq_t *a = arg; 84 85 debug(3, "ou_refcnt=%d arg=%p b=%p", ou_refcnt, a, a->buf); 86 atomic_add_int(&a->refcnt, 1); 87 } 88 89 /* 90 | function for freeing external storage for mbuf 91 */ 92 static void 93 ext_free(void *arg) 94 { 95 pduq_t *a = arg; 96 97 if (atomic_fetchadd_int(&a->refcnt, -1) == 1) 98 if (a->buf != NULL) { 99 debug(3, "ou_refcnt=%d a=%p b=%p", ou_refcnt, a, a->buf); 100 kfree(a->buf, M_ISCSI); 101 a->buf = NULL; 102 } 103 } 104 105 int 106 isc_sendPDU(isc_session_t *sp, pduq_t *pq) 107 { 108 struct mbuf *mh, **mp; 109 pdu_t *pp = &pq->pdu; 110 int len, error; 111 112 debug_called(8); 113 /* 114 | mbuf for the iSCSI header 115 */ 116 MGETHDR(mh, MB_TRYWAIT, MT_DATA); 117 mh->m_len = mh->m_pkthdr.len = sizeof(union ipdu_u); 118 mh->m_pkthdr.rcvif = NULL; 119 MH_ALIGN(mh, sizeof(union ipdu_u)); 120 bcopy(&pp->ipdu, mh->m_data, sizeof(union ipdu_u)); 121 mh->m_next = NULL; 122 123 if(sp->hdrDigest) 124 pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0); 125 if(pp->ahs_len) { 126 /* 127 | Add any AHS to the iSCSI hdr mbuf 128 | XXX Assert: (mh->m_pkthdr.len + pp->ahs_len) < MHLEN 129 */ 130 bcopy(pp->ahs, (mh->m_data + mh->m_len), pp->ahs_len); 131 mh->m_len += pp->ahs_len; 132 mh->m_pkthdr.len += pp->ahs_len; 133 134 if(sp->hdrDigest) 135 pq->pdu.hdr_dig = sp->hdrDigest(&pp->ahs, pp->ahs_len, pq->pdu.hdr_dig); 136 } 137 if(sp->hdrDigest) { 138 debug(2, "hdr_dig=%x", pq->pdu.hdr_dig); 139 /* 140 | Add header digest to the iSCSI hdr mbuf 141 | XXX Assert: (mh->m_pkthdr.len + 4) < MHLEN 142 */ 143 bcopy(&pp->hdr_dig, (mh->m_data + mh->m_len), sizeof(int)); 144 mh->m_len += sizeof(int); 145 mh->m_pkthdr.len += sizeof(int); 146 } 147 mp = &mh->m_next; 148 if(pq->pdu.ds) { 149 struct mbuf *md; 150 int off = 0; 151 152 len = pp->ds_len; 153 while(len & 03) // the specs say it must be int alligned 154 len++; 155 while(len > 0) { 156 int l; 157 158 MGET(md, MB_TRYWAIT, MT_DATA); 159 pq->refcnt++; 160 161 l = min(MCLBYTES, len); 162 debug(5, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l); 163 md->m_ext.ext_buf = pq->buf; 164 md->m_ext.ext_free = ext_free; 165 md->m_ext.ext_ref = ext_ref; 166 md->m_ext.ext_arg = pq; 167 md->m_ext.ext_size = l; 168 md->m_flags |= M_EXT; 169 md->m_data = pp->ds + off; 170 md->m_len = l; 171 md->m_next = NULL; 172 mh->m_pkthdr.len += l; 173 *mp = md; 174 mp = &md->m_next; 175 len -= l; 176 off += l; 177 } 178 } 179 if(sp->dataDigest) { 180 struct mbuf *me; 181 182 pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0); 183 184 MGET(me, MB_TRYWAIT, MT_DATA); 185 me->m_len = sizeof(int); 186 MH_ALIGN(mh, sizeof(int)); 187 bcopy(&pp->ds_dig, me->m_data, sizeof(int)); 188 me->m_next = NULL; 189 mh->m_pkthdr.len += sizeof(int); 190 *mp = me; 191 } 192 if((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, curthread)) != 0) { 193 sdebug(3, "error=%d", error); 194 return error; 195 } 196 sp->stats.nsent++; 197 getmicrouptime(&sp->stats.t_sent); 198 return 0; 199 } 200 #else /* NO_USE_MBUF */ 201 int 202 isc_sendPDU(isc_session_t *sp, pduq_t *pq) 203 { 204 struct uio *uio = &pq->uio; 205 struct iovec *iv; 206 pdu_t *pp = &pq->pdu; 207 int len, error; 208 209 debug_called(8); 210 211 bzero(uio, sizeof(struct uio)); 212 uio->uio_rw = UIO_WRITE; 213 uio->uio_segflg = UIO_SYSSPACE; 214 uio->uio_td = curthread; 215 uio->uio_iov = iv = pq->iov; 216 217 iv->iov_base = &pp->ipdu; 218 iv->iov_len = sizeof(union ipdu_u); 219 uio->uio_resid = pq->len; 220 iv++; 221 if(sp->hdrDigest) 222 pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0); 223 if(pp->ahs_len) { 224 iv->iov_base = pp->ahs; 225 iv->iov_len = pp->ahs_len; 226 iv++; 227 228 if(sp->hdrDigest) 229 pq->pdu.hdr_dig = sp->hdrDigest(&pp->ahs, pp->ahs_len, pq->pdu.hdr_dig); 230 } 231 if(sp->hdrDigest) { 232 debug(2, "hdr_dig=%x", pq->pdu.hdr_dig); 233 iv->iov_base = &pp->hdr_dig; 234 iv->iov_len = sizeof(int); 235 iv++; 236 } 237 if(pq->pdu.ds) { 238 iv->iov_base = pp->ds; 239 iv->iov_len = pp->ds_len; 240 while(iv->iov_len & 03) // the specs say it must be int alligned 241 iv->iov_len++; 242 iv++; 243 } 244 if(sp->dataDigest) { 245 pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0); 246 iv->iov_base = &pp->ds_dig; 247 iv->iov_len = sizeof(int); 248 iv++; 249 } 250 uio->uio_iovcnt = iv - pq->iov; 251 sdebug(5, "opcode=%x iovcnt=%d uio_resid=%d itt=%x", 252 pp->ipdu.bhs.opcode, uio->uio_iovcnt, uio->uio_resid, 253 ntohl(pp->ipdu.bhs.itt)); 254 sdebug(5, "sp=%p sp->soc=%p uio=%p sp->td=%p", 255 sp, sp->soc, uio, sp->td); 256 do { 257 len = uio->uio_resid; 258 error = sosend(sp->soc, NULL, uio, 0, 0, 0, curthread); 259 if(uio->uio_resid == 0 || error || len == uio->uio_resid) { 260 if(uio->uio_resid) { 261 sdebug(2, "uio->uio_resid=%d uio->uio_iovcnt=%d error=%d len=%d", 262 uio->uio_resid, uio->uio_iovcnt, error, len); 263 if(error == 0) 264 error = EAGAIN; // 35 265 } 266 break; 267 } 268 /* 269 | XXX: untested code 270 */ 271 sdebug(1, "uio->uio_resid=%d uio->uio_iovcnt=%d", 272 uio->uio_resid, uio->uio_iovcnt); 273 iv = uio->uio_iov; 274 len -= uio->uio_resid; 275 while(uio->uio_iovcnt > 0) { 276 if(iv->iov_len > len) { 277 caddr_t bp = (caddr_t)iv->iov_base; 278 279 iv->iov_len -= len; 280 iv->iov_base = (void *)&bp[len]; 281 break; 282 } 283 len -= iv->iov_len; 284 uio->uio_iovcnt--; 285 uio->uio_iov++; 286 iv++; 287 } 288 } while(uio->uio_resid); 289 290 if(error == 0) { 291 sp->stats.nsent++; 292 getmicrouptime(&sp->stats.t_sent); 293 294 } 295 296 return error; 297 } 298 #endif /* USE_MBUF */ 299 300 /* 301 | wait till a PDU header is received 302 | from the socket. 303 */ 304 /* 305 The format of the BHS is: 306 307 Byte/ 0 | 1 | 2 | 3 | 308 / | | | | 309 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 310 +---------------+---------------+---------------+---------------+ 311 0|.|I| Opcode |F| Opcode-specific fields | 312 +---------------+---------------+---------------+---------------+ 313 4|TotalAHSLength | DataSegmentLength | 314 +---------------+---------------+---------------+---------------+ 315 8| LUN or Opcode-specific fields | 316 + + 317 12| | 318 +---------------+---------------+---------------+---------------+ 319 16| Initiator Task Tag | 320 +---------------+---------------+---------------+---------------+ 321 20/ Opcode-specific fields / 322 +/ / 323 +---------------+---------------+---------------+---------------+ 324 48 325 */ 326 static __inline int 327 so_getbhs(isc_session_t *sp) 328 { 329 bhs_t *bhs = &sp->bhs; 330 struct uio *uio = &sp->uio; 331 struct iovec *iov = &sp->iov; 332 int error, flags; 333 334 debug_called(8); 335 336 iov->iov_base = bhs; 337 iov->iov_len = sizeof(bhs_t); 338 339 uio->uio_iov = iov; 340 uio->uio_iovcnt = 1; 341 uio->uio_rw = UIO_READ; 342 uio->uio_segflg = UIO_SYSSPACE; 343 uio->uio_td = curthread; // why ... 344 uio->uio_resid = sizeof(bhs_t); 345 346 flags = MSG_WAITALL; 347 error = so_pru_soreceive(sp->soc, NULL, uio, NULL, NULL, &flags); 348 349 if(error) 350 debug(2, "error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd", 351 error, 352 sp->soc->so_error, uio->uio_resid, iov->iov_len); 353 if(!error && (uio->uio_resid > 0)) { 354 error = EPIPE; // was EAGAIN 355 debug(2, "error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd " 356 "so_state=%x", 357 error, 358 sp->soc->so_error, uio->uio_resid, iov->iov_len, 359 sp->soc->so_state); 360 } 361 362 return error; 363 } 364 365 /* 366 | so_recv gets called when there is at least 367 | an iSCSI header in the queue 368 */ 369 static int 370 so_recv(isc_session_t *sp, pduq_t *pq) 371 { 372 struct socket *so = sp->soc; 373 sn_t *sn = &sp->sn; 374 struct uio *uio = &pq->uio; 375 struct sockbuf sbp; 376 pdu_t *pp; 377 int error; 378 size_t n, len; 379 bhs_t *bhs; 380 u_int max, exp; 381 382 debug_called(8); 383 /* 384 | now calculate how much data should be in the buffer 385 | NOTE: digest is not verified/calculated - yet 386 */ 387 pp = &pq->pdu; 388 bhs = &pp->ipdu.bhs; 389 390 sbinit(&sbp, 0); 391 len = 0; 392 if(bhs->AHSLength) { 393 pp->ahs_len = bhs->AHSLength * 4; 394 len += pp->ahs_len; 395 } 396 if(sp->hdrDigest) 397 len += 4; 398 if(bhs->DSLength) { 399 n = bhs->DSLength; 400 #if BYTE_ORDER == LITTLE_ENDIAN 401 pp->ds_len = ((n & 0x00ff0000) >> 16) 402 | (n & 0x0000ff00) 403 | ((n & 0x000000ff) << 16); 404 #else 405 pp->ds_len = n; 406 #endif 407 len += pp->ds_len; 408 while(len & 03) 409 len++; 410 if(sp->dataDigest) 411 len += 4; 412 } 413 414 if((sp->opt.maxRecvDataSegmentLength > 0) && (len > sp->opt.maxRecvDataSegmentLength)) { 415 #if 0 416 xdebug("impossible PDU length(%d) opt.maxRecvDataSegmentLength=%d", 417 len, sp->opt.maxRecvDataSegmentLength); 418 // deep trouble here, probably all we can do is 419 // force a disconnect, XXX: check RFC ... 420 log(LOG_ERR, 421 "so_recv: impossible PDU length(%ld) from iSCSI %s/%s\n", 422 len, sp->opt.targetAddress, sp->opt.targetName); 423 #endif 424 /* 425 | XXX: this will really screwup the stream. 426 | should clear up the buffer till a valid header 427 | is found, or just close connection ... 428 | should read the RFC. 429 */ 430 error = E2BIG; 431 goto out; 432 } 433 if(len) { 434 int flags; 435 struct mbuf **mpp; 436 437 mpp = &pq->mp; 438 439 sbp.sb_climit = len; 440 uio->uio_td = curthread; // why ... 441 if(sp->douio) { 442 // it's more efficient to use mbufs -- why? 443 if(bhs->opcode == ISCSI_READ_DATA) { 444 pduq_t *opq; 445 446 opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1); 447 if(opq != NULL) { 448 union ccb *ccb = opq->ccb; 449 struct ccb_scsiio *csio = &ccb->csio; 450 pdu_t *opp = &opq->pdu; 451 scsi_req_t *cmd = &opp->ipdu.scsi_req; 452 data_in_t *rcmd = &pq->pdu.ipdu.data_in; 453 bhs_t *bhp = &opp->ipdu.bhs; 454 int r; 455 456 if(bhp->opcode == ISCSI_SCSI_CMD 457 && cmd->R 458 && (ntohl(cmd->edtlen) >= pq->pdu.ds_len)) { 459 struct iovec *iov = pq->iov; 460 iov->iov_base = csio->data_ptr + ntohl(rcmd->bo); 461 iov->iov_len = pq->pdu.ds_len; 462 463 uio->uio_rw = UIO_READ; 464 uio->uio_segflg = UIO_SYSSPACE; 465 uio->uio_iov = iov; 466 uio->uio_iovcnt = 1; 467 if(len > pq->pdu.ds_len) { 468 pq->iov[1].iov_base = &r; 469 pq->iov[1].iov_len = len - pq->pdu.ds_len; 470 uio->uio_iovcnt++; 471 } 472 mpp = NULL; 473 474 sdebug(4, "uio_resid=0x%zx itt=0x%x bp=%p bo=%x len=%x/%x", 475 uio->uio_resid, 476 ntohl(pq->pdu.ipdu.bhs.itt), 477 csio->data_ptr, ntohl(rcmd->bo), ntohl(cmd->edtlen), pq->pdu.ds_len); 478 } 479 } 480 } 481 } 482 /* 483 * Here we call so_pru_receive with a sockbuf so we can obtain 484 * the mbuf chain that can be assigned later to the pq->mp, 485 * which is the mbuf wanted. 486 * For the moment, resid will be saved in the uio. 487 */ 488 flags = MSG_WAITALL; 489 error = so_pru_soreceive(so, NULL, NULL, &sbp, NULL, &flags); 490 pq->mp = sbp.sb_mb; 491 uio->uio_resid = sbp.sb_climit - sbp.sb_cc; 492 //if(error == EAGAIN) 493 // XXX: this needs work! it hangs iscontrol 494 if(error || uio->uio_resid) 495 goto out; 496 } 497 pq->len += len; 498 sdebug(6, "len=%d] opcode=0x%x ahs_len=0x%x ds_len=0x%x", 499 pq->len, bhs->opcode, pp->ahs_len, pp->ds_len); 500 501 max = ntohl(bhs->MaxCmdSN); 502 exp = ntohl(bhs->ExpStSN); 503 504 if(max < exp - 1 && 505 max > exp - _MAXINCR) { 506 sdebug(2, "bad cmd window size"); 507 error = EIO; // XXX: for now; 508 goto out; // error 509 } 510 511 if(SNA_GT(max, sn->maxCmd)) 512 sn->maxCmd = max; 513 514 if(SNA_GT(exp, sn->expCmd)) 515 sn->expCmd = exp; 516 517 sp->cws = sn->maxCmd - sn->expCmd + 1; 518 519 return 0; 520 521 out: 522 // XXX: need some work here 523 xdebug("have a problem, error=%d", error); 524 pdu_free(sp->isc, pq); 525 if(!error && uio->uio_resid > 0) 526 error = EPIPE; 527 return error; 528 } 529 530 /* 531 | wait for something to arrive. 532 | and if the pdu is without errors, process it. 533 */ 534 static int 535 so_input(isc_session_t *sp) 536 { 537 pduq_t *pq; 538 int error; 539 540 debug_called(8); 541 /* 542 | first read in the iSCSI header 543 */ 544 error = so_getbhs(sp); 545 if(error == 0) { 546 /* 547 | now read the rest. 548 */ 549 pq = pdu_alloc(sp->isc, M_NOWAIT); 550 if(pq == NULL) { // XXX: might cause a deadlock ... 551 debug(3, "out of pdus, wait"); 552 pq = pdu_alloc(sp->isc, M_NOWAIT); // OK to WAIT 553 } 554 pq->pdu.ipdu.bhs = sp->bhs; 555 pq->len = sizeof(bhs_t); // so far only the header was read 556 error = so_recv(sp, pq); 557 if(error != 0) { 558 error += 0x800; // XXX: just to see the error. 559 // terminal error 560 // XXX: close connection and exit 561 } 562 else { 563 sp->stats.nrecv++; 564 getmicrouptime(&sp->stats.t_recv); 565 ism_recv(sp, pq); 566 } 567 } 568 return error; 569 } 570 571 /* 572 | one per active (connected) session. 573 | this thread is responsible for reading 574 | in packets from the target. 575 */ 576 static void 577 isc_soc(void *vp) 578 { 579 isc_session_t *sp = (isc_session_t *)vp; 580 struct socket *so = sp->soc; 581 int error; 582 583 get_mplock(); 584 debug_called(8); 585 586 sp->td = curthread; 587 if(sp->cam_path) 588 ic_release(sp); 589 590 error = 0; 591 while((sp->flags & (ISC_CON_RUN | ISC_LINK_UP)) == (ISC_CON_RUN | ISC_LINK_UP)) { 592 // XXX: hunting ... 593 if(sp->soc == NULL || !(so->so_state & SS_ISCONNECTED)) { 594 debug(2, "sp->soc=%p", sp->soc); 595 break; 596 } 597 error = so_input(sp); 598 if(error == 0) { 599 iscsi_lock_ex(&sp->io_mtx); 600 if(sp->flags & ISC_OWAITING) { 601 wakeup(&sp->flags); 602 } 603 iscsi_unlock_ex(&sp->io_mtx); 604 } else if(error == EPIPE) { 605 break; 606 } 607 else if(error == EAGAIN) { 608 if(so->so_state & SS_ISCONNECTED) 609 // there seems to be a problem in 6.0 ... 610 tsleep(sp, 0, "iscsoc", 2*hz); 611 } 612 } 613 sdebug(2, "terminated, flags=%x so_state=%x error=%d proc=%p", 614 sp->flags, so ? so->so_state : 0, error, sp->proc); 615 if((sp->proc != NULL) && sp->signal) { 616 PROC_LOCK(sp->proc); 617 ksignal(sp->proc, sp->signal); 618 PROC_UNLOCK(sp->proc); 619 sp->flags |= ISC_SIGNALED; 620 sdebug(2, "pid=%d signaled(%d)", sp->proc->p_pid, sp->signal); 621 } 622 else { 623 // we have to do something ourselves 624 // like closing this session ... 625 } 626 /* 627 | we've been terminated 628 */ 629 // do we need this mutex ...? 630 //iscsi_lock_ex(&sp->io_mtx); 631 sp->flags &= ~(ISC_CON_RUNNING | ISC_LINK_UP); 632 wakeup(&sp->soc); 633 //iscsi_unlock_ex(&sp->io_mtx); 634 635 sdebug(2, "dropped ISC_CON_RUNNING"); 636 637 rel_mplock(); 638 } 639 640 void 641 isc_stop_receiver(isc_session_t *sp) 642 { 643 debug_called(8); 644 debug(3, "sp=%p sp->sid=%d sp->soc=%p", sp, sp ? sp->sid : 0, 645 sp ? sp->soc : NULL); 646 iscsi_lock_ex(&sp->io_mtx); 647 sp->flags &= ~ISC_LINK_UP; 648 if (sp->flags & ISC_CON_RUNNING) { 649 issleep(&sp->soc, &sp->io_mtx, 0, "iscstpc", 5*hz); 650 } 651 iscsi_unlock_ex(&sp->io_mtx); 652 653 if (sp->soc) 654 soshutdown(sp->soc, SHUT_RD); 655 656 iscsi_lock_ex(&sp->io_mtx); 657 sdebug(3, "soshutdown"); 658 sp->flags &= ~ISC_CON_RUN; 659 while(sp->flags & ISC_CON_RUNNING) { 660 sdebug(3, "waiting flags=%x", sp->flags); 661 issleep(&sp->soc, &sp->io_mtx, 0, "iscstpc", hz); 662 } 663 iscsi_unlock_ex(&sp->io_mtx); 664 665 if (sp->fp != NULL) { 666 fdrop(sp->fp); 667 sp->fp = NULL; 668 } 669 /* sofree(sp->soc); fp deals with socket termination */ 670 sp->soc = NULL; 671 672 sdebug(3, "done"); 673 } 674 675 void 676 isc_start_receiver(isc_session_t *sp) 677 { 678 debug_called(8); 679 680 sp->flags |= ISC_CON_RUN | ISC_LINK_UP; 681 sp->flags |= ISC_CON_RUNNING; 682 683 kthread_create(isc_soc, sp, &sp->soc_thr, "iscsi%d", sp->sid); 684 } 685