1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
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
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
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
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
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
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
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
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
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
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
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
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
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(sp, 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
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 #if __FreeBSD_version >= 700000
575 destroy_dev(sp->dev);
576 #endif
577
578 debug(3, "terminated sp=%p sp->sid=%d", sp, sp->sid);
579
580 #if __FreeBSD_version >= 800000
581 kproc_exit(0);
582 #else
583 kthread_exit(0);
584 #endif
585 }
586
587 #if 0
588 static int
589 isc_dump_options(SYSCTL_HANDLER_ARGS)
590 {
591 int error;
592 isc_session_t *sp;
593 struct sbuf sb;
594
595 sbuf_new_for_sysctl(&sb, NULL, 128, req);
596
597 sp = (isc_session_t *)arg1;
598 sbuf_printf(&sb, "targetname='%s'", sp->opt.targetName);
599 sbuf_printf(&sb, " targetaddress='%s'", sp->opt.targetAddress);
600 error = sbuf_finish(&sb);
601 sbuf_delete(&sb);
602 return error;
603 }
604 #endif
605
606 static int
607 isc_dump_stats(SYSCTL_HANDLER_ARGS)
608 {
609 isc_session_t *sp;
610 struct isc_softc *sc;
611 int error;
612 struct sbuf sb;
613
614 sp = (isc_session_t *)arg1;
615 sc = sp->isc;
616
617 sbuf_new_for_sysctl(&sb, NULL, 128, req);
618
619 sbuf_printf(&sb, "recv=%d sent=%d", sp->stats.nrecv, sp->stats.nsent);
620 sbuf_printf(&sb, " flags=0x%08x pdus-alloc=%d pdus-max=%d",
621 sp->flags, sc->npdu_alloc, sc->npdu_max);
622 sbuf_printf(&sb, " cws=%d cmd=%x exp=%x max=%x stat=%x itt=%x",
623 sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt);
624 error = sbuf_finish(&sb);
625 sbuf_delete(&sb);
626 return error;
627 }
628
629 static void
630 isc_add_sysctls(isc_session_t *sp)
631 {
632 debug_called(8);
633 sdebug(6, "sid=%d %s", sp->sid, devtoname(sp->dev));
634
635 sysctl_ctx_init(&sp->clist);
636 sp->oid = SYSCTL_ADD_NODE(&sp->clist,
637 SYSCTL_CHILDREN(sp->isc->oid),
638 OID_AUTO,
639 devtoname(sp->dev) + 5, // iscsi0
640 CTLFLAG_RD,
641 0,
642 "initiator");
643 SYSCTL_ADD_PROC(&sp->clist,
644 SYSCTL_CHILDREN(sp->oid),
645 OID_AUTO,
646 "targetname",
647 CTLTYPE_STRING | CTLFLAG_RD,
648 (void *)&sp->opt.targetName, 0,
649 sysctl_handle_string, "A", "target name");
650
651 SYSCTL_ADD_PROC(&sp->clist,
652 SYSCTL_CHILDREN(sp->oid),
653 OID_AUTO,
654 "targeaddress",
655 CTLTYPE_STRING | CTLFLAG_RD,
656 (void *)&sp->opt.targetAddress, 0,
657 sysctl_handle_string, "A", "target address");
658
659 SYSCTL_ADD_PROC(&sp->clist,
660 SYSCTL_CHILDREN(sp->oid),
661 OID_AUTO,
662 "stats",
663 CTLTYPE_STRING | CTLFLAG_RD,
664 (void *)sp, 0,
665 isc_dump_stats, "A", "statistics");
666
667 SYSCTL_ADD_INT(&sp->clist,
668 SYSCTL_CHILDREN(sp->oid),
669 OID_AUTO,
670 "douio",
671 CTLFLAG_RW,
672 &sp->douio, 0, "enable uio on read");
673 }
674
675 void
676 ism_stop(isc_session_t *sp)
677 {
678 struct isc_softc *sc = sp->isc;
679 int n;
680
681 debug_called(8);
682 sdebug(2, "terminating");
683 /*
684 | first stop the receiver
685 */
686 isc_stop_receiver(sp);
687 /*
688 | now stop the xmitter
689 */
690 n = 5;
691 sp->flags &= ~ISC_SM_RUN;
692 while(n-- && (sp->flags & ISC_SM_RUNNING)) {
693 sdebug(2, "n=%d", n);
694 wakeup(&sp->flags);
695 tsleep(sp, PRIBIO, "-", 5*hz);
696 }
697 sdebug(2, "final n=%d", n);
698 sp->flags &= ~ISC_FFPHASE;
699
700 iscsi_cleanup(sp);
701
702 (void)i_pdu_flush(sp);
703
704 ic_destroy(sp);
705
706 sx_xlock(&sc->unit_sx);
707 free_unr(sc->unit, sp->sid);
708 sx_xunlock(&sc->unit_sx);
709
710 mtx_lock(&sc->isc_mtx);
711 TAILQ_REMOVE(&sc->isc_sess, sp, sp_link);
712 sc->nsess--;
713 mtx_unlock(&sc->isc_mtx);
714
715 #if __FreeBSD_version < 700000
716 destroy_dev(sp->dev);
717 #endif
718
719 mtx_destroy(&sp->rsp_mtx);
720 mtx_destroy(&sp->rsv_mtx);
721 mtx_destroy(&sp->hld_mtx);
722 mtx_destroy(&sp->snd_mtx);
723 mtx_destroy(&sp->io_mtx);
724
725 i_freeopt(&sp->opt);
726
727 if(sysctl_ctx_free(&sp->clist))
728 xdebug("sysctl_ctx_free failed");
729
730 free(sp, M_ISCSI);
731 }
732
733 int
734 ism_start(isc_session_t *sp)
735 {
736 debug_called(8);
737 /*
738 | now is a good time to do some initialization
739 */
740 TAILQ_INIT(&sp->rsp);
741 TAILQ_INIT(&sp->rsv);
742 TAILQ_INIT(&sp->csnd);
743 TAILQ_INIT(&sp->isnd);
744 TAILQ_INIT(&sp->wsnd);
745 TAILQ_INIT(&sp->hld);
746
747 mtx_init(&sp->rsv_mtx, "iscsi-rsv", NULL, MTX_DEF);
748 mtx_init(&sp->rsp_mtx, "iscsi-rsp", NULL, MTX_DEF);
749 mtx_init(&sp->snd_mtx, "iscsi-snd", NULL, MTX_DEF);
750 mtx_init(&sp->hld_mtx, "iscsi-hld", NULL, MTX_DEF);
751 mtx_init(&sp->io_mtx, "iscsi-io", NULL, MTX_DEF);
752
753 isc_add_sysctls(sp);
754
755 sp->flags |= ISC_SM_RUN;
756
757 debug(4, "starting ism_proc: sp->sid=%d", sp->sid);
758
759 #if __FreeBSD_version >= 800000
760 return kproc_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid);
761 #else
762 return kthread_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid);
763 #endif
764 }
Cache object: ab5a64422123b60a9cb746515feb28a7
|