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