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 | $Id: iscsivar.h,v 1.30 2007/04/22 10:12:11 danny Exp danny $ 30 */ 31 #ifndef ISCSI_INITIATOR_DEBUG 32 #define ISCSI_INITIATOR_DEBUG 1 33 #endif 34 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) 43 #else 44 #define debug(level, fmt, args...) 45 #define debug_called(level) 46 #define sdebug(level, fmt, args...) 47 #endif /* ISCSI_INITIATOR_DEBUG */ 48 49 #define xdebug(fmt, args...) kprintf(">>> %s: " fmt "\n", __func__ , ##args) 50 51 #define PROC_LOCK(p) 52 #define PROC_UNLOCK(p) 53 54 #define MAX_SESSIONS 256 55 56 typedef uint32_t digest_t(const void *, int len, uint32_t ocrc); 57 58 typedef struct objcache *objcache_t; 59 60 MALLOC_DECLARE(M_ISCSI); 61 62 #ifndef BIT 63 #define BIT(n) (1 <<(n)) 64 #endif 65 66 #define ISC_SM_RUN BIT(0) 67 #define ISC_SM_RUNNING BIT(1) 68 69 #define ISC_LINK_UP BIT(2) 70 #define ISC_CON_RUN BIT(3) 71 #define ISC_CON_RUNNING BIT(4) 72 #define ISC_KILL BIT(5) 73 #define ISC_OQNOTEMPTY BIT(6) 74 #define ISC_OWAITING BIT(7) 75 #define ISC_FFPHASE BIT(8) 76 #define ISC_FFPWAIT BIT(9) 77 78 #define ISC_MEMWAIT BIT(10) 79 #define ISC_SIGNALED BIT(11) 80 #define ISC_FROZEN BIT(12) 81 #define ISC_STALLED BIT(13) 82 83 #define ISC_HOLD BIT(14) 84 #define ISC_HOLDED BIT(15) 85 86 #define ISC_SHUTDOWN BIT(31) 87 88 /* 89 | some stats 90 */ 91 struct i_stats { 92 int npdu; // number of pdus malloc'ed. 93 int nrecv; // unprocessed received pdus 94 int nsent; // sent pdus 95 96 int nrsp, max_rsp; 97 int nrsv, max_rsv; 98 int ncsnd, max_csnd; 99 int nisnd, max_isnd; 100 int nwsnd, max_wsnd; 101 int nhld, max_hld; 102 103 struct timeval t_sent; 104 struct timeval t_recv; 105 }; 106 107 /* 108 | one per 'session' 109 */ 110 111 typedef TAILQ_HEAD(, pduq) queue_t; 112 113 typedef struct isc_session { 114 TAILQ_ENTRY(isc_session) sp_link; 115 int flags; 116 struct cdev *dev; 117 struct socket *soc; 118 struct file *fp; 119 struct thread *td; 120 121 struct proc *proc; // the userland process 122 int signal; 123 124 struct thread *soc_thr; 125 126 struct thread *stp; // the sm thread 127 128 struct isc_softc *isc; 129 130 digest_t *hdrDigest; // the digest alg. if any 131 digest_t *dataDigest; // the digest alg. if any 132 133 int sid; // Session ID 134 int targetid; 135 // int cid; // Connection ID 136 // int tsih; // target session identifier handle 137 sn_t sn; // sequence number stuff; 138 int cws; // current window size 139 140 int target_nluns; // this and target_lun are 141 // hopefully temporal till I 142 // figure out a better way. 143 lun_id_t target_lun[ISCSI_MAX_LUNS]; 144 145 struct mtx rsp_mtx; 146 struct mtx rsv_mtx; 147 struct mtx snd_mtx; 148 struct mtx hld_mtx; 149 struct mtx io_mtx; 150 queue_t rsp; 151 queue_t rsv; 152 queue_t csnd; 153 queue_t isnd; 154 queue_t wsnd; 155 queue_t hld; 156 157 /* 158 | negotiable values 159 */ 160 isc_opt_t opt; 161 162 struct i_stats stats; 163 struct cam_path *cam_path; 164 bhs_t bhs; 165 struct uio uio; 166 struct iovec iov; 167 /* 168 | sysctl stuff 169 */ 170 struct sysctl_ctx_list clist; 171 struct sysctl_oid *oid; 172 int douio; //XXX: turn on/off uio on read 173 } isc_session_t; 174 175 typedef struct pduq { 176 TAILQ_ENTRY(pduq) pq_link; 177 178 caddr_t buf; 179 u_int len; // the total length of the pdu 180 pdu_t pdu; 181 union ccb *ccb; 182 183 struct uio uio; 184 struct iovec iov[5]; // XXX: careful ... 185 struct mbuf *mp; 186 struct timeval ts; 187 int refcnt; 188 queue_t *pduq; 189 } pduq_t; 190 191 struct isc_softc { 192 //int state; 193 struct cdev *dev; 194 eventhandler_tag eh; 195 char isid[6]; // Initiator Session ID (48 bits) 196 struct lock lock; 197 198 int nsess; 199 TAILQ_HEAD(,isc_session) isc_sess; 200 isc_session_t *sessions[MAX_SESSIONS]; 201 202 struct lock pdu_lock; 203 #ifdef ISCSI_INITIATOR_DEBUG 204 int npdu_alloc, npdu_max; // for instrumentation 205 #endif 206 #define MAX_PDUS (MAX_SESSIONS*256) // XXX: at the moment this is arbitrary 207 objcache_t pdu_zone; // pool of free pdu's 208 TAILQ_HEAD(,pduq) freepdu; 209 /* 210 | cam stuff 211 */ 212 struct cam_sim *cam_sim; 213 struct cam_path *cam_path; 214 struct lock cam_lock; 215 /* 216 | sysctl stuff 217 */ 218 struct sysctl_ctx_list clist; 219 struct sysctl_oid *oid; 220 }; 221 222 #ifdef ISCSI_INITIATOR_DEBUG 223 extern struct lock iscsi_dbg_lock; 224 #endif 225 226 void isc_start_receiver(isc_session_t *sp); 227 void isc_stop_receiver(isc_session_t *sp); 228 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); 232 233 int ism_fullfeature(struct cdev *dev, int flag); 234 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); 238 239 int ic_init(struct isc_softc *sc); 240 void ic_destroy(struct isc_softc *sc); 241 int ic_fullfeature(struct cdev *dev); 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_stop(isc_session_t *sp); 248 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); 257 258 void ic_freeze(isc_session_t *sp); 259 void ic_release(isc_session_t *sp); 260 261 // Serial Number Arithmetic 262 #define _MAXINCR 0x7FFFFFFF // 2 ^ 31 - 1 263 #define SNA_GT(i1, i2) ((i1 != i2) && (\ 264 (i1 < i2 && i2 - i1 > _MAXINCR) ||\ 265 (i1 > i2 && i1 - i2 < _MAXINCR))?1: 0) 266 267 /* 268 * inlines 269 * 270 * DragonFly note: CAM locks itself, peripherals do not lock CAM. 271 */ 272 #ifdef _CAM_CAM_XPT_SIM_H 273 274 #define CAM_LOCK(arg) /*lockmgr(&arg->cam_lock, LK_EXCLUSIVE)*/ 275 #define CAM_UNLOCK(arg) /*lockmgr(&arg->cam_lock, LK_RELEASE)*/ 276 277 static __inline void 278 XPT_DONE(struct isc_softc *isp, union ccb *ccb) 279 { 280 CAM_LOCK(isp); 281 xpt_done(ccb); 282 CAM_UNLOCK(isp); 283 } 284 285 #endif /* _CAM_CAM_XPT_SIM_H */ 286 287 #define iscsi_lock_ex(mtx) mtx_lock_ex_quick(mtx) 288 #define iscsi_unlock_ex(mtx) mtx_unlock(mtx) 289 #define issleep(id, mtx, flags, wmesg, to) \ 290 mtxsleep(id, mtx, flags, wmesg, to) 291 292 static __inline pduq_t * 293 pdu_alloc(struct isc_softc *isc, int wait) 294 { 295 pduq_t *pq; 296 297 lockmgr(&isc->pdu_lock, LK_EXCLUSIVE); 298 if((pq = TAILQ_FIRST(&isc->freepdu)) == NULL) { 299 lockmgr(&isc->pdu_lock, LK_RELEASE); 300 pq = objcache_get(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/); 301 } 302 else { 303 TAILQ_REMOVE(&isc->freepdu, pq, pq_link); 304 lockmgr(&isc->pdu_lock, LK_RELEASE); 305 } 306 307 if(pq == NULL) { 308 debug(7, "out of mem"); 309 return NULL; 310 } 311 #ifdef ISCSI_INITIATOR_DEBUG 312 lockmgr(&isc->pdu_lock, LK_EXCLUSIVE); 313 isc->npdu_alloc++; 314 if(isc->npdu_alloc > isc->npdu_max) 315 isc->npdu_max = isc->npdu_alloc; 316 lockmgr(&isc->pdu_lock, LK_RELEASE); 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 kfree(pq->buf, M_ISCSI); 331 #endif 332 lockmgr(&isc->pdu_lock, LK_EXCLUSIVE); 333 TAILQ_INSERT_TAIL(&isc->freepdu, pq, pq_link); 334 #ifdef ISCSI_INITIATOR_DEBUG 335 isc->npdu_alloc--; 336 #endif 337 lockmgr(&isc->pdu_lock, LK_RELEASE); 338 } 339 340 static __inline void 341 i_nqueue_rsp(isc_session_t *sp, pduq_t *pq) 342 { 343 iscsi_lock_ex(&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 iscsi_unlock_ex(&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 iscsi_lock_ex(&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 iscsi_unlock_ex(&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 iscsi_lock_ex(&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 iscsi_unlock_ex(&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 iscsi_lock_ex(&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 iscsi_unlock_ex(&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 iscsi_lock_ex(&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 iscsi_unlock_ex(&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 iscsi_lock_ex(&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 iscsi_unlock_ex(&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 iscsi_lock_ex(&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 iscsi_unlock_ex(&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 iscsi_lock_ex(&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 iscsi_unlock_ex(&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 iscsi_lock_ex(&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 iscsi_unlock_ex(&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 iscsi_lock_ex(&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 iscsi_unlock_ex(&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 iscsi_lock_ex(&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 iscsi_unlock_ex(&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 iscsi_lock_ex(&sp->snd_mtx); 496 KASSERT(pq->pduq != NULL, ("pq->pduq is NULL")); 497 TAILQ_INSERT_TAIL(pq->pduq, pq, pq_link); 498 iscsi_unlock_ex(&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 getmicrouptime(&pq->ts); 508 iscsi_lock_ex(&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 iscsi_unlock_ex(&sp->hld_mtx); 513 return; 514 } 515 516 static __inline void 517 i_remove_hld(isc_session_t *sp, pduq_t *pq) 518 { 519 iscsi_lock_ex(&sp->hld_mtx); 520 sp->stats.nhld--; 521 TAILQ_REMOVE(&sp->hld, pq, pq_link); 522 iscsi_unlock_ex(&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 iscsi_lock_ex(&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 iscsi_unlock_ex(&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 iscsi_lock_ex(&sp->hld_mtx); 548 TAILQ_FOREACH_MUTABLE(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 iscsi_unlock_ex(&sp->hld_mtx); 558 559 return pq; 560 } 561 562 static __inline void 563 i_mbufcopy(struct mbuf *mp, caddr_t dp, int len) 564 { 565 struct mbuf *m; 566 caddr_t bp; 567 568 for(m = mp; m != NULL; m = m->m_next) { 569 bp = mtod(m, caddr_t); 570 /* 571 | the pdu is word (4 octed) aligned 572 | so len <= packet 573 */ 574 memcpy(dp, bp, MIN(len, m->m_len)); 575 dp += m->m_len; 576 len -= m->m_len; 577 if(len <= 0) 578 break; 579 } 580 } 581