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 2/6] scsifront driver

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 2/6] scsifront driver
From: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx>
Date: Wed, 02 Aug 2006 17:32:21 +0900
Delivery-date: Wed, 02 Aug 2006 01:34:19 -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 c84cd764b0d7f8bcf911b0e44cc29742b8c760e9
# Parent  4e1a4618df3a66d8100b3f50c96fafe523858440
SCSI frontend driver

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

diff -r 4e1a4618df3a -r c84cd764b0d7 
linux-2.6-xen-sparse/drivers/xen/scsifront/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/scsifront/Makefile       Wed Aug 02 
15:15:36 2006 +0900
@@ -0,0 +1,1 @@
+obj-$(CONFIG_XEN_SCSI_FRONTEND)        += scsifront.o
diff -r 4e1a4618df3a -r c84cd764b0d7 
linux-2.6-xen-sparse/drivers/xen/scsifront/scsifront.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/scsifront/scsifront.c    Wed Aug 02 
15:15:36 2006 +0900
@@ -0,0 +1,473 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (C) 2006 FUJITA Tomonori <tomof@xxxxxxx>
+ *
+ * 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/version.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/uio.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/srp.h>
+#include <xen/evtchn.h>
+#include <xen/xenbus.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/io/scsi.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/grant_table.h>
+#include <xen/gnttab.h>
+#include <asm/hypervisor.h>
+
+#define eprintk(fmt, args...)                                  \
+do {                                                           \
+       printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);  \
+} while (0)
+
+#define dprintk eprintk
+
+static unsigned int debug = 0;
+module_param(debug, int, 0644);
+
+struct scsifront_info {
+       struct xenbus_device *dev;
+       struct Scsi_Host *host;
+       unsigned int evtchn;
+       unsigned int irq;
+       unsigned long ring_ref;
+       struct scsi_front_ring ring;
+};
+
+static int map_data_for_srp_cmd(struct scsifront_info *info,
+                               struct scsi_cmnd *sc, struct srp_cmd *cmd)
+{
+       struct scatterlist *sg = sc->request_buffer;
+       struct srp_direct_buf *buf;
+       grant_ref_t gref_head;
+       int err, i, ref;
+       u8 fmt;
+
+       if (!sg || sc->sc_data_direction == DMA_NONE)
+               return 0;
+
+       err = gnttab_alloc_grant_references(SRP_MAX_INDIRECT, &gref_head);
+       if (err)
+               return -ENOMEM;
+
+       if (sc->use_sg == 1) {
+               buf = (void *) cmd->add_data;
+               fmt = SRP_DATA_DESC_DIRECT;
+
+               ref = gnttab_claim_grant_reference(&gref_head);
+               gnttab_grant_foreign_access_ref(ref, info->dev->otherend_id,
+                                               page_to_phys(sg->page) >> 
PAGE_SHIFT, 0);
+
+               buf->va = sg->offset;
+               buf->key = ref;
+               buf->len = sg->length;
+       } else {
+               struct srp_indirect_buf *ind = (void *) cmd->add_data;
+               int total = 0;
+               fmt = SRP_DATA_DESC_INDIRECT;
+
+               if (sc->sc_data_direction == DMA_TO_DEVICE)
+                       cmd->data_out_desc_cnt = sc->use_sg;
+               else
+                       cmd->data_in_desc_cnt = sc->use_sg;
+
+               ind->table_desc.va = (u64) (unsigned long)ind->desc_list;
+               ind->table_desc.key = 0;
+               ind->table_desc.len = sizeof(*buf) * sc->use_sg;
+
+               buf = (struct srp_direct_buf *) ind->desc_list;
+               for (i = 0; i < sc->use_sg; i++, sg++) {
+                       ref = gnttab_claim_grant_reference(&gref_head);
+                       gnttab_grant_foreign_access_ref(ref, 
info->dev->otherend_id,
+                                                       page_to_phys(sg->page) 
>> PAGE_SHIFT,
+                                                       0);
+                       buf[i].va = sg->offset;
+                       buf[i].key = ref;
+                       buf[i].len = sg->length;
+                       total += sg->length;
+               }
+
+               ind->len = total;
+       }
+
+       if (sc->sc_data_direction == DMA_TO_DEVICE)
+               cmd->buf_fmt = fmt << 4;
+       else
+               cmd->buf_fmt = fmt;
+
+       gnttab_free_grant_references(gref_head);
+
+       return 0;
+}
+
+static int scsifront_queuecommand(struct scsi_cmnd *sc,
+                                  void (*done)(struct scsi_cmnd *))
+{
+       struct Scsi_Host *host = sc->device->host;
+       struct scsifront_info *info = (struct scsifront_info *) host->hostdata;
+       struct scsi_request *ring_req;
+       struct scsi_front_ring *ring = &info->ring;
+       struct srp_cmd *cmd;
+       int err, notify;
+
+       if (info->dev->state != XenbusStateConnected || RING_FULL(ring)) {
+               eprintk("busy %u!\n", info->dev->state);
+               return SCSI_MLQUEUE_HOST_BUSY;
+       }
+       sc->scsi_done = done;
+       sc->result = 0;
+
+       ring_req = RING_GET_REQUEST(ring, ring->req_prod_pvt);
+       cmd = (struct srp_cmd *) ring_req->buf;
+
+       memset(cmd, 0, SRP_MAX_IU_LEN);
+       cmd->opcode = SRP_CMD;
+       int_to_scsilun(sc->device->lun, (struct scsi_lun *) &cmd->lun);
+       cmd->tag = (long) sc;
+       memcpy(cmd->cdb, sc->cmnd, sc->cmd_len);
+
+       err = map_data_for_srp_cmd(info, sc, cmd);
+       if (err)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
+       ring->req_prod_pvt++;
+
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
+       notify_remote_via_irq(info->irq);
+
+       return 0;
+}
+
+static int scsifront_eh_abort_handler(struct scsi_cmnd *sc)
+{
+       BUG();
+       return 0;
+}
+
+static void scsifront_cmd_done(struct scsifront_info *info, int idx)
+{
+       struct scsi_front_ring *ring = &info->ring;
+       struct scsi_request *ring_req;
+       struct srp_cmd *cmd;
+       struct scsi_cmnd *sc;
+       struct srp_direct_buf *buf;
+       int i;
+
+       ring_req = RING_GET_REQUEST(ring, idx);
+       cmd = (struct srp_cmd *) ring_req->buf;
+       sc = (struct scsi_cmnd *) (long) cmd->tag;
+
+       if (!sc->request_buffer || (sc->sc_data_direction != DMA_TO_DEVICE &&
+                                   sc->sc_data_direction != DMA_FROM_DEVICE))
+               return;
+
+       if (sc->use_sg == 1) {
+               buf = (void *) cmd->add_data;
+               gnttab_end_foreign_access(buf->key, 0, 0UL);
+       } else {
+               struct srp_indirect_buf *ind = (void *) cmd->add_data;
+               buf = (struct srp_direct_buf *) ind->desc_list;
+
+               for (i = 0; i < sc->use_sg; i++, buf++)
+                       gnttab_end_foreign_access(buf->key, 0, 0UL);
+       }
+}
+
+static irqreturn_t scsifront_intr(int irq, void *dev_id,
+                                  struct pt_regs *ptregs)
+{
+       struct scsifront_info *info = (struct scsifront_info *) dev_id;
+       struct scsi_front_ring *ring = &info->ring;
+       struct scsi_response *ring_res;
+       struct scsi_cmnd *sc;
+       struct srp_rsp *rsp;
+       int i, rp;
+
+       if (info->dev->state != XenbusStateConnected)
+               return IRQ_HANDLED;
+
+again:
+       rp = info->ring.sring->rsp_prod;
+       rmb();
+
+       for (i = info->ring.rsp_cons; i != rp; i++) {
+               ring_res = RING_GET_RESPONSE(ring, i);
+
+               rsp = (struct srp_rsp *) ring_res->buf;
+               sc = ((void *) (unsigned long) rsp->tag);
+               sc->result = rsp->status;
+
+               scsifront_cmd_done(info, i);
+
+               if (rsp->flags & SRP_RSP_FLAG_SNSVALID) {
+                       memcpy(sc->sense_buffer, rsp->data +
+                              be32_to_cpu(rsp->resp_data_len),
+                              min_t(int, be32_to_cpu(rsp->sense_data_len),
+                                    SCSI_SENSE_BUFFERSIZE));
+               }
+
+               if (rsp->flags & (SRP_RSP_FLAG_DOOVER | SRP_RSP_FLAG_DOUNDER))
+                       sc->resid = be32_to_cpu(rsp->data_out_res_cnt);
+               else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | 
SRP_RSP_FLAG_DIUNDER))
+                       sc->resid = be32_to_cpu(rsp->data_in_res_cnt);
+
+               sc->scsi_done(sc);
+       }
+
+       info->ring.rsp_cons = i;
+       if (i != info->ring.req_prod_pvt) {
+               int more_to_do;
+               RING_FINAL_CHECK_FOR_RESPONSES(ring, more_to_do);
+               if (more_to_do)
+                       goto again;
+       } else
+               ring->sring->rsp_event = i + 1;
+
+       return IRQ_HANDLED;
+}
+
+static int scsifront_alloc_ring(struct scsifront_info *info)
+{
+       struct xenbus_device *dev = info->dev;
+       struct scsi_sring *sring;
+       int err = -ENOMEM;
+
+       sring = (struct scsi_sring *) __get_free_page(GFP_KERNEL);
+       if (!sring) {
+               xenbus_dev_fatal(dev, err, "fail to allocate shared ring");
+               return err;
+       }
+
+       SHARED_RING_INIT(sring);
+       FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+       dprintk("%u\n", RING_SIZE(&info->ring));
+
+       err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+       if (err < 0) {
+               xenbus_dev_fatal(dev, err, "fail to grant shared ring");
+               goto free_sring;
+       }
+       info->ring_ref = err;
+
+       err = xenbus_alloc_evtchn(dev, &info->evtchn);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "fail to allocate evtchn");
+               return err;
+       }
+
+       err = bind_evtchn_to_irqhandler(info->evtchn, scsifront_intr,
+                                       SA_SAMPLE_RANDOM, "scsifront", info);
+       if (err <= 0) {
+               xenbus_dev_fatal(dev, err, "bind_evtchn_to_irqhandler failed");
+               goto fail;
+       }
+       info->irq = err;
+
+       return 0;
+fail:
+       /* free resource */
+free_sring:
+       free_page((unsigned long) sring);
+
+       return err;
+}
+
+static int scsifront_init_ring(struct scsifront_info *info)
+{
+       struct xenbus_device *dev = info->dev;
+       struct xenbus_transaction xbt;
+       int err;
+
+       dprintk("");
+
+       err = scsifront_alloc_ring(info);
+       if (err)
+               return err;
+       dprintk("%lu %u\n", info->ring_ref, info->evtchn);
+
+again:
+       err = xenbus_transaction_start(&xbt);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "starting transaction");
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%lu",
+                           info->ring_ref);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "%s", "writing ring-ref");
+               goto fail;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+                           info->evtchn);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "%s", "writing event-channel");
+               goto fail;
+       }
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err) {
+               if (err == -EAGAIN)
+                       goto again;
+               xenbus_dev_fatal(dev, err, "completing transaction");
+       } else
+               xenbus_switch_state(dev, XenbusStateInitialised);
+
+       return 0;
+fail:
+       xenbus_transaction_end(xbt, 1);
+       /* free resource */
+       return err;
+}
+
+static struct scsi_host_template scsifront_sht = {
+       .module                 = THIS_MODULE,
+       .name                   = "Xen SCSI frontend driver",
+       .queuecommand           = scsifront_queuecommand,
+       .eh_abort_handler       = scsifront_eh_abort_handler,
+       .cmd_per_lun            = SRP_CAN_QUEUE,
+       .can_queue              = SRP_CAN_QUEUE,
+       .this_id                = -1,
+       .sg_tablesize           = SRP_MAX_INDIRECT,
+       .use_clustering         = DISABLE_CLUSTERING,
+       .proc_name              = "scsifront",
+};
+
+static int scsifront_probe(struct xenbus_device *dev,
+                           const struct xenbus_device_id *id)
+{
+       struct Scsi_Host *host;
+       struct scsifront_info *info;
+       int err = -ENOMEM;
+
+       host = scsi_host_alloc(&scsifront_sht, sizeof(*info));
+       if (!host) {
+               xenbus_dev_fatal(dev, err, "fail to allocate scsi host");
+               return err;
+       }
+       info = (struct scsifront_info *) host->hostdata;
+       dev->dev.driver_data = info;
+       info->dev = dev;
+       info->host = host;
+
+       err = scsifront_init_ring(info);
+       if (err)
+               scsi_host_put(host);
+
+       return err;
+}
+
+static int scsifront_connect(struct scsifront_info *info)
+{
+       struct xenbus_device *dev = info->dev;
+       struct Scsi_Host *host = info->host;
+       int err = -ENOMEM;
+
+       dprintk("%u\n", dev->state);
+       if (dev->state == XenbusStateConnected)
+               return 0;
+
+       xenbus_switch_state(dev, XenbusStateConnected);
+
+       host->max_id = 1;
+       host->max_channel = 0;
+
+       err = scsi_add_host(host, &dev->dev);
+       if (err) {
+               eprintk("fail to add scsi host %d\n", err);
+               return err;
+       }
+       scsi_scan_host(host);
+
+       return 0;
+}
+
+static int scsifront_remove(struct xenbus_device *dev)
+{
+       struct scsifront_info *info = dev->dev.driver_data;
+
+       scsi_remove_host(info->host);
+       scsi_host_put(info->host);
+
+       return 0;
+}
+
+static void scsifront_backend_changed(struct xenbus_device *dev,
+                                      XenbusState backend_state)
+{
+       struct scsifront_info *info = dev->dev.driver_data;
+
+       dprintk("%p %u %u\n", dev, dev->state, backend_state);
+
+       switch (backend_state) {
+       case XenbusStateUnknown:
+       case XenbusStateInitialising:
+       case XenbusStateInitWait:
+       case XenbusStateInitialised:
+       case XenbusStateClosed:
+               break;
+
+       case XenbusStateConnected:
+               scsifront_connect(info);
+               break;
+
+       case XenbusStateClosing:
+               break;
+       }
+}
+
+static struct xenbus_device_id scsifront_ids[] = {
+       { "scsi" },
+       { "" }
+};
+
+static struct xenbus_driver scsifront = {
+       .name                   = "scsi",
+       .owner                  = THIS_MODULE,
+       .ids                    = scsifront_ids,
+       .probe                  = scsifront_probe,
+       .remove                 = scsifront_remove,
+/*     .resume                 = scsifront_resume, */
+       .otherend_changed       = scsifront_backend_changed,
+};
+
+static int __init scsifront_init(void)
+{
+       if (!is_running_on_xen())
+               return -ENODEV;
+
+       return xenbus_register_frontend(&scsifront);
+}
+static void scsifront_exit(void)
+{
+       return xenbus_unregister_driver(&scsifront);
+}
+
+module_init(scsifront_init);
+module_exit(scsifront_exit);
+
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_DESCRIPTION("Xen SCSI frontend driver");
+MODULE_LICENSE("GPL");

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH 2/6] scsifront driver, FUJITA Tomonori <=