Deleted Added
sdiff udiff text old ( 201758 ) new ( 211095 )
full compact
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: head/sys/dev/iscsi/initiator/isc_sm.c 201758 2010-01-07 21:01:37Z mbr $");
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
67static 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
77static 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
106static 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
126static 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
142static 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 */
164static 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
193static 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
258int
259i_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
301int
302isc_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 */
332static void
333ism_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
354int
355ism_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
377void
378ism_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
458/*
459 | go through the out queues looking for work
460 | if either nothing to do, or window is closed
461 | return.
462 */
463static int
464proc_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
563/*
564 | survives link breakdowns.
565 */
566static void
567ism_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
614static int
615isc_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
631static int
632isc_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
657static int
658isc_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
669static int
670isc_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
681static void
682isc_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
727void
728ism_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
782int
783ism_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}