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