2 * Copyright (c) 2005-2011 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
30 | $Id: iscsivar.h 743 2009-08-08 10:54:53Z danny $
32 #define ISCSI_MAX_LUNS 128 // don't touch this
33 #if ISCSI_MAX_LUNS > 8
36 | sysctl kern.cam.cam_srch_hi=1
40 #ifndef ISCSI_INITIATOR_DEBUG
41 #define ISCSI_INITIATOR_DEBUG 1
44 #ifdef ISCSI_INITIATOR_DEBUG
45 extern int iscsi_debug;
46 #define debug(level, fmt, args...) do {if(level <= iscsi_debug)\
47 printf("%s: " fmt "\n", __func__ , ##args);} while(0)
48 #define sdebug(level, fmt, args...) do {if(level <= iscsi_debug)\
49 printf("%d] %s: " fmt "\n", sp->sid, __func__ , ##args);} while(0)
50 #define debug_called(level) do {if(level <= iscsi_debug)\
51 printf("%s: called\n", __func__);} while(0)
53 #define debug(level, fmt, args...)
54 #define debug_called(level)
55 #define sdebug(level, fmt, args...)
56 #endif /* ISCSI_INITIATOR_DEBUG */
58 #define xdebug(fmt, args...) printf(">>> %s: " fmt "\n", __func__ , ##args)
60 #define MAX_SESSIONS ISCSI_MAX_TARGETS
61 #define MAX_PDUS (MAX_SESSIONS*256) // XXX: at the moment this is arbitrary
63 typedef uint32_t digest_t(const void *, int len, uint32_t ocrc);
65 MALLOC_DECLARE(M_ISCSI);
66 MALLOC_DECLARE(M_ISCSIBUF);
67 MALLOC_DECLARE(M_PDU);
69 #define ISOK2DIG(dig, pp) ((dig != NULL) && ((pp->ipdu.bhs.opcode & 0x1f) != ISCSI_LOGIN_CMD))
72 #define BIT(n) (1 <<(n))
75 #define ISC_SM_RUN BIT(0)
76 #define ISC_SM_RUNNING BIT(1)
78 #define ISC_LINK_UP BIT(2)
79 #define ISC_CON_RUN BIT(3)
80 #define ISC_CON_RUNNING BIT(4)
81 #define ISC_KILL BIT(5)
82 #define ISC_OQNOTEMPTY BIT(6)
83 #define ISC_OWAITING BIT(7)
84 #define ISC_FFPHASE BIT(8)
86 #define ISC_CAMDEVS BIT(9)
87 #define ISC_SCANWAIT BIT(10)
89 #define ISC_MEMWAIT BIT(11)
90 #define ISC_SIGNALED BIT(12)
92 #define ISC_HOLD BIT(15)
93 #define ISC_HOLDED BIT(16)
95 #define ISC_SHUTDOWN BIT(31)
101 int npdu; // number of pdus malloc'ed.
102 int nrecv; // unprocessed received pdus
103 int nsent; // sent pdus
112 struct bintime t_sent;
113 struct bintime t_recv;
120 typedef TAILQ_HEAD(, pduq) queue_t;
122 typedef struct isc_session {
123 TAILQ_ENTRY(isc_session) sp_link;
130 struct proc *proc; // the userland process
132 struct proc *soc_proc;
133 struct proc *stp; // the sm thread
135 struct isc_softc *isc;
137 digest_t *hdrDigest; // the digest alg. if any
138 digest_t *dataDigest; // the digest alg. if any
140 int sid; // Session ID
141 sn_t sn; // sequence number stuff;
142 int cws; // current window size
144 int target_nluns; // this and target_lun are
145 // hopefully temporal till I
146 // figure out a better way.
147 int target_lun[ISCSI_MAX_LUNS/(sizeof(int)*8) + 1];
161 isc_opt_t opt; // negotiable values
163 struct i_stats stats;
170 struct cam_sim *cam_sim;
171 struct cam_path *cam_path;
176 struct sysctl_ctx_list clist;
177 struct sysctl_oid *oid;
178 int douio; //XXX: turn on/off uio on read
181 typedef struct pduq {
182 TAILQ_ENTRY(pduq) pq_link;
185 u_int len; // the total length of the pdu
190 struct iovec iov[5]; // XXX: careful ...
199 TAILQ_HEAD(,isc_session) isc_sess;
202 char isid[6]; // Initiator Session ID (48 bits)
206 uma_zone_t pdu_zone; // pool of free pdu's
207 TAILQ_HEAD(,pduq) freepdu;
209 #ifdef ISCSI_INITIATOR_DEBUG
210 int npdu_alloc, npdu_max; // for instrumentation
212 #ifdef DO_EVENTHANDLER
218 struct sysctl_ctx_list clist;
219 struct sysctl_oid *oid;
222 #ifdef ISCSI_INITIATOR_DEBUG
223 extern struct mtx iscsi_dbg_mtx;
226 void isc_start_receiver(isc_session_t *sp);
227 void isc_stop_receiver(isc_session_t *sp);
229 int isc_sendPDU(isc_session_t *sp, pduq_t *pq);
230 int isc_qout(isc_session_t *sp, pduq_t *pq);
231 int i_prepPDU(isc_session_t *sp, pduq_t *pq);
233 int ism_fullfeature(struct cdev *dev, int flag);
235 int i_pdu_flush(isc_session_t *sc);
236 int i_setopt(isc_session_t *sp, isc_opt_t *opt);
237 void i_freeopt(isc_opt_t *opt);
239 int ic_init(isc_session_t *sp);
240 void ic_destroy(isc_session_t *sp);
241 void ic_lost_target(isc_session_t *sp, int target);
242 int ic_getCamVals(isc_session_t *sp, iscsi_cam_t *cp);
244 void ism_recv(isc_session_t *sp, pduq_t *pq);
245 int ism_start(isc_session_t *sp);
246 void ism_restart(isc_session_t *sp);
247 void ism_stop(isc_session_t *sp);
249 int scsi_encap(struct cam_sim *sim, union ccb *ccb);
250 int scsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
251 void iscsi_r2t(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
252 void iscsi_done(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
253 void iscsi_reject(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
254 void iscsi_async(isc_session_t *sp, pduq_t *pq);
255 void iscsi_cleanup(isc_session_t *sp);
256 int iscsi_requeue(isc_session_t *sp);
258 // Serial Number Arithmetic
259 #define _MAXINCR 0x7FFFFFFF // 2 ^ 31 - 1
260 #define SNA_GT(i1, i2) ((i1 != i2) && (\
261 (i1 < i2 && i2 - i1 > _MAXINCR) ||\
262 (i1 > i2 && i1 - i2 < _MAXINCR))?1: 0)
267 #ifdef _CAM_CAM_XPT_SIM_H
269 #if __FreeBSD_version < 600000
270 #define CAM_LOCK(arg)
271 #define CAM_ULOCK(arg)
274 XPT_DONE(isc_session_t *sp, union ccb *ccb)
280 #elif __FreeBSD_version >= 700000
281 #define CAM_LOCK(arg) mtx_lock(&arg->cam_mtx)
282 #define CAM_UNLOCK(arg) mtx_unlock(&arg->cam_mtx)
285 XPT_DONE(isc_session_t *sp, union ccb *ccb)
292 //__FreeBSD_version >= 600000
293 #define CAM_LOCK(arg)
294 #define CAM_UNLOCK(arg)
295 #define XPT_DONE(ignore, arg) xpt_done(arg)
298 #endif /* _CAM_CAM_XPT_SIM_H */
300 static __inline pduq_t *
301 pdu_alloc(struct isc_softc *isc, int wait)
305 pq = (pduq_t *)uma_zalloc(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/);
307 debug(7, "out of mem");
310 #ifdef ISCSI_INITIATOR_DEBUG
311 mtx_lock(&iscsi_dbg_mtx);
313 if(isc->npdu_alloc > isc->npdu_max)
314 isc->npdu_max = isc->npdu_alloc;
315 mtx_unlock(&iscsi_dbg_mtx);
317 memset(pq, 0, sizeof(pduq_t));
323 pdu_free(struct isc_softc *isc, pduq_t *pq)
329 free(pq->buf, M_ISCSIBUF);
331 uma_zfree(isc->pdu_zone, pq);
332 #ifdef ISCSI_INITIATOR_DEBUG
333 mtx_lock(&iscsi_dbg_mtx);
335 mtx_unlock(&iscsi_dbg_mtx);
340 i_nqueue_rsp(isc_session_t *sp, pduq_t *pq)
342 mtx_lock(&sp->rsp_mtx);
343 if(++sp->stats.nrsp > sp->stats.max_rsp)
344 sp->stats.max_rsp = sp->stats.nrsp;
345 TAILQ_INSERT_TAIL(&sp->rsp, pq, pq_link);
346 mtx_unlock(&sp->rsp_mtx);
349 static __inline pduq_t *
350 i_dqueue_rsp(isc_session_t *sp)
354 mtx_lock(&sp->rsp_mtx);
355 if((pq = TAILQ_FIRST(&sp->rsp)) != NULL) {
357 TAILQ_REMOVE(&sp->rsp, pq, pq_link);
359 mtx_unlock(&sp->rsp_mtx);
365 i_nqueue_rsv(isc_session_t *sp, pduq_t *pq)
367 mtx_lock(&sp->rsv_mtx);
368 if(++sp->stats.nrsv > sp->stats.max_rsv)
369 sp->stats.max_rsv = sp->stats.nrsv;
370 TAILQ_INSERT_TAIL(&sp->rsv, pq, pq_link);
371 mtx_unlock(&sp->rsv_mtx);
374 static __inline pduq_t *
375 i_dqueue_rsv(isc_session_t *sp)
379 mtx_lock(&sp->rsv_mtx);
380 if((pq = TAILQ_FIRST(&sp->rsv)) != NULL) {
382 TAILQ_REMOVE(&sp->rsv, pq, pq_link);
384 mtx_unlock(&sp->rsv_mtx);
390 i_nqueue_csnd(isc_session_t *sp, pduq_t *pq)
392 mtx_lock(&sp->snd_mtx);
393 if(++sp->stats.ncsnd > sp->stats.max_csnd)
394 sp->stats.max_csnd = sp->stats.ncsnd;
395 TAILQ_INSERT_TAIL(&sp->csnd, pq, pq_link);
396 mtx_unlock(&sp->snd_mtx);
399 static __inline pduq_t *
400 i_dqueue_csnd(isc_session_t *sp)
404 mtx_lock(&sp->snd_mtx);
405 if((pq = TAILQ_FIRST(&sp->csnd)) != NULL) {
407 TAILQ_REMOVE(&sp->csnd, pq, pq_link);
409 mtx_unlock(&sp->snd_mtx);
415 i_nqueue_isnd(isc_session_t *sp, pduq_t *pq)
417 mtx_lock(&sp->snd_mtx);
418 if(++sp->stats.nisnd > sp->stats.max_isnd)
419 sp->stats.max_isnd = sp->stats.nisnd;
420 TAILQ_INSERT_TAIL(&sp->isnd, pq, pq_link);
421 mtx_unlock(&sp->snd_mtx);
424 static __inline pduq_t *
425 i_dqueue_isnd(isc_session_t *sp)
429 mtx_lock(&sp->snd_mtx);
430 if((pq = TAILQ_FIRST(&sp->isnd)) != NULL) {
432 TAILQ_REMOVE(&sp->isnd, pq, pq_link);
434 mtx_unlock(&sp->snd_mtx);
440 i_nqueue_wsnd(isc_session_t *sp, pduq_t *pq)
442 mtx_lock(&sp->snd_mtx);
443 if(++sp->stats.nwsnd > sp->stats.max_wsnd)
444 sp->stats.max_wsnd = sp->stats.nwsnd;
445 TAILQ_INSERT_TAIL(&sp->wsnd, pq, pq_link);
446 mtx_unlock(&sp->snd_mtx);
449 static __inline pduq_t *
450 i_dqueue_wsnd(isc_session_t *sp)
454 mtx_lock(&sp->snd_mtx);
455 if((pq = TAILQ_FIRST(&sp->wsnd)) != NULL) {
457 TAILQ_REMOVE(&sp->wsnd, pq, pq_link);
459 mtx_unlock(&sp->snd_mtx);
464 static __inline pduq_t *
465 i_dqueue_snd(isc_session_t *sp, int which)
470 mtx_lock(&sp->snd_mtx);
471 if((which & BIT(0)) && (pq = TAILQ_FIRST(&sp->isnd)) != NULL) {
473 TAILQ_REMOVE(&sp->isnd, pq, pq_link);
474 pq->pduq = &sp->isnd; // remember where you came from
476 if((which & BIT(1)) && (pq = TAILQ_FIRST(&sp->wsnd)) != NULL) {
478 TAILQ_REMOVE(&sp->wsnd, pq, pq_link);
479 pq->pduq = &sp->wsnd; // remember where you came from
481 if((which & BIT(2)) && (pq = TAILQ_FIRST(&sp->csnd)) != NULL) {
483 TAILQ_REMOVE(&sp->csnd, pq, pq_link);
484 pq->pduq = &sp->csnd; // remember where you came from
486 mtx_unlock(&sp->snd_mtx);
492 i_rqueue_pdu(isc_session_t *sp, pduq_t *pq)
494 mtx_lock(&sp->snd_mtx);
495 KASSERT(pq->pduq != NULL, ("pq->pduq is NULL"));
496 TAILQ_INSERT_TAIL(pq->pduq, pq, pq_link);
497 mtx_unlock(&sp->snd_mtx);
501 | Waiting for ACK (or something :-)
504 i_nqueue_hld(isc_session_t *sp, pduq_t *pq)
507 mtx_lock(&sp->hld_mtx);
508 if(++sp->stats.nhld > sp->stats.max_hld)
509 sp->stats.max_hld = sp->stats.nhld;
510 TAILQ_INSERT_TAIL(&sp->hld, pq, pq_link);
511 mtx_unlock(&sp->hld_mtx);
516 i_remove_hld(isc_session_t *sp, pduq_t *pq)
518 mtx_lock(&sp->hld_mtx);
520 TAILQ_REMOVE(&sp->hld, pq, pq_link);
521 mtx_unlock(&sp->hld_mtx);
524 static __inline pduq_t *
525 i_dqueue_hld(isc_session_t *sp)
529 mtx_lock(&sp->hld_mtx);
530 if((pq = TAILQ_FIRST(&sp->hld)) != NULL) {
532 TAILQ_REMOVE(&sp->hld, pq, pq_link);
534 mtx_unlock(&sp->hld_mtx);
539 static __inline pduq_t *
540 i_search_hld(isc_session_t *sp, int itt, int keep)
546 mtx_lock(&sp->hld_mtx);
547 TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, tmp) {
548 if(pq->pdu.ipdu.bhs.itt == itt) {
551 TAILQ_REMOVE(&sp->hld, pq, pq_link);
556 mtx_unlock(&sp->hld_mtx);
562 i_acked_hld(isc_session_t *sp, pdu_t *op)
565 u_int exp = sp->sn.expCmd;
568 mtx_lock(&sp->hld_mtx);
569 TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, tmp) {
570 if((op && op->ipdu.bhs.itt == pq->pdu.ipdu.bhs.itt)
572 && (pq->pdu.ipdu.bhs.opcode != ISCSI_WRITE_DATA)
573 && SNA_GT(exp, ntohl(pq->pdu.ipdu.bhs.ExpStSN)))) {
575 TAILQ_REMOVE(&sp->hld, pq, pq_link);
576 pdu_free(sp->isc, pq);
579 mtx_unlock(&sp->hld_mtx);
583 i_mbufcopy(struct mbuf *mp, caddr_t dp, int len)
588 for(m = mp; m != NULL; m = m->m_next) {
589 bp = mtod(m, caddr_t);
591 | the pdu is word (4 octed) aligned
594 memcpy(dp, bp, MIN(len, m->m_len));