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