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