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