]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/iscsi/initiator/iscsivar.h
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / iscsi / initiator / iscsivar.h
1 /*-
2  * Copyright (c) 2005-2011 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$
27  */
28
29 /*
30  | $Id: iscsivar.h 743 2009-08-08 10:54:53Z danny $
31  */
32 #define ISCSI_MAX_LUNS          128     // don't touch this
33 #if ISCSI_MAX_LUNS > 8
34 /*
35  | for this to work 
36  | sysctl kern.cam.cam_srch_hi=1
37  */
38 #endif
39
40 #ifndef ISCSI_INITIATOR_DEBUG
41 #define ISCSI_INITIATOR_DEBUG 1
42 #endif
43
44 #ifdef ISCSI_INITIATOR_DEBUG
45 extern int iscsi_debug;
46 #define debug(level, fmt, args...)      do {if(level <= iscsi_debug)\
47         printf("%s: " fmt "\n", __func__ , ##args);} while(0)
48 #define sdebug(level, fmt, args...)     do {if(level <= iscsi_debug)\
49         printf("%d] %s: " fmt "\n", sp->sid, __func__ , ##args);} while(0)
50 #define debug_called(level)             do {if(level <= iscsi_debug)\
51         printf("%s: called\n",  __func__);} while(0)
52 #else
53 #define debug(level, fmt, args...)
54 #define debug_called(level)
55 #define sdebug(level, fmt, args...)
56 #endif /* ISCSI_INITIATOR_DEBUG */
57
58 #define xdebug(fmt, args...)    printf(">>> %s: " fmt "\n", __func__ , ##args)
59
60 #define MAX_SESSIONS    ISCSI_MAX_TARGETS
61 #define MAX_PDUS        (MAX_SESSIONS*256) // XXX: at the moment this is arbitrary
62
63 typedef uint32_t digest_t(const void *, int len, uint32_t ocrc);
64
65 MALLOC_DECLARE(M_ISCSI);
66 MALLOC_DECLARE(M_ISCSIBUF);
67 MALLOC_DECLARE(M_PDU);
68
69 #define ISOK2DIG(dig, pp)       ((dig != NULL) && ((pp->ipdu.bhs.opcode & 0x1f) != ISCSI_LOGIN_CMD))
70
71 #ifndef BIT
72 #define BIT(n)  (1 <<(n))
73 #endif
74
75 #define ISC_SM_RUN      BIT(0)
76 #define ISC_SM_RUNNING  BIT(1)
77
78 #define ISC_LINK_UP     BIT(2)
79 #define ISC_CON_RUN     BIT(3)
80 #define ISC_CON_RUNNING BIT(4)
81 #define ISC_KILL        BIT(5)
82 #define ISC_OQNOTEMPTY  BIT(6)
83 #define ISC_OWAITING    BIT(7)
84 #define ISC_FFPHASE     BIT(8)
85
86 #define ISC_CAMDEVS     BIT(9)
87 #define ISC_SCANWAIT    BIT(10)
88
89 #define ISC_MEMWAIT     BIT(11)
90 #define ISC_SIGNALED    BIT(12)
91
92 #define ISC_HOLD        BIT(15)
93 #define ISC_HOLDED      BIT(16)
94
95 #define ISC_SHUTDOWN    BIT(31)
96
97 /*
98  | some stats
99  */
100 struct i_stats {
101      int        npdu;   // number of pdus malloc'ed.
102      int        nrecv;  // unprocessed received pdus
103      int        nsent;  // sent pdus
104
105      int        nrsp, max_rsp;
106      int        nrsv, max_rsv;
107      int        ncsnd, max_csnd;
108      int        nisnd, max_isnd;
109      int        nwsnd, max_wsnd;
110      int        nhld, max_hld;
111
112      struct bintime t_sent;
113      struct bintime t_recv;
114 };
115
116 /*
117  | one per 'session'
118  */
119
120 typedef TAILQ_HEAD(, pduq) queue_t;
121
122 typedef struct isc_session {
123      TAILQ_ENTRY(isc_session)   sp_link;
124      int                flags;
125      struct cdev        *dev;
126      struct socket      *soc;
127      struct file        *fp;
128      struct thread      *td;
129
130      struct proc        *proc; // the userland process
131      int                signal;
132      struct proc        *soc_proc;
133      struct proc        *stp;   // the sm thread
134
135      struct isc_softc   *isc;
136
137      digest_t           *hdrDigest;     // the digest alg. if any
138      digest_t           *dataDigest;    // the digest alg. if any
139
140      int                sid;            // Session ID
141      sn_t               sn;             // sequence number stuff;
142      int                cws;            // current window size
143
144      int                target_nluns; // this and target_lun are
145                                       // hopefully temporal till I
146                                       // figure out a better way.
147      int                target_lun[ISCSI_MAX_LUNS/(sizeof(int)*8) + 1];
148
149      struct mtx         rsp_mtx;
150      struct mtx         rsv_mtx;
151      struct mtx         snd_mtx;
152      struct mtx         hld_mtx;
153      struct mtx         io_mtx;
154      queue_t            rsp;
155      queue_t            rsv;
156      queue_t            csnd;
157      queue_t            isnd;
158      queue_t            wsnd;
159      queue_t            hld;                            
160
161      isc_opt_t          opt;    // negotiable values
162
163      struct i_stats     stats;
164      bhs_t              bhs;
165      struct uio         uio;
166      struct iovec       iov;
167      /*
168       | cam stuff
169       */
170      struct cam_sim     *cam_sim;
171      struct cam_path    *cam_path;
172      struct mtx         cam_mtx;
173      /*
174       | sysctl stuff
175       */
176      struct sysctl_ctx_list     clist;
177      struct sysctl_oid  *oid;
178      int        douio;  //XXX: turn on/off uio on read
179 } isc_session_t;
180
181 typedef struct pduq {
182      TAILQ_ENTRY(pduq)  pq_link;
183
184      caddr_t            buf;
185      u_int              len;    // the total length of the pdu
186      pdu_t              pdu;
187      union ccb          *ccb;
188
189      struct uio         uio;
190      struct iovec       iov[5]; // XXX: careful ...
191      struct mbuf        *mp;
192      struct bintime     ts;
193      queue_t            *pduq;          
194 } pduq_t;
195 /*
196  */
197 struct isc_softc {
198      struct mtx         isc_mtx;
199      TAILQ_HEAD(,isc_session)   isc_sess;
200      int                nsess;
201      struct cdev        *dev;
202      char               isid[6];        // Initiator Session ID (48 bits)
203      struct unrhdr      *unit;
204      struct sx          unit_sx;
205
206      uma_zone_t         pdu_zone;       // pool of free pdu's
207      TAILQ_HEAD(,pduq)  freepdu;
208
209 #ifdef  ISCSI_INITIATOR_DEBUG
210      int                 npdu_alloc, npdu_max; // for instrumentation
211 #endif
212 #ifdef DO_EVENTHANDLER
213      eventhandler_tag   eh;
214 #endif
215      /*
216       | sysctl stuff
217       */
218      struct sysctl_ctx_list     clist;
219      struct sysctl_oid          *oid;
220 };
221
222 #ifdef  ISCSI_INITIATOR_DEBUG
223 extern struct mtx iscsi_dbg_mtx;
224 #endif
225
226 void    isc_start_receiver(isc_session_t *sp);
227 void    isc_stop_receiver(isc_session_t *sp);
228
229 int     isc_sendPDU(isc_session_t *sp, pduq_t *pq);
230 int     isc_qout(isc_session_t *sp, pduq_t *pq);
231 int     i_prepPDU(isc_session_t *sp, pduq_t *pq);
232
233 int     ism_fullfeature(struct cdev *dev, int flag);
234
235 int     i_pdu_flush(isc_session_t *sc);
236 int     i_setopt(isc_session_t *sp, isc_opt_t *opt);
237 void    i_freeopt(isc_opt_t *opt);
238
239 int     ic_init(isc_session_t *sp);
240 void    ic_destroy(isc_session_t *sp);
241 void    ic_lost_target(isc_session_t *sp, int target);
242 int     ic_getCamVals(isc_session_t *sp, iscsi_cam_t *cp);
243
244 void    ism_recv(isc_session_t *sp, pduq_t *pq);
245 int     ism_start(isc_session_t *sp);
246 void    ism_restart(isc_session_t *sp);
247 void    ism_stop(isc_session_t *sp);
248
249 int     scsi_encap(struct cam_sim *sim, union ccb *ccb);
250 int     scsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
251 void    iscsi_r2t(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
252 void    iscsi_done(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
253 void    iscsi_reject(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
254 void    iscsi_async(isc_session_t *sp,  pduq_t *pq);
255 void    iscsi_cleanup(isc_session_t *sp);
256 int     iscsi_requeue(isc_session_t *sp);
257
258 // Serial Number Arithmetic
259 #define _MAXINCR        0x7FFFFFFF      // 2 ^ 31 - 1
260 #define SNA_GT(i1, i2)  ((i1 != i2) && (\
261         (i1 < i2 && i2 - i1 > _MAXINCR) ||\
262         (i1 > i2 && i1 - i2 < _MAXINCR))?1: 0)
263
264 /*
265  | inlines
266  */
267 #ifdef _CAM_CAM_XPT_SIM_H
268
269 #if __FreeBSD_version <  600000
270 #define CAM_LOCK(arg)
271 #define CAM_ULOCK(arg)
272
273 static __inline void
274 XPT_DONE(isc_session_t *sp, union ccb *ccb)
275 {
276      mtx_lock(&Giant);
277      xpt_done(ccb);
278      mtx_unlock(&Giant);
279 }
280 #elif __FreeBSD_version >= 700000
281 #define CAM_LOCK(arg)   mtx_lock(&arg->cam_mtx)
282 #define CAM_UNLOCK(arg) mtx_unlock(&arg->cam_mtx)
283
284 static __inline void
285 XPT_DONE(isc_session_t *sp, union ccb *ccb)
286 {
287      CAM_LOCK(sp);
288      xpt_done(ccb);
289      CAM_UNLOCK(sp);
290 }
291 #else
292 //__FreeBSD_version >= 600000
293 #define CAM_LOCK(arg)
294 #define CAM_UNLOCK(arg)
295 #define XPT_DONE(ignore, arg)   xpt_done(arg)
296 #endif
297
298 #endif /* _CAM_CAM_XPT_SIM_H */
299
300 static __inline pduq_t *
301 pdu_alloc(struct isc_softc *isc, int wait)
302 {
303      pduq_t     *pq;
304
305      pq = (pduq_t *)uma_zalloc(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/);
306      if(pq == NULL) {
307           debug(7, "out of mem");
308           return NULL;
309      }
310 #ifdef ISCSI_INITIATOR_DEBUG
311      mtx_lock(&iscsi_dbg_mtx);
312      isc->npdu_alloc++;
313      if(isc->npdu_alloc > isc->npdu_max)
314           isc->npdu_max = isc->npdu_alloc;
315      mtx_unlock(&iscsi_dbg_mtx);
316 #endif
317      memset(pq, 0, sizeof(pduq_t));
318
319      return pq;
320 }
321
322 static __inline void
323 pdu_free(struct isc_softc *isc, pduq_t *pq)
324 {
325      if(pq->mp)
326           m_freem(pq->mp);
327 #ifdef NO_USE_MBUF
328      if(pq->buf != NULL)
329           free(pq->buf, M_ISCSIBUF);
330 #endif
331      uma_zfree(isc->pdu_zone, pq);
332 #ifdef ISCSI_INITIATOR_DEBUG
333      mtx_lock(&iscsi_dbg_mtx);
334      isc->npdu_alloc--;
335      mtx_unlock(&iscsi_dbg_mtx);
336 #endif
337 }
338
339 static __inline void
340 i_nqueue_rsp(isc_session_t *sp, pduq_t *pq)
341 {
342      mtx_lock(&sp->rsp_mtx);
343      if(++sp->stats.nrsp > sp->stats.max_rsp)
344           sp->stats.max_rsp = sp->stats.nrsp;
345      TAILQ_INSERT_TAIL(&sp->rsp, pq, pq_link);
346      mtx_unlock(&sp->rsp_mtx);
347 }
348
349 static __inline pduq_t *
350 i_dqueue_rsp(isc_session_t *sp)
351 {
352      pduq_t *pq;
353
354      mtx_lock(&sp->rsp_mtx);
355      if((pq = TAILQ_FIRST(&sp->rsp)) != NULL) {
356           sp->stats.nrsp--;
357           TAILQ_REMOVE(&sp->rsp, pq, pq_link);
358      }
359      mtx_unlock(&sp->rsp_mtx);
360
361      return pq;
362 }
363
364 static __inline void
365 i_nqueue_rsv(isc_session_t *sp, pduq_t *pq)
366 {
367      mtx_lock(&sp->rsv_mtx);
368      if(++sp->stats.nrsv > sp->stats.max_rsv)
369           sp->stats.max_rsv = sp->stats.nrsv;
370      TAILQ_INSERT_TAIL(&sp->rsv, pq, pq_link);
371      mtx_unlock(&sp->rsv_mtx);
372 }
373
374 static __inline pduq_t *
375 i_dqueue_rsv(isc_session_t *sp)
376 {
377      pduq_t *pq;
378
379      mtx_lock(&sp->rsv_mtx);
380      if((pq = TAILQ_FIRST(&sp->rsv)) != NULL) {
381           sp->stats.nrsv--;
382           TAILQ_REMOVE(&sp->rsv, pq, pq_link);
383      }
384      mtx_unlock(&sp->rsv_mtx);
385
386      return pq;
387 }
388
389 static __inline void
390 i_nqueue_csnd(isc_session_t *sp, pduq_t *pq)
391 {
392      mtx_lock(&sp->snd_mtx);
393      if(++sp->stats.ncsnd > sp->stats.max_csnd)
394           sp->stats.max_csnd = sp->stats.ncsnd;
395      TAILQ_INSERT_TAIL(&sp->csnd, pq, pq_link);
396      mtx_unlock(&sp->snd_mtx);
397 }
398
399 static __inline pduq_t *
400 i_dqueue_csnd(isc_session_t *sp)
401 {
402      pduq_t *pq;
403
404      mtx_lock(&sp->snd_mtx);
405      if((pq = TAILQ_FIRST(&sp->csnd)) != NULL) {
406           sp->stats.ncsnd--;
407           TAILQ_REMOVE(&sp->csnd, pq, pq_link);
408      }
409      mtx_unlock(&sp->snd_mtx);
410
411      return pq;
412 }
413
414 static __inline void
415 i_nqueue_isnd(isc_session_t *sp, pduq_t *pq)
416 {
417      mtx_lock(&sp->snd_mtx);
418      if(++sp->stats.nisnd > sp->stats.max_isnd)
419           sp->stats.max_isnd = sp->stats.nisnd;
420      TAILQ_INSERT_TAIL(&sp->isnd, pq, pq_link);
421      mtx_unlock(&sp->snd_mtx);
422 }
423
424 static __inline pduq_t *
425 i_dqueue_isnd(isc_session_t *sp)
426 {
427      pduq_t *pq;
428
429      mtx_lock(&sp->snd_mtx);
430      if((pq = TAILQ_FIRST(&sp->isnd)) != NULL) {
431           sp->stats.nisnd--;
432           TAILQ_REMOVE(&sp->isnd, pq, pq_link);
433      }
434      mtx_unlock(&sp->snd_mtx);
435
436      return pq;
437 }
438
439 static __inline void
440 i_nqueue_wsnd(isc_session_t *sp, pduq_t *pq)
441 {
442      mtx_lock(&sp->snd_mtx);
443      if(++sp->stats.nwsnd > sp->stats.max_wsnd)
444           sp->stats.max_wsnd = sp->stats.nwsnd;
445      TAILQ_INSERT_TAIL(&sp->wsnd, pq, pq_link);
446      mtx_unlock(&sp->snd_mtx);
447 }
448
449 static __inline pduq_t *
450 i_dqueue_wsnd(isc_session_t *sp)
451 {
452      pduq_t *pq;
453
454      mtx_lock(&sp->snd_mtx);
455      if((pq = TAILQ_FIRST(&sp->wsnd)) != NULL) {
456           sp->stats.nwsnd--;
457           TAILQ_REMOVE(&sp->wsnd, pq, pq_link);
458      }
459      mtx_unlock(&sp->snd_mtx);
460
461      return pq;
462 }
463
464 static __inline pduq_t *
465 i_dqueue_snd(isc_session_t *sp, int which)
466 {
467      pduq_t *pq;
468
469      pq = NULL;
470      mtx_lock(&sp->snd_mtx);
471      if((which & BIT(0)) && (pq = TAILQ_FIRST(&sp->isnd)) != NULL) {
472           sp->stats.nisnd--;
473           TAILQ_REMOVE(&sp->isnd, pq, pq_link);
474           pq->pduq = &sp->isnd; // remember where you came from
475      } else
476      if((which & BIT(1)) && (pq = TAILQ_FIRST(&sp->wsnd)) != NULL) {
477           sp->stats.nwsnd--;
478           TAILQ_REMOVE(&sp->wsnd, pq, pq_link);
479           pq->pduq = &sp->wsnd; // remember where you came from
480      } else
481      if((which & BIT(2)) && (pq = TAILQ_FIRST(&sp->csnd)) != NULL) {
482           sp->stats.ncsnd--;
483           TAILQ_REMOVE(&sp->csnd, pq, pq_link);
484           pq->pduq = &sp->csnd; // remember where you came from
485      }
486      mtx_unlock(&sp->snd_mtx);
487
488      return pq;
489 }
490
491 static __inline void
492 i_rqueue_pdu(isc_session_t *sp, pduq_t *pq)
493 {
494      mtx_lock(&sp->snd_mtx);
495      KASSERT(pq->pduq != NULL, ("pq->pduq is NULL"));
496      TAILQ_INSERT_TAIL(pq->pduq, pq, pq_link);
497      mtx_unlock(&sp->snd_mtx);     
498 }
499
500 /*
501  | Waiting for ACK (or something :-)
502  */
503 static __inline void
504 i_nqueue_hld(isc_session_t *sp, pduq_t *pq)
505 {
506      getbintime(&pq->ts);
507      mtx_lock(&sp->hld_mtx);
508      if(++sp->stats.nhld > sp->stats.max_hld)
509           sp->stats.max_hld = sp->stats.nhld;
510      TAILQ_INSERT_TAIL(&sp->hld, pq, pq_link);
511      mtx_unlock(&sp->hld_mtx);
512      return;
513 }
514
515 static __inline void
516 i_remove_hld(isc_session_t *sp, pduq_t *pq)
517 {
518      mtx_lock(&sp->hld_mtx);
519      sp->stats.nhld--;
520      TAILQ_REMOVE(&sp->hld, pq, pq_link);
521      mtx_unlock(&sp->hld_mtx);
522 }
523
524 static __inline pduq_t *
525 i_dqueue_hld(isc_session_t *sp)
526 {
527      pduq_t *pq;
528
529      mtx_lock(&sp->hld_mtx);
530      if((pq = TAILQ_FIRST(&sp->hld)) != NULL) {
531           sp->stats.nhld--;
532           TAILQ_REMOVE(&sp->hld, pq, pq_link);
533      }
534      mtx_unlock(&sp->hld_mtx);
535
536      return pq;
537 }
538
539 static __inline pduq_t *
540 i_search_hld(isc_session_t *sp, int itt, int keep)
541 {
542      pduq_t     *pq, *tmp;
543
544      pq = NULL;
545
546      mtx_lock(&sp->hld_mtx);
547      TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, tmp) {
548           if(pq->pdu.ipdu.bhs.itt == itt) {
549                if(!keep) {
550                     sp->stats.nhld--;
551                     TAILQ_REMOVE(&sp->hld, pq, pq_link);
552                }
553                break;
554           }
555      }
556      mtx_unlock(&sp->hld_mtx);
557
558      return pq;
559 }
560
561 static __inline void
562 i_acked_hld(isc_session_t *sp, pdu_t *op)
563 {
564      pduq_t     *pq, *tmp;
565      u_int exp = sp->sn.expCmd;
566      
567      pq = NULL;
568      mtx_lock(&sp->hld_mtx);
569      TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, tmp) {
570           if((op && op->ipdu.bhs.itt == pq->pdu.ipdu.bhs.itt)
571              || (pq->ccb == NULL
572                  && (pq->pdu.ipdu.bhs.opcode != ISCSI_WRITE_DATA)
573                  && SNA_GT(exp, ntohl(pq->pdu.ipdu.bhs.ExpStSN)))) {
574                sp->stats.nhld--;
575                TAILQ_REMOVE(&sp->hld, pq, pq_link);
576                pdu_free(sp->isc, pq);
577           }
578      }
579      mtx_unlock(&sp->hld_mtx);
580 }
581
582 static __inline void
583 i_mbufcopy(struct mbuf *mp, caddr_t dp, int len)
584 {
585      struct mbuf *m;
586      caddr_t bp;
587
588      for(m = mp; m != NULL; m = m->m_next) {
589           bp = mtod(m, caddr_t);
590           /*
591            | the pdu is word (4 octed) aligned
592            | so len <= packet
593            */
594           memcpy(dp, bp, MIN(len, m->m_len));
595           dp += m->m_len;
596           len -= m->m_len;
597           if(len <= 0)
598                break;
599      }
600 }