WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

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

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 4/6] scsifront/back drivers' user-space daemon
From: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx>
Date: Wed, 02 Aug 2006 17:32:25 +0900
Delivery-date: Wed, 02 Aug 2006 01:38:23 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH 4/6] scsifront/back drivers' user-space daemon, FUJITA Tomonori <=