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