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