]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/iscsi/initiator/isc_soc.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / iscsi / initiator / isc_soc.c
1 /*-
2  * Copyright (c) 2005-2007 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  */
27 /*
28  | iSCSI
29  | $Id: isc_soc.c,v 1.26 2007/05/19 06:09:01 danny Exp danny $
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include "opt_iscsi_initiator.h"
36
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/conf.h>
40 #include <sys/systm.h>
41 #include <sys/malloc.h>
42 #include <sys/ctype.h>
43 #include <sys/errno.h>
44 #include <sys/sysctl.h>
45 #include <sys/file.h>
46 #include <sys/uio.h>
47 #include <sys/socketvar.h>
48 #include <sys/socket.h>
49 #include <sys/protosw.h>
50 #include <sys/proc.h>
51 #include <sys/ioccom.h>
52 #include <sys/queue.h>
53 #include <sys/kthread.h>
54 #include <sys/syslog.h>
55 #include <sys/mbuf.h>
56 #include <sys/user.h>
57
58 #include <dev/iscsi/initiator/iscsi.h>
59 #include <dev/iscsi/initiator/iscsivar.h>
60
61 #ifndef USE_MBUF
62 #define USE_MBUF
63 #endif
64
65 #ifdef USE_MBUF
66 /*
67  |  a dummy function for freeing external storage for mbuf
68  */
69 static void
70 nil_fn(void *a, void *b)
71 {
72 }
73 static int nil_refcnt = 0;
74 #endif /* USE_MBUF */
75
76 int
77 isc_sendPDU(isc_session_t *sp, pduq_t *pq)
78 {
79      pdu_t              *pp = &pq->pdu;
80      int                len, error;
81 #ifdef USE_MBUF
82      struct mbuf        *mh, **mp;
83 #else
84      struct uio         *uio = &pq->uio;
85      struct iovec       *iv;
86 #endif /* USE_MBUF */
87
88      debug_called(8);
89
90 #ifndef USE_MBUF
91      bzero(uio, sizeof(struct uio));
92      uio->uio_rw        = UIO_WRITE;
93      uio->uio_segflg    = UIO_SYSSPACE;
94      uio->uio_td        = sp->td;
95      uio->uio_iov       = iv = pq->iov;
96
97      iv->iov_base       = &pp->ipdu;
98      iv->iov_len        = sizeof(union ipdu_u);
99      uio->uio_resid     = pq->len;
100      iv++;
101 #else /* USE_MBUF */
102      /*  mbuf for the iSCSI header */
103      MGETHDR(mh, M_TRYWAIT, MT_DATA);
104      mh->m_len = mh->m_pkthdr.len = sizeof(union ipdu_u);
105      mh->m_pkthdr.rcvif = NULL;
106      MH_ALIGN(mh, sizeof(union ipdu_u));
107      bcopy(&pp->ipdu, mh->m_data, sizeof(union ipdu_u));
108      mh->m_next = NULL;
109 #endif /* USE_MBUF */
110
111      if(sp->hdrDigest)
112           pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
113      if(pp->ahs_len) {
114 #ifndef USE_MBUF
115           iv->iov_base  = pp->ahs;
116           iv->iov_len   = pp->ahs_len;
117           iv++;
118 #else /* USE_MBUF */
119           /* Add any AHS to the iSCSI hdr mbuf */
120           /* XXX Assert: (mh->m_pkthdr.len + pp->ahs_len) < MHLEN */
121           bcopy(pp->ahs, (mh->m_data + mh->m_len), pp->ahs_len);
122           mh->m_len += pp->ahs_len;
123           mh->m_pkthdr.len += pp->ahs_len;
124 #endif /* USE_MBUF */
125           if(sp->hdrDigest)
126                pq->pdu.hdr_dig = sp->hdrDigest(&pp->ahs, pp->ahs_len, pq->pdu.hdr_dig);
127      }
128      if(sp->hdrDigest) {
129           debug(2, "hdr_dig=%x", pq->pdu.hdr_dig);
130 #ifndef USE_MBUF
131           iv->iov_base  = &pp->hdr_dig;
132           iv->iov_len   = sizeof(int);
133           iv++;
134 #else /* USE_MBUF */
135           /* Add header digest to the iSCSI hdr mbuf */ 
136           /* XXX Assert: (mh->m_pkthdr.len + 4) < MHLEN */
137           bcopy(&pp->hdr_dig, (mh->m_data + mh->m_len), sizeof(int));
138           mh->m_len += sizeof(int);
139           mh->m_pkthdr.len += sizeof(int);
140 #endif /* USE_MBUF */
141      }
142 #ifdef USE_MBUF
143      mp = &mh->m_next;
144 #endif /* USE_MBUF */
145      if(pq->pdu.ds) {
146 #ifndef USE_MBUF
147           iv->iov_base  = pp->ds;
148           iv->iov_len   = pp->ds_len;
149           while(iv->iov_len & 03) // the specs say it must be int alligned
150                iv->iov_len++;
151           iv++;
152 #else /* USE_MBUF */
153           struct mbuf   *md;
154           int           off = 0;
155
156           len = pp->ds_len;
157           while(len & 03) // the specs say it must be int alligned
158                len++;
159
160           while (len > 0) {
161                 int       l;
162           
163                 MGET(md, M_TRYWAIT, MT_DATA);
164                 md->m_ext.ref_cnt = &nil_refcnt;
165                 l = min(MCLBYTES, len);
166                 MEXTADD(md, pp->ds + off, l, nil_fn,
167                         NULL, 0, EXT_EXTREF);
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
174                 len -= l;
175                 off += l;
176           } 
177 #endif /* USE_MBUF */
178      }
179      if(sp->dataDigest) {
180 #ifdef USE_MBUF
181           struct mbuf   *me;
182
183 #endif /* USE_MBUF */
184           pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0);
185 #ifndef USE_MBUF
186           iv->iov_base  = &pp->ds_dig;
187           iv->iov_len   = sizeof(int);
188           iv++;
189 #else /* USE_MBUF */
190           MGET(me, M_TRYWAIT, MT_DATA);
191           me->m_len = sizeof(int);
192           MH_ALIGN(mh, sizeof(int));
193           bcopy(&pp->ds_dig, me->m_data, sizeof(int));
194           me->m_next = NULL;
195      
196           mh->m_pkthdr.len += sizeof(int);
197           *mp = me;
198 #endif /* USE_MBUF */
199      }
200
201 #ifndef USE_MBUF
202      uio->uio_iovcnt    = iv - pq->iov;
203      sdebug(5, "opcode=%x iovcnt=%d uio_resid=%d itt=%x",
204             pp->ipdu.bhs.opcode, uio->uio_iovcnt, uio->uio_resid,
205             ntohl(pp->ipdu.bhs.itt));
206      sdebug(5, "sp=%p sp->soc=%p uio=%p sp->td=%p",
207             sp, sp->soc, uio, sp->td);
208
209      do {
210           len = uio->uio_resid;
211           error = sosend(sp->soc, NULL, uio, 0, 0, 0, sp->td);
212           if(uio->uio_resid == 0 || error || len == uio->uio_resid) {
213                if(uio->uio_resid) {
214                     sdebug(2, "uio->uio_resid=%d uio->uio_iovcnt=%d error=%d len=%d",
215                            uio->uio_resid, uio->uio_iovcnt, error, len);
216                     if(error == 0)
217                          error = EAGAIN; // 35
218                }
219                break;
220           }
221           /*
222            | XXX: untested code
223            */
224           sdebug(1, "uio->uio_resid=%d uio->uio_iovcnt=%d",
225                 uio->uio_resid, uio->uio_iovcnt);
226           iv = uio->uio_iov;
227           len -= uio->uio_resid;
228           while(uio->uio_iovcnt > 0) {
229                if(iv->iov_len > len) {
230                     caddr_t     bp = (caddr_t)iv->iov_base;
231
232                     iv->iov_len -= len;
233                     iv->iov_base = (void *)&bp[len];
234                     break;
235                }
236                len -= iv->iov_len;
237                uio->uio_iovcnt--;
238                uio->uio_iov++;
239                iv++;
240           }
241      } while(uio->uio_resid);
242
243      if(error == 0) {
244           sp->stats.nsent++;
245           getbintime(&sp->stats.t_sent);
246 #else /* USE_MBUF */
247      if ((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, sp->td)) != 0) {
248            m_freem(mh);
249            return (error);
250 #endif /* USE_MBUF */
251      }
252 #ifndef USE_MBUF
253      return error;
254 #else /* USE_MBUF */
255      sp->stats.nsent++;
256      getbintime(&sp->stats.t_sent);
257      return 0;
258 #endif /* USE_MBUF */
259 }
260
261 /*
262  | wait till a PDU header is received
263  | from the socket.
264  */
265 /*
266    The format of the BHS is:
267
268    Byte/     0       |       1       |       2       |       3       |
269       /              |               |               |               |
270      |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|
271      +---------------+---------------+---------------+---------------+
272     0|.|I| Opcode    |F|  Opcode-specific fields                     |
273      +---------------+---------------+---------------+---------------+
274     4|TotalAHSLength | DataSegmentLength                             |
275      +---------------+---------------+---------------+---------------+
276     8| LUN or Opcode-specific fields                                 |
277      +                                                               +
278    12|                                                               |
279      +---------------+---------------+---------------+---------------+
280    16| Initiator Task Tag                                            |
281      +---------------+---------------+---------------+---------------+
282    20/ Opcode-specific fields                                        /
283     +/                                                               /
284      +---------------+---------------+---------------+---------------+
285    48
286  */
287 static __inline int
288 so_getbhs(isc_session_t *sp)
289 {
290      bhs_t *bhs         = &sp->bhs;
291      struct uio         *uio = &sp->uio;
292      struct iovec       *iov = &sp->iov;
293      int                error, flags;
294
295      debug_called(8);
296
297      iov->iov_base      = bhs;
298      iov->iov_len       = sizeof(bhs_t);
299
300      uio->uio_iov       = iov;
301      uio->uio_iovcnt    = 1;
302      uio->uio_rw        = UIO_READ;
303      uio->uio_segflg    = UIO_SYSSPACE;
304      uio->uio_td        = curthread; // why ...
305      uio->uio_resid     = sizeof(bhs_t);
306
307      flags = MSG_WAITALL;
308      error = soreceive(sp->soc, NULL, uio, 0, 0, &flags);
309
310      if(error)
311           debug(2, "error=%d so_error=%d uio->uio_resid=%d iov.iov_len=%zd",
312                 error,
313                 sp->soc->so_error, uio->uio_resid, iov->iov_len);
314      if(!error && (uio->uio_resid > 0)) {
315           debug(2, "error=%d so_error=%d uio->uio_resid=%d iov.iov_len=%zd so_state=%x",
316                 error,
317                 sp->soc->so_error, uio->uio_resid, iov->iov_len, sp->soc->so_state);
318           error = EAGAIN; // EPIPE;
319      }
320           
321      return error;
322 }
323
324 /*
325  | so_recv gets called when there is at least
326  | an iSCSI header in the queue
327  */
328 static int
329 so_recv(isc_session_t *sp, pduq_t *pq)
330 {
331      struct socket      *so = sp->soc;
332      sn_t               *sn = &sp->sn;
333      struct uio         *uio = &pq->uio;
334      pdu_t              *pp;
335      int                error;
336      size_t             n, len;
337      bhs_t              *bhs;
338      u_int              max, exp;
339
340      debug_called(8);
341      /*
342       | now calculate how much data should be in the buffer
343       | NOTE: digest is not verified/calculated - yet
344       */
345      pp = &pq->pdu;
346      bhs = &pp->ipdu.bhs;
347
348      len = 0;
349      if(bhs->AHSLength) {
350           pp->ahs_len = bhs->AHSLength * 4;
351           len += pp->ahs_len;
352      }
353      if(sp->hdrDigest)
354           len += 4;
355      if(bhs->DSLength) {
356           n = bhs->DSLength;
357 #if BYTE_ORDER == LITTLE_ENDIAN
358           pp->ds_len = ((n & 0x00ff0000) >> 16)
359                | (n & 0x0000ff00)
360                | ((n & 0x000000ff) << 16);
361 #else
362           pp->ds_len = n;
363 #endif
364           len += pp->ds_len;
365           while(len & 03)
366                len++;
367           if(sp->dataDigest)
368                len += 4;
369      }
370
371      if((sp->opt.maxRecvDataSegmentLength > 0) && (len > sp->opt.maxRecvDataSegmentLength)) {
372 #if 0
373           xdebug("impossible PDU length(%d) opt.maxRecvDataSegmentLength=%d",
374                  len, sp->opt.maxRecvDataSegmentLength);
375           // deep trouble here, probably all we can do is
376           // force a disconnect, XXX: check RFC ...
377           log(LOG_ERR,
378               "so_recv: impossible PDU length(%ld) from iSCSI %s/%s\n",
379               len, sp->opt.targetAddress, sp->opt.targetName);
380 #endif
381           /*
382            | XXX: this will realy screwup the stream.
383            | should clear up the buffer till a valid header
384            | is found, or just close connection ...
385            | should read the RFC.
386            */
387           error = E2BIG;
388           goto out;
389      }
390      if(len) {
391           int   flags;
392
393           uio->uio_resid = len;
394           uio->uio_td = curthread; // why ...
395           flags = MSG_WAITALL;
396
397           error = soreceive(so, NULL, uio, &pq->mp, NULL, &flags);
398           //if(error == EAGAIN)
399           // XXX: this needs work! it hangs iscontrol
400           if(error || uio->uio_resid)
401                goto out;
402      }
403      pq->len += len;
404      sdebug(6, "len=%d] opcode=0x%x ahs_len=0x%x ds_len=0x%x",
405             pq->len, bhs->opcode, pp->ahs_len, pp->ds_len);
406
407      max = ntohl(bhs->MaxCmdSN);
408      exp = ntohl(bhs->ExpStSN);
409
410      if(max < exp - 1 &&
411         max > exp - _MAXINCR) {
412           sdebug(2,  "bad cmd window size");
413           error = EIO; // XXX: for now;
414           goto out; // error
415      }
416
417      if(SNA_GT(max, sn->maxCmd))
418           sn->maxCmd = max;
419
420      if(SNA_GT(exp, sn->expCmd))
421           sn->expCmd = exp;
422
423      sp->cws = sn->maxCmd - sn->expCmd + 1;
424
425      return 0;
426
427  out:
428      // XXX: need some work here
429      xdebug("have a problem, error=%d", error);
430      pdu_free(sp->isc, pq);
431      if(!error && uio->uio_resid > 0)
432           error = EPIPE;
433      return error;
434 }
435 /*
436  | wait for something to arrive.
437  | and if the pdu is without errors, process it.
438  */
439 static int
440 so_input(isc_session_t *sp)
441 {
442      pduq_t             *pq;
443      int                error;
444
445      debug_called(8);
446      /*
447       | first read in the iSCSI header
448       */
449      error = so_getbhs(sp);
450      if(error == 0) {
451           /*
452            | now read the rest.
453            */
454           pq = pdu_alloc(sp->isc, 1);  // OK to WAIT
455           pq->pdu.ipdu.bhs = sp->bhs;
456           pq->len = sizeof(bhs_t);      // so far only the header was read
457           error = so_recv(sp, pq);
458           if(error != 0) {
459                error += 0x800; // XXX: just to see the error.
460                // terminal error
461                // XXX: close connection and exit
462           }
463           else {
464                sp->stats.nrecv++;
465                getbintime(&sp->stats.t_recv);
466                ism_recv(sp, pq);
467           }
468      }
469      return error;
470 }
471
472 /*
473  | one per active (connected) session.
474  | this thread is responsible for reading
475  | in packets from the target.
476  */
477 static void
478 isc_soc(void *vp)
479 {
480      isc_session_t      *sp = (isc_session_t *)vp;
481      struct socket      *so = sp->soc;
482      int                error;
483
484      debug_called(8);
485
486      sp->flags |= ISC_CON_RUNNING;
487
488      if(sp->cam_path)
489           ic_release(sp);
490
491      error = 0;
492      while(sp->flags & ISC_CON_RUN) {
493           // XXX: hunting ...
494           if(sp->soc == NULL || !(so->so_state & SS_ISCONNECTED)) {
495                debug(2, "sp->soc=%p", sp->soc);
496                break;
497           }
498           error = so_input(sp);
499           if(error == 0) {
500 #ifdef ISC_OWAITING
501                mtx_lock(&sp->io_mtx);
502                if(sp->flags & ISC_OWAITING) {
503                     sp->flags &= ~ISC_OWAITING;
504                }
505                wakeup(&sp->flags);
506                mtx_unlock(&sp->io_mtx);
507 #else
508                wakeup(&sp->flags);
509 #endif
510
511           } else if(error == EPIPE)
512                break;
513           else if(error == EAGAIN) {
514                if(so->so_state & SS_ISCONNECTED) 
515                     // there seems to be a problem in 6.0 ...
516                     tsleep(sp, PRIBIO, "isc_soc", 2*hz);
517           }
518      }
519      sdebug(2, "terminated, flags=%x so_count=%d so_state=%x error=%d",
520             sp->flags, so->so_count, so->so_state, error);
521      if((sp->proc != NULL) && sp->signal) {
522           PROC_LOCK(sp->proc);
523           psignal(sp->proc, sp->signal);
524           PROC_UNLOCK(sp->proc);
525           sp->flags |= ISC_SIGNALED;
526           sdebug(2, "pid=%d signaled(%d)", sp->proc->p_pid, sp->signal);
527      }
528      else {
529           // we have to do something ourselves
530           // like closing this session ...
531      }
532      /*
533       | we've been terminated
534       */
535      // do we need this mutex ...?
536      mtx_lock(&sp->io_mtx);
537      sp->flags &= ~ISC_CON_RUNNING;
538      wakeup(&sp->soc);
539
540      mtx_unlock(&sp->io_mtx);
541
542      kthread_exit(0);
543 }
544
545 void
546 isc_stop_receiver(isc_session_t *sp)
547 {
548      int n = 5;
549      debug_called(8);
550
551      sdebug(4, "sp=%p sp->soc=%p", sp, sp? sp->soc: 0);
552      soshutdown(sp->soc, SHUT_RD);
553
554      mtx_lock(&sp->io_mtx);
555      sp->flags &= ~ISC_CON_RUN;
556      while(n-- && (sp->flags & ISC_CON_RUNNING)) {
557           sdebug(3, "waiting n=%d... flags=%x", n, sp->flags);
558           msleep(&sp->soc, &sp->io_mtx, PRIBIO, "isc_stpc", 5*hz);
559      }
560      mtx_unlock(&sp->io_mtx);
561
562      if(sp->fp != NULL)
563           fdrop(sp->fp, sp->td);
564      fputsock(sp->soc);
565      sp->soc = NULL;
566      sp->fp = NULL;
567 }
568
569 void
570 isc_start_receiver(isc_session_t *sp)
571 {
572      debug_called(8);
573
574      sp->flags |= ISC_CON_RUN;
575      kthread_create(isc_soc, sp, &sp->soc_proc, 0, 0, "iscsi%d", sp->sid);
576 }