]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/dev/iscsi/initiator/isc_sm.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / dev / 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  */
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$");
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
67 static 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
77 static 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
106 static 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
126 static 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
142 static 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  */
164 static 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
193 static 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
258 int
259 i_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
301 int
302 isc_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  */
332 static void
333 ism_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
354 int
355 ism_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
377 void
378 ism_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 \f
458 /*
459  | go through the out queues looking for work
460  | if either nothing to do, or window is closed
461  | return.
462  */
463 static int
464 proc_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 \f
563 /*
564  | survives link breakdowns.
565  */
566 static void
567 ism_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
614 static int
615 isc_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
631 static int
632 isc_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
657 static int
658 isc_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      
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      snprintf(buf, sizeof(buf), "%s", *cp);
677      error = SYSCTL_OUT(req, buf, strlen(buf));
678      return error;
679 }
680      
681 static void
682 isc_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
727 void
728 ism_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
782 int
783 ism_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 }