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