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