xref: /dragonfly/sys/dev/disk/iscsi/initiator/isc_sm.c (revision fcf6efef)
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/isc_sm.c,v 1.3 2008/11/25 07:17:11 scottl Exp $
27e25c779eSMatthew Dillon  */
28e25c779eSMatthew Dillon /*
29e25c779eSMatthew Dillon  | iSCSI - Session Manager
30e25c779eSMatthew Dillon  | $Id: isc_sm.c,v 1.30 2007/04/22 09:53:09 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/conf.h>
38e25c779eSMatthew Dillon #include <sys/systm.h>
39e25c779eSMatthew Dillon #include <sys/malloc.h>
40e25c779eSMatthew Dillon #include <sys/ctype.h>
41e25c779eSMatthew Dillon #include <sys/errno.h>
42e25c779eSMatthew Dillon #include <sys/sysctl.h>
43e25c779eSMatthew Dillon #include <sys/file.h>
44e25c779eSMatthew Dillon #include <sys/uio.h>
45e25c779eSMatthew Dillon #include <sys/socketvar.h>
46e25c779eSMatthew Dillon #include <sys/socket.h>
47e25c779eSMatthew Dillon #include <sys/protosw.h>
48e25c779eSMatthew Dillon #include <sys/proc.h>
49e25c779eSMatthew Dillon #include <sys/queue.h>
50e25c779eSMatthew Dillon #include <sys/kthread.h>
51e25c779eSMatthew Dillon #include <sys/syslog.h>
52e25c779eSMatthew Dillon #include <sys/mbuf.h>
53e25c779eSMatthew Dillon #include <sys/bus.h>
54e25c779eSMatthew Dillon #include <sys/eventhandler.h>
55cd8ab232SMatthew Dillon 
56e25c779eSMatthew Dillon #include <sys/mutex2.h>
57cd8ab232SMatthew Dillon #include <sys/mplock2.h>
58e25c779eSMatthew Dillon 
59e25c779eSMatthew Dillon #include <bus/cam/cam.h>
60e25c779eSMatthew Dillon #include <bus/cam/cam_ccb.h>
61e25c779eSMatthew Dillon #include <bus/cam/cam_sim.h>
62e25c779eSMatthew Dillon #include <bus/cam/cam_xpt_sim.h>
63e25c779eSMatthew Dillon #include <bus/cam/cam_periph.h>
64e25c779eSMatthew Dillon 
65e25c779eSMatthew Dillon #include <dev/disk/iscsi/initiator/iscsi.h>
66e25c779eSMatthew Dillon #include <dev/disk/iscsi/initiator/iscsivar.h>
67e25c779eSMatthew Dillon 
68e25c779eSMatthew Dillon static void
_async(isc_session_t * sp,pduq_t * pq)69e25c779eSMatthew Dillon _async(isc_session_t *sp, pduq_t *pq)
70e25c779eSMatthew Dillon {
71e25c779eSMatthew Dillon      debug_called(8);
72e25c779eSMatthew Dillon 
73e25c779eSMatthew Dillon      iscsi_async(sp, pq);
74e25c779eSMatthew Dillon 
75e25c779eSMatthew Dillon      pdu_free(sp->isc, pq);
76e25c779eSMatthew Dillon }
77e25c779eSMatthew Dillon 
78e25c779eSMatthew Dillon static void
_reject(isc_session_t * sp,pduq_t * pq)79e25c779eSMatthew Dillon _reject(isc_session_t *sp, pduq_t *pq)
80e25c779eSMatthew Dillon {
81e25c779eSMatthew Dillon      pduq_t	*opq;
82e25c779eSMatthew Dillon      pdu_t	*pdu;
83e25c779eSMatthew Dillon      reject_t	*reject;
84e25c779eSMatthew Dillon      int	itt;
85e25c779eSMatthew Dillon 
86e25c779eSMatthew Dillon      debug_called(8);
87e25c779eSMatthew Dillon      pdu = mtod(pq->mp, pdu_t *);
88e25c779eSMatthew Dillon      itt = pdu->ipdu.bhs.itt;
89e25c779eSMatthew Dillon      reject = &pq->pdu.ipdu.reject;
90e25c779eSMatthew Dillon      sdebug(2, "itt=%x reason=0x%x", ntohl(itt), reject->reason);
91e25c779eSMatthew Dillon      opq = i_search_hld(sp, itt, 0);
92e25c779eSMatthew Dillon      if(opq != NULL)
93e25c779eSMatthew Dillon 	  iscsi_reject(sp, opq, pq);
94e25c779eSMatthew Dillon      else {
95e25c779eSMatthew Dillon 	  switch(pq->pdu.ipdu.bhs.opcode) {
96e25c779eSMatthew Dillon 	  case ISCSI_LOGOUT_CMD: // XXX: wasabi does this - can't figure out why
97e25c779eSMatthew Dillon 	       sdebug(2, "ISCSI_LOGOUT_CMD ...");
98e25c779eSMatthew Dillon 	       break;
99e25c779eSMatthew Dillon 	  default:
100e25c779eSMatthew Dillon 	       xdebug("%d] we lost something itt=%x",
101e25c779eSMatthew Dillon 		      sp->sid, ntohl(pq->pdu.ipdu.bhs.itt));
102e25c779eSMatthew Dillon 	  }
103e25c779eSMatthew Dillon      }
104e25c779eSMatthew Dillon      pdu_free(sp->isc, pq);
105e25c779eSMatthew Dillon }
106e25c779eSMatthew Dillon 
107e25c779eSMatthew Dillon static void
_r2t(isc_session_t * sp,pduq_t * pq)108e25c779eSMatthew Dillon _r2t(isc_session_t *sp, pduq_t *pq)
109e25c779eSMatthew Dillon {
110e25c779eSMatthew Dillon      pduq_t	*opq;
111e25c779eSMatthew Dillon 
112e25c779eSMatthew Dillon      debug_called(8);
113e25c779eSMatthew Dillon      opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1);
114e25c779eSMatthew Dillon      if(opq != NULL) {
115e25c779eSMatthew Dillon 	  iscsi_r2t(sp, opq, pq);
116e25c779eSMatthew Dillon      }
117e25c779eSMatthew Dillon      else {
118e25c779eSMatthew Dillon 	  r2t_t		*r2t = &pq->pdu.ipdu.r2t;
119e25c779eSMatthew Dillon 
120e25c779eSMatthew Dillon 	  xdebug("%d] we lost something itt=%x r2tSN=%d bo=%x ddtl=%x",
121e25c779eSMatthew Dillon 		 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt),
122e25c779eSMatthew Dillon 		 ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl));
123e25c779eSMatthew Dillon      }
124e25c779eSMatthew Dillon      pdu_free(sp->isc, pq);
125e25c779eSMatthew Dillon }
126e25c779eSMatthew Dillon 
127e25c779eSMatthew Dillon static void
_scsi_rsp(isc_session_t * sp,pduq_t * pq)128e25c779eSMatthew Dillon _scsi_rsp(isc_session_t *sp, pduq_t *pq)
129e25c779eSMatthew Dillon {
130e25c779eSMatthew Dillon      pduq_t	*opq;
131e25c779eSMatthew Dillon 
132e25c779eSMatthew Dillon      debug_called(8);
133e25c779eSMatthew Dillon      opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 0);
134e25c779eSMatthew Dillon      debug(5, "itt=%x pq=%p opq=%p", ntohl(pq->pdu.ipdu.bhs.itt), pq, opq);
135e25c779eSMatthew Dillon      if(opq != NULL)
136e25c779eSMatthew Dillon 	  iscsi_done(sp, opq, pq);
137e25c779eSMatthew Dillon      else
138e25c779eSMatthew Dillon 	  xdebug("%d] we lost something itt=%x",
139e25c779eSMatthew Dillon 		 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt));
140e25c779eSMatthew Dillon      pdu_free(sp->isc, pq);
141e25c779eSMatthew Dillon }
142e25c779eSMatthew Dillon 
143e25c779eSMatthew Dillon static void
_read_data(isc_session_t * sp,pduq_t * pq)144e25c779eSMatthew Dillon _read_data(isc_session_t *sp, pduq_t *pq)
145e25c779eSMatthew Dillon {
146e25c779eSMatthew Dillon      pduq_t		*opq;
147e25c779eSMatthew Dillon 
148e25c779eSMatthew Dillon      debug_called(8);
149e25c779eSMatthew Dillon      opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1);
150e25c779eSMatthew Dillon      if(opq != NULL) {
151e25c779eSMatthew Dillon 	  if(scsi_decap(sp, opq, pq) != 1) {
152e25c779eSMatthew Dillon 	       i_remove_hld(sp, opq); // done
153e25c779eSMatthew Dillon 	       pdu_free(sp->isc, opq);
154e25c779eSMatthew Dillon 	  }
155e25c779eSMatthew Dillon      }
156e25c779eSMatthew Dillon      else
157e25c779eSMatthew Dillon 	  xdebug("%d] we lost something itt=%x",
158e25c779eSMatthew Dillon 		 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt));
159e25c779eSMatthew Dillon      pdu_free(sp->isc, pq);
160e25c779eSMatthew Dillon }
161e25c779eSMatthew Dillon /*
162e25c779eSMatthew Dillon  | this is a kludge,
163e25c779eSMatthew Dillon  | the jury is not back with a veredict, user or kernel
164e25c779eSMatthew Dillon  */
165e25c779eSMatthew Dillon static void
_nop_out(isc_session_t * sp)166e25c779eSMatthew Dillon _nop_out(isc_session_t *sp)
167e25c779eSMatthew Dillon {
168e25c779eSMatthew Dillon      pduq_t	*pq;
169e25c779eSMatthew Dillon      nop_out_t	*nop_out;
170e25c779eSMatthew Dillon 
171e25c779eSMatthew Dillon      debug_called(8);
172e25c779eSMatthew Dillon 
173e25c779eSMatthew Dillon      sdebug(4, "cws=%d", sp->cws);
174e25c779eSMatthew Dillon      if(sp->cws == 0) {
175e25c779eSMatthew Dillon 	  /*
176e25c779eSMatthew Dillon 	   | only send a nop if window is closed.
177e25c779eSMatthew Dillon 	   */
178e25c779eSMatthew Dillon 	  if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL)
179e25c779eSMatthew Dillon 	       // I guess we ran out of resources
180e25c779eSMatthew Dillon 	       return;
181e25c779eSMatthew Dillon 	  nop_out = &pq->pdu.ipdu.nop_out;
182e25c779eSMatthew Dillon 	  nop_out->opcode = ISCSI_NOP_OUT;
183e25c779eSMatthew Dillon 	  nop_out->itt = htonl(sp->sn.itt);
184e25c779eSMatthew Dillon 	  nop_out->ttt = -1;
185e25c779eSMatthew Dillon 	  nop_out->I = 1;
186e25c779eSMatthew Dillon 	  nop_out->F = 1;
187e25c779eSMatthew Dillon 	  if(isc_qout(sp, pq) != 0) {
188e25c779eSMatthew Dillon 	       sdebug(1, "failed");
189e25c779eSMatthew Dillon 	       pdu_free(sp->isc, pq);
190e25c779eSMatthew Dillon 	  }
191e25c779eSMatthew Dillon      }
192e25c779eSMatthew Dillon }
193e25c779eSMatthew Dillon 
194e25c779eSMatthew Dillon static void
_nop_in(isc_session_t * sp,pduq_t * pq)195e25c779eSMatthew Dillon _nop_in(isc_session_t *sp, pduq_t *pq)
196e25c779eSMatthew Dillon {
197e25c779eSMatthew Dillon      pdu_t	*pp = &pq->pdu;
198e25c779eSMatthew Dillon      nop_in_t	*nop_in = &pp->ipdu.nop_in;
199e25c779eSMatthew Dillon      bhs_t	*bhs = &pp->ipdu.bhs;
200e25c779eSMatthew Dillon 
201e25c779eSMatthew Dillon      debug_called(8);
202e25c779eSMatthew Dillon 
203e25c779eSMatthew Dillon      sdebug(5, "itt=%x ttt=%x", htonl(nop_in->itt), htonl(nop_in->ttt));
204e25c779eSMatthew Dillon      if(nop_in->itt == -1) {
205e25c779eSMatthew Dillon 	  if(pp->ds_len != 0) {
206e25c779eSMatthew Dillon 	       /*
207e25c779eSMatthew Dillon 		| according to RFC 3720 this should be zero
208e25c779eSMatthew Dillon 		| what to do if not?
209e25c779eSMatthew Dillon 		*/
210e25c779eSMatthew Dillon 	       xdebug("%d] dslen not zero", sp->sid);
211e25c779eSMatthew Dillon 	  }
212e25c779eSMatthew Dillon 	  if(nop_in->ttt != -1) {
213e25c779eSMatthew Dillon 	       nop_out_t	*nop_out;
214e25c779eSMatthew Dillon 	       /*
215e25c779eSMatthew Dillon 		| target wants a nop_out
216e25c779eSMatthew Dillon 	        */
217e25c779eSMatthew Dillon 	       bhs->opcode = ISCSI_NOP_OUT;
218e25c779eSMatthew Dillon 	       bhs->I = 1;
219e25c779eSMatthew Dillon 	       bhs->F = 1;
220e25c779eSMatthew Dillon 	       /*
221e25c779eSMatthew Dillon 		| we are reusing the pdu, so bhs->ttt == nop_in->ttt;
222e25c779eSMatthew Dillon 		| and need to zero out 'Reserved'
223e25c779eSMatthew Dillon 		| small cludge here.
224e25c779eSMatthew Dillon 	        */
225e25c779eSMatthew Dillon 	       nop_out = &pp->ipdu.nop_out;
226e25c779eSMatthew Dillon 	       nop_out->sn.maxcmd = 0;
227e25c779eSMatthew Dillon 	       memset(nop_out->mbz, 0, sizeof(nop_out->mbz));
228e25c779eSMatthew Dillon 	       (void)isc_qout(sp, pq); //XXX: should check return?
229e25c779eSMatthew Dillon 	       return;
230e25c779eSMatthew Dillon 	  }
231e25c779eSMatthew Dillon 	  //else {
232e25c779eSMatthew Dillon 	       // just making noise?
233e25c779eSMatthew Dillon 	       // see 10.9.1: target does not want and answer.
234e25c779eSMatthew Dillon 	  //}
235e25c779eSMatthew Dillon 
236e25c779eSMatthew Dillon      } else
237e25c779eSMatthew Dillon      if(nop_in->ttt == -1) {
238e25c779eSMatthew Dillon 	  /*
239e25c779eSMatthew Dillon 	   | it is an answer to a nop_in from us
240e25c779eSMatthew Dillon 	   */
241e25c779eSMatthew Dillon 	  if(nop_in->itt != -1) {
242e25c779eSMatthew Dillon #ifdef ISC_WAIT4PING
243e25c779eSMatthew Dillon 	       // XXX: MUTEX please
244e25c779eSMatthew Dillon 	       if(sp->flags & ISC_WAIT4PING) {
245e25c779eSMatthew Dillon 		    i_nqueue_rsp(sp, pq);
246e25c779eSMatthew Dillon 		    wakeup(&sp->rsp);
247e25c779eSMatthew Dillon 		    return;
248e25c779eSMatthew Dillon 	       }
249e25c779eSMatthew Dillon #endif
250e25c779eSMatthew Dillon 	  }
251e25c779eSMatthew Dillon      }
252e25c779eSMatthew Dillon      /*
253e25c779eSMatthew Dillon       | drop it
254e25c779eSMatthew Dillon       */
255e25c779eSMatthew Dillon      pdu_free(sp->isc, pq);
256e25c779eSMatthew Dillon      return;
257e25c779eSMatthew Dillon }
258e25c779eSMatthew Dillon 
259e25c779eSMatthew Dillon int
i_prepPDU(isc_session_t * sp,pduq_t * pq)260e25c779eSMatthew Dillon i_prepPDU(isc_session_t *sp, pduq_t *pq)
261e25c779eSMatthew Dillon {
262e25c779eSMatthew Dillon      size_t	len, n;
263e25c779eSMatthew Dillon      pdu_t	*pp = &pq->pdu;
264e25c779eSMatthew Dillon      bhs_t	*bhp = &pp->ipdu.bhs;
265e25c779eSMatthew Dillon 
266e25c779eSMatthew Dillon      len = sizeof(bhs_t);
267e25c779eSMatthew Dillon      if(pp->ahs_len) {
268e25c779eSMatthew Dillon 	  len += pp->ahs_len;
269e25c779eSMatthew Dillon 	  bhp->AHSLength =  pp->ahs_len / 4;
270e25c779eSMatthew Dillon      }
271e25c779eSMatthew Dillon      if(sp->hdrDigest)
272e25c779eSMatthew Dillon 	  len += 4;
273e25c779eSMatthew Dillon      if(pp->ds_len) {
274e25c779eSMatthew Dillon 	  n = pp->ds_len;
275e25c779eSMatthew Dillon 	  len += n;
276e25c779eSMatthew Dillon #if BYTE_ORDER == LITTLE_ENDIAN
277e25c779eSMatthew Dillon 	  bhp->DSLength = ((n & 0x00ff0000) >> 16)
278e25c779eSMatthew Dillon 	       | (n & 0x0000ff00)
279e25c779eSMatthew Dillon 	       | ((n & 0x000000ff) << 16);
280e25c779eSMatthew Dillon #else
281e25c779eSMatthew Dillon 	  bhp->DSLength = n;
282e25c779eSMatthew Dillon #endif
283e25c779eSMatthew Dillon 	  if(len & 03) {
284e25c779eSMatthew Dillon 	       n = 4 - (len & 03);
285e25c779eSMatthew Dillon 	       len += n;
286e25c779eSMatthew Dillon 	  }
287e25c779eSMatthew Dillon 	  if(sp->dataDigest)
288e25c779eSMatthew Dillon 	       len += 4;
289e25c779eSMatthew Dillon      }
290e25c779eSMatthew Dillon 
291e25c779eSMatthew Dillon      pq->len = len;
292e25c779eSMatthew Dillon      len -= sizeof(bhs_t);
293e25c779eSMatthew Dillon      if(sp->opt.maxBurstLength && (len > sp->opt.maxBurstLength)) {
294e25c779eSMatthew Dillon 	  xdebug("%d] pdu len=%zd > %d",
295e25c779eSMatthew Dillon 		 sp->sid, len, sp->opt.maxBurstLength);
296e25c779eSMatthew Dillon 	  // XXX: when this happens it used to hang ...
297e25c779eSMatthew Dillon 	  return E2BIG;
298e25c779eSMatthew Dillon      }
299e25c779eSMatthew Dillon      return 0;
300e25c779eSMatthew Dillon }
301e25c779eSMatthew Dillon 
302e25c779eSMatthew Dillon int
isc_qout(isc_session_t * sp,pduq_t * pq)303e25c779eSMatthew Dillon isc_qout(isc_session_t *sp, pduq_t *pq)
304e25c779eSMatthew Dillon {
305e25c779eSMatthew Dillon      int error = 0;
306e25c779eSMatthew Dillon 
307e25c779eSMatthew Dillon      debug_called(8);
308e25c779eSMatthew Dillon 
309e25c779eSMatthew Dillon      if(pq->len == 0 && (error = i_prepPDU(sp, pq)))
310e25c779eSMatthew Dillon 	  return error;
311e25c779eSMatthew Dillon 
312e25c779eSMatthew Dillon      if(pq->pdu.ipdu.bhs.I)
313e25c779eSMatthew Dillon 	  i_nqueue_isnd(sp, pq);
314e25c779eSMatthew Dillon      else
315e25c779eSMatthew Dillon      if(pq->pdu.ipdu.data_out.opcode == ISCSI_WRITE_DATA)
316e25c779eSMatthew Dillon 	  i_nqueue_wsnd(sp, pq);
317e25c779eSMatthew Dillon      else
318e25c779eSMatthew Dillon 	  i_nqueue_csnd(sp, pq);
319e25c779eSMatthew Dillon 
320e25c779eSMatthew Dillon      sdebug(5, "enqued: pq=%p", pq);
321e25c779eSMatthew Dillon 
322e25c779eSMatthew Dillon      iscsi_lock_ex(&sp->io_mtx);
323e25c779eSMatthew Dillon      sp->flags |= ISC_OQNOTEMPTY;
324e25c779eSMatthew Dillon      if(sp->flags & ISC_OWAITING)
325e25c779eSMatthew Dillon 	  wakeup(&sp->flags);
326e25c779eSMatthew Dillon      iscsi_unlock_ex(&sp->io_mtx);
327e25c779eSMatthew Dillon 
328e25c779eSMatthew Dillon      return error;
329e25c779eSMatthew Dillon }
330e25c779eSMatthew Dillon /*
331e25c779eSMatthew Dillon  | called when a fullPhase is restarted
332e25c779eSMatthew Dillon  */
333e25c779eSMatthew Dillon static void
ism_restart(isc_session_t * sp)334e25c779eSMatthew Dillon ism_restart(isc_session_t *sp)
335e25c779eSMatthew Dillon {
336e25c779eSMatthew Dillon      int lastcmd;
337e25c779eSMatthew Dillon 
338e25c779eSMatthew Dillon      sdebug(2, "restart ...");
339e25c779eSMatthew Dillon      lastcmd = iscsi_requeue(sp);
340e25c779eSMatthew Dillon #if 0
341e25c779eSMatthew Dillon      if(lastcmd != sp->sn.cmd) {
342e25c779eSMatthew Dillon 	  sdebug(1, "resetting CmdSN to=%d (from %d)", lastcmd, sp->sn.cmd);
343e25c779eSMatthew Dillon 	  sp->sn.cmd = lastcmd;
344e25c779eSMatthew Dillon      }
345e25c779eSMatthew Dillon #endif
346e25c779eSMatthew Dillon      iscsi_lock_ex(&sp->io_mtx);
347e25c779eSMatthew Dillon      if(sp->flags & ISC_OWAITING) {
348e25c779eSMatthew Dillon 	  wakeup(&sp->flags);
349e25c779eSMatthew Dillon      }
350e25c779eSMatthew Dillon      iscsi_unlock_ex(&sp->io_mtx);
351e25c779eSMatthew Dillon 
352e25c779eSMatthew Dillon      sdebug(2, "restarted lastcmd=0x%x", lastcmd);
353e25c779eSMatthew Dillon }
354e25c779eSMatthew Dillon 
355e25c779eSMatthew Dillon int
ism_fullfeature(struct cdev * dev,int flag)356e25c779eSMatthew Dillon ism_fullfeature(struct cdev *dev, int flag)
357e25c779eSMatthew Dillon {
358e25c779eSMatthew Dillon      isc_session_t *sp = (isc_session_t *)dev->si_drv2;
359e25c779eSMatthew Dillon      int	error;
360e25c779eSMatthew Dillon 
361e25c779eSMatthew Dillon      sdebug(2, "flag=%d", flag);
362e25c779eSMatthew Dillon 
363e25c779eSMatthew Dillon      error = 0;
364e25c779eSMatthew Dillon      switch(flag) {
365e25c779eSMatthew Dillon      case 0: // stop
366e25c779eSMatthew Dillon 	  sp->flags &= ~ISC_FFPHASE;
367e25c779eSMatthew Dillon 	  break;
368e25c779eSMatthew Dillon      case 1: // start
369e25c779eSMatthew Dillon 	  error = ic_fullfeature(dev);
370e25c779eSMatthew Dillon 	  break;
371e25c779eSMatthew Dillon      case 2: // restart
372e25c779eSMatthew Dillon 	  ism_restart(sp);
373e25c779eSMatthew Dillon 	  break;
374e25c779eSMatthew Dillon      }
375e25c779eSMatthew Dillon      return error;
376e25c779eSMatthew Dillon }
377e25c779eSMatthew Dillon 
378e25c779eSMatthew Dillon void
ism_recv(isc_session_t * sp,pduq_t * pq)379e25c779eSMatthew Dillon ism_recv(isc_session_t *sp, pduq_t *pq)
380e25c779eSMatthew Dillon {
381e25c779eSMatthew Dillon      bhs_t	*bhs;
382e25c779eSMatthew Dillon      int	statSN;
383e25c779eSMatthew Dillon 
384e25c779eSMatthew Dillon      debug_called(8);
385e25c779eSMatthew Dillon 
386e25c779eSMatthew Dillon      bhs = &pq->pdu.ipdu.bhs;
387e25c779eSMatthew Dillon      statSN = ntohl(bhs->OpcodeSpecificFields[1]);
388e25c779eSMatthew Dillon #if 0
389e25c779eSMatthew Dillon      {
390e25c779eSMatthew Dillon 	  /*
391e25c779eSMatthew Dillon 	   | this code is only for debugging.
392e25c779eSMatthew Dillon 	   */
393e25c779eSMatthew Dillon 	  sn_t	*sn = &sp->sn;
394e25c779eSMatthew Dillon 	  if(sp->cws == 0) {
395e25c779eSMatthew Dillon 	       if((sp->flags & ISC_STALLED) == 0) {
396e25c779eSMatthew Dillon 		    sdebug(4, "window closed: max=0x%x exp=0x%x opcode=0x%x cmd=0x%x cws=%d.",
397e25c779eSMatthew Dillon 			   sn->maxCmd, sn->expCmd, bhs->opcode, sn->cmd, sp->cws);
398e25c779eSMatthew Dillon 		    sp->flags |= ISC_STALLED;
399e25c779eSMatthew Dillon 	       } else
400e25c779eSMatthew Dillon 	       if(sp->flags & ISC_STALLED) {
401e25c779eSMatthew Dillon 		    sdebug(4, "window opened: max=0x%x exp=0x%x opcode=0x%x cmd=0x%x cws=%d.",
402e25c779eSMatthew Dillon 			   sn->maxCmd, sn->expCmd, bhs->opcode, sn->cmd, sp->cws);
4033598cc14SSascha Wildner 		    sp->flags &= ~ISC_STALLED;
404e25c779eSMatthew Dillon 	       }
405e25c779eSMatthew Dillon 	  }
406e25c779eSMatthew Dillon      }
407e25c779eSMatthew Dillon #endif
408e25c779eSMatthew Dillon 
409e25c779eSMatthew Dillon #ifdef notyet
410e25c779eSMatthew Dillon      if(sp->sn.expCmd != sn->cmd) {
411e25c779eSMatthew Dillon 	  sdebug(1, "we lost something ... exp=0x%x cmd=0x%x",
412e25c779eSMatthew Dillon 		 sn->expCmd, sn->cmd);
413e25c779eSMatthew Dillon      }
414e25c779eSMatthew Dillon #endif
415e25c779eSMatthew Dillon      sdebug(5, "opcode=0x%x itt=0x%x stat#0x%x maxcmd=0x%0x",
416e25c779eSMatthew Dillon 	    bhs->opcode, ntohl(bhs->itt), statSN, sp->sn.maxCmd);
417e25c779eSMatthew Dillon 
418e25c779eSMatthew Dillon      switch(bhs->opcode) {
419e25c779eSMatthew Dillon      case ISCSI_READ_DATA: {
420e25c779eSMatthew Dillon 	  data_in_t 	*cmd = &pq->pdu.ipdu.data_in;
421e25c779eSMatthew Dillon 
422e25c779eSMatthew Dillon 	  if(cmd->S == 0)
423e25c779eSMatthew Dillon 	       break;
424e25c779eSMatthew Dillon      }
425e25c779eSMatthew Dillon 
426e25c779eSMatthew Dillon      default:
427e25c779eSMatthew Dillon 	  if(statSN > (sp->sn.stat + 1)) {
428e25c779eSMatthew Dillon 	       sdebug(1, "we lost some rec=0x%x exp=0x%x",
429e25c779eSMatthew Dillon 		      statSN, sp->sn.stat);
430e25c779eSMatthew Dillon 	       // XXX: must do some error recovery here.
431e25c779eSMatthew Dillon 	  }
432e25c779eSMatthew Dillon 	  sp->sn.stat = statSN;
433e25c779eSMatthew Dillon      }
434e25c779eSMatthew Dillon 
435e25c779eSMatthew Dillon      switch(bhs->opcode) {
436e25c779eSMatthew Dillon      case ISCSI_LOGIN_RSP:
437e25c779eSMatthew Dillon      case ISCSI_TEXT_RSP:
438e25c779eSMatthew Dillon      case ISCSI_LOGOUT_RSP:
439e25c779eSMatthew Dillon 	  i_nqueue_rsp(sp, pq);
440e25c779eSMatthew Dillon 	  wakeup(&sp->rsp);
441e25c779eSMatthew Dillon 	  sdebug(3, "wakeup rsp");
442e25c779eSMatthew Dillon 	  break;
443e25c779eSMatthew Dillon 
444e25c779eSMatthew Dillon      case ISCSI_NOP_IN:		_nop_in(sp, pq);	break;
445e25c779eSMatthew Dillon      case ISCSI_SCSI_RSP:	_scsi_rsp(sp, pq);	break;
446e25c779eSMatthew Dillon      case ISCSI_READ_DATA:	_read_data(sp, pq);	break;
447e25c779eSMatthew Dillon      case ISCSI_R2T:		_r2t(sp, pq);		break;
448e25c779eSMatthew Dillon      case ISCSI_REJECT:		_reject(sp, pq);	break;
449e25c779eSMatthew Dillon      case ISCSI_ASYNC:		_async(sp, pq);		break;
450e25c779eSMatthew Dillon 
451e25c779eSMatthew Dillon      case ISCSI_TASK_RSP:
452e25c779eSMatthew Dillon      default:
453e25c779eSMatthew Dillon 	  sdebug(1, "opcode=0x%x itt=0x%x not implemented yet",
454e25c779eSMatthew Dillon 		 bhs->opcode, ntohl(bhs->itt));
455e25c779eSMatthew Dillon 	  break;
456e25c779eSMatthew Dillon      }
457e25c779eSMatthew Dillon }
458e25c779eSMatthew Dillon 
459e25c779eSMatthew Dillon /*
460e25c779eSMatthew Dillon  | go through the out queues looking for work
461e25c779eSMatthew Dillon  | if either nothing to do, or window is closed
462e25c779eSMatthew Dillon  | return.
463e25c779eSMatthew Dillon  */
464e25c779eSMatthew Dillon static int
proc_out(isc_session_t * sp)465e25c779eSMatthew Dillon proc_out(isc_session_t *sp)
466e25c779eSMatthew Dillon {
467e25c779eSMatthew Dillon      sn_t	*sn = &sp->sn;
468e25c779eSMatthew Dillon      pduq_t	*pq;
469e25c779eSMatthew Dillon      int	error, ndone;
470e25c779eSMatthew Dillon      int	which;
471e25c779eSMatthew Dillon 
472e25c779eSMatthew Dillon      debug_called(8);
473e25c779eSMatthew Dillon      error = ndone = 0;
474e25c779eSMatthew Dillon 
475e25c779eSMatthew Dillon      while(sp->flags & ISC_LINK_UP) {
476e25c779eSMatthew Dillon 	  pdu_t *pp;
477e25c779eSMatthew Dillon 	  bhs_t	*bhs;
478e25c779eSMatthew Dillon 	  /*
479e25c779eSMatthew Dillon 	   | check if there is outstanding work in:
480e25c779eSMatthew Dillon 	   | 1- the Immediate queue
481e25c779eSMatthew Dillon 	   | 2- the R2T queue
482e25c779eSMatthew Dillon 	   | 3- the cmd queue, only if the command window allows it.
483e25c779eSMatthew Dillon 	   */
484e25c779eSMatthew Dillon 	  which = BIT(0) | BIT(1);
485e25c779eSMatthew Dillon 	  if(SNA_GT(sn->cmd, sn->maxCmd) == 0) // if(sn->maxCmd - sn->smc + 1) > 0
486e25c779eSMatthew Dillon 	       which |= BIT(2);
487e25c779eSMatthew Dillon 
488e25c779eSMatthew Dillon 	  sdebug(4, "which=%d sn->maxCmd=%d sn->cmd=%d", which, sn->maxCmd, sn->cmd);
489e25c779eSMatthew Dillon 
490e25c779eSMatthew Dillon 	  if((pq = i_dqueue_snd(sp, which)) == NULL)
491e25c779eSMatthew Dillon 	       break;
492e25c779eSMatthew Dillon 	  sdebug(4, "pq=%p", pq);
493e25c779eSMatthew Dillon 
494e25c779eSMatthew Dillon 	  pp = &pq->pdu;
495e25c779eSMatthew Dillon 	  bhs = &pp->ipdu.bhs;
496e25c779eSMatthew Dillon 	  switch(bhs->opcode) {
497e25c779eSMatthew Dillon 	  case ISCSI_SCSI_CMD:
498e25c779eSMatthew Dillon 	       sn->itt++;
499e25c779eSMatthew Dillon 	       bhs->itt = htonl(sn->itt);
500e25c779eSMatthew Dillon 
501e25c779eSMatthew Dillon 	  case ISCSI_LOGIN_CMD:
502e25c779eSMatthew Dillon 	  case ISCSI_TEXT_CMD:
503e25c779eSMatthew Dillon 	  case ISCSI_LOGOUT_CMD:
504e25c779eSMatthew Dillon 	  case ISCSI_SNACK:
505e25c779eSMatthew Dillon 	  case ISCSI_NOP_OUT:
506e25c779eSMatthew Dillon 	  case ISCSI_TASK_CMD:
507e25c779eSMatthew Dillon 	       bhs->CmdSN = htonl(sn->cmd);
508e25c779eSMatthew Dillon 	       if(bhs->I == 0)
509e25c779eSMatthew Dillon 		    sn->cmd++;
510e25c779eSMatthew Dillon 
511e25c779eSMatthew Dillon 	  case ISCSI_WRITE_DATA:
512e25c779eSMatthew Dillon 	       bhs->ExpStSN = htonl(sn->stat);
513e25c779eSMatthew Dillon 	       break;
514e25c779eSMatthew Dillon 
515e25c779eSMatthew Dillon 	  default:
516e25c779eSMatthew Dillon 	       // XXX: can this happen?
517e25c779eSMatthew Dillon 	       xdebug("bad opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)",
518e25c779eSMatthew Dillon 		      bhs->opcode,
519e25c779eSMatthew Dillon 		      sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt);
520e25c779eSMatthew Dillon 	       // XXX: and now?
521e25c779eSMatthew Dillon 	  }
522e25c779eSMatthew Dillon 
523e25c779eSMatthew Dillon 	  sdebug(4, "opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)",
524e25c779eSMatthew Dillon 		bhs->opcode,
525e25c779eSMatthew Dillon 		sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt);
526e25c779eSMatthew Dillon 
527e25c779eSMatthew Dillon 	  if(pq->ccb)
528e25c779eSMatthew Dillon 	       i_nqueue_hld(sp, pq);
529e25c779eSMatthew Dillon 
530e25c779eSMatthew Dillon 	  if((error = isc_sendPDU(sp, pq)) == 0) {
531e25c779eSMatthew Dillon 	       ndone++;
532e25c779eSMatthew Dillon 	       if(pq->ccb == NULL)
533e25c779eSMatthew Dillon 		    pdu_free(sp->isc, pq);
534e25c779eSMatthew Dillon 	  }
535e25c779eSMatthew Dillon 	  else {
536e25c779eSMatthew Dillon 	       xdebug("error=%d ndone=%d opcode=0x%x ccb=%p itt=%x",
537e25c779eSMatthew Dillon 		      error, ndone, bhs->opcode, pq->ccb, ntohl(bhs->itt));
538e25c779eSMatthew Dillon 	       if(pq->ccb)
539e25c779eSMatthew Dillon 		    i_remove_hld(sp, pq);
540e25c779eSMatthew Dillon 	       switch(error) {
541e25c779eSMatthew Dillon 	       case EPIPE:
542e25c779eSMatthew Dillon 		    sp->flags &= ~ISC_LINK_UP;
543e25c779eSMatthew Dillon 
544e25c779eSMatthew Dillon 	       case EAGAIN:
545e25c779eSMatthew Dillon 		    xdebug("requed");
546e25c779eSMatthew Dillon 		    i_rqueue_pdu(sp, pq);
547e25c779eSMatthew Dillon 		    break;
548e25c779eSMatthew Dillon 
549e25c779eSMatthew Dillon 	       default:
550e25c779eSMatthew Dillon 	       if(pq->ccb) {
551e25c779eSMatthew Dillon 			 xdebug("back to cam");
552e25c779eSMatthew Dillon 			 pq->ccb->ccb_h.status |= CAM_REQUEUE_REQ; // some better error?
553e25c779eSMatthew Dillon 			 XPT_DONE(sp->isc, pq->ccb);
554e25c779eSMatthew Dillon 			 pdu_free(sp->isc, pq);
555e25c779eSMatthew Dillon 	       }
556e25c779eSMatthew Dillon 		    else
557e25c779eSMatthew Dillon 			 xdebug("we lost it!");
558e25c779eSMatthew Dillon 	       }
559e25c779eSMatthew Dillon 	  }
560e25c779eSMatthew Dillon      }
561e25c779eSMatthew Dillon      return error;
562e25c779eSMatthew Dillon }
563e25c779eSMatthew Dillon 
564e25c779eSMatthew Dillon /*
565e25c779eSMatthew Dillon  | survives link breakdowns.
566e25c779eSMatthew Dillon  */
567e25c779eSMatthew Dillon static void
ism_proc(void * vp)568e25c779eSMatthew Dillon ism_proc(void *vp)
569e25c779eSMatthew Dillon {
570e25c779eSMatthew Dillon      isc_session_t 	*sp = (isc_session_t *)vp;
571e25c779eSMatthew Dillon      int		error;
572e25c779eSMatthew Dillon 
573cd8ab232SMatthew Dillon      get_mplock();
574e25c779eSMatthew Dillon      debug_called(8);
575e25c779eSMatthew Dillon 
576e25c779eSMatthew Dillon      sdebug(3, "started sp->flags=%x", sp->flags);
577e25c779eSMatthew Dillon      do {
578e25c779eSMatthew Dillon 	  if((sp->flags & ISC_HOLD) == 0) {
579e25c779eSMatthew Dillon 	       error = proc_out(sp);
580e25c779eSMatthew Dillon 	       if(error) {
581e25c779eSMatthew Dillon 		    sdebug(3, "error=%d", error);
582e25c779eSMatthew Dillon 	       }
583e25c779eSMatthew Dillon 	  }
584e25c779eSMatthew Dillon 	  iscsi_lock_ex(&sp->io_mtx);
585e25c779eSMatthew Dillon 	  if((sp->flags & ISC_LINK_UP) == 0) {
586e25c779eSMatthew Dillon 	       wakeup(&sp->soc);
587e25c779eSMatthew Dillon 	  }
588e25c779eSMatthew Dillon 
589e25c779eSMatthew Dillon 	  if((sp->flags & (ISC_OQNOTEMPTY | ISC_SM_RUN)) == ISC_SM_RUN) {
590e25c779eSMatthew Dillon 	       sp->flags |= ISC_OWAITING;
591e25c779eSMatthew Dillon 	       if(issleep(&sp->flags, &sp->io_mtx, 0, "iscproc", hz*30) == EWOULDBLOCK) {
592e25c779eSMatthew Dillon 		    if(sp->flags & ISC_CON_RUNNING)
593e25c779eSMatthew Dillon 		    _nop_out(sp);
594e25c779eSMatthew Dillon 	       }
595e25c779eSMatthew Dillon 	       sp->flags &= ~ISC_OWAITING;
596e25c779eSMatthew Dillon 	  }
597e25c779eSMatthew Dillon 	  sp->flags &= ~ISC_OQNOTEMPTY;
598e25c779eSMatthew Dillon 	  iscsi_unlock_ex(&sp->io_mtx);
599e25c779eSMatthew Dillon      } while(sp->flags & ISC_SM_RUN);
600e25c779eSMatthew Dillon 
601e25c779eSMatthew Dillon      sp->flags &= ~ISC_SM_RUNNING;
602e25c779eSMatthew Dillon      sdebug(3, "dropped ISC_SM_RUNNING");
603e25c779eSMatthew Dillon 
604e25c779eSMatthew Dillon      wakeup(sp);
605e25c779eSMatthew Dillon 
606e25c779eSMatthew Dillon      debug(3, "terminated sp=%p sp->sid=%d", sp, sp->sid);
607e25c779eSMatthew Dillon 
608cd8ab232SMatthew Dillon      rel_mplock();
609e25c779eSMatthew Dillon }
610e25c779eSMatthew Dillon 
611e25c779eSMatthew Dillon #if 0
612e25c779eSMatthew Dillon static int
613e25c779eSMatthew Dillon isc_dump_options(SYSCTL_HANDLER_ARGS)
614e25c779eSMatthew Dillon {
615e25c779eSMatthew Dillon      int error;
616e25c779eSMatthew Dillon      isc_session_t *sp;
617e25c779eSMatthew Dillon      char	buf[1024], *bp;
618e25c779eSMatthew Dillon 
619e25c779eSMatthew Dillon      sp = (isc_session_t *)arg1;
620e25c779eSMatthew Dillon      bp = buf;
621e25c779eSMatthew Dillon      ksprintf(bp, "targetname='%s'", sp->opt.targetName);
622e25c779eSMatthew Dillon      bp += strlen(bp);
623e25c779eSMatthew Dillon      ksprintf(bp, " targetname='%s'", sp->opt.targetAddress);
624e25c779eSMatthew Dillon      error = SYSCTL_OUT(req, buf, strlen(buf));
625e25c779eSMatthew Dillon      return error;
626e25c779eSMatthew Dillon }
627e25c779eSMatthew Dillon #endif
628e25c779eSMatthew Dillon 
629e25c779eSMatthew Dillon static int
isc_dump_stats(SYSCTL_HANDLER_ARGS)630e25c779eSMatthew Dillon isc_dump_stats(SYSCTL_HANDLER_ARGS)
631e25c779eSMatthew Dillon {
632e25c779eSMatthew Dillon      isc_session_t	*sp;
633e25c779eSMatthew Dillon      struct isc_softc	*sc;
634e25c779eSMatthew Dillon      char	buf[1024], *bp;
635e25c779eSMatthew Dillon      int 	error, n;
636e25c779eSMatthew Dillon 
637e25c779eSMatthew Dillon      sp = (isc_session_t *)arg1;
638e25c779eSMatthew Dillon      sc = sp->isc;
639e25c779eSMatthew Dillon 
640e25c779eSMatthew Dillon      bp = buf;
641e25c779eSMatthew Dillon      n = sizeof(buf);
642e25c779eSMatthew Dillon      ksnprintf(bp, n, "recv=%d sent=%d", sp->stats.nrecv, sp->stats.nsent);
643e25c779eSMatthew Dillon      bp += strlen(bp);
644e25c779eSMatthew Dillon      n -= strlen(bp);
645e25c779eSMatthew Dillon      ksnprintf(bp, n, " flags=0x%08x pdus-alloc=%d pdus-max=%d",
646e25c779eSMatthew Dillon 		  sp->flags, sc->npdu_alloc, sc->npdu_max);
647e25c779eSMatthew Dillon      bp += strlen(bp);
648e25c779eSMatthew Dillon      n -= strlen(bp);
649e25c779eSMatthew Dillon      ksnprintf(bp, n, " cws=%d cmd=%x exp=%x max=%x stat=%x itt=%x",
650e25c779eSMatthew Dillon 		  sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt);
651e25c779eSMatthew Dillon      error = SYSCTL_OUT(req, buf, strlen(buf));
652e25c779eSMatthew Dillon      return error;
653e25c779eSMatthew Dillon }
654e25c779eSMatthew Dillon 
655e25c779eSMatthew Dillon static int
isc_sysctl_targetName(SYSCTL_HANDLER_ARGS)656e25c779eSMatthew Dillon isc_sysctl_targetName(SYSCTL_HANDLER_ARGS)
657e25c779eSMatthew Dillon {
658e25c779eSMatthew Dillon      char	buf[128], **cp;
659e25c779eSMatthew Dillon      int 	error;
660e25c779eSMatthew Dillon 
661e25c779eSMatthew Dillon      cp = (char **)arg1;
662e25c779eSMatthew Dillon      ksnprintf(buf, sizeof(buf), "%s", *cp);
663e25c779eSMatthew Dillon      error = SYSCTL_OUT(req, buf, strlen(buf));
664e25c779eSMatthew Dillon      return error;
665e25c779eSMatthew Dillon }
666e25c779eSMatthew Dillon static int
isc_sysctl_targetAddress(SYSCTL_HANDLER_ARGS)667e25c779eSMatthew Dillon isc_sysctl_targetAddress(SYSCTL_HANDLER_ARGS)
668e25c779eSMatthew Dillon {
669e25c779eSMatthew Dillon      char	buf[128], **cp;
670e25c779eSMatthew Dillon      int 	error;
671e25c779eSMatthew Dillon 
672e25c779eSMatthew Dillon      cp = (char **)arg1;
673e25c779eSMatthew Dillon      ksnprintf(buf, sizeof(buf), "%s", *cp);
674e25c779eSMatthew Dillon      error = SYSCTL_OUT(req, buf, strlen(buf));
675e25c779eSMatthew Dillon      return error;
676e25c779eSMatthew Dillon }
677e25c779eSMatthew Dillon static void
isc_add_sysctls(isc_session_t * sp)678e25c779eSMatthew Dillon isc_add_sysctls(isc_session_t *sp)
679e25c779eSMatthew Dillon {
680e25c779eSMatthew Dillon      debug_called(8);
681e25c779eSMatthew Dillon      sdebug(6, "sid=%d %s", sp->sid, sp->dev->si_name);
682e25c779eSMatthew Dillon 
683e25c779eSMatthew Dillon      sysctl_ctx_init(&sp->clist);
684e25c779eSMatthew Dillon      sp->oid = SYSCTL_ADD_NODE(&sp->clist,
685e25c779eSMatthew Dillon 			       SYSCTL_CHILDREN(sp->isc->oid),
686e25c779eSMatthew Dillon 			       OID_AUTO,
687e25c779eSMatthew Dillon 			       sp->dev->si_name+5, // iscsi0
688e25c779eSMatthew Dillon 			       CTLFLAG_RD,
689e25c779eSMatthew Dillon 			       0,
690e25c779eSMatthew Dillon 			       "initiator");
691e25c779eSMatthew Dillon      SYSCTL_ADD_PROC(&sp->clist,
692e25c779eSMatthew Dillon 		     SYSCTL_CHILDREN(sp->oid),
693e25c779eSMatthew Dillon 		     OID_AUTO,
694e25c779eSMatthew Dillon 		     "targetname",
695e25c779eSMatthew Dillon 		     CTLFLAG_RD,
696e25c779eSMatthew Dillon 		     (void *)&sp->opt.targetName, 0,
697e25c779eSMatthew Dillon 		     isc_sysctl_targetName, "A", "target name");
698e25c779eSMatthew Dillon 
699e25c779eSMatthew Dillon      SYSCTL_ADD_PROC(&sp->clist,
700e25c779eSMatthew Dillon 		     SYSCTL_CHILDREN(sp->oid),
701e25c779eSMatthew Dillon 		     OID_AUTO,
702e25c779eSMatthew Dillon 		     "targeaddress",
703e25c779eSMatthew Dillon 		     CTLFLAG_RD,
704e25c779eSMatthew Dillon 		     (void *)&sp->opt.targetAddress, 0,
705e25c779eSMatthew Dillon 		     isc_sysctl_targetAddress, "A", "target address");
706e25c779eSMatthew Dillon 
707e25c779eSMatthew Dillon      SYSCTL_ADD_PROC(&sp->clist,
708e25c779eSMatthew Dillon 		     SYSCTL_CHILDREN(sp->oid),
709e25c779eSMatthew Dillon 		     OID_AUTO,
710e25c779eSMatthew Dillon 		     "stats",
711e25c779eSMatthew Dillon 		     CTLFLAG_RD,
712e25c779eSMatthew Dillon 		     (void *)sp, 0,
713e25c779eSMatthew Dillon 		     isc_dump_stats, "A", "statistics");
714e25c779eSMatthew Dillon 
715e25c779eSMatthew Dillon      SYSCTL_ADD_INT(&sp->clist,
716e25c779eSMatthew Dillon 		     SYSCTL_CHILDREN(sp->oid),
717e25c779eSMatthew Dillon 		     OID_AUTO,
718e25c779eSMatthew Dillon 		     "douio",
719e25c779eSMatthew Dillon 		     CTLFLAG_RW,
720e25c779eSMatthew Dillon 		     &sp->douio, 0, "enable uio on read");
721e25c779eSMatthew Dillon }
722e25c779eSMatthew Dillon 
723e25c779eSMatthew Dillon void
ism_stop(isc_session_t * sp)724e25c779eSMatthew Dillon ism_stop(isc_session_t *sp)
725e25c779eSMatthew Dillon {
726e25c779eSMatthew Dillon      struct isc_softc *sc = sp->isc;
727e25c779eSMatthew Dillon      cdev_t	dev;
728e25c779eSMatthew Dillon 
729e25c779eSMatthew Dillon      debug_called(8);
730e25c779eSMatthew Dillon      sdebug(2, "terminating");
731e25c779eSMatthew Dillon      /*
732e25c779eSMatthew Dillon       | first stop the receiver
733e25c779eSMatthew Dillon       */
734e25c779eSMatthew Dillon      isc_stop_receiver(sp);
735e25c779eSMatthew Dillon 
736e25c779eSMatthew Dillon      /*
737e25c779eSMatthew Dillon       | now stop the xmitter
738e25c779eSMatthew Dillon       */
739e25c779eSMatthew Dillon      sp->flags &= ~ISC_SM_RUN;
740e25c779eSMatthew Dillon      while(sp->flags & ISC_SM_RUNNING) {
741e25c779eSMatthew Dillon 	  sdebug(2, "waiting for ism to stop");
742e25c779eSMatthew Dillon 	  wakeup(&sp->flags);
743e25c779eSMatthew Dillon 	  tsleep(sp, 0, "-", hz);
744e25c779eSMatthew Dillon      }
745e25c779eSMatthew Dillon      sdebug(2, "ism stopped");
746e25c779eSMatthew Dillon      sp->flags &= ~ISC_FFPHASE;
747e25c779eSMatthew Dillon 
748e25c779eSMatthew Dillon      iscsi_cleanup(sp);
749e25c779eSMatthew Dillon 
750e25c779eSMatthew Dillon      (void)i_pdu_flush(sp);
751e25c779eSMatthew Dillon 
752e25c779eSMatthew Dillon      ic_lost_target(sp, sp->sid);
753e25c779eSMatthew Dillon 
754e25c779eSMatthew Dillon      lockmgr(&sc->lock, LK_EXCLUSIVE);
755e25c779eSMatthew Dillon      TAILQ_REMOVE(&sc->isc_sess, sp, sp_link);
756e25c779eSMatthew Dillon      sc->nsess--;
757e25c779eSMatthew Dillon      lockmgr(&sc->lock, LK_RELEASE);
758e25c779eSMatthew Dillon 
759e25c779eSMatthew Dillon      dev = sp->dev;
760e25c779eSMatthew Dillon      sp->dev = NULL;
761e25c779eSMatthew Dillon 
762e25c779eSMatthew Dillon      release_dev(dev);
763e25c779eSMatthew Dillon      destroy_dev(dev);
764e25c779eSMatthew Dillon 
765e25c779eSMatthew Dillon      mtx_uninit(&sp->rsp_mtx);
766e25c779eSMatthew Dillon      mtx_uninit(&sp->rsv_mtx);
767e25c779eSMatthew Dillon      mtx_uninit(&sp->hld_mtx);
768e25c779eSMatthew Dillon      mtx_uninit(&sp->snd_mtx);
769e25c779eSMatthew Dillon      mtx_uninit(&sp->io_mtx);
770e25c779eSMatthew Dillon 
771e25c779eSMatthew Dillon      i_freeopt(&sp->opt);
772e25c779eSMatthew Dillon      sc->sessions[sp->sid] = NULL;
773e25c779eSMatthew Dillon 
774e25c779eSMatthew Dillon      if(sysctl_ctx_free(&sp->clist))
775e25c779eSMatthew Dillon 	  xdebug("sysctl_ctx_free failed");
776e25c779eSMatthew Dillon 
777e25c779eSMatthew Dillon      kfree(sp, M_ISCSI);
778e25c779eSMatthew Dillon }
779e25c779eSMatthew Dillon 
780e25c779eSMatthew Dillon int
ism_start(isc_session_t * sp)781e25c779eSMatthew Dillon ism_start(isc_session_t *sp)
782e25c779eSMatthew Dillon {
783e25c779eSMatthew Dillon      debug_called(8);
784e25c779eSMatthew Dillon     /*
785e25c779eSMatthew Dillon      | now is a good time to do some initialization
786e25c779eSMatthew Dillon      */
787e25c779eSMatthew Dillon      TAILQ_INIT(&sp->rsp);
788e25c779eSMatthew Dillon      TAILQ_INIT(&sp->rsv);
789e25c779eSMatthew Dillon      TAILQ_INIT(&sp->csnd);
790e25c779eSMatthew Dillon      TAILQ_INIT(&sp->isnd);
791e25c779eSMatthew Dillon      TAILQ_INIT(&sp->wsnd);
792e25c779eSMatthew Dillon      TAILQ_INIT(&sp->hld);
793e25c779eSMatthew Dillon 
794*cabfc9f6SMatthew Dillon      mtx_init(&sp->rsv_mtx, "irsv");
795*cabfc9f6SMatthew Dillon      mtx_init(&sp->rsp_mtx, "irsp");
796*cabfc9f6SMatthew Dillon      mtx_init(&sp->snd_mtx, "isnd");
797*cabfc9f6SMatthew Dillon      mtx_init(&sp->hld_mtx, "ihld");
798e25c779eSMatthew Dillon 
799*cabfc9f6SMatthew Dillon      mtx_init(&sp->io_mtx, "isio");
800e25c779eSMatthew Dillon 
801e25c779eSMatthew Dillon      isc_add_sysctls(sp);
802e25c779eSMatthew Dillon 
803e25c779eSMatthew Dillon      sp->flags |= ISC_SM_RUN;
804e25c779eSMatthew Dillon      sp->flags |= ISC_SM_RUNNING;
805e25c779eSMatthew Dillon 
806e25c779eSMatthew Dillon      debug(4, "starting ism_proc: sp->sid=%d", sp->sid);
807e25c779eSMatthew Dillon      return kthread_create(ism_proc, sp, &sp->stp, "ism_%d", sp->sid);
808e25c779eSMatthew Dillon }
809