[PATCH RFC 2/3] SCSI Userspace Target: scsi tgt core functions

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

 



SCSI Userspace Target code.

Signed-off-by: Mike Christie <michaelc@xxxxxxxxxxx>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx>

diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 3c606cf..d09c792 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -27,6 +27,13 @@ config SCSI
 	  However, do not compile this as a module if your root file system
 	  (the one containing the directory /) is located on a SCSI device.
 
+config SCSI_TGT
+	tristate "SCSI target support"
+	depends on SCSI && EXPERIMENTAL
+	---help---
+	  If you want to use SCSI target mode drivers enable this option.
+	  If you choose M, the module will be called scsi_tgt.
+
 config SCSI_PROC_FS
 	bool "legacy /proc/scsi/ support"
 	depends on SCSI && PROC_FS
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index b9d2bb8..75cd7fc 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -21,6 +21,7 @@ CFLAGS_seagate.o =   -DARBITRATE -DPARIT
 subdir-$(CONFIG_PCMCIA)		+= pcmcia
 
 obj-$(CONFIG_SCSI)		+= scsi_mod.o
+obj-$(CONFIG_SCSI_TGT)		+= scsi_tgt.o
 
 obj-$(CONFIG_RAID_ATTRS)	+= raid_class.o
 
@@ -155,6 +156,8 @@ scsi_mod-y			+= scsi.o hosts.o scsi_ioct
 scsi_mod-$(CONFIG_SYSCTL)	+= scsi_sysctl.o
 scsi_mod-$(CONFIG_SCSI_PROC_FS)	+= scsi_proc.o
 
+scsi_tgt-y			+= scsi_tgt_lib.o scsi_tgt_nl.o
+
 sd_mod-objs	:= sd.o
 sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
 ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
