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