1/*- 2 * Copyright (c) 2005-2011 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 */ 27/* 28 | $Id: iscsi.c 752 2009-08-20 11:23:28Z danny $ 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD$"); 33 34#include "opt_iscsi_initiator.h" 35 36#include <sys/param.h> 37#include <sys/capability.h> 38#include <sys/kernel.h> 39#include <sys/module.h> 40#include <sys/conf.h> 41#include <sys/bus.h> 42#include <sys/systm.h> 43#include <sys/malloc.h> 44#include <sys/ctype.h> 45#include <sys/errno.h> 46#include <sys/sysctl.h> 47#include <sys/file.h> 48#include <sys/uio.h> 49#include <sys/socketvar.h> 50#include <sys/socket.h> 51#include <sys/protosw.h> 52#include <sys/proc.h> 53#include <sys/ioccom.h> 54#include <sys/queue.h> 55#include <sys/kthread.h> 56#include <sys/mbuf.h> 57#include <sys/syslog.h> 58#include <vm/uma.h> 59#include <sys/sx.h> 60 61#include <dev/iscsi_initiator/iscsi.h> 62#include <dev/iscsi_initiator/iscsivar.h> 63static char *iscsi_driver_version = "2.3.1"; 64 65static struct isc_softc *isc; 66 67MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI driver"); 68MALLOC_DEFINE(M_ISCSIBUF, "iSCbuf", "iSCSI buffers"); 69static MALLOC_DEFINE(M_TMP, "iSCtmp", "iSCSI tmp"); 70 71#ifdef ISCSI_INITIATOR_DEBUG 72int iscsi_debug = ISCSI_INITIATOR_DEBUG; 73SYSCTL_INT(_debug, OID_AUTO, iscsi_initiator, CTLFLAG_RW, &iscsi_debug, 0, 74 "iSCSI driver debug flag"); 75 76struct mtx iscsi_dbg_mtx; 77#endif 78 79static int max_sessions = MAX_SESSIONS; 80SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_sessions, CTLFLAG_RDTUN, &max_sessions, MAX_SESSIONS, 81 "Max sessions allowed"); 82static int max_pdus = MAX_PDUS; 83SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_pdus, CTLFLAG_RDTUN, &max_pdus, MAX_PDUS, 84 "Max pdu pool"); 85 86static char isid[6+1] = { 87 0x80, 88 'D', 89 'I', 90 'B', 91 '0', 92 '0', 93 0 94}; 95 96static int i_create_session(struct cdev *dev, int *ndev); 97 98static int i_ping(struct cdev *dev); 99static int i_send(struct cdev *dev, caddr_t arg, struct thread *td); 100static int i_recv(struct cdev *dev, caddr_t arg, struct thread *td); 101static int i_setsoc(isc_session_t *sp, int fd, struct thread *td); 102static int i_fullfeature(struct cdev *dev, int flag); 103 104static d_open_t iscsi_open; 105static d_close_t iscsi_close; 106static d_ioctl_t iscsi_ioctl; 107#ifdef ISCSI_INITIATOR_DEBUG 108static d_read_t iscsi_read; 109#endif 110 111static struct cdevsw iscsi_cdevsw = { 112 .d_version = D_VERSION, 113 .d_open = iscsi_open, 114 .d_close = iscsi_close, 115 .d_ioctl = iscsi_ioctl, 116#ifdef ISCSI_INITIATOR_DEBUG 117 .d_read = iscsi_read, 118#endif 119 .d_name = "iSCSI", 120}; 121 122static int 123iscsi_open(struct cdev *dev, int flags, int otype, struct thread *td) 124{ 125 debug_called(8); 126 127 debug(7, "dev=%d", dev2unit(dev)); 128 129 if(dev2unit(dev) > max_sessions) { 130 // should not happen 131 return ENODEV; 132 } 133 return 0; 134} 135 136static int 137iscsi_close(struct cdev *dev, int flag, int otyp, struct thread *td) 138{ 139 isc_session_t *sp; 140 141 debug_called(8); 142 143 debug(3, "session=%d flag=%x", dev2unit(dev), flag); 144 145 if(dev2unit(dev) == max_sessions) { 146 return 0; 147 } 148 sp = dev->si_drv2; 149 if(sp != NULL) { 150 sdebug(3, "sp->flags=%x", sp->flags ); 151 /* 152 | if still in full phase, this probably means 153 | that something went realy bad. 154 | it could be a result from 'shutdown', in which case 155 | we will ignore it (so buffers can be flushed). 156 | the problem is that there is no way of differentiating 157 | between a shutdown procedure and 'iscontrol' dying. 158 */ 159 if(sp->flags & ISC_FFPHASE) 160 // delay in case this is a shutdown. 161 tsleep(sp, PRIBIO, "isc-cls", 60*hz); 162 ism_stop(sp); 163 } 164 debug(2, "done"); 165 return 0; 166} 167 168static int 169iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, struct thread *td) 170{ 171 struct isc_softc *sc; 172 isc_session_t *sp; 173 isc_opt_t *opt; 174 int error; 175 176 debug_called(8); 177 178 error = 0; 179 if(dev2unit(dev) == max_sessions) { 180 /* 181 | non Session commands 182 */ 183 sc = dev->si_drv1; 184 if(sc == NULL) 185 return ENXIO; 186 187 switch(cmd) { 188 case ISCSISETSES: 189 error = i_create_session(dev, (int *)arg); 190 if(error == 0) 191 break; 192 193 default: 194 error = ENXIO; 195 } 196 return error; 197 } 198 /* 199 | session commands 200 */ 201 sp = dev->si_drv2; 202 if(sp == NULL) 203 return ENXIO; 204 205 sdebug(6, "dev=%d cmd=%d", dev2unit(dev), (int)(cmd & 0xff)); 206 207 switch(cmd) { 208 case ISCSISETSOC: 209 error = i_setsoc(sp, *(u_int *)arg, td); 210 break; 211 212 case ISCSISETOPT: 213 opt = (isc_opt_t *)arg; 214 error = i_setopt(sp, opt); 215 break; 216 217 case ISCSISEND: 218 error = i_send(dev, arg, td); 219 break; 220 221 case ISCSIRECV: 222 error = i_recv(dev, arg, td); 223 break; 224 225 case ISCSIPING: 226 error = i_ping(dev); 227 break; 228 229 case ISCSISTART: 230 error = sp->soc == NULL? ENOTCONN: i_fullfeature(dev, 1); 231 if(error == 0) { 232 sp->proc = td->td_proc; 233 SYSCTL_ADD_INT(&sp->clist, SYSCTL_CHILDREN(sp->oid), 234 OID_AUTO, "pid", CTLFLAG_RD, 235 &sp->proc->p_pid, sizeof(pid_t), "control process id"); 236 } 237 break; 238 239 case ISCSIRESTART: 240 error = sp->soc == NULL? ENOTCONN: i_fullfeature(dev, 2); 241 break; 242 243 case ISCSISTOP: 244 error = i_fullfeature(dev, 0); 245 break; 246 247 case ISCSISIGNAL: { 248 int sig = *(int *)arg; 249 250 if(sig < 0 || sig > _SIG_MAXSIG) 251 error = EINVAL; 252 else 253 sp->signal = sig; 254 break; 255 } 256 257 case ISCSIGETCAM: { 258 iscsi_cam_t *cp = (iscsi_cam_t *)arg; 259 260 error = ic_getCamVals(sp, cp); 261 break; 262 } 263 264 default: 265 error = ENOIOCTL; 266 } 267 268 return error; 269} 270 271static int 272iscsi_read(struct cdev *dev, struct uio *uio, int ioflag) 273{ 274#ifdef ISCSI_INITIATOR_DEBUG 275 struct isc_softc *sc; 276 isc_session_t *sp; 277 pduq_t *pq; 278 char buf[1024]; 279 280 sc = dev->si_drv1; 281 sp = dev->si_drv2; 282 if(dev2unit(dev) == max_sessions) { 283 sprintf(buf, "/----- Session ------/\n"); 284 uiomove(buf, strlen(buf), uio); 285 int i = 0; 286 287 TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) { 288 if(uio->uio_resid == 0) 289 return 0; 290 sprintf(buf, "%03d] '%s' '%s'\n", i++, sp->opt.targetAddress, sp->opt.targetName); 291 uiomove(buf, strlen(buf), uio); 292 } 293 sprintf(buf, "free npdu_alloc=%d, npdu_max=%d\n", sc->npdu_alloc, sc->npdu_max); 294 uiomove(buf, strlen(buf), uio); 295 } 296 else { 297 int i = 0; 298 struct socket *so = sp->soc; 299#define pukeit(i, pq) do {\ 300 sprintf(buf, "%03d] %06x %02x %06x %06x %jd\n",\ 301 i, ntohl(pq->pdu.ipdu.bhs.CmdSN),\ 302 pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\ 303 ntohl(pq->pdu.ipdu.bhs.ExpStSN),\ 304 (intmax_t)pq->ts.sec);\ 305 } while(0) 306 307 sprintf(buf, "%d/%d /---- hld -----/\n", sp->stats.nhld, sp->stats.max_hld); 308 uiomove(buf, strlen(buf), uio); 309 TAILQ_FOREACH(pq, &sp->hld, pq_link) { 310 if(uio->uio_resid == 0) 311 return 0; 312 pukeit(i, pq); i++; 313 uiomove(buf, strlen(buf), uio); 314 } 315 sprintf(buf, "%d/%d /---- rsp -----/\n", sp->stats.nrsp, sp->stats.max_rsp); 316 uiomove(buf, strlen(buf), uio); 317 i = 0; 318 TAILQ_FOREACH(pq, &sp->rsp, pq_link) { 319 if(uio->uio_resid == 0) 320 return 0; 321 pukeit(i, pq); i++; 322 uiomove(buf, strlen(buf), uio); 323 } 324 sprintf(buf, "%d/%d /---- csnd -----/\n", sp->stats.ncsnd, sp->stats.max_csnd); 325 i = 0; 326 uiomove(buf, strlen(buf), uio); 327 TAILQ_FOREACH(pq, &sp->csnd, pq_link) { 328 if(uio->uio_resid == 0) 329 return 0; 330 pukeit(i, pq); i++; 331 uiomove(buf, strlen(buf), uio); 332 } 333 sprintf(buf, "%d/%d /---- wsnd -----/\n", sp->stats.nwsnd, sp->stats.max_wsnd); 334 i = 0; 335 uiomove(buf, strlen(buf), uio); 336 TAILQ_FOREACH(pq, &sp->wsnd, pq_link) { 337 if(uio->uio_resid == 0) 338 return 0; 339 pukeit(i, pq); i++; 340 uiomove(buf, strlen(buf), uio); 341 } 342 sprintf(buf, "%d/%d /---- isnd -----/\n", sp->stats.nisnd, sp->stats.max_isnd); 343 i = 0; 344 uiomove(buf, strlen(buf), uio); 345 TAILQ_FOREACH(pq, &sp->isnd, pq_link) { 346 if(uio->uio_resid == 0) 347 return 0; 348 pukeit(i, pq); i++; 349 uiomove(buf, strlen(buf), uio); 350 } 351 352 sprintf(buf, "/---- Stats ---/\n"); 353 uiomove(buf, strlen(buf), uio); 354 355 sprintf(buf, "recv=%d sent=%d\n", sp->stats.nrecv, sp->stats.nsent); 356 uiomove(buf, strlen(buf), uio); 357 358 sprintf(buf, "flags=%x pdus: alloc=%d max=%d\n", 359 sp->flags, sc->npdu_alloc, sc->npdu_max); 360 uiomove(buf, strlen(buf), uio); 361 362 sprintf(buf, "cws=%d last cmd=%x exp=%x max=%x stat=%x itt=%x\n", 363 sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt); 364 uiomove(buf, strlen(buf), uio); 365 366 sprintf(buf, "/---- socket -----/\nso_count=%d so_state=%x\n", so->so_count, so->so_state); 367 uiomove(buf, strlen(buf), uio); 368 369 } 370#endif 371 return 0; 372} 373 374static int 375i_ping(struct cdev *dev) 376{ 377 return 0; 378} 379/* 380 | low level I/O 381 */ 382static int 383i_setsoc(isc_session_t *sp, int fd, struct thread *td) 384{ 385 cap_rights_t rights; 386 int error = 0; 387 388 if(sp->soc != NULL) 389 isc_stop_receiver(sp); 390 391 error = fget(td, fd, cap_rights_init(&rights, CAP_SOCK_CLIENT), &sp->fp); 392 if(error) 393 return error; 394 395 error = fgetsock(td, fd, cap_rights_init(&rights, CAP_SOCK_CLIENT), 396 &sp->soc, 0); 397 if(error == 0) { 398 sp->td = td; 399 isc_start_receiver(sp); 400 } 401 else { 402 fdrop(sp->fp, td); 403 sp->fp = NULL; 404 } 405 406 return error; 407} 408 409static int 410i_send(struct cdev *dev, caddr_t arg, struct thread *td) 411{ 412 isc_session_t *sp = dev->si_drv2; 413 caddr_t bp; 414 pduq_t *pq; 415 pdu_t *pp; 416 int n, error; 417 418 debug_called(8); 419 420 if(sp->soc == NULL) 421 return ENOTCONN; 422 423 if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) 424 return EAGAIN; 425 pp = &pq->pdu; 426 pq->pdu = *(pdu_t *)arg; 427 if((error = i_prepPDU(sp, pq)) != 0) 428 goto out; 429 430 bp = NULL; 431 if((pq->len - sizeof(union ipdu_u)) > 0) { 432 pq->buf = bp = malloc(pq->len - sizeof(union ipdu_u), M_ISCSIBUF, M_NOWAIT); 433 if(pq->buf == NULL) { 434 error = EAGAIN; 435 goto out; 436 } 437 } 438 else 439 pq->buf = NULL; // just in case? 440 441 sdebug(2, "len=%d ahs_len=%d ds_len=%d buf=%zu@%p", 442 pq->len, pp->ahs_len, pp->ds_len, pq->len - sizeof(union ipdu_u), bp); 443 444 if(pp->ahs_len) { 445 // XXX: never tested, looks suspicious 446 n = pp->ahs_len; 447 error = copyin(pp->ahs_addr, bp, n); 448 if(error != 0) { 449 sdebug(3, "copyin ahs: error=%d", error); 450 goto out; 451 } 452 pp->ahs_addr = (ahs_t *)bp; 453 bp += n; 454 } 455 if(pp->ds_len) { 456 n = pp->ds_len; 457 error = copyin(pp->ds_addr, bp, n); 458 if(error != 0) { 459 sdebug(3, "copyin ds: error=%d", error); 460 goto out; 461 } 462 pp->ds_addr = bp; 463 bp += n; 464 while(n & 03) { 465 n++; 466 *bp++ = 0; 467 } 468 } 469 470 error = isc_qout(sp, pq); 471 if(error == 0) 472 wakeup(&sp->flags); // XXX: to 'push' proc_out ... 473out: 474 if(error) 475 pdu_free(sp->isc, pq); 476 477 return error; 478} 479 480static int 481i_recv(struct cdev *dev, caddr_t arg, struct thread *td) 482{ 483 isc_session_t *sp = dev->si_drv2; 484 pduq_t *pq; 485 pdu_t *pp, *up; 486 caddr_t bp; 487 int error, mustfree, cnt; 488 size_t need, have, n; 489 490 debug_called(8); 491 492 if(sp == NULL) 493 return EIO; 494 495 if(sp->soc == NULL) 496 return ENOTCONN; 497 cnt = 6; // XXX: maybe the user can request a time out? 498 mtx_lock(&sp->rsp_mtx); 499 while((pq = TAILQ_FIRST(&sp->rsp)) == NULL) { 500 msleep(&sp->rsp, &sp->rsp_mtx, PRIBIO, "isc_rsp", hz*10); 501 if(cnt-- == 0) break; // XXX: for now, needs work 502 } 503 if(pq != NULL) { 504 sp->stats.nrsp--; 505 TAILQ_REMOVE(&sp->rsp, pq, pq_link); 506 } 507 mtx_unlock(&sp->rsp_mtx); 508 509 sdebug(6, "cnt=%d", cnt); 510 511 if(pq == NULL) { 512 error = ENOTCONN; 513 sdebug(3, "error=%d sp->flags=%x ", error, sp->flags); 514 return error; 515 } 516 up = (pdu_t *)arg; 517 pp = &pq->pdu; 518 up->ipdu = pp->ipdu; 519 n = 0; 520 up->ds_len = 0; 521 up->ahs_len = 0; 522 error = 0; 523 524 if(pq->mp) { 525 u_int len; 526 527 // Grr... 528 len = 0; 529 if(pp->ahs_len) { 530 len += pp->ahs_len; 531 } 532 if(pp->ds_len) { 533 len += pp->ds_len; 534 } 535 536 mustfree = 0; 537 if(len > pq->mp->m_len) { 538 mustfree++; 539 bp = malloc(len, M_TMP, M_WAITOK); 540 sdebug(4, "need mbufcopy: %d", len); 541 i_mbufcopy(pq->mp, bp, len); 542 } 543 else 544 bp = mtod(pq->mp, caddr_t); 545 546 if(pp->ahs_len) { 547 need = pp->ahs_len; 548 n = MIN(up->ahs_size, need); 549 error = copyout(bp, (caddr_t)up->ahs_addr, n); 550 up->ahs_len = n; 551 bp += need; 552 } 553 if(!error && pp->ds_len) { 554 need = pp->ds_len; 555 if((have = up->ds_size) == 0) { 556 have = up->ahs_size - n; 557 up->ds_addr = (caddr_t)up->ahs_addr + n; 558 } 559 n = MIN(have, need); 560 error = copyout(bp, (caddr_t)up->ds_addr, n); 561 up->ds_len = n; 562 } 563 564 if(mustfree) 565 free(bp, M_TMP); 566 } 567 568 sdebug(6, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len); 569 570 pdu_free(sp->isc, pq); 571 572 return error; 573} 574 575static int 576i_fullfeature(struct cdev *dev, int flag) 577{ 578 isc_session_t *sp = dev->si_drv2; 579 int error; 580 581 sdebug(2, "flag=%d", flag); 582 583 error = 0; 584 switch(flag) { 585 case 0: // stop 586 sp->flags &= ~ISC_FFPHASE; 587 break; 588 case 1: // start 589 sp->flags |= ISC_FFPHASE; 590 error = ic_init(sp); 591 break; 592 case 2: // restart 593 sp->flags |= ISC_FFPHASE; 594 ism_restart(sp); 595 break; 596 } 597 return error; 598} 599 600static int 601i_create_session(struct cdev *dev, int *ndev) 602{ 603 struct isc_softc *sc = dev->si_drv1; 604 isc_session_t *sp; 605 int error, n; 606 607 debug_called(8); 608 609 sp = malloc(sizeof(isc_session_t), M_ISCSI, M_WAITOK | M_ZERO); 610 if(sp == NULL) 611 return ENOMEM; 612 613 sx_xlock(&sc->unit_sx); 614 if((n = alloc_unr(sc->unit)) < 0) { 615 sx_unlock(&sc->unit_sx); 616 free(sp, M_ISCSI); 617 xdebug("too many sessions!"); 618 return EPERM; 619 } 620 sx_unlock(&sc->unit_sx); 621 622 mtx_lock(&sc->isc_mtx); 623 TAILQ_INSERT_TAIL(&sc->isc_sess, sp, sp_link); 624 isc->nsess++; 625 mtx_unlock(&sc->isc_mtx); 626 627 sp->dev = make_dev(&iscsi_cdevsw, n, UID_ROOT, GID_WHEEL, 0600, "iscsi%d", n); 628 *ndev = sp->sid = n; 629 sp->isc = sc; 630 sp->dev->si_drv1 = sc; 631 sp->dev->si_drv2 = sp; 632 633 sp->opt.maxRecvDataSegmentLength = 8192; 634 sp->opt.maxXmitDataSegmentLength = 8192; 635 sp->opt.maxBurstLength = 65536; // 64k 636 sp->opt.maxluns = ISCSI_MAX_LUNS; 637 638 error = ism_start(sp); 639 640 return error; 641} 642 643#ifdef notused 644static void 645iscsi_counters(isc_session_t *sp) 646{ 647 int h, r, s; 648 pduq_t *pq; 649 650#define _puke(i, pq) do {\ 651 debug(2, "%03d] %06x %02x %x %ld %jd %x\n",\ 652 i, ntohl( pq->pdu.ipdu.bhs.CmdSN), \ 653 pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\ 654 (long)pq->ts.sec, pq->ts.frac, pq->flags);\ 655 } while(0) 656 657 h = r = s = 0; 658 TAILQ_FOREACH(pq, &sp->hld, pq_link) { 659 _puke(h, pq); 660 h++; 661 } 662 TAILQ_FOREACH(pq, &sp->rsp, pq_link) r++; 663 TAILQ_FOREACH(pq, &sp->csnd, pq_link) s++; 664 TAILQ_FOREACH(pq, &sp->wsnd, pq_link) s++; 665 TAILQ_FOREACH(pq, &sp->isnd, pq_link) s++; 666 debug(2, "hld=%d rsp=%d snd=%d", h, r, s); 667} 668#endif 669 670static void 671iscsi_shutdown(void *v) 672{ 673 struct isc_softc *sc = v; 674 isc_session_t *sp; 675 int n; 676 677 debug_called(8); 678 if(sc == NULL) { 679 xdebug("sc is NULL!"); 680 return; 681 } 682#ifdef DO_EVENTHANDLER 683 if(sc->eh == NULL) 684 debug(2, "sc->eh is NULL"); 685 else { 686 EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->eh); 687 debug(2, "done n=%d", sc->nsess); 688 } 689#endif 690 n = 0; 691 TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) { 692 debug(2, "%2d] sp->flags=0x%08x", n, sp->flags); 693 n++; 694 } 695 debug(2, "done"); 696} 697 698static void 699free_pdus(struct isc_softc *sc) 700{ 701 debug_called(8); 702 703 if(sc->pdu_zone != NULL) { 704 uma_zdestroy(sc->pdu_zone); 705 sc->pdu_zone = NULL; 706 } 707} 708 709static int 710iscsi_start(void) 711{ 712 debug_called(8); 713 714 TUNABLE_INT_FETCH("net.iscsi_initiator.max_sessions", &max_sessions); 715 TUNABLE_INT_FETCH("net.iscsi_initiator.max_pdus", &max_pdus); 716 717 isc = malloc(sizeof(struct isc_softc), M_ISCSI, M_ZERO|M_WAITOK); 718 mtx_init(&isc->isc_mtx, "iscsi-isc", NULL, MTX_DEF); 719 720 TAILQ_INIT(&isc->isc_sess); 721 /* 722 | now init the free pdu list 723 */ 724 isc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t), 725 NULL, NULL, NULL, NULL, 726 0, 0); 727 uma_zone_set_max(isc->pdu_zone, max_pdus); 728 isc->unit = new_unrhdr(0, max_sessions-1, NULL); 729 sx_init(&isc->unit_sx, "iscsi sx"); 730 731#ifdef DO_EVENTHANDLER 732 if((isc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown, 733 sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL) 734 xdebug("shutdown event registration failed\n"); 735#endif 736 /* 737 | sysctl stuff 738 */ 739 sysctl_ctx_init(&isc->clist); 740 isc->oid = SYSCTL_ADD_NODE(&isc->clist, 741 SYSCTL_STATIC_CHILDREN(_net), 742 OID_AUTO, 743 "iscsi_initiator", 744 CTLFLAG_RD, 745 0, 746 "iSCSI Subsystem"); 747 748 SYSCTL_ADD_STRING(&isc->clist, 749 SYSCTL_CHILDREN(isc->oid), 750 OID_AUTO, 751 "driver_version", 752 CTLFLAG_RD, 753 iscsi_driver_version, 754 0, 755 "iscsi driver version"); 756 757 SYSCTL_ADD_STRING(&isc->clist, 758 SYSCTL_CHILDREN(isc->oid), 759 OID_AUTO, 760 "isid", 761 CTLFLAG_RW, 762 isid, 763 6+1, 764 "initiator part of the Session Identifier"); 765 766 SYSCTL_ADD_INT(&isc->clist, 767 SYSCTL_CHILDREN(isc->oid), 768 OID_AUTO, 769 "sessions", 770 CTLFLAG_RD, 771 &isc->nsess, 772 sizeof(isc->nsess), 773 "number of active session"); 774 775#ifdef ISCSI_INITIATOR_DEBUG 776 mtx_init(&iscsi_dbg_mtx, "iscsi_dbg", NULL, MTX_DEF); 777#endif 778 779 isc->dev = make_dev_credf(MAKEDEV_CHECKNAME, &iscsi_cdevsw, max_sessions, 780 NULL, UID_ROOT, GID_WHEEL, 0600, "iscsi"); 781 if (isc->dev == NULL) { 782 xdebug("iscsi_initiator: make_dev_credf failed"); 783 return (EEXIST); 784 } 785 isc->dev->si_drv1 = isc; 786 787 printf("iscsi: version %s\n", iscsi_driver_version); 788 return (0); 789} 790 791/* 792 | Notes: 793 | unload SHOULD fail if there is activity 794 | activity: there is/are active session/s 795 */ 796static void 797iscsi_stop(void) 798{ 799 isc_session_t *sp, *sp_tmp; 800 801 debug_called(8); 802 803 /* 804 | go through all the sessions 805 | Note: close should have done this ... 806 */ 807 TAILQ_FOREACH_SAFE(sp, &isc->isc_sess, sp_link, sp_tmp) { 808 //XXX: check for activity ... 809 ism_stop(sp); 810 if(sp->cam_sim != NULL) 811 ic_destroy(sp); 812 } 813 mtx_destroy(&isc->isc_mtx); 814 sx_destroy(&isc->unit_sx); 815 816 free_pdus(isc); 817 818 if(isc->dev) 819 destroy_dev(isc->dev); 820 821 if(sysctl_ctx_free(&isc->clist)) 822 xdebug("sysctl_ctx_free failed"); 823 824 iscsi_shutdown(isc); // XXX: check EVENTHANDLER_ ... 825 826#ifdef ISCSI_INITIATOR_DEBUG 827 mtx_destroy(&iscsi_dbg_mtx); 828#endif 829 830 free(isc, M_ISCSI); 831} 832 833static int 834iscsi_modevent(module_t mod, int what, void *arg) 835{ 836 int error = 0; 837 838 debug_called(8); 839 840 switch(what) { 841 case MOD_LOAD: 842 error = iscsi_start(); 843 break; 844 845 case MOD_QUIESCE: 846 if(isc->nsess) { 847 xdebug("iscsi module busy(nsess=%d), cannot unload", isc->nsess); 848 log(LOG_ERR, "iscsi module busy, cannot unload"); 849 } 850 return isc->nsess; 851 852 case MOD_SHUTDOWN: 853 break; 854 855 case MOD_UNLOAD: 856 iscsi_stop(); 857 break; 858 859 default: 860 break; 861 } 862 return (error); 863} 864 865moduledata_t iscsi_mod = { 866 "iscsi_initiator", 867 (modeventhand_t) iscsi_modevent, 868 0 869}; 870 871#ifdef ISCSI_ROOT 872static void 873iscsi_rootconf(void) 874{ 875#if 0 876 nfs_setup_diskless(); 877 if (nfs_diskless_valid) 878 rootdevnames[0] = "nfs:"; 879#endif 880 printf("** iscsi_rootconf **\n"); 881} 882 883SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL) 884#endif 885 886DECLARE_MODULE(iscsi_initiator, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 887MODULE_DEPEND(iscsi_initiator, cam, 1, 1, 1); 888