new file mode 100644
index 0000000..9bc67f3
--- /dev/null
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -0,0 +1,396 @@
+/*
+ * SCSI target lib functions
+ *
+ * Copyright 2005 Mike Christie
+ * Copyright 2005 FUJITA Tomonori
+ *
+ * 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, 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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/blkdev.h>
+#include <linux/elevator.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "scsi_tgt_priv.h"
+
+static struct workqueue_struct *scsi_tgtd;
+
+/* set by interface */
+struct task_struct *tgtd_tsk;
+
+static void scsi_uspace_request_fn(struct request_queue *q)
+{
+	struct request *rq;
+	struct scsi_cmnd *cmd;
+
+	/*
+	 * TODO: just send everthing in the queue to userspace in
+	 * one vector instead of multiple calls
+	 */
+	while ((rq = elv_next_request(q)) != NULL) {
+		cmd = rq->special;
+
+		/* the completion code kicks us in case we hit this */
+		if (blk_queue_start_tag(q, rq))
+			break;
+
+		spin_unlock_irq(q->queue_lock);
+		if (scsi_tgt_uspace_send(cmd, scsilun_to_int(rq->end_io_data),
+					 GFP_ATOMIC) < 0)
+			goto requeue;
+		spin_lock_irq(q->queue_lock);
+	}
+
+	return;
+requeue:
+	spin_lock_irq(q->queue_lock);
+	/* need to track cnts and plug */
+	blk_requeue_request(q, rq);
+	spin_lock_irq(q->queue_lock);
+}
+
+/**
+ * scsi_tgt_alloc_queue - setup queue used for message passing
+ * shost: scsi host
+ *
+ * This should be called by the LLD after host allocation
+ **/
+int scsi_tgt_alloc_queue(struct Scsi_Host *shost)
+{
+	struct request_queue *q;
+
+	/*
+	 * uspace sets the noop scheduler for us since the others
+	 * are overkill
+	 *
+	 * Do we need to send a netlink event or should uspace
+	 * just respond to the hotplug event?
+	 */
+	q = __scsi_alloc_queue(shost, scsi_uspace_request_fn);
+	if (!q)
+		return -ENOMEM;
+
+	q->nr_requests = shost->hostt->can_queue;
+	blk_queue_init_tags(q, shost->hostt->can_queue, NULL);
+	shost->uspace_req_q = q;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_alloc_queue);
+
+/**
+ * scsi_tgt_queue_command - queue command for userspace processing
+ * @cmd:	scsi command
+ * @scsilun:	scsi lun
+ * @noblock:	set to nonzero if the command should be queued
+ **/
+void scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun,
+			    int noblock)
+{
+	/*
+	 * For now this just calls the request_fn from this context.
+	 * For HW llds though we do not want to execute from here so
+	 * the elevator code needs something like a REQ_TGT_CMD or
+	 * REQ_MSG_DONT_UNPLUG_IMMED_BECUASE_WE_WILL_HANDLE_IT
+	 */
+	cmd->request->end_io_data = scsilun;
+	elv_add_request(cmd->shost->uspace_req_q, cmd->request,
+			ELEVATOR_INSERT_BACK, 1);
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_queue_command);
+
+/*
+ * We do not do clustering yet. We will when we convert to block layer fns
+ */
+static void scsi_unmap_user_pages(struct scsi_cmnd *cmd)
+{
+	struct scatterlist *sg = cmd->request_buffer;
+	struct page *page;
+	int i;
+
+	for (i = 0; i < cmd->use_sg; i++) {
+		page = sg[i].page;
+		if (!page)
+			break;
+		if (cmd->sc_data_direction == DMA_TO_DEVICE)
+			set_page_dirty_lock(page);
+		page_cache_release(page);
+	}
+}
+
+static void scsi_tgt_cmd_destroy(void *data)
+{
+	struct scsi_cmnd *cmd = data;
+
+	dprintk("cmd %p\n", cmd);
+
+	scsi_unmap_user_pages(cmd);
+	kfree(cmd->request_buffer);
+	scsi_tgt_uspace_send_status(cmd, GFP_KERNEL);
+	scsi_host_put_command(cmd);
+}
+
+/*
+ * This is run from a interrpt handler normally and the unmap
+ * needs process context so we must queue
+ */
+static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
+{
+	dprintk("cmd %p\n", cmd);
+
+	INIT_WORK(&cmd->work, scsi_tgt_cmd_destroy, cmd);
+	queue_work(scsi_tgtd, &cmd->work);
+}
+
+static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
+{
+	struct Scsi_Host *shost = cmd->shost;
+	int err;
+
+	dprintk("cmd %p\n", cmd);
+
+	err = shost->hostt->transfer_response(cmd, scsi_tgt_cmd_done);
+	switch (err) {
+	case SCSI_MLQUEUE_HOST_BUSY:
+	case SCSI_MLQUEUE_DEVICE_BUSY:
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static void scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
+{
+	int err;
+
+	err = __scsi_tgt_transfer_response(cmd);
+	if (!err)
+		return;
+
+	cmd->result = DID_BUS_BUSY << 16;
+	if (scsi_tgt_uspace_send_status(cmd, GFP_ATOMIC) <= 0)
+		/* the eh will have to pick this up */
+		printk(KERN_ERR "Could not send cmd %p status\n", cmd);
+}
+
+#define pgcnt(size, offset) \
+	((((size) + ((offset) & ~PAGE_CACHE_MASK)) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)
+
+/*
+ * TODO: replace with block layer function or modify so it honors the LLD
+ * limits and can then be used by the ULDs. Or could we also have a
+ * get_user_pages() that takes a scatterlist.
+ *
+ * Instead we could create a fake /dev/sd entry for this target, and
+ * userspace could write a SG_IO command to it. The LLD queuecommand
+ * would either need to be able to handle this target command
+ * and initiator commands at the same time though (this would take some
+ * extra code).
+ */
+static int scsi_map_user_pages(struct scsi_cmnd *cmd, u64 offset, int rw)
+{
+	int i, err = -EIO, cnt;
+	struct page *page, **pages;
+	u64 poffset = offset & ~PAGE_MASK;
+	unsigned size, rest = cmd->request_bufflen;
+	struct scatterlist *sg;
+
+	cnt = pgcnt(cmd->request_bufflen, offset);
+	pages = kzalloc(cnt * sizeof(struct page *), GFP_KERNEL);
+	if (!pages)
+		return -ENOMEM;
+
+	cmd->request_buffer = kmalloc(cnt * sizeof(struct scatterlist),
+				      GFP_KERNEL);
+	if (!cmd->request_buffer)
+		goto release_pages;
+	cmd->use_sg = cnt;
+
+	dprintk("cmd %p addr %p cnt %d\n", cmd, cmd->buffer, cnt);
+
+	down_read(&tgtd_tsk->mm->mmap_sem);
+	err = get_user_pages(tgtd_tsk, tgtd_tsk->mm, (unsigned long)cmd->buffer,
+			     cnt, rw == WRITE, 0, pages, NULL);
+	up_read(&tgtd_tsk->mm->mmap_sem);
+
+	if (err < cnt) {
+		printk(KERN_ERR "cannot get user pages %d %d\n", err, cnt);
+		err = -EIO;
+		goto free_sg;
+	}
+
+	/*
+	 * need to fix this for HW LLDs. We could do
+	 *
+	 * scsi_req_map_sg(cmd->request, tmp_sg, cnt, len, GFP_KERNEL);
+	 * blk_rq_map_sg(shost->uspace_req_q, rq, final_sg);
+	 *
+	 * but that seems like such a waste. We need to merge the rest of
+	 * SCSI ULD and blk layer scatterlist code into one nice api.
+	 * Also need to handle if we cannot get enough clustered pages
+	 * to do this in one call (need dma the command in mutliple
+	 * calls maybe??).
+	 */
+	sg = cmd->request_buffer;
+	for (i = 0; i < cnt; i++) {
+		size = min_t(u32, rest, PAGE_SIZE - poffset);
+
+		sg[i].page = pages[i];
+		sg[i].offset = poffset;
+		sg[i].length = size;
+
+		poffset = 0;
+		rest -= size;
+	}
+
+	return 0;
+
+free_sg:
+	kfree(cmd->request_buffer);
+release_pages:
+	for (i = 0; i < cnt; i++) {
+		page = pages[i];
+		if(!page)
+			break;
+		if (!err && rw == WRITE)
+			set_page_dirty_lock(page);
+		page_cache_release(page);
+	}
+	kfree(pages);
+
+	return err;
+}
+
+static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd)
+{
+	if (!cmd->result) {
+		scsi_tgt_transfer_response(cmd);
+		return;
+	}
+
+	if (scsi_tgt_uspace_send_status(cmd, GFP_ATOMIC) <= 0)
+		/* the tgt uspace eh will have to pick this up */
+		printk(KERN_ERR "Could not send cmd %p status\n", cmd);
+}
+
+static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd)
+{
+	int err;
+
+	err = cmd->shost->hostt->transfer_data(cmd, scsi_tgt_data_transfer_done);
+	switch (err) {
+		case SCSI_MLQUEUE_HOST_BUSY:
+		case SCSI_MLQUEUE_DEVICE_BUSY:
+			return -EAGAIN;
+	default:
+		return 0;
+	}
+}
+
+static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr,
+				unsigned len)
+{
+	char __user *p = (char __user *) uaddr;
+
+	if (copy_from_user(cmd->sense_buffer, p,
+			   min_t(unsigned, SCSI_SENSE_BUFFERSIZE, len))) {
+		printk(KERN_ERR "Could not copy the sense buffer\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+int scsi_tgt_kspace_exec(int host_no, u32 cid, int result, u32 len, u64 offset,
+			 unsigned long uaddr, u8 rw, u8 try_map)
+{
+	struct Scsi_Host *shost;
+	struct scsi_cmnd *cmd;
+	struct request *rq;
+	int err;
+
+	/* TODO: replace with a O(1) alg */
+	shost = scsi_host_lookup(host_no);
+	if (IS_ERR(shost)) {
+		printk(KERN_ERR "Could not find host no %d\n", host_no);
+		return -EINVAL;
+	}
+
+	rq = blk_queue_find_tag(shost->uspace_req_q, cid);
+	if (!rq) {
+		printk(KERN_ERR "Could not find cid %u\n", cid);
+		return -EINVAL;
+	}
+	cmd = rq->special;
+
+	dprintk("cmd %p result %d len %d bufflen %u\n", cmd,
+		result, len, cmd->request_bufflen);
+
+	cmd->buffer = (void *)uaddr;
+	cmd->result = result;
+	if (len)
+		cmd->request_bufflen = len;
+
+	if (!cmd->request_bufflen)
+		return __scsi_tgt_transfer_response(cmd);
+
+	/*
+	 * TODO: Do we need to handle case where request does not
+	 * align with LLD.
+	 */
+	err = scsi_map_user_pages(cmd, offset, rw);
+	if (err) {
+		eprintk("%p %d\n", cmd, err);
+		return -EAGAIN;
+	}
+
+	/* userspace failure */
+	if (cmd->result) {
+		if (status_byte(cmd->result) == CHECK_CONDITION)
+			scsi_tgt_copy_sense(cmd, uaddr, len);
+		return __scsi_tgt_transfer_response(cmd);
+	}
+	/* ask the target LLD to transfer the data to the buffer */
+	return scsi_tgt_transfer_data(cmd);
+}
+
+static int __init scsi_tgt_init(void)
+{
+	int err;
+
+	scsi_tgtd = create_workqueue("scsi_tgtd");
+	if (!scsi_tgtd)
+		return -ENOMEM;
+
+	err = scsi_tgt_nl_init();
+	if (err)
+		destroy_workqueue(scsi_tgtd);
+	return err;
+}
+
+static void __exit scsi_tgt_exit(void)
+{
+	destroy_workqueue(scsi_tgtd);
+	scsi_tgt_nl_exit();
+}
+
+module_init(scsi_tgt_init);
+module_exit(scsi_tgt_exit);
+
+MODULE_DESCRIPTION("SCSI target core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/scsi_tgt_nl.c b/drivers/scsi/scsi_tgt_nl.c
new file mode 100644
index 0000000..1bb308c
--- /dev/null
+++ b/drivers/scsi/scsi_tgt_nl.c
@@ -0,0 +1,188 @@
+/*
+ * Target Netlink Framework code
+ *
+ * (C) 2005 FUJITA Tomonori <tomof@xxxxxxx>
+ * (C) 2005 Mike Christie <michaelc@xxxxxxxxxxx>
+ * This code is licenced under the GPL.
+ */
+
+#include <linux/netlink.h>
+#include <linux/blkdev.h>
+#include <net/tcp.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tgt_if.h>
+
+#include "scsi_tgt_priv.h"
+
+static int tgtd_pid;
+static struct sock *nls;
+
+int scsi_tgt_uspace_send(struct scsi_cmnd *cmd, u64 lun, gfp_t gfp_mask)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+	struct tgt_event *ev;
+	char *pdu;
+	int len, err;
+
+	len = NLMSG_SPACE(sizeof(*ev) + MAX_COMMAND_SIZE);
+	/*
+	 * TODO: add MAX_COMMAND_SIZE to ev and add mempool
+	 */
+	skb = alloc_skb(NLMSG_SPACE(len), gfp_mask);
+	if (!skb)
+		return -ENOMEM;
+
+	dprintk("%p %d %Zd %d\n", cmd, len, sizeof(*ev), MAX_COMMAND_SIZE);
+	nlh = __nlmsg_put(skb, tgtd_pid, 0, TGT_KEVENT_CMD_REQ,
+			  len - sizeof(*nlh), 0);
+	ev = NLMSG_DATA(nlh);
+	memset(ev, 0, sizeof(*ev));
+
+	pdu = (char *) ev->data;
+	ev->k.cmd_req.host_no = cmd->shost->host_no;
+	ev->k.cmd_req.dev_id = lun;
+	ev->k.cmd_req.cid = cmd->request->tag;
+	ev->k.cmd_req.data_len = cmd->request_bufflen;
+	memcpy(ev->data, cmd->cmnd, MAX_COMMAND_SIZE);
+
+	err = netlink_unicast(nls, skb, tgtd_pid, 0);
+	if (err < 0)
+		printk(KERN_ERR "scsi_tgt_uspace_send: could not send skb "
+		      "to pid %d err %d\n", tgtd_pid, err);
+	return err;
+}
+
+static int send_event_res(uint16_t type, struct tgt_event *p,
+			  void *data, int dlen, gfp_t flags)
+{
+	struct tgt_event *ev;
+	struct nlmsghdr *nlh;
+	struct sk_buff *skb;
+	uint32_t len;
+
+	len = NLMSG_SPACE(sizeof(*ev) + dlen);
+	skb = alloc_skb(len, flags);
+	if (!skb)
+		return -ENOMEM;
+
+	nlh = __nlmsg_put(skb, tgtd_pid, 0, type, len - sizeof(*nlh), 0);
+
+	ev = NLMSG_DATA(nlh);
+	memcpy(ev, p, sizeof(*ev));
+	if (dlen)
+		memcpy(ev->data, data, dlen);
+
+	return netlink_unicast(nls, skb, tgtd_pid, 0);
+}
+
+int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+{
+	struct tgt_event ev;
+
+	memset(&ev, 0, sizeof(ev));
+	ev.k.cmd_done.host_no = cmd->shost->host_no;
+	ev.k.cmd_done.cid = (unsigned long)cmd;
+	ev.k.cmd_done.result = cmd->result;
+
+	return send_event_res(TGT_KEVENT_CMD_DONE, &ev, NULL, 0, gfp_mask);
+}
+
+static int event_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+	struct tgt_event *ev = NLMSG_DATA(nlh);
+	int err = 0;
+
+	dprintk("%d %d %d\n", nlh->nlmsg_type,
+		nlh->nlmsg_pid, current->pid);
+
+	switch (nlh->nlmsg_type) {
+	case TGT_UEVENT_START:
+		tgtd_pid = NETLINK_CREDS(skb)->pid;
+		tgtd_tsk = current;
+		break;
+	case TGT_UEVENT_CMD_RES:
+		/* TODO: handle multiple cmds in one event */
+		err = scsi_tgt_kspace_exec(ev->u.cmd_res.host_no,
+					   ev->u.cmd_res.cid,
+					   ev->u.cmd_res.result,
+					   ev->u.cmd_res.len,
+					   ev->u.cmd_res.offset,
+					   ev->u.cmd_res.uaddr,
+					   ev->u.cmd_res.rw,
+					   ev->u.cmd_res.try_map);
+		break;
+	default:
+		eprintk("unknown type %d\n", nlh->nlmsg_type);
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+static int event_recv_skb(struct sk_buff *skb)
+{
+	int err;
+	uint32_t rlen;
+	struct nlmsghdr	*nlh;
+
+	while (skb->len >= NLMSG_SPACE(0)) {
+		nlh = (struct nlmsghdr *) skb->data;
+		if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
+			return 0;
+		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+		if (rlen > skb->len)
+			rlen = skb->len;
+		err = event_recv_msg(skb, nlh);
+
+		dprintk("%d %d\n", nlh->nlmsg_type, err);
+		/*
+		 * TODO for passthru commands the lower level should
+		 * probably handle the result or we should modify this
+		 */
+		if (nlh->nlmsg_type != TGT_UEVENT_CMD_RES) {
+			struct tgt_event ev;
+
+			memset(&ev, 0, sizeof(ev));
+			ev.k.event_res.err = err;
+			send_event_res(TGT_KEVENT_RESPONSE, &ev, NULL, 0,
+				       GFP_KERNEL | __GFP_NOFAIL);
+		}
+		skb_pull(skb, rlen);
+	}
+	return 0;
+}
+
+static void event_recv(struct sock *sk, int length)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
+		if (NETLINK_CREDS(skb)->uid) {
+			skb_pull(skb, skb->len);
+			kfree_skb(skb);
+			continue;
+		}
+
+		if (event_recv_skb(skb) && skb->len)
+			skb_queue_head(&sk->sk_receive_queue, skb);
+		else
+			kfree_skb(skb);
+	}
+}
+
+void __exit scsi_tgt_nl_exit(void)
+{
+	sock_release(nls->sk_socket);
+}
+
+int __init scsi_tgt_nl_init(void)
+{
+	nls = netlink_kernel_create(NETLINK_TGT, 1, event_recv,
+				    THIS_MODULE);
+	if (!nls)
+		return -ENOMEM;
+
+	return 0;
+}
diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h
new file mode 100644
index 0000000..23aba10
--- /dev/null
+++ b/drivers/scsi/scsi_tgt_priv.h
@@ -0,0 +1,22 @@
+struct scsi_cmnd;
+struct task_struct;
+
+/* tmp - will replace with SCSI logging stuff */
+#define dprintk(fmt, args...)					\
+do {								\
+	printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);	\
+} while (0)
+
+#define eprintk dprintk
+
+
+extern struct task_struct *tgtd_tsk;
+
+extern void scsi_tgt_nl_exit(void);
+extern int scsi_tgt_nl_init(void);
+
+extern int scsi_tgt_uspace_send(struct scsi_cmnd *cmd, u64 lun, gfp_t gfp_mask);
+extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, gfp_t flags);
+extern int scsi_tgt_kspace_exec(int host_no, u32 cid, int result, u32 len,
+				u64 offset, unsigned long uaddr, u8 rw,
+				u8 try_map);
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 6a2ccf7..580fb42 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -21,6 +21,7 @@
 #define NETLINK_DNRTMSG		14	/* DECnet routing messages */
 #define NETLINK_KOBJECT_UEVENT	15	/* Kernel messages to userspace */
 #define NETLINK_GENERIC		16
