Commit | Line | Data |
---|---|---|
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> | |
e25c779e MD |
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> | |
e25c779e MD |
56 | #include <sys/socketops.h> |
57 | ||
cd8ab232 MD |
58 | #include <sys/thread2.h> |
59 | #include <sys/mutex2.h> | |
60 | #include <sys/mplock2.h> | |
61 | ||
e25c779e MD |
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 | } | |
8650c3d4 | 191 | if((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, curthread)) != 0) { |
e25c779e MD |
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; | |
8650c3d4 | 213 | uio->uio_td = curthread; |
e25c779e MD |
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; | |
8650c3d4 | 257 | error = sosend(sp->soc, NULL, uio, 0, 0, 0, curthread); |
e25c779e MD |
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) | |
bfc09ba0 | 349 | debug(2, "error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd", |
e25c779e MD |
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 | |
bfc09ba0 MD |
354 | debug(2, "error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd " |
355 | "so_state=%x", | |
e25c779e | 356 | error, |
bfc09ba0 MD |
357 | sp->soc->so_error, uio->uio_resid, iov->iov_len, |
358 | sp->soc->so_state); | |
e25c779e MD |
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; | |
e25c779e MD |
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 | } | |
e25c779e MD |
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 | ||
cd8ab232 | 578 | get_mplock(); |
e25c779e MD |
579 | debug_called(8); |
580 | ||
8650c3d4 | 581 | sp->td = curthread; |
e25c779e MD |
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", | |
a08a53fe | 609 | sp->flags, so ? so->so_state : 0, error, sp->proc); |
e25c779e MD |
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 | ||
cd8ab232 | 632 | rel_mplock(); |
e25c779e MD |
633 | } |
634 | ||
635 | void | |
636 | isc_stop_receiver(isc_session_t *sp) | |
637 | { | |
638 | debug_called(8); | |
8e44e571 SW |
639 | debug(3, "sp=%p sp->sid=%d sp->soc=%p", sp, sp ? sp->sid : 0, |
640 | sp ? sp->soc : NULL); | |
e25c779e MD |
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) | |
8e44e571 | 649 | soshutdown(sp->soc, SHUT_RD); |
e25c779e MD |
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); | |
8e44e571 SW |
662 | sp->fp = NULL; |
663 | } | |
e25c779e MD |
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 | } |