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