This patch implments a netlink interface for the scsi tgt framework.
I was not sure if code using the netlink interface had to get reviewed
by the netdev guys. I am ccing them on this patch and providing
a basic review of why/how we want to use netlink.

I did not think the netdev people wanted to see the scsi and
block layer code, so I am just sending the netlink interface part
of this patchset to netdev. I can resend the other parts if
needed.

The scsi tgt framework, adds support for scsi target mode
cards. So instead of using the scsi card in your box as a initiator/host
you can use it as a target/server.

The reason for the netlink use is becuase the target normally
receives a interrupt indicating that a command or event is
ready to be processed. The scsi card's driver will then call
a scsi lib function which eventually calls scsi_tgt_uspace_send (in
this patch below) to tell userspace to begin to process the request
(userspace contains the state model). Later userspace will call back
into the kernel by sending a netlink msg, and instruct the scsi driver
what to do next. When the scsi driver is done executing the
operation, it will send a netlink message back to userspace
to indicate the success or failure of the operation (using 
scsi_tgt_uspace_send_status in the patch below).


Signed-off-by: Mike Christie <[EMAIL PROTECTED]>
Signed-off-by: FUJITA Tomonori <[EMAIL PROTECTED]>


diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
new file mode 100644
index 0000000..38b35da
--- /dev/null
+++ b/drivers/scsi/scsi_tgt_if.c
@@ -0,0 +1,214 @@
+/*
+ * SCSI target kernel/user interface functions
+ *
+ * Copyright (C) 2005 FUJITA Tomonori <[EMAIL PROTECTED]>
+ * Copyright (C) 2005 Mike Christie <[EMAIL PROTECTED]>
+ *
+ * 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 <linux/blkdev.h>
+#include <linux/file.h>
+#include <linux/netlink.h>
+#include <net/tcp.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tgt.h>
+#include <scsi/scsi_tgt_if.h>
+
+#include "scsi_tgt_priv.h"
+
+static int tgtd_pid;
+static struct sock *nl_sk;
+
+static int send_event_res(uint16_t type, struct tgt_event *p,
+                         void *data, int dlen, gfp_t flags, pid_t pid)
+{
+       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, 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(nl_sk, skb, pid, 0);
+}
+
+int scsi_tgt_uspace_send(struct scsi_cmnd *cmd, struct scsi_lun *lun, gfp_t 
gfp_mask)
+{
+       struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
+       struct sk_buff *skb;
+       struct nlmsghdr *nlh;
+       struct tgt_event *ev;
+       struct tgt_cmd *tcmd;
+       int err, len;
+
+       len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct tgt_cmd));
+       /*
+        * TODO: add MAX_COMMAND_SIZE to ev and add mempool
+        */
+       skb = alloc_skb(NLMSG_SPACE(len), gfp_mask);
+       if (!skb)
+               return -ENOMEM;
+
+       nlh = __nlmsg_put(skb, tgtd_pid, 0, TGT_KEVENT_CMD_REQ,
+                         len - sizeof(*nlh), 0);
+
+       ev = NLMSG_DATA(nlh);
+       ev->k.cmd_req.host_no = shost->host_no;
+       ev->k.cmd_req.cid = cmd->request->tag;
+       ev->k.cmd_req.data_len = cmd->request_bufflen;
+
+       dprintk("%d %u %u\n", ev->k.cmd_req.host_no, ev->k.cmd_req.cid,
+               ev->k.cmd_req.data_len);
+
+       /* FIXME: we need scsi core to do that. */
+       memcpy(cmd->cmnd, cmd->data_cmnd, MAX_COMMAND_SIZE);
+
+       tcmd = (struct tgt_cmd *) ev->data;
+       memcpy(tcmd->scb, cmd->cmnd, sizeof(tcmd->scb));
+       memcpy(tcmd->lun, lun, sizeof(struct scsi_lun));
+
+       err = netlink_unicast(nl_sk, skb, tgtd_pid, 0);
+       if (err < 0)
+               printk(KERN_ERR "scsi_tgt_uspace_send: could not send skb %d\n",
+                      err);
+       return err;
+}
+
+int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+{
+       struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
+       struct tgt_event ev;
+       char dummy[sizeof(struct tgt_cmd)];
+
+       memset(&ev, 0, sizeof(ev));
+       ev.k.cmd_done.host_no = shost->host_no;
+       ev.k.cmd_done.cid = cmd->request->tag;
+       ev.k.cmd_done.result = cmd->result;
+
+       return send_event_res(TGT_KEVENT_CMD_DONE, &ev, dummy, sizeof(dummy),
+                             gfp_mask, tgtd_pid);
+}
+
+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_TGTD_BIND:
+               tgtd_pid = NETLINK_CREDS(skb)->pid;
+               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,
+                                       nlh->nlmsg_pid);
+               }
+               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_if_exit(void)
+{
+       sock_release(nl_sk->sk_socket);
+}
+
+int __init scsi_tgt_if_init(void)
+{
+       nl_sk = netlink_kernel_create(NETLINK_TGT, 1, event_recv,
+                                   THIS_MODULE);
+       if (!nl_sk)
+               return -ENOMEM;
+
+       return 0;
+}
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_if.h b/include/scsi/scsi_tgt_if.h
new file mode 100644
index 0000000..da3a808
--- /dev/null
+++ b/include/scsi/scsi_tgt_if.h
@@ -0,0 +1,88 @@
+/*
+ * SCSI target kernel/user interface
+ *
+ * Copyright (C) 2005 FUJITA Tomonori <[EMAIL PROTECTED]>
+ * Copyright (C) 2005 Mike Christie <[EMAIL PROTECTED]>
+ *
+ * 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
+ */
+#ifndef __SCSI_TARGET_IF_H
+#define __SCSI_TARGET_IF_H
+
+enum tgt_event_type {
+       /* user -> kernel */
+       TGT_UEVENT_TGTD_BIND,
+       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 pk_fd;
+               } tgtd_bind;
+               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))));
+
+struct tgt_cmd {
+       uint8_t scb[16];
+       uint8_t lun[8];
+       int tags;
+} __attribute__ ((aligned (sizeof(uint64_t))));
+
+#endif


-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to