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