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