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