AMD64 - Fix format conversions and other warnings.
[dragonfly.git] / sys / dev / disk / iscsi / initiator / isc_soc.c
CommitLineData
e25c779e
MD
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/ioccom.h>
50#include <sys/queue.h>
51#include <sys/kthread.h>
52#include <sys/syslog.h>
53#include <sys/mbuf.h>
54#include <sys/user.h>
55#include <signal.h>
56#include <sys/eventhandler.h>
57#include <sys/mutex.h>
58#include <sys/mutex2.h>
59#include <sys/socketops.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
73static int ou_refcnt = 0;
74
75/*
76 | function for counting refs on external storage for mbuf
77 */
78static void
79ext_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 */
90static void
91ext_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
103int
104isc_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, MB_TRYWAIT, 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, MB_TRYWAIT, 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, MB_TRYWAIT, 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, sp->td)) != 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 */
199int
200isc_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 = sp->td;
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, sp->td);
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 */
324static __inline int
325so_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)
bfc09ba0 348 debug(2, "error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd",
e25c779e
MD
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
bfc09ba0
MD
353 debug(2, "error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd "
354 "so_state=%x",
e25c779e 355 error,
bfc09ba0
MD
356 sp->soc->so_error, uio->uio_resid, iov->iov_len,
357 sp->soc->so_state);
e25c779e
MD
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 */
367static int
368so_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 struct mbuf **mpp;
434
435 mpp = &pq->mp;
436
437 sbp.sb_climit = len;
438 uio->uio_td = curthread; // why ...
439 if(sp->douio) {
440 // it's more efficient to use mbufs -- why?
441 if(bhs->opcode == ISCSI_READ_DATA) {
442 pduq_t *opq;
443
444 opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1);
445 if(opq != NULL) {
446 union ccb *ccb = opq->ccb;
447 struct ccb_scsiio *csio = &ccb->csio;
448 pdu_t *opp = &opq->pdu;
449 scsi_req_t *cmd = &opp->ipdu.scsi_req;
450 data_in_t *rcmd = &pq->pdu.ipdu.data_in;
451 bhs_t *bhp = &opp->ipdu.bhs;
452 int r;
453
454 if(bhp->opcode == ISCSI_SCSI_CMD
455 && cmd->R
456 && (ntohl(cmd->edtlen) >= pq->pdu.ds_len)) {
457 struct iovec *iov = pq->iov;
458 iov->iov_base = csio->data_ptr + ntohl(rcmd->bo);
459 iov->iov_len = pq->pdu.ds_len;
460
461 uio->uio_rw = UIO_READ;
462 uio->uio_segflg = UIO_SYSSPACE;
463 uio->uio_iov = iov;
464 uio->uio_iovcnt = 1;
465 if(len > pq->pdu.ds_len) {
466 pq->iov[1].iov_base = &r;
467 pq->iov[1].iov_len = len - pq->pdu.ds_len;
468 uio->uio_iovcnt++;
469 }
470 mpp = NULL;
471
472 sdebug(4, "uio_resid=0x%zx itt=0x%x bp=%p bo=%x len=%x/%x",
473 uio->uio_resid,
474 ntohl(pq->pdu.ipdu.bhs.itt),
475 csio->data_ptr, ntohl(rcmd->bo), ntohl(cmd->edtlen), pq->pdu.ds_len);
476 }
477 }
478 }
479 }
480 /*
481 * Here we call so_pru_receive with a sockbuf so we can obtain
482 * the mbuf chain that can be assigned later to the pq->mp,
483 * which is the mbuf wanted.
484 * For the moment, resid will be saved in the uio.
485 */
486 flags = MSG_WAITALL;
487 error = so_pru_soreceive(so, NULL, NULL, &sbp, NULL, &flags);
488 pq->mp = sbp.sb_mb;
489 uio->uio_resid = sbp.sb_climit - sbp.sb_cc;
490 //if(error == EAGAIN)
491 // XXX: this needs work! it hangs iscontrol
492 if(error || uio->uio_resid)
493 goto out;
494 }
495 pq->len += len;
496 sdebug(6, "len=%d] opcode=0x%x ahs_len=0x%x ds_len=0x%x",
497 pq->len, bhs->opcode, pp->ahs_len, pp->ds_len);
498
499 max = ntohl(bhs->MaxCmdSN);
500 exp = ntohl(bhs->ExpStSN);
501
502 if(max < exp - 1 &&
503 max > exp - _MAXINCR) {
504 sdebug(2, "bad cmd window size");
505 error = EIO; // XXX: for now;
506 goto out; // error
507 }
508
509 if(SNA_GT(max, sn->maxCmd))
510 sn->maxCmd = max;
511
512 if(SNA_GT(exp, sn->expCmd))
513 sn->expCmd = exp;
514
515 sp->cws = sn->maxCmd - sn->expCmd + 1;
516
517 return 0;
518
519 out:
520 // XXX: need some work here
521 xdebug("have a problem, error=%d", error);
522 pdu_free(sp->isc, pq);
523 if(!error && uio->uio_resid > 0)
524 error = EPIPE;
525 return error;
526}
527
528/*
529 | wait for something to arrive.
530 | and if the pdu is without errors, process it.
531 */
532static int
533so_input(isc_session_t *sp)
534{
535 pduq_t *pq;
536 int error;
537
538 debug_called(8);
539 /*
540 | first read in the iSCSI header
541 */
542 error = so_getbhs(sp);
543 if(error == 0) {
544 /*
545 | now read the rest.
546 */
547 pq = pdu_alloc(sp->isc, M_NOWAIT);
548 if(pq == NULL) { // XXX: might cause a deadlock ...
549 debug(3, "out of pdus, wait");
550 pq = pdu_alloc(sp->isc, M_NOWAIT); // OK to WAIT
551 }
552 pq->pdu.ipdu.bhs = sp->bhs;
553 pq->len = sizeof(bhs_t); // so far only the header was read
554 error = so_recv(sp, pq);
555 if(error != 0) {
556 error += 0x800; // XXX: just to see the error.
557 // terminal error
558 // XXX: close connection and exit
559 }
560 else {
561 sp->stats.nrecv++;
562 getmicrouptime(&sp->stats.t_recv);
563 ism_recv(sp, pq);
564 }
565 }
566 return error;
567}
568
569/*
570 | one per active (connected) session.
571 | this thread is responsible for reading
572 | in packets from the target.
573 */
574static void
575isc_soc(void *vp)
576{
577 isc_session_t *sp = (isc_session_t *)vp;
578 struct socket *so = sp->soc;
579 int error;
580
581 debug_called(8);
582
583 if(sp->cam_path)
584 ic_release(sp);
585
586 error = 0;
587 while((sp->flags & (ISC_CON_RUN | ISC_LINK_UP)) == (ISC_CON_RUN | ISC_LINK_UP)) {
588 // XXX: hunting ...
589 if(sp->soc == NULL || !(so->so_state & SS_ISCONNECTED)) {
590 debug(2, "sp->soc=%p", sp->soc);
591 break;
592 }
593 error = so_input(sp);
594 if(error == 0) {
595 iscsi_lock_ex(&sp->io_mtx);
596 if(sp->flags & ISC_OWAITING) {
597 wakeup(&sp->flags);
598 }
599 iscsi_unlock_ex(&sp->io_mtx);
600 } else if(error == EPIPE) {
601 break;
602 }
603 else if(error == EAGAIN) {
604 if(so->so_state & SS_ISCONNECTED)
605 // there seems to be a problem in 6.0 ...
606 tsleep(sp, 0, "iscsoc", 2*hz);
607 }
608 }
609 sdebug(2, "terminated, flags=%x so_state=%x error=%d proc=%p",
610 sp->flags, so->so_state, error, sp->proc);
611 if((sp->proc != NULL) && sp->signal) {
612 PROC_LOCK(sp->proc);
613 ksignal(sp->proc, sp->signal);
614 PROC_UNLOCK(sp->proc);
615 sp->flags |= ISC_SIGNALED;
616 sdebug(2, "pid=%d signaled(%d)", sp->proc->p_pid, sp->signal);
617 }
618 else {
619 // we have to do something ourselves
620 // like closing this session ...
621 }
622 /*
623 | we've been terminated
624 */
625 // do we need this mutex ...?
626 //iscsi_lock_ex(&sp->io_mtx);
627 sp->flags &= ~(ISC_CON_RUNNING | ISC_LINK_UP);
628 wakeup(&sp->soc);
629 //iscsi_unlock_ex(&sp->io_mtx);
630
631 sdebug(2, "dropped ISC_CON_RUNNING");
632
633 kthread_exit();
634}
635
636void
637isc_stop_receiver(isc_session_t *sp)
638{
639 debug_called(8);
640 sdebug(3, "sp=%p sp->soc=%p", sp, sp? sp->soc: 0);
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
670void
671isc_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}