/* $OpenBSD: task.c,v 1.3 2010/09/25 16:20:06 sobrado Exp $ */ /* * Copyright (c) 2009 Claudio Jeker * * 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 #include #include #include #include #include #include #include #include #include #include #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"); pdu_free(p); } break; default: log_pdu(p, 1); log_warnx("not handled yet. fix me"); pdu_free(p); } }