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