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