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 /*
30  | $Id: iscsivar.h,v 1.30 2007/04/22 10:12:11 danny Exp danny $
31  */
32 #include <sys/mutex2.h>
33 
34 #ifndef ISCSI_INITIATOR_DEBUG
35 #define ISCSI_INITIATOR_DEBUG 1
36 #endif
37 
38 #ifdef ISCSI_INITIATOR_DEBUG
39 extern int iscsi_debug;
40 #define debug(level, fmt, args...)	do {if(level <= iscsi_debug)\
41 	kprintf("%s: " fmt "\n", __func__ , ##args);} while(0)
42 #define sdebug(level, fmt, args...)	do {if(level <= iscsi_debug)\
43 	kprintf("%d] %s: " fmt "\n", sp->sid, __func__ , ##args);} while(0)
44 #define debug_called(level)		do {if(level <= iscsi_debug)\
45 	kprintf("%s: called\n",  __func__);} while(0)
46 #else
47 #define debug(level, fmt, args...)
48 #define debug_called(level)
49 #define sdebug(level, fmt, args...)
50 #endif /* ISCSI_INITIATOR_DEBUG */
51 
52 #define xdebug(fmt, args...)	kprintf(">>> %s: " fmt "\n", __func__ , ##args)
53 
54 #define PROC_LOCK(p)
55 #define PROC_UNLOCK(p)
56 
57 #define MAX_SESSIONS		256
58 
59 typedef uint32_t digest_t(const void *, int len, uint32_t ocrc);
60 
61 typedef struct objcache	*objcache_t;
62 
63 MALLOC_DECLARE(M_ISCSI);
64 
65 #ifndef BIT
66 #define BIT(n)	(1 <<(n))
67 #endif
68 
69 #define ISC_SM_RUN	BIT(0)
70 #define ISC_SM_RUNNING	BIT(1)
71 
72 #define ISC_LINK_UP	BIT(2)
73 #define ISC_CON_RUN	BIT(3)
74 #define ISC_CON_RUNNING	BIT(4)
75 #define ISC_KILL	BIT(5)
76 #define ISC_OQNOTEMPTY	BIT(6)
77 #define ISC_OWAITING	BIT(7)
78 #define ISC_FFPHASE	BIT(8)
79 #define ISC_FFPWAIT	BIT(9)
80 
81 #define ISC_MEMWAIT	BIT(10)
82 #define ISC_SIGNALED	BIT(11)
83 #define ISC_FROZEN	BIT(12)
84 #define ISC_STALLED	BIT(13)
85 
86 #define ISC_HOLD	BIT(14)
87 #define ISC_HOLDED	BIT(15)
88 
89 #define ISC_SHUTDOWN	BIT(31)
90 
91 /*
92  | some stats
93  */
94 struct i_stats {
95      int	npdu;	// number of pdus malloc'ed.
96      int	nrecv;	// unprocessed received pdus
97      int	nsent;	// sent pdus
98 
99      int	nrsp, max_rsp;
100      int	nrsv, max_rsv;
101      int	ncsnd, max_csnd;
102      int	nisnd, max_isnd;
103      int	nwsnd, max_wsnd;
104      int	nhld, max_hld;
105 
106      struct timeval t_sent;
107      struct timeval t_recv;
108 };
109 
110 /*
111  | one per 'session'
112  */
113 
114 typedef TAILQ_HEAD(, pduq) queue_t;
115 
116 typedef struct isc_session {
117      TAILQ_ENTRY(isc_session)	sp_link;
118      int		flags;
119      struct cdev	*dev;
120      struct socket	*soc;
121      struct file	*fp;
122      struct thread	*td;
123 
124      struct proc 	*proc; // the userland process
125      int		signal;
126 
127      struct thread 	*soc_thr;
128 
129      struct thread	*stp;	// the sm thread
130 
131      struct isc_softc	*isc;
132 
133      digest_t   	*hdrDigest;     // the digest alg. if any
134      digest_t   	*dataDigest;    // the digest alg. if any
135 
136      int		sid;		// Session ID
137      int		targetid;
138 //     int		cid;		// Connection ID
139 //     int		tsih;		// target session identifier handle
140      sn_t       	sn;             // sequence number stuff;
141      int		cws;		// current window size
142 
143      int		target_nluns; // this and target_lun are
144 				      // hopefully temporal till I
145 				      // figure out a better way.
146      lun_id_t		target_lun[ISCSI_MAX_LUNS];
147 
148      struct mtx		rsp_mtx;
149      struct mtx		rsv_mtx;
150      struct mtx		snd_mtx;
151      struct mtx		hld_mtx;
152      struct mtx		io_mtx;
153      queue_t		rsp;
154      queue_t		rsv;
155      queue_t		csnd;
156      queue_t		isnd;
157      queue_t		wsnd;
158      queue_t		hld;
159 
160      /*
161       | negotiable values
162       */
163      isc_opt_t		opt;
164 
165      struct i_stats	stats;
166      struct cam_path	*cam_path;
167      bhs_t		bhs;
168      struct uio		uio;
169      struct iovec	iov;
170      /*
171       | sysctl stuff
172       */
173      struct sysctl_ctx_list	clist;
174      struct sysctl_oid	*oid;
175      int	douio;	//XXX: turn on/off uio on read
176 } isc_session_t;
177 
178 typedef struct pduq {
179      TAILQ_ENTRY(pduq)	pq_link;
180 
181      caddr_t		buf;
182      u_int		len;	// the total length of the pdu
183      pdu_t		pdu;
184      union ccb		*ccb;
185 
186      struct uio		uio;
187      struct iovec	iov[5];	// XXX: careful ...
188      struct mbuf	*mp;
189      struct timeval	ts;
190      int 		refcnt;
191      queue_t		*pduq;
192 } pduq_t;
193 
194 struct isc_softc {
195      //int		state;
196      struct cdev	*dev;
197      eventhandler_tag	eh;
198      char		isid[6];	// Initiator Session ID (48 bits)
199      struct lock	lock;
200 
201      int			nsess;
202      TAILQ_HEAD(,isc_session)	isc_sess;
203      isc_session_t		*sessions[MAX_SESSIONS];
204 
205      struct lock		pdu_lock;
206 #ifdef  ISCSI_INITIATOR_DEBUG
207      int			 npdu_alloc, npdu_max; // for instrumentation
208 #endif
209 #define MAX_PDUS	(MAX_SESSIONS*256) // XXX: at the moment this is arbitrary
210      objcache_t			pdu_zone; // pool of free pdu's
211      TAILQ_HEAD(,pduq)		freepdu;
212      /*
213       | cam stuff
214       */
215      struct cam_sim		*cam_sim;
216      struct cam_path		*cam_path;
217      struct lock		cam_lock;
218      /*
219       | sysctl stuff
220       */
221      struct sysctl_ctx_list	clist;
222      struct sysctl_oid		*oid;
223 };
224 
225 #ifdef  ISCSI_INITIATOR_DEBUG
226 extern struct lock iscsi_dbg_lock;
227 #endif
228 
229 void	isc_start_receiver(isc_session_t *sp);
230 void	isc_stop_receiver(isc_session_t *sp);
231 
232 int	isc_sendPDU(isc_session_t *sp, pduq_t *pq);
233 int	isc_qout(isc_session_t *sp, pduq_t *pq);
234 int	i_prepPDU(isc_session_t *sp, pduq_t *pq);
235 
236 int	ism_fullfeature(struct cdev *dev, int flag);
237 
238 int	i_pdu_flush(isc_session_t *sc);
239 int	i_setopt(isc_session_t *sp, isc_opt_t *opt);
240 void	i_freeopt(isc_opt_t *opt);
241 
242 int	ic_init(struct isc_softc *sc);
243 void	ic_destroy(struct isc_softc *sc);
244 int	ic_fullfeature(struct cdev *dev);
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_stop(isc_session_t *sp);
251 
252 int	scsi_encap(struct cam_sim *sim, union ccb *ccb);
253 int	scsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
254 void	iscsi_r2t(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
255 void	iscsi_done(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
256 void	iscsi_reject(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
257 void	iscsi_async(isc_session_t *sp,  pduq_t *pq);
258 void	iscsi_cleanup(isc_session_t *sp);
259 int	iscsi_requeue(isc_session_t *sp);
260 
261 void	ic_freeze(isc_session_t *sp);
262 void	ic_release(isc_session_t *sp);
263 
264 // Serial Number Arithmetic
265 #define _MAXINCR	0x7FFFFFFF	// 2 ^ 31 - 1
266 #define SNA_GT(i1, i2)	((i1 != i2) && (\
267 	(i1 < i2 && i2 - i1 > _MAXINCR) ||\
268 	(i1 > i2 && i1 - i2 < _MAXINCR))?1: 0)
269 
270 /*
271  * inlines
272  *
273  * DragonFly note: CAM locks itself, peripherals do not lock CAM.
274  */
275 #ifdef _CAM_CAM_XPT_SIM_H
276 
277 #define CAM_LOCK(arg)	/*lockmgr(&arg->cam_lock, LK_EXCLUSIVE)*/
278 #define CAM_UNLOCK(arg)	/*lockmgr(&arg->cam_lock, LK_RELEASE)*/
279 
280 static __inline void
281 XPT_DONE(struct isc_softc *isp, union ccb *ccb)
282 {
283      CAM_LOCK(isp);
284      xpt_done(ccb);
285      CAM_UNLOCK(isp);
286 }
287 
288 #endif /* _CAM_CAM_XPT_SIM_H */
289 
290 #define iscsi_lock_ex(mtx)	mtx_lock_ex_quick(mtx)
291 #define iscsi_unlock_ex(mtx)	mtx_unlock(mtx)
292 #define issleep(id, mtx, flags, wmesg, to)	\
293 				mtxsleep(id, mtx, flags, wmesg, to)
294 
295 static __inline pduq_t *
296 pdu_alloc(struct isc_softc *isc, int wait)
297 {
298      pduq_t	*pq;
299 
300      lockmgr(&isc->pdu_lock, LK_EXCLUSIVE);
301      if((pq = TAILQ_FIRST(&isc->freepdu)) == NULL) {
302 	  lockmgr(&isc->pdu_lock, LK_RELEASE);
303 	  pq = objcache_get(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/);
304      }
305      else {
306 	  TAILQ_REMOVE(&isc->freepdu, pq, pq_link);
307 	  lockmgr(&isc->pdu_lock, LK_RELEASE);
308      }
309 
310      if(pq == NULL) {
311 	  debug(7, "out of mem");
312 	  return NULL;
313      }
314 #ifdef ISCSI_INITIATOR_DEBUG
315      lockmgr(&isc->pdu_lock, LK_EXCLUSIVE);
316      isc->npdu_alloc++;
317      if(isc->npdu_alloc > isc->npdu_max)
318 	  isc->npdu_max = isc->npdu_alloc;
319      lockmgr(&isc->pdu_lock, LK_RELEASE);
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 	  kfree(pq->buf, M_ISCSI);
334 #endif
335      lockmgr(&isc->pdu_lock, LK_EXCLUSIVE);
336      TAILQ_INSERT_TAIL(&isc->freepdu, pq, pq_link);
337 #ifdef ISCSI_INITIATOR_DEBUG
338      isc->npdu_alloc--;
339 #endif
340      lockmgr(&isc->pdu_lock, LK_RELEASE);
341 }
342 
343 static __inline void
344 i_nqueue_rsp(isc_session_t *sp, pduq_t *pq)
345 {
346      iscsi_lock_ex(&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      iscsi_unlock_ex(&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      iscsi_lock_ex(&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      iscsi_unlock_ex(&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      iscsi_lock_ex(&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      iscsi_unlock_ex(&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      iscsi_lock_ex(&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      iscsi_unlock_ex(&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      iscsi_lock_ex(&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      iscsi_unlock_ex(&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      iscsi_lock_ex(&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      iscsi_unlock_ex(&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      iscsi_lock_ex(&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      iscsi_unlock_ex(&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      iscsi_lock_ex(&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      iscsi_unlock_ex(&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      iscsi_lock_ex(&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      iscsi_unlock_ex(&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      iscsi_lock_ex(&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      iscsi_unlock_ex(&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      iscsi_lock_ex(&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      iscsi_unlock_ex(&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      iscsi_lock_ex(&sp->snd_mtx);
499      KASSERT(pq->pduq != NULL, ("pq->pduq is NULL"));
500      TAILQ_INSERT_TAIL(pq->pduq, pq, pq_link);
501      iscsi_unlock_ex(&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      getmicrouptime(&pq->ts);
511      iscsi_lock_ex(&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      iscsi_unlock_ex(&sp->hld_mtx);
516      return;
517 }
518 
519 static __inline void
520 i_remove_hld(isc_session_t *sp, pduq_t *pq)
521 {
522      iscsi_lock_ex(&sp->hld_mtx);
523      sp->stats.nhld--;
524      TAILQ_REMOVE(&sp->hld, pq, pq_link);
525      iscsi_unlock_ex(&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      iscsi_lock_ex(&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      iscsi_unlock_ex(&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      iscsi_lock_ex(&sp->hld_mtx);
551      TAILQ_FOREACH_MUTABLE(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      iscsi_unlock_ex(&sp->hld_mtx);
561 
562      return pq;
563 }
564 
565 static __inline void
566 i_mbufcopy(struct mbuf *mp, caddr_t dp, int len)
567 {
568      struct mbuf *m;
569      caddr_t bp;
570 
571      for(m = mp; m != NULL; m = m->m_next) {
572 	  bp = mtod(m, caddr_t);
573 	  /*
574 	   | the pdu is word (4 octed) aligned
575 	   | so len <= packet
576 	   */
577 	  memcpy(dp, bp, MIN(len, m->m_len));
578 	  dp += m->m_len;
579 	  len -= m->m_len;
580 	  if(len <= 0)
581 	       break;
582      }
583 }
584