xref: /openbsd-src/usr.sbin/iscsid/task.c (revision bb7fde4eb499e35fa8d42b21dd3965ab16f36437)
1*bb7fde4eSclaudio /*	$OpenBSD: task.c,v 1.10 2014/05/10 11:28:02 claudio Exp $ */
2bde1ae23Sclaudio 
3bde1ae23Sclaudio /*
4bde1ae23Sclaudio  * Copyright (c) 2009 Claudio Jeker <claudio@openbsd.org>
5bde1ae23Sclaudio  *
6bde1ae23Sclaudio  * Permission to use, copy, modify, and distribute this software for any
7bde1ae23Sclaudio  * purpose with or without fee is hereby granted, provided that the above
8bde1ae23Sclaudio  * copyright notice and this permission notice appear in all copies.
9bde1ae23Sclaudio  *
10bde1ae23Sclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11bde1ae23Sclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12bde1ae23Sclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13bde1ae23Sclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14bde1ae23Sclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15bde1ae23Sclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16bde1ae23Sclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17bde1ae23Sclaudio  */
18bde1ae23Sclaudio #include <sys/types.h>
19bde1ae23Sclaudio #include <sys/queue.h>
20bde1ae23Sclaudio #include <sys/socket.h>
21bde1ae23Sclaudio #include <sys/uio.h>
22bde1ae23Sclaudio 
23bde1ae23Sclaudio #include <scsi/iscsi.h>
24bde1ae23Sclaudio 
25bde1ae23Sclaudio #include <errno.h>
26bde1ae23Sclaudio #include <event.h>
27bde1ae23Sclaudio #include <stdio.h>
28bde1ae23Sclaudio #include <stdlib.h>
29bde1ae23Sclaudio #include <strings.h>
30bde1ae23Sclaudio #include <unistd.h>
31bde1ae23Sclaudio 
32bde1ae23Sclaudio #include "iscsid.h"
33bde1ae23Sclaudio #include "log.h"
34bde1ae23Sclaudio 
35bde1ae23Sclaudio /*
36de8a731fSsobrado  * Task handling, PDU are attached to tasks and task are scheduled across
37bde1ae23Sclaudio  * all connections of a session.
38bde1ae23Sclaudio  */
39bde1ae23Sclaudio 
40bde1ae23Sclaudio void
task_init(struct task * t,struct session * s,int immediate,void * carg,void (* c)(struct connection *,void *,struct pdu *),void (* f)(void *))41bde1ae23Sclaudio task_init(struct task *t, struct session *s, int immediate, void *carg,
42cb408c6cSclaudio     void (*c)(struct connection *, void *, struct pdu *),
43cb408c6cSclaudio     void (*f)(void *))
44bde1ae23Sclaudio {
45bde1ae23Sclaudio 	TAILQ_INIT(&t->sendq);
46bde1ae23Sclaudio 	TAILQ_INIT(&t->recvq);
47bde1ae23Sclaudio 	t->callback = c;
48cb408c6cSclaudio 	t->failback = f;
49bde1ae23Sclaudio 	t->callarg = carg;
50cb408c6cSclaudio 	/* skip reserved and maybe bad ITT values */
51cb408c6cSclaudio 	if (s->itt == 0xffffffff || s->itt == 0)
52cb408c6cSclaudio 		s->itt = 1;
53bde1ae23Sclaudio 	t->itt = s->itt++; /* XXX we could do better here */
54bde1ae23Sclaudio 	t->cmdseqnum = s->cmdseqnum;
55bde1ae23Sclaudio 	if (!immediate)
56bde1ae23Sclaudio 		s->cmdseqnum++;
57bde1ae23Sclaudio }
58bde1ae23Sclaudio 
59bde1ae23Sclaudio void
taskq_cleanup(struct taskq * tq)60cb408c6cSclaudio taskq_cleanup(struct taskq *tq)
61cb408c6cSclaudio {
62cb408c6cSclaudio 	struct task *t;
63cb408c6cSclaudio 
64cb408c6cSclaudio 	while ((t = TAILQ_FIRST(tq))) {
65cb408c6cSclaudio 		TAILQ_REMOVE(tq, t, entry);
66cb408c6cSclaudio 		if (t->failback)
67cb408c6cSclaudio 			t->failback(t->callarg);
686727bd69Sclaudio 		conn_task_cleanup(NULL, t);
69cb408c6cSclaudio 		free(t);
70cb408c6cSclaudio 	}
71cb408c6cSclaudio }
72cb408c6cSclaudio 
73cb408c6cSclaudio void
task_pdu_add(struct task * t,struct pdu * p)74bde1ae23Sclaudio task_pdu_add(struct task *t, struct pdu *p)
75bde1ae23Sclaudio {
76bde1ae23Sclaudio 	struct iscsi_pdu *ipdu;
77bde1ae23Sclaudio 
78bde1ae23Sclaudio 	/* fixup the pdu by setting the itt and seqnum if needed */
79bde1ae23Sclaudio 	ipdu = pdu_getbuf(p, NULL, PDU_HEADER);
80bde1ae23Sclaudio 	ipdu->itt = ntohl(t->itt);
81bde1ae23Sclaudio 	switch (ISCSI_PDU_OPCODE(ipdu->opcode)) {
82bde1ae23Sclaudio 	case ISCSI_OP_I_NOP:
83bde1ae23Sclaudio 	case ISCSI_OP_SCSI_REQUEST:
84bde1ae23Sclaudio 	case ISCSI_OP_TASK_REQUEST:
85bde1ae23Sclaudio 	case ISCSI_OP_LOGIN_REQUEST:
86bde1ae23Sclaudio 	case ISCSI_OP_TEXT_REQUEST:
87bde1ae23Sclaudio 	case ISCSI_OP_LOGOUT_REQUEST:
88bde1ae23Sclaudio 		ipdu->cmdsn = ntohl(t->cmdseqnum);
89bde1ae23Sclaudio 		break;
90bde1ae23Sclaudio 	}
91bde1ae23Sclaudio 
92bde1ae23Sclaudio 	TAILQ_INSERT_TAIL(&t->sendq, p, entry);
93bde1ae23Sclaudio }
94bde1ae23Sclaudio 
95bde1ae23Sclaudio void
task_pdu_cb(struct connection * c,struct pdu * p)96bde1ae23Sclaudio task_pdu_cb(struct connection *c, struct pdu *p)
97bde1ae23Sclaudio {
98bde1ae23Sclaudio 	struct task *t;
99bde1ae23Sclaudio 	struct iscsi_pdu *ipdu;
100bde1ae23Sclaudio 	u_int32_t itt;
101bde1ae23Sclaudio 
102bde1ae23Sclaudio 	ipdu = pdu_getbuf(p, NULL, PDU_HEADER);
103bde1ae23Sclaudio 	switch (ISCSI_PDU_OPCODE(ipdu->opcode)) {
104bde1ae23Sclaudio 	case ISCSI_OP_T_NOP:
10517fa8594Sclaudio 		itt = ntohl(ipdu->itt);
10617fa8594Sclaudio 		if (itt == 0xffffffff) {
10717fa8594Sclaudio 			/* target issued a ping, must answer back immediately */
10817fa8594Sclaudio 			c->expstatsn = ntohl(ipdu->cmdsn) + 1;
10917fa8594Sclaudio 			initiator_nop_in_imm(c, p);
11017fa8594Sclaudio 			break;
11117fa8594Sclaudio 		}
11217fa8594Sclaudio 		/* FALLTHROUGH */
113bde1ae23Sclaudio 	case ISCSI_OP_LOGIN_RESPONSE:
114bde1ae23Sclaudio 	case ISCSI_OP_TEXT_RESPONSE:
115bde1ae23Sclaudio 	case ISCSI_OP_LOGOUT_RESPONSE:
116bde1ae23Sclaudio 	case ISCSI_OP_SCSI_RESPONSE:
117bde1ae23Sclaudio 	case ISCSI_OP_R2T:
118bde1ae23Sclaudio 	case ISCSI_OP_DATA_IN:
119bde1ae23Sclaudio 		itt = ntohl(ipdu->itt);
120bde1ae23Sclaudio 		c->expstatsn = ntohl(ipdu->cmdsn) + 1;
121bde1ae23Sclaudio 
122bde1ae23Sclaudio 		/* XXX for now search the task on the connection queue
123bde1ae23Sclaudio 		   later on this should be moved to a per session RB tree but
124bde1ae23Sclaudio 		   now I do the quick ugly thing. */
125bde1ae23Sclaudio 		TAILQ_FOREACH(t, &c->tasks, entry) {
126bde1ae23Sclaudio 			if (itt == t->itt)
127bde1ae23Sclaudio 				break;
128bde1ae23Sclaudio 		}
129bde1ae23Sclaudio 		if (t)
130bde1ae23Sclaudio 			t->callback(c, t->callarg, p);
131bde1ae23Sclaudio 		else {
132bde1ae23Sclaudio 			log_debug("no task for PDU found");
13331d7b63eSclaudio 			log_pdu(p, 1);
134bde1ae23Sclaudio 			pdu_free(p);
135bde1ae23Sclaudio 		}
136bde1ae23Sclaudio 		break;
137bde1ae23Sclaudio 	default:
138bde1ae23Sclaudio 		log_warnx("not handled yet. fix me");
13931d7b63eSclaudio 		log_pdu(p, 1);
140bde1ae23Sclaudio 		pdu_free(p);
141bde1ae23Sclaudio 	}
142bde1ae23Sclaudio }
143