task.c revision 1.3
1/*	$OpenBSD: task.c,v 1.3 2010/09/25 16:20:06 sobrado Exp $ */
2
3/*
4 * Copyright (c) 2009 Claudio Jeker <claudio@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18#include <sys/types.h>
19#include <sys/queue.h>
20#include <sys/socket.h>
21#include <sys/uio.h>
22
23#include <scsi/iscsi.h>
24
25#include <errno.h>
26#include <event.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <strings.h>
30#include <unistd.h>
31
32#include "iscsid.h"
33#include "log.h"
34
35/*
36 * Task handling, PDU are attached to tasks and task are scheduled across
37 * all connections of a session.
38 */
39
40void
41task_init(struct task *t, struct session *s, int immediate, void *carg,
42    void (*c)(struct connection *, void *, struct pdu *))
43{
44	TAILQ_INIT(&t->sendq);
45	TAILQ_INIT(&t->recvq);
46	t->callback = c;
47	t->callarg = carg;
48	t->itt = s->itt++; /* XXX we could do better here */
49	t->cmdseqnum = s->cmdseqnum;
50	if (!immediate)
51		s->cmdseqnum++;
52}
53
54void
55task_cleanup(struct task *t, struct connection *c)
56{
57/* XXX THIS FEELS WRONG FOR NOW */
58	pdu_free_queue(&t->sendq);
59	pdu_free_queue(&t->recvq);
60	/* XXX need some state to know if queued or not */
61	TAILQ_REMOVE(&c->tasks, t, entry);
62}
63
64void
65task_pdu_add(struct task *t, struct pdu *p)
66{
67	struct iscsi_pdu *ipdu;
68
69	/* fixup the pdu by setting the itt and seqnum if needed */
70	ipdu = pdu_getbuf(p, NULL, PDU_HEADER);
71	ipdu->itt = ntohl(t->itt);
72	switch (ISCSI_PDU_OPCODE(ipdu->opcode)) {
73	case ISCSI_OP_I_NOP:
74	case ISCSI_OP_SCSI_REQUEST:
75	case ISCSI_OP_TASK_REQUEST:
76	case ISCSI_OP_LOGIN_REQUEST:
77	case ISCSI_OP_TEXT_REQUEST:
78	case ISCSI_OP_LOGOUT_REQUEST:
79		ipdu->cmdsn = ntohl(t->cmdseqnum);
80		break;
81	}
82
83	TAILQ_INSERT_TAIL(&t->sendq, p, entry);
84}
85
86void
87task_pdu_cb(struct connection *c, struct pdu *p)
88{
89	struct task *t;
90	struct iscsi_pdu *ipdu;
91	u_int32_t itt;
92
93	ipdu = pdu_getbuf(p, NULL, PDU_HEADER);
94	switch (ISCSI_PDU_OPCODE(ipdu->opcode)) {
95	case ISCSI_OP_T_NOP:
96	case ISCSI_OP_LOGIN_RESPONSE:
97	case ISCSI_OP_TEXT_RESPONSE:
98	case ISCSI_OP_LOGOUT_RESPONSE:
99	case ISCSI_OP_SCSI_RESPONSE:
100	case ISCSI_OP_R2T:
101	case ISCSI_OP_DATA_IN:
102		itt = ntohl(ipdu->itt);
103		c->expstatsn = ntohl(ipdu->cmdsn) + 1;
104
105		/* XXX for now search the task on the connection queue
106		   later on this should be moved to a per session RB tree but
107		   now I do the quick ugly thing. */
108		TAILQ_FOREACH(t, &c->tasks, entry) {
109			if (itt == t->itt)
110				break;
111		}
112		if (t)
113			t->callback(c, t->callarg, p);
114		else {
115			log_debug("no task for PDU found");
116			pdu_free(p);
117		}
118		break;
119	default:
120log_pdu(p, 1);
121		log_warnx("not handled yet. fix me");
122		pdu_free(p);
123	}
124}
125