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