2 * Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
28 | iSCSI - Session Manager
29 | $Id: isc_sm.c 743 2009-08-08 10:54:53Z danny $
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
35 #include "opt_iscsi_initiator.h"
37 #include <sys/param.h>
38 #include <sys/kernel.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>
47 #include <sys/socketvar.h>
48 #include <sys/socket.h>
49 #include <sys/protosw.h>
51 #include <sys/ioccom.h>
52 #include <sys/queue.h>
53 #include <sys/kthread.h>
54 #include <sys/syslog.h>
62 #include <cam/cam_ccb.h>
63 #include <cam/cam_sim.h>
64 #include <cam/cam_xpt_sim.h>
65 #include <cam/cam_periph.h>
67 #include <dev/iscsi_initiator/iscsi.h>
68 #include <dev/iscsi_initiator/iscsivar.h>
71 _async(isc_session_t *sp, pduq_t *pq)
77 pdu_free(sp->isc, pq);
81 _reject(isc_session_t *sp, pduq_t *pq)
89 pdu = mtod(pq->mp, pdu_t *);
90 itt = pdu->ipdu.bhs.itt;
91 reject = &pq->pdu.ipdu.reject;
92 sdebug(2, "itt=%x reason=0x%x", ntohl(itt), reject->reason);
93 opq = i_search_hld(sp, itt, 0);
95 iscsi_reject(sp, opq, pq);
97 switch(pq->pdu.ipdu.bhs.opcode) {
98 case ISCSI_LOGOUT_CMD: // XXX: wasabi does this - can't figure out why
99 sdebug(2, "ISCSI_LOGOUT_CMD ...");
102 xdebug("%d] we lost something itt=%x",
103 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt));
106 pdu_free(sp->isc, pq);
110 _r2t(isc_session_t *sp, pduq_t *pq)
115 opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1);
117 iscsi_r2t(sp, opq, pq);
120 r2t_t *r2t = &pq->pdu.ipdu.r2t;
122 xdebug("%d] we lost something itt=%x r2tSN=%d bo=%x ddtl=%x",
123 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt),
124 ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl));
126 pdu_free(sp->isc, pq);
130 _scsi_rsp(isc_session_t *sp, pduq_t *pq)
135 opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 0);
136 debug(5, "itt=%x pq=%p opq=%p", ntohl(pq->pdu.ipdu.bhs.itt), pq, opq);
138 iscsi_done(sp, opq, pq);
139 i_acked_hld(sp, &pq->pdu);
142 xdebug("%d] we lost something itt=%x",
143 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt));
144 pdu_free(sp->isc, pq);
148 _read_data(isc_session_t *sp, pduq_t *pq)
153 opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1);
155 if(scsi_decap(sp, opq, pq) != 1) {
156 i_remove_hld(sp, opq); // done
157 pdu_free(sp->isc, opq);
161 xdebug("%d] we lost something itt=%x",
162 sp->sid, ntohl(pq->pdu.ipdu.bhs.itt));
163 pdu_free(sp->isc, pq);
167 | the jury is not back with a veredict, user or kernel
170 _nop_out(isc_session_t *sp)
177 sdebug(4, "cws=%d", sp->cws);
180 | only send a nop if window is closed.
182 if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL)
183 // I guess we ran out of resources
185 nop_out = &pq->pdu.ipdu.nop_out;
186 nop_out->opcode = ISCSI_NOP_OUT;
187 nop_out->itt = htonl(sp->sn.itt);
191 if(isc_qout(sp, pq) != 0) {
193 pdu_free(sp->isc, pq);
199 _nop_in(isc_session_t *sp, pduq_t *pq)
201 pdu_t *pp = &pq->pdu;
202 nop_in_t *nop_in = &pp->ipdu.nop_in;
203 bhs_t *bhs = &pp->ipdu.bhs;
207 sdebug(5, "itt=%x ttt=%x", htonl(nop_in->itt), htonl(nop_in->ttt));
208 if(nop_in->itt == -1) {
209 if(pp->ds_len != 0) {
211 | according to RFC 3720 this should be zero
214 xdebug("%d] dslen not zero", sp->sid);
216 if(nop_in->ttt != -1) {
219 | target wants a nop_out
221 bhs->opcode = ISCSI_NOP_OUT;
225 | we are reusing the pdu, so bhs->ttt == nop_in->ttt;
226 | and need to zero out 'Reserved'
229 nop_out = &pp->ipdu.nop_out;
230 nop_out->sn.maxcmd = 0;
231 memset(nop_out->mbz, 0, sizeof(nop_out->mbz));
232 (void)isc_qout(sp, pq); //XXX: should check return?
236 // just making noise?
237 // see 10.9.1: target does not want and answer.
241 if(nop_in->ttt == -1) {
243 | it is an answer to a nop_in from us
245 if(nop_in->itt != -1) {
248 if(sp->flags & ISC_WAIT4PING) {
249 i_nqueue_rsp(sp, pq);
259 pdu_free(sp->isc, pq);
264 i_prepPDU(isc_session_t *sp, pduq_t *pq)
267 pdu_t *pp = &pq->pdu;
268 bhs_t *bhp = &pp->ipdu.bhs;
273 bhp->AHSLength = pp->ahs_len / 4;
275 if(ISOK2DIG(sp->hdrDigest, pp))
280 #if BYTE_ORDER == LITTLE_ENDIAN
281 bhp->DSLength = ((n & 0x00ff0000) >> 16)
283 | ((n & 0x000000ff) << 16);
291 if(ISOK2DIG(sp->dataDigest, pp))
296 len -= sizeof(bhs_t);
297 if(sp->opt.maxBurstLength && (len > sp->opt.maxBurstLength)) {
298 xdebug("%d] pdu len=%zd > %d",
299 sp->sid, len, sp->opt.maxBurstLength);
300 // XXX: when this happens it used to hang ...
307 isc_qout(isc_session_t *sp, pduq_t *pq)
313 if(pq->len == 0 && (error = i_prepPDU(sp, pq)))
316 if(pq->pdu.ipdu.bhs.I)
317 i_nqueue_isnd(sp, pq);
319 if(pq->pdu.ipdu.data_out.opcode == ISCSI_WRITE_DATA)
320 i_nqueue_wsnd(sp, pq);
322 i_nqueue_csnd(sp, pq);
324 sdebug(5, "enqued: pq=%p", pq);
326 mtx_lock(&sp->io_mtx);
327 sp->flags |= ISC_OQNOTEMPTY;
328 if(sp->flags & ISC_OWAITING)
330 mtx_unlock(&sp->io_mtx);
335 | called when a fullPhase is restarted
338 ism_restart(isc_session_t *sp)
342 sdebug(2, "restart ...");
343 lastcmd = iscsi_requeue(sp);
345 if(lastcmd != sp->sn.cmd) {
346 sdebug(1, "resetting CmdSN to=%d (from %d)", lastcmd, sp->sn.cmd);
347 sp->sn.cmd = lastcmd;
350 mtx_lock(&sp->io_mtx);
351 if(sp->flags & ISC_OWAITING) {
354 mtx_unlock(&sp->io_mtx);
356 sdebug(2, "restarted sn.cmd=0x%x lastcmd=0x%x", sp->sn.cmd, lastcmd);
360 ism_recv(isc_session_t *sp, pduq_t *pq)
367 bhs = &pq->pdu.ipdu.bhs;
368 statSN = ntohl(bhs->OpcodeSpecificFields[1]);
371 if(sp->sn.expCmd != sn->cmd) {
372 sdebug(1, "we lost something ... exp=0x%x cmd=0x%x",
373 sn->expCmd, sn->cmd);
376 sdebug(5, "opcode=0x%x itt=0x%x stat#0x%x maxcmd=0x%0x",
377 bhs->opcode, ntohl(bhs->itt), statSN, sp->sn.maxCmd);
379 switch(bhs->opcode) {
380 case ISCSI_READ_DATA: {
381 data_in_t *cmd = &pq->pdu.ipdu.data_in;
388 if(statSN > (sp->sn.stat + 1)) {
389 sdebug(1, "we lost some rec=0x%x exp=0x%x",
390 statSN, sp->sn.stat);
391 // XXX: must do some error recovery here.
393 sp->sn.stat = statSN;
396 switch(bhs->opcode) {
397 case ISCSI_LOGIN_RSP:
399 case ISCSI_LOGOUT_RSP:
400 i_nqueue_rsp(sp, pq);
402 sdebug(3, "wakeup rsp");
405 case ISCSI_NOP_IN: _nop_in(sp, pq); break;
406 case ISCSI_SCSI_RSP: _scsi_rsp(sp, pq); break;
407 case ISCSI_READ_DATA: _read_data(sp, pq); break;
408 case ISCSI_R2T: _r2t(sp, pq); break;
409 case ISCSI_REJECT: _reject(sp, pq); break;
410 case ISCSI_ASYNC: _async(sp, pq); break;
414 sdebug(1, "opcode=0x%x itt=0x%x not implemented yet",
415 bhs->opcode, ntohl(bhs->itt));
421 | go through the out queues looking for work
422 | if either nothing to do, or window is closed
426 proc_out(isc_session_t *sp)
435 while(sp->flags & ISC_LINK_UP) {
439 | check if there is outstanding work in:
440 | 1- the Immediate queue
442 | 3- the cmd queue, only if the command window allows it.
444 which = BIT(0) | BIT(1);
445 if(SNA_GT(sn->cmd, sn->maxCmd) == 0) // if(sn->maxCmd - sn->smc + 1) > 0
448 sdebug(4, "which=%d sn->maxCmd=%d sn->cmd=%d", which, sn->maxCmd, sn->cmd);
450 if((pq = i_dqueue_snd(sp, which)) == NULL)
452 sdebug(4, "pq=%p", pq);
456 switch(bhs->opcode) {
459 bhs->itt = htonl(sn->itt);
461 case ISCSI_LOGIN_CMD:
463 case ISCSI_LOGOUT_CMD:
467 bhs->CmdSN = htonl(sn->cmd);
471 case ISCSI_WRITE_DATA:
472 bhs->ExpStSN = htonl(sn->stat + 1);
476 // XXX: can this happen?
477 xdebug("bad opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)",
479 sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt);
483 sdebug(4, "opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)",
485 sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt);
487 if(bhs->opcode != ISCSI_NOP_OUT)
489 | enqued till ack is received
490 | note: sosend(...) does not mean the packet left
491 | the host so that freeing resources has to wait
493 i_nqueue_hld(sp, pq);
495 error = isc_sendPDU(sp, pq);
496 if(bhs->opcode == ISCSI_NOP_OUT)
497 pdu_free(sp->isc, pq);
499 xdebug("error=%d opcode=0x%x ccb=%p itt=%x",
500 error, bhs->opcode, pq->ccb, ntohl(bhs->itt));
501 i_remove_hld(sp, pq);
504 sp->flags &= ~ISC_LINK_UP;
508 i_rqueue_pdu(sp, pq);
513 xdebug("back to cam");
514 pq->ccb->ccb_h.status |= CAM_REQUEUE_REQ; // some better error?
515 XPT_DONE(sp, pq->ccb);
516 pdu_free(sp->isc, pq);
519 xdebug("we lost it!");
527 | survives link breakdowns.
532 isc_session_t *sp = (isc_session_t *)vp;
537 sp->flags |= ISC_SM_RUNNING;
538 sdebug(3, "started sp->flags=%x", sp->flags);
540 if((sp->flags & ISC_HOLD) == 0) {
541 error = proc_out(sp);
543 sdebug(3, "error=%d", error);
546 mtx_lock(&sp->io_mtx);
547 if((sp->flags & ISC_LINK_UP) == 0) {
548 sdebug(3, "ISC_LINK_UP==0, sp->flags=%x ", sp->flags);
550 sdebug(3, "so_state=%x", sp->soc->so_state);
554 if(!(sp->flags & ISC_OQNOTEMPTY)) {
555 sp->flags |= ISC_OWAITING;
556 if(msleep(&sp->flags, &sp->io_mtx, PRIBIO, "isc_proc", hz*30) == EWOULDBLOCK) {
557 if(sp->flags & ISC_CON_RUNNING)
560 sp->flags &= ~ISC_OWAITING;
562 sp->flags &= ~ISC_OQNOTEMPTY;
563 mtx_unlock(&sp->io_mtx);
564 } while(sp->flags & ISC_SM_RUN);
566 sp->flags &= ~ISC_SM_RUNNING;
567 sdebug(3, "dropped ISC_SM_RUNNING");
570 wakeup(sp); // XXX: do we need this one?
572 #if __FreeBSD_version >= 700000
573 destroy_dev(sp->dev);
576 debug(3, "terminated sp=%p sp->sid=%d", sp, sp->sid);
578 #if __FreeBSD_version >= 800000
587 isc_dump_options(SYSCTL_HANDLER_ARGS)
593 sbuf_new_for_sysctl(&sb, NULL, 128, req);
595 sp = (isc_session_t *)arg1;
596 sbuf_printf(&sb, "targetname='%s'", sp->opt.targetName);
597 sbuf_printf(&sb, " targetaddress='%s'", sp->opt.targetAddress);
598 error = sbuf_finish(&sb);
605 isc_dump_stats(SYSCTL_HANDLER_ARGS)
608 struct isc_softc *sc;
612 sp = (isc_session_t *)arg1;
615 sbuf_new_for_sysctl(&sb, NULL, 128, req);
617 sbuf_printf(&sb, "recv=%d sent=%d", sp->stats.nrecv, sp->stats.nsent);
618 sbuf_printf(&sb, " flags=0x%08x pdus-alloc=%d pdus-max=%d",
619 sp->flags, sc->npdu_alloc, sc->npdu_max);
620 sbuf_printf(&sb, " cws=%d cmd=%x exp=%x max=%x stat=%x itt=%x",
621 sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt);
622 error = sbuf_finish(&sb);
628 isc_add_sysctls(isc_session_t *sp)
631 sdebug(6, "sid=%d %s", sp->sid, devtoname(sp->dev));
633 sysctl_ctx_init(&sp->clist);
634 sp->oid = SYSCTL_ADD_NODE(&sp->clist,
635 SYSCTL_CHILDREN(sp->isc->oid),
637 devtoname(sp->dev) + 5, // iscsi0
641 SYSCTL_ADD_PROC(&sp->clist,
642 SYSCTL_CHILDREN(sp->oid),
645 CTLTYPE_STRING | CTLFLAG_RD,
646 (void *)&sp->opt.targetName, 0,
647 sysctl_handle_string, "A", "target name");
649 SYSCTL_ADD_PROC(&sp->clist,
650 SYSCTL_CHILDREN(sp->oid),
653 CTLTYPE_STRING | CTLFLAG_RD,
654 (void *)&sp->opt.targetAddress, 0,
655 sysctl_handle_string, "A", "target address");
657 SYSCTL_ADD_PROC(&sp->clist,
658 SYSCTL_CHILDREN(sp->oid),
661 CTLTYPE_STRING | CTLFLAG_RD,
663 isc_dump_stats, "A", "statistics");
665 SYSCTL_ADD_INT(&sp->clist,
666 SYSCTL_CHILDREN(sp->oid),
670 &sp->douio, 0, "enable uio on read");
674 ism_stop(isc_session_t *sp)
676 struct isc_softc *sc = sp->isc;
680 sdebug(2, "terminating");
682 | first stop the receiver
684 isc_stop_receiver(sp);
686 | now stop the xmitter
689 sp->flags &= ~ISC_SM_RUN;
690 while(n-- && (sp->flags & ISC_SM_RUNNING)) {
691 sdebug(2, "n=%d", n);
693 tsleep(sp, PRIBIO, "-", 5*hz);
695 sdebug(2, "final n=%d", n);
696 sp->flags &= ~ISC_FFPHASE;
700 (void)i_pdu_flush(sp);
704 sx_xlock(&sc->unit_sx);
705 free_unr(sc->unit, sp->sid);
706 sx_xunlock(&sc->unit_sx);
708 mtx_lock(&sc->isc_mtx);
709 TAILQ_REMOVE(&sc->isc_sess, sp, sp_link);
711 mtx_unlock(&sc->isc_mtx);
713 #if __FreeBSD_version < 700000
714 destroy_dev(sp->dev);
717 mtx_destroy(&sp->rsp_mtx);
718 mtx_destroy(&sp->rsv_mtx);
719 mtx_destroy(&sp->hld_mtx);
720 mtx_destroy(&sp->snd_mtx);
721 mtx_destroy(&sp->io_mtx);
725 if(sysctl_ctx_free(&sp->clist))
726 xdebug("sysctl_ctx_free failed");
732 ism_start(isc_session_t *sp)
736 | now is a good time to do some initialization
738 TAILQ_INIT(&sp->rsp);
739 TAILQ_INIT(&sp->rsv);
740 TAILQ_INIT(&sp->csnd);
741 TAILQ_INIT(&sp->isnd);
742 TAILQ_INIT(&sp->wsnd);
743 TAILQ_INIT(&sp->hld);
745 mtx_init(&sp->rsv_mtx, "iscsi-rsv", NULL, MTX_DEF);
746 mtx_init(&sp->rsp_mtx, "iscsi-rsp", NULL, MTX_DEF);
747 mtx_init(&sp->snd_mtx, "iscsi-snd", NULL, MTX_DEF);
748 mtx_init(&sp->hld_mtx, "iscsi-hld", NULL, MTX_DEF);
749 mtx_init(&sp->io_mtx, "iscsi-io", NULL, MTX_DEF);
753 sp->flags |= ISC_SM_RUN;
755 debug(4, "starting ism_proc: sp->sid=%d", sp->sid);
757 #if __FreeBSD_version >= 800000
758 return kproc_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid);
760 return kthread_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid);