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