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