1171568Sscottl/*-
2234233Sjpaetzel * Copyright (c) 2005-2011 Daniel Braniss <danny@cs.huji.ac.il>
3171568Sscottl * All rights reserved.
4171568Sscottl *
5171568Sscottl * Redistribution and use in source and binary forms, with or without
6171568Sscottl * modification, are permitted provided that the following conditions
7171568Sscottl * are met:
8171568Sscottl * 1. Redistributions of source code must retain the above copyright
9171568Sscottl *    notice, this list of conditions and the following disclaimer.
10171568Sscottl * 2. Redistributions in binary form must reproduce the above copyright
11171568Sscottl *    notice, this list of conditions and the following disclaimer in the
12171568Sscottl *    documentation and/or other materials provided with the distribution.
13171568Sscottl *
14171568Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15171568Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16171568Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17171568Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18171568Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19171568Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20171568Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21171568Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22171568Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23171568Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24171568Sscottl * SUCH DAMAGE.
25171568Sscottl *
26171568Sscottl * $FreeBSD$
27171568Sscottl */
28211095Sdes
29171568Sscottl/*
30211095Sdes | $Id: iscsivar.h 743 2009-08-08 10:54:53Z danny $
31171568Sscottl */
32211095Sdes#define ISCSI_MAX_LUNS		128	// don't touch this
33211095Sdes#if ISCSI_MAX_LUNS > 8
34211095Sdes/*
35211095Sdes | for this to work
36211095Sdes | sysctl kern.cam.cam_srch_hi=1
37211095Sdes */
38211095Sdes#endif
39211095Sdes
40171568Sscottl#ifndef ISCSI_INITIATOR_DEBUG
41171568Sscottl#define ISCSI_INITIATOR_DEBUG 1
42171568Sscottl#endif
43171568Sscottl
44171568Sscottl#ifdef ISCSI_INITIATOR_DEBUG
45171568Sscottlextern int iscsi_debug;
46171568Sscottl#define debug(level, fmt, args...)	do {if(level <= iscsi_debug)\
47171568Sscottl	printf("%s: " fmt "\n", __func__ , ##args);} while(0)
48171568Sscottl#define sdebug(level, fmt, args...)	do {if(level <= iscsi_debug)\
49171568Sscottl     	printf("%d] %s: " fmt "\n", sp->sid, __func__ , ##args);} while(0)
50171568Sscottl#define debug_called(level)		do {if(level <= iscsi_debug)\
51171568Sscottl	printf("%s: called\n",  __func__);} while(0)
52171568Sscottl#else
53171568Sscottl#define debug(level, fmt, args...)
54171568Sscottl#define debug_called(level)
55171568Sscottl#define sdebug(level, fmt, args...)
56171568Sscottl#endif /* ISCSI_INITIATOR_DEBUG */
57171568Sscottl
58185289Sscottl#define xdebug(fmt, args...)	printf(">>> %s: " fmt "\n", __func__ , ##args)
59171568Sscottl
60211095Sdes#define MAX_SESSIONS	ISCSI_MAX_TARGETS
61211095Sdes#define MAX_PDUS	(MAX_SESSIONS*256) // XXX: at the moment this is arbitrary
62171568Sscottl
63171568Sscottltypedef uint32_t digest_t(const void *, int len, uint32_t ocrc);
64171568Sscottl
65171568SscottlMALLOC_DECLARE(M_ISCSI);
66211095SdesMALLOC_DECLARE(M_ISCSIBUF);
67171568Sscottl
68211095Sdes#define ISOK2DIG(dig, pp)	((dig != NULL) && ((pp->ipdu.bhs.opcode & 0x1f) != ISCSI_LOGIN_CMD))
69211095Sdes
70171568Sscottl#ifndef BIT
71171568Sscottl#define BIT(n)	(1 <<(n))
72171568Sscottl#endif
73171568Sscottl
74171568Sscottl#define ISC_SM_RUN	BIT(0)
75171568Sscottl#define ISC_SM_RUNNING	BIT(1)
76171568Sscottl
77185289Sscottl#define ISC_LINK_UP	BIT(2)
78171568Sscottl#define ISC_CON_RUN	BIT(3)
79171568Sscottl#define ISC_CON_RUNNING	BIT(4)
80171568Sscottl#define ISC_KILL	BIT(5)
81185289Sscottl#define ISC_OQNOTEMPTY	BIT(6)
82185289Sscottl#define ISC_OWAITING	BIT(7)
83171568Sscottl#define ISC_FFPHASE	BIT(8)
84171568Sscottl
85211095Sdes#define ISC_CAMDEVS	BIT(9)
86211095Sdes#define ISC_SCANWAIT	BIT(10)
87171568Sscottl
88211095Sdes#define ISC_MEMWAIT	BIT(11)
89211095Sdes#define ISC_SIGNALED	BIT(12)
90185289Sscottl
91211095Sdes#define ISC_HOLD	BIT(15)
92211095Sdes#define ISC_HOLDED	BIT(16)
93211095Sdes
94171568Sscottl#define ISC_SHUTDOWN	BIT(31)
95171568Sscottl
96171568Sscottl/*
97171568Sscottl | some stats
98171568Sscottl */
99171568Sscottlstruct i_stats {
100171568Sscottl     int	npdu;	// number of pdus malloc'ed.
101171568Sscottl     int	nrecv;	// unprocessed received pdus
102171568Sscottl     int	nsent;	// sent pdus
103171568Sscottl
104171568Sscottl     int	nrsp, max_rsp;
105171568Sscottl     int	nrsv, max_rsv;
106171568Sscottl     int	ncsnd, max_csnd;
107171568Sscottl     int	nisnd, max_isnd;
108171568Sscottl     int	nwsnd, max_wsnd;
109171568Sscottl     int	nhld, max_hld;
110171568Sscottl
111171568Sscottl     struct bintime t_sent;
112171568Sscottl     struct bintime t_recv;
113171568Sscottl};
114171568Sscottl
115171568Sscottl/*
116171568Sscottl | one per 'session'
117171568Sscottl */
118185289Sscottl
119185289Sscottltypedef TAILQ_HEAD(, pduq) queue_t;
120185289Sscottl
121171568Sscottltypedef struct isc_session {
122171568Sscottl     TAILQ_ENTRY(isc_session)	sp_link;
123171568Sscottl     int		flags;
124171568Sscottl     struct cdev	*dev;
125171568Sscottl     struct socket	*soc;
126171568Sscottl     struct file	*fp;
127171568Sscottl     struct thread	*td;
128171568Sscottl
129171568Sscottl     struct proc 	*proc; // the userland process
130171568Sscottl     int		signal;
131171568Sscottl     struct proc 	*soc_proc;
132171568Sscottl     struct proc	*stp;	// the sm thread
133171568Sscottl
134171568Sscottl     struct isc_softc	*isc;
135171568Sscottl
136171568Sscottl     digest_t   	*hdrDigest;     // the digest alg. if any
137171568Sscottl     digest_t   	*dataDigest;    // the digest alg. if any
138171568Sscottl
139171568Sscottl     int		sid;		// Session ID
140171568Sscottl     sn_t       	sn;             // sequence number stuff;
141171568Sscottl     int		cws;		// current window size
142171568Sscottl
143171568Sscottl     int		target_nluns; // this and target_lun are
144171568Sscottl				      // hopefully temporal till I
145171568Sscottl				      // figure out a better way.
146211095Sdes     int		target_lun[ISCSI_MAX_LUNS/(sizeof(int)*8) + 1];
147171568Sscottl
148171568Sscottl     struct mtx		rsp_mtx;
149171568Sscottl     struct mtx		rsv_mtx;
150171568Sscottl     struct mtx		snd_mtx;
151171568Sscottl     struct mtx		hld_mtx;
152171568Sscottl     struct mtx		io_mtx;
153185289Sscottl     queue_t		rsp;
154185289Sscottl     queue_t		rsv;
155185289Sscottl     queue_t		csnd;
156185289Sscottl     queue_t		isnd;
157185289Sscottl     queue_t		wsnd;
158185289Sscottl     queue_t		hld;
159171568Sscottl
160211095Sdes     isc_opt_t		opt;	// negotiable values
161171568Sscottl
162171568Sscottl     struct i_stats	stats;
163171568Sscottl     bhs_t		bhs;
164171568Sscottl     struct uio		uio;
165171568Sscottl     struct iovec	iov;
166171568Sscottl     /*
167211095Sdes      | cam stuff
168211095Sdes      */
169211095Sdes     struct cam_sim	*cam_sim;
170211095Sdes     struct cam_path	*cam_path;
171211095Sdes     struct mtx		cam_mtx;
172211095Sdes     /*
173171568Sscottl      | sysctl stuff
174171568Sscottl      */
175171568Sscottl     struct sysctl_ctx_list	clist;
176171568Sscottl     struct sysctl_oid	*oid;
177185289Sscottl     int	douio;	//XXX: turn on/off uio on read
178171568Sscottl} isc_session_t;
179171568Sscottl
180171568Sscottltypedef struct pduq {
181171568Sscottl     TAILQ_ENTRY(pduq)	pq_link;
182171568Sscottl
183171568Sscottl     caddr_t		buf;
184171568Sscottl     u_int		len;	// the total length of the pdu
185171568Sscottl     pdu_t		pdu;
186171568Sscottl     union ccb		*ccb;
187171568Sscottl
188171568Sscottl     struct uio		uio;
189171568Sscottl     struct iovec	iov[5];	// XXX: careful ...
190171568Sscottl     struct mbuf	*mp;
191171568Sscottl     struct bintime	ts;
192211095Sdes     queue_t		*pduq;
193171568Sscottl} pduq_t;
194211095Sdes/*
195211095Sdes */
196171568Sscottlstruct isc_softc {
197211095Sdes     struct mtx		isc_mtx;
198211095Sdes     TAILQ_HEAD(,isc_session)	isc_sess;
199211095Sdes     int		nsess;
200171568Sscottl     struct cdev	*dev;
201171568Sscottl     char		isid[6];	// Initiator Session ID (48 bits)
202211095Sdes     struct unrhdr	*unit;
203211095Sdes     struct sx 		unit_sx;
204171568Sscottl
205211095Sdes     uma_zone_t		pdu_zone;	// pool of free pdu's
206234233Sjpaetzel     TAILQ_HEAD(,pduq)	freepdu;
207234233Sjpaetzel
208171568Sscottl#ifdef  ISCSI_INITIATOR_DEBUG
209211095Sdes     int		 npdu_alloc, npdu_max; // for instrumentation
210171568Sscottl#endif
211211095Sdes#ifdef DO_EVENTHANDLER
212211095Sdes     eventhandler_tag	eh;
213211095Sdes#endif
214171568Sscottl     /*
215171568Sscottl      | sysctl stuff
216171568Sscottl      */
217171568Sscottl     struct sysctl_ctx_list	clist;
218171568Sscottl     struct sysctl_oid		*oid;
219171568Sscottl};
220171568Sscottl
221171568Sscottl#ifdef  ISCSI_INITIATOR_DEBUG
222171568Sscottlextern struct mtx iscsi_dbg_mtx;
223171568Sscottl#endif
224171568Sscottl
225171568Sscottlvoid	isc_start_receiver(isc_session_t *sp);
226171568Sscottlvoid	isc_stop_receiver(isc_session_t *sp);
227171568Sscottl
228171568Sscottlint	isc_sendPDU(isc_session_t *sp, pduq_t *pq);
229171568Sscottlint	isc_qout(isc_session_t *sp, pduq_t *pq);
230171568Sscottlint	i_prepPDU(isc_session_t *sp, pduq_t *pq);
231171568Sscottl
232171568Sscottlint	ism_fullfeature(struct cdev *dev, int flag);
233171568Sscottl
234171568Sscottlint	i_pdu_flush(isc_session_t *sc);
235171568Sscottlint	i_setopt(isc_session_t *sp, isc_opt_t *opt);
236171568Sscottlvoid	i_freeopt(isc_opt_t *opt);
237171568Sscottl
238211095Sdesint	ic_init(isc_session_t *sp);
239211095Sdesvoid	ic_destroy(isc_session_t *sp);
240171568Sscottlvoid	ic_lost_target(isc_session_t *sp, int target);
241171568Sscottlint	ic_getCamVals(isc_session_t *sp, iscsi_cam_t *cp);
242171568Sscottl
243171568Sscottlvoid	ism_recv(isc_session_t *sp, pduq_t *pq);
244171568Sscottlint	ism_start(isc_session_t *sp);
245211095Sdesvoid	ism_restart(isc_session_t *sp);
246171568Sscottlvoid	ism_stop(isc_session_t *sp);
247171568Sscottl
248171568Sscottlint	scsi_encap(struct cam_sim *sim, union ccb *ccb);
249171568Sscottlint	scsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
250171568Sscottlvoid	iscsi_r2t(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
251171568Sscottlvoid	iscsi_done(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
252171568Sscottlvoid	iscsi_reject(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
253171568Sscottlvoid	iscsi_async(isc_session_t *sp,  pduq_t *pq);
254171568Sscottlvoid	iscsi_cleanup(isc_session_t *sp);
255171568Sscottlint	iscsi_requeue(isc_session_t *sp);
256171568Sscottl
257171568Sscottl// Serial Number Arithmetic
258171568Sscottl#define _MAXINCR	0x7FFFFFFF	// 2 ^ 31 - 1
259171568Sscottl#define SNA_GT(i1, i2)	((i1 != i2) && (\
260171568Sscottl	(i1 < i2 && i2 - i1 > _MAXINCR) ||\
261171568Sscottl	(i1 > i2 && i1 - i2 < _MAXINCR))?1: 0)
262171568Sscottl
263171568Sscottl/*
264171568Sscottl | inlines
265171568Sscottl */
266171568Sscottl#ifdef _CAM_CAM_XPT_SIM_H
267171568Sscottl
268171568Sscottl#if __FreeBSD_version <  600000
269171568Sscottl#define CAM_LOCK(arg)
270171568Sscottl#define CAM_ULOCK(arg)
271171568Sscottl
272171568Sscottlstatic __inline void
273211095SdesXPT_DONE(isc_session_t *sp, union ccb *ccb)
274171568Sscottl{
275171568Sscottl     mtx_lock(&Giant);
276171568Sscottl     xpt_done(ccb);
277171568Sscottl     mtx_unlock(&Giant);
278171568Sscottl}
279171568Sscottl#elif __FreeBSD_version >= 700000
280171568Sscottl#define CAM_LOCK(arg)	mtx_lock(&arg->cam_mtx)
281171568Sscottl#define CAM_UNLOCK(arg)	mtx_unlock(&arg->cam_mtx)
282171568Sscottl
283171568Sscottlstatic __inline void
284211095SdesXPT_DONE(isc_session_t *sp, union ccb *ccb)
285171568Sscottl{
286211095Sdes     CAM_LOCK(sp);
287171568Sscottl     xpt_done(ccb);
288211095Sdes     CAM_UNLOCK(sp);
289171568Sscottl}
290171568Sscottl#else
291171568Sscottl//__FreeBSD_version >= 600000
292171568Sscottl#define CAM_LOCK(arg)
293171568Sscottl#define CAM_UNLOCK(arg)
294171568Sscottl#define XPT_DONE(ignore, arg)	xpt_done(arg)
295171568Sscottl#endif
296171568Sscottl
297171568Sscottl#endif /* _CAM_CAM_XPT_SIM_H */
298171568Sscottl
299171568Sscottlstatic __inline pduq_t *
300171568Sscottlpdu_alloc(struct isc_softc *isc, int wait)
301171568Sscottl{
302171568Sscottl     pduq_t	*pq;
303171568Sscottl
304212149Sdes     pq = (pduq_t *)uma_zalloc(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/);
305171568Sscottl     if(pq == NULL) {
306185289Sscottl	  debug(7, "out of mem");
307171568Sscottl	  return NULL;
308171568Sscottl     }
309171568Sscottl#ifdef ISCSI_INITIATOR_DEBUG
310234233Sjpaetzel     mtx_lock(&iscsi_dbg_mtx);
311171568Sscottl     isc->npdu_alloc++;
312171568Sscottl     if(isc->npdu_alloc > isc->npdu_max)
313171568Sscottl	  isc->npdu_max = isc->npdu_alloc;
314234233Sjpaetzel     mtx_unlock(&iscsi_dbg_mtx);
315171568Sscottl#endif
316171568Sscottl     memset(pq, 0, sizeof(pduq_t));
317171568Sscottl
318171568Sscottl     return pq;
319171568Sscottl}
320171568Sscottl
321171568Sscottlstatic __inline void
322171568Sscottlpdu_free(struct isc_softc *isc, pduq_t *pq)
323171568Sscottl{
324171568Sscottl     if(pq->mp)
325171568Sscottl	  m_freem(pq->mp);
326185289Sscottl#ifdef NO_USE_MBUF
327171568Sscottl     if(pq->buf != NULL)
328211095Sdes	  free(pq->buf, M_ISCSIBUF);
329185289Sscottl#endif
330234233Sjpaetzel     uma_zfree(isc->pdu_zone, pq);
331171568Sscottl#ifdef ISCSI_INITIATOR_DEBUG
332234233Sjpaetzel     mtx_lock(&iscsi_dbg_mtx);
333171568Sscottl     isc->npdu_alloc--;
334234233Sjpaetzel     mtx_unlock(&iscsi_dbg_mtx);
335171568Sscottl#endif
336171568Sscottl}
337171568Sscottl
338171568Sscottlstatic __inline void
339171568Sscottli_nqueue_rsp(isc_session_t *sp, pduq_t *pq)
340171568Sscottl{
341171568Sscottl     mtx_lock(&sp->rsp_mtx);
342171568Sscottl     if(++sp->stats.nrsp > sp->stats.max_rsp)
343171568Sscottl	  sp->stats.max_rsp = sp->stats.nrsp;
344171568Sscottl     TAILQ_INSERT_TAIL(&sp->rsp, pq, pq_link);
345171568Sscottl     mtx_unlock(&sp->rsp_mtx);
346171568Sscottl}
347171568Sscottl
348171568Sscottlstatic __inline pduq_t *
349171568Sscottli_dqueue_rsp(isc_session_t *sp)
350171568Sscottl{
351171568Sscottl     pduq_t *pq;
352171568Sscottl
353171568Sscottl     mtx_lock(&sp->rsp_mtx);
354171568Sscottl     if((pq = TAILQ_FIRST(&sp->rsp)) != NULL) {
355171568Sscottl	  sp->stats.nrsp--;
356171568Sscottl	  TAILQ_REMOVE(&sp->rsp, pq, pq_link);
357171568Sscottl     }
358171568Sscottl     mtx_unlock(&sp->rsp_mtx);
359171568Sscottl
360171568Sscottl     return pq;
361171568Sscottl}
362171568Sscottl
363171568Sscottlstatic __inline void
364171568Sscottli_nqueue_rsv(isc_session_t *sp, pduq_t *pq)
365171568Sscottl{
366171568Sscottl     mtx_lock(&sp->rsv_mtx);
367171568Sscottl     if(++sp->stats.nrsv > sp->stats.max_rsv)
368171568Sscottl	  sp->stats.max_rsv = sp->stats.nrsv;
369171568Sscottl     TAILQ_INSERT_TAIL(&sp->rsv, pq, pq_link);
370171568Sscottl     mtx_unlock(&sp->rsv_mtx);
371171568Sscottl}
372171568Sscottl
373171568Sscottlstatic __inline pduq_t *
374171568Sscottli_dqueue_rsv(isc_session_t *sp)
375171568Sscottl{
376171568Sscottl     pduq_t *pq;
377171568Sscottl
378171568Sscottl     mtx_lock(&sp->rsv_mtx);
379171568Sscottl     if((pq = TAILQ_FIRST(&sp->rsv)) != NULL) {
380171568Sscottl	  sp->stats.nrsv--;
381171568Sscottl	  TAILQ_REMOVE(&sp->rsv, pq, pq_link);
382171568Sscottl     }
383171568Sscottl     mtx_unlock(&sp->rsv_mtx);
384171568Sscottl
385171568Sscottl     return pq;
386171568Sscottl}
387171568Sscottl
388171568Sscottlstatic __inline void
389171568Sscottli_nqueue_csnd(isc_session_t *sp, pduq_t *pq)
390171568Sscottl{
391171568Sscottl     mtx_lock(&sp->snd_mtx);
392171568Sscottl     if(++sp->stats.ncsnd > sp->stats.max_csnd)
393171568Sscottl	  sp->stats.max_csnd = sp->stats.ncsnd;
394171568Sscottl     TAILQ_INSERT_TAIL(&sp->csnd, pq, pq_link);
395171568Sscottl     mtx_unlock(&sp->snd_mtx);
396171568Sscottl}
397171568Sscottl
398171568Sscottlstatic __inline pduq_t *
399171568Sscottli_dqueue_csnd(isc_session_t *sp)
400171568Sscottl{
401171568Sscottl     pduq_t *pq;
402171568Sscottl
403171568Sscottl     mtx_lock(&sp->snd_mtx);
404171568Sscottl     if((pq = TAILQ_FIRST(&sp->csnd)) != NULL) {
405171568Sscottl	  sp->stats.ncsnd--;
406171568Sscottl	  TAILQ_REMOVE(&sp->csnd, pq, pq_link);
407171568Sscottl     }
408171568Sscottl     mtx_unlock(&sp->snd_mtx);
409171568Sscottl
410171568Sscottl     return pq;
411171568Sscottl}
412171568Sscottl
413171568Sscottlstatic __inline void
414171568Sscottli_nqueue_isnd(isc_session_t *sp, pduq_t *pq)
415171568Sscottl{
416171568Sscottl     mtx_lock(&sp->snd_mtx);
417171568Sscottl     if(++sp->stats.nisnd > sp->stats.max_isnd)
418171568Sscottl	  sp->stats.max_isnd = sp->stats.nisnd;
419171568Sscottl     TAILQ_INSERT_TAIL(&sp->isnd, pq, pq_link);
420171568Sscottl     mtx_unlock(&sp->snd_mtx);
421171568Sscottl}
422171568Sscottl
423171568Sscottlstatic __inline pduq_t *
424171568Sscottli_dqueue_isnd(isc_session_t *sp)
425171568Sscottl{
426171568Sscottl     pduq_t *pq;
427171568Sscottl
428171568Sscottl     mtx_lock(&sp->snd_mtx);
429171568Sscottl     if((pq = TAILQ_FIRST(&sp->isnd)) != NULL) {
430171568Sscottl	  sp->stats.nisnd--;
431171568Sscottl	  TAILQ_REMOVE(&sp->isnd, pq, pq_link);
432171568Sscottl     }
433171568Sscottl     mtx_unlock(&sp->snd_mtx);
434171568Sscottl
435171568Sscottl     return pq;
436171568Sscottl}
437171568Sscottl
438171568Sscottlstatic __inline void
439171568Sscottli_nqueue_wsnd(isc_session_t *sp, pduq_t *pq)
440171568Sscottl{
441171568Sscottl     mtx_lock(&sp->snd_mtx);
442171568Sscottl     if(++sp->stats.nwsnd > sp->stats.max_wsnd)
443171568Sscottl	  sp->stats.max_wsnd = sp->stats.nwsnd;
444171568Sscottl     TAILQ_INSERT_TAIL(&sp->wsnd, pq, pq_link);
445171568Sscottl     mtx_unlock(&sp->snd_mtx);
446171568Sscottl}
447171568Sscottl
448171568Sscottlstatic __inline pduq_t *
449171568Sscottli_dqueue_wsnd(isc_session_t *sp)
450171568Sscottl{
451171568Sscottl     pduq_t *pq;
452171568Sscottl
453171568Sscottl     mtx_lock(&sp->snd_mtx);
454171568Sscottl     if((pq = TAILQ_FIRST(&sp->wsnd)) != NULL) {
455171568Sscottl	  sp->stats.nwsnd--;
456171568Sscottl	  TAILQ_REMOVE(&sp->wsnd, pq, pq_link);
457171568Sscottl     }
458171568Sscottl     mtx_unlock(&sp->snd_mtx);
459171568Sscottl
460171568Sscottl     return pq;
461171568Sscottl}
462171568Sscottl
463171568Sscottlstatic __inline pduq_t *
464171568Sscottli_dqueue_snd(isc_session_t *sp, int which)
465171568Sscottl{
466171568Sscottl     pduq_t *pq;
467171568Sscottl
468171568Sscottl     pq = NULL;
469171568Sscottl     mtx_lock(&sp->snd_mtx);
470171568Sscottl     if((which & BIT(0)) && (pq = TAILQ_FIRST(&sp->isnd)) != NULL) {
471171568Sscottl	  sp->stats.nisnd--;
472171568Sscottl	  TAILQ_REMOVE(&sp->isnd, pq, pq_link);
473185289Sscottl	  pq->pduq = &sp->isnd;	// remember where you came from
474171568Sscottl     } else
475171568Sscottl     if((which & BIT(1)) && (pq = TAILQ_FIRST(&sp->wsnd)) != NULL) {
476171568Sscottl	  sp->stats.nwsnd--;
477171568Sscottl	  TAILQ_REMOVE(&sp->wsnd, pq, pq_link);
478185289Sscottl	  pq->pduq = &sp->wsnd;	// remember where you came from
479171568Sscottl     } else
480171568Sscottl     if((which & BIT(2)) && (pq = TAILQ_FIRST(&sp->csnd)) != NULL) {
481171568Sscottl	  sp->stats.ncsnd--;
482171568Sscottl	  TAILQ_REMOVE(&sp->csnd, pq, pq_link);
483185289Sscottl	  pq->pduq = &sp->csnd;	// remember where you came from
484171568Sscottl     }
485171568Sscottl     mtx_unlock(&sp->snd_mtx);
486171568Sscottl
487171568Sscottl     return pq;
488171568Sscottl}
489171568Sscottl
490185289Sscottlstatic __inline void
491185289Sscottli_rqueue_pdu(isc_session_t *sp, pduq_t *pq)
492185289Sscottl{
493185289Sscottl     mtx_lock(&sp->snd_mtx);
494185289Sscottl     KASSERT(pq->pduq != NULL, ("pq->pduq is NULL"));
495185289Sscottl     TAILQ_INSERT_TAIL(pq->pduq, pq, pq_link);
496185289Sscottl     mtx_unlock(&sp->snd_mtx);
497185289Sscottl}
498185289Sscottl
499171568Sscottl/*
500171568Sscottl | Waiting for ACK (or something :-)
501171568Sscottl */
502171568Sscottlstatic __inline void
503171568Sscottli_nqueue_hld(isc_session_t *sp, pduq_t *pq)
504171568Sscottl{
505171568Sscottl     getbintime(&pq->ts);
506171568Sscottl     mtx_lock(&sp->hld_mtx);
507171568Sscottl     if(++sp->stats.nhld > sp->stats.max_hld)
508171568Sscottl	  sp->stats.max_hld = sp->stats.nhld;
509171568Sscottl     TAILQ_INSERT_TAIL(&sp->hld, pq, pq_link);
510171568Sscottl     mtx_unlock(&sp->hld_mtx);
511171568Sscottl     return;
512171568Sscottl}
513171568Sscottl
514171568Sscottlstatic __inline void
515171568Sscottli_remove_hld(isc_session_t *sp, pduq_t *pq)
516171568Sscottl{
517171568Sscottl     mtx_lock(&sp->hld_mtx);
518171568Sscottl     sp->stats.nhld--;
519171568Sscottl     TAILQ_REMOVE(&sp->hld, pq, pq_link);
520171568Sscottl     mtx_unlock(&sp->hld_mtx);
521171568Sscottl}
522171568Sscottl
523171568Sscottlstatic __inline pduq_t *
524171568Sscottli_dqueue_hld(isc_session_t *sp)
525171568Sscottl{
526171568Sscottl     pduq_t *pq;
527171568Sscottl
528171568Sscottl     mtx_lock(&sp->hld_mtx);
529171568Sscottl     if((pq = TAILQ_FIRST(&sp->hld)) != NULL) {
530171568Sscottl	  sp->stats.nhld--;
531171568Sscottl	  TAILQ_REMOVE(&sp->hld, pq, pq_link);
532171568Sscottl     }
533171568Sscottl     mtx_unlock(&sp->hld_mtx);
534171568Sscottl
535171568Sscottl     return pq;
536171568Sscottl}
537171568Sscottl
538171568Sscottlstatic __inline pduq_t *
539171568Sscottli_search_hld(isc_session_t *sp, int itt, int keep)
540171568Sscottl{
541171568Sscottl     pduq_t	*pq, *tmp;
542171568Sscottl
543171568Sscottl     pq = NULL;
544171568Sscottl
545171568Sscottl     mtx_lock(&sp->hld_mtx);
546171568Sscottl     TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, tmp) {
547171568Sscottl	  if(pq->pdu.ipdu.bhs.itt == itt) {
548171568Sscottl	       if(!keep) {
549171568Sscottl		    sp->stats.nhld--;
550171568Sscottl		    TAILQ_REMOVE(&sp->hld, pq, pq_link);
551171568Sscottl	       }
552171568Sscottl	       break;
553171568Sscottl	  }
554171568Sscottl     }
555171568Sscottl     mtx_unlock(&sp->hld_mtx);
556171568Sscottl
557171568Sscottl     return pq;
558171568Sscottl}
559171568Sscottl
560171568Sscottlstatic __inline void
561211095Sdesi_acked_hld(isc_session_t *sp, pdu_t *op)
562211095Sdes{
563211095Sdes     pduq_t	*pq, *tmp;
564211095Sdes     u_int exp = sp->sn.expCmd;
565211095Sdes
566211095Sdes     pq = NULL;
567211095Sdes     mtx_lock(&sp->hld_mtx);
568211095Sdes     TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, tmp) {
569211095Sdes	  if((op && op->ipdu.bhs.itt == pq->pdu.ipdu.bhs.itt)
570211095Sdes	     || (pq->ccb == NULL
571211095Sdes		 && (pq->pdu.ipdu.bhs.opcode != ISCSI_WRITE_DATA)
572211095Sdes		 && SNA_GT(exp, ntohl(pq->pdu.ipdu.bhs.ExpStSN)))) {
573211095Sdes	       sp->stats.nhld--;
574211095Sdes	       TAILQ_REMOVE(&sp->hld, pq, pq_link);
575211095Sdes	       pdu_free(sp->isc, pq);
576211095Sdes	  }
577211095Sdes     }
578211095Sdes     mtx_unlock(&sp->hld_mtx);
579211095Sdes}
580211095Sdes
581211095Sdesstatic __inline void
582171568Sscottli_mbufcopy(struct mbuf *mp, caddr_t dp, int len)
583171568Sscottl{
584171568Sscottl     struct mbuf *m;
585171568Sscottl     caddr_t bp;
586171568Sscottl
587171568Sscottl     for(m = mp; m != NULL; m = m->m_next) {
588171568Sscottl	  bp = mtod(m, caddr_t);
589171568Sscottl	  /*
590171568Sscottl	   | the pdu is word (4 octed) aligned
591171568Sscottl	   | so len <= packet
592171568Sscottl	   */
593171568Sscottl	  memcpy(dp, bp, MIN(len, m->m_len));
594171568Sscottl	  dp += m->m_len;
595171568Sscottl	  len -= m->m_len;
596171568Sscottl	  if(len <= 0)
597171568Sscottl	       break;
598171568Sscottl     }
599171568Sscottl}
600