xref: /dragonfly/sys/dev/disk/iscsi/initiator/iscsi.c (revision acdf1ee6)
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