+#define NETLINK_TGT		17	/* SCSI target */
 
 #define MAX_LINKS 32		
 
diff --git a/include/scsi/scsi_tgt.h b/include/scsi/scsi_tgt.h
new file mode 100644
index 0000000..c1dc0d2
--- /dev/null
+++ b/include/scsi/scsi_tgt.h
@@ -0,0 +1,10 @@
+/*
+ * SCSI target definitions
+ */
+
+struct Scsi_Host;
+struct scsi_cmnd;
+struct scsi_lun;
+
+extern int scsi_tgt_alloc_queue(struct Scsi_Host *);
+extern void scsi_tgt_queue_command(struct scsi_cmnd *, struct scsi_lun *, int);
diff --git a/include/scsi/scsi_tgt_if.h b/include/scsi/scsi_tgt_if.h
new file mode 100644
index 0000000..fe5f0f9
--- /dev/null
+++ b/include/scsi/scsi_tgt_if.h
@@ -0,0 +1,70 @@
+/*
+ * SCSI target netlink interface
+ *
+ * (C) 2005 FUJITA Tomonori <tomof@xxxxxxx>
+ * (C) 2005 Mike Christie <michaelc@xxxxxxxxxxx>
+ * This code is licenced under the GPL.
+ */
+
+#ifndef SCSI_TARGET_FRAMEWORK_IF_H
+#define SCSI_TARGET_FRAMEWORK_IF_H
+
+enum tgt_event_type {
+	/* user -> kernel */
+	TGT_UEVENT_START,
+	TGT_UEVENT_TARGET_SETUP,
+	TGT_UEVENT_CMD_RES,
+
+	/* kernel -> user */
+	TGT_KEVENT_RESPONSE,
+	TGT_KEVENT_CMD_REQ,
+	TGT_KEVENT_CMD_DONE,
+};
+
+struct tgt_event {
+	/* user-> kernel */
+	union {
+		struct {
+			int host_no;
+			int pid;
+		} setup_target;
+		struct {
+			int host_no;
+			uint32_t cid;
+			uint32_t len;
+			int result;
+			uint64_t uaddr;
+			uint64_t offset;
+			uint8_t rw;
+			uint8_t try_map;
+		} cmd_res;
+	} u;
+
+	/* kernel -> user */
+	union {
+		struct {
+			int err;
+		} event_res;
+		struct {
+			int host_no;
+			uint32_t cid;
+			uint32_t data_len;
+			uint64_t dev_id;
+		} cmd_req;
+		struct {
+			int host_no;
+			uint32_t cid;
+			int result;
+		} cmd_done;
+	} k;
+
+	/*
+	 * I think a pointer is a unsigned long but this struct
+	 * gets passed around from the kernel to userspace and
+	 * back again so to handle some ppc64 setups where userspace is
+	 * 32 bits but the kernel is 64 we do this odd thing
+	 */
+	uint64_t data[0];
+} __attribute__ ((aligned (sizeof(uint64_t))));
+
+#endif


-
: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux