iscsi.c revision 171568
1171568Sscottl/*- 2171568Sscottl * Copyright (c) 2005-2007 Daniel Braniss <danny@cs.huji.ac.il> 3171568Sscottl * All rights reserved. 4171568Sscottl * 5171568Sscottl * Redistribution and use in source and binary forms, with or without 6171568Sscottl * modification, are permitted provided that the following conditions 7171568Sscottl * are met: 8171568Sscottl * 1. Redistributions of source code must retain the above copyright 9171568Sscottl * notice, this list of conditions and the following disclaimer. 10171568Sscottl * 2. Redistributions in binary form must reproduce the above copyright 11171568Sscottl * notice, this list of conditions and the following disclaimer in the 12171568Sscottl * documentation and/or other materials provided with the distribution. 13171568Sscottl * 14171568Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15171568Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16171568Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17171568Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18171568Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19171568Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20171568Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21171568Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22171568Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23171568Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24171568Sscottl * SUCH DAMAGE. 25171568Sscottl * 26171568Sscottl */ 27171568Sscottl/* 28171568Sscottl | iSCSI 29171568Sscottl | $Id: iscsi.c,v 1.35 2007/04/22 08:58:29 danny Exp danny $ 30171568Sscottl */ 31171568Sscottl 32171568Sscottl#include <sys/cdefs.h> 33171568Sscottl__FBSDID("$FreeBSD: head/sys/dev/iscsi/initiator/iscsi.c 171568 2007-07-24 15:35:02Z scottl $"); 34171568Sscottl 35171568Sscottl#include "opt_iscsi_initiator.h" 36171568Sscottl 37171568Sscottl#include <sys/param.h> 38171568Sscottl#include <sys/kernel.h> 39171568Sscottl#include <sys/module.h> 40171568Sscottl#include <sys/conf.h> 41171568Sscottl#include <sys/bus.h> 42171568Sscottl#include <sys/systm.h> 43171568Sscottl#include <sys/malloc.h> 44171568Sscottl#include <sys/ctype.h> 45171568Sscottl#include <sys/errno.h> 46171568Sscottl#include <sys/sysctl.h> 47171568Sscottl#include <sys/file.h> 48171568Sscottl#include <sys/uio.h> 49171568Sscottl#include <sys/socketvar.h> 50171568Sscottl#include <sys/socket.h> 51171568Sscottl#include <sys/protosw.h> 52171568Sscottl#include <sys/proc.h> 53171568Sscottl#include <sys/ioccom.h> 54171568Sscottl#include <sys/queue.h> 55171568Sscottl#include <sys/kthread.h> 56171568Sscottl#include <sys/mbuf.h> 57171568Sscottl#include <sys/syslog.h> 58171568Sscottl#include <vm/uma.h> 59171568Sscottl 60171568Sscottl#include <dev/iscsi/initiator/iscsi.h> 61171568Sscottl#include <dev/iscsi/initiator/iscsivar.h> 62171568Sscottl 63171568Sscottlstatic char *iscsi_driver_version = "2.0.99"; 64171568Sscottl 65171568Sscottlstatic struct isc_softc isc; 66171568Sscottl 67171568SscottlMALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI driver"); 68171568Sscottl 69171568Sscottl#ifdef ISCSI_INITIATOR_DEBUG 70171568Sscottlint iscsi_debug = ISCSI_INITIATOR_DEBUG; 71171568SscottlSYSCTL_INT(_debug, OID_AUTO, iscsi_initiator, CTLFLAG_RW, &iscsi_debug, 0, 72171568Sscottl "iSCSI driver debug flag"); 73171568Sscottl 74171568Sscottlstruct mtx iscsi_dbg_mtx; 75171568Sscottl#endif 76171568Sscottl 77171568Sscottl 78171568Sscottlstatic char isid[6+1] = { 79171568Sscottl 0x80, 80171568Sscottl 'D', 81171568Sscottl 'I', 82171568Sscottl 'B', 83171568Sscottl '0', 84171568Sscottl '0', 85171568Sscottl 0 86171568Sscottl}; 87171568Sscottl 88171568Sscottlstatic int i_create_session(struct cdev *dev, int *ndev); 89171568Sscottl 90171568Sscottlstatic int i_ping(struct cdev *dev); 91171568Sscottlstatic int i_send(struct cdev *dev, caddr_t arg, struct thread *td); 92171568Sscottlstatic int i_recv(struct cdev *dev, caddr_t arg, struct thread *td); 93171568Sscottlstatic int i_setsoc(isc_session_t *sp, int fd, struct thread *td); 94171568Sscottl 95171568Sscottlstatic d_open_t iscsi_open; 96171568Sscottlstatic d_close_t iscsi_close; 97171568Sscottlstatic d_ioctl_t iscsi_ioctl; 98171568Sscottl#ifdef ISCSI_INITIATOR_DEBUG 99171568Sscottlstatic d_read_t iscsi_read; 100171568Sscottl#endif 101171568Sscottl 102171568Sscottlstatic struct cdevsw iscsi_cdevsw = { 103171568Sscottl .d_version = D_VERSION, 104171568Sscottl .d_open = iscsi_open, 105171568Sscottl .d_close = iscsi_close, 106171568Sscottl .d_ioctl = iscsi_ioctl, 107171568Sscottl#ifdef ISCSI_INITIATOR_DEBUG 108171568Sscottl .d_read = iscsi_read, 109171568Sscottl#endif 110171568Sscottl .d_name = "iSCSI", 111171568Sscottl}; 112171568Sscottl 113171568Sscottlstatic int 114171568Sscottliscsi_open(struct cdev *dev, int flags, int otype, struct thread *td) 115171568Sscottl{ 116171568Sscottl debug_called(8); 117171568Sscottl 118171568Sscottl debug(7, "dev=%d", minor(dev)); 119171568Sscottl 120171568Sscottl if(minor(dev) > MAX_SESSIONS) { 121171568Sscottl // should not happen 122171568Sscottl return ENODEV; 123171568Sscottl } 124171568Sscottl if(minor(dev) == MAX_SESSIONS) { 125171568Sscottl#if 1 126171568Sscottl struct isc_softc *sc = (struct isc_softc *)dev->si_drv1; 127171568Sscottl 128171568Sscottl // this should be in iscsi_start 129171568Sscottl if(sc->cam_sim == NULL) 130171568Sscottl ic_init(sc); 131171568Sscottl#endif 132171568Sscottl } 133171568Sscottl return 0; 134171568Sscottl} 135171568Sscottl 136171568Sscottlstatic int 137171568Sscottliscsi_close(struct cdev *dev, int flag, int otyp, struct thread *td) 138171568Sscottl{ 139171568Sscottl struct isc *sc; 140171568Sscottl isc_session_t *sp; 141171568Sscottl 142171568Sscottl debug_called(8); 143171568Sscottl 144171568Sscottl debug(3, "flag=%x", flag); 145171568Sscottl 146171568Sscottl sc = (struct isc *)dev->si_drv1; 147171568Sscottl if(minor(dev) == MAX_SESSIONS) { 148171568Sscottl return 0; 149171568Sscottl } 150171568Sscottl sp = (isc_session_t *)dev->si_drv2; 151171568Sscottl if(sp != NULL) { 152171568Sscottl sdebug(2, "session=%d flags=%x", minor(dev), sp->flags ); 153171568Sscottl /* 154171568Sscottl | if still in full phase, this probably means 155171568Sscottl | that something went realy bad. 156171568Sscottl | it could be a result from 'shutdown', in which case 157171568Sscottl | we will ignore it (so buffers can be flushed). 158171568Sscottl | the problem is that there is no way of differentiating 159171568Sscottl | between a shutdown procedure and 'iscontrol' dying. 160171568Sscottl */ 161171568Sscottl if(sp->flags & ISC_FFPHASE) 162171568Sscottl // delay in case this is a shutdown. 163171568Sscottl tsleep(sp, PRIBIO, "isc-cls", 60*hz); 164171568Sscottl ism_stop(sp); 165171568Sscottl } 166171568Sscottl debug(2, "done"); 167171568Sscottl return 0; 168171568Sscottl} 169171568Sscottl 170171568Sscottlstatic int 171171568Sscottliscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, struct thread *td) 172171568Sscottl{ 173171568Sscottl struct isc *sc; 174171568Sscottl isc_session_t *sp; 175171568Sscottl isc_opt_t *opt; 176171568Sscottl int error; 177171568Sscottl 178171568Sscottl sc = (struct isc *)dev->si_drv1; 179171568Sscottl debug_called(8); 180171568Sscottl 181171568Sscottl error = 0; 182171568Sscottl if(minor(dev) == MAX_SESSIONS) { 183171568Sscottl /* 184171568Sscottl | non Session commands 185171568Sscottl */ 186171568Sscottl if(sc == NULL) 187171568Sscottl return ENXIO; 188171568Sscottl 189171568Sscottl switch(cmd) { 190171568Sscottl case ISCSISETSES: 191171568Sscottl error = i_create_session(dev, (int *)arg); 192171568Sscottl if(error == 0) 193171568Sscottl 194171568Sscottl break; 195171568Sscottl 196171568Sscottl default: 197171568Sscottl error = ENXIO; // XXX: 198171568Sscottl } 199171568Sscottl return error; 200171568Sscottl } 201171568Sscottl sp = (isc_session_t *)dev->si_drv2; 202171568Sscottl /* 203171568Sscottl | session commands 204171568Sscottl */ 205171568Sscottl if(sp == NULL) 206171568Sscottl return ENXIO; 207171568Sscottl 208171568Sscottl sdebug(6, "dev=%d cmd=%d", minor(dev), (int)(cmd & 0xff)); 209171568Sscottl 210171568Sscottl switch(cmd) { 211171568Sscottl case ISCSISETSOC: 212171568Sscottl error = i_setsoc(sp, *(u_int *)arg, td); 213171568Sscottl break; 214171568Sscottl 215171568Sscottl case ISCSISETOPT: 216171568Sscottl opt = (isc_opt_t *)arg; 217171568Sscottl error = i_setopt(sp, opt); 218171568Sscottl break; 219171568Sscottl 220171568Sscottl case ISCSISEND: 221171568Sscottl error = i_send(dev, arg, td); 222171568Sscottl break; 223171568Sscottl 224171568Sscottl case ISCSIRECV: 225171568Sscottl error = i_recv(dev, arg, td); 226171568Sscottl break; 227171568Sscottl 228171568Sscottl case ISCSIPING: 229171568Sscottl error = i_ping(dev); 230171568Sscottl break; 231171568Sscottl 232171568Sscottl case ISCSISTART: 233171568Sscottl error = sp->soc == NULL? ENOTCONN: ism_fullfeature(dev, 1); 234171568Sscottl if(error == 0) { 235171568Sscottl sp->proc = td->td_proc; 236171568Sscottl SYSCTL_ADD_UINT(&sp->clist, 237171568Sscottl SYSCTL_CHILDREN(sp->oid), 238171568Sscottl OID_AUTO, 239171568Sscottl "pid", 240171568Sscottl CTLFLAG_RD, 241171568Sscottl &sp->proc->p_pid, sizeof(pid_t), "control process id"); 242171568Sscottl } 243171568Sscottl break; 244171568Sscottl 245171568Sscottl case ISCSIRESTART: 246171568Sscottl error = sp->soc == NULL? ENOTCONN: ism_fullfeature(dev, 2); 247171568Sscottl break; 248171568Sscottl 249171568Sscottl case ISCSISTOP: 250171568Sscottl error = ism_fullfeature(dev, 0); 251171568Sscottl break; 252171568Sscottl 253171568Sscottl case ISCSISIGNAL: { 254171568Sscottl int sig = *(int *)arg; 255171568Sscottl 256171568Sscottl if(sig < 0 || sig > _SIG_MAXSIG) 257171568Sscottl error = EINVAL; 258171568Sscottl else 259171568Sscottl sp->signal = sig; 260171568Sscottl break; 261171568Sscottl } 262171568Sscottl 263171568Sscottl case ISCSIGETCAM: { 264171568Sscottl iscsi_cam_t *cp = (iscsi_cam_t *)arg; 265171568Sscottl 266171568Sscottl error = ic_getCamVals(sp, cp); 267171568Sscottl break; 268171568Sscottl } 269171568Sscottl 270171568Sscottl default: 271171568Sscottl error = ENOIOCTL; 272171568Sscottl } 273171568Sscottl 274171568Sscottl return error; 275171568Sscottl} 276171568Sscottl 277171568Sscottlstatic int 278171568Sscottliscsi_read(struct cdev *dev, struct uio *uio, int ioflag) 279171568Sscottl{ 280171568Sscottl#ifdef ISCSI_INITIATOR_DEBUG 281171568Sscottl struct isc_softc *sc; 282171568Sscottl isc_session_t *sp; 283171568Sscottl pduq_t *pq; 284171568Sscottl char buf[1024]; 285171568Sscottl 286171568Sscottl sc = (struct isc_softc *)dev->si_drv1; 287171568Sscottl sp = (isc_session_t *)dev->si_drv2; 288171568Sscottl if(minor(dev) == MAX_SESSIONS) { 289171568Sscottl sprintf(buf, "/----- Session ------/\n"); 290171568Sscottl uiomove(buf, strlen(buf), uio); 291171568Sscottl int i = 0; 292171568Sscottl 293171568Sscottl TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) { 294171568Sscottl if(uio->uio_resid == 0) 295171568Sscottl return 0; 296171568Sscottl sprintf(buf, "%03d] '%s' '%s'\n", i++, sp->opt.targetAddress, sp->opt.targetName); 297171568Sscottl uiomove(buf, strlen(buf), uio); 298171568Sscottl } 299171568Sscottl } 300171568Sscottl else { 301171568Sscottl int i = 0; 302171568Sscottl struct socket *so = sp->soc; 303171568Sscottl#define pukeit(i, pq) do {\ 304171568Sscottl sprintf(buf, "%03d] %06x %02x %x %ld %jd\n",\ 305171568Sscottl i, ntohl( pq->pdu.ipdu.bhs.CmdSN), \ 306171568Sscottl pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\ 307171568Sscottl (long)pq->ts.sec, pq->ts.frac);\ 308171568Sscottl } while(0) 309171568Sscottl 310171568Sscottl sprintf(buf, "%d/%d /---- hld -----/\n", sp->stats.nhld, sp->stats.max_hld); 311171568Sscottl uiomove(buf, strlen(buf), uio); 312171568Sscottl TAILQ_FOREACH(pq, &sp->hld, pq_link) { 313171568Sscottl if(uio->uio_resid == 0) 314171568Sscottl return 0; 315171568Sscottl pukeit(i, pq); i++; 316171568Sscottl uiomove(buf, strlen(buf), uio); 317171568Sscottl } 318171568Sscottl sprintf(buf, "%d/%d /---- rsp -----/\n", sp->stats.nrsp, sp->stats.max_rsp); 319171568Sscottl uiomove(buf, strlen(buf), uio); 320171568Sscottl i = 0; 321171568Sscottl TAILQ_FOREACH(pq, &sp->rsp, pq_link) { 322171568Sscottl if(uio->uio_resid == 0) 323171568Sscottl return 0; 324171568Sscottl pukeit(i, pq); i++; 325171568Sscottl uiomove(buf, strlen(buf), uio); 326171568Sscottl } 327171568Sscottl sprintf(buf, "%d/%d /---- csnd -----/\n", sp->stats.ncsnd, sp->stats.max_csnd); 328171568Sscottl i = 0; 329171568Sscottl uiomove(buf, strlen(buf), uio); 330171568Sscottl TAILQ_FOREACH(pq, &sp->csnd, pq_link) { 331171568Sscottl if(uio->uio_resid == 0) 332171568Sscottl return 0; 333171568Sscottl pukeit(i, pq); i++; 334171568Sscottl uiomove(buf, strlen(buf), uio); 335171568Sscottl } 336171568Sscottl sprintf(buf, "%d/%d /---- wsnd -----/\n", sp->stats.nwsnd, sp->stats.max_wsnd); 337171568Sscottl i = 0; 338171568Sscottl uiomove(buf, strlen(buf), uio); 339171568Sscottl TAILQ_FOREACH(pq, &sp->wsnd, pq_link) { 340171568Sscottl if(uio->uio_resid == 0) 341171568Sscottl return 0; 342171568Sscottl pukeit(i, pq); i++; 343171568Sscottl uiomove(buf, strlen(buf), uio); 344171568Sscottl } 345171568Sscottl sprintf(buf, "%d/%d /---- isnd -----/\n", sp->stats.nisnd, sp->stats.max_isnd); 346171568Sscottl i = 0; 347171568Sscottl uiomove(buf, strlen(buf), uio); 348171568Sscottl TAILQ_FOREACH(pq, &sp->isnd, pq_link) { 349171568Sscottl if(uio->uio_resid == 0) 350171568Sscottl return 0; 351171568Sscottl pukeit(i, pq); i++; 352171568Sscottl uiomove(buf, strlen(buf), uio); 353171568Sscottl } 354171568Sscottl 355171568Sscottl sprintf(buf, "/---- Stats ---/\n"); 356171568Sscottl uiomove(buf, strlen(buf), uio); 357171568Sscottl 358171568Sscottl sprintf(buf, "recv=%d sent=%d\n", sp->stats.nrecv, sp->stats.nsent); 359171568Sscottl uiomove(buf, strlen(buf), uio); 360171568Sscottl 361171568Sscottl sprintf(buf, "flags=%x pdus: alloc=%d max=%d\n", 362171568Sscottl sp->flags, sc->npdu_alloc, sc->npdu_max); 363171568Sscottl uiomove(buf, strlen(buf), uio); 364171568Sscottl 365171568Sscottl sprintf(buf, "cws=%d last cmd=%x exp=%x max=%x stat=%x itt=%x\n", 366171568Sscottl sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt); 367171568Sscottl uiomove(buf, strlen(buf), uio); 368171568Sscottl 369171568Sscottl sprintf(buf, "/---- socket -----/\nso_count=%d so_state=%x\n", so->so_count, so->so_state); 370171568Sscottl uiomove(buf, strlen(buf), uio); 371171568Sscottl 372171568Sscottl } 373171568Sscottl#endif 374171568Sscottl return 0; 375171568Sscottl} 376171568Sscottl 377171568Sscottlstatic int 378171568Sscottli_ping(struct cdev *dev) 379171568Sscottl{ 380171568Sscottl return 0; 381171568Sscottl} 382171568Sscottl/* 383171568Sscottl | low level I/O 384171568Sscottl */ 385171568Sscottlstatic int 386171568Sscottli_setsoc(isc_session_t *sp, int fd, struct thread *td) 387171568Sscottl{ 388171568Sscottl int error = 0; 389171568Sscottl 390171568Sscottl if(sp->soc != NULL) 391171568Sscottl isc_stop_receiver(sp); 392171568Sscottl 393171568Sscottl error = fget(td, fd, &sp->fp); 394171568Sscottl if(error) 395171568Sscottl return error; 396171568Sscottl 397171568Sscottl if((error = fgetsock(td, fd, &sp->soc, 0)) == 0) { 398171568Sscottl sp->td = td; 399171568Sscottl isc_start_receiver(sp); 400171568Sscottl } 401171568Sscottl else { 402171568Sscottl fdrop(sp->fp, td); 403171568Sscottl sp->fp = NULL; 404171568Sscottl } 405171568Sscottl 406171568Sscottl return error; 407171568Sscottl} 408171568Sscottl 409171568Sscottlstatic int 410171568Sscottli_send(struct cdev *dev, caddr_t arg, struct thread *td) 411171568Sscottl{ 412171568Sscottl isc_session_t *sp = (isc_session_t *)dev->si_drv2; 413171568Sscottl struct isc_softc *sc = (struct isc_softc *)dev->si_drv1; 414171568Sscottl caddr_t bp; 415171568Sscottl pduq_t *pq; 416171568Sscottl pdu_t *pp; 417171568Sscottl int n, error; 418171568Sscottl 419171568Sscottl debug_called(8); 420171568Sscottl 421171568Sscottl if(sp->soc == NULL) 422171568Sscottl return ENOTCONN; 423171568Sscottl 424171568Sscottl if((pq = pdu_alloc(sc, 0)) == NULL) 425171568Sscottl return EAGAIN; 426171568Sscottl pp = &pq->pdu; 427171568Sscottl 428171568Sscottl pq->pdu = *(pdu_t *)arg; 429171568Sscottl if((error = i_prepPDU(sp, pq)) != 0) 430171568Sscottl return error; 431171568Sscottl 432171568Sscottl sdebug(4, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len); 433171568Sscottl 434171568Sscottl pq->buf = bp = malloc(pq->len - sizeof(union ipdu_u), M_ISCSI, M_WAITOK); 435171568Sscottl 436171568Sscottl if(pp->ahs_len) { 437171568Sscottl n = pp->ahs_len; 438171568Sscottl copyin(pp->ahs, bp, n); 439171568Sscottl pp->ahs = (ahs_t *)bp; 440171568Sscottl bp += n; 441171568Sscottl } 442171568Sscottl if(pp->ds_len) { 443171568Sscottl n = pp->ds_len; 444171568Sscottl copyin(pp->ds, bp, n); // can fail ... 445171568Sscottl pp->ds = bp; 446171568Sscottl bp += n; 447171568Sscottl while(n & 03) { 448171568Sscottl n++; 449171568Sscottl *bp++ = 0; 450171568Sscottl } 451171568Sscottl } 452171568Sscottl 453171568Sscottl error = isc_qout(sp, pq); 454171568Sscottl 455171568Sscottl return error; 456171568Sscottl} 457171568Sscottl 458171568Sscottl/* 459171568Sscottl | NOTE: must calculate digest if requiered. 460171568Sscottl */ 461171568Sscottlstatic int 462171568Sscottli_recv(struct cdev *dev, caddr_t arg, struct thread *td) 463171568Sscottl{ 464171568Sscottl isc_session_t *sp = (isc_session_t *)dev->si_drv2; 465171568Sscottl pduq_t *pq; 466171568Sscottl pdu_t *pp, *up; 467171568Sscottl caddr_t bp; 468171568Sscottl int error, mustfree, cnt; 469171568Sscottl size_t need, have, n; 470171568Sscottl 471171568Sscottl debug_called(8); 472171568Sscottl 473171568Sscottl if(sp == NULL) 474171568Sscottl return EIO; 475171568Sscottl 476171568Sscottl if(sp->soc == NULL) 477171568Sscottl return ENOTCONN; 478171568Sscottl cnt = 6; // XXX: maybe the user can request a time out? 479171568Sscottl mtx_lock(&sp->rsp_mtx); 480171568Sscottl while((pq = TAILQ_FIRST(&sp->rsp)) == NULL) { 481171568Sscottl msleep(&sp->rsp, &sp->rsp_mtx, PRIBIO, "isc_rsp", hz*10); 482171568Sscottl if(cnt-- == 0) break; // XXX: for now, needs work 483171568Sscottl } 484171568Sscottl if(pq != NULL) { 485171568Sscottl sp->stats.nrsp--; 486171568Sscottl TAILQ_REMOVE(&sp->rsp, pq, pq_link); 487171568Sscottl } 488171568Sscottl mtx_unlock(&sp->rsp_mtx); 489171568Sscottl 490171568Sscottl sdebug(3, "cnt=%d", cnt); 491171568Sscottl 492171568Sscottl if(pq == NULL) { 493171568Sscottl error = ENOTCONN; 494171568Sscottl sdebug(3, "error=%d sp->flags=%x ", error, sp->flags); 495171568Sscottl return error; 496171568Sscottl } 497171568Sscottl up = (pdu_t *)arg; 498171568Sscottl pp = &pq->pdu; 499171568Sscottl up->ipdu = pp->ipdu; 500171568Sscottl n = 0; 501171568Sscottl up->ds_len = 0; 502171568Sscottl up->ahs_len = 0; 503171568Sscottl error = 0; 504171568Sscottl 505171568Sscottl if(pq->mp) { 506171568Sscottl u_int len; 507171568Sscottl 508171568Sscottl // Grr... 509171568Sscottl len = 0; 510171568Sscottl if(pp->ahs_len) { 511171568Sscottl len += pp->ahs_len; 512171568Sscottl if(sp->hdrDigest) 513171568Sscottl len += 4; 514171568Sscottl } 515171568Sscottl if(pp->ds_len) { 516171568Sscottl len += pp->ds_len; 517171568Sscottl if(sp->hdrDigest) 518171568Sscottl len += 4; 519171568Sscottl } 520171568Sscottl 521171568Sscottl mustfree = 0; 522171568Sscottl if(len > pq->mp->m_len) { 523171568Sscottl mustfree++; 524171568Sscottl bp = malloc(len, M_ISCSI, M_WAITOK); 525171568Sscottl sdebug(4, "need mbufcopy: %d", len); 526171568Sscottl i_mbufcopy(pq->mp, bp, len); 527171568Sscottl } 528171568Sscottl else 529171568Sscottl bp = mtod(pq->mp, caddr_t); 530171568Sscottl 531171568Sscottl if(pp->ahs_len) { 532171568Sscottl need = pp->ahs_len; 533171568Sscottl if(sp->hdrDigest) 534171568Sscottl need += 4; 535171568Sscottl n = MIN(up->ahs_size, need); 536171568Sscottl error = copyout(bp, (caddr_t)up->ahs, n); 537171568Sscottl up->ahs_len = n; 538171568Sscottl bp += need; 539171568Sscottl } 540171568Sscottl if(!error && pp->ds_len) { 541171568Sscottl need = pp->ds_len; 542171568Sscottl if(sp->hdrDigest) 543171568Sscottl need += 4; 544171568Sscottl if((have = up->ds_size) == 0) { 545171568Sscottl have = up->ahs_size - n; 546171568Sscottl up->ds = (caddr_t)up->ahs + n; 547171568Sscottl } 548171568Sscottl n = MIN(have, need); 549171568Sscottl error = copyout(bp, (caddr_t)up->ds, n); 550171568Sscottl up->ds_len = n; 551171568Sscottl } 552171568Sscottl 553171568Sscottl if(mustfree) 554171568Sscottl free(bp, M_ISCSI); 555171568Sscottl } 556171568Sscottl 557171568Sscottl sdebug(6, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len); 558171568Sscottl 559171568Sscottl pdu_free(sp->isc, pq); 560171568Sscottl 561171568Sscottl return error; 562171568Sscottl} 563171568Sscottl 564171568Sscottlstatic int 565171568Sscottli_create_session(struct cdev *dev, int *ndev) 566171568Sscottl{ 567171568Sscottl struct isc_softc *sc = (struct isc_softc *)dev->si_drv1; 568171568Sscottl isc_session_t *sp; 569171568Sscottl int error, n; 570171568Sscottl 571171568Sscottl debug_called(8); 572171568Sscottl sp = (isc_session_t *)malloc(sizeof *sp, M_ISCSI, M_WAITOK | M_ZERO); 573171568Sscottl if(sp == NULL) 574171568Sscottl return ENOMEM; 575171568Sscottl mtx_lock(&sc->mtx); 576171568Sscottl /* 577171568Sscottl | search for the lowest unused sid 578171568Sscottl */ 579171568Sscottl for(n = 0; n < MAX_SESSIONS; n++) 580171568Sscottl if(sc->sessions[n] == NULL) 581171568Sscottl break; 582171568Sscottl if(n == MAX_SESSIONS) { 583171568Sscottl mtx_unlock(&sc->mtx); 584171568Sscottl free(sp, M_ISCSI); 585171568Sscottl return EPERM; 586171568Sscottl } 587171568Sscottl TAILQ_INSERT_TAIL(&sc->isc_sess, sp, sp_link); 588171568Sscottl sc->nsess++; 589171568Sscottl mtx_unlock(&sc->mtx); 590171568Sscottl 591171568Sscottl sc->sessions[n] = sp; 592171568Sscottl sp->dev = make_dev(&iscsi_cdevsw, n, UID_ROOT, GID_WHEEL, 0600, "iscsi%d", n); 593171568Sscottl *ndev = sp->sid = n; 594171568Sscottl sp->isc = sc; 595171568Sscottl sp->dev->si_drv1 = sc; 596171568Sscottl sp->dev->si_drv2 = sp; 597171568Sscottl 598171568Sscottl sp->opt.maxRecvDataSegmentLength = 8192; 599171568Sscottl sp->opt.maxXmitDataSegmentLength = 8192; 600171568Sscottl 601171568Sscottl sp->opt.maxBurstLength = 65536; // 64k 602171568Sscottl 603171568Sscottl sdebug(2, "sessionID=%d", n); 604171568Sscottl error = ism_start(sp); 605171568Sscottl 606171568Sscottl sdebug(2, "error=%d", error); 607171568Sscottl 608171568Sscottl return error; 609171568Sscottl} 610171568Sscottl 611171568Sscottl#ifdef notused 612171568Sscottlstatic void 613171568Sscottliscsi_counters(isc_session_t *sp) 614171568Sscottl{ 615171568Sscottl int h, r, s; 616171568Sscottl pduq_t *pq; 617171568Sscottl 618171568Sscottl#define _puke(i, pq) do {\ 619171568Sscottl debug(2, "%03d] %06x %02x %x %ld %jd %x\n",\ 620171568Sscottl i, ntohl( pq->pdu.ipdu.bhs.CmdSN), \ 621171568Sscottl pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\ 622171568Sscottl (long)pq->ts.sec, pq->ts.frac, pq->flags);\ 623171568Sscottl } while(0) 624171568Sscottl 625171568Sscottl h = r = s = 0; 626171568Sscottl TAILQ_FOREACH(pq, &sp->hld, pq_link) { 627171568Sscottl _puke(h, pq); 628171568Sscottl h++; 629171568Sscottl } 630171568Sscottl TAILQ_FOREACH(pq, &sp->rsp, pq_link) r++; 631171568Sscottl TAILQ_FOREACH(pq, &sp->csnd, pq_link) s++; 632171568Sscottl TAILQ_FOREACH(pq, &sp->wsnd, pq_link) s++; 633171568Sscottl TAILQ_FOREACH(pq, &sp->isnd, pq_link) s++; 634171568Sscottl debug(2, "hld=%d rsp=%d snd=%d", h, r, s); 635171568Sscottl} 636171568Sscottl#endif 637171568Sscottl 638171568Sscottlstatic void 639171568Sscottliscsi_shutdown(void *v) 640171568Sscottl{ 641171568Sscottl struct isc_softc *sc = (struct isc_softc *)v; 642171568Sscottl isc_session_t *sp; 643171568Sscottl int n; 644171568Sscottl 645171568Sscottl debug_called(8); 646171568Sscottl if(sc == NULL) { 647171568Sscottl xdebug("sc is NULL!"); 648171568Sscottl return; 649171568Sscottl } 650171568Sscottl if(sc->eh == NULL) 651171568Sscottl debug(2, "sc->eh is NULL!"); 652171568Sscottl else { 653171568Sscottl EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->eh); 654171568Sscottl debug(2, "done n=%d", sc->nsess); 655171568Sscottl } 656171568Sscottl n = 0; 657171568Sscottl TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) { 658171568Sscottl debug(2, "%2d] sp->flags=0x%08x", n, sp->flags); 659171568Sscottl n++; 660171568Sscottl } 661171568Sscottl} 662171568Sscottl 663171568Sscottlstatic void 664171568Sscottliscsi_start(void) 665171568Sscottl{ 666171568Sscottl struct isc_softc *sc = &isc; 667171568Sscottl 668171568Sscottl debug_called(8); 669171568Sscottl 670171568Sscottl memset(sc, 0, sizeof(struct isc_softc)); 671171568Sscottl 672171568Sscottl sc->dev = make_dev(&iscsi_cdevsw, MAX_SESSIONS, UID_ROOT, GID_WHEEL, 0600, "iscsi"); 673171568Sscottl sc->dev->si_drv1 = sc; 674171568Sscottl 675171568Sscottl TAILQ_INIT(&sc->isc_sess); 676171568Sscottl 677171568Sscottl sc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t), 678171568Sscottl NULL, NULL, NULL, NULL, 679171568Sscottl 0, 0); 680171568Sscottl if(sc->pdu_zone == NULL) { 681171568Sscottl printf("iscsi_initiator: uma_zcreate failed"); 682171568Sscottl // XXX: and now what? 683171568Sscottl } 684171568Sscottl uma_zone_set_max(sc->pdu_zone, MAX_PDUS*2+1); 685171568Sscottl mtx_init(&sc->mtx, "iscsi", NULL, MTX_DEF); 686171568Sscottl mtx_init(&sc->pdu_mtx, "iscsi pdu pool", NULL, MTX_DEF); 687171568Sscottl 688171568Sscottl#if 0 689171568Sscottl // XXX: this will cause a panic if the 690171568Sscottl // module is loaded too early 691171568Sscottl if(ic_init(sc) != 0) 692171568Sscottl return; 693171568Sscottl#else 694171568Sscottl sc->cam_sim = NULL; 695171568Sscottl#endif 696171568Sscottl if((sc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown, 697171568Sscottl sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL) 698171568Sscottl xdebug("shutdown event registration failed\n"); 699171568Sscottl /* 700171568Sscottl | sysctl stuff 701171568Sscottl */ 702171568Sscottl sysctl_ctx_init(&sc->clist); 703171568Sscottl sc->oid = SYSCTL_ADD_NODE(&sc->clist, 704171568Sscottl SYSCTL_STATIC_CHILDREN(_net), 705171568Sscottl OID_AUTO, 706171568Sscottl "iscsi", 707171568Sscottl CTLFLAG_RD, 708171568Sscottl 0, 709171568Sscottl "iSCSI Subsystem"); 710171568Sscottl 711171568Sscottl SYSCTL_ADD_STRING(&sc->clist, 712171568Sscottl SYSCTL_CHILDREN(sc->oid), 713171568Sscottl OID_AUTO, 714171568Sscottl "driver_version", 715171568Sscottl CTLFLAG_RD, 716171568Sscottl iscsi_driver_version, 717171568Sscottl 0, 718171568Sscottl "iscsi driver version"); 719171568Sscottl 720171568Sscottl SYSCTL_ADD_STRING(&sc->clist, 721171568Sscottl SYSCTL_CHILDREN(sc->oid), 722171568Sscottl OID_AUTO, 723171568Sscottl "isid", 724171568Sscottl CTLFLAG_RW, 725171568Sscottl isid, 726171568Sscottl 6+1, 727171568Sscottl "initiator part of the Session Identifier"); 728171568Sscottl 729171568Sscottl SYSCTL_ADD_INT(&sc->clist, 730171568Sscottl SYSCTL_CHILDREN(sc->oid), 731171568Sscottl OID_AUTO, 732171568Sscottl "sessions", 733171568Sscottl CTLFLAG_RD, 734171568Sscottl &sc->nsess, 735171568Sscottl sizeof(sc->nsess), 736171568Sscottl "number of active session"); 737171568Sscottl} 738171568Sscottl 739171568Sscottl/* 740171568Sscottl | Notes: 741171568Sscottl | unload SHOULD fail if there is activity 742171568Sscottl | activity: there is/are active session/s 743171568Sscottl */ 744171568Sscottlstatic void 745171568Sscottliscsi_stop(void) 746171568Sscottl{ 747171568Sscottl struct isc_softc *sc = &isc; 748171568Sscottl isc_session_t *sp, *sp_tmp; 749171568Sscottl 750171568Sscottl debug_called(8); 751171568Sscottl 752171568Sscottl /* 753171568Sscottl | go through all the sessions 754171568Sscottl | Note: close should have done this ... 755171568Sscottl */ 756171568Sscottl TAILQ_FOREACH_SAFE(sp, &sc->isc_sess, sp_link, sp_tmp) { 757171568Sscottl //XXX: check for activity ... 758171568Sscottl ism_stop(sp); 759171568Sscottl } 760171568Sscottl if(sc->cam_sim != NULL) 761171568Sscottl ic_destroy(sc); 762171568Sscottl 763171568Sscottl mtx_destroy(&sc->mtx); 764171568Sscottl mtx_destroy(&sc->pdu_mtx); 765171568Sscottl uma_zdestroy(sc->pdu_zone); 766171568Sscottl 767171568Sscottl if(sc->dev) 768171568Sscottl destroy_dev(sc->dev); 769171568Sscottl 770171568Sscottl if(sysctl_ctx_free(&sc->clist)) 771171568Sscottl xdebug("sysctl_ctx_free failed"); 772171568Sscottl} 773171568Sscottl 774171568Sscottlstatic int 775171568Sscottliscsi_modevent(module_t mod, int what, void *arg) 776171568Sscottl{ 777171568Sscottl debug_called(8); 778171568Sscottl 779171568Sscottl switch(what) { 780171568Sscottl case MOD_LOAD: 781171568Sscottl iscsi_start(); 782171568Sscottl break; 783171568Sscottl 784171568Sscottl case MOD_QUIESCE: 785171568Sscottl#if 1 786171568Sscottl if(isc.nsess) { 787171568Sscottl xdebug("iscsi module busy(nsess=%d), cannot unload", isc.nsess); 788171568Sscottl log(LOG_ERR, "iscsi module busy, cannot unload"); 789171568Sscottl } 790171568Sscottl return isc.nsess; 791171568Sscottl#endif 792171568Sscottl case MOD_SHUTDOWN: 793171568Sscottl break; 794171568Sscottl 795171568Sscottl case MOD_UNLOAD: 796171568Sscottl iscsi_stop(); 797171568Sscottl break; 798171568Sscottl 799171568Sscottl default: 800171568Sscottl break; 801171568Sscottl } 802171568Sscottl return 0; 803171568Sscottl} 804171568Sscottlmoduledata_t iscsi_mod = { 805171568Sscottl "iscsi", 806171568Sscottl (modeventhand_t) iscsi_modevent, 807171568Sscottl 0 808171568Sscottl}; 809171568Sscottl 810171568SscottlDECLARE_MODULE(iscsi, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 811