FUJITA Tomonori
2007-Jan-02 17:57 UTC
[Xen-devel] [PATCH 2/4] add scsifront/scsiback drivers
This addes scsifront/scsiback drivers. Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> diff -r 105d5d6b4e0d -r 95ca3ffbdbfd buildconfigs/linux-defconfig_xen_x86_32 --- a/buildconfigs/linux-defconfig_xen_x86_32 Wed Jan 03 01:34:02 2007 +0900 +++ b/buildconfigs/linux-defconfig_xen_x86_32 Wed Jan 03 01:35:35 2007 +0900 @@ -1050,13 +1050,14 @@ CONFIG_IDEDMA_AUTO=y # SCSI device support # CONFIG_RAID_ATTRS=m -CONFIG_SCSI=m +CONFIG_SCSI=y +CONFIG_SCSI_TGT=y CONFIG_SCSI_PROC_FS=y # # SCSI support type (disk, tape, CD-ROM) # -CONFIG_BLK_DEV_SD=m +CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=m @@ -1158,6 +1159,7 @@ CONFIG_SCSI_DC390T=m CONFIG_SCSI_DC390T=m CONFIG_SCSI_NSP32=m CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_SRP=y # # PCMCIA SCSI adapter support @@ -3027,12 +3029,14 @@ CONFIG_XEN_PCIDEV_BACKEND_VPCI=y # CONFIG_XEN_PCIDEV_BACKEND_SLOT is not set # CONFIG_XEN_PCIDEV_BE_DEBUG is not set CONFIG_XEN_BLKDEV_BACKEND=y +CONFIG_XEN_SCSI_BACKEND=y CONFIG_XEN_BLKDEV_TAP=y CONFIG_XEN_NETDEV_BACKEND=y # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set CONFIG_XEN_NETDEV_LOOPBACK=y # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y +CONFIG_XEN_SCSI_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y CONFIG_XEN_FRAMEBUFFER=y CONFIG_XEN_KEYBOARD=y diff -r 105d5d6b4e0d -r 95ca3ffbdbfd linux-2.6-xen-sparse/drivers/xen/Kconfig --- a/linux-2.6-xen-sparse/drivers/xen/Kconfig Wed Jan 03 01:34:02 2007 +0900 +++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig Wed Jan 03 01:35:35 2007 +0900 @@ -44,6 +44,17 @@ config XEN_BACKEND help Support for backend device drivers that provide I/O services to other virtual machines. + +config XEN_SCSI_BACKEND + tristate "SCSI backend driver" + depends on XEN_BACKEND && SCSI_TGT + default y + help + The SCSI backend driver allows the kernel to export its SCSI HBAs + to other guests via a high-performance shared-memory interface. + SCSI requests are redirected to userspace through netlink interface. + The user-space daemon can export disk images, which may be implemented + as files, in memory, or on other hosts across the network. config XEN_BLKDEV_BACKEND tristate "Block-device backend driver" @@ -162,6 +173,14 @@ config XEN_BLKDEV_FRONTEND dedicated device-driver domain, or your master control domain (domain 0), then you almost certainly want to say Y here. +config XEN_SCSI_FRONTEND + tristate "SCSI frontend driver" + depends on XEN && SCSI + default y + help + The SCSI frontend driver allows the kernel to access SCSI HBAs + within another guest OS. + config XEN_NETDEV_FRONTEND tristate "Network-device frontend driver" depends on XEN && NET diff -r 105d5d6b4e0d -r 95ca3ffbdbfd linux-2.6-xen-sparse/drivers/xen/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/Makefile Wed Jan 03 01:34:02 2007 +0900 +++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Wed Jan 03 01:35:35 2007 +0900 @@ -8,10 +8,12 @@ obj-$(CONFIG_XEN_BALLOON) += balloon/ obj-$(CONFIG_XEN_BALLOON) += balloon/ obj-$(CONFIG_XEN_DEVMEM) += char/ obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/ +obj-$(CONFIG_XEN_SCSI_BACKEND) += scsiback/ obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/ obj-$(CONFIG_XEN_TPMDEV_BACKEND) += tpmback/ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/ +obj-$(CONFIG_XEN_SCSI_FRONTEND) += scsifront/ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ diff -r 105d5d6b4e0d -r 95ca3ffbdbfd linux-2.6-xen-sparse/drivers/xen/scsiback/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/drivers/xen/scsiback/Makefile Wed Jan 03 01:35:35 2007 +0900 @@ -0,0 +1,2 @@ +obj-$(CONFIG_XEN_SCSI_BACKEND) += scsibk.o +scsibk-y += interface.o scsiback.o diff -r 105d5d6b4e0d -r 95ca3ffbdbfd linux-2.6-xen-sparse/drivers/xen/scsiback/interface.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/drivers/xen/scsiback/interface.c Wed Jan 03 01:35:35 2007 +0900 @@ -0,0 +1,153 @@ +/****************************************************************************** + * arch/xen/drivers/blkif/backend/interface.c + * + * Block-device interface management. + * + * Copyright (c) 2004, Keir Fraser + * + * 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 <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/driver_util.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> +#include "scsiback_priv.h" + +static int map_frontend_page(struct scsiback_info *info, unsigned long shared_page) +{ + struct gnttab_map_grant_ref op; + int err; + + gnttab_set_map_op(&op, (unsigned long)info->ring_area->addr, + GNTMAP_host_map, shared_page, + info->dev->otherend_id); + + lock_vm_area(info->ring_area); + err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); + unlock_vm_area(info->ring_area); + BUG_ON(err); + + if (op.status) { + printk(" Grant table operation failure !\n"); + return op.status; + } + + info->shmem_ref = shared_page; + info->shmem_handle = op.handle; + +#ifdef CONFIG_XEN_IA64_DOM0_NON_VP + /* on some arch''s, map_grant_ref behaves like mmap, in that the + * passed address is a hint and a different address may be returned */ + info->ring_area->addr = gnttab_map_vaddr(op); +#endif + + return 0; +} + +static void unmap_frontend_page(struct scsiback_info *info) +{ + struct gnttab_unmap_grant_ref op; + int err; + + op.host_addr = (unsigned long)info->ring_area->addr; + op.handle = info->shmem_handle; + op.dev_bus_addr = 0; + + lock_vm_area(info->ring_area); + err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1); + unlock_vm_area(info->ring_area); + BUG_ON(err); +} + +int scsiback_init_sring(struct scsiback_info *info, + unsigned long shared_page, unsigned int evtchn) +{ + struct scsi_sring *sring; + int err; + struct evtchn_bind_interdomain bind_interdomain; + + if (info->irq) { + printk("Already connected through?\n"); + return 0; + } + + info->ring_area = alloc_vm_area(PAGE_SIZE); + if (!info) + return -ENOMEM; + + err = map_frontend_page(info, shared_page); + if (err) + goto free_vm; + + bind_interdomain.remote_dom = info->dev->otherend_id; + bind_interdomain.remote_port = evtchn; + + err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, + &bind_interdomain); + if (err) + goto unmap_page; + + info->evtchn = bind_interdomain.local_port; + + sring = (struct scsi_sring *) info->ring_area->addr; + BACK_RING_INIT(&info->ring, sring, PAGE_SIZE); + + info->irq = bind_evtchn_to_irqhandler(info->evtchn, scsiback_intr, + 0, "scsi-backend", info); + return 0; + +unmap_page: + unmap_frontend_page(info); +free_vm: + free_vm_area(info->ring_area); + return err; +} + +void scsiback_exit_sring(struct scsiback_info *info) +{ + /* Already disconnected? */ + if (info->irq) + unbind_from_irqhandler(info->irq, info); + + if (info->ring.sring) { + unmap_frontend_page(info); + free_vm_area(info->ring_area); + } +} diff -r 105d5d6b4e0d -r 95ca3ffbdbfd linux-2.6-xen-sparse/drivers/xen/scsiback/scsiback.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/drivers/xen/scsiback/scsiback.c Wed Jan 03 01:35:35 2007 +0900 @@ -0,0 +1,712 @@ +/* + * Xen SCSI backend driver + * + * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org> + * + * 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 + * + * Based on the blktap driver code. + * + * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield + * + */ +#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/scsi_tgt.h> +#include <scsi/srp.h> +#include <scsi/libsrp.h> +#include <xen/evtchn.h> +#include <xen/balloon.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> +#include "scsiback_priv.h" + +#define INVALID_GRANT_HANDLE 0xFFFF + +#define eprintk(fmt, args...) \ +do { \ + printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \ +} while (0) + +#define dprintk(fmt, args...) \ +do { \ + if (debug) \ + printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \ +} while (0) + +static unsigned int debug = 0; +static int major; +static struct workqueue_struct *scsibkd; + +module_param(debug, int, 0644); + +static int req_index(struct scsiback_info *info, struct scsi_request *req) +{ + return (req - RING_GET_REQUEST(&info->ring, 0)); +} + +static int __idx(struct scsiback_info *info, struct scsi_request *req, + int idx) +{ + return req_index(info, req) * SRP_MAX_INDIRECT + idx; +} + +static unsigned long idx_to_uaddr(struct scsiback_info *info, + struct scsi_request *req, int i) +{ + return info->ustart + (__idx(info, req, i) << PAGE_SHIFT); +} + +static unsigned long idx_to_kaddr(struct scsiback_info *info, + struct scsi_request *req, int i) +{ + struct page *page = info->mmap_pages[__idx(info, req, i)]; + unsigned long pfn = page_to_pfn(page); + return (unsigned long)pfn_to_kaddr(pfn); +} + +static int scsiback_send_rsp(struct scsiback_info *info, struct scsi_cmnd *sc, + void (*done)(struct scsi_cmnd *)) +{ + struct scsi_back_ring *ring = &info->ring; + struct scsi_response *rsp; + struct scsi_request *req = (struct scsi_request *) sc->SCp.ptr; + struct srp_cmd *cmd = (struct srp_cmd *) req->buf; + struct srp_rsp *srsp; + int notify; + + rsp = RING_GET_RESPONSE(ring, ring->rsp_prod_pvt); + srsp = (struct srp_rsp *) rsp->buf; + srsp->opcode = SRP_RSP; + srsp->tag = cmd->tag; + srsp->resp_data_len = 0; + srsp->status = NO_SENSE; + srsp->data_in_res_cnt = 0; + srsp->data_out_res_cnt = 0; + srsp->flags &= ~SRP_RSP_FLAG_RSPVALID; + + ring->rsp_prod_pvt++; + + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify); + + notify_remote_via_irq(info->irq); + + done(sc); + return 0; +} + +static int scsiback_cmd_done_fn(struct scsi_cmnd *sc, struct scatterlist *sg, + int nsg, struct srp_direct_buf *md, int nmd, + enum dma_data_direction dir, unsigned int len) +{ + struct Scsi_Host *host; + struct scsiback_info *info; + struct scsi_request *req; + struct vm_area_struct *vma; + struct gnttab_unmap_grant_ref unmap[SRP_MAX_INDIRECT * 2]; + int i, op, err, offset; + u64 kaddr, uaddr, ptep; + + host = (struct Scsi_Host *) sc->host_scribble; + info = (struct scsiback_info *) host->hostdata; + req = (struct scsi_request *) sc->SCp.ptr; + vma = info->mmap_vma; + + dprintk("%p %d %d %d %u %p\n", req, nsg, nmd, dir, len, vma); + + for (i = 0; i < nmd; i++) { + struct page *page, **map = vma->vm_private_data; + + uaddr = idx_to_uaddr(info, req, i); + kaddr = idx_to_kaddr(info, req, i); + + dprintk("%d %llx %llx\n", i, uaddr, kaddr); + + page = pfn_to_page(__pa(kaddr) >> PAGE_SHIFT); + ClearPageReserved(page); + offset = (uaddr - vma->vm_start) >> PAGE_SHIFT; + map[offset] = NULL; + + } + + if (vma && xen_feature(XENFEAT_auto_translated_physmap)) { + down_write(&vma->vm_mm->mmap_sem); + zap_page_range(vma, idx_to_uaddr(info, req, 0), + nmd << PAGE_SHIFT, NULL); + up_write(&vma->vm_mm->mmap_sem); + } + + for (op = i = 0; i < nmd; i++) { + uaddr = idx_to_uaddr(info, req, i); + kaddr = idx_to_kaddr(info, req, i); + + dprintk("%d %d %llx %llx\n", i, op, uaddr, kaddr); + + gnttab_set_unmap_op(&unmap[op], kaddr, GNTMAP_host_map, + info->handle[__idx(info, req, i)].k); + + err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, op); + BUG_ON(err); + op++; + + if (info->handle[__idx(info, req, i)].u != INVALID_GRANT_HANDLE) { + + err = create_lookup_pte_addr(vma->vm_mm, uaddr, &ptep); + BUG_ON(err); /* FIXME */ + + dprintk("%d %d %llx %llx\n", i, op, uaddr, kaddr); + + gnttab_set_unmap_op(&unmap[op], ptep, GNTMAP_host_map, + info->handle[__idx(info, req, i)].u); + op++; + } + } + + err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, op); + BUG_ON(err); + + if (vma && !xen_feature(XENFEAT_auto_translated_physmap)) + zap_page_range(vma, idx_to_uaddr(info, req, 0), + nmd << PAGE_SHIFT, NULL); + + dprintk("%p %d %d %d %u %p\n", req, nsg, nmd, dir, len, vma); + + return 0; +} + +static int scsiback_cmd_done(struct scsi_cmnd *sc, + void (*done)(struct scsi_cmnd *)) +{ + struct Scsi_Host *host = (struct Scsi_Host *) sc->host_scribble; + struct scsiback_info *info = (struct scsiback_info *) host->hostdata; + struct scsi_request *req = (struct scsi_request *) sc->SCp.ptr; + struct srp_cmd *cmd = (struct srp_cmd *) req->buf; + + srp_transfer_data(sc, cmd, scsiback_cmd_done_fn, 0, 0); + scsiback_send_rsp(info, sc, done); + return 0; +} + +static int scsiback_eh_abort_handler(struct scsi_cmnd *scmd) +{ + BUG_ON(1); + return 0; +} + +static struct scsi_host_template scsiback_sht = { + .module = THIS_MODULE, + .name = "scsiback", + .can_queue = SRP_CAN_QUEUE, + .sg_tablesize = SG_ALL, + .use_clustering = DISABLE_CLUSTERING, + .transfer_response = scsiback_cmd_done, + .eh_abort_handler = scsiback_eh_abort_handler, +}; + +struct scsiback_srp_arg { + struct scsiback_info *info; + struct scsi_request *req; +}; + +static int scsiback_cmd_fn(struct scsi_cmnd *sc, struct scatterlist *sg, + int nsg, struct srp_direct_buf *md, int nmd, + enum dma_data_direction dir, unsigned int len) +{ + struct scsiback_srp_arg *arg = (struct scsiback_srp_arg *) sc; + struct scsiback_info *info = arg->info; + struct scsi_request *req = arg->req; + struct vm_area_struct *vma = info->mmap_vma; + struct gnttab_map_grant_ref map[SRP_MAX_INDIRECT * 2]; + struct page *page; + struct iovec *iov; + int i, op, err; + u64 uaddr, kaddr, ptep; + u32 flags; + + /* TODO: replace iovec */ + iov = (struct iovec *) + (info->uring + SRP_SG_SIZE * req_index(info, req)); + memset(iov, 0, SRP_SG_SIZE); + + for (op = i = 0; i < nmd; i++) { + uaddr = idx_to_uaddr(info, req, i); + kaddr = idx_to_kaddr(info, req, i); + + dprintk("%d %llx %llx %x\n", i, (unsigned long long)uaddr, + (unsigned long long)kaddr, (md + i)->key); + + page = virt_to_page(kaddr); + + flags = GNTMAP_host_map; + if (dir == DMA_TO_DEVICE) + flags |= GNTMAP_readonly; + + gnttab_set_map_op(&map[op], kaddr, flags, + (md + i)->key, + info->dev->otherend_id); + op++; + + if (!xen_feature(XENFEAT_auto_translated_physmap)) { + err = create_lookup_pte_addr(vma->vm_mm, uaddr, &ptep); + BUG_ON(err); /* FIXME */ + + flags = GNTMAP_host_map | GNTMAP_application_map + | GNTMAP_contains_pte; + if (dir == DMA_TO_DEVICE) + flags |= GNTMAP_readonly; + + gnttab_set_map_op(&map[op], ptep, flags, + (md + i)->key, + info->dev->otherend_id); + op++; + } + } + + err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, op); + BUG_ON(err); + + if (!xen_feature(XENFEAT_auto_translated_physmap)) { + for (i = 0; i < nmd; i++) { + int offset, j, idx; + + j = i * 2; + idx = __idx(info, req, i); + + uaddr = idx_to_uaddr(info, req, i); + kaddr = idx_to_kaddr(info, req, i); + + /* FIXME */ + BUG_ON(map[j].status); + BUG_ON(map[j + 1].status); + + info->handle[idx].k = map[j].handle; + info->handle[idx].u = map[j + 1].handle; + set_phys_to_machine(__pa(kaddr) >> PAGE_SHIFT, + FOREIGN_FRAME(map[j].dev_bus_addr >> PAGE_SHIFT)); + offset = (uaddr - vma->vm_start) >> PAGE_SHIFT; + page = pfn_to_page(__pa(kaddr) >> PAGE_SHIFT); + ((struct page **) vma->vm_private_data)[offset] = page; + SetPageReserved(page); + + offset = (md + i)->va & (PAGE_SIZE-1); + iov[i].iov_base = (void *) ((unsigned long) uaddr + offset); + iov[i].iov_len = (md + i)->len; + + dprintk("%llx %d %p %d\n", (unsigned long long)uaddr, + offset, iov[i].iov_base, iov[i].iov_len); + } + } else { + for (i = 0; i < nmd; i++) { + int offset, idx; + + uaddr = idx_to_uaddr(info, req, i); + kaddr = idx_to_kaddr(info, req, i); + + /* FIXME */ + BUG_ON(map[i].status); + + idx = __idx(info, req, i); + info->handle[idx].k = map[i].handle; + info->handle[idx].u = INVALID_GRANT_HANDLE; + + offset = (uaddr - vma->vm_start) >> PAGE_SHIFT; + page = pfn_to_page(__pa(kaddr) >> PAGE_SHIFT); + ((struct page **) vma->vm_private_data)[offset] = page; + SetPageReserved(page); + + offset = (md + i)->va & (PAGE_SIZE-1); + iov[i].iov_base = (void *) ((unsigned long) uaddr + offset); + iov[i].iov_len = (md + i)->len; + + dprintk("%llx %d %p %d\n", (unsigned long long)uaddr, + offset, iov[i].iov_base, iov[i].iov_len); + } + } + return 0; +} + +static void scsiback_worker(void *data) +{ + struct scsiback_info *info = data; + struct scsi_back_ring *ring = &info->ring; + struct scsi_request *req; + struct srp_cmd *cmd; + struct vm_area_struct *vma = info->mmap_vma; + struct scsiback_srp_arg arg; + RING_IDX rc, rp; + u64 addr; + + rc = ring->req_cons; + rp = ring->sring->req_prod; + rmb(); + + while ((rc != rp) && !RING_REQUEST_CONS_OVERFLOW(ring, rc)) { + dprintk("%u %u\n", rc, rp); + req = RING_GET_REQUEST(ring, rc); + ring->req_cons = ++rc; + cmd = (struct srp_cmd *) req->buf; + + arg.info = info; + arg.req = req; + + dprintk("%x %x\n", cmd->opcode, cmd->cdb[0]); + srp_transfer_data((struct scsi_cmnd *)&arg, cmd, + scsiback_cmd_fn, 0, 0); + addr = vma->vm_start + SRP_SG_SIZE * req_index(info, req); + srp_cmd_queue(info->host, cmd, req, addr); + } +} + +irqreturn_t scsiback_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct scsiback_info *info = (struct scsiback_info *) dev_id; + + queue_work(scsibkd, &info->scsiback_work); + + return IRQ_HANDLED; +} + +static int scsiback_connect(struct scsiback_info *info) +{ + struct xenbus_device *dev = info->dev; + unsigned long ring_ref; + unsigned int evtchn; + int err; + + err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", + &ring_ref, "event-channel", "%u", &evtchn, NULL); + if (err) { + xenbus_dev_fatal(dev, err, "reading %s ring", dev->otherend); + return err; + } + + return scsiback_init_sring(info, ring_ref, evtchn); +} + +static void scsiback_frontend_changed(struct xenbus_device *dev, + enum xenbus_state frontend_state) +{ + struct scsiback_info *info = dev->dev.driver_data; + int err; + + dprintk("%p %u %u\n", dev, dev->state, frontend_state); + switch (frontend_state) { + case XenbusStateInitialising: + break; + + case XenbusStateInitialised: + case XenbusStateConnected: + if (dev->state == XenbusStateConnected) + break; + + err = scsiback_connect(info); + if (err) + break; + + err = xenbus_switch_state(dev, XenbusStateConnected); + if (err) + xenbus_dev_fatal(dev, err, "switching to Connected state", + dev->nodename); + break; + + case XenbusStateClosing: + xenbus_switch_state(dev, XenbusStateClosing); + break; + + case XenbusStateClosed: + xenbus_switch_state(dev, XenbusStateClosed); + if (xenbus_dev_is_online(dev)) + break; + + case XenbusStateUnknown: + /* + * wordaround. + */ + if (info->host->host_no) + device_unregister(&dev->dev); + break; + default: + xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend", + frontend_state); + break; + } +} + +static void scsiback_backend_changed(struct xenbus_watch *watch, + const char **vec, unsigned int len) +{ + struct scsiback_info *info + container_of(watch, struct scsiback_info, backend_watch); + + dprintk("%p %u\n", info->dev, info->dev->state); + + /* TODO */ +} + +static int scsiback_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + int err, nr; + struct Scsi_Host *host; + struct scsiback_info *info; + struct xenbus_transaction xbt; + + dprintk("%p %d\n", dev, dev->otherend_id); + + host = scsi_host_alloc(&scsiback_sht, sizeof(struct scsiback_info)); + if (!host) + return -ENOMEM; + err = scsi_tgt_alloc_queue(host); + if (err) + goto put_host; + + err = scsi_add_host(host, &dev->dev); + if (err) + goto put_host; + + info = (struct scsiback_info *) host->hostdata; + dev->dev.driver_data = info; + info->dev = dev; + info->host = host; + + info->uring = get_zeroed_page(GFP_KERNEL); + if (!info->uring) + goto put_host; + SetPageReserved(virt_to_page(info->uring)); + + nr = SRP_RING_PAGES + SRP_MAPPED_PAGES; + info->mmap_pages = alloc_empty_pages_and_pagevec(nr); + if (!info->mmap_pages) + goto free_ring; + + INIT_WORK(&info->scsiback_work, scsiback_worker, info); + + err = xenbus_transaction_start(&xbt); + if (err) + eprintk("fail to transcation %d\n", err); + + err = xenbus_printf(xbt, dev->nodename, "hostno", "%u", host->host_no); + if (err) + eprintk("fail to transcation %d\n", err); + + err = xenbus_transaction_end(xbt, 0); + if (err) + eprintk("fail to transcation %d\n", err); + + err = xenbus_watch_path2(dev, dev->nodename, + "scsi-host", + &info->backend_watch, + scsiback_backend_changed); + if (err) + goto free_page; + + err = xenbus_switch_state(dev, XenbusStateInitWait); + if (err) + goto stop_watch; + + return 0; + +stop_watch: + /* free resource */ +free_page: + free_empty_pages_and_pagevec(info->mmap_pages, nr); +free_ring: + free_page(info->uring); +put_host: + scsi_host_put(host); + return err; +} + +static int scsiback_remove(struct xenbus_device *dev) +{ + struct scsiback_info *info = dev->dev.driver_data; + struct Scsi_Host *host = info->host; + + dprintk("%p %u\n", host, host->host_no); + + return 0; +} + +/* should we free the resource in scsiback_remove? */ +static int scsiback_release(struct inode *inode, struct file *filp) +{ + unsigned int hostno = MINOR(filp->f_dentry->d_inode->i_rdev); + struct scsiback_info *info; + struct Scsi_Host *host; + + host = scsi_host_lookup(hostno); + if (!host) { + eprintk("no scsi host %d\n", hostno); + return -EAGAIN; + } + info = (struct scsiback_info *)host->hostdata; + + ClearPageReserved(virt_to_page(info->uring)); + free_page(info->uring); + + /* TODO */ +#if 0 + vma = info->mmap_vma; + if (vma) { + zap_page_range(vma, vma->vm_start, + vma->vm_end - vma->vm_start, NULL); + info->mmap_vma = NULL; + } +#endif + free_empty_pages_and_pagevec(info->mmap_pages, + SRP_RING_PAGES + SRP_MAPPED_PAGES); + scsi_remove_host(host); + scsi_tgt_free_queue(host); + scsi_host_put(host); + + return 0; +} + +static struct page *scsiback_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + return NOPAGE_SIGBUS; +} + +struct vm_operations_struct scsiback_vm_ops = { + .nopage = scsiback_nopage, +}; + +static int scsiback_mmap(struct file *filp, struct vm_area_struct *vma) +{ + int i, err; + unsigned long nr; + unsigned int hostno = MINOR(filp->f_dentry->d_inode->i_rdev); + struct page **map; + struct scsiback_info *info; + struct Scsi_Host *host; + + dprintk("%u start %lx, end %lx\n", hostno, vma->vm_start, vma->vm_end); + + host = scsi_host_lookup(hostno); + if (!host) { + eprintk("no scsi host %d\n", hostno); + return -EAGAIN; + } + info = (struct scsiback_info *)host->hostdata; + + vma->vm_flags |= VM_RESERVED; + vma->vm_ops = &scsiback_vm_ops; + + nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + if (nr != SRP_RING_PAGES + SRP_MAPPED_PAGES) { + eprintk("you _must_ map exactly %lu pages!\n", nr); + err = -EINVAL; + goto host_put; + } + + err = remap_pfn_range(vma, vma->vm_start, + __pa(info->uring) >> PAGE_SHIFT, + PAGE_SIZE, vma->vm_page_prot); + if (err) { + eprintk("fail to map frontend ring %d!\n", err); + goto host_put; + } + + /* Mark this VM as containing foreign pages, and set up mappings. */ + map = kzalloc(nr * sizeof(struct page_struct *), GFP_KERNEL); + if (!map) { + eprintk("Couldn''t alloc VM_FOREIGN map.\n"); + err = -ENOMEM; + zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, NULL); + goto host_put; + } + + for (i = 0; i < nr; i++) + map[i] = NULL; + + vma->vm_private_data = map; + vma->vm_flags |= VM_FOREIGN; + + info->ustart = vma->vm_start + (SRP_RING_PAGES << PAGE_SHIFT); + + dprintk("%d %u start %lx, end %lx ustart %llx\n", + err, hostno, vma->vm_start, vma->vm_end, info->ustart); + + info->mmap_vma = vma; +host_put: + scsi_host_put(host); + + return err; +} + +static struct file_operations scsiback_fops = { + .owner = THIS_MODULE, + .mmap = scsiback_mmap, + .release = scsiback_release, +}; + +static struct xenbus_device_id scsiback_ids[] = { + { "scsi" }, + { "" } +}; + +static struct xenbus_driver scsiback = { + .name = "scsi", + .owner = THIS_MODULE, + .ids = scsiback_ids, + .probe = scsiback_probe, + .remove = scsiback_remove, + .otherend_changed = scsiback_frontend_changed +}; + +static int __init scsiback_init(void) +{ + int err = -ENOMEM; + + if (!is_running_on_xen()) + return -ENODEV; + + major = register_chrdev(0, "scsiback", &scsiback_fops); + if (major < 0) + return major; + + scsibkd = create_singlethread_workqueue("scsibkd"); + if (!scsibkd) + goto free_dev; + + err = xenbus_register_backend(&scsiback); + if (err) + goto destroy_wq; + return 0; +free_dev: + unregister_chrdev(major, "scsiback"); +destroy_wq: + destroy_workqueue(scsibkd); + return err; +} + +module_init(scsiback_init); + +MODULE_AUTHOR("FUJITA Tomonori"); +MODULE_DESCRIPTION("Xen SCSI backend driver"); +MODULE_LICENSE("GPL"); diff -r 105d5d6b4e0d -r 95ca3ffbdbfd linux-2.6-xen-sparse/drivers/xen/scsiback/scsiback_priv.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/drivers/xen/scsiback/scsiback_priv.h Wed Jan 03 01:35:35 2007 +0900 @@ -0,0 +1,35 @@ +struct grant_handle_pair { + grant_handle_t k; + grant_handle_t u; +}; + +struct scsiback_info { + struct xenbus_device *dev; + struct Scsi_Host *host; + struct xenbus_watch backend_watch; + + unsigned int evtchn; + unsigned int irq; + + struct scsi_back_ring ring; + struct vm_struct *ring_area; + + grant_handle_t shmem_handle; + grant_ref_t shmem_ref; + + struct work_struct scsiback_work; + + /* Add something tgt code to support this kind of stuff? */ + unsigned long uring; + + struct vm_area_struct *mmap_vma; + struct page **mmap_pages; + u64 ustart; + + struct grant_handle_pair handle[SRP_CAN_QUEUE * SRP_MAX_INDIRECT]; +}; + +extern irqreturn_t scsiback_intr(int, void *, struct pt_regs *); +extern int scsiback_init_sring(struct scsiback_info *, + unsigned long, unsigned int); +extern void scsiback_exit_sring(struct scsiback_info *); diff -r 105d5d6b4e0d -r 95ca3ffbdbfd 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 Jan 03 01:35:35 2007 +0900 @@ -0,0 +1,1 @@ +obj-$(CONFIG_XEN_SCSI_FRONTEND) += scsifront.o diff -r 105d5d6b4e0d -r 95ca3ffbdbfd 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 Jan 03 01:35:35 2007 +0900 @@ -0,0 +1,472 @@ +/* + * Xen SCSI frontend driver + * + * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org> + * + * 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"); diff -r 105d5d6b4e0d -r 95ca3ffbdbfd xen/include/public/io/scsi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/public/io/scsi.h Wed Jan 03 01:35:35 2007 +0900 @@ -0,0 +1,42 @@ +#ifndef __XEN__PUBLIC_IO_SCSI_H__ +#define __XEN__PUBLIC_IO_SCSI_H__ + +#include "ring.h" + +#define SRP_MAX_IU_LEN 256 +#define SRP_CAN_QUEUE 8 + +struct scsi_request { + char buf[SRP_MAX_IU_LEN]; +}; + +struct scsi_response { + char buf[sizeof(struct srp_rsp)]; +}; + +DEFINE_RING_TYPES(scsi, struct scsi_request, struct scsi_response); + +#define SRP_MAX_INDIRECT ((SRP_MAX_IU_LEN - \ + sizeof (struct srp_cmd) - \ + sizeof (struct srp_indirect_buf)) / 16) + +#define SRP_MAPPED_PAGES (SRP_CAN_QUEUE * SRP_MAX_INDIRECT) +#define SRP_SG_SIZE (sizeof(struct iovec) * SRP_MAX_INDIRECT) +#define SRP_RING_PAGES (((SRP_SG_SIZE * SRP_CAN_QUEUE) \ + + PAGE_SIZE - 1) >> PAGE_SHIFT) + +/* + * We use iovec structure so the combination of 32-bit user-space tgtd + * and 64-bit kernel does not work. + */ + +/* + * srp_cmd : 48 bytes + * srp_direct_buf : 16 bytes + * srp_indirect_buf : 20 bytes + * SRP_MAX_INDIRECT : 11 + * SRP_MAX_MAPPED_PAGES : 88 + * SRP_RING_PAGES : 1 + */ + +#endif _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel