xref: /NextBSD/sys/dev/iscsi_initiator/isc_sm.c (revision 287e3b14e9552995def1802ec9c5034f4adf28ec)
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 
60 #include <cam/cam.h>
61 #include <cam/cam_ccb.h>
62 #include <cam/cam_sim.h>
63 #include <cam/cam_xpt_sim.h>
64 #include <cam/cam_periph.h>
65 
66 #include <dev/iscsi_initiator/iscsi.h>
67 #include <dev/iscsi_initiator/iscsivar.h>
68 
69 static void
_async(isc_session_t * sp,pduq_t * pq)70 _async(isc_session_t *sp, pduq_t *pq)
71 {
72      debug_called(8);
73 
74      iscsi_async(sp, pq);
75 
76      pdu_free(sp->isc, pq);
77 }
78 
79 static void
_reject(isc_session_t * sp,pduq_t * pq)80 _reject(isc_session_t *sp, pduq_t *pq)
81 {
82      pduq_t	*opq;
83      pdu_t	*pdu;
84      reject_t	*reject;
85      int	itt;
86 
87      debug_called(8);
88      pdu = mtod(pq->mp, pdu_t *);
89      itt = pdu->ipdu.bhs.itt;
90      reject = &pq->pdu.ipdu.reject;
91      sdebug(2, "itt=%x reason=0x%x", ntohl(itt), reject->reason);
92      opq = i_search_hld(sp, itt, 0);
93      if(opq != NULL)
94 	  iscsi_reject(sp, opq, pq);
95      else {
96 	  switch(pq->pdu.ipdu.bhs.opcode) {
97 	  case ISCSI_LOGOUT_CMD: // XXX: wasabi does this - can't figure out why
98 	       sdebug(2, "ISCSI_LOGOUT_CMD ...");
99 	       break;
100 	  default:
101 	       xdebug("%d] we lost something itt=%x",
102 		      sp->sid, ntohl(pq->pdu.ipdu.bhs.itt));
103 	  }
104      }
105      pdu_free(sp->isc, pq);
106 }
107 
108 static void
_r2t(isc_session_t * sp,pduq_t * pq)109 _r2t(isc_session_t *sp, pduq_t *pq)
110 {
111      pduq_t	*opq;
112 
113      debug_called(8);
114      opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1);
115      if(opq != NULL) {
116 	  iscsi_r2t(sp, opq, pq);
117      }
118      else {
119 	  r2t_t		*r2t = &pq->pdu.ipdu.r2t;
120 
121 	  xdebug("%d] we lost something itt=%x r2tSN=%d bo=%x ddtl=%x",
122 		 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt),
123 		 ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl));
124      }
125      pdu_free(sp->isc, pq);
126 }
127 
128 static void
_scsi_rsp(isc_session_t * sp,pduq_t * pq)129 _scsi_rsp(isc_session_t *sp, pduq_t *pq)
130 {
131      pduq_t	*opq;
132 
133      debug_called(8);
134      opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 0);
135      debug(5, "itt=%x pq=%p opq=%p", ntohl(pq->pdu.ipdu.bhs.itt), pq, opq);
136      if(opq != NULL) {
137 	  iscsi_done(sp, opq, pq);
138 	  i_acked_hld(sp, &pq->pdu);
139      }
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
_read_data(isc_session_t * sp,pduq_t * pq)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
_nop_out(isc_session_t * sp)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
_nop_in(isc_session_t * sp,pduq_t * pq)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
i_prepPDU(isc_session_t * sp,pduq_t * pq)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(ISOK2DIG(sp->hdrDigest, pp))
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(ISOK2DIG(sp->dataDigest, pp))
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
isc_qout(isc_session_t * sp,pduq_t * pq)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      mtx_lock(&sp->io_mtx);
326      sp->flags |= ISC_OQNOTEMPTY;
327      if(sp->flags & ISC_OWAITING)
328 	  wakeup(&sp->flags);
329      mtx_unlock(&sp->io_mtx);
330 
331      return error;
332 }
333 /*
334  | called when a fullPhase is restarted
335  */
336 void
ism_restart(isc_session_t * sp)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      mtx_lock(&sp->io_mtx);
350      if(sp->flags & ISC_OWAITING) {
351 	  wakeup(&sp->flags);
352      }
353      mtx_unlock(&sp->io_mtx);
354 
355      sdebug(2, "restarted sn.cmd=0x%x lastcmd=0x%x", sp->sn.cmd, lastcmd);
356 }
357 
358 void
ism_recv(isc_session_t * sp,pduq_t * pq)359 ism_recv(isc_session_t *sp, pduq_t *pq)
360 {
361      bhs_t	*bhs;
362      int	statSN;
363 
364      debug_called(8);
365 
366      bhs = &pq->pdu.ipdu.bhs;
367      statSN = ntohl(bhs->OpcodeSpecificFields[1]);
368 
369 #ifdef notyet
370      if(sp->sn.expCmd != sn->cmd) {
371 	  sdebug(1, "we lost something ... exp=0x%x cmd=0x%x",
372 		 sn->expCmd, sn->cmd);
373      }
374 #endif
375      sdebug(5, "opcode=0x%x itt=0x%x stat#0x%x maxcmd=0x%0x",
376 	    bhs->opcode, ntohl(bhs->itt), statSN, sp->sn.maxCmd);
377 
378      switch(bhs->opcode) {
379      case ISCSI_READ_DATA: {
380 	  data_in_t 	*cmd = &pq->pdu.ipdu.data_in;
381 
382 	  if(cmd->S == 0)
383 	       break;
384      }
385 
386      default:
387 	  if(statSN > (sp->sn.stat + 1)) {
388 	       sdebug(1, "we lost some rec=0x%x exp=0x%x",
389 		      statSN, sp->sn.stat);
390 	       // XXX: must do some error recovery here.
391 	  }
392 	  sp->sn.stat = statSN;
393      }
394 
395      switch(bhs->opcode) {
396      case ISCSI_LOGIN_RSP:
397      case ISCSI_TEXT_RSP:
398      case ISCSI_LOGOUT_RSP:
399 	  i_nqueue_rsp(sp, pq);
400 	  wakeup(&sp->rsp);
401 	  sdebug(3, "wakeup rsp");
402 	  break;
403 
404      case ISCSI_NOP_IN:		_nop_in(sp, pq);	break;
405      case ISCSI_SCSI_RSP:	_scsi_rsp(sp, pq);	break;
406      case ISCSI_READ_DATA:	_read_data(sp, pq);	break;
407      case ISCSI_R2T:		_r2t(sp, pq);		break;
408      case ISCSI_REJECT:		_reject(sp, pq);	break;
409      case ISCSI_ASYNC:		_async(sp, pq);		break;
410 
411      case ISCSI_TASK_RSP:
412      default:
413 	  sdebug(1, "opcode=0x%x itt=0x%x not implemented yet",
414 		 bhs->opcode, ntohl(bhs->itt));
415 	  break;
416      }
417 }
418 
419 /*
420  | go through the out queues looking for work
421  | if either nothing to do, or window is closed
422  | return.
423  */
424 static int
proc_out(isc_session_t * sp)425 proc_out(isc_session_t *sp)
426 {
427      sn_t	*sn = &sp->sn;
428      pduq_t	*pq;
429      int	error, which;
430 
431      debug_called(8);
432      error = 0;
433 
434      while(sp->flags & ISC_LINK_UP) {
435 	  pdu_t *pp;
436 	  bhs_t	*bhs;
437 	  /*
438 	   | check if there is outstanding work in:
439 	   | 1- the Immediate queue
440 	   | 2- the R2T queue
441 	   | 3- the cmd queue, only if the command window allows it.
442 	   */
443 	  which = BIT(0) | BIT(1);
444 	  if(SNA_GT(sn->cmd, sn->maxCmd) == 0) // if(sn->maxCmd - sn->smc + 1) > 0
445 	       which |= BIT(2);
446 
447 	  sdebug(4, "which=%d sn->maxCmd=%d sn->cmd=%d", which, sn->maxCmd, sn->cmd);
448 
449 	  if((pq = i_dqueue_snd(sp, which)) == NULL)
450 	       break;
451 	  sdebug(4, "pq=%p", pq);
452 
453 	  pp = &pq->pdu;
454 	  bhs = &pp->ipdu.bhs;
455 	  switch(bhs->opcode) {
456 	  case ISCSI_SCSI_CMD:
457 	       sn->itt++;
458 	       bhs->itt = htonl(sn->itt);
459 
460 	  case ISCSI_LOGIN_CMD:
461 	  case ISCSI_TEXT_CMD:
462 	  case ISCSI_LOGOUT_CMD:
463 	  case ISCSI_SNACK:
464 	  case ISCSI_NOP_OUT:
465 	  case ISCSI_TASK_CMD:
466 	       bhs->CmdSN = htonl(sn->cmd);
467 	       if(bhs->I == 0)
468 		    sn->cmd++;
469 
470 	  case ISCSI_WRITE_DATA:
471 	       bhs->ExpStSN = htonl(sn->stat + 1);
472 	       break;
473 
474 	  default:
475 	       // XXX: can this happen?
476 	       xdebug("bad opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)",
477 		      bhs->opcode,
478 		      sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt);
479 	       // XXX: and now?
480 	  }
481 
482 	  sdebug(4, "opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)",
483 		bhs->opcode,
484 		sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt);
485 
486 	  if(bhs->opcode != ISCSI_NOP_OUT)
487 	       /*
488 		| enqued till ack is received
489 		| note: sosend(...) does not mean the packet left
490 		| the host so that freeing resources has to wait
491 	        */
492 	       i_nqueue_hld(sp, pq);
493 
494 	  error = isc_sendPDU(sp, pq);
495 	  if(bhs->opcode == ISCSI_NOP_OUT)
496 	       pdu_free(sp->isc, pq);
497 	  if(error) {
498 	       xdebug("error=%d opcode=0x%x ccb=%p itt=%x",
499 		      error, bhs->opcode, pq->ccb, ntohl(bhs->itt));
500 	       i_remove_hld(sp, pq);
501 	       switch(error) {
502 	       case EPIPE:
503 		    sp->flags &= ~ISC_LINK_UP;
504 
505 	       case EAGAIN:
506 		    xdebug("requed");
507 		    i_rqueue_pdu(sp, pq);
508 		    break;
509 
510 	       default:
511 		    if(pq->ccb) {
512 			 xdebug("back to cam");
513 			 pq->ccb->ccb_h.status |= CAM_REQUEUE_REQ; // some better error?
514 			 XPT_DONE(sp, pq->ccb);
515 			 pdu_free(sp->isc, pq);
516 		    }
517 		    else
518 			 xdebug("we lost it!");
519 	       }
520 	  }
521      }
522      return error;
523 }
524 
525 /*
526  | survives link breakdowns.
527  */
528 static void
ism_out(void * vp)529 ism_out(void *vp)
530 {
531      isc_session_t 	*sp = (isc_session_t *)vp;
532      int		error;
533 
534      debug_called(8);
535 
536      sp->flags |= ISC_SM_RUNNING;
537      sdebug(3, "started sp->flags=%x", sp->flags);
538      do {
539 	  if((sp->flags & ISC_HOLD) == 0) {
540 	       error = proc_out(sp);
541 	       if(error) {
542 		    sdebug(3, "error=%d", error);
543 	       }
544 	  }
545 	  mtx_lock(&sp->io_mtx);
546 	  if((sp->flags & ISC_LINK_UP) == 0) {
547 	       sdebug(3, "ISC_LINK_UP==0, sp->flags=%x ", sp->flags);
548 	       if(sp->soc != NULL)
549 		    sdebug(3, "so_state=%x", sp->soc->so_state);
550 	       wakeup(&sp->soc);
551 	  }
552 
553 	  if(!(sp->flags & ISC_OQNOTEMPTY)) {
554 	       sp->flags |= ISC_OWAITING;
555 	       if(msleep(&sp->flags, &sp->io_mtx, PRIBIO, "isc_proc", hz*30) == EWOULDBLOCK) {
556 		    if(sp->flags & ISC_CON_RUNNING)
557 			 _nop_out(sp);
558 	       }
559 	       sp->flags &= ~ISC_OWAITING;
560 	  }
561 	  sp->flags &= ~ISC_OQNOTEMPTY;
562 	  mtx_unlock(&sp->io_mtx);
563      } while(sp->flags & ISC_SM_RUN);
564 
565      sp->flags &= ~ISC_SM_RUNNING;
566      sdebug(3, "dropped ISC_SM_RUNNING");
567 
568      wakeup(&sp->soc);
569      wakeup(sp); // XXX: do we need this one?
570 
571 #if __FreeBSD_version >= 700000
572      destroy_dev(sp->dev);
573 #endif
574 
575      debug(3, "terminated sp=%p sp->sid=%d", sp, sp->sid);
576 
577 #if __FreeBSD_version >= 800000
578      kproc_exit(0);
579 #else
580      kthread_exit(0);
581 #endif
582 }
583 
584 #if 0
585 static int
586 isc_dump_options(SYSCTL_HANDLER_ARGS)
587 {
588      int error;
589      isc_session_t *sp;
590      struct sbuf sb;
591 
592      sbuf_new_for_sysctl(&sb, NULL, 128, req);
593 
594      sp = (isc_session_t *)arg1;
595      sbuf_printf(&sb, "targetname='%s'", sp->opt.targetName);
596      sbuf_printf(&sb, " targetaddress='%s'", sp->opt.targetAddress);
597      error = sbuf_finish(&sb);
598      sbuf_delete(&sb);
599      return error;
600 }
601 #endif
602 
603 static int
isc_dump_stats(SYSCTL_HANDLER_ARGS)604 isc_dump_stats(SYSCTL_HANDLER_ARGS)
605 {
606      isc_session_t	*sp;
607      struct isc_softc	*sc;
608      int 	error;
609      struct sbuf sb;
610 
611      sp = (isc_session_t *)arg1;
612      sc = sp->isc;
613 
614      sbuf_new_for_sysctl(&sb, NULL, 128, req);
615 
616      sbuf_printf(&sb, "recv=%d sent=%d", sp->stats.nrecv, sp->stats.nsent);
617      sbuf_printf(&sb, " flags=0x%08x pdus-alloc=%d pdus-max=%d",
618 		 sp->flags, sc->npdu_alloc, sc->npdu_max);
619      sbuf_printf(&sb, " cws=%d cmd=%x exp=%x max=%x stat=%x itt=%x",
620 		  sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt);
621      error = sbuf_finish(&sb);
622      sbuf_delete(&sb);
623      return error;
624 }
625 
626 static void
isc_add_sysctls(isc_session_t * sp)627 isc_add_sysctls(isc_session_t *sp)
628 {
629      debug_called(8);
630      sdebug(6, "sid=%d %s", sp->sid, devtoname(sp->dev));
631 
632      sysctl_ctx_init(&sp->clist);
633      sp->oid = SYSCTL_ADD_NODE(&sp->clist,
634 			       SYSCTL_CHILDREN(sp->isc->oid),
635 			       OID_AUTO,
636 			       devtoname(sp->dev) + 5, // iscsi0
637 			       CTLFLAG_RD,
638 			       0,
639 			       "initiator");
640      SYSCTL_ADD_PROC(&sp->clist,
641 		     SYSCTL_CHILDREN(sp->oid),
642 		     OID_AUTO,
643 		     "targetname",
644 		     CTLTYPE_STRING | CTLFLAG_RD,
645 		     (void *)&sp->opt.targetName, 0,
646 		     sysctl_handle_string, "A", "target name");
647 
648      SYSCTL_ADD_PROC(&sp->clist,
649 		     SYSCTL_CHILDREN(sp->oid),
650 		     OID_AUTO,
651 		     "targeaddress",
652 		     CTLTYPE_STRING | CTLFLAG_RD,
653 		     (void *)&sp->opt.targetAddress, 0,
654 		     sysctl_handle_string, "A", "target address");
655 
656      SYSCTL_ADD_PROC(&sp->clist,
657 		     SYSCTL_CHILDREN(sp->oid),
658 		     OID_AUTO,
659 		     "stats",
660 		     CTLTYPE_STRING | CTLFLAG_RD,
661 		     (void *)sp, 0,
662 		     isc_dump_stats, "A", "statistics");
663 
664      SYSCTL_ADD_INT(&sp->clist,
665 		     SYSCTL_CHILDREN(sp->oid),
666 		     OID_AUTO,
667 		     "douio",
668 		     CTLFLAG_RW,
669 		     &sp->douio, 0, "enable uio on read");
670 }
671 
672 void
ism_stop(isc_session_t * sp)673 ism_stop(isc_session_t *sp)
674 {
675      struct isc_softc *sc = sp->isc;
676      int	n;
677 
678      debug_called(8);
679      sdebug(2, "terminating");
680      /*
681       | first stop the receiver
682       */
683      isc_stop_receiver(sp);
684      /*
685       | now stop the xmitter
686       */
687      n = 5;
688      sp->flags &= ~ISC_SM_RUN;
689      while(n-- && (sp->flags & ISC_SM_RUNNING)) {
690 	  sdebug(2, "n=%d", n);
691 	  wakeup(&sp->flags);
692 	  tsleep(sp, PRIBIO, "-", 5*hz);
693      }
694      sdebug(2, "final n=%d", n);
695      sp->flags &= ~ISC_FFPHASE;
696 
697      iscsi_cleanup(sp);
698 
699      (void)i_pdu_flush(sp);
700 
701      ic_destroy(sp);
702 
703      sx_xlock(&sc->unit_sx);
704      free_unr(sc->unit, sp->sid);
705      sx_xunlock(&sc->unit_sx);
706 
707      mtx_lock(&sc->isc_mtx);
708      TAILQ_REMOVE(&sc->isc_sess, sp, sp_link);
709      sc->nsess--;
710      mtx_unlock(&sc->isc_mtx);
711 
712 #if __FreeBSD_version < 700000
713      destroy_dev(sp->dev);
714 #endif
715 
716      mtx_destroy(&sp->rsp_mtx);
717      mtx_destroy(&sp->rsv_mtx);
718      mtx_destroy(&sp->hld_mtx);
719      mtx_destroy(&sp->snd_mtx);
720      mtx_destroy(&sp->io_mtx);
721 
722      i_freeopt(&sp->opt);
723 
724      if(sysctl_ctx_free(&sp->clist))
725 	  xdebug("sysctl_ctx_free failed");
726 
727      free(sp, M_ISCSI);
728 }
729 
730 int
ism_start(isc_session_t * sp)731 ism_start(isc_session_t *sp)
732 {
733      debug_called(8);
734     /*
735      | now is a good time to do some initialization
736      */
737      TAILQ_INIT(&sp->rsp);
738      TAILQ_INIT(&sp->rsv);
739      TAILQ_INIT(&sp->csnd);
740      TAILQ_INIT(&sp->isnd);
741      TAILQ_INIT(&sp->wsnd);
742      TAILQ_INIT(&sp->hld);
743 
744      mtx_init(&sp->rsv_mtx, "iscsi-rsv", NULL, MTX_DEF);
745      mtx_init(&sp->rsp_mtx, "iscsi-rsp", NULL, MTX_DEF);
746      mtx_init(&sp->snd_mtx, "iscsi-snd", NULL, MTX_DEF);
747      mtx_init(&sp->hld_mtx, "iscsi-hld", NULL, MTX_DEF);
748      mtx_init(&sp->io_mtx, "iscsi-io", NULL, MTX_DEF);
749 
750      isc_add_sysctls(sp);
751 
752      sp->flags |= ISC_SM_RUN;
753 
754      debug(4, "starting ism_proc: sp->sid=%d", sp->sid);
755 
756 #if __FreeBSD_version >= 800000
757      return kproc_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid);
758 #else
759      return kthread_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid);
760 #endif
761 }
762