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