[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 4/6] scsifront/back drivers' user-space daemon



# HG changeset patch
# User fujita.tomonori@xxxxxxxxxxxxx
# Node ID ed8d345449c176cb5fe0ccff4299da782eb63c08
# Parent  6d90075b4fefbe3f12b241f39a1b3959cc3bbeab
SCSI frontend and backend drivers' user-space daemon

This patch includes the user-space daemon code that performs the SCSI
protocol and I/O operations. This is a modified version of user-space
code of the SCSI target framework.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx>

diff -r 6d90075b4fef -r ed8d345449c1 tools/Makefile
--- a/tools/Makefile    Wed Aug 02 15:08:23 2006 +0900
+++ b/tools/Makefile    Wed Aug 02 15:11:34 2006 +0900
@@ -16,6 +16,7 @@ SUBDIRS-$(VTPM_TOOLS) += vtpm_manager
 SUBDIRS-$(VTPM_TOOLS) += vtpm_manager
 SUBDIRS-$(VTPM_TOOLS) += vtpm
 SUBDIRS-y += xenstat
+SUBDIRS-y += tgtd
 
 # These don't cross-compile
 ifeq ($(XEN_COMPILE_ARCH),$(XEN_TARGET_ARCH))
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/Makefile       Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,35 @@
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+INCLUDES += -I$(XEN_LIBXC) -I$(XEN_XENSTORE) -I$(XEN_ROOT)/xen/include
+
+LINUX_ROOT := $(wildcard $(XEN_ROOT)/linux-2.6.*-xen)
+INCLUDES += -I$(LINUX_ROOT)/include
+
+CFLAGS += -Wall -O2
+CFLAGS += -Wno-unused -Wstrict-prototypes
+CFLAGS += -fPIC
+CFLAGS += -D_LARGEFILE64_SOURCE
+
+CFLAGS += -D _GNU_SOURCE
+
+CFLAGS += $(INCLUDES) 
+
+TGTD_OBJS = tgtd.o tgtif.o mgmt.o target.o scsi.o log.o driver.o xen.o
+TGTD_OBJS += xs_api.o xenbus.o
+
+PROGRAMS = tgtd tgtadm
+
+all: $(PROGRAMS)
+
+tgtd: $(TGTD_OBJS)
+       $(CC) $^ -g -o $@ -L$(XEN_XENSTORE) -l xenstore
+
+tgtadm: tgtadm.o
+       $(CC) $^ -o $@
+
+install: $(PROGRAMS)
+       install -m0755 $(PROGRAMS) $(DESTDIR)/usr/sbin
+
+clean:
+       rm -f *.o $(PROGRAMS)
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/driver.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/driver.c       Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,25 @@
+#include <errno.h>
+#include <string.h>
+#include <poll.h>
+#include <inttypes.h>
+
+#include "tgtd.h"
+#include "driver.h"
+#include "xen.h"
+
+struct tgt_driver *tgt_drivers[] = {
+       &xen,
+       NULL,
+};
+
+int get_driver_index(char *name)
+{
+       int i;
+
+       for (i = 0; tgt_drivers[i]; i++) {
+               if (!strcmp(name, tgt_drivers[i]->name))
+                       return i;
+       }
+
+       return -ENOENT;
+}
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/driver.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/driver.h       Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,26 @@
+#include <poll.h>
+
+struct tgt_driver {
+       const char *name;
+
+       int (*init) (int *);
+       int (*poll_init) (struct pollfd *);
+       int (*event_handle) (struct pollfd *);
+
+       int (*target_create) (int, char *);
+       int (*target_destroy) (int);
+       int (*target_bind)(int);
+
+       uint64_t (*scsi_get_lun)(uint8_t *);
+       int (*scsi_report_luns)(struct list_head *, uint8_t *, uint8_t *,
+                               uint8_t *, int *);
+       int (*scsi_inquiry)(struct tgt_device *, int, uint8_t *, uint8_t *,
+                           uint8_t *, int *);
+       int npfd;
+       int enable;
+       int pfd_index;
+};
+
+extern struct tgt_driver *tgt_drivers[];
+extern int get_driver_index(char *name);
+
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/list.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/list.h Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,81 @@
+/* taken from linux kernel */
+
+#undef offsetof
+#ifdef __compiler_offsetof
+#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define container_of(ptr, type, member) ({                     \
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);   \
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+struct list_head {
+       struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+       struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+       list->next = list;
+       list->prev = list;
+}
+
+static inline int list_empty(const struct list_head *head)
+{
+       return head->next == head;
+}
+
+#define list_entry(ptr, type, member) \
+       container_of(ptr, type, member)
+
+#define list_for_each(pos, head) \
+       for (pos = (head)->next; pos != (head); pos = pos->next)
+
+#define list_for_each_entry(pos, head, member)                         \
+       for (pos = list_entry((head)->next, typeof(*pos), member);      \
+            &pos->member != (head);                                    \
+            pos = list_entry(pos->member.next, typeof(*pos), member))
+
+#define list_for_each_entry_safe(pos, n, head, member)                 \
+       for (pos = list_entry((head)->next, typeof(*pos), member),      \
+               n = list_entry(pos->member.next, typeof(*pos), member); \
+            &pos->member != (head);                                    \
+            pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+static inline void __list_add(struct list_head *new,
+                             struct list_head *prev,
+                             struct list_head *next)
+{
+       next->prev = new;
+       new->next = next;
+       new->prev = prev;
+       prev->next = new;
+}
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head, head->next);
+}
+
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head->prev, head);
+}
+
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+       next->prev = prev;
+       prev->next = next;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       entry->next = entry->prev = NULL;
+}
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/log.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/log.c  Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2002-2003 Ardis Technolgies <roman@xxxxxxxxxxxxx>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <signal.h>
+#include <sys/shm.h>
+#include <sys/ipc.h>
+#include <sys/types.h>
+
+#include "log.h"
+
+#define SEMKEY 0xA7L
+#define LOGDBG 0
+
+#if LOGDBG
+#define logdbg(file, fmt, args...) fprintf(file, fmt, ##args)
+#else
+#define logdbg(file, fmt, args...) do {} while (0)
+#endif
+
+static char *log_name;
+static int is_daemon, is_debug;
+
+static int logarea_init (int size)
+{
+       int shmid;
+
+       logdbg(stderr,"enter logarea_init\n");
+
+       if ((shmid = shmget(IPC_PRIVATE, sizeof(struct logarea),
+                           0644 | IPC_CREAT | IPC_EXCL)) == -1)
+               return 1;
+
+       la = shmat(shmid, NULL, 0);
+       if (!la)
+               return 1;
+
+       if (size < MAX_MSG_SIZE)
+               size = LOG_SPACE_SIZE;
+
+       if ((shmid = shmget(IPC_PRIVATE, size,
+                           0644 | IPC_CREAT | IPC_EXCL)) == -1) {
+               shmdt(la);
+               return 1;
+       }
+
+       la->start = shmat(shmid, NULL, 0);
+       if (!la->start) {
+               shmdt(la);
+               return 1;
+       }
+       memset(la->start, 0, size);
+
+       la->empty = 1;
+       la->end = la->start + size;
+       la->head = la->start;
+       la->tail = la->start;
+
+       if ((shmid = shmget(IPC_PRIVATE, MAX_MSG_SIZE + sizeof(struct logmsg),
+                           0644 | IPC_CREAT | IPC_EXCL)) == -1) {
+               shmdt(la->start);
+               shmdt(la);
+               return 1;
+       }
+       la->buff = shmat(shmid, NULL, 0);
+       if (!la->buff) {
+               shmdt(la->start);
+               shmdt(la);
+               return 1;
+       }
+
+       if ((la->semid = semget(SEMKEY, 1, 0666 | IPC_CREAT)) < 0) {
+               shmdt(la->buff);
+               shmdt(la->start);
+               shmdt(la);
+               return 1;
+       }
+
+       la->semarg.val=1;
+       if (semctl(la->semid, 0, SETVAL, la->semarg) < 0) {
+               shmdt(la->buff);
+               shmdt(la->start);
+               shmdt(la);
+               return 1;
+       }
+
+       la->ops[0].sem_num = 0;
+       la->ops[0].sem_flg = 0;
+
+       return 0;
+
+}
+
+static void free_logarea (void)
+{
+       semctl(la->semid, 0, IPC_RMID, la->semarg);
+       shmdt(la->buff);
+       shmdt(la->start);
+       shmdt(la);
+       return;
+}
+
+#if LOGDBG
+static void dump_logarea (void)
+{
+       struct logmsg * msg;
+
+       logdbg(stderr, "\n==== area: start addr = %p, end addr = %p ====\n",
+               la->start, la->end);
+       logdbg(stderr, "|addr     |next     |prio|msg\n");
+
+       for (msg = (struct logmsg *)la->head; (void *)msg != la->tail;
+            msg = msg->next)
+               logdbg(stderr, "|%p |%p |%i   |%s\n", (void *)msg, msg->next,
+                               msg->prio, (char *)&msg->str);
+
+       logdbg(stderr, "|%p |%p |%i   |%s\n", (void *)msg, msg->next,
+                       msg->prio, (char *)&msg->str);
+
+       logdbg(stderr, "\n\n");
+}
+#endif
+
+int log_enqueue (int prio, const char * fmt, va_list ap)
+{
+       int len, fwd;
+       char buff[MAX_MSG_SIZE];
+       struct logmsg * msg;
+       struct logmsg * lastmsg;
+
+       lastmsg = (struct logmsg *)la->tail;
+
+       if (!la->empty) {
+               fwd = sizeof(struct logmsg) +
+                     strlen((char *)&lastmsg->str) * sizeof(char) + 1;
+               la->tail += fwd;
+       }
+       vsnprintf(buff, MAX_MSG_SIZE, fmt, ap);
+       len = strlen(buff) * sizeof(char) + 1;
+
+       /* not enough space on tail : rewind */
+       if (la->head <= la->tail &&
+           (len + sizeof(struct logmsg)) > (la->end - la->tail)) {
+               logdbg(stderr, "enqueue: rewind tail to %p\n", la->tail);
+                       la->tail = la->start;
+       }
+
+       /* not enough space on head : drop msg */
+       if (la->head > la->tail &&
+           (len + sizeof(struct logmsg)) > (la->head - la->tail)) {
+               logdbg(stderr, "enqueue: log area overrun, drop msg\n");
+
+               if (!la->empty)
+                       la->tail = lastmsg;
+
+               return 1;
+       }
+
+       /* ok, we can stage the msg in the area */
+       la->empty = 0;
+       msg = (struct logmsg *)la->tail;
+       msg->prio = prio;
+       memcpy((void *)&msg->str, buff, len);
+       lastmsg->next = la->tail;
+       msg->next = la->head;
+
+       logdbg(stderr, "enqueue: %p, %p, %i, %s\n", (void *)msg, msg->next,
+               msg->prio, (char *)&msg->str);
+
+#if LOGDBG
+       dump_logarea();
+#endif
+       return 0;
+}
+
+int log_dequeue (void * buff)
+{
+       struct logmsg * src = (struct logmsg *)la->head;
+       struct logmsg * dst = (struct logmsg *)buff;
+       struct logmsg * lst = (struct logmsg *)la->tail;
+
+       if (la->empty)
+               return 1;
+
+       int len = strlen((char *)&src->str) * sizeof(char) +
+                 sizeof(struct logmsg) + 1;
+
+       dst->prio = src->prio;
+       memcpy(dst, src,  len);
+
+       if (la->tail == la->head)
+               la->empty = 1; /* we purge the last logmsg */
+       else {
+               la->head = src->next;
+               lst->next = la->head;
+       }
+       logdbg(stderr, "dequeue: %p, %p, %i, %s\n",
+               (void *)src, src->next, src->prio, (char *)&src->str);
+
+       memset((void *)src, 0,  len);
+
+       return la->empty;
+}
+
+/*
+ * this one can block under memory pressure
+ */
+static void log_syslog (void * buff)
+{
+       struct logmsg * msg = (struct logmsg *)buff;
+
+       syslog(msg->prio, "%s", (char *)&msg->str);
+}
+
+static void dolog(int prio, const char *fmt, va_list ap)
+{
+       if (is_daemon) {
+               la->ops[0].sem_op = -1;
+               if (semop(la->semid, la->ops, 1) < 0) {
+                       syslog(LOG_ERR, "semop up failed");
+                       return;
+               }
+
+               log_enqueue(prio, fmt, ap);
+
+               la->ops[0].sem_op = 1;
+               if (semop(la->semid, la->ops, 1) < 0) {
+                       syslog(LOG_ERR, "semop down failed");
+                       return;
+               }
+       } else {
+               fprintf(stderr, "%s: ", log_name);
+               vfprintf(stderr, fmt, ap);
+               fflush(stderr);
+       }
+}
+
+void log_warning(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       dolog(LOG_WARNING, fmt, ap);
+       va_end(ap);
+}
+
+void log_error(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       dolog(LOG_ERR, fmt, ap);
+       va_end(ap);
+}
+
+void log_debug(const char *fmt, ...)
+{
+       if (!is_debug)
+               return;
+
+       va_list ap;
+       va_start(ap, fmt);
+       dolog(LOG_DEBUG, fmt, ap);
+       va_end(ap);
+}
+
+static void log_flush(void)
+{
+       while (!la->empty) {
+               la->ops[0].sem_op = -1;
+               if (semop(la->semid, la->ops, 1) < 0) {
+                       syslog(LOG_ERR, "semop up failed");
+                       exit(1);
+               }
+               log_dequeue(la->buff);
+               la->ops[0].sem_op = 1;
+               if (semop(la->semid, la->ops, 1) < 0) {
+                       syslog(LOG_ERR, "semop down failed");
+                       exit(1);
+               }
+               log_syslog(la->buff);
+       }
+}
+
+int log_init(char *program_name, int size, int daemon, int debug)
+{
+       is_daemon = daemon;
+       is_debug = debug;
+
+       logdbg(stderr,"enter log_init\n");
+       log_name = program_name;
+       if (is_daemon) {
+               struct sigaction sa_old;
+               struct sigaction sa_new;
+               pid_t pid;
+
+               openlog(log_name, 0, LOG_DAEMON);
+               setlogmask (LOG_UPTO (LOG_DEBUG));
+
+               if (logarea_init(size)) {
+                       syslog(LOG_ERR, "failed to initialize the logger\n");
+                       return 1;
+               }
+
+               pid = fork();
+               if (pid < 0) {
+                       syslog(LOG_ERR, "fail to fork the logger\n");
+                       return 1;
+               } else if (pid) {
+                       syslog(LOG_WARNING,
+                              "Target daemon logger with pid=%d started!\n", 
pid);
+                       return 0;
+               }
+
+               /* flush on daemon's crash */
+               sa_new.sa_handler = (void*)log_flush;
+               sigemptyset(&sa_new.sa_mask);
+               sa_new.sa_flags = 0;
+               sigaction(SIGSEGV, &sa_new, &sa_old );
+
+               while(1) {
+                       log_flush();
+                       sleep(1);
+               }
+               exit(0);
+       }
+
+       return 0;
+}
+
+void log_close (void)
+{
+       if (is_daemon) {
+               closelog();
+               free_logarea();
+       }
+       return;
+}
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/log.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/log.h  Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,84 @@
+/*
+ * iSCSI Safe Logging and Tracing Library
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * maintained by open-iscsi@xxxxxxxxxxxxxxxx
+ *
+ * circular buffer code based on log.c from dm-multipath project
+ *
+ * heavily based on code from log.c:
+ *   Copyright (C) 2002-2003 Ardis Technolgies <roman@xxxxxxxxxxxxx>,
+ *   licensed under the terms of the GNU GPL v2.0,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+#ifndef LOG_H
+#define LOG_H
+
+#include <sys/sem.h>
+
+union semun {
+       int val;
+       struct semid_ds *buf;
+       unsigned short int *array;
+       struct seminfo *__buf;
+};
+
+#define LOG_SPACE_SIZE 16384
+#define MAX_MSG_SIZE 256
+
+extern int log_daemon;
+extern int log_level;
+
+struct logmsg {
+       short int prio;
+       void *next;
+       char *str;
+};
+
+struct logarea {
+       int empty;
+       void *head;
+       void *tail;
+       void *start;
+       void *end;
+       char *buff;
+       struct sembuf ops[1];
+       int semid;
+       union semun semarg;
+};
+
+struct logarea *la;
+
+extern int log_init (char * progname, int size, int daemon, int debug);
+extern void log_close (void);
+extern void dump_logmsg (void *);
+extern void log_warning(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+extern void log_error(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+extern void log_debug(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+
+#define eprintf(fmt, args...)                                          \
+do {                                                                   \
+       log_error("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);       \
+} while (0)
+
+#define dprintf(fmt, args...)                                          \
+do {                                                                   \
+       log_debug("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);       \
+} while (0)
+
+#endif /* LOG_H */
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/mgmt.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/mgmt.c Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,308 @@
+/*
+ * SCSI target management functions
+ *
+ * Copyright (C) 2005 FUJITA Tomonori <tomof@xxxxxxx>
+ * Copyright (C) 2005 Mike Christie <michaelc@xxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <scsi/scsi_tgt_if.h>
+
+#include "tgtd.h"
+#include "log.h"
+#include "tgtadm.h"
+#include "driver.h"
+
+#define BUFSIZE 4096
+
+static void device_create_parser(char *args, char **path, char **devtype)
+{
+       char *p, *q;
+
+       if (isspace(*args))
+               args++;
+       if ((p = strchr(args, '\n')))
+               *p = '\0';
+
+       while ((p = strsep(&args, ","))) {
+               if (!p)
+                       continue;
+
+               if (!(q = strchr(p, '=')))
+                       continue;
+               *q++ = '\0';
+
+               if (!strcmp(p, "Path"))
+                       *path = q;
+               else if (!strcmp(p, "Type"))
+                       *devtype = q;
+       }
+}
+
+static int target_mgmt(int lld_no, struct tgtadm_req *req, char *params,
+                      struct tgtadm_res *res, int *rlen)
+{
+       int err = -EINVAL;
+
+       switch (req->op) {
+       case OP_NEW:
+               err = tgt_target_create(req->tid);
+               if (!err && tgt_drivers[lld_no]->target_create)
+                       tgt_drivers[lld_no]->target_create(req->tid, params);
+               break;
+       case OP_DELETE:
+               err = tgt_target_destroy(req->tid);
+               if (!err && tgt_drivers[lld_no]->target_destroy)
+                       tgt_drivers[lld_no]->target_destroy(req->tid);
+               break;
+       case OP_BIND:
+               err = tgt_target_bind(req->tid, req->host_no, lld_no);
+               break;
+       default:
+               break;
+       }
+
+       res->err = err;
+       res->len = (char *) res->data - (char *) res;
+
+       return err;
+}
+
+static int device_mgmt(int lld_no, struct tgtadm_req *req, char *params,
+                      struct tgtadm_res *res, int *rlen)
+{
+       int err = -EINVAL;
+       char *path, *devtype;
+
+       switch (req->op) {
+       case OP_NEW:
+               path = devtype = NULL;
+               device_create_parser(params, &path, &devtype);
+               if (!path)
+                       eprintf("Invalid path\n");
+               else
+                       err = tgt_device_create(req->tid, req->lun, path);
+               break;
+       case OP_DELETE:
+               err = tgt_device_destroy(req->tid, req->lun);
+               break;
+       default:
+               break;
+       }
+
+       res->err = err;
+       res->len = (char *) res->data - (char *) res;
+
+       return err;
+}
+
+int tgt_mgmt(int lld_no, struct tgtadm_req *req, struct tgtadm_res *res,
+            int len)
+{
+       int err = -EINVAL;
+       char *params = (char *) req->data;
+
+       dprintf("%d %d %d %d %d %" PRIx64 " %" PRIx64 " %s %d\n",
+               req->len, lld_no, req->mode, req->op,
+               req->tid, req->sid, req->lun, params, getpid());
+
+       switch (req->mode) {
+       case MODE_TARGET:
+               err = target_mgmt(lld_no, req, params, res, &len);
+               break;
+       case MODE_DEVICE:
+               err = device_mgmt(lld_no, req, params, res, &len);
+               break;
+       default:
+               break;
+       }
+
+       return err;
+}
+
+static int ipc_accept(int accept_fd)
+{
+       struct sockaddr addr;
+       socklen_t len;
+       int fd;
+
+       len = sizeof(addr);
+       fd = accept(accept_fd, (struct sockaddr *) &addr, &len);
+       if (fd < 0)
+               eprintf("can't accept a new connection %s\n", strerror(errno));
+       return fd;
+}
+
+static int ipc_perm(int fd)
+{
+       struct ucred cred;
+       socklen_t len;
+       int err;
+
+       len = sizeof(cred);
+       err = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, (void *) &cred, &len);
+       if (err) {
+               eprintf("can't get sockopt %s\n", strerror(errno));
+               return -1;
+       }
+
+       if (cred.uid || cred.gid)
+               return -EPERM;
+
+       return 0;
+}
+
+static void ipc_send_res(int fd, struct tgtadm_res *res)
+{
+       struct iovec iov;
+       struct msghdr msg;
+       int err;
+
+       iov.iov_base = res;
+       iov.iov_len = res->len;
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+
+       err = sendmsg(fd, &msg, MSG_DONTWAIT);
+       if (err != res->len)
+               eprintf("can't write %s\n", strerror(errno));
+}
+
+void ipc_event_handle(int accept_fd)
+{
+       int fd, err;
+       char sbuf[BUFSIZE], rbuf[BUFSIZE];
+       struct iovec iov;
+       struct msghdr msg;
+       struct tgtadm_req *req;
+       struct tgtadm_res *res;
+       int lld_no, len;
+
+       req = (struct tgtadm_req *) sbuf;
+       memset(sbuf, 0, sizeof(sbuf));
+
+       fd = ipc_accept(accept_fd);
+       if (fd < 0)
+               return;
+
+       err = ipc_perm(fd);
+       if (err < 0)
+               goto out;
+
+       len = (char *) req->data - (char *) req;
+       iov.iov_base = req;
+       iov.iov_len = len;
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+
+       err = recvmsg(fd, &msg, MSG_PEEK | MSG_DONTWAIT);
+       if (err != len) {
+               eprintf("can't read %s\n", strerror(errno));
+               goto out;
+       }
+
+       if (req->len > sizeof(sbuf) - len) {
+               eprintf("too long data %d\n", req->len);
+               goto out;
+       }
+
+       iov.iov_base = req;
+       iov.iov_len = req->len;
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+
+       err = recvmsg(fd, &msg, MSG_DONTWAIT);
+       if (err != req->len) {
+               eprintf("can't read %s\n", strerror(errno));
+               err = -EIO;
+               goto out;
+       }
+
+       dprintf("%d %s %d %d %d\n", req->mode, req->lld, err, req->len, fd);
+       res = (struct tgtadm_res *) rbuf;
+       memset(rbuf, 0, sizeof(rbuf));
+
+       lld_no = get_driver_index(req->lld);
+       if (lld_no < 0) {
+               eprintf("can't find the driver\n");
+               res->err = ENOENT;
+               res->len = (char *) res->data - (char *) res;
+               goto send;
+       }
+
+       err = tgt_mgmt(lld_no, req, res, sizeof(rbuf));
+       if (err)
+               eprintf("%d %d %d %d\n", req->mode, lld_no, err, res->len);
+
+send:
+       ipc_send_res(fd, res);
+out:
+       if (fd > 0)
+               close(fd);
+
+       return;
+}
+
+int ipc_init(int *ipc_fd)
+{
+       int fd, err;
+       struct sockaddr_un addr;
+
+       fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+       if (fd < 0) {
+               eprintf("can't open a socket %s\n", strerror(errno));
+               return -1;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_LOCAL;
+       memcpy((char *) &addr.sun_path + 1, TGT_IPC_NAMESPACE,
+              strlen(TGT_IPC_NAMESPACE));
+
+       err = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
+       if (err) {
+               eprintf("can't bind a socket %s\n", strerror(errno));
+               goto out;
+       }
+
+       err = listen(fd, 32);
+       if (err < 0) {
+               eprintf("can't listen a socket %s\n", strerror(errno));
+               goto out;
+       }
+
+       *ipc_fd = fd;
+       return 0;
+out:
+       close(fd);
+       return -1;
+}
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/scsi.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/scsi.c Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,577 @@
+/*
+ * SCSI command processing
+ *
+ * (C) 2004 - 2005 FUJITA Tomonori <tomof@xxxxxxx>
+ * (C) 2005 Mike Christie <michaelc@xxxxxxxxxxx>
+ *
+ * SCSI target emulation code is based on Ardis's iSCSI implementation.
+ *   http://www.ardistech.com/iscsi/
+ *   Copyright (C) 2002-2003 Ardis Technolgies <roman@xxxxxxxxxxxxx>,
+ *   licensed under the terms of the GNU GPL v2.0,
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <byteswap.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <syscall.h>
+#include <unistd.h>
+#include <linux/fs.h>
+#include <sys/mman.h>
+
+#include "tgtd.h"
+#include "driver.h"
+#include "scsi.h"
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define __cpu_to_be32(x) bswap_32(x)
+#define __cpu_to_be64(x) bswap_64(x)
+#define __be32_to_cpu(x) bswap_32(x)
+#define __be64_to_cpu(x) bswap_64(x)
+#else
+#define __cpu_to_be32(x) (x)
+#define __cpu_to_be64(x) (x)
+#define __be32_to_cpu(x) (x)
+#define __be64_to_cpu(x) (x)
+#endif
+
+#define BLK_SHIFT      9
+
+int sense_data_build(uint8_t *data, uint8_t res_code, uint8_t key,
+                    uint8_t ascode, uint8_t ascodeq)
+{
+       int len = 6;
+
+       data[0] = res_code | 1U << 7;
+       data[2] = key;
+       data[7] = len;
+       data[12] = ascode;
+       data[13] = ascodeq;
+
+       return len + 8;
+}
+
+static int insert_disconnect_pg(uint8_t *ptr)
+{
+       unsigned char disconnect_pg[] = {0x02, 0x0e, 0x80, 0x80, 0x00, 0x0a, 
0x00, 0x00,
+                                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00};
+
+       memcpy(ptr, disconnect_pg, sizeof(disconnect_pg));
+       return sizeof(disconnect_pg);
+}
+
+static int insert_caching_pg(uint8_t *ptr)
+{
+       unsigned char caching_pg[] = {0x08, 0x12, 0x14, 0x00, 0xff, 0xff, 0x00, 
0x00,
+                                     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0x00, 
0x00,
+                                     0x00, 0x00, 0x00, 0x00};
+
+       memcpy(ptr, caching_pg, sizeof(caching_pg));
+       return sizeof(caching_pg);
+}
+
+static int insert_ctrl_m_pg(uint8_t *ptr)
+{
+       unsigned char ctrl_m_pg[] = {0x0a, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                    0x00, 0x00, 0x02, 0x4b};
+
+       memcpy(ptr, ctrl_m_pg, sizeof(ctrl_m_pg));
+       return sizeof(ctrl_m_pg);
+}
+
+static int insert_iec_m_pg(uint8_t *ptr)
+{
+       unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0x00, 0x00, 0x00, 0x00,
+                                   0x00, 0x00, 0x00, 0x00, 0x00};
+
+       memcpy(ptr, iec_m_pg, sizeof(iec_m_pg));
+       return sizeof(iec_m_pg);
+}
+
+static int insert_format_m_pg(uint8_t *ptr)
+{
+       unsigned char format_m_pg[] = {0x03, 0x16, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00,
+                                      0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 
0x00, 0x00,
+                                      0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 
0x00, 0x00};
+       memcpy(ptr, format_m_pg, sizeof(format_m_pg));
+       return sizeof(format_m_pg);
+}
+
+static int insert_geo_m_pg(uint8_t *ptr, uint64_t sec)
+{
+       unsigned char geo_m_pg[] = {0x04, 0x16, 0x00, 0x00, 0x00, 0x40, 0x00, 
0x00,
+                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00,
+                                   0x00, 0x00, 0x00, 0x00, 0x3a, 0x98, 0x00, 
0x00};
+       uint32_t ncyl, *p;
+
+       /* assume 0xff heads, 15krpm. */
+       memcpy(ptr, geo_m_pg, sizeof(geo_m_pg));
+       ncyl = sec >> 14; /* 256 * 64 */
+       p = (uint32_t *)(ptr + 1);
+       *p = *p | __cpu_to_be32(ncyl);
+       return sizeof(geo_m_pg);
+}
+
+static int mode_sense(struct tgt_device *dev, uint8_t *scb, uint8_t *data, int 
*len)
+{
+       int result = SAM_STAT_GOOD;
+       uint8_t pcode = scb[2] & 0x3f;
+       uint64_t size;
+
+       *len = 4;
+       size = dev->size >> BLK_SHIFT;
+
+       if ((scb[1] & 0x8))
+               data[3] = 0;
+       else {
+               data[3] = 8;
+               *len += 8;
+               *(uint32_t *)(data + 4) = (size >> 32) ?
+                       __cpu_to_be32(0xffffffff) : __cpu_to_be32(size);
+               *(uint32_t *)(data + 8) = __cpu_to_be32(1 << BLK_SHIFT);
+       }
+
+       switch (pcode) {
+       case 0x0:
+               break;
+       case 0x2:
+               *len += insert_disconnect_pg(data + *len);
+               break;
+       case 0x3:
+               *len += insert_format_m_pg(data + *len);
+               break;
+       case 0x4:
+               *len += insert_geo_m_pg(data + *len, size);
+               break;
+       case 0x8:
+               *len += insert_caching_pg(data + *len);
+               break;
+       case 0xa:
+               *len += insert_ctrl_m_pg(data + *len);
+               break;
+       case 0x1c:
+               *len += insert_iec_m_pg(data + *len);
+               break;
+       case 0x3f:
+               *len += insert_disconnect_pg(data + *len);
+               *len += insert_format_m_pg(data + *len);
+               *len += insert_geo_m_pg(data + *len, size);
+               *len += insert_caching_pg(data + *len);
+               *len += insert_ctrl_m_pg(data + *len);
+               *len += insert_iec_m_pg(data + *len);
+               break;
+       default:
+               result = SAM_STAT_CHECK_CONDITION;
+               *len = sense_data_build(data, 0x70, ILLEGAL_REQUEST,
+                                       0x24, 0);
+       }
+
+       data[0] = *len - 1;
+
+       return result;
+}
+
+#define VENDOR_ID      "IET"
+#define PRODUCT_ID     "VIRTUAL-DISK"
+#define PRODUCT_REV    "0"
+
+static int __inquiry(struct tgt_device *dev, int host_no, uint8_t *lun_buf,
+                    uint8_t *scb, uint8_t *data, int *len)
+{
+       int result = SAM_STAT_CHECK_CONDITION;
+
+       if (((scb[1] & 0x3) == 0x3) || (!(scb[1] & 0x3) && scb[2]))
+               goto err;
+
+       dprintf("%x %x\n", scb[1], scb[2]);
+
+       if (!(scb[1] & 0x3)) {
+               data[2] = 4;
+               data[3] = 0x42;
+               data[4] = 59;
+               data[7] = 0x02;
+               memset(data + 8, 0x20, 28);
+               memcpy(data + 8,
+                      VENDOR_ID, min_t(size_t, strlen(VENDOR_ID), 8));
+               memcpy(data + 16,
+                      PRODUCT_ID, min_t(size_t, strlen(PRODUCT_ID), 16));
+               memcpy(data + 32,
+                      PRODUCT_REV, min_t(size_t, strlen(PRODUCT_REV), 4));
+               data[58] = 0x03;
+               data[59] = 0x20;
+               data[60] = 0x09;
+               data[61] = 0x60;
+               data[62] = 0x03;
+               data[63] = 0x00;
+               *len = 64;
+               result = SAM_STAT_GOOD;
+       } else if (scb[1] & 0x2) {
+               /* CmdDt bit is set */
+               /* We do not support it now. */
+               data[1] = 0x1;
+               data[5] = 0;
+               *len = 6;
+               result = SAM_STAT_GOOD;
+       } else if (scb[1] & 0x1) {
+               /* EVPD bit set */
+               if (scb[2] == 0x0) {
+                       data[1] = 0x0;
+                       data[3] = 3;
+                       data[4] = 0x0;
+                       data[5] = 0x80;
+                       data[6] = 0x83;
+                       *len = 7;
+                       result = SAM_STAT_GOOD;
+               } else if (scb[2] == 0x80) {
+                       data[1] = 0x80;
+                       data[3] = 4;
+                       memset(data + 4, 0x20, 4);
+                       *len = 8;
+                       result = SAM_STAT_GOOD;
+               } else if (scb[2] == 0x83) {
+                       uint32_t tmp = SCSI_ID_LEN * sizeof(uint8_t);
+
+                       data[1] = 0x83;
+                       data[3] = tmp + 4;
+                       data[4] = 0x1;
+                       data[5] = 0x1;
+                       data[7] = tmp;
+                       if (dev)
+                               strncpy(data + 8, dev->scsi_id, SCSI_ID_LEN);
+                       *len = tmp + 8;
+                       result = SAM_STAT_GOOD;
+               }
+       }
+
+       if (result != SAM_STAT_GOOD)
+               goto err;
+
+       *len = min_t(int, *len, scb[4]);
+
+       if (!dev)
+               data[0] = TYPE_NO_LUN;
+
+       return SAM_STAT_GOOD;
+
+err:
+       *len = sense_data_build(data, 0x70, ILLEGAL_REQUEST,
+                               0x24, 0);
+       return SAM_STAT_CHECK_CONDITION;
+}
+
+static int inquiry(int lid, struct tgt_device *dev, int host_no,
+                  uint8_t *lun_buf, uint8_t *scb, uint8_t *data, int *len)
+{
+       typeof(__inquiry) *fn;
+
+       fn = tgt_drivers[lid]->scsi_inquiry ? : __inquiry;
+       return fn(dev, host_no, lun_buf, scb, data, len);
+}
+
+static int __report_luns(struct list_head *dev_list, uint8_t *lun_buf,
+                        uint8_t *scb, uint8_t *p, int *len)
+{
+       struct tgt_device *dev;
+       uint64_t lun, *data = (uint64_t *) p;
+       int idx, alen, oalen, nr_luns, rbuflen = 4096;
+       int result = SAM_STAT_GOOD;
+
+       memset(data, 0, rbuflen);
+
+       alen = __be32_to_cpu(*(uint32_t *)&scb[6]);
+       if (alen < 16) {
+               *len = sense_data_build(p, 0x70, ILLEGAL_REQUEST,
+                                       0x24, 0);
+               return SAM_STAT_CHECK_CONDITION;
+       }
+
+       alen &= ~(8 - 1);
+       oalen = alen;
+
+       alen -= 8;
+       rbuflen -= 8; /* FIXME */
+       idx = 1;
+       nr_luns = 0;
+
+       list_for_each_entry(dev, dev_list, dlist) {
+               lun = dev->lun;
+
+               lun = ((lun > 0xff) ? (0x1 << 30) : 0) | ((0x3ff & lun) << 16);
+               data[idx++] = __cpu_to_be64(lun << 32);
+               if (!(alen -= 8))
+                       break;
+               if (!(rbuflen -= 8)) {
+                       fprintf(stderr, "FIXME: too many luns\n");
+                       exit(-1);
+               }
+               nr_luns++;
+       }
+
+       *((uint32_t *) data) = __cpu_to_be32(nr_luns * 8);
+       *len = min(oalen, nr_luns * 8 + 8);
+
+       return result;
+}
+
+static int report_luns(int lid, struct list_head *dev_list, uint8_t *lun_buf,
+                      uint8_t *scb, uint8_t *p, int *len)
+{
+       typeof(__report_luns) *fn;
+       fn = tgt_drivers[lid]->scsi_report_luns ? : __report_luns;
+       return fn(dev_list, lun_buf, scb, p, len);
+}
+
+static int read_capacity(struct tgt_device *dev, uint8_t *scb, uint8_t *p, int 
*len)
+{
+       uint32_t *data = (uint32_t *) p;
+       uint64_t size;
+
+       if (!(scb[8] & 0x1) & (scb[2] | scb[3] | scb[4] | scb[5])) {
+               *len = sense_data_build(p, 0x70, ILLEGAL_REQUEST,
+                                       0x24, 0);
+               return SAM_STAT_CHECK_CONDITION;
+       }
+
+       size = dev->size >> BLK_SHIFT;
+
+       data[0] = (size >> 32) ?
+               __cpu_to_be32(0xffffffff) : __cpu_to_be32(size - 1);
+       data[1] = __cpu_to_be32(1U << BLK_SHIFT);
+       *len = 8;
+
+       return SAM_STAT_GOOD;
+}
+
+static int sync_cache(struct tgt_device *dev, uint8_t *data, int *len)
+{
+       int err;
+
+       err = fsync(dev->fd);
+
+       switch (err) {
+       case EROFS:
+       case EINVAL:
+       case EBADF:
+       case EIO:
+               /*
+                * is this the right sense code?
+                * what should I put for the asc/ascq?
+                */
+               *len = sense_data_build(data, 0x70, ILLEGAL_REQUEST, 0, 0);
+               return SAM_STAT_CHECK_CONDITION;
+       default:
+               *len = 0;
+               return SAM_STAT_GOOD;
+       }
+}
+
+/*
+ * TODO: We always assume autosense.
+ */
+static int request_sense(uint8_t *data, int* len)
+{
+       *len = sense_data_build(data, 0x70, NO_SENSE, 0, 0);
+
+       return SAM_STAT_GOOD;
+}
+
+static int sevice_action(struct tgt_device *dev, uint8_t *scb, uint8_t *p, int 
*len)
+{
+       uint32_t *data = (uint32_t *) p;
+       uint64_t *data64, size;
+
+       size = dev->size >> BLK_SHIFT;
+
+       data64 = (uint64_t *) data;
+       data64[0] = __cpu_to_be64(size - 1);
+       data[2] = __cpu_to_be32(1UL << BLK_SHIFT);
+
+       *len = 32;
+
+       return SAM_STAT_GOOD;
+}
+
+static int mmap_device(uint8_t *scb, int *len, int fd, uint32_t datalen,
+                      struct iovec *iov, int iovcnt, uint64_t *offset, int rw)
+{
+       void *p;
+       uint64_t off;
+       *len = 0;
+       int err = SAM_STAT_GOOD;
+
+       switch (scb[0]) {
+       case READ_6:
+       case WRITE_6:
+               off = ((scb[1] & 0x1f) << 16) + (scb[2] << 8) + scb[3];
+               break;
+       case READ_10:
+       case WRITE_10:
+       case WRITE_VERIFY:
+               off = __be32_to_cpu(*(uint32_t *) &scb[2]);
+               break;
+       case READ_16:
+       case WRITE_16:
+               off = __be64_to_cpu(*(uint64_t *) &scb[2]);
+               break;
+       default:
+               off = 0;
+               break;
+       }
+
+       off <<= BLK_SHIFT;
+
+       lseek64(fd, off, SEEK_SET);
+       if (rw == READ)
+               readv(fd, iov, iovcnt);
+       else
+               writev(fd, iov, iovcnt);
+
+       *offset = off;
+       *len = datalen;
+       printf("%u %" PRIu64 "\n", datalen, off);
+
+       return err;
+}
+
+static inline int mmap_cmd_init(uint8_t *scb, uint8_t *rw)
+{
+       int result = 1;
+
+       switch (scb[0]) {
+       case READ_6:
+       case READ_10:
+       case READ_16:
+               *rw = READ;
+               break;
+       case WRITE_6:
+       case WRITE_10:
+       case WRITE_16:
+       case WRITE_VERIFY:
+               *rw = WRITE;
+               break;
+       default:
+               result = 0;
+       }
+       return result;
+}
+
+#define        TGT_INVALID_DEV_ID      ~0ULL
+
+static uint64_t __scsi_get_devid(uint8_t *p)
+{
+       uint64_t lun = TGT_INVALID_DEV_ID;
+
+       switch (*p >> 6) {
+       case 0:
+               lun = p[1];
+               break;
+       case 1:
+               lun = (0x3f & p[0]) << 8 | p[1];
+               break;
+       case 2:
+       case 3:
+       default:
+               break;
+       }
+
+       return lun;
+}
+
+uint64_t scsi_get_devid(int lid, uint8_t *p)
+{
+       typeof(__scsi_get_devid) *fn;
+       fn = tgt_drivers[lid]->scsi_get_lun ? : __scsi_get_devid;
+       return fn(p);
+}
+
+int scsi_cmd_perform(int lid, int host_no, uint8_t *pdu, int *len,
+                    uint32_t datalen, struct iovec *iov, int iovcnt,
+                    uint8_t *rw, uint8_t *try_map, uint64_t *offset, uint8_t 
*lun_buf,
+                    struct tgt_device *dev, struct list_head *dev_list)
+{
+       int result = SAM_STAT_GOOD;
+       uint8_t *data, *scb = pdu;
+
+       dprintf("%x %u %p\n", scb[0], datalen, iov[0].iov_base);
+
+       *offset = 0;
+       data = iov[0].iov_base; /* FIXME */
+       mmap_cmd_init(scb, rw);
+
+       if (!dev)
+               switch (scb[0]) {
+               case REQUEST_SENSE:
+               case INQUIRY:
+               case REPORT_LUNS:
+                       break;
+               default:
+                       *offset = 0;
+                       *len = sense_data_build(data, 0x70, ILLEGAL_REQUEST,
+                                               0x25, 0);
+                       result = SAM_STAT_CHECK_CONDITION;
+                       goto out;
+               }
+
+       switch (scb[0]) {
+       case INQUIRY:
+               result = inquiry(lid, dev, host_no, lun_buf, scb, data, len);
+               break;
+       case REPORT_LUNS:
+               result = report_luns(lid, dev_list, lun_buf, scb, data, len);
+               break;
+       case READ_CAPACITY:
+               result = read_capacity(dev, scb, data, len);
+               break;
+       case MODE_SENSE:
+               result = mode_sense(dev, scb, data, len);
+               break;
+       case REQUEST_SENSE:
+               result = request_sense(data, len);
+               break;
+       case SERVICE_ACTION_IN:
+               result = sevice_action(dev, scb, data, len);
+               break;
+       case SYNCHRONIZE_CACHE:
+               result = sync_cache(dev, data, len);
+               break;
+       case START_STOP:
+       case TEST_UNIT_READY:
+       case VERIFY:
+               *len = 0;
+               break;
+       case READ_6:
+       case READ_10:
+       case READ_16:
+       case WRITE_6:
+       case WRITE_10:
+       case WRITE_16:
+       case WRITE_VERIFY:
+               result = mmap_device(scb, len, dev->fd, datalen,
+                                    iov, iovcnt, offset, *rw);
+               if (result == SAM_STAT_GOOD)
+                       *try_map = 1;
+               else {
+                       *rw = READ;
+                       *offset = 0;
+                       *len = sense_data_build(data, 0x70, ILLEGAL_REQUEST,
+                                               0x25, 0);
+               }
+               break;
+       case RESERVE:
+       case RELEASE:
+       case RESERVE_10:
+       case RELEASE_10:
+       default:
+               eprintf("unknown command %x %u\n", scb[0], datalen);
+               *len = 0;
+               break;
+       }
+
+out:
+
+       return result;
+}
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/scsi.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/scsi.h Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,145 @@
+/*
+ * taken from kernel.h
+ *
+ * better if we include kernel's one directly.
+ */
+
+#define TEST_UNIT_READY       0x00
+#define REZERO_UNIT           0x01
+#define REQUEST_SENSE         0x03
+#define FORMAT_UNIT           0x04
+#define READ_BLOCK_LIMITS     0x05
+#define REASSIGN_BLOCKS       0x07
+#define INITIALIZE_ELEMENT_STATUS 0x07
+#define READ_6                0x08
+#define WRITE_6               0x0a
+#define SEEK_6                0x0b
+#define READ_REVERSE          0x0f
+#define WRITE_FILEMARKS       0x10
+#define SPACE                 0x11
+#define INQUIRY               0x12
+#define RECOVER_BUFFERED_DATA 0x14
+#define MODE_SELECT           0x15
+#define RESERVE               0x16
+#define RELEASE               0x17
+#define COPY                  0x18
+#define ERASE                 0x19
+#define MODE_SENSE            0x1a
+#define START_STOP            0x1b
+#define RECEIVE_DIAGNOSTIC    0x1c
+#define SEND_DIAGNOSTIC       0x1d
+#define ALLOW_MEDIUM_REMOVAL  0x1e
+
+#define SET_WINDOW            0x24
+#define READ_CAPACITY         0x25
+#define READ_10               0x28
+#define WRITE_10              0x2a
+#define SEEK_10               0x2b
+#define POSITION_TO_ELEMENT   0x2b
+#define WRITE_VERIFY          0x2e
+#define VERIFY                0x2f
+#define SEARCH_HIGH           0x30
+#define SEARCH_EQUAL          0x31
+#define SEARCH_LOW            0x32
+#define SET_LIMITS            0x33
+#define PRE_FETCH             0x34
+#define READ_POSITION         0x34
+#define SYNCHRONIZE_CACHE     0x35
+#define LOCK_UNLOCK_CACHE     0x36
+#define READ_DEFECT_DATA      0x37
+#define MEDIUM_SCAN           0x38
+#define COMPARE               0x39
+#define COPY_VERIFY           0x3a
+#define WRITE_BUFFER          0x3b
+#define READ_BUFFER           0x3c
+#define UPDATE_BLOCK          0x3d
+#define READ_LONG             0x3e
+#define WRITE_LONG            0x3f
+#define CHANGE_DEFINITION     0x40
+#define WRITE_SAME            0x41
+#define READ_TOC              0x43
+#define LOG_SELECT            0x4c
+#define LOG_SENSE             0x4d
+#define MODE_SELECT_10        0x55
+#define RESERVE_10            0x56
+#define RELEASE_10            0x57
+#define MODE_SENSE_10         0x5a
+#define PERSISTENT_RESERVE_IN 0x5e
+#define PERSISTENT_RESERVE_OUT 0x5f
+#define REPORT_LUNS           0xa0
+#define MOVE_MEDIUM           0xa5
+#define EXCHANGE_MEDIUM       0xa6
+#define READ_12               0xa8
+#define WRITE_12              0xaa
+#define WRITE_VERIFY_12       0xae
+#define SEARCH_HIGH_12        0xb0
+#define SEARCH_EQUAL_12       0xb1
+#define SEARCH_LOW_12         0xb2
+#define READ_ELEMENT_STATUS   0xb8
+#define SEND_VOLUME_TAG       0xb6
+#define WRITE_LONG_2          0xea
+#define READ_16               0x88
+#define WRITE_16              0x8a
+#define VERIFY_16            0x8f
+#define SERVICE_ACTION_IN     0x9e
+#define        SAI_READ_CAPACITY_16  0x10
+
+#define SAM_STAT_GOOD            0x00
+#define SAM_STAT_CHECK_CONDITION 0x02
+#define SAM_STAT_CONDITION_MET   0x04
+#define SAM_STAT_BUSY            0x08
+#define SAM_STAT_INTERMEDIATE    0x10
+#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14
+#define SAM_STAT_RESERVATION_CONFLICT 0x18
+#define SAM_STAT_COMMAND_TERMINATED 0x22
+#define SAM_STAT_TASK_SET_FULL   0x28
+#define SAM_STAT_ACA_ACTIVE      0x30
+#define SAM_STAT_TASK_ABORTED    0x40
+
+#define NO_SENSE            0x00
+#define RECOVERED_ERROR     0x01
+#define NOT_READY           0x02
+#define MEDIUM_ERROR        0x03
+#define HARDWARE_ERROR      0x04
+#define ILLEGAL_REQUEST     0x05
+#define UNIT_ATTENTION      0x06
+#define DATA_PROTECT        0x07
+#define BLANK_CHECK         0x08
+#define COPY_ABORTED        0x0a
+#define ABORTED_COMMAND     0x0b
+#define VOLUME_OVERFLOW     0x0d
+#define MISCOMPARE          0x0e
+
+#define TYPE_DISK           0x00
+#define TYPE_TAPE           0x01
+#define TYPE_PRINTER        0x02
+#define TYPE_PROCESSOR      0x03
+#define TYPE_WORM           0x04
+#define TYPE_ROM            0x05
+#define TYPE_SCANNER        0x06
+#define TYPE_MOD            0x07
+
+#define TYPE_MEDIUM_CHANGER 0x08
+#define TYPE_COMM           0x09
+#define TYPE_RAID           0x0c
+#define TYPE_ENCLOSURE      0x0d
+#define TYPE_RBC           0x0e
+#define TYPE_NO_LUN         0x7f
+
+#define        MSG_SIMPLE_TAG  0x20
+#define        MSG_HEAD_TAG    0x21
+#define        MSG_ORDERED_TAG 0x22
+
+#define        MAX_NR_TARGET           1024
+#define        MAX_NR_HOST             1024
+#define        DEFAULT_NR_DEVICE       64
+#define        MAX_NR_DEVICE           (1 << 20)
+
+#define ABORT_TASK          0x0d
+#define ABORT_TASK_SET      0x06
+#define CLEAR_ACA           0x16
+#define CLEAR_TASK_SET      0x0e
+#define LOGICAL_UNIT_RESET  0x17
+#define TASK_ABORTED         0x20
+#define SAM_STAT_TASK_ABORTED    0x40
+
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/target.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/target.c       Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,795 @@
+/*
+ * SCSI target daemon core functions
+ *
+ * Copyright (C) 2005 FUJITA Tomonori <tomof@xxxxxxx>
+ * Copyright (C) 2005 Mike Christie <michaelc@xxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <poll.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <linux/fs.h>
+
+#ifndef BITS_PER_LONG
+#define BITS_PER_LONG (ULONG_MAX == 0xFFFFFFFFUL ? 32 : 64)
+#endif
+#include <linux/hash.h>
+
+#include "tgtd.h"
+#include "tgtadm.h"
+#include "driver.h"
+#include "scsi.h"
+
+#define        HASH_ORDER      4
+#define        cmd_hashfn(cid) hash_long((cid), HASH_ORDER)
+
+enum {
+       TGT_QUEUE_BLOCKED,
+       TGT_QUEUE_DELETED,
+};
+
+enum {
+       TGT_CMD_QUEUED,
+       TGT_CMD_PROCESSED,
+};
+
+struct scsi_iovec {
+       uint32_t iovcnt;
+       struct iovec iov[0];
+} __attribute__((packed));
+
+struct mgmt_req {
+       uint64_t mid;
+       int busy;
+       int function;
+};
+
+struct cmd {
+       struct list_head hlist;
+       struct list_head qlist;
+       struct list_head clist;
+       uint32_t cid;
+       uint64_t uaddr;
+       uint32_t len;
+       int mmapped;
+       struct tgt_device *dev;
+       unsigned long state;
+
+       /* Kill the followings when we use shared memory instead of netlink. */
+       int hostno;
+       uint32_t data_len;
+       uint8_t scb[16];
+       uint8_t lun[8];
+       int attribute;
+       uint64_t tag;
+       struct mgmt_req *mreq;
+       struct scsi_iovec *siov;
+};
+
+struct target {
+       int tid;
+       int lid;
+
+       uint64_t max_device;
+       struct tgt_device **devt;
+       struct list_head device_list;
+
+       struct list_head cmd_hash_list[1 << HASH_ORDER];
+       struct list_head cmd_list;
+       struct tgt_cmd_queue cmd_queue;
+};
+
+static struct target *tgtt[MAX_NR_TARGET];
+static struct target *hostt[MAX_NR_HOST];
+
+#define QUEUE_FNS(bit, name)                                           \
+static inline void set_queue_##name(struct tgt_cmd_queue *q)           \
+{                                                                      \
+       (q)->state |= (1UL << TGT_QUEUE_##bit);                         \
+}                                                                      \
+static inline void clear_queue_##name(struct tgt_cmd_queue *q)         \
+{                                                                      \
+       (q)->state &= ~(1UL << TGT_QUEUE_##bit);                        \
+}                                                                      \
+static inline int queue_##name(const struct tgt_cmd_queue *q)          \
+{                                                                      \
+       return ((q)->state & (1UL << TGT_QUEUE_##bit));                 \
+}
+
+static inline int queue_active(const struct tgt_cmd_queue *q)          \
+{                                                                      \
+       return ((q)->active_cmd);                                       \
+}
+
+QUEUE_FNS(BLOCKED, blocked)
+QUEUE_FNS(DELETED, deleted)
+
+#define CMD_FNS(bit, name)                                             \
+static inline void set_cmd_##name(struct cmd *c)                       \
+{                                                                      \
+       (c)->state |= (1UL << TGT_CMD_##bit);                           \
+}                                                                      \
+static inline void clear_cmd_##name(struct cmd *c)                     \
+{                                                                      \
+       (c)->state &= ~(1UL << TGT_CMD_##bit);                          \
+}                                                                      \
+static inline int cmd_##name(const struct cmd *c)                      \
+{                                                                      \
+       return ((c)->state & (1UL << TGT_CMD_##bit));                   \
+}
+
+CMD_FNS(QUEUED, queued)
+CMD_FNS(PROCESSED, processed)
+
+
+static struct target *target_get(int tid)
+{
+       if (tid >= MAX_NR_TARGET) {
+               eprintf("Too larget target id %d\n", tid);
+               return NULL;
+       }
+       return tgtt[tid];
+}
+
+static struct tgt_device *device_get(struct target *target, uint64_t dev_id)
+{
+       if (dev_id < target->max_device || dev_id < MAX_NR_DEVICE)
+               return target->devt[dev_id];
+
+       dprintf("Invalid device id %" PRIu64 "%d\n", dev_id, MAX_NR_DEVICE);
+       return NULL;
+}
+
+static struct target *host_to_target(int host_no)
+{
+       if (host_no < MAX_NR_HOST)
+               return hostt[host_no];
+
+       return NULL;
+}
+
+static void resize_device_table(struct target *target, uint64_t did)
+{
+       struct tgt_device *device;
+       void *p, *q;
+
+       p = calloc(did + 1, sizeof(device));
+       memcpy(p, target->devt, sizeof(device) * target->max_device);
+       q = target->devt;
+       target->devt = p;
+       target->max_device = did + 1;
+       free(q);
+}
+
+static void tgt_device_link(struct target *target, struct tgt_device *dev)
+{
+       struct tgt_device *ent;
+       struct list_head *pos;
+
+       list_for_each(pos, &target->device_list) {
+               ent = list_entry(pos, struct tgt_device, dlist);
+               if (dev->lun < ent->lun)
+                       break;
+       }
+       list_add(&dev->dlist, pos);
+}
+
+void tgt_cmd_queue_init(struct tgt_cmd_queue *q)
+{
+       q->active_cmd = 0;
+       q->state = 0;
+       INIT_LIST_HEAD(&q->queue);
+}
+
+int tgt_device_create(int tid, uint64_t dev_id, char *path)
+{
+       struct target *target;
+       struct tgt_device *device;
+       struct stat64 st;
+       int err, dev_fd;
+       uint64_t size;
+
+       dprintf("%d %" PRIu64 " %s\n", tid, dev_id, path);
+
+       target = target_get(tid);
+       if (!target)
+               return -ENOENT;
+
+       device = device_get(target, dev_id);
+       if (device) {
+               eprintf("device %" PRIu64 " already exists\n", dev_id);
+               return -EINVAL;
+       }
+
+       dev_fd = open(path, O_RDWR | O_LARGEFILE);
+       if (dev_fd < 0) {
+               eprintf("Could not open %s %s\n", path, strerror(errno));
+               return dev_fd;
+       }
+
+       err = fstat64(dev_fd, &st);
+       if (err < 0) {
+               printf("Cannot get stat %d %s\n", dev_fd, strerror(errno));
+               goto close_dev_fd;
+       }
+
+       if (S_ISREG(st.st_mode))
+               size = st.st_size;
+       else if(S_ISBLK(st.st_mode)) {
+               err = ioctl(dev_fd, BLKGETSIZE64, &size);
+               if (err < 0) {
+                       eprintf("Cannot get size %s\n", strerror(errno));
+                       goto close_dev_fd;
+               }
+       } else {
+               eprintf("Cannot use this mode %x\n", st.st_mode);
+               goto close_dev_fd;
+       }
+
+       if (dev_id >= target->max_device)
+               resize_device_table(target, dev_id);
+
+       device = malloc(sizeof(*device));
+       if (!device)
+               goto close_dev_fd;
+
+       device->fd = dev_fd;
+       device->addr = 0;
+       device->size = size;
+       device->lun = dev_id;
+       snprintf(device->scsi_id, sizeof(device->scsi_id),
+                "deadbeaf%d:%" PRIu64, tid, dev_id);
+       target->devt[dev_id] = device;
+
+       if (device->addr)
+               eprintf("Succeed to mmap the device %" PRIx64 "\n",
+                       device->addr);
+
+       tgt_device_link(target, device);
+       tgt_cmd_queue_init(&device->cmd_queue);
+
+       eprintf("Succeed to add a logical unit %" PRIu64 " to the target %d\n",
+               dev_id, tid);
+
+       return 0;
+close_dev_fd:
+       close(dev_fd);
+       return err;
+}
+
+int tgt_device_destroy(int tid, uint64_t dev_id)
+{
+       struct target *target;
+       struct tgt_device *device;
+
+       dprintf("%u %" PRIu64 "\n", tid, dev_id);
+
+       target = target_get(tid);
+       if (!target)
+               return -ENOENT;
+
+       device = device_get(target, dev_id);
+       if (!device) {
+               eprintf("device %" PRIu64 " not found\n", dev_id);
+               return -EINVAL;
+       }
+
+       if (!list_empty(&device->cmd_queue.queue))
+               return -EBUSY;
+
+       target->devt[dev_id] = NULL;
+       if (device->addr)
+               munmap((void *) (unsigned long) device->addr, device->size);
+
+       close(device->fd);
+
+       list_del(&device->dlist);
+
+       free(device);
+       return 0;
+}
+
+static int tgt_kspace_send_cmd(struct cmd *cmd, int result, int rw)
+{
+       struct tgt_event ev;
+
+       ev.type = TGT_UEVENT_CMD_RSP;
+       ev.u.cmd_rsp.host_no = cmd->hostno;
+       ev.u.cmd_rsp.cid = cmd->cid;
+       ev.u.cmd_rsp.len = cmd->len;
+       ev.u.cmd_rsp.result = result;
+       ev.u.cmd_rsp.uaddr = cmd->uaddr;
+       ev.u.cmd_rsp.rw = rw;
+
+       return kreq_send(&ev);
+}
+
+static int cmd_pre_perform(struct tgt_cmd_queue *q, struct cmd *cmd)
+{
+       int enabled = 0;
+
+       if (cmd->attribute != MSG_SIMPLE_TAG)
+               dprintf("non simple attribute %u %x %" PRIu64 " %d\n",
+                       cmd->cid, cmd->attribute, cmd->dev ? cmd->dev->lun : 
~0ULL,
+                       q->active_cmd);
+
+       switch (cmd->attribute) {
+       case MSG_SIMPLE_TAG:
+               if (!queue_blocked(q))
+                       enabled = 1;
+               break;
+       case MSG_ORDERED_TAG:
+               if (!queue_blocked(q) && !queue_active(q))
+                       enabled = 1;
+               break;
+       case MSG_HEAD_TAG:
+               enabled = 1;
+               break;
+       default:
+               eprintf("unknown command attribute %x\n", cmd->attribute);
+               cmd->attribute = MSG_ORDERED_TAG;
+               if (!queue_blocked(q) && !queue_active(q))
+                       enabled = 1;
+       }
+
+       return enabled;
+}
+
+static void cmd_post_perform(struct tgt_cmd_queue *q, struct cmd *cmd,
+                            unsigned long uaddr,
+                            int len, uint8_t mmapped)
+{
+       cmd->uaddr = uaddr;
+       cmd->len = len;
+       cmd->mmapped = mmapped;
+
+       q->active_cmd++;
+       switch (cmd->attribute) {
+       case MSG_ORDERED_TAG:
+       case MSG_HEAD_TAG:
+               set_queue_blocked(q);
+               break;
+       }
+}
+
+static void cmd_queue(struct tgt_event *ev_req)
+{
+       struct target *target;
+       struct tgt_cmd_queue *q;
+       struct cmd *cmd;
+       int result, enabled, len = 0;
+       uint64_t offset, dev_id;
+       uint8_t rw = 0, mmapped = 0;
+       int hostno = ev_req->k.cmd_req.host_no;
+
+       target = host_to_target(hostno);
+       if (!target) {
+               int tid, lid = 0, err = -1;
+               if (tgt_drivers[lid]->target_bind) {
+                       /* FIXME! */
+                       tid = tgt_drivers[0]->target_bind(hostno);
+                       if (tid >= 0) {
+                               err = tgt_target_bind(tid, hostno, lid);
+                               if (!err)
+                                       target = host_to_target(hostno);
+                       }
+               }
+
+               if (!target) {
+                       eprintf("%d is not bind to any target\n",
+                               ev_req->k.cmd_req.host_no);
+                       return;
+               }
+       }
+
+       /* TODO: preallocate cmd */
+       cmd = calloc(1, sizeof(*cmd));
+       cmd->hostno = ev_req->k.cmd_req.host_no;
+       cmd->cid = ev_req->k.cmd_req.cid;
+       cmd->attribute = ev_req->k.cmd_req.attribute;
+       cmd->tag = ev_req->k.cmd_req.tag;
+
+       dprintf("%llx\n", ev_req->k.cmd_req.uaddr);
+
+       cmd->siov = (struct scsi_iovec *)
+               (void *) ((unsigned long) ev_req->k.cmd_req.uaddr);
+
+       dprintf("%d %p %u\n", cmd->siov->iovcnt, cmd->siov->iov[0].iov_base,
+               cmd->siov->iov[0].iov_len);
+
+       list_add(&cmd->clist, &target->cmd_list);
+       list_add(&cmd->hlist, &target->cmd_hash_list[cmd_hashfn(cmd->cid)]);
+
+       dev_id = scsi_get_devid(target->lid, ev_req->k.cmd_req.lun);
+       dprintf("%u %x %" PRIx64 "\n", cmd->cid, ev_req->k.cmd_req.scb[0],
+               dev_id);
+
+       cmd->dev = device_get(target, dev_id);
+       if (cmd->dev)
+               q = &cmd->dev->cmd_queue;
+       else
+               q = &target->cmd_queue;
+
+       enabled = cmd_pre_perform(q, cmd);
+
+       if (enabled) {
+               result = scsi_cmd_perform(target->lid,
+                                         cmd->hostno, ev_req->k.cmd_req.scb,
+                                         &len, ev_req->k.cmd_req.data_len,
+                                         &(cmd->siov->iov[0]), 
cmd->siov->iovcnt,
+                                         &rw, &mmapped, &offset,
+                                         ev_req->k.cmd_req.lun, cmd->dev,
+                                         &target->device_list);
+
+               cmd_post_perform(q, cmd, 0, len, mmapped);
+
+               dprintf("%u %x %"  PRIx64 " %d\n",
+                       cmd->cid, ev_req->k.cmd_req.scb[0], offset, result);
+
+               set_cmd_processed(cmd);
+               tgt_kspace_send_cmd(cmd, result, rw);
+       } else {
+               set_cmd_queued(cmd);
+               dprintf("blocked %u %x %" PRIu64 " %d\n",
+                       cmd->cid, ev_req->k.cmd_req.scb[0],
+                       cmd->dev ? cmd->dev->lun : ~0ULL,
+                       q->active_cmd);
+
+               memcpy(cmd->scb, ev_req->k.cmd_req.scb, sizeof(cmd->scb));
+               memcpy(cmd->lun, ev_req->k.cmd_req.lun, sizeof(cmd->lun));
+               cmd->len = ev_req->k.cmd_req.data_len;
+               list_add_tail(&cmd->qlist, &q->queue);
+       }
+}
+
+static void post_cmd_done(struct tgt_cmd_queue *q)
+{
+       struct cmd *cmd, *tmp;
+       int enabled, result, len = 0;
+       uint8_t rw = 0, mmapped = 0;
+       uint64_t offset;
+       unsigned long uaddr = 0;
+       struct target *target;
+
+       list_for_each_entry_safe(cmd, tmp, &q->queue, qlist) {
+               enabled = cmd_pre_perform(q, cmd);
+               if (enabled) {
+                       list_del(&cmd->qlist);
+                       target = host_to_target(cmd->hostno);
+                       if (!target) {
+                               eprintf("fail to find target!\n");
+                               exit(1);
+                       }
+                       dprintf("perform %u %x\n", cmd->cid, cmd->attribute);
+                       result = scsi_cmd_perform(target->lid,
+                                                 cmd->hostno, cmd->scb,
+                                                 &len,
+                                                 cmd->len,
+                                                 &(cmd->siov->iov[0]),
+                                                 cmd->siov->iovcnt,
+                                                 &rw,
+                                                 &mmapped,
+                                                 &offset,
+                                                 cmd->lun,
+                                                 cmd->dev,
+                                                 &target->device_list);
+                       cmd_post_perform(q, cmd, uaddr, len, mmapped);
+                       set_cmd_processed(cmd);
+                       tgt_kspace_send_cmd(cmd, result, rw);
+               } else
+                       break;
+       }
+}
+
+static struct cmd *find_cmd(struct target *target, uint32_t cid)
+{
+       struct cmd *cmd;
+       struct list_head *head = &target->cmd_hash_list[cmd_hashfn(cid)];
+
+       list_for_each_entry(cmd, head, hlist) {
+               if (cmd->cid == cid)
+                       return cmd;
+       }
+       return NULL;
+}
+
+static void __cmd_done(struct target *target, struct cmd *cmd)
+{
+       struct tgt_cmd_queue *q;
+       int err, do_munmap;
+
+       list_del(&cmd->clist);
+       list_del(&cmd->hlist);
+
+       if (cmd->dev)
+               q = &cmd->dev->cmd_queue;
+       else
+               q = &target->cmd_queue;
+
+       q->active_cmd--;
+       switch (cmd->attribute) {
+       case MSG_ORDERED_TAG:
+       case MSG_HEAD_TAG:
+               clear_queue_blocked(q);
+               break;
+       }
+
+       free(cmd);
+
+       post_cmd_done(q);
+}
+
+static int tgt_kspace_send_tsk_mgmt(int host_no, uint64_t mid, int result)
+{
+       struct tgt_event ev;
+
+       ev.u.tsk_mgmt_rsp.host_no = host_no;
+       ev.u.tsk_mgmt_rsp.mid = mid;
+       ev.u.tsk_mgmt_rsp.result = result;
+
+       return kreq_send(&ev);
+}
+
+static void cmd_done(struct tgt_event *ev)
+{
+       struct target *target;
+       struct cmd *cmd;
+       struct mgmt_req *mreq;
+       int host_no = ev->k.cmd_done.host_no;
+       uint32_t cid = ev->k.cmd_done.cid;
+
+       target = host_to_target(host_no);
+       if (!target) {
+               eprintf("%d is not bind to any target\n", host_no);
+               return;
+       }
+
+       cmd = find_cmd(target, cid);
+       if (!cmd) {
+               eprintf("Cannot find cmd %d %u\n", host_no, cid);
+               return;
+       }
+
+       mreq = cmd->mreq;
+       if (mreq && !--mreq->busy) {
+               int err = mreq->function == ABORT_TASK ? -EEXIST : 0;
+               tgt_kspace_send_tsk_mgmt(cmd->hostno, mreq->mid, err);
+               free(mreq);
+       }
+
+       __cmd_done(target, cmd);
+}
+
+static int abort_cmd(struct target* target, struct mgmt_req *mreq,
+                    struct cmd *cmd)
+{
+       int err = 0;
+
+       eprintf("found %" PRIx64 " %lx\n", cmd->tag, cmd->state);
+
+       if (cmd_processed(cmd)) {
+               /*
+                * We've already sent this command to kernel space.
+                * We'll send the tsk mgmt response when we get the
+                * completion of this command.
+                */
+               cmd->mreq = mreq;
+               err = -EBUSY;
+       } else {
+               __cmd_done(target, cmd);
+               tgt_kspace_send_cmd(cmd, TASK_ABORTED, 0);
+       }
+       return err;
+}
+
+static int abort_task_set(struct mgmt_req *mreq, struct target* target, int 
host_no,
+                         uint64_t tag, uint8_t *lun, int all)
+{
+       struct cmd *cmd, *tmp;
+       int err, count = 0;
+
+       eprintf("found %" PRIx64 " %d\n", tag, all);
+
+       list_for_each_entry_safe(cmd, tmp, &target->cmd_list, clist) {
+               if ((all && cmd->hostno == host_no)||
+                   (cmd->tag == tag && cmd->hostno == host_no) ||
+                   (lun && !memcmp(cmd->lun, lun, sizeof(cmd->lun)))) {
+                       err = abort_cmd(target, mreq, cmd);
+                       if (err)
+                               mreq->busy++;
+                       count++;
+               }
+       }
+
+       return count;
+}
+
+static void tsk_mgmt_req(struct tgt_event *ev_req)
+{
+       struct target *target;
+       struct mgmt_req *mreq;
+       int err = 0, count, send = 1;
+       int host_no = ev_req->k.cmd_req.host_no;
+
+       target = host_to_target(host_no);
+       if (!target) {
+               eprintf("%d is not bind to any target\n",
+                       ev_req->k.cmd_req.host_no);
+               return;
+       }
+
+       mreq = calloc(1, sizeof(*mreq));
+       mreq->mid = ev_req->k.tsk_mgmt_req.mid;
+       mreq->function = ev_req->k.tsk_mgmt_req.function;
+
+       switch (mreq->function) {
+       case ABORT_TASK:
+               count = abort_task_set(mreq, target, host_no,
+                                      ev_req->k.tsk_mgmt_req.tag,
+                                      NULL, 0);
+               if (mreq->busy)
+                       send = 0;
+               if (!count)
+                       err = -EEXIST;
+               break;
+       case ABORT_TASK_SET:
+               count = abort_task_set(mreq, target, host_no, 0, NULL, 1);
+               if (mreq->busy)
+                       send = 0;
+               break;
+       case CLEAR_ACA:
+       case CLEAR_TASK_SET:
+               eprintf("Not supported yet %x\n",
+                       ev_req->k.tsk_mgmt_req.function);
+               err = -EINVAL;
+               break;
+       case LOGICAL_UNIT_RESET:
+               count = abort_task_set(mreq, target, host_no, 0,
+                                      ev_req->k.tsk_mgmt_req.lun, 0);
+               if (mreq->busy)
+                       send = 0;
+               break;
+       default:
+               err = -EINVAL;
+               eprintf("Unknown task management %x\n",
+                       ev_req->k.tsk_mgmt_req.function);
+       }
+
+       if (send) {
+               tgt_kspace_send_tsk_mgmt(ev_req->k.cmd_req.host_no,
+                                        ev_req->k.tsk_mgmt_req.mid, err);
+               free(mreq);
+       }
+}
+
+void kreq_exec(struct tgt_event *ev)
+{
+       dprintf("event %u\n", ev->type);
+
+       switch (ev->type) {
+       case TGT_KEVENT_CMD_REQ:
+               cmd_queue(ev);
+               break;
+       case TGT_KEVENT_CMD_DONE:
+               cmd_done(ev);
+               break;
+       case TGT_KEVENT_TSK_MGMT_REQ:
+               tsk_mgmt_req(ev);
+               break;
+       default:
+               eprintf("unknown event %u\n", ev->type);
+               exit(1);
+       }
+}
+
+int tgt_target_bind(int tid, int host_no, int lid)
+{
+       if (!tgtt[tid]) {
+               eprintf("target is not found %d\n", tid);
+               return -EINVAL;
+       }
+       tgtt[tid]->lid = lid;
+
+       if (hostt[host_no]) {
+               eprintf("host is already binded %d %d\n", tid, host_no);
+               return -EINVAL;
+       }
+
+       eprintf("Succeed to bind the target %d to the scsi host %d\n",
+               tid, host_no);
+       hostt[host_no] = tgtt[tid];
+       return 0;
+}
+
+int tgt_target_create(int tid)
+{
+       int err, i;
+       struct target *target;
+
+       if (tid >= MAX_NR_TARGET) {
+               eprintf("Too larget target id %d\n", tid);
+               return -EINVAL;
+       }
+
+       if (tgtt[tid]) {
+               eprintf("Target id %d already exists\n", tid);
+               return -EINVAL;
+       }
+
+       target = malloc(sizeof(*target));
+       if (!target) {
+               eprintf("Out of memoryn\n");
+               return -ENOMEM;
+       }
+
+       target->tid = tid;
+       INIT_LIST_HEAD(&target->cmd_list);
+       for (i = 0; i < ARRAY_SIZE(target->cmd_hash_list); i++)
+               INIT_LIST_HEAD(&target->cmd_hash_list[i]);
+
+       INIT_LIST_HEAD(&target->device_list);
+
+       target->devt = calloc(DEFAULT_NR_DEVICE, sizeof(struct tgt_device *));
+       if (!target->devt) {
+               eprintf("Out of memoryn\n");
+               err = 0;
+               goto free_target;
+       }
+       target->max_device = DEFAULT_NR_DEVICE;
+
+       tgt_cmd_queue_init(&target->cmd_queue);
+
+       eprintf("Succeed to create a new target %d\n", tid);
+       tgtt[tid] = target;
+       return 0;
+
+free_target:
+       free(target);
+       return err;
+}
+
+int tgt_target_destroy(int tid)
+{
+       struct target *target = target_get(tid);
+
+       if (!target)
+               return -ENOENT;
+
+       if (!list_empty(&target->device_list)) {
+               eprintf("target %d still has devices\n", tid);
+               return -EBUSY;
+       }
+
+       if (!list_empty(&target->cmd_queue.queue))
+               return -EBUSY;
+
+       free(target->devt);
+
+       tgtt[tid] = NULL;
+       free(target);
+
+       return 0;
+}
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/tgtadm.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/tgtadm.c       Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,338 @@
+/*
+ * SCSI target daemon management interface
+ *
+ * Copyright (C) 2005 FUJITA Tomonori <tomof@xxxxxxx>
+ * Copyright (C) 2005 Mike Christie <michaelc@xxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <ctype.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include "tgtd.h"
+#include "tgtadm.h"
+#include "driver.h"
+
+#undef eprintf
+#define eprintf(fmt, args...)                                          \
+do {                                                                   \
+       fprintf(stderr, "%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \
+} while (0)
+
+#undef dprintf
+#define dprintf eprintf
+
+#define BUFSIZE 4096
+
+static char program_name[] = "tgtadm";
+
+static struct option const long_options[] =
+{
+       {"lld", required_argument, NULL, 'n'},
+       {"op", required_argument, NULL, 'o'},
+       {"tid", required_argument, NULL, 't'},
+       {"sid", required_argument, NULL, 's'},
+       {"cid", required_argument, NULL, 'c'},
+       {"lun", required_argument, NULL, 'l'},
+       {"params", required_argument, NULL, 'p'},
+       {"user", no_argument, NULL, 'u'},
+       {"hostno", required_argument, NULL, 'i'},
+       {"version", no_argument, NULL, 'v'},
+       {"help", no_argument, NULL, 'h'},
+       {NULL, 0, NULL, 0},
+};
+
+static void usage(int status)
+{
+       if (status != 0)
+               fprintf(stderr, "Try `%s --help' for more information.\n", 
program_name);
+       else {
+               printf("Usage: %s [OPTION]\n", program_name);
+               printf("\
+Linux Target Framework Administration Utility.\n\
+\n\
+  --op new --tid=[id] --params [name]\n\
+                        add a new target with [id]. [id] must not be zero.\n\
+  --op delete --tid=[id]\n\
+                        delete specific target with [id]. The target must\n\
+                        have no active sessions.\n\
+  --op new --tid=[id] --lun=[lun] --params Path=[path]\n\
+                        add a new logical unit with [lun] to specific\n\
+                        target with [id]. The logical unit is offered\n\
+                        to the initiators. [path] must be block device files\n\
+                        (including LVM and RAID devices) or regular files.\n\
+  --op delete --tid=[id] --lun=[lun]\n\
+                        delete specific logical unit with [lun] that\n\
+                        the target with [id] has.\n\
+  --op delete --tid=[id] --sid=[sid] --cid=[cid]\n\
+                        delete specific connection with [cid] in a session\n\
+                        with [sid] that the target with [id] has.\n\
+                        If the session has no connections after\n\
+                        the operation, the session will be deleted\n\
+                        automatically.\n\
+  --op delete           stop all activity.\n\
+  --op update --tid=[id] --params=key1=value1,key2=value2,...\n\
+                        change the target parameters of specific\n\
+                        target with [id].\n\
+  --op new --tid=[id] --user --params=[user]=[name],Password=[pass]\n\
+                        add a new account with [pass] for specific target.\n\
+                        [user] could be [IncomingUser] or [OutgoingUser].\n\
+                        If you don't specify a target (omit --tid option),\n\
+                        you add a new account for discovery sessions.\n\
+  --op delete --tid=[id] --user --params=[user]=[name]\n\
+                        delete specific account having [name] of specific\n\
+                        target. [user] could be [IncomingUser] or\n\
+                        [OutgoingUser].\n\
+                        If you don't specify a target (omit --tid option),\n\
+                        you delete the account for discovery sessions.\n\
+  --version             display version and exit\n\
+  --help                display this help and exit\n\
+\n\
+Report bugs to <stgt-devel@xxxxxxxxxxxxxxxx>.\n");
+       }
+       exit(status == 0 ? 0 : -1);
+}
+
+static int ipc_mgmt_connect(int *fd)
+{
+       int err;
+       struct sockaddr_un addr;
+
+       *fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+       if (*fd < 0) {
+               eprintf("Cannot create a socket %s\n", strerror(errno));
+               return -1;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_LOCAL;
+       memcpy((char *) &addr.sun_path + 1, TGT_IPC_NAMESPACE, 
strlen(TGT_IPC_NAMESPACE));
+
+       err = connect(*fd, (struct sockaddr *) &addr, sizeof(addr));
+       if (err < 0) {
+               eprintf("Cannot connect to tgtd %s\n", strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
+
+static int ipc_mgmt_res(int fd)
+{
+       struct tgtadm_res *res;
+       char buf[BUFSIZE];
+       int err, len = (void *) res->data - (void *) res;
+
+       err = read(fd, buf, len);
+       if (err < 0) {
+               eprintf("Cannot read from tgtd %s\n", strerror(errno));
+               return -1;
+       }
+
+       res = (struct tgtadm_res *) buf;
+       if (res->err) {
+               eprintf("Error %d\n", res->err);
+               return -1;
+       }
+
+       dprintf("got the response %d %d\n", res->err, res->len);
+
+       len = res->len - len;
+       if (!len)
+               return 0;
+
+       while (len) {
+               int t;
+               memset(buf, 0, sizeof(buf));
+               t = min_t(int, sizeof(buf), len);
+               err = read(fd, buf, t);
+               if (err < 0) {
+                       eprintf("Cannot read from tgtd %s\n", strerror(errno));
+                       return -1;
+               }
+               printf("%s", buf);
+               len -= t;
+       }
+
+       return 0;
+}
+
+static int ipc_mgmt_req(struct tgtadm_req *req)
+{
+       int err, fd = 0;
+
+       err = ipc_mgmt_connect(&fd);
+       if (err < 0)
+               goto out;
+
+       err = write(fd, (char *) req, req->len);
+       if (err < 0) {
+               eprintf("Cannot send to tgtd %s\n", strerror(errno));
+               goto out;
+       }
+
+       dprintf("sent to tgtd %d\n", err);
+
+       err = ipc_mgmt_res(fd);
+out:
+       if (fd > 0)
+               close(fd);
+       return err;
+}
+
+static int set_to_mode(uint32_t set)
+{
+       int mode = MODE_SYSTEM;
+
+       if (set & (1 << MODE_USER))
+               mode = MODE_USER;
+       else if (set & (1 << MODE_DEVICE))
+               mode = MODE_DEVICE;
+       else if (set & (1 << MODE_CONNECTION))
+               mode = MODE_CONNECTION;
+       else if (set & (1 << MODE_SESSION))
+               mode = MODE_SESSION;
+       else if (set & (1 << MODE_TARGET))
+               mode = MODE_TARGET;
+
+       return mode;
+}
+
+static int str_to_op(char *str)
+{
+       int op;
+
+       if (!strcmp("new", str))
+               op = OP_NEW;
+       else if (!strcmp("delete", str))
+               op = OP_DELETE;
+       else if (!strcmp("bind", str))
+               op = OP_BIND;
+       else if (!strcmp("show", str))
+               op = OP_SHOW;
+       else
+               op = -1;
+
+       return op;
+}
+
+int main(int argc, char **argv)
+{
+       int ch, longindex;
+       int err = -EINVAL, op = -1, len = 0;
+       int tid = -1;
+       uint32_t cid = 0, set = 0, hostno = 0;
+       uint64_t sid = 0, lun = 0;
+       char *params = NULL, *lldname = NULL;
+       struct tgtadm_req *req;
+       char buf[BUFSIZE];
+
+       optind = 1;
+       while ((ch = getopt_long(argc, argv, "n:o:t:s:c:l:p:uvh",
+                                long_options, &longindex)) >= 0) {
+               switch (ch) {
+               case 'n':
+                       lldname = optarg;
+                       break;
+               case 'o':
+                       op = str_to_op(optarg);
+                       break;
+               case 't':
+                       tid = strtol(optarg, NULL, 10);
+                       set |= (1 << MODE_TARGET);
+                       break;
+               case 's':
+                       sid = strtoull(optarg, NULL, 10);
+                       set |= (1 << MODE_SESSION);
+                       break;
+               case 'c':
+                       cid = strtoul(optarg, NULL, 10);
+                       set |= (1 << MODE_CONNECTION);
+                       break;
+               case 'l':
+                       lun = strtoull(optarg, NULL, 10);
+                       set |= (1 << MODE_DEVICE);
+                       break;
+               case 'i':
+                       hostno = strtol(optarg, NULL, 10);
+                       break;
+               case 'b':
+                       break;
+               case 'p':
+                       params = optarg;
+                       break;
+               case 'u':
+                       set |= (1 << MODE_USER);
+                       break;
+               case 'v':
+                       printf("%s\n", program_name);
+                       exit(0);
+                       break;
+               case 'h':
+                       usage(0);
+                       break;
+               default:
+                       usage(-1);
+               }
+       }
+       if (op < 0) {
+               eprintf("You must specify the operation type\n");
+               goto out;
+       }
+
+       if (optind < argc) {
+               fprintf(stderr, "unrecognized: ");
+               while (optind < argc)
+                       fprintf(stderr, "%s", argv[optind++]);
+               fprintf(stderr, "\n");
+               usage(-1);
+       }
+
+       memset(buf, 0, sizeof(buf));
+
+       req = (struct tgtadm_req *) buf;
+       strncpy(req->lld, lldname, sizeof(req->lld));
+       req->mode = set_to_mode(set);
+       req->op = op;
+       req->tid = tid;
+       req->sid = sid;
+       req->lun = lun;
+       req->host_no = hostno;
+
+       if (params) {
+               len = min(strlen(params), sizeof(buf) - len);
+               strncpy((char *) req->data, params, len);
+       }
+       req->len = ((char *) req->data - (char *) req) + len;
+
+       err = ipc_mgmt_req(req);
+out:
+       return err;
+}
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/tgtadm.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/tgtadm.h       Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,44 @@
+#ifndef TGTADM_H
+#define TGTADM_H
+
+#define TGT_IPC_NAMESPACE      "TGT_IPC_ABSTRACT_NAMESPACE"
+#define TGT_LLD_NAME_LEN       64
+
+enum tgtadm_op {
+       OP_NEW,
+       OP_DELETE,
+       OP_SHOW,
+       OP_BIND,
+};
+
+enum tgtadm_mode {
+       MODE_SYSTEM,
+       MODE_TARGET,
+       MODE_DEVICE,
+
+       MODE_SESSION,
+       MODE_CONNECTION,
+       MODE_USER,
+};
+
+struct tgtadm_req {
+       enum tgtadm_mode mode;
+       enum tgtadm_op op;
+       uint32_t len;
+
+       uint32_t tid;
+       uint64_t sid;
+       uint32_t cid;
+       uint64_t lun;
+       char lld[TGT_LLD_NAME_LEN];
+       uint32_t host_no;
+       uint64_t data[0];
+} __attribute__ ((aligned (sizeof(uint64_t))));
+
+struct tgtadm_res {
+       uint32_t err;
+       uint32_t len;
+       uint64_t data[0];
+} __attribute__ ((aligned (sizeof(uint64_t))));;
+
+#endif
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/tgtd.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/tgtd.c Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,288 @@
+/*
+ * SCSI target daemon
+ *
+ * Copyright (C) 2005 FUJITA Tomonori <tomof@xxxxxxx>
+ * Copyright (C) 2005 Mike Christie <michaelc@xxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <poll.h>
+#include <signal.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+
+#include "tgtd.h"
+#include "driver.h"
+
+enum {
+       POLL_KI, /* kernel interface */
+       POLL_IPC, /* unix domain socket for tgtdadm */
+       POLL_END,
+};
+
+static char program_name[] = "tgtd";
+
+static struct option const long_options[] =
+{
+       {"foreground", no_argument, 0, 'f'},
+       {"debug", required_argument, 0, 'd'},
+       {"version", no_argument, 0, 'v'},
+       {"help", no_argument, 0, 'h'},
+       {0, 0, 0, 0},
+};
+
+static void usage(int status)
+{
+       if (status)
+               fprintf(stderr, "Try `%s --help' for more information.\n", 
program_name);
+       else {
+               printf("Usage: %s [OPTION]\n", program_name);
+               printf("\
+Target framework daemon.\n\
+  -l, --lld               specify low level drivers to run\n\
+  -f, --foreground        make the program run in the foreground\n\
+  -d, --debug debuglevel  print debugging information\n\
+  -h, --help              display this help and exit\n\
+");
+       }
+       exit(1);
+}
+
+static void signal_catch(int signo) {
+}
+
+static int daemonize(void)
+{
+       pid_t pid;
+
+       pid = fork();
+       if (pid < 0)
+               return -ENOMEM;
+       else if (pid)
+               exit(0);
+
+       setsid();
+       chdir("/");
+       close(0);
+       open("/dev/null", O_RDWR);
+       dup2(0, 1);
+       dup2(0, 2);
+
+       return 0;
+}
+
+static void oom_adjust(void)
+{
+       int fd;
+       char path[64];
+
+       /* Should we use RT stuff? */
+       nice(-20);
+
+       /* Avoid oom-killer */
+       sprintf(path, "/proc/%d/oom_adj", getpid());
+       fd = open(path, O_WRONLY);
+       if (fd < 0) {
+               fprintf(stderr, "can not adjust oom-killer's pardon %s\n", 
path);
+               return;
+       }
+       write(fd, "-17\n", 4);
+       close(fd);
+}
+
+static void event_loop(struct pollfd *pfd, int npfd, int timeout)
+{
+       int nevent, i;
+       struct tgt_driver *d;
+
+retry:
+       /*
+        * TODO: replace something efficient than poll.
+        */
+       nevent = poll(pfd, npfd, timeout);
+       if (nevent < 0) {
+               if (errno != EINTR) {
+                       eprintf("%s\n", strerror(errno));
+                       exit(1);
+               }
+               goto retry;
+       } else if (nevent == 0) {
+               /*
+                * TODO: need kinda scheduling stuff like open-iscsi here.
+                */
+               goto retry;
+       }
+
+       if (pfd[POLL_KI].revents) {
+               kreq_recv();
+               nevent--;
+       }
+
+       if (pfd[POLL_IPC].revents) {
+               dprintf("ipc event\n");
+               ipc_event_handle(pfd[POLL_IPC].fd);
+               nevent--;
+       }
+
+       if (!nevent)
+               goto retry;
+
+       for (i = 0; tgt_drivers[i]; i++) {
+               dprintf("lld event\n");
+               d = tgt_drivers[i];
+               d->event_handle(pfd + d->pfd_index);
+       }
+
+       goto retry;
+}
+
+static struct pollfd *pfd_init(int npfd, int nl_fd, int ud_fd)
+{
+       struct tgt_driver *d;
+       struct pollfd *pfd;
+       int i, idx = POLL_END;
+
+       pfd = calloc(npfd, sizeof(struct pollfd));
+       if (!pfd)
+               return NULL;
+
+       pfd[POLL_KI].fd = nl_fd;
+       pfd[POLL_KI].events = POLLIN;
+       pfd[POLL_IPC].fd = ud_fd;
+       pfd[POLL_IPC].events = POLLIN;
+
+       for (i = 0; tgt_drivers[i]; i++) {
+               d = tgt_drivers[i];
+               if (d->enable && d->npfd) {
+                       d->pfd_index = idx;
+                       d->poll_init(pfd + idx);
+                       idx += d->npfd;
+               }
+       }
+
+       return pfd;
+}
+
+static int lld_init(char *data, int *npfd)
+{
+       char *list, *p, *q;
+       int index, err, np, ndriver = 0;
+
+       p = list = strdup(data);
+       if (!p)
+               return 0;
+
+       while (p) {
+               q = strchr(p, ',');
+               if (q)
+                       *q++ = '\0';
+               index = get_driver_index(p);
+               p = q;
+               if (index >= 0) {
+                       np = 0;
+                       if (tgt_drivers[index]->init) {
+                               err = tgt_drivers[index]->init(&np);
+                               if (err)
+                                       continue;
+                       }
+                       tgt_drivers[index]->enable = 1;
+                       tgt_drivers[index]->npfd = np;
+                       ndriver++;
+                       *npfd += np;
+               }
+       }
+       free(list);
+
+       return ndriver;
+}
+
+int main(int argc, char **argv)
+{
+       struct pollfd *pfd;
+       struct sigaction sa_old;
+       struct sigaction sa_new;
+       int err, ch, longindex, nr_lld = 0, nr_pfd = POLL_END;
+       int is_daemon = 1, is_debug = 1;
+       int ki_fd, ipc_fd, timeout = -1;
+
+       /* do not allow ctrl-c for now... */
+       sa_new.sa_handler = signal_catch;
+       sigemptyset(&sa_new.sa_mask);
+       sa_new.sa_flags = 0;
+       sigaction(SIGINT, &sa_new, &sa_old );
+       sigaction(SIGPIPE, &sa_new, &sa_old );
+       sigaction(SIGTERM, &sa_new, &sa_old );
+
+       while ((ch = getopt_long(argc, argv, "fd:vh", long_options,
+                                &longindex)) >= 0) {
+               switch (ch) {
+               case 'f':
+                       is_daemon = 0;
+                       break;
+               case 'd':
+                       is_debug = atoi(optarg);
+                       break;
+               case 'v':
+                       exit(0);
+                       break;
+               case 'h':
+                       usage(0);
+                       break;
+               default:
+                       usage(1);
+                       break;
+               }
+       }
+
+       /* run only xen */
+       nr_lld = lld_init("xen", &nr_pfd);
+       if (!nr_lld) {
+               printf("No available low level driver!\n");
+               exit(1);
+       }
+
+       if (is_daemon && daemonize())
+               exit(1);
+
+       oom_adjust();
+
+       err = log_init(program_name, LOG_SPACE_SIZE, is_daemon, is_debug);
+       if (err)
+               exit(1);
+
+       err = kreq_init(&ki_fd);
+       if (err)
+               exit(1);
+
+       err = ipc_init(&ipc_fd);
+       if (err)
+               exit(1);
+
+       pfd = pfd_init(nr_pfd, ki_fd, ipc_fd);
+
+       event_loop(pfd, nr_pfd, timeout);
+
+       return 0;
+}
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/tgtd.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/tgtd.h Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,50 @@
+#ifndef __TARGET_DAEMON_H
+#define __TARGET_DAEMON_H
+
+#include "log.h"
+#include "util.h"
+#include <scsi/scsi_tgt_if.h>
+#include <sys/uio.h>
+
+#define        SCSI_ID_LEN     24
+
+struct tgt_cmd_queue {
+       int active_cmd;
+       unsigned long state;
+       struct list_head queue;
+};
+
+struct tgt_device {
+       int fd;
+       uint64_t addr; /* persistent mapped address */
+       uint64_t size;
+       uint64_t lun;
+       char scsi_id[SCSI_ID_LEN];
+       struct list_head dlist;
+
+       struct tgt_cmd_queue cmd_queue;
+};
+
+extern int kreq_init(int *fd);
+extern int kreq_recv(void);
+extern int kreq_send(struct tgt_event *ev);
+
+extern int ipc_init(int *fd);
+extern void ipc_event_handle(int accept_fd);
+
+extern void kreq_exec(struct tgt_event *ev);
+extern int tgt_device_create(int tid, uint64_t lun, char *path);
+extern int tgt_device_destroy(int tid, uint64_t lun);
+extern int tgt_target_create(int tid);
+extern int tgt_target_destroy(int tid);
+extern int tgt_target_bind(int tid, int host_no, int lid);
+
+extern uint64_t scsi_get_devid(int lid, uint8_t *pdu);
+extern int scsi_cmd_perform(int lid, int host_no, uint8_t *pdu, int *len,
+                           uint32_t datalen, struct iovec *iov, int iovcnt,
+                           uint8_t *rw, uint8_t *try_map, uint64_t *offset, 
uint8_t *lun_buf,
+                           struct tgt_device *dev, struct list_head *dev_list);
+
+extern int sense_data_build(uint8_t *data, uint8_t res_code, uint8_t key,
+                           uint8_t ascode, uint8_t ascodeq);
+#endif
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/tgtif.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/tgtif.c        Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,182 @@
+/*
+ * SCSI kernel and user interface
+ *
+ * Copyright (C) 2006 FUJITA Tomonori <tomof@xxxxxxx>
+ * Copyright (C) 2006 Mike Christie <michaelc@xxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <scsi/scsi_tgt_if.h>
+
+#include "tgtd.h"
+
+struct uring {
+       uint32_t idx;
+       uint32_t nr_entry;
+       int entry_size;
+       char *buf;
+       int buf_size;
+};
+
+static struct uring kuring, ukring;
+static int chrfd;
+
+static inline struct rbuf_hdr *head_ring_hdr(struct uring *r)
+{
+       uint32_t offset = (r->idx & (r->nr_entry - 1)) * r->entry_size;
+       return (struct rbuf_hdr *) (r->buf + offset);
+}
+
+static void ring_init(struct uring *r, char *buf, int bsize, int esize)
+{
+       int i;
+
+       esize += sizeof(struct rbuf_hdr);
+       r->idx = 0;
+       r->buf = buf;
+       r->buf_size = bsize;
+       r->entry_size = esize;
+
+       bsize /= esize;
+       for (i = 0; (1 << i) < bsize && (1 << (i + 1)) <= bsize; i++)
+               ;
+       r->nr_entry = 1 << i;
+
+       dprintf("%u %u\n", r->entry_size, r->nr_entry);
+}
+
+int kreq_send(struct tgt_event *ev)
+{
+       struct rbuf_hdr *hdr;
+       hdr = head_ring_hdr(&ukring);
+       if (hdr->status)
+               return -ENOMEM;
+
+       memcpy(hdr->data, ev, sizeof(*ev));
+       ukring.idx++;
+       hdr->status = 1;
+
+       write(chrfd, ev, 1);
+
+       return 0;
+}
+
+int kreq_recv(void)
+{
+       struct rbuf_hdr *hdr;
+
+       dprintf("nl event %u\n", kuring.idx);
+
+retry:
+       hdr = head_ring_hdr(&kuring);
+       if (!hdr->status)
+               return 0;
+
+       kreq_exec((struct tgt_event *) (hdr->data));
+       hdr->status = 0;
+       kuring.idx++;
+
+       goto retry;
+}
+
+static int ctrdev_open(char *devpath)
+{
+       FILE *f;
+       char devname[256];
+       char buf[256];
+       int devn;
+       int ctlfd;
+
+       f = fopen("/proc/devices", "r");
+       if (!f) {
+               eprintf("Cannot open control path to the driver\n");
+               return -1;
+       }
+
+       devn = 0;
+       while (!feof(f)) {
+               if (!fgets(buf, sizeof (buf), f))
+                       break;
+
+               if (sscanf(buf, "%d %s", &devn, devname) != 2)
+                       continue;
+
+               if (!strcmp(devname, "tgt"))
+                       break;
+
+               devn = 0;
+       }
+
+       fclose(f);
+       if (!devn) {
+               eprintf("cannot find iscsictl in /proc/devices - "
+                       "make sure the module is loaded\n");
+               return -1;
+       }
+
+       unlink(devpath);
+       if (mknod(devpath, (S_IFCHR | 0600), (devn << 8))) {
+               eprintf("cannot create %s %s\n", devpath, strerror(errno));
+               return -1;
+       }
+
+       ctlfd = open(devpath, O_RDWR);
+       if (ctlfd < 0) {
+               eprintf("cannot open %s %s\n", devpath, strerror(errno));
+               return -1;
+       }
+
+       return ctlfd;
+}
+
+#define CHRDEV_PATH "/dev/tgt"
+
+int kreq_init(int *ki_fd)
+{
+       int fd, size = TGT_RINGBUF_SIZE;
+       char *buf;
+
+       fd = ctrdev_open(CHRDEV_PATH);
+       if (fd < 0)
+               return fd;
+
+       buf = mmap(NULL, size * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+       if (buf == MAP_FAILED) {
+               eprintf("fail to mmap %s\n", strerror(errno));
+               close(fd);
+               return -EINVAL;
+       }
+
+       ring_init(&kuring, buf, size, sizeof(struct tgt_event));
+       ring_init(&ukring, buf + size, size, sizeof(struct tgt_event));
+
+       *ki_fd = chrfd = fd;
+
+       return 0;
+}
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/util.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/util.h Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,33 @@
+#include <sys/user.h>
+#include "list.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#ifndef PAGE_SHIFT
+#define        PAGE_SHIFT      12
+#define        PAGE_SIZE       (1UL << PAGE_SHIFT)
+#define        PAGE_MASK       (~(PAGE_SIZE-1))
+#endif
+
+#define pgcnt(size, offset)    ((((size) + ((offset) & ~PAGE_MASK)) + 
PAGE_SIZE - 1) >> PAGE_SHIFT)
+
+#define        DEFDMODE        
(S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
+#define        DEFFMODE        (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
+
+#define min(x,y) ({ \
+       typeof(x) _x = (x);     \
+       typeof(y) _y = (y);     \
+       (void) (&_x == &_y);            \
+       _x < _y ? _x : _y; })
+
+#define max(x,y) ({ \
+       typeof(x) _x = (x);     \
+       typeof(y) _y = (y);     \
+       (void) (&_x == &_y);            \
+       _x > _y ? _x : _y; })
+
+#define min_t(type,x,y) \
+       ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+#define max_t(type,x,y) \
+       ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
+
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/xen.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/xen.c  Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,59 @@
+#include <string.h>
+#include <sys/poll.h>
+#include <xs.h>
+
+#include "tgtd.h"
+#include "xs_api.h"
+
+#define MAX_FDS 32
+#define POLL_STORE 0
+
+/* xenstore/xenbus: */
+extern int add_blockdevice_probe_watch(struct xs_handle *h,
+                                       const char *domname);
+extern int xs_fire_next_watch(struct xs_handle *h);
+
+static struct xs_handle *xsh;
+
+void xen_event_handle(struct pollfd *pfd)
+{
+       if (pfd[POLL_STORE].revents)
+               xs_fire_next_watch(xsh);
+}
+
+int xen_poll_init(struct pollfd *pfd)
+{
+       int i;
+
+       pfd[POLL_STORE].fd = xs_fileno(xsh);
+       pfd[POLL_STORE].events = POLLIN;
+
+       dprintf("%d\n", pfd[POLL_STORE].fd);
+
+       return 0;
+}
+
+int xen_init(int *npfd)
+{
+       int err;
+
+       *npfd = 1 + MAX_FDS;
+       dprintf("%d\n", *npfd);
+
+       xsh = xs_daemon_open();
+       if (!xsh) {
+               eprintf("xs_daemon_open\n");
+               goto open_failed;
+       }
+
+       err = add_blockdevice_probe_watch(xsh, "Domain-0");
+       if (err) {
+               eprintf("adding device probewatch\n");
+               goto open_failed;
+       }
+
+       return 0;
+
+open_failed:
+       return -1;
+}
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/xen.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/xen.h  Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,15 @@
+#ifndef __TGTXEN_H__
+#define __TGTXEN_H__
+
+extern int xen_init(int *);
+extern int xen_poll_init(struct pollfd *);
+extern int xen_event_handle(struct pollfd *);
+
+struct tgt_driver xen = {
+       .name           = "xen",
+       .init           = xen_init,
+       .poll_init      = xen_poll_init,
+       .event_handle   = xen_event_handle,
+};
+
+#endif
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/xenbus.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/xenbus.c       Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,382 @@
+/*
+ * xenbus.c
+ *
+ * xenbus interface to the blocktap.
+ *
+ * this handles the top-half of integration with block devices through the
+ * store -- the tap driver negotiates the device channel etc, while the
+ * userland tap client needs to sort out the disk parameters etc.
+ *
+ * (c) 2005 Andrew Warfield and Julian Chesterfield
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <printf.h>
+#include <string.h>
+#include <err.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <xs.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <time.h>
+#include <sys/time.h>
+
+/* FIXME */
+#define SRP_RING_PAGES 1
+#define SRP_MAPPED_PAGES 88
+
+#include "tgtd.h"
+#include "xs_api.h"
+
+struct backend_info
+{
+       int frontend_id;
+
+       char *path;
+       char *backpath;
+       char *frontpath;
+
+       struct list_head list;
+};
+
+static LIST_HEAD(belist);
+
+static int strsep_len(const char *str, char c, unsigned int len)
+{
+       unsigned int i;
+
+       for (i = 0; str[i]; i++)
+               if (str[i] == c) {
+                       if (len == 0)
+                               return i;
+                       len--;
+               }
+       return (len == 0) ? i : -ERANGE;
+}
+
+static int get_be_id(const char *str)
+{
+       int len,end;
+       const char *ptr;
+       char *tptr, num[10];
+
+       len = strsep_len(str, '/', 6);
+       end = strlen(str);
+       if((len < 0) || (end < 0)) return -1;
+
+       ptr = str + len + 1;
+       strncpy(num,ptr,end - len);
+       tptr = num + (end - (len + 1));
+       *tptr = '\0';
+
+       return atoi(num);
+}
+
+static struct backend_info *be_lookup_be(const char *bepath)
+{
+       struct backend_info *be;
+
+       list_for_each_entry(be, &belist, list)
+               if (strcmp(bepath, be->backpath) == 0)
+                       return be;
+       return (struct backend_info *)NULL;
+}
+
+static int be_exists_be(const char *bepath)
+{
+       return (be_lookup_be(bepath) != NULL);
+}
+
+static struct backend_info *be_lookup_fe(const char *fepath)
+{
+       struct backend_info *be;
+
+       list_for_each_entry(be, &belist, list)
+               if (strcmp(fepath, be->frontpath) == 0)
+                       return be;
+       return (struct backend_info *)NULL;
+}
+
+#if 0
+static int backend_remove(struct xs_handle *h, struct backend_info *be)
+{
+       /* Unhook from be list. */
+       list_del(&be->list);
+       dprintf("Removing backend\n");
+
+       /* Free everything else. */
+       if (be->blkif) {
+               dprintf("Freeing blkif dev [%d]\n",be->blkif->devnum);
+               free_blkif(be->blkif);
+       }
+       if (be->frontpath)
+               free(be->frontpath);
+       if (be->backpath)
+               free(be->backpath);
+       free(be);
+       return 0;
+}
+#endif
+
+static int tgt_device_setup(struct xs_handle *h, char *bepath)
+{
+       struct backend_info *be;
+       char *path = NULL, *p, *dev;
+       int len, err = -EINVAL;
+       long int handle;
+
+       be = be_lookup_be(bepath);
+       if (!be) {
+               dprintf("ERROR: backend changed called for nonexistent "
+                       "backend! (%s)\n", bepath);
+               return err;
+       }
+
+        err = xs_gather(h, bepath, "dev", NULL, &path, NULL);
+        if (err) {
+                eprintf("cannot get dev %d\n", err);
+               return err;
+       }
+
+       /* TODO: we need to lun param. */
+       err = tgt_device_create(be->frontend_id, 0, path);
+       dprintf("%d path %s\n", err, path);
+       if (err)
+               return err;
+
+       err = xs_printf(h, be->backpath, "info", "%d", be->frontend_id);
+       if (!err)
+               dprintf("ERROR: Failed writing info");
+
+       dprintf("[SETUP] Complete\n\n");
+
+       return err;
+}
+
+static int chrdev_open(char *name, uint8_t minor)
+{
+       FILE *f;
+       char devname[256];
+       char buf[256];
+       int devn;
+       int ctlfd;
+
+       f = fopen("/proc/devices", "r");
+       if (!f) {
+               eprintf("Cannot open control path to the driver\n");
+               return -1;
+       }
+
+       devn = 0;
+       while (!feof(f)) {
+               if (!fgets(buf, sizeof (buf), f))
+                       break;
+
+               if (sscanf(buf, "%d %s", &devn, devname) != 2)
+                       continue;
+
+               if (!strcmp(devname, name))
+                       break;
+
+               devn = 0;
+       }
+
+       fclose(f);
+       if (!devn) {
+               eprintf("cannot find %s in /proc/devices - "
+                       "make sure the module is loaded\n", name);
+               return -1;
+       }
+
+       snprintf(devname, sizeof(devname), "/dev/%s%d", name, minor);
+
+       unlink(devname);
+       if (mknod(devname, (S_IFCHR | 0600), (devn << 8) | minor)) {
+               eprintf("cannot create %s %s\n", devname, strerror(errno));
+               return -1;
+       }
+
+       ctlfd = open(devname, O_RDWR);
+       if (ctlfd < 0) {
+               eprintf("cannot open %s %s\n", devname, strerror(errno));
+               return -1;
+       }
+
+       return ctlfd;
+}
+
+/*
+ * Xenstore watch callback entry point. This code replaces the hotplug scripts,
+ * and as soon as the xenstore backend driver entries are created, this script
+ * gets called.
+ */
+static void tgt_probe(struct xs_handle *h, struct xenbus_watch *w,
+                     const char *bepath_im)
+{
+       struct backend_info *be = NULL;
+       char *frontend = NULL, *bepath = NULL, *p;
+       int err, len, fd, msize = (SRP_RING_PAGES + SRP_MAPPED_PAGES) * 
PAGE_SIZE;
+       void *addr;
+       uint32_t hostno;
+
+       bepath = strdup(bepath_im);
+       if (!bepath) {
+               dprintf("No path\n");
+               return;
+       }
+
+       /*
+        *asserts that xenstore structure is always 7 levels deep
+        *e.g. /local/domain/0/backend/vbd/1/2049
+        */
+        len = strsep_len(bepath, '/', 7);
+        if (len < 0)
+               goto free_be;
+        bepath[len] = '\0';
+
+       be = calloc(1, sizeof(*be));
+       if (!be) {
+               dprintf("ERROR: allocating backend structure\n");
+               goto free_be;
+       }
+
+       err = xs_gather(h, bepath,
+                       "frontend-id", "%d", &be->frontend_id,
+                       "frontend", NULL, &frontend,
+                       NULL);
+
+       dprintf("%d %d %s\n", err, be->frontend_id, frontend);
+       if (err) {
+               /*
+                *Unable to find frontend entries,
+                *bus-id is no longer valid
+                */
+               dprintf("ERROR: Frontend-id check failed, removing backend: 
[%s]\n",bepath);
+
+               /*BE info should already exist, free new mem and find old 
entry*/
+               free(be);
+               be = be_lookup_be(bepath);
+/*             if (be && be->blkif) */
+/*                     backend_remove(h, be); */
+/*             else */
+/*                     goto free_be; */
+               if (bepath)
+                       free(bepath);
+               return;
+       }
+
+        /* Are we already tracking this device? */
+        if (be_exists_be(bepath))
+               goto free_be;
+
+        err = xs_gather(h, bepath, "hostno", "%u", &hostno, NULL);
+       if (err)
+               goto free_be;
+
+       fd = chrdev_open("scsiback", hostno);
+       if (fd < 0)
+               goto free_be;
+
+       addr = mmap(NULL, msize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+       if (addr == MAP_FAILED) {
+               eprintf("failed to mmap %u %s\n", msize, strerror(errno));
+               goto close_fd;
+       }
+       dprintf("addr: %p size: %d\n", addr, msize);
+
+       err = tgt_target_create(be->frontend_id);
+       if (err && err != -EEXIST)
+               goto close_fd;
+
+       be->backpath = bepath;
+               be->frontpath = frontend;
+
+       /* FIXME */
+       err = tgt_target_bind(be->frontend_id, hostno, 0);
+
+        list_add(&be->list, &belist);
+
+        dprintf("[PROBE]\tADDED NEW DEVICE (%s)\n", bepath);
+       dprintf("\tFRONTEND (%s),(%d)\n", frontend, be->frontend_id);
+
+       tgt_device_setup(h, bepath);
+       return;
+
+close_fd:
+       close(fd);
+free_be:
+       if (frontend)
+               free(frontend);
+        if (bepath)
+               free(bepath);
+       if(be)
+               free(be);
+       return;
+}
+
+/*
+ *We set a general watch on the backend vbd directory
+ *ueblktap_probe is called for every update
+ *Our job is simply to monitor for new entries, and to
+ *create the state and attach a disk.
+ */
+
+int add_blockdevice_probe_watch(struct xs_handle *h, const char *domname)
+{
+       char *domid, *path;
+       struct xenbus_watch *watch;
+       int er;
+
+       domid = get_dom_domid(h, domname);
+
+       dprintf("%s: %s\n", domname, (domid != NULL) ? domid : "[ not found! 
]");
+
+       asprintf(&path, "/local/domain/%s/backend/scsi", domid);
+       if (path == NULL)
+               return -ENOMEM;
+
+       watch = (struct xenbus_watch *)malloc(sizeof(struct xenbus_watch));
+       if (!watch) {
+               dprintf("ERROR: unable to malloc vbd_watch [%s]\n", path);
+               return -EINVAL;
+       }
+       watch->node = path;
+       watch->callback = tgt_probe;
+       er = register_xenbus_watch(h, watch);
+       if (er == 0) {
+               dprintf("ERROR: adding vbd probe watch %s\n", path);
+               return -EINVAL;
+       }
+       return 0;
+}
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/xs_api.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/xs_api.c       Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,352 @@
+/*
+ * xs_api.c
+ * 
+ * blocktap interface functions to xenstore
+ *
+ * (c) 2005 Andrew Warfield and Julian Chesterfield
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <printf.h>
+#include <string.h>
+#include <err.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <xs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <poll.h>
+/* #include "blktaplib.h" */
+#include "list.h"
+#include "xs_api.h"
+
+#if 0
+#define DPRINTF(_f, _a...) printf ( _f , ## _a )
+#else
+#define DPRINTF(_f, _a...) ((void)0)
+#endif
+
+static LIST_HEAD(watches);
+#define BASE_DEV_VAL 2048
+
+int xs_gather(struct xs_handle *xs, const char *dir, ...)
+{
+       va_list ap;
+       const char *name;
+       char *path, **e;
+       int ret = 0, num,i;
+       unsigned int len;
+       xs_transaction_t xth;
+
+again:
+       if( (xth = xs_transaction_start(xs)) == XBT_NULL ) {
+               printf("unable to start xs trasanction\n");
+               ret = ENOMEM;
+               return ret;
+       }
+       
+       va_start(ap, dir);
+       while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
+               const char *fmt = va_arg(ap, char *);
+               void *result = va_arg(ap, void *);
+               char *p;
+               
+               if (asprintf(&path, "%s/%s", dir, name) == -1)
+               {
+                       printf("allocation error in xs_gather!\n");
+                       ret = ENOMEM;
+                       break;
+               }
+               
+               p = xs_read(xs, xth, path, &len);
+               
+               
+               free(path);
+               if (p == NULL) {
+                       ret = ENOENT;
+                       break;
+               }
+               if (fmt) {
+                       if (sscanf(p, fmt, result) == 0)
+                               ret = EINVAL;
+                       free(p);
+               } else
+                       *(char **)result = p;
+       }
+       va_end(ap);
+
+       if (!xs_transaction_end(xs, xth, ret)) {
+               if (ret == 0 && errno == EAGAIN)
+                       goto again;
+                else
+                       ret = errno;
+       }
+
+       return ret;
+}
+
+
+/* Single printf and write: returns -errno or 0. */
+int xs_printf(struct xs_handle *h, const char *dir, const char *node, 
+             const char *fmt, ...)
+{
+        char *buf, *path;
+        va_list ap;
+        int ret;
+       
+        va_start(ap, fmt);
+        ret = vasprintf(&buf, fmt, ap);
+        va_end(ap);
+       
+        asprintf(&path, "%s/%s", dir, node);
+       
+        if ((path == NULL) || (buf == NULL))
+               return 0;
+
+        ret = xs_write(h, XBT_NULL, path, buf, strlen(buf)+1);
+       
+        free(buf);
+        free(path);
+       
+        return ret;
+}
+
+
+int xs_exists(struct xs_handle *h, const char *path)
+{
+       char **d;
+       unsigned int num;
+       xs_transaction_t xth;
+       
+       if( (xth = xs_transaction_start(h)) == XBT_NULL ) {
+               printf("unable to start xs trasanction\n");
+               return 0;
+       }       
+       
+       d = xs_directory(h, xth, path, &num);
+       xs_transaction_end(h, xth, 0);
+       if (d == NULL)
+               return 0;
+       free(d);
+       return 1;
+}
+
+
+
+/* This assumes that the domain name we are looking for is unique! Name 
parameter Domain-0 */
+char *get_dom_domid(struct xs_handle *h, const char *name)
+{
+       char **e, *val, *domid = NULL;
+       unsigned int num, len;
+       int i;
+       char *path;
+       xs_transaction_t xth;
+       
+       if ( (xth = xs_transaction_start(h)) == XBT_NULL ) {
+               warn("unable to start xs trasanction\n");
+               return NULL;
+       }
+       
+       e = xs_directory(h, xth, "/local/domain", &num);
+       
+       i=0;
+       while (i < num) {
+               asprintf(&path, "/local/domain/%s/name", e[i]);
+               val = xs_read(h, xth, path, &len);
+               free(path);
+               if (val == NULL)
+                       continue;
+               
+               if (strcmp(val, name) == 0) {
+                       /* match! */
+                       asprintf(&path, "/local/domain/%s/domid", e[i]);
+                       domid = xs_read(h, xth, path, &len);
+                       free(val);
+                       free(path);
+                       break;
+               }
+               free(val);
+               i++;
+       }
+       xs_transaction_end(h, xth, 0);
+       
+       free(e);
+       return domid;
+}
+
+int convert_dev_name_to_num(char *name) {
+       char *p_sd, *p_hd, *p_xvd, *p_plx, *p, *alpha,*ptr;
+       int majors[10] = {3,22,33,34,56,57,88,89,90,91};
+       int maj,i;
+
+       asprintf(&p_sd,"/dev/sd");
+       asprintf(&p_hd,"/dev/hd");
+       asprintf(&p_xvd,"/dev/xvd");
+       asprintf(&p_plx,"plx");
+       asprintf(&alpha,"abcdefghijklmnop");
+       
+
+       if(strstr(name,p_sd)!=NULL) {
+               p = name + strlen(p_sd);
+               for(i=0,ptr=alpha;i<strlen(alpha);i++) {
+                       if(*ptr==*p)
+                               break;
+                       *ptr++;
+               }
+               *p++;
+               return BASE_DEV_VAL + (16*i) + atoi(p);
+       } else if(strstr(name,p_hd)!=NULL) {
+               p = name + strlen(p_hd);
+               for(i=0,ptr=alpha;i<strlen(alpha);i++) {
+                       if(*ptr==*p) break;
+                       *ptr++;
+               }
+               *p++;
+               return (majors[i/2]*256) + atoi(p);
+
+       } else if(strstr(name,p_xvd)!=NULL) {
+               p = name + strlen(p_xvd);
+               for(i=0,ptr=alpha;i<strlen(alpha);i++) {
+                       if(*ptr==*p) break;
+                       *ptr++;
+               }
+               *p++;
+               return (202*256) + (16*i) + atoi(p);
+
+       } else if(strstr(name,p_plx)!=NULL) {
+               p = name + strlen(p_plx);
+               return atoi(p);
+
+       } else {
+               DPRINTF("Unknown device type, setting to default.\n");
+               return BASE_DEV_VAL;
+       }
+       return 0;
+}
+
+/* A little paranoia: we don't just trust token. */
+static struct xenbus_watch *find_watch(const char *token)
+{
+       struct xenbus_watch *i, *cmp;
+       
+       cmp = (void *)strtoul(token, NULL, 16);
+       
+       list_for_each_entry(i, &watches, list)
+               if (i == cmp)
+                       return i;
+       return NULL;
+}
+
+/* Register callback to watch this node. like xs_watch, return 0 on failure */
+int register_xenbus_watch(struct xs_handle *h, struct xenbus_watch *watch)
+{
+       /* Pointer in ascii is the token. */
+       char token[sizeof(watch) * 2 + 1];
+       int er;
+       
+       sprintf(token, "%lX", (long)watch);
+       if (find_watch(token)) 
+       {
+               warn("watch collision!");
+               return -EINVAL;
+       }
+       
+       er = xs_watch(h, watch->node, token);
+       if (er != 0) {
+               list_add(&watch->list, &watches);
+       } 
+        
+       return er;
+}
+
+int unregister_xenbus_watch(struct xs_handle *h, struct xenbus_watch *watch)
+{
+       char token[sizeof(watch) * 2 + 1];
+       int er;
+       
+       sprintf(token, "%lX", (long)watch);
+       if (!find_watch(token))
+       {
+               warn("no such watch!");
+               return -EINVAL;
+       }
+       
+       
+       er = xs_unwatch(h, watch->node, token);
+       list_del(&watch->list);
+       
+       if (er == 0)
+               warn("XENBUS Failed to release watch %s: %i",
+                    watch->node, er);
+       return 0;
+}
+
+/* Re-register callbacks to all watches. */
+void reregister_xenbus_watches(struct xs_handle *h)
+{
+       struct xenbus_watch *watch;
+       char token[sizeof(watch) * 2 + 1];
+       
+       list_for_each_entry(watch, &watches, list) {
+               sprintf(token, "%lX", (long)watch);
+               xs_watch(h, watch->node, token);
+       }
+}
+
+/* based on watch_thread() */
+int xs_fire_next_watch(struct xs_handle *h)
+{
+       char **res;
+       char *token;
+       char *node = NULL;
+       struct xenbus_watch *w;
+       int er;
+       unsigned int num;
+       
+       res = xs_read_watch(h, &num);
+       if (res == NULL) 
+               return -EAGAIN; /* in O_NONBLOCK, read_watch returns 0... */
+       
+       node  = res[XS_WATCH_PATH];
+       token = res[XS_WATCH_TOKEN];
+       
+       w = find_watch(token);
+       if (!w)
+       {
+               warn("unregistered watch fired");
+               goto done;
+       }
+       w->callback(h, w, node);
+       
+ done:
+       free(res);
+       return 1;
+}
diff -r 6d90075b4fef -r ed8d345449c1 tools/tgtd/xs_api.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/tgtd/xs_api.h       Wed Aug 02 15:11:34 2006 +0900
@@ -0,0 +1,50 @@
+/*
+ * xs_api.h
+ *
+ * (c) 2005 Andrew Warfield and Julian Chesterfield
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+struct xenbus_watch
+{
+        struct list_head list;
+        char *node;
+        void (*callback)(struct xs_handle *h, 
+                         struct xenbus_watch *, 
+                         const  char *node);
+};
+
+int xs_gather(struct xs_handle *xs, const char *dir, ...);
+int xs_printf(struct xs_handle *h, const char *dir, const char *node, 
+             const char *fmt, ...);
+int xs_exists(struct xs_handle *h, const char *path);
+char *get_dom_domid(struct xs_handle *h, const char *name);
+int convert_dev_name_to_num(char *name);
+int register_xenbus_watch(struct xs_handle *h, struct xenbus_watch *watch);
+int unregister_xenbus_watch(struct xs_handle *h, struct xenbus_watch *watch);
+void reregister_xenbus_watches(struct xs_handle *h);
+int xs_fire_next_watch(struct xs_handle *h);

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.