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 MALLOC_DECLARE(M_PDU); 62 63 #ifndef BIT 64 #define BIT(n) (1 <<(n)) 65 #endif 66 67 #define ISC_SM_RUN BIT(0) 68 #define ISC_SM_RUNNING BIT(1) 69 70 #define ISC_LINK_UP BIT(2) 71 #define ISC_CON_RUN BIT(3) 72 #define ISC_CON_RUNNING BIT(4) 73 #define ISC_KILL BIT(5) 74 #define ISC_OQNOTEMPTY BIT(6) 75 #define ISC_OWAITING BIT(7) 76 #define ISC_FFPHASE BIT(8) 77 #define ISC_FFPWAIT BIT(9) 78 79 #define ISC_MEMWAIT BIT(10) 80 #define ISC_SIGNALED BIT(11) 81 #define ISC_FROZEN BIT(12) 82 #define ISC_STALLED BIT(13) 83 84 #define ISC_HOLD BIT(14) 85 #define ISC_HOLDED BIT(15) 86 87 #define ISC_SHUTDOWN BIT(31) 88 89 /* 90 | some stats 91 */ 92 struct i_stats { 93 int npdu; // number of pdus malloc'ed. 94 int nrecv; // unprocessed received pdus 95 int nsent; // sent pdus 96 97 int nrsp, max_rsp; 98 int nrsv, max_rsv; 99 int ncsnd, max_csnd; 100 int nisnd, max_isnd; 101 int nwsnd, max_wsnd; 102 int nhld, max_hld; 103 104 struct timeval t_sent; 105 struct timeval t_recv; 106 }; 107 108 /* 109 | one per 'session' 110 */ 111 112 typedef TAILQ_HEAD(, pduq) queue_t; 113 114 typedef struct isc_session { 115 TAILQ_ENTRY(isc_session) sp_link; 116 int flags; 117 struct cdev *dev; 118 struct socket *soc; 119 struct file *fp; 120 struct thread *td; 121 122 struct proc *proc; // the userland process 123 int signal; 124 125 struct thread *soc_thr; 126 127 struct thread *stp; // the sm thread 128 129 struct isc_softc *isc; 130 131 digest_t *hdrDigest; // the digest alg. if any 132 digest_t *dataDigest; // the digest alg. if any 133 134 int sid; // Session ID 135 int targetid; 136 // int cid; // Connection ID 137 // int tsih; // target session identifier handle 138 sn_t sn; // sequence number stuff; 139 int cws; // current window size 140 141 int target_nluns; // this and target_lun are 142 // hopefully temporal till I 143 // figure out a better way. 144 lun_id_t target_lun[ISCSI_MAX_LUNS]; 145 146 struct mtx rsp_mtx; 147 struct mtx rsv_mtx; 148 struct mtx snd_mtx; 149 struct mtx hld_mtx; 150 struct mtx io_mtx; 151 queue_t rsp; 152 queue_t rsv; 153 queue_t csnd; 154 queue_t isnd; 155 queue_t wsnd; 156 queue_t hld; 157 158 /* 159 | negotiable values 160 */ 161 isc_opt_t opt; 162 163 struct i_stats stats; 164 struct cam_path *cam_path; 165 bhs_t bhs; 166 struct uio uio; 167 struct iovec iov; 168 /* 169 | sysctl stuff 170 */ 171 struct sysctl_ctx_list clist; 172 struct sysctl_oid *oid; 173 int douio; //XXX: turn on/off uio on read 174 } isc_session_t; 175 176 typedef struct pduq { 177 TAILQ_ENTRY(pduq) pq_link; 178 179 caddr_t buf; 180 u_int len; // the total length of the pdu 181 pdu_t pdu; 182 union ccb *ccb; 183 184 struct uio uio; 185 struct iovec iov[5]; // XXX: careful ... 186 struct mbuf *mp; 187 struct timeval ts; 188 int refcnt; 189 queue_t *pduq; 190 } pduq_t; 191 192 struct isc_softc { 193 //int state; 194 struct cdev *dev; 195 eventhandler_tag eh; 196 char isid[6]; // Initiator Session ID (48 bits) 197 struct lock lock; 198 199 int nsess; 200 TAILQ_HEAD(,isc_session) isc_sess; 201 isc_session_t *sessions[MAX_SESSIONS]; 202 203 struct lock pdu_lock; 204 #ifdef ISCSI_INITIATOR_DEBUG 205 int npdu_alloc, npdu_max; // for instrumentation 206 #endif 207 #define MAX_PDUS (MAX_SESSIONS*256) // XXX: at the moment this is arbitrary 208 objcache_t pdu_zone; // pool of free pdu's 209 TAILQ_HEAD(,pduq) freepdu; 210 /* 211 | cam stuff 212 */ 213 struct cam_sim *cam_sim; 214 struct cam_path *cam_path; 215 struct lock cam_lock; 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 lock iscsi_dbg_lock; 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(struct isc_softc *sc); 241 void ic_destroy(struct isc_softc *sc); 242 int ic_fullfeature(struct cdev *dev); 243 void ic_lost_target(isc_session_t *sp, int target); 244 int ic_getCamVals(isc_session_t *sp, iscsi_cam_t *cp); 245 246 void ism_recv(isc_session_t *sp, pduq_t *pq); 247 int ism_start(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 void ic_freeze(isc_session_t *sp); 260 void ic_release(isc_session_t *sp); 261 262 // Serial Number Arithmetic 263 #define _MAXINCR 0x7FFFFFFF // 2 ^ 31 - 1 264 #define SNA_GT(i1, i2) ((i1 != i2) && (\ 265 (i1 < i2 && i2 - i1 > _MAXINCR) ||\ 266 (i1 > i2 && i1 - i2 < _MAXINCR))?1: 0) 267 268 /* 269 * inlines 270 * 271 * DragonFly note: CAM locks itself, peripherals do not lock CAM. 272 */ 273 #ifdef _CAM_CAM_XPT_SIM_H 274 275 #define CAM_LOCK(arg) /*lockmgr(&arg->cam_lock, LK_EXCLUSIVE)*/ 276 #define CAM_UNLOCK(arg) /*lockmgr(&arg->cam_lock, LK_RELEASE)*/ 277 278 static __inline void 279 XPT_DONE(struct isc_softc *isp, union ccb *ccb) 280 { 281 CAM_LOCK(isp); 282 xpt_done(ccb); 283 CAM_UNLOCK(isp); 284 } 285 286 #endif /* _CAM_CAM_XPT_SIM_H */ 287 288 #define iscsi_lock_ex(mtx) mtx_lock_ex_quick(mtx, __func__) 289 #define iscsi_unlock_ex(mtx) mtx_unlock(mtx) 290 #define issleep(id, mtx, flags, wmesg, to) \ 291 mtxsleep(id, mtx, flags, wmesg, to) 292 293 static __inline pduq_t * 294 pdu_alloc(struct isc_softc *isc, int wait) 295 { 296 pduq_t *pq; 297 298 lockmgr(&isc->pdu_lock, LK_EXCLUSIVE); 299 if((pq = TAILQ_FIRST(&isc->freepdu)) == NULL) { 300 lockmgr(&isc->pdu_lock, LK_RELEASE); 301 pq = objcache_get(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/); 302 } 303 else { 304 TAILQ_REMOVE(&isc->freepdu, pq, pq_link); 305 lockmgr(&isc->pdu_lock, LK_RELEASE); 306 } 307 308 if(pq == NULL) { 309 debug(7, "out of mem"); 310 return NULL; 311 } 312 #ifdef ISCSI_INITIATOR_DEBUG 313 lockmgr(&isc->pdu_lock, LK_EXCLUSIVE); 314 isc->npdu_alloc++; 315 if(isc->npdu_alloc > isc->npdu_max) 316 isc->npdu_max = isc->npdu_alloc; 317 lockmgr(&isc->pdu_lock, LK_RELEASE); 318 #endif 319 memset(pq, 0, sizeof(pduq_t)); 320 321 return pq; 322 } 323 324 static __inline void 325 pdu_free(struct isc_softc *isc, pduq_t *pq) 326 { 327 if(pq->mp) 328 m_freem(pq->mp); 329 #ifdef NO_USE_MBUF 330 if(pq->buf != NULL) 331 kfree(pq->buf, M_ISCSI); 332 #endif 333 lockmgr(&isc->pdu_lock, LK_EXCLUSIVE); 334 TAILQ_INSERT_TAIL(&isc->freepdu, pq, pq_link); 335 #ifdef ISCSI_INITIATOR_DEBUG 336 isc->npdu_alloc--; 337 #endif 338 lockmgr(&isc->pdu_lock, LK_RELEASE); 339 } 340 341 static __inline void 342 i_nqueue_rsp(isc_session_t *sp, pduq_t *pq) 343 { 344 iscsi_lock_ex(&sp->rsp_mtx); 345 if(++sp->stats.nrsp > sp->stats.max_rsp) 346 sp->stats.max_rsp = sp->stats.nrsp; 347 TAILQ_INSERT_TAIL(&sp->rsp, pq, pq_link); 348 iscsi_unlock_ex(&sp->rsp_mtx); 349 } 350 351 static __inline pduq_t * 352 i_dqueue_rsp(isc_session_t *sp) 353 { 354 pduq_t *pq; 355 356 iscsi_lock_ex(&sp->rsp_mtx); 357 if((pq = TAILQ_FIRST(&sp->rsp)) != NULL) { 358 sp->stats.nrsp--; 359 TAILQ_REMOVE(&sp->rsp, pq, pq_link); 360 } 361 iscsi_unlock_ex(&sp->rsp_mtx); 362 363 return pq; 364 } 365 366 static __inline void 367 i_nqueue_rsv(isc_session_t *sp, pduq_t *pq) 368 { 369 iscsi_lock_ex(&sp->rsv_mtx); 370 if(++sp->stats.nrsv > sp->stats.max_rsv) 371 sp->stats.max_rsv = sp->stats.nrsv; 372 TAILQ_INSERT_TAIL(&sp->rsv, pq, pq_link); 373 iscsi_unlock_ex(&sp->rsv_mtx); 374 } 375 376 static __inline pduq_t * 377 i_dqueue_rsv(isc_session_t *sp) 378 { 379 pduq_t *pq; 380 381 iscsi_lock_ex(&sp->rsv_mtx); 382 if((pq = TAILQ_FIRST(&sp->rsv)) != NULL) { 383 sp->stats.nrsv--; 384 TAILQ_REMOVE(&sp->rsv, pq, pq_link); 385 } 386 iscsi_unlock_ex(&sp->rsv_mtx); 387 388 return pq; 389 } 390 391 static __inline void 392 i_nqueue_csnd(isc_session_t *sp, pduq_t *pq) 393 { 394 iscsi_lock_ex(&sp->snd_mtx); 395 if(++sp->stats.ncsnd > sp->stats.max_csnd) 396 sp->stats.max_csnd = sp->stats.ncsnd; 397 TAILQ_INSERT_TAIL(&sp->csnd, pq, pq_link); 398 iscsi_unlock_ex(&sp->snd_mtx); 399 } 400 401 static __inline pduq_t * 402 i_dqueue_csnd(isc_session_t *sp) 403 { 404 pduq_t *pq; 405 406 iscsi_lock_ex(&sp->snd_mtx); 407 if((pq = TAILQ_FIRST(&sp->csnd)) != NULL) { 408 sp->stats.ncsnd--; 409 TAILQ_REMOVE(&sp->csnd, pq, pq_link); 410 } 411 iscsi_unlock_ex(&sp->snd_mtx); 412 413 return pq; 414 } 415 416 static __inline void 417 i_nqueue_isnd(isc_session_t *sp, pduq_t *pq) 418 { 419 iscsi_lock_ex(&sp->snd_mtx); 420 if(++sp->stats.nisnd > sp->stats.max_isnd) 421 sp->stats.max_isnd = sp->stats.nisnd; 422 TAILQ_INSERT_TAIL(&sp->isnd, pq, pq_link); 423 iscsi_unlock_ex(&sp->snd_mtx); 424 } 425 426 static __inline pduq_t * 427 i_dqueue_isnd(isc_session_t *sp) 428 { 429 pduq_t *pq; 430 431 iscsi_lock_ex(&sp->snd_mtx); 432 if((pq = TAILQ_FIRST(&sp->isnd)) != NULL) { 433 sp->stats.nisnd--; 434 TAILQ_REMOVE(&sp->isnd, pq, pq_link); 435 } 436 iscsi_unlock_ex(&sp->snd_mtx); 437 438 return pq; 439 } 440 441 static __inline void 442 i_nqueue_wsnd(isc_session_t *sp, pduq_t *pq) 443 { 444 iscsi_lock_ex(&sp->snd_mtx); 445 if(++sp->stats.nwsnd > sp->stats.max_wsnd) 446 sp->stats.max_wsnd = sp->stats.nwsnd; 447 TAILQ_INSERT_TAIL(&sp->wsnd, pq, pq_link); 448 iscsi_unlock_ex(&sp->snd_mtx); 449 } 450 451 static __inline pduq_t * 452 i_dqueue_wsnd(isc_session_t *sp) 453 { 454 pduq_t *pq; 455 456 iscsi_lock_ex(&sp->snd_mtx); 457 if((pq = TAILQ_FIRST(&sp->wsnd)) != NULL) { 458 sp->stats.nwsnd--; 459 TAILQ_REMOVE(&sp->wsnd, pq, pq_link); 460 } 461 iscsi_unlock_ex(&sp->snd_mtx); 462 463 return pq; 464 } 465 466 static __inline pduq_t * 467 i_dqueue_snd(isc_session_t *sp, int which) 468 { 469 pduq_t *pq; 470 471 pq = NULL; 472 iscsi_lock_ex(&sp->snd_mtx); 473 if((which & BIT(0)) && (pq = TAILQ_FIRST(&sp->isnd)) != NULL) { 474 sp->stats.nisnd--; 475 TAILQ_REMOVE(&sp->isnd, pq, pq_link); 476 pq->pduq = &sp->isnd; // remember where you came from 477 } else 478 if((which & BIT(1)) && (pq = TAILQ_FIRST(&sp->wsnd)) != NULL) { 479 sp->stats.nwsnd--; 480 TAILQ_REMOVE(&sp->wsnd, pq, pq_link); 481 pq->pduq = &sp->wsnd; // remember where you came from 482 } else 483 if((which & BIT(2)) && (pq = TAILQ_FIRST(&sp->csnd)) != NULL) { 484 sp->stats.ncsnd--; 485 TAILQ_REMOVE(&sp->csnd, pq, pq_link); 486 pq->pduq = &sp->csnd; // remember where you came from 487 } 488 iscsi_unlock_ex(&sp->snd_mtx); 489 490 return pq; 491 } 492 493 static __inline void 494 i_rqueue_pdu(isc_session_t *sp, pduq_t *pq) 495 { 496 iscsi_lock_ex(&sp->snd_mtx); 497 KASSERT(pq->pduq != NULL, ("pq->pduq is NULL")); 498 TAILQ_INSERT_TAIL(pq->pduq, pq, pq_link); 499 iscsi_unlock_ex(&sp->snd_mtx); 500 } 501 502 /* 503 | Waiting for ACK (or something :-) 504 */ 505 static __inline void 506 i_nqueue_hld(isc_session_t *sp, pduq_t *pq) 507 { 508 getmicrouptime(&pq->ts); 509 iscsi_lock_ex(&sp->hld_mtx); 510 if(++sp->stats.nhld > sp->stats.max_hld) 511 sp->stats.max_hld = sp->stats.nhld; 512 TAILQ_INSERT_TAIL(&sp->hld, pq, pq_link); 513 iscsi_unlock_ex(&sp->hld_mtx); 514 return; 515 } 516 517 static __inline void 518 i_remove_hld(isc_session_t *sp, pduq_t *pq) 519 { 520 iscsi_lock_ex(&sp->hld_mtx); 521 sp->stats.nhld--; 522 TAILQ_REMOVE(&sp->hld, pq, pq_link); 523 iscsi_unlock_ex(&sp->hld_mtx); 524 } 525 526 static __inline pduq_t * 527 i_dqueue_hld(isc_session_t *sp) 528 { 529 pduq_t *pq; 530 531 iscsi_lock_ex(&sp->hld_mtx); 532 if((pq = TAILQ_FIRST(&sp->hld)) != NULL) { 533 sp->stats.nhld--; 534 TAILQ_REMOVE(&sp->hld, pq, pq_link); 535 } 536 iscsi_unlock_ex(&sp->hld_mtx); 537 538 return pq; 539 } 540 541 static __inline pduq_t * 542 i_search_hld(isc_session_t *sp, int itt, int keep) 543 { 544 pduq_t *pq, *tmp; 545 546 pq = NULL; 547 548 iscsi_lock_ex(&sp->hld_mtx); 549 TAILQ_FOREACH_MUTABLE(pq, &sp->hld, pq_link, tmp) { 550 if(pq->pdu.ipdu.bhs.itt == itt) { 551 if(!keep) { 552 sp->stats.nhld--; 553 TAILQ_REMOVE(&sp->hld, pq, pq_link); 554 } 555 break; 556 } 557 } 558 iscsi_unlock_ex(&sp->hld_mtx); 559 560 return pq; 561 } 562 563 static __inline void 564 i_mbufcopy(struct mbuf *mp, caddr_t dp, int len) 565 { 566 struct mbuf *m; 567 caddr_t bp; 568 569 for(m = mp; m != NULL; m = m->m_next) { 570 bp = mtod(m, caddr_t); 571 /* 572 | the pdu is word (4 octed) aligned 573 | so len <= packet 574 */ 575 memcpy(dp, bp, MIN(len, m->m_len)); 576 dp += m->m_len; 577 len -= m->m_len; 578 if(len <= 0) 579 break; 580 } 581 } 582