iscsi.c revision 331722
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: stable/11/sys/dev/iscsi_initiator/iscsi.c 331722 2018-03-29 02:50:57Z eadler $"); 33 34#include "opt_iscsi_initiator.h" 35 36#include <sys/param.h> 37#include <sys/capsicum.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, 81 &max_sessions, 0, "Max sessions allowed"); 82static int max_pdus = MAX_PDUS; 83SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_pdus, CTLFLAG_RDTUN, 84 &max_pdus, 0, "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 really 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 = getsock_cap(td, fd, cap_rights_init(&rights, CAP_SOCK_CLIENT), 392 &sp->fp, NULL, NULL); 393 if(error) 394 return error; 395 396 sp->soc = sp->fp->f_data; 397 sp->td = td; 398 isc_start_receiver(sp); 399 400 return error; 401} 402 403static int 404i_send(struct cdev *dev, caddr_t arg, struct thread *td) 405{ 406 isc_session_t *sp = dev->si_drv2; 407 caddr_t bp; 408 pduq_t *pq; 409 pdu_t *pp; 410 int n, error; 411 412 debug_called(8); 413 414 if(sp->soc == NULL) 415 return ENOTCONN; 416 417 if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) 418 return EAGAIN; 419 pp = &pq->pdu; 420 pq->pdu = *(pdu_t *)arg; 421 if((error = i_prepPDU(sp, pq)) != 0) 422 goto out; 423 424 bp = NULL; 425 if((pq->len - sizeof(union ipdu_u)) > 0) { 426 pq->buf = bp = malloc(pq->len - sizeof(union ipdu_u), M_ISCSIBUF, M_NOWAIT); 427 if(pq->buf == NULL) { 428 error = EAGAIN; 429 goto out; 430 } 431 } 432 else 433 pq->buf = NULL; // just in case? 434 435 sdebug(2, "len=%d ahs_len=%d ds_len=%d buf=%zu@%p", 436 pq->len, pp->ahs_len, pp->ds_len, pq->len - sizeof(union ipdu_u), bp); 437 438 if(pp->ahs_len) { 439 // XXX: never tested, looks suspicious 440 n = pp->ahs_len; 441 error = copyin(pp->ahs_addr, bp, n); 442 if(error != 0) { 443 sdebug(3, "copyin ahs: error=%d", error); 444 goto out; 445 } 446 pp->ahs_addr = (ahs_t *)bp; 447 bp += n; 448 } 449 if(pp->ds_len) { 450 n = pp->ds_len; 451 error = copyin(pp->ds_addr, bp, n); 452 if(error != 0) { 453 sdebug(3, "copyin ds: error=%d", error); 454 goto out; 455 } 456 pp->ds_addr = bp; 457 bp += n; 458 while(n & 03) { 459 n++; 460 *bp++ = 0; 461 } 462 } 463 464 error = isc_qout(sp, pq); 465 if(error == 0) 466 wakeup(&sp->flags); // XXX: to 'push' proc_out ... 467out: 468 if(error) 469 pdu_free(sp->isc, pq); 470 471 return error; 472} 473 474static int 475i_recv(struct cdev *dev, caddr_t arg, struct thread *td) 476{ 477 isc_session_t *sp = dev->si_drv2; 478 pduq_t *pq; 479 pdu_t *pp, *up; 480 caddr_t bp; 481 int error, mustfree, cnt; 482 size_t need, have, n; 483 484 debug_called(8); 485 486 if(sp == NULL) 487 return EIO; 488 489 if(sp->soc == NULL) 490 return ENOTCONN; 491 cnt = 6; // XXX: maybe the user can request a time out? 492 mtx_lock(&sp->rsp_mtx); 493 while((pq = TAILQ_FIRST(&sp->rsp)) == NULL) { 494 msleep(&sp->rsp, &sp->rsp_mtx, PRIBIO, "isc_rsp", hz*10); 495 if(cnt-- == 0) break; // XXX: for now, needs work 496 } 497 if(pq != NULL) { 498 sp->stats.nrsp--; 499 TAILQ_REMOVE(&sp->rsp, pq, pq_link); 500 } 501 mtx_unlock(&sp->rsp_mtx); 502 503 sdebug(6, "cnt=%d", cnt); 504 505 if(pq == NULL) { 506 error = ENOTCONN; 507 sdebug(3, "error=%d sp->flags=%x ", error, sp->flags); 508 return error; 509 } 510 up = (pdu_t *)arg; 511 pp = &pq->pdu; 512 up->ipdu = pp->ipdu; 513 n = 0; 514 up->ds_len = 0; 515 up->ahs_len = 0; 516 error = 0; 517 518 if(pq->mp) { 519 u_int len; 520 521 // Grr... 522 len = 0; 523 if(pp->ahs_len) { 524 len += pp->ahs_len; 525 } 526 if(pp->ds_len) { 527 len += pp->ds_len; 528 } 529 530 mustfree = 0; 531 if(len > pq->mp->m_len) { 532 mustfree++; 533 bp = malloc(len, M_TMP, M_WAITOK); 534 sdebug(4, "need mbufcopy: %d", len); 535 i_mbufcopy(pq->mp, bp, len); 536 } 537 else 538 bp = mtod(pq->mp, caddr_t); 539 540 if(pp->ahs_len) { 541 need = pp->ahs_len; 542 n = MIN(up->ahs_size, need); 543 error = copyout(bp, (caddr_t)up->ahs_addr, n); 544 up->ahs_len = n; 545 bp += need; 546 } 547 if(!error && pp->ds_len) { 548 need = pp->ds_len; 549 if((have = up->ds_size) == 0) { 550 have = up->ahs_size - n; 551 up->ds_addr = (caddr_t)up->ahs_addr + n; 552 } 553 n = MIN(have, need); 554 error = copyout(bp, (caddr_t)up->ds_addr, n); 555 up->ds_len = n; 556 } 557 558 if(mustfree) 559 free(bp, M_TMP); 560 } 561 562 sdebug(6, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len); 563 564 pdu_free(sp->isc, pq); 565 566 return error; 567} 568 569static int 570i_fullfeature(struct cdev *dev, int flag) 571{ 572 isc_session_t *sp = dev->si_drv2; 573 int error; 574 575 sdebug(2, "flag=%d", flag); 576 577 error = 0; 578 switch(flag) { 579 case 0: // stop 580 sp->flags &= ~ISC_FFPHASE; 581 break; 582 case 1: // start 583 sp->flags |= ISC_FFPHASE; 584 error = ic_init(sp); 585 break; 586 case 2: // restart 587 sp->flags |= ISC_FFPHASE; 588 ism_restart(sp); 589 break; 590 } 591 return error; 592} 593 594static int 595i_create_session(struct cdev *dev, int *ndev) 596{ 597 struct isc_softc *sc = dev->si_drv1; 598 isc_session_t *sp; 599 int error, n; 600 601 debug_called(8); 602 603 sp = malloc(sizeof(isc_session_t), M_ISCSI, M_WAITOK | M_ZERO); 604 if(sp == NULL) 605 return ENOMEM; 606 607 sx_xlock(&sc->unit_sx); 608 if((n = alloc_unr(sc->unit)) < 0) { 609 sx_unlock(&sc->unit_sx); 610 free(sp, M_ISCSI); 611 xdebug("too many sessions!"); 612 return EPERM; 613 } 614 sx_unlock(&sc->unit_sx); 615 616 mtx_lock(&sc->isc_mtx); 617 TAILQ_INSERT_TAIL(&sc->isc_sess, sp, sp_link); 618 isc->nsess++; 619 mtx_unlock(&sc->isc_mtx); 620 621 sp->dev = make_dev(&iscsi_cdevsw, n, UID_ROOT, GID_WHEEL, 0600, "iscsi%d", n); 622 *ndev = sp->sid = n; 623 sp->isc = sc; 624 sp->dev->si_drv1 = sc; 625 sp->dev->si_drv2 = sp; 626 627 sp->opt.maxRecvDataSegmentLength = 8192; 628 sp->opt.maxXmitDataSegmentLength = 8192; 629 sp->opt.maxBurstLength = 65536; // 64k 630 sp->opt.maxluns = ISCSI_MAX_LUNS; 631 632 error = ism_start(sp); 633 634 return error; 635} 636 637#ifdef notused 638static void 639iscsi_counters(isc_session_t *sp) 640{ 641 int h, r, s; 642 pduq_t *pq; 643 644#define _puke(i, pq) do {\ 645 debug(2, "%03d] %06x %02x %x %ld %jd %x\n",\ 646 i, ntohl( pq->pdu.ipdu.bhs.CmdSN), \ 647 pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\ 648 (long)pq->ts.sec, pq->ts.frac, pq->flags);\ 649 } while(0) 650 651 h = r = s = 0; 652 TAILQ_FOREACH(pq, &sp->hld, pq_link) { 653 _puke(h, pq); 654 h++; 655 } 656 TAILQ_FOREACH(pq, &sp->rsp, pq_link) r++; 657 TAILQ_FOREACH(pq, &sp->csnd, pq_link) s++; 658 TAILQ_FOREACH(pq, &sp->wsnd, pq_link) s++; 659 TAILQ_FOREACH(pq, &sp->isnd, pq_link) s++; 660 debug(2, "hld=%d rsp=%d snd=%d", h, r, s); 661} 662#endif 663 664static void 665iscsi_shutdown(void *v) 666{ 667 struct isc_softc *sc = v; 668 isc_session_t *sp; 669 int n; 670 671 debug_called(8); 672 if(sc == NULL) { 673 xdebug("sc is NULL!"); 674 return; 675 } 676#ifdef DO_EVENTHANDLER 677 if(sc->eh == NULL) 678 debug(2, "sc->eh is NULL"); 679 else { 680 EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->eh); 681 debug(2, "done n=%d", sc->nsess); 682 } 683#endif 684 n = 0; 685 TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) { 686 debug(2, "%2d] sp->flags=0x%08x", n, sp->flags); 687 n++; 688 } 689 debug(2, "done"); 690} 691 692static void 693free_pdus(struct isc_softc *sc) 694{ 695 debug_called(8); 696 697 if(sc->pdu_zone != NULL) { 698 uma_zdestroy(sc->pdu_zone); 699 sc->pdu_zone = NULL; 700 } 701} 702 703static int 704iscsi_start(void) 705{ 706 debug_called(8); 707 708 isc = malloc(sizeof(struct isc_softc), M_ISCSI, M_ZERO|M_WAITOK); 709 mtx_init(&isc->isc_mtx, "iscsi-isc", NULL, MTX_DEF); 710 711 TAILQ_INIT(&isc->isc_sess); 712 /* 713 | now init the free pdu list 714 */ 715 isc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t), 716 NULL, NULL, NULL, NULL, 717 0, 0); 718 uma_zone_set_max(isc->pdu_zone, max_pdus); 719 isc->unit = new_unrhdr(0, max_sessions-1, NULL); 720 sx_init(&isc->unit_sx, "iscsi sx"); 721 722#ifdef DO_EVENTHANDLER 723 if((isc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown, 724 sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL) 725 xdebug("shutdown event registration failed\n"); 726#endif 727 /* 728 | sysctl stuff 729 */ 730 sysctl_ctx_init(&isc->clist); 731 isc->oid = SYSCTL_ADD_NODE(&isc->clist, 732 SYSCTL_STATIC_CHILDREN(_net), 733 OID_AUTO, 734 "iscsi_initiator", 735 CTLFLAG_RD, 736 0, 737 "iSCSI Subsystem"); 738 739 SYSCTL_ADD_STRING(&isc->clist, 740 SYSCTL_CHILDREN(isc->oid), 741 OID_AUTO, 742 "driver_version", 743 CTLFLAG_RD, 744 iscsi_driver_version, 745 0, 746 "iscsi driver version"); 747 748 SYSCTL_ADD_STRING(&isc->clist, 749 SYSCTL_CHILDREN(isc->oid), 750 OID_AUTO, 751 "isid", 752 CTLFLAG_RW, 753 isid, 754 6+1, 755 "initiator part of the Session Identifier"); 756 757 SYSCTL_ADD_INT(&isc->clist, 758 SYSCTL_CHILDREN(isc->oid), 759 OID_AUTO, 760 "sessions", 761 CTLFLAG_RD, 762 &isc->nsess, 763 sizeof(isc->nsess), 764 "number of active session"); 765 766#ifdef ISCSI_INITIATOR_DEBUG 767 mtx_init(&iscsi_dbg_mtx, "iscsi_dbg", NULL, MTX_DEF); 768#endif 769 770 isc->dev = make_dev_credf(MAKEDEV_CHECKNAME, &iscsi_cdevsw, max_sessions, 771 NULL, UID_ROOT, GID_WHEEL, 0600, "iscsi"); 772 if (isc->dev == NULL) { 773 xdebug("iscsi_initiator: make_dev_credf failed"); 774 return (EEXIST); 775 } 776 isc->dev->si_drv1 = isc; 777 778 printf("iscsi: version %s\n", iscsi_driver_version); 779 return (0); 780} 781 782/* 783 | Notes: 784 | unload SHOULD fail if there is activity 785 | activity: there is/are active session/s 786 */ 787static void 788iscsi_stop(void) 789{ 790 isc_session_t *sp, *sp_tmp; 791 792 debug_called(8); 793 794 /* 795 | go through all the sessions 796 | Note: close should have done this ... 797 */ 798 TAILQ_FOREACH_SAFE(sp, &isc->isc_sess, sp_link, sp_tmp) { 799 //XXX: check for activity ... 800 ism_stop(sp); 801 } 802 mtx_destroy(&isc->isc_mtx); 803 sx_destroy(&isc->unit_sx); 804 805 free_pdus(isc); 806 807 if(isc->dev) 808 destroy_dev(isc->dev); 809 810 if(sysctl_ctx_free(&isc->clist)) 811 xdebug("sysctl_ctx_free failed"); 812 813 iscsi_shutdown(isc); // XXX: check EVENTHANDLER_ ... 814 815#ifdef ISCSI_INITIATOR_DEBUG 816 mtx_destroy(&iscsi_dbg_mtx); 817#endif 818 819 free(isc, M_ISCSI); 820} 821 822static int 823iscsi_modevent(module_t mod, int what, void *arg) 824{ 825 int error = 0; 826 827 debug_called(8); 828 829 switch(what) { 830 case MOD_LOAD: 831 error = iscsi_start(); 832 break; 833 834 case MOD_QUIESCE: 835 if(isc->nsess) { 836 xdebug("iscsi module busy(nsess=%d), cannot unload", isc->nsess); 837 log(LOG_ERR, "iscsi module busy, cannot unload"); 838 } 839 return isc->nsess; 840 841 case MOD_SHUTDOWN: 842 break; 843 844 case MOD_UNLOAD: 845 iscsi_stop(); 846 break; 847 848 default: 849 break; 850 } 851 return (error); 852} 853 854moduledata_t iscsi_mod = { 855 "iscsi_initiator", 856 (modeventhand_t) iscsi_modevent, 857 0 858}; 859 860#ifdef ISCSI_ROOT 861static void 862iscsi_rootconf(void) 863{ 864#if 0 865 nfs_setup_diskless(); 866 if (nfs_diskless_valid) 867 rootdevnames[0] = "nfs:"; 868#endif 869 printf("** iscsi_rootconf **\n"); 870} 871 872SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL) 873#endif 874 875DECLARE_MODULE(iscsi_initiator, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 876MODULE_DEPEND(iscsi_initiator, cam, 1, 1, 1); 877