2 * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $FreeBSD: src/sys/dev/iscsi/initiator/iscsivar.h,v 1.2 2008/11/25 07:17:11 scottl Exp $
29 | $Id: iscsivar.h,v 1.30 2007/04/22 10:12:11 danny Exp danny $
31 #ifndef ISCSI_INITIATOR_DEBUG
32 #define ISCSI_INITIATOR_DEBUG 1
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)
44 #define debug(level, fmt, args...)
45 #define debug_called(level)
46 #define sdebug(level, fmt, args...)
47 #endif /* ISCSI_INITIATOR_DEBUG */
49 #define xdebug(fmt, args...) kprintf(">>> %s: " fmt "\n", __func__ , ##args)
52 #define PROC_UNLOCK(p)
54 #define MAX_SESSIONS 256
56 typedef uint32_t digest_t(const void *, int len, uint32_t ocrc);
58 typedef struct objcache *objcache_t;
60 MALLOC_DECLARE(M_ISCSI);
61 MALLOC_DECLARE(M_PDU);
64 #define BIT(n) (1 <<(n))
67 #define ISC_SM_RUN BIT(0)
68 #define ISC_SM_RUNNING BIT(1)
70 #define ISC_LINK_UP BIT(2)
71 #define ISC_CON_RUN BIT(3)
72 #define ISC_CON_RUNNING BIT(4)
73 #define ISC_KILL BIT(5)
74 #define ISC_OQNOTEMPTY BIT(6)
75 #define ISC_OWAITING BIT(7)
76 #define ISC_FFPHASE BIT(8)
77 #define ISC_FFPWAIT BIT(9)
79 #define ISC_MEMWAIT BIT(10)
80 #define ISC_SIGNALED BIT(11)
81 #define ISC_FROZEN BIT(12)
82 #define ISC_STALLED BIT(13)
84 #define ISC_HOLD BIT(14)
85 #define ISC_HOLDED BIT(15)
87 #define ISC_SHUTDOWN BIT(31)
93 int npdu; // number of pdus malloc'ed.
94 int nrecv; // unprocessed received pdus
95 int nsent; // sent pdus
104 struct timeval t_sent;
105 struct timeval t_recv;
112 typedef TAILQ_HEAD(, pduq) queue_t;
114 typedef struct isc_session {
115 TAILQ_ENTRY(isc_session) sp_link;
122 struct proc *proc; // the userland process
125 struct thread *soc_thr;
127 struct thread *stp; // the sm thread
129 struct isc_softc *isc;
131 digest_t *hdrDigest; // the digest alg. if any
132 digest_t *dataDigest; // the digest alg. if any
134 int sid; // Session ID
136 // int cid; // Connection ID
137 // int tsih; // target session identifier handle
138 sn_t sn; // sequence number stuff;
139 int cws; // current window size
141 int target_nluns; // this and target_lun are
142 // hopefully temporal till I
143 // figure out a better way.
144 lun_id_t target_lun[ISCSI_MAX_LUNS];
163 struct i_stats stats;
164 struct cam_path *cam_path;
171 struct sysctl_ctx_list clist;
172 struct sysctl_oid *oid;
173 int douio; //XXX: turn on/off uio on read
176 typedef struct pduq {
177 TAILQ_ENTRY(pduq) pq_link;
180 u_int len; // the total length of the pdu
185 struct iovec iov[5]; // XXX: careful ...
196 char isid[6]; // Initiator Session ID (48 bits)
200 TAILQ_HEAD(,isc_session) isc_sess;
201 isc_session_t *sessions[MAX_SESSIONS];
203 struct lock pdu_lock;
204 #ifdef ISCSI_INITIATOR_DEBUG
205 int npdu_alloc, npdu_max; // for instrumentation
207 #define MAX_PDUS (MAX_SESSIONS*256) // XXX: at the moment this is arbitrary
208 objcache_t pdu_zone; // pool of free pdu's
209 TAILQ_HEAD(,pduq) freepdu;
213 struct cam_sim *cam_sim;
214 struct cam_path *cam_path;
215 struct lock cam_lock;
219 struct sysctl_ctx_list clist;
220 struct sysctl_oid *oid;
223 #ifdef ISCSI_INITIATOR_DEBUG
224 extern struct lock iscsi_dbg_lock;
227 void isc_start_receiver(isc_session_t *sp);
228 void isc_stop_receiver(isc_session_t *sp);
230 int isc_sendPDU(isc_session_t *sp, pduq_t *pq);
231 int isc_qout(isc_session_t *sp, pduq_t *pq);
232 int i_prepPDU(isc_session_t *sp, pduq_t *pq);
234 int ism_fullfeature(struct cdev *dev, int flag);
236 int i_pdu_flush(isc_session_t *sc);
237 int i_setopt(isc_session_t *sp, isc_opt_t *opt);
238 void i_freeopt(isc_opt_t *opt);
240 int ic_init(struct isc_softc *sc);
241 void ic_destroy(struct isc_softc *sc);
242 int ic_fullfeature(struct cdev *dev);
243 void ic_lost_target(isc_session_t *sp, int target);
244 int ic_getCamVals(isc_session_t *sp, iscsi_cam_t *cp);
246 void ism_recv(isc_session_t *sp, pduq_t *pq);
247 int ism_start(isc_session_t *sp);
248 void ism_stop(isc_session_t *sp);
250 int scsi_encap(struct cam_sim *sim, union ccb *ccb);
251 int scsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
252 void iscsi_r2t(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
253 void iscsi_done(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
254 void iscsi_reject(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
255 void iscsi_async(isc_session_t *sp, pduq_t *pq);
256 void iscsi_cleanup(isc_session_t *sp);
257 int iscsi_requeue(isc_session_t *sp);
259 void ic_freeze(isc_session_t *sp);
260 void ic_release(isc_session_t *sp);
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)
271 * DragonFly note: CAM locks itself, peripherals do not lock CAM.
273 #ifdef _CAM_CAM_XPT_SIM_H
275 #define CAM_LOCK(arg) /*lockmgr(&arg->cam_lock, LK_EXCLUSIVE)*/
276 #define CAM_UNLOCK(arg) /*lockmgr(&arg->cam_lock, LK_RELEASE)*/
279 XPT_DONE(struct isc_softc *isp, union ccb *ccb)
286 #endif /* _CAM_CAM_XPT_SIM_H */
288 #define iscsi_lock_ex(mtx) mtx_lock_ex_quick(mtx, __func__)
289 #define iscsi_unlock_ex(mtx) mtx_unlock(mtx)
290 #define issleep(id, mtx, flags, wmesg, to) \
291 mtxsleep(id, mtx, flags, wmesg, to)
293 static __inline pduq_t *
294 pdu_alloc(struct isc_softc *isc, int wait)
298 lockmgr(&isc->pdu_lock, LK_EXCLUSIVE);
299 if((pq = TAILQ_FIRST(&isc->freepdu)) == NULL) {
300 lockmgr(&isc->pdu_lock, LK_RELEASE);
301 pq = objcache_get(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/);
304 TAILQ_REMOVE(&isc->freepdu, pq, pq_link);
305 lockmgr(&isc->pdu_lock, LK_RELEASE);
309 debug(7, "out of mem");
312 #ifdef ISCSI_INITIATOR_DEBUG
313 lockmgr(&isc->pdu_lock, LK_EXCLUSIVE);
315 if(isc->npdu_alloc > isc->npdu_max)
316 isc->npdu_max = isc->npdu_alloc;
317 lockmgr(&isc->pdu_lock, LK_RELEASE);
319 memset(pq, 0, sizeof(pduq_t));
325 pdu_free(struct isc_softc *isc, pduq_t *pq)
331 kfree(pq->buf, M_ISCSI);
333 lockmgr(&isc->pdu_lock, LK_EXCLUSIVE);
334 TAILQ_INSERT_TAIL(&isc->freepdu, pq, pq_link);
335 #ifdef ISCSI_INITIATOR_DEBUG
338 lockmgr(&isc->pdu_lock, LK_RELEASE);
342 i_nqueue_rsp(isc_session_t *sp, pduq_t *pq)
344 iscsi_lock_ex(&sp->rsp_mtx);
345 if(++sp->stats.nrsp > sp->stats.max_rsp)
346 sp->stats.max_rsp = sp->stats.nrsp;
347 TAILQ_INSERT_TAIL(&sp->rsp, pq, pq_link);
348 iscsi_unlock_ex(&sp->rsp_mtx);
351 static __inline pduq_t *
352 i_dqueue_rsp(isc_session_t *sp)
356 iscsi_lock_ex(&sp->rsp_mtx);
357 if((pq = TAILQ_FIRST(&sp->rsp)) != NULL) {
359 TAILQ_REMOVE(&sp->rsp, pq, pq_link);
361 iscsi_unlock_ex(&sp->rsp_mtx);
367 i_nqueue_rsv(isc_session_t *sp, pduq_t *pq)
369 iscsi_lock_ex(&sp->rsv_mtx);
370 if(++sp->stats.nrsv > sp->stats.max_rsv)
371 sp->stats.max_rsv = sp->stats.nrsv;
372 TAILQ_INSERT_TAIL(&sp->rsv, pq, pq_link);
373 iscsi_unlock_ex(&sp->rsv_mtx);
376 static __inline pduq_t *
377 i_dqueue_rsv(isc_session_t *sp)
381 iscsi_lock_ex(&sp->rsv_mtx);
382 if((pq = TAILQ_FIRST(&sp->rsv)) != NULL) {
384 TAILQ_REMOVE(&sp->rsv, pq, pq_link);
386 iscsi_unlock_ex(&sp->rsv_mtx);
392 i_nqueue_csnd(isc_session_t *sp, pduq_t *pq)
394 iscsi_lock_ex(&sp->snd_mtx);
395 if(++sp->stats.ncsnd > sp->stats.max_csnd)
396 sp->stats.max_csnd = sp->stats.ncsnd;
397 TAILQ_INSERT_TAIL(&sp->csnd, pq, pq_link);
398 iscsi_unlock_ex(&sp->snd_mtx);
401 static __inline pduq_t *
402 i_dqueue_csnd(isc_session_t *sp)
406 iscsi_lock_ex(&sp->snd_mtx);
407 if((pq = TAILQ_FIRST(&sp->csnd)) != NULL) {
409 TAILQ_REMOVE(&sp->csnd, pq, pq_link);
411 iscsi_unlock_ex(&sp->snd_mtx);
417 i_nqueue_isnd(isc_session_t *sp, pduq_t *pq)
419 iscsi_lock_ex(&sp->snd_mtx);
420 if(++sp->stats.nisnd > sp->stats.max_isnd)
421 sp->stats.max_isnd = sp->stats.nisnd;
422 TAILQ_INSERT_TAIL(&sp->isnd, pq, pq_link);
423 iscsi_unlock_ex(&sp->snd_mtx);
426 static __inline pduq_t *
427 i_dqueue_isnd(isc_session_t *sp)
431 iscsi_lock_ex(&sp->snd_mtx);
432 if((pq = TAILQ_FIRST(&sp->isnd)) != NULL) {
434 TAILQ_REMOVE(&sp->isnd, pq, pq_link);
436 iscsi_unlock_ex(&sp->snd_mtx);
442 i_nqueue_wsnd(isc_session_t *sp, pduq_t *pq)
444 iscsi_lock_ex(&sp->snd_mtx);
445 if(++sp->stats.nwsnd > sp->stats.max_wsnd)
446 sp->stats.max_wsnd = sp->stats.nwsnd;
447 TAILQ_INSERT_TAIL(&sp->wsnd, pq, pq_link);
448 iscsi_unlock_ex(&sp->snd_mtx);
451 static __inline pduq_t *
452 i_dqueue_wsnd(isc_session_t *sp)
456 iscsi_lock_ex(&sp->snd_mtx);
457 if((pq = TAILQ_FIRST(&sp->wsnd)) != NULL) {
459 TAILQ_REMOVE(&sp->wsnd, pq, pq_link);
461 iscsi_unlock_ex(&sp->snd_mtx);
466 static __inline pduq_t *
467 i_dqueue_snd(isc_session_t *sp, int which)
472 iscsi_lock_ex(&sp->snd_mtx);
473 if((which & BIT(0)) && (pq = TAILQ_FIRST(&sp->isnd)) != NULL) {
475 TAILQ_REMOVE(&sp->isnd, pq, pq_link);
476 pq->pduq = &sp->isnd; // remember where you came from
478 if((which & BIT(1)) && (pq = TAILQ_FIRST(&sp->wsnd)) != NULL) {
480 TAILQ_REMOVE(&sp->wsnd, pq, pq_link);
481 pq->pduq = &sp->wsnd; // remember where you came from
483 if((which & BIT(2)) && (pq = TAILQ_FIRST(&sp->csnd)) != NULL) {
485 TAILQ_REMOVE(&sp->csnd, pq, pq_link);
486 pq->pduq = &sp->csnd; // remember where you came from
488 iscsi_unlock_ex(&sp->snd_mtx);
494 i_rqueue_pdu(isc_session_t *sp, pduq_t *pq)
496 iscsi_lock_ex(&sp->snd_mtx);
497 KASSERT(pq->pduq != NULL, ("pq->pduq is NULL"));
498 TAILQ_INSERT_TAIL(pq->pduq, pq, pq_link);
499 iscsi_unlock_ex(&sp->snd_mtx);
503 | Waiting for ACK (or something :-)
506 i_nqueue_hld(isc_session_t *sp, pduq_t *pq)
508 getmicrouptime(&pq->ts);
509 iscsi_lock_ex(&sp->hld_mtx);
510 if(++sp->stats.nhld > sp->stats.max_hld)
511 sp->stats.max_hld = sp->stats.nhld;
512 TAILQ_INSERT_TAIL(&sp->hld, pq, pq_link);
513 iscsi_unlock_ex(&sp->hld_mtx);
518 i_remove_hld(isc_session_t *sp, pduq_t *pq)
520 iscsi_lock_ex(&sp->hld_mtx);
522 TAILQ_REMOVE(&sp->hld, pq, pq_link);
523 iscsi_unlock_ex(&sp->hld_mtx);
526 static __inline pduq_t *
527 i_dqueue_hld(isc_session_t *sp)
531 iscsi_lock_ex(&sp->hld_mtx);
532 if((pq = TAILQ_FIRST(&sp->hld)) != NULL) {
534 TAILQ_REMOVE(&sp->hld, pq, pq_link);
536 iscsi_unlock_ex(&sp->hld_mtx);
541 static __inline pduq_t *
542 i_search_hld(isc_session_t *sp, int itt, int keep)
548 iscsi_lock_ex(&sp->hld_mtx);
549 TAILQ_FOREACH_MUTABLE(pq, &sp->hld, pq_link, tmp) {
550 if(pq->pdu.ipdu.bhs.itt == itt) {
553 TAILQ_REMOVE(&sp->hld, pq, pq_link);
558 iscsi_unlock_ex(&sp->hld_mtx);
564 i_mbufcopy(struct mbuf *mp, caddr_t dp, int len)
569 for(m = mp; m != NULL; m = m->m_next) {
570 bp = mtod(m, caddr_t);
572 | the pdu is word (4 octed) aligned
575 memcpy(dp, bp, MIN(len, m->m_len));