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
XPT_DONE(struct isc_softc * isp,union ccb * ccb)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 *
pdu_alloc(struct isc_softc * isc,int wait)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
pdu_free(struct isc_softc * isc,pduq_t * pq)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
i_nqueue_rsp(isc_session_t * sp,pduq_t * pq)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 *
i_dqueue_rsp(isc_session_t * sp)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
i_nqueue_rsv(isc_session_t * sp,pduq_t * pq)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 *
i_dqueue_rsv(isc_session_t * sp)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
i_nqueue_csnd(isc_session_t * sp,pduq_t * pq)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 *
i_dqueue_csnd(isc_session_t * sp)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
i_nqueue_isnd(isc_session_t * sp,pduq_t * pq)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 *
i_dqueue_isnd(isc_session_t * sp)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
i_nqueue_wsnd(isc_session_t * sp,pduq_t * pq)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 *
i_dqueue_wsnd(isc_session_t * sp)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 *
i_dqueue_snd(isc_session_t * sp,int which)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
i_rqueue_pdu(isc_session_t * sp,pduq_t * pq)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
i_nqueue_hld(isc_session_t * sp,pduq_t * pq)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
i_remove_hld(isc_session_t * sp,pduq_t * pq)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 *
i_dqueue_hld(isc_session_t * sp)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 *
i_search_hld(isc_session_t * sp,int itt,int keep)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
i_mbufcopy(struct mbuf * mp,caddr_t dp,int len)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