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