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 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 * 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 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 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 * 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 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 * 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 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 * 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 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 * 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 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 * 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 * 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 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 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 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 * 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 * 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 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