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