1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2005-2011 Daniel Braniss <danny@cs.huji.ac.il>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD$
29 */
30
31 /*
32 | $Id: iscsivar.h 743 2009-08-08 10:54:53Z danny $
33 */
34 #define ISCSI_MAX_LUNS 128 // don't touch this
35 #if ISCSI_MAX_LUNS > 8
36 /*
37 | for this to work
38 | sysctl kern.cam.cam_srch_hi=1
39 */
40 #endif
41
42 #ifndef ISCSI_INITIATOR_DEBUG
43 #define ISCSI_INITIATOR_DEBUG 1
44 #endif
45
46 #ifdef ISCSI_INITIATOR_DEBUG
47 extern int iscsi_debug;
48 #define debug(level, fmt, args...) do {if(level <= iscsi_debug)\
49 printf("%s: " fmt "\n", __func__ , ##args);} while(0)
50 #define sdebug(level, fmt, args...) do {if(level <= iscsi_debug)\
51 printf("%d] %s: " fmt "\n", sp->sid, __func__ , ##args);} while(0)
52 #define debug_called(level) do {if(level <= iscsi_debug)\
53 printf("%s: called\n", __func__);} while(0)
54 #else
55 #define debug(level, fmt, args...)
56 #define debug_called(level)
57 #define sdebug(level, fmt, args...)
58 #endif /* ISCSI_INITIATOR_DEBUG */
59
60 #define xdebug(fmt, args...) printf(">>> %s: " fmt "\n", __func__ , ##args)
61
62 #define MAX_SESSIONS ISCSI_MAX_TARGETS
63 #define MAX_PDUS (MAX_SESSIONS*256) // XXX: at the moment this is arbitrary
64
65 typedef uint32_t digest_t(const void *, int len, uint32_t ocrc);
66
67 MALLOC_DECLARE(M_ISCSI);
68 MALLOC_DECLARE(M_ISCSIBUF);
69
70 #define ISOK2DIG(dig, pp) ((dig != NULL) && ((pp->ipdu.bhs.opcode & 0x1f) != ISCSI_LOGIN_CMD))
71
72 #ifndef BIT
73 #define BIT(n) (1 <<(n))
74 #endif
75
76 #define ISC_SM_RUN BIT(0)
77 #define ISC_SM_RUNNING BIT(1)
78
79 #define ISC_LINK_UP BIT(2)
80 #define ISC_CON_RUN BIT(3)
81 #define ISC_CON_RUNNING BIT(4)
82 #define ISC_KILL BIT(5)
83 #define ISC_OQNOTEMPTY BIT(6)
84 #define ISC_OWAITING BIT(7)
85 #define ISC_FFPHASE BIT(8)
86
87 #define ISC_CAMDEVS BIT(9)
88 #define ISC_SCANWAIT BIT(10)
89
90 #define ISC_MEMWAIT BIT(11)
91 #define ISC_SIGNALED BIT(12)
92
93 #define ISC_HOLD BIT(15)
94 #define ISC_HOLDED BIT(16)
95
96 #define ISC_SHUTDOWN BIT(31)
97
98 /*
99 | some stats
100 */
101 struct i_stats {
102 int npdu; // number of pdus malloc'ed.
103 int nrecv; // unprocessed received pdus
104 int nsent; // sent pdus
105
106 int nrsp, max_rsp;
107 int nrsv, max_rsv;
108 int ncsnd, max_csnd;
109 int nisnd, max_isnd;
110 int nwsnd, max_wsnd;
111 int nhld, max_hld;
112
113 struct bintime t_sent;
114 struct bintime t_recv;
115 };
116
117 /*
118 | one per 'session'
119 */
120
121 typedef TAILQ_HEAD(, pduq) queue_t;
122
123 typedef struct isc_session {
124 TAILQ_ENTRY(isc_session) sp_link;
125 int flags;
126 struct cdev *dev;
127 struct socket *soc;
128 struct file *fp;
129 struct thread *td;
130
131 struct proc *proc; // the userland process
132 int signal;
133 struct proc *soc_proc;
134 struct proc *stp; // the sm thread
135
136 struct isc_softc *isc;
137
138 digest_t *hdrDigest; // the digest alg. if any
139 digest_t *dataDigest; // the digest alg. if any
140
141 int sid; // Session ID
142 sn_t sn; // sequence number stuff;
143 int cws; // current window size
144
145 int target_nluns; // this and target_lun are
146 // hopefully temporal till I
147 // figure out a better way.
148 int target_lun[ISCSI_MAX_LUNS/(sizeof(int)*8) + 1];
149
150 struct mtx rsp_mtx;
151 struct mtx rsv_mtx;
152 struct mtx snd_mtx;
153 struct mtx hld_mtx;
154 struct mtx io_mtx;
155 queue_t rsp;
156 queue_t rsv;
157 queue_t csnd;
158 queue_t isnd;
159 queue_t wsnd;
160 queue_t hld;
161
162 isc_opt_t opt; // negotiable values
163
164 struct i_stats stats;
165 bhs_t bhs;
166 struct uio uio;
167 struct iovec iov;
168 /*
169 | cam stuff
170 */
171 struct cam_sim *cam_sim;
172 struct cam_path *cam_path;
173 struct mtx cam_mtx;
174 /*
175 | sysctl stuff
176 */
177 struct sysctl_ctx_list clist;
178 struct sysctl_oid *oid;
179 int douio; //XXX: turn on/off uio on read
180 } isc_session_t;
181
182 typedef struct pduq {
183 TAILQ_ENTRY(pduq) pq_link;
184
185 caddr_t buf;
186 u_int len; // the total length of the pdu
187 pdu_t pdu;
188 union ccb *ccb;
189
190 struct uio uio;
191 struct iovec iov[5]; // XXX: careful ...
192 struct mbuf *mp;
193 struct bintime ts;
194 queue_t *pduq;
195 } pduq_t;
196 /*
197 */
198 struct isc_softc {
199 struct mtx isc_mtx;
200 TAILQ_HEAD(,isc_session) isc_sess;
201 int nsess;
202 struct cdev *dev;
203 char isid[6]; // Initiator Session ID (48 bits)
204 struct unrhdr *unit;
205 struct sx unit_sx;
206
207 uma_zone_t pdu_zone; // pool of free pdu's
208 TAILQ_HEAD(,pduq) freepdu;
209
210 #ifdef ISCSI_INITIATOR_DEBUG
211 int npdu_alloc, npdu_max; // for instrumentation
212 #endif
213 #ifdef DO_EVENTHANDLER
214 eventhandler_tag eh;
215 #endif
216 /*
217 | sysctl stuff
218 */
219 struct sysctl_ctx_list clist;
220 struct sysctl_oid *oid;
221 };
222
223 #ifdef ISCSI_INITIATOR_DEBUG
224 extern struct mtx iscsi_dbg_mtx;
225 #endif
226
227 void isc_start_receiver(isc_session_t *sp);
228 void isc_stop_receiver(isc_session_t *sp);
229
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);
233
234 int ism_fullfeature(struct cdev *dev, int flag);
235
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);
239
240 int ic_init(isc_session_t *sp);
241 void ic_destroy(isc_session_t *sp);
242 void ic_lost_target(isc_session_t *sp, int target);
243 int ic_getCamVals(isc_session_t *sp, iscsi_cam_t *cp);
244
245 void ism_recv(isc_session_t *sp, pduq_t *pq);
246 int ism_start(isc_session_t *sp);
247 void ism_restart(isc_session_t *sp);
248 void ism_stop(isc_session_t *sp);
249
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);
258
259 // Serial Number Arithmetic
260 #define _MAXINCR 0x7FFFFFFF // 2 ^ 31 - 1
261 #define SNA_GT(i1, i2) ((i1 != i2) && (\
262 (i1 < i2 && i2 - i1 > _MAXINCR) ||\
263 (i1 > i2 && i1 - i2 < _MAXINCR))?1: 0)
264
265 /*
266 | inlines
267 */
268 #ifdef _CAM_CAM_XPT_SIM_H
269
270 #if __FreeBSD_version < 600000
271 #define CAM_LOCK(arg)
272 #define CAM_ULOCK(arg)
273
274 static __inline void
275 XPT_DONE(isc_session_t *sp, union ccb *ccb)
276 {
277 mtx_lock(&Giant);
278 xpt_done(ccb);
279 mtx_unlock(&Giant);
280 }
281 #elif __FreeBSD_version >= 700000
282 #define CAM_LOCK(arg) mtx_lock(&arg->cam_mtx)
283 #define CAM_UNLOCK(arg) mtx_unlock(&arg->cam_mtx)
284
285 static __inline void
286 XPT_DONE(isc_session_t *sp, union ccb *ccb)
287 {
288 CAM_LOCK(sp);
289 xpt_done(ccb);
290 CAM_UNLOCK(sp);
291 }
292 #else
293 //__FreeBSD_version >= 600000
294 #define CAM_LOCK(arg)
295 #define CAM_UNLOCK(arg)
296 #define XPT_DONE(ignore, arg) xpt_done(arg)
297 #endif
298
299 #endif /* _CAM_CAM_XPT_SIM_H */
300
301 static __inline pduq_t *
302 pdu_alloc(struct isc_softc *isc, int wait)
303 {
304 pduq_t *pq;
305
306 pq = (pduq_t *)uma_zalloc(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/);
307 if(pq == NULL) {
308 debug(7, "out of mem");
309 return NULL;
310 }
311 #ifdef ISCSI_INITIATOR_DEBUG
312 mtx_lock(&iscsi_dbg_mtx);
313 isc->npdu_alloc++;
314 if(isc->npdu_alloc > isc->npdu_max)
315 isc->npdu_max = isc->npdu_alloc;
316 mtx_unlock(&iscsi_dbg_mtx);
317 #endif
318 memset(pq, 0, sizeof(pduq_t));
319
320 return pq;
321 }
322
323 static __inline void
324 pdu_free(struct isc_softc *isc, pduq_t *pq)
325 {
326 if(pq->mp)
327 m_freem(pq->mp);
328 #ifdef NO_USE_MBUF
329 if(pq->buf != NULL)
330 free(pq->buf, M_ISCSIBUF);
331 #endif
332 uma_zfree(isc->pdu_zone, pq);
333 #ifdef ISCSI_INITIATOR_DEBUG
334 mtx_lock(&iscsi_dbg_mtx);
335 isc->npdu_alloc--;
336 mtx_unlock(&iscsi_dbg_mtx);
337 #endif
338 }
339
340 static __inline void
341 i_nqueue_rsp(isc_session_t *sp, pduq_t *pq)
342 {
343 mtx_lock(&sp->rsp_mtx);
344 if(++sp->stats.nrsp > sp->stats.max_rsp)
345 sp->stats.max_rsp = sp->stats.nrsp;
346 TAILQ_INSERT_TAIL(&sp->rsp, pq, pq_link);
347 mtx_unlock(&sp->rsp_mtx);
348 }
349
350 static __inline pduq_t *
351 i_dqueue_rsp(isc_session_t *sp)
352 {
353 pduq_t *pq;
354
355 mtx_lock(&sp->rsp_mtx);
356 if((pq = TAILQ_FIRST(&sp->rsp)) != NULL) {
357 sp->stats.nrsp--;
358 TAILQ_REMOVE(&sp->rsp, pq, pq_link);
359 }
360 mtx_unlock(&sp->rsp_mtx);
361
362 return pq;
363 }
364
365 static __inline void
366 i_nqueue_rsv(isc_session_t *sp, pduq_t *pq)
367 {
368 mtx_lock(&sp->rsv_mtx);
369 if(++sp->stats.nrsv > sp->stats.max_rsv)
370 sp->stats.max_rsv = sp->stats.nrsv;
371 TAILQ_INSERT_TAIL(&sp->rsv, pq, pq_link);
372 mtx_unlock(&sp->rsv_mtx);
373 }
374
375 static __inline pduq_t *
376 i_dqueue_rsv(isc_session_t *sp)
377 {
378 pduq_t *pq;
379
380 mtx_lock(&sp->rsv_mtx);
381 if((pq = TAILQ_FIRST(&sp->rsv)) != NULL) {
382 sp->stats.nrsv--;
383 TAILQ_REMOVE(&sp->rsv, pq, pq_link);
384 }
385 mtx_unlock(&sp->rsv_mtx);
386
387 return pq;
388 }
389
390 static __inline void
391 i_nqueue_csnd(isc_session_t *sp, pduq_t *pq)
392 {
393 mtx_lock(&sp->snd_mtx);
394 if(++sp->stats.ncsnd > sp->stats.max_csnd)
395 sp->stats.max_csnd = sp->stats.ncsnd;
396 TAILQ_INSERT_TAIL(&sp->csnd, pq, pq_link);
397 mtx_unlock(&sp->snd_mtx);
398 }
399
400 static __inline pduq_t *
401 i_dqueue_csnd(isc_session_t *sp)
402 {
403 pduq_t *pq;
404
405 mtx_lock(&sp->snd_mtx);
406 if((pq = TAILQ_FIRST(&sp->csnd)) != NULL) {
407 sp->stats.ncsnd--;
408 TAILQ_REMOVE(&sp->csnd, pq, pq_link);
409 }
410 mtx_unlock(&sp->snd_mtx);
411
412 return pq;
413 }
414
415 static __inline void
416 i_nqueue_isnd(isc_session_t *sp, pduq_t *pq)
417 {
418 mtx_lock(&sp->snd_mtx);
419 if(++sp->stats.nisnd > sp->stats.max_isnd)
420 sp->stats.max_isnd = sp->stats.nisnd;
421 TAILQ_INSERT_TAIL(&sp->isnd, pq, pq_link);
422 mtx_unlock(&sp->snd_mtx);
423 }
424
425 static __inline pduq_t *
426 i_dqueue_isnd(isc_session_t *sp)
427 {
428 pduq_t *pq;
429
430 mtx_lock(&sp->snd_mtx);
431 if((pq = TAILQ_FIRST(&sp->isnd)) != NULL) {
432 sp->stats.nisnd--;
433 TAILQ_REMOVE(&sp->isnd, pq, pq_link);
434 }
435 mtx_unlock(&sp->snd_mtx);
436
437 return pq;
438 }
439
440 static __inline void
441 i_nqueue_wsnd(isc_session_t *sp, pduq_t *pq)
442 {
443 mtx_lock(&sp->snd_mtx);
444 if(++sp->stats.nwsnd > sp->stats.max_wsnd)
445 sp->stats.max_wsnd = sp->stats.nwsnd;
446 TAILQ_INSERT_TAIL(&sp->wsnd, pq, pq_link);
447 mtx_unlock(&sp->snd_mtx);
448 }
449
450 static __inline pduq_t *
451 i_dqueue_wsnd(isc_session_t *sp)
452 {
453 pduq_t *pq;
454
455 mtx_lock(&sp->snd_mtx);
456 if((pq = TAILQ_FIRST(&sp->wsnd)) != NULL) {
457 sp->stats.nwsnd--;
458 TAILQ_REMOVE(&sp->wsnd, pq, pq_link);
459 }
460 mtx_unlock(&sp->snd_mtx);
461
462 return pq;
463 }
464
465 static __inline pduq_t *
466 i_dqueue_snd(isc_session_t *sp, int which)
467 {
468 pduq_t *pq;
469
470 pq = NULL;
471 mtx_lock(&sp->snd_mtx);
472 if((which & BIT(0)) && (pq = TAILQ_FIRST(&sp->isnd)) != NULL) {
473 sp->stats.nisnd--;
474 TAILQ_REMOVE(&sp->isnd, pq, pq_link);
475 pq->pduq = &sp->isnd; // remember where you came from
476 } else
477 if((which & BIT(1)) && (pq = TAILQ_FIRST(&sp->wsnd)) != NULL) {
478 sp->stats.nwsnd--;
479 TAILQ_REMOVE(&sp->wsnd, pq, pq_link);
480 pq->pduq = &sp->wsnd; // remember where you came from
481 } else
482 if((which & BIT(2)) && (pq = TAILQ_FIRST(&sp->csnd)) != NULL) {
483 sp->stats.ncsnd--;
484 TAILQ_REMOVE(&sp->csnd, pq, pq_link);
485 pq->pduq = &sp->csnd; // remember where you came from
486 }
487 mtx_unlock(&sp->snd_mtx);
488
489 return pq;
490 }
491
492 static __inline void
493 i_rqueue_pdu(isc_session_t *sp, pduq_t *pq)
494 {
495 mtx_lock(&sp->snd_mtx);
496 KASSERT(pq->pduq != NULL, ("pq->pduq is NULL"));
497 TAILQ_INSERT_TAIL(pq->pduq, pq, pq_link);
498 mtx_unlock(&sp->snd_mtx);
499 }
500
501 /*
502 | Waiting for ACK (or something :-)
503 */
504 static __inline void
505 i_nqueue_hld(isc_session_t *sp, pduq_t *pq)
506 {
507 getbintime(&pq->ts);
508 mtx_lock(&sp->hld_mtx);
509 if(++sp->stats.nhld > sp->stats.max_hld)
510 sp->stats.max_hld = sp->stats.nhld;
511 TAILQ_INSERT_TAIL(&sp->hld, pq, pq_link);
512 mtx_unlock(&sp->hld_mtx);
513 return;
514 }
515
516 static __inline void
517 i_remove_hld(isc_session_t *sp, pduq_t *pq)
518 {
519 mtx_lock(&sp->hld_mtx);
520 sp->stats.nhld--;
521 TAILQ_REMOVE(&sp->hld, pq, pq_link);
522 mtx_unlock(&sp->hld_mtx);
523 }
524
525 static __inline pduq_t *
526 i_dqueue_hld(isc_session_t *sp)
527 {
528 pduq_t *pq;
529
530 mtx_lock(&sp->hld_mtx);
531 if((pq = TAILQ_FIRST(&sp->hld)) != NULL) {
532 sp->stats.nhld--;
533 TAILQ_REMOVE(&sp->hld, pq, pq_link);
534 }
535 mtx_unlock(&sp->hld_mtx);
536
537 return pq;
538 }
539
540 static __inline pduq_t *
541 i_search_hld(isc_session_t *sp, int itt, int keep)
542 {
543 pduq_t *pq, *tmp;
544
545 pq = NULL;
546
547 mtx_lock(&sp->hld_mtx);
548 TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, tmp) {
549 if(pq->pdu.ipdu.bhs.itt == itt) {
550 if(!keep) {
551 sp->stats.nhld--;
552 TAILQ_REMOVE(&sp->hld, pq, pq_link);
553 }
554 break;
555 }
556 }
557 mtx_unlock(&sp->hld_mtx);
558
559 return pq;
560 }
561
562 static __inline void
563 i_acked_hld(isc_session_t *sp, pdu_t *op)
564 {
565 pduq_t *pq, *tmp;
566 u_int exp = sp->sn.expCmd;
567
568 pq = NULL;
569 mtx_lock(&sp->hld_mtx);
570 TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, tmp) {
571 if((op && op->ipdu.bhs.itt == pq->pdu.ipdu.bhs.itt)
572 || (pq->ccb == NULL
573 && (pq->pdu.ipdu.bhs.opcode != ISCSI_WRITE_DATA)
574 && SNA_GT(exp, ntohl(pq->pdu.ipdu.bhs.ExpStSN)))) {
575 sp->stats.nhld--;
576 TAILQ_REMOVE(&sp->hld, pq, pq_link);
577 pdu_free(sp->isc, pq);
578 }
579 }
580 mtx_unlock(&sp->hld_mtx);
581 }
582
583 static __inline void
584 i_mbufcopy(struct mbuf *mp, caddr_t dp, int len)
585 {
586 struct mbuf *m;
587 caddr_t bp;
588
589 for(m = mp; m != NULL; m = m->m_next) {
590 bp = mtod(m, caddr_t);
591 /*
592 | the pdu is word (4 octed) aligned
593 | so len <= packet
594 */
595 memcpy(dp, bp, MIN(len, m->m_len));
596 dp += m->m_len;
597 len -= m->m_len;
598 if(len <= 0)
599 break;
600 }
601 }
Cache object: 1fc6256971b18ec46310baa4eb946a89
|