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

[Xen-devel] [PATCH 6/6] add scsi target patch



# HG changeset patch
# User fujita.tomonori@xxxxxxxxxxxxx
# Node ID 3749a0e2580a668bfb029fb0348e9f89660becd6
# Parent  840f33e54054270e3f4b9704111ed52bd381653b
Add scsi target patch

This patch includes the SCSI target framework (tgt) that adds target
driver support in Linux SCSI mid layer. This is a modified version of
the version included in the -mm tree.

diff -r 840f33e54054 -r 3749a0e2580a patches/linux-2.6.16.13/tgt.patch
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.13/tgt.patch Wed Aug 02 15:03:05 2006 +0900
@@ -0,0 +1,3253 @@
+Subject: [PATCH] scsi target: add target support and IBM VIO driver
+
+---
+
+ block/ll_rw_blk.c                |   40 +-
+ block/scsi_ioctl.c               |    3 
+ drivers/scsi/Kconfig             |   30 +
+ drivers/scsi/Makefile            |    5 
+ drivers/scsi/hosts.c             |    5 
+ drivers/scsi/ibmvscsi/Makefile   |    2 
+ drivers/scsi/ibmvscsi/ibmvstgt.c |  943 ++++++++++++++++++++++++++++++++++++++
+ drivers/scsi/libsrp.c            |  450 ++++++++++++++++++
+ drivers/scsi/scsi.c              |   43 +-
+ drivers/scsi/scsi_lib.c          |   33 +
+ drivers/scsi/scsi_tgt_if.c       |  316 +++++++++++++
+ drivers/scsi/scsi_tgt_lib.c      |  707 ++++++++++++++++++++++++++++
+ drivers/scsi/scsi_tgt_priv.h     |   24 +
+ fs/bio.c                         |   19 -
+ include/linux/blkdev.h           |    3 
+ include/scsi/libsrp.h            |   75 +++
+ include/scsi/scsi_cmnd.h         |    8 
+ include/scsi/scsi_host.h         |   43 ++
+ include/scsi/scsi_tgt.h          |   17 +
+ include/scsi/scsi_tgt_if.h       |   91 ++++
+ 20 files changed, 2793 insertions(+), 64 deletions(-)
+ create mode 100644 drivers/scsi/ibmvscsi/ibmvstgt.c
+ create mode 100644 drivers/scsi/libsrp.c
+ create mode 100644 drivers/scsi/scsi_tgt_if.c
+ create mode 100644 drivers/scsi/scsi_tgt_lib.c
+ create mode 100644 drivers/scsi/scsi_tgt_priv.h
+ create mode 100644 include/scsi/libsrp.h
+ create mode 100644 include/scsi/scsi_tgt.h
+ create mode 100644 include/scsi/scsi_tgt_if.h
+
+f21c20da255c84fe2072df460048f379af3eeb29
+diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
+index 7eb36c5..4fe85d7 100644
+--- a/block/ll_rw_blk.c
++++ b/block/ll_rw_blk.c
+@@ -2351,19 +2351,20 @@ int blk_rq_map_user(request_queue_t *q, 
+       else
+               bio = bio_copy_user(q, uaddr, len, reading);
+ 
+-      if (!IS_ERR(bio)) {
+-              rq->bio = rq->biotail = bio;
+-              blk_rq_bio_prep(q, rq, bio);
++      if (IS_ERR(bio))
++              return PTR_ERR(bio);
+ 
+-              rq->buffer = rq->data = NULL;
+-              rq->data_len = len;
+-              return 0;
++      if (bio->bi_size != len) {
++              bio_endio(bio, bio->bi_size, 0);
++              bio_unmap_user(bio);
++              return -EINVAL;
+       }
+ 
+-      /*
+-       * bio is the err-ptr
+-       */
+-      return PTR_ERR(bio);
++      rq->bio = rq->biotail = bio;
++      blk_rq_bio_prep(q, rq, bio);
++      rq->buffer = rq->data = NULL;
++      rq->data_len = len;
++      return 0;
+ }
+ 
+ EXPORT_SYMBOL(blk_rq_map_user);
+@@ -2389,7 +2390,7 @@ EXPORT_SYMBOL(blk_rq_map_user);
+  *    unmapping.
+  */
+ int blk_rq_map_user_iov(request_queue_t *q, struct request *rq,
+-                      struct sg_iovec *iov, int iov_count)
++                      struct sg_iovec *iov, int iov_count, unsigned int len)
+ {
+       struct bio *bio;
+ 
+@@ -2403,6 +2404,12 @@ int blk_rq_map_user_iov(request_queue_t 
+       if (IS_ERR(bio))
+               return PTR_ERR(bio);
+ 
++      if (bio->bi_size != len) {
++              bio_endio(bio, bio->bi_size, 0);
++              bio_unmap_user(bio);
++              return -EINVAL;
++      }
++
+       rq->bio = rq->biotail = bio;
+       blk_rq_bio_prep(q, rq, bio);
+       rq->buffer = rq->data = NULL;
+@@ -2826,16 +2833,12 @@ static void init_request_from_bio(struct
+ 
+       req->errors = 0;
+       req->hard_sector = req->sector = bio->bi_sector;
+-      req->hard_nr_sectors = req->nr_sectors = bio_sectors(bio);
+-      req->current_nr_sectors = req->hard_cur_sectors = bio_cur_sectors(bio);
+-      req->nr_phys_segments = bio_phys_segments(req->q, bio);
+-      req->nr_hw_segments = bio_hw_segments(req->q, bio);
+-      req->buffer = bio_data(bio);    /* see ->buffer comment above */
+       req->waiting = NULL;
+-      req->bio = req->biotail = bio;
+       req->ioprio = bio_prio(bio);
+       req->rq_disk = bio->bi_bdev->bd_disk;
+       req->start_time = jiffies;
++
++      blk_rq_bio_prep(req->q, req, bio);
+ }
+ 
+ static int __make_request(request_queue_t *q, struct bio *bio)
+@@ -3487,9 +3490,6 @@ EXPORT_SYMBOL(end_request);
+ 
+ void blk_rq_bio_prep(request_queue_t *q, struct request *rq, struct bio *bio)
+ {
+-      /* first three bits are identical in rq->flags and bio->bi_rw */
+-      rq->flags |= (bio->bi_rw & 7);
+-
+       rq->nr_phys_segments = bio_phys_segments(q, bio);
+       rq->nr_hw_segments = bio_hw_segments(q, bio);
+       rq->current_nr_sectors = bio_cur_sectors(bio);
+diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
+index b33eda2..b77e185 100644
+--- a/block/scsi_ioctl.c
++++ b/block/scsi_ioctl.c
+@@ -274,7 +274,8 @@ static int sg_io(struct file *file, requ
+                       goto out;
+               }
+ 
+-              ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count);
++              ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count,
++                                        hdr->dxfer_len);
+               kfree(iov);
+       } else if (hdr->dxfer_len)
+               ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len);
+diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
+index a480a37..82234ec 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 && NET && 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
+@@ -900,6 +907,20 @@ config SCSI_IBMVSCSI
+         To compile this driver as a module, choose M here: the
+         module will be called ibmvscsic.
+ 
++config SCSI_IBMVSCSIS
++      tristate "IBM Virtual SCSI Server support"
++      depends on PPC_PSERIES && SCSI_TGT && SCSI_SRP
++      help
++        This is the SRP target driver for IBM pSeries virtual environments.
++
++        The userspace component needed to initialize the driver and
++        documentation can be found:
++
++        http://stgt.berlios.de/
++
++        To compile this driver as a module, choose M here: the
++        module will be called ibmvstgt.
++
+ config SCSI_INITIO
+       tristate "Initio 9100U(W) support"
+       depends on PCI && SCSI
+@@ -1829,6 +1850,15 @@ config ZFCP
+           called zfcp. If you want to compile it as a module, say M here
+           and read <file:Documentation/modules.txt>.
+ 
++config SCSI_SRP
++      tristate "SCSI RDMA Protocol helper library"
++      depends on SCSI
++      help
++        If you wish to use SRP target drivers, say Y.
++
++        To compile this driver as a module, choose M here: the
++        module will be called libsrp.
++
+ endmenu
+ 
+ source "drivers/scsi/pcmcia/Kconfig"
+diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
+index 81803a1..b4eb854 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
+ 
+@@ -120,7 +121,9 @@ obj-$(CONFIG_SCSI_FCAL)            += fcal.o
+ obj-$(CONFIG_SCSI_LASI700)    += 53c700.o lasi700.o
+ obj-$(CONFIG_SCSI_NSP32)      += nsp32.o
+ obj-$(CONFIG_SCSI_IPR)                += ipr.o
++obj-$(CONFIG_SCSI_SRP)                += libsrp.o
+ obj-$(CONFIG_SCSI_IBMVSCSI)   += ibmvscsi/
++obj-$(CONFIG_SCSI_IBMVSCSIS)  += ibmvscsi/
+ obj-$(CONFIG_SCSI_SATA_AHCI)  += libata.o ahci.o
+ obj-$(CONFIG_SCSI_SATA_SVW)   += libata.o sata_svw.o
+ obj-$(CONFIG_SCSI_ATA_PIIX)   += libata.o ata_piix.o
+@@ -156,6 +159,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_if.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/hosts.c b/drivers/scsi/hosts.c
+index dfcb96f..f8cce09 100644
+--- a/drivers/scsi/hosts.c
++++ b/drivers/scsi/hosts.c
+@@ -264,6 +264,11 @@ static void scsi_host_dev_release(struct
+       if (shost->work_q)
+               destroy_workqueue(shost->work_q);
+ 
++      if (shost->uspace_req_q) {
++              kfree(shost->uspace_req_q->queuedata);
++              scsi_free_queue(shost->uspace_req_q);
++      }
++
+       scsi_destroy_command_freelist(shost);
+       kfree(shost->shost_data);
+ 
+diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
+index 4e247b6..6ac0633 100644
+--- a/drivers/scsi/ibmvscsi/Makefile
++++ b/drivers/scsi/ibmvscsi/Makefile
+@@ -3,3 +3,5 @@ obj-$(CONFIG_SCSI_IBMVSCSI)    += ibmvscsic
+ ibmvscsic-y                   += ibmvscsi.o
+ ibmvscsic-$(CONFIG_PPC_ISERIES)       += iseries_vscsi.o 
+ ibmvscsic-$(CONFIG_PPC_PSERIES)       += rpa_vscsi.o 
++
++obj-$(CONFIG_SCSI_IBMVSCSIS)  += ibmvstgt.o
+diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c 
b/drivers/scsi/ibmvscsi/ibmvstgt.c
+new file mode 100644
+index 0000000..cf1e851
+--- /dev/null
++++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
+@@ -0,0 +1,943 @@
++/*
++ * IBM eServer i/pSeries Virtual SCSI Target Driver
++ * Copyright (C) 2003-2005 Dave Boutcher (boutcher@xxxxxxxxxx) IBM Corp.
++ *                       Santiago Leon (santil@xxxxxxxxxx) IBM Corp.
++ *                       Linda Xie (lxie@xxxxxxxxxx) IBM Corp.
++ *
++ * Copyright (C) 2005-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
++ * USA
++ */
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <scsi/scsi.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_tgt.h>
++#include <scsi/libsrp.h>
++#include <asm/hvcall.h>
++#include <asm/iommu.h>
++#include <asm/prom.h>
++#include <asm/vio.h>
++
++#include "ibmvscsi.h"
++
++#define       INITIAL_SRP_LIMIT       16
++#define       DEFAULT_MAX_SECTORS     512
++
++#define       TGT_NAME        "ibmvstgt"
++
++/*
++ * Hypervisor calls.
++ */
++#define h_copy_rdma(l, sa, sb, da, db) \
++                      plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db)
++#define h_send_crq(ua, l, h) \
++                      plpar_hcall_norets(H_SEND_CRQ, ua, l, h)
++#define h_reg_crq(ua, tok, sz)\
++                      plpar_hcall_norets(H_REG_CRQ, ua, tok, sz);
++#define h_free_crq(ua) \
++                      plpar_hcall_norets(H_FREE_CRQ, ua);
++
++/* tmp - will replace with SCSI logging stuff */
++#define eprintk(fmt, args...)                                 \
++do {                                                          \
++      printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);  \
++} while (0)
++/* #define dprintk eprintk */
++#define dprintk(fmt, args...)
++
++struct vio_port {
++      struct vio_dev *dma_dev;
++
++      struct crq_queue crq_queue;
++      struct work_struct crq_work;
++
++      unsigned long liobn;
++      unsigned long riobn;
++};
++
++static struct workqueue_struct *vtgtd;
++
++/*
++ * These are fixed for the system and come from the Open Firmware device tree.
++ * We just store them here to save getting them every time.
++ */
++static char system_id[64] = "";
++static char partition_name[97] = "UNKNOWN";
++static unsigned int partition_number = -1;
++
++static struct vio_port *target_to_port(struct srp_target *target)
++{
++      return (struct vio_port *) target->ldata;
++}
++
++static inline union viosrp_iu *vio_iu(struct iu_entry *iue)
++{
++      return (union viosrp_iu *) (iue->sbuf->buf);
++}
++
++static int send_iu(struct iu_entry *iue, uint64_t length, uint8_t format)
++{
++      struct srp_target *target = iue->target;
++      struct vio_port *vport = target_to_port(target);
++      long rc, rc1;
++      union {
++              struct viosrp_crq cooked;
++              uint64_t raw[2];
++      } crq;
++
++      /* First copy the SRP */
++      rc = h_copy_rdma(length, vport->liobn, iue->sbuf->dma,
++                       vport->riobn, iue->remote_token);
++
++      if (rc)
++              eprintk("Error %ld transferring data\n", rc);
++
++      crq.cooked.valid = 0x80;
++      crq.cooked.format = format;
++      crq.cooked.reserved = 0x00;
++      crq.cooked.timeout = 0x00;
++      crq.cooked.IU_length = length;
++      crq.cooked.IU_data_ptr = vio_iu(iue)->srp.rsp.tag;
++
++      if (rc == 0)
++              crq.cooked.status = 0x99;       /* Just needs to be non-zero */
++      else
++              crq.cooked.status = 0x00;
++
++      rc1 = h_send_crq(vport->dma_dev->unit_address, crq.raw[0], crq.raw[1]);
++
++      if (rc1) {
++              eprintk("%ld sending response\n", rc1);
++              return rc1;
++      }
++
++      return rc;
++}
++
++#define SRP_RSP_SENSE_DATA_LEN        18
++
++static int send_rsp(struct iu_entry *iue, unsigned char status,
++                  unsigned char asc)
++{
++      union viosrp_iu *iu = vio_iu(iue);
++      uint64_t tag = iu->srp.rsp.tag;
++
++      /* If the linked bit is on and status is good */
++      if (test_bit(V_LINKED, &iue->flags) && (status == NO_SENSE))
++              status = 0x10;
++
++      memset(iu, 0, sizeof(struct srp_rsp));
++      iu->srp.rsp.opcode = SRP_RSP;
++      iu->srp.rsp.req_lim_delta = 1;
++      iu->srp.rsp.tag = tag;
++
++      if (test_bit(V_DIOVER, &iue->flags))
++              iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER;
++
++      iu->srp.rsp.data_in_res_cnt = 0;
++      iu->srp.rsp.data_out_res_cnt = 0;
++
++      iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID;
++
++      iu->srp.rsp.resp_data_len = 0;
++      iu->srp.rsp.status = status;
++      if (status) {
++              uint8_t *sense = iu->srp.rsp.data;
++
++              if (iue->scmd) {
++                      iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
++                      iu->srp.rsp.sense_data_len = SCSI_SENSE_BUFFERSIZE;
++                      memcpy(sense, iue->scmd->sense_buffer,
++                             SCSI_SENSE_BUFFERSIZE);
++              } else {
++                      iu->srp.rsp.status = SAM_STAT_CHECK_CONDITION;
++                      iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
++                      iu->srp.rsp.sense_data_len = SRP_RSP_SENSE_DATA_LEN;
++
++                      /* Valid bit and 'current errors' */
++                      sense[0] = (0x1 << 7 | 0x70);
++                      /* Sense key */
++                      sense[2] = status;
++                      /* Additional sense length */
++                      sense[7] = 0xa; /* 10 bytes */
++                      /* Additional sense code */
++                      sense[12] = asc;
++              }
++      }
++
++      send_iu(iue, sizeof(iu->srp.rsp) + SRP_RSP_SENSE_DATA_LEN,
++              VIOSRP_SRP_FORMAT);
++
++      return 0;
++}
++
++static void handle_cmd_queue(struct srp_target *target)
++{
++      struct iu_entry *iue;
++      unsigned long flags;
++
++retry:
++      spin_lock_irqsave(&target->lock, flags);
++
++      list_for_each_entry(iue, &target->cmd_queue, ilist) {
++              if (!test_and_set_bit(V_FLYING, &iue->flags)) {
++                      spin_unlock_irqrestore(&target->lock, flags);
++                      srp_cmd_perform(iue, (struct srp_cmd *) iue->sbuf->buf);
++                      goto retry;
++              }
++      }
++
++      spin_unlock_irqrestore(&target->lock, flags);
++}
++
++static int ibmvstgt_rdma(struct iu_entry *iue, struct scatterlist *sg, int 
nsg,
++                       struct srp_direct_buf *md, int nmd,
++                       enum dma_data_direction dir, unsigned int rest)
++{
++      struct srp_target *target = iue->target;
++      struct vio_port *vport = target_to_port(target);
++      dma_addr_t token;
++      long err;
++      unsigned int done = 0;
++      int i, sidx, soff;
++
++      sidx = soff = 0;
++      token = sg_dma_address(sg + sidx);
++
++      for (i = 0; i < nmd && rest; i++) {
++              unsigned int mdone, mlen;
++
++              mlen = min(rest, md[i].len);
++              for (mdone = 0; mlen;) {
++                      int slen = min(sg_dma_len(sg + sidx) - soff, mlen);
++
++                      if (dir == DMA_TO_DEVICE)
++                              err = h_copy_rdma(slen,
++                                                vport->riobn,
++                                                md[i].va + mdone,
++                                                vport->liobn,
++                                                token + soff);
++                      else
++                              err = h_copy_rdma(slen,
++                                                vport->liobn,
++                                                token + soff,
++                                                vport->riobn,
++                                                md[i].va + mdone);
++
++                      if (err != H_SUCCESS) {
++                              eprintk("rdma error %d %d\n", dir, slen);
++                              goto out;
++                      }
++
++                      mlen -= slen;
++                      mdone += slen;
++                      soff += slen;
++                      done += slen;
++
++                      if (soff == sg_dma_len(sg + sidx)) {
++                              sidx++;
++                              soff = 0;
++                              token = sg_dma_address(sg + sidx);
++
++                              if (sidx > nsg) {
++                                      eprintk("out of sg %p %d %d\n",
++                                              iue, sidx, nsg);
++                                      goto out;
++                              }
++                      }
++              };
++
++              rest -= mlen;
++      }
++out:
++
++      return 0;
++}
++
++static int ibmvstgt_transfer_data(struct scsi_cmnd *scmd,
++                                void (*done)(struct scsi_cmnd *))
++{
++      struct iu_entry *iue = (struct iu_entry *) scmd->SCp.ptr;
++      int err;
++
++      err = srp_transfer_data(scmd, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma);
++      done(scmd);
++
++      return err;
++}
++
++static int ibmvstgt_cmd_done(struct scsi_cmnd *scmd,
++                           void (*done)(struct scsi_cmnd *))
++{
++      unsigned long flags;
++      struct iu_entry *iue = (struct iu_entry *) scmd->SCp.ptr;
++      struct srp_target *target = iue->target;
++
++      dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]);
++
++      spin_lock_irqsave(&target->lock, flags);
++      list_del(&iue->ilist);
++      spin_unlock_irqrestore(&target->lock, flags);
++
++      if (scmd->result != SAM_STAT_GOOD) {
++              eprintk("operation failed %p %d %x\n",
++                      iue, scmd->result, vio_iu(iue)->srp.cmd.cdb[0]);
++              send_rsp(iue, HARDWARE_ERROR, 0x00);
++      } else
++              send_rsp(iue, NO_SENSE, 0x00);
++
++      done(scmd);
++      srp_iu_put(iue);
++      return 0;
++}
++
++int send_adapter_info(struct iu_entry *iue,
++                    dma_addr_t remote_buffer, uint16_t length)
++{
++      struct srp_target *target = iue->target;
++      struct vio_port *vport = target_to_port(target);
++      struct Scsi_Host *shost = target->shost;
++      dma_addr_t data_token;
++      struct mad_adapter_info_data *info;
++      int err;
++
++      info = dma_alloc_coherent(target->dev, sizeof(*info), &data_token,
++                                GFP_KERNEL);
++      if (!info) {
++              eprintk("bad dma_alloc_coherent %p\n", target);
++              return 1;
++      }
++
++      /* Get remote info */
++      err = h_copy_rdma(sizeof(*info), vport->riobn, remote_buffer,
++                        vport->liobn, data_token);
++      if (err == H_SUCCESS) {
++              dprintk("Client connect: %s (%d)\n",
++                      info->partition_name, info->partition_number);
++      }
++
++      memset(info, 0, sizeof(*info));
++
++      strcpy(info->srp_version, "16.a");
++      strncpy(info->partition_name, partition_name,
++              sizeof(info->partition_name));
++      info->partition_number = partition_number;
++      info->mad_version = 1;
++      info->os_type = 2;
++      info->port_max_txu[0] = shost->hostt->max_sectors << 9;
++
++      /* Send our info to remote */
++      err = h_copy_rdma(sizeof(*info), vport->liobn, data_token,
++                        vport->riobn, remote_buffer);
++
++      dma_free_coherent(target->dev, sizeof(*info), info, data_token);
++
++      if (err != H_SUCCESS) {
++              eprintk("Error sending adapter info %d\n", err);
++              return 1;
++      }
++
++      return 0;
++}
++
++static void process_login(struct iu_entry *iue)
++{
++      union viosrp_iu *iu = vio_iu(iue);
++      struct srp_login_rsp *rsp = &iu->srp.login_rsp;
++      uint64_t tag = iu->srp.rsp.tag;
++
++      /* TODO handle case that requested size is wrong and
++       * buffer format is wrong
++       */
++      memset(iu, 0, sizeof(struct srp_login_rsp));
++      rsp->opcode = SRP_LOGIN_RSP;
++      rsp->req_lim_delta = INITIAL_SRP_LIMIT;
++      rsp->tag = tag;
++      rsp->max_it_iu_len = sizeof(union srp_iu);
++      rsp->max_ti_iu_len = sizeof(union srp_iu);
++      /* direct and indirect */
++      rsp->buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT;
++
++      send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT);
++}
++
++static inline void queue_cmd(struct iu_entry *iue)
++{
++      struct srp_target *target = iue->target;
++      unsigned long flags;
++
++      spin_lock_irqsave(&target->lock, flags);
++      list_add_tail(&iue->ilist, &target->cmd_queue);
++      spin_unlock_irqrestore(&target->lock, flags);
++}
++
++static int process_tsk_mgmt(struct iu_entry *iue)
++{
++      union viosrp_iu *iu = vio_iu(iue);
++      int fn;
++
++      dprintk("%p %u\n", iue, iu->srp.tsk_mgmt.tsk_mgmt_func);
++
++      switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
++      case SRP_TSK_ABORT_TASK:
++              fn = ABORT_TASK;
++              break;
++      case SRP_TSK_ABORT_TASK_SET:
++              fn = ABORT_TASK_SET;
++              break;
++      case SRP_TSK_CLEAR_TASK_SET:
++              fn = CLEAR_TASK_SET;
++              break;
++      case SRP_TSK_LUN_RESET:
++              fn = LOGICAL_UNIT_RESET;
++              break;
++      case SRP_TSK_CLEAR_ACA:
++              fn = CLEAR_ACA;
++              break;
++      default:
++              fn = 0;
++      }
++      if (fn)
++              scsi_tgt_tsk_mgmt_request(iue->target->shost, fn,
++                                        iu->srp.tsk_mgmt.task_tag,
++                                        (struct scsi_lun *) 
&iu->srp.tsk_mgmt.lun,
++                                        iue);
++      else
++              send_rsp(iue, ILLEGAL_REQUEST, 0x20);
++
++      return !fn;
++}
++
++static int process_mad_iu(struct iu_entry *iue)
++{
++      union viosrp_iu *iu = vio_iu(iue);
++      struct viosrp_adapter_info *info;
++      struct viosrp_host_config *conf;
++
++      switch (iu->mad.empty_iu.common.type) {
++      case VIOSRP_EMPTY_IU_TYPE:
++              eprintk("%s\n", "Unsupported EMPTY MAD IU");
++              break;
++      case VIOSRP_ERROR_LOG_TYPE:
++              eprintk("%s\n", "Unsupported ERROR LOG MAD IU");
++              iu->mad.error_log.common.status = 1;
++              send_iu(iue, sizeof(iu->mad.error_log), VIOSRP_MAD_FORMAT);
++              break;
++      case VIOSRP_ADAPTER_INFO_TYPE:
++              info = &iu->mad.adapter_info;
++              info->common.status = send_adapter_info(iue, info->buffer,
++                                                      info->common.length);
++              send_iu(iue, sizeof(*info), VIOSRP_MAD_FORMAT);
++              break;
++      case VIOSRP_HOST_CONFIG_TYPE:
++              conf = &iu->mad.host_config;
++              conf->common.status = 1;
++              send_iu(iue, sizeof(*conf), VIOSRP_MAD_FORMAT);
++              break;
++      default:
++              eprintk("Unknown type %u\n", iu->srp.rsp.opcode);
++      }
++
++      return 1;
++}
++
++static int process_srp_iu(struct iu_entry *iue)
++{
++      union viosrp_iu *iu = vio_iu(iue);
++      int done = 1;
++      u8 opcode = iu->srp.rsp.opcode;
++
++      switch (opcode) {
++      case SRP_LOGIN_REQ:
++              process_login(iue);
++              break;
++      case SRP_TSK_MGMT:
++              done = process_tsk_mgmt(iue);
++              break;
++      case SRP_CMD:
++              queue_cmd(iue);
++              done = 0;
++              break;
++      case SRP_LOGIN_RSP:
++      case SRP_I_LOGOUT:
++      case SRP_T_LOGOUT:
++      case SRP_RSP:
++      case SRP_CRED_REQ:
++      case SRP_CRED_RSP:
++      case SRP_AER_REQ:
++      case SRP_AER_RSP:
++              eprintk("Unsupported type %u\n", opcode);
++              break;
++      default:
++              eprintk("Unknown type %u\n", opcode);
++      }
++
++      return done;
++}
++
++static void process_iu(struct viosrp_crq *crq, struct srp_target *target)
++{
++      struct vio_port *vport = target_to_port(target);
++      struct iu_entry *iue;
++      long err, done;
++
++      iue = srp_iu_get(target);
++      if (!iue) {
++              eprintk("Error getting IU from pool, %p\n", target);
++              return;
++      }
++
++      iue->remote_token = crq->IU_data_ptr;
++
++      err = h_copy_rdma(crq->IU_length, vport->riobn,
++                        iue->remote_token, vport->liobn, iue->sbuf->dma);
++
++      if (err != H_SUCCESS)
++              eprintk("%ld transferring data error %p\n", err, iue);
++
++      if (crq->format == VIOSRP_MAD_FORMAT)
++              done = process_mad_iu(iue);
++      else
++              done = process_srp_iu(iue);
++
++      if (done)
++              srp_iu_put(iue);
++}
++
++static irqreturn_t ibmvstgt_interrupt(int irq, void *data, struct pt_regs 
*regs)
++{
++      struct srp_target *target = (struct srp_target *) data;
++      struct vio_port *vport = target_to_port(target);
++
++      vio_disable_interrupts(vport->dma_dev);
++      queue_work(vtgtd, &vport->crq_work);
++
++      return IRQ_HANDLED;
++}
++
++static int crq_queue_create(struct crq_queue *queue, struct srp_target 
*target)
++{
++      int err;
++      struct vio_port *vport = target_to_port(target);
++
++      queue->msgs = (struct viosrp_crq *) get_zeroed_page(GFP_KERNEL);
++      if (!queue->msgs)
++              goto malloc_failed;
++      queue->size = PAGE_SIZE / sizeof(*queue->msgs);
++
++      queue->msg_token = dma_map_single(target->dev, queue->msgs,
++                                        queue->size * sizeof(*queue->msgs),
++                                        DMA_BIDIRECTIONAL);
++
++      if (dma_mapping_error(queue->msg_token))
++              goto map_failed;
++
++      err = h_reg_crq(vport->dma_dev->unit_address, queue->msg_token,
++                      PAGE_SIZE);
++
++      /* If the adapter was left active for some reason (like kexec)
++       * try freeing and re-registering
++       */
++      if (err == H_RESOURCE) {
++          do {
++              err = h_free_crq(vport->dma_dev->unit_address);
++          } while (err == H_BUSY || H_IS_LONG_BUSY(err));
++
++          err = h_reg_crq(vport->dma_dev->unit_address, queue->msg_token,
++                          PAGE_SIZE);
++      }
++
++      if (err != H_SUCCESS && err != 2) {
++              eprintk("Error 0x%x opening virtual adapter\n", err);
++              goto reg_crq_failed;
++      }
++
++      err = request_irq(vport->dma_dev->irq, &ibmvstgt_interrupt,
++                        SA_INTERRUPT, "ibmvstgt", target);
++      if (err)
++              goto req_irq_failed;
++
++      vio_enable_interrupts(vport->dma_dev);
++
++      h_send_crq(vport->dma_dev->unit_address, 0xC001000000000000, 0);
++
++      queue->cur = 0;
++      spin_lock_init(&queue->lock);
++
++      return 0;
++
++req_irq_failed:
++      do {
++              err = h_free_crq(vport->dma_dev->unit_address);
++      } while (err == H_BUSY || H_IS_LONG_BUSY(err));
++
++reg_crq_failed:
++      dma_unmap_single(target->dev, queue->msg_token,
++                       queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
++map_failed:
++      free_page((unsigned long) queue->msgs);
++
++malloc_failed:
++      return -ENOMEM;
++}
++
++static void crq_queue_destroy(struct srp_target *target)
++{
++      struct vio_port *vport = target_to_port(target);
++      struct crq_queue *queue = &vport->crq_queue;
++      int err;
++
++      free_irq(vport->dma_dev->irq, target);
++      do {
++              err = h_free_crq(vport->dma_dev->unit_address);
++      } while (err == H_BUSY || H_IS_LONG_BUSY(err));
++
++      dma_unmap_single(target->dev, queue->msg_token,
++                       queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
++
++      free_page((unsigned long) queue->msgs);
++}
++
++static void process_crq(struct viosrp_crq *crq,       struct srp_target 
*target)
++{
++      struct vio_port *vport = target_to_port(target);
++      dprintk("%x %x\n", crq->valid, crq->format);
++
++      switch (crq->valid) {
++      case 0xC0:
++              /* initialization */
++              switch (crq->format) {
++              case 0x01:
++                      h_send_crq(vport->dma_dev->unit_address,
++                                 0xC002000000000000, 0);
++                      break;
++              case 0x02:
++                      break;
++              default:
++                      eprintk("Unknown format %u\n", crq->format);
++              }
++              break;
++      case 0xFF:
++              /* transport event */
++              break;
++      case 0x80:
++              /* real payload */
++              switch (crq->format) {
++              case VIOSRP_SRP_FORMAT:
++              case VIOSRP_MAD_FORMAT:
++                      process_iu(crq, target);
++                      break;
++              case VIOSRP_OS400_FORMAT:
++              case VIOSRP_AIX_FORMAT:
++              case VIOSRP_LINUX_FORMAT:
++              case VIOSRP_INLINE_FORMAT:
++                      eprintk("Unsupported format %u\n", crq->format);
++                      break;
++              default:
++                      eprintk("Unknown format %u\n", crq->format);
++              }
++              break;
++      default:
++              eprintk("unknown message type 0x%02x!?\n", crq->valid);
++      }
++}
++
++static inline struct viosrp_crq *next_crq(struct crq_queue *queue)
++{
++      struct viosrp_crq *crq;
++      unsigned long flags;
++
++      spin_lock_irqsave(&queue->lock, flags);
++      crq = &queue->msgs[queue->cur];
++      if (crq->valid & 0x80) {
++              if (++queue->cur == queue->size)
++                      queue->cur = 0;
++      } else
++              crq = NULL;
++      spin_unlock_irqrestore(&queue->lock, flags);
++
++      return crq;
++}
++
++static void handle_crq(void *data)
++{
++      struct srp_target *target = (struct srp_target *) data;
++      struct vio_port *vport = target_to_port(target);
++      struct viosrp_crq *crq;
++      int done = 0;
++
++      while (!done) {
++              while ((crq = next_crq(&vport->crq_queue)) != NULL) {
++                      process_crq(crq, target);
++                      crq->valid = 0x00;
++              }
++
++              vio_enable_interrupts(vport->dma_dev);
++
++              crq = next_crq(&vport->crq_queue);
++              if (crq) {
++                      vio_disable_interrupts(vport->dma_dev);
++                      process_crq(crq, target);
++                      crq->valid = 0x00;
++              } else
++                      done = 1;
++      }
++
++      handle_cmd_queue(target);
++}
++
++
++static int ibmvstgt_eh_abort_handler(struct scsi_cmnd *scmd)
++{
++      unsigned long flags;
++      struct iu_entry *iue = (struct iu_entry *) scmd->SCp.ptr;
++      struct srp_target *target = iue->target;
++
++      dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]);
++
++      spin_lock_irqsave(&target->lock, flags);
++      list_del(&iue->ilist);
++      spin_unlock_irqrestore(&target->lock, flags);
++
++      srp_iu_put(iue);
++
++      return 0;
++}
++
++static int ibmvstgt_tsk_mgmt_response(u64 mid, int result)
++{
++      struct iu_entry *iue = (struct iu_entry *) ((void *) mid);
++      union viosrp_iu *iu = vio_iu(iue);
++      unsigned char status, asc;
++
++      eprintk("%p %d\n", iue, result);
++      status = NO_SENSE;
++      asc = 0;
++
++      switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
++      case SRP_TSK_ABORT_TASK:
++              asc = 0x14;
++              if (result)
++                      status = ABORTED_COMMAND;
++              break;
++      default:
++              break;
++      }
++
++      send_rsp(iue, status, asc);
++      srp_iu_put(iue);
++
++      return 0;
++}
++
++static ssize_t system_id_show(struct class_device *cdev, char *buf)
++{
++      return snprintf(buf, PAGE_SIZE, "%s\n", system_id);
++}
++
++static ssize_t partition_number_show(struct class_device *cdev, char *buf)
++{
++      return snprintf(buf, PAGE_SIZE, "%x\n", partition_number);
++}
++
++static ssize_t unit_address_show(struct class_device *cdev, char *buf)
++{
++      struct Scsi_Host *shost = class_to_shost(cdev);
++      struct srp_target *target = host_to_target(shost);
++      struct vio_port *vport = target_to_port(target);
++      return snprintf(buf, PAGE_SIZE, "%x\n", vport->dma_dev->unit_address);
++}
++
++static CLASS_DEVICE_ATTR(system_id, S_IRUGO, system_id_show, NULL);
++static CLASS_DEVICE_ATTR(partition_number, S_IRUGO, partition_number_show, 
NULL);
++static CLASS_DEVICE_ATTR(unit_address, S_IRUGO, unit_address_show, NULL);
++
++static struct class_device_attribute *ibmvstgt_attrs[] = {
++      &class_device_attr_system_id,
++      &class_device_attr_partition_number,
++      &class_device_attr_unit_address,
++      NULL,
++};
++
++static struct scsi_host_template ibmvstgt_sht = {
++      .name                   = TGT_NAME,
++      .module                 = THIS_MODULE,
++      .can_queue              = INITIAL_SRP_LIMIT,
++      .sg_tablesize           = SG_ALL,
++      .use_clustering         = DISABLE_CLUSTERING,
++      .max_sectors            = DEFAULT_MAX_SECTORS,
++      .transfer_response      = ibmvstgt_cmd_done,
++      .transfer_data          = ibmvstgt_transfer_data,
++      .eh_abort_handler       = ibmvstgt_eh_abort_handler,
++      .tsk_mgmt_response      = ibmvstgt_tsk_mgmt_response,
++      .shost_attrs            = ibmvstgt_attrs,
++      .proc_name              = TGT_NAME,
++};
++
++static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
++{
++      struct Scsi_Host *shost;
++      struct srp_target *target;
++      struct vio_port *vport;
++      unsigned int *dma, dma_size;
++      int err = -ENOMEM;
++
++      vport = kzalloc(sizeof(struct vio_port), GFP_KERNEL);
++      if (!vport)
++              return err;
++      shost = scsi_host_alloc(&ibmvstgt_sht, sizeof(struct srp_target));
++      if (!shost)
++              goto free_vport;
++      err = scsi_tgt_alloc_queue(shost);
++      if (err)
++              goto put_host;
++
++      target = host_to_target(shost);
++      target->shost = shost;
++      vport->dma_dev = dev;
++      target->ldata = vport;
++      err = srp_target_alloc(target, &dev->dev, INITIAL_SRP_LIMIT,
++                             SRP_MAX_IU_LEN);
++      if (err)
++              goto put_host;
++
++      dma = (unsigned int *) vio_get_attribute(dev, "ibm,my-dma-window",
++                                               &dma_size);
++      if (!dma || dma_size != 40) {
++              eprintk("Couldn't get window property %d\n", dma_size);
++              err = -EIO;
++              goto free_srp_target;
++      }
++      vport->liobn = dma[0];
++      vport->riobn = dma[5];
++
++      INIT_WORK(&vport->crq_work, handle_crq, target);
++
++      err = crq_queue_create(&vport->crq_queue, target);
++      if (err)
++              goto free_srp_target;
++
++      err = scsi_add_host(shost, target->dev);
++      if (err)
++              goto destroy_queue;
++      return 0;
++
++destroy_queue:
++      crq_queue_destroy(target);
++free_srp_target:
++      srp_target_free(target);
++put_host:
++      scsi_host_put(shost);
++free_vport:
++      kfree(vport);
++      return err;
++}
++
++static int ibmvstgt_remove(struct vio_dev *dev)
++{
++      struct srp_target *target = (struct srp_target *) dev->dev.driver_data;
++      struct Scsi_Host *shost = target->shost;
++
++      srp_target_free(target);
++      crq_queue_destroy(target);
++      scsi_remove_host(shost);
++      scsi_host_put(shost);
++      return 0;
++}
++
++static struct vio_device_id ibmvstgt_device_table[] __devinitdata = {
++      {"v-scsi-host", "IBM,v-scsi-host"},
++      {"",""}
++};
++
++MODULE_DEVICE_TABLE(vio, ibmvstgt_device_table);
++
++static struct vio_driver ibmvstgt_driver = {
++      .id_table = ibmvstgt_device_table,
++      .probe = ibmvstgt_probe,
++      .remove = ibmvstgt_remove,
++      .driver = {
++              .name = "ibmvscsi",
++              .owner = THIS_MODULE,
++      }
++};
++
++static int get_system_info(void)
++{
++      struct device_node *rootdn;
++      char *id, *model, *name;
++      unsigned int *num;
++
++      rootdn = find_path_device("/");
++      if (!rootdn)
++              return -ENOENT;
++
++      model = get_property(rootdn, "model", NULL);
++      id = get_property(rootdn, "system-id", NULL);
++      if (model && id)
++              snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
++
++      name = get_property(rootdn, "ibm,partition-name", NULL);
++      if (name)
++              strncpy(partition_name, name, sizeof(partition_name));
++
++      num = (unsigned int *) get_property(rootdn, "ibm,partition-no", NULL);
++      if (num)
++              partition_number = *num;
++
++      return 0;
++}
++
++static int ibmvstgt_init(void)
++{
++      int err = -ENOMEM;
++
++      printk("IBM eServer i/pSeries Virtual SCSI Target Driver\n");
++
++      vtgtd = create_workqueue("ibmvtgtd");
++      if (!vtgtd)
++              return err;
++
++      err = get_system_info();
++      if (err)
++              goto destroy_wq;
++
++      err = vio_register_driver(&ibmvstgt_driver);
++      if (err)
++              goto destroy_wq;
++
++      return 0;
++
++destroy_wq:
++      destroy_workqueue(vtgtd);
++      return err;
++}
++
++static void ibmvstgt_exit(void)
++{
++      printk("Unregister IBM virtual SCSI driver\n");
++
++      destroy_workqueue(vtgtd);
++      vio_unregister_driver(&ibmvstgt_driver);
++}
++
++MODULE_DESCRIPTION("IBM Virtual SCSI Target");
++MODULE_AUTHOR("Dave Boutcher");
++MODULE_LICENSE("GPL");
++
++module_init(ibmvstgt_init);
++module_exit(ibmvstgt_exit);
+diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
+new file mode 100644
+index 0000000..36b5b39
+--- /dev/null
++++ b/drivers/scsi/libsrp.c
+@@ -0,0 +1,450 @@
++/*
++ * SCSI RDAM Protocol lib functions
++ *
++ * 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/err.h>
++#include <linux/kfifo.h>
++#include <linux/scatterlist.h>
++#include <linux/dma-mapping.h>
++#include <linux/pci.h>
++#include <scsi/scsi.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_tcq.h>
++#include <scsi/scsi_tgt.h>
++#include <scsi/srp.h>
++#include <scsi/libsrp.h>
++
++enum srp_task_attributes {
++      SRP_SIMPLE_TASK = 0,
++      SRP_HEAD_TASK = 1,
++      SRP_ORDERED_TASK = 2,
++      SRP_ACA_TASK = 4
++};
++
++/* tmp - will replace with SCSI logging stuff */
++#define eprintk(fmt, args...)                                 \
++do {                                                          \
++      printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);  \
++} while (0)
++/* #define dprintk eprintk */
++#define dprintk(fmt, args...)
++
++static int srp_iu_pool_alloc(struct srp_queue *q, size_t max,
++                           struct srp_buf **ring)
++{
++      int i;
++      struct iu_entry *iue;
++
++      q->pool = kcalloc(max, sizeof(struct iu_entry *), GFP_KERNEL);
++      if (!q->pool)
++              return -ENOMEM;
++      q->items = kcalloc(max, sizeof(struct iu_entry), GFP_KERNEL);
++      if (!q->items)
++              goto free_pool;
++
++      spin_lock_init(&q->lock);
++      q->queue = kfifo_init((void *) q->pool, max * sizeof(void *),
++                            GFP_KERNEL, &q->lock);
++      if (IS_ERR(q->queue))
++              goto free_item;
++
++      for (i = 0, iue = q->items; i < max; i++) {
++              __kfifo_put(q->queue, (void *) &iue, sizeof(void *));
++              iue->sbuf = ring[i];
++              iue++;
++      }
++      return 0;
++
++free_item:
++      kfree(q->items);
++free_pool:
++      kfree(q->pool);
++      return -ENOMEM;
++}
++
++static void srp_iu_pool_free(struct srp_queue *q)
++{
++      kfree(q->items);
++      kfree(q->pool);
++}
++
++static struct srp_buf ** srp_ring_alloc(struct device *dev,
++                                      size_t max, size_t size)
++{
++      int i;
++      struct srp_buf **ring;
++
++      ring = kcalloc(max, sizeof(struct srp_buf *), GFP_KERNEL);
++      if (!ring)
++              return NULL;
++
++      for (i = 0; i < max; i++) {
++              ring[i] = kzalloc(sizeof(struct srp_buf), GFP_KERNEL);
++              if (!ring[i])
++                      goto out;
++              ring[i]->buf = dma_alloc_coherent(dev, size, &ring[i]->dma,
++                                                GFP_KERNEL);
++              if (!ring[i]->buf)
++                      goto out;
++      }
++      return ring;
++
++out:
++      for (i = 0; i < max && ring[i]; i++) {
++              if (ring[i]->buf)
++                      dma_free_coherent(dev, size, ring[i]->buf, 
ring[i]->dma);
++              kfree(ring[i]);
++      }
++      kfree(ring);
++
++      return NULL;
++}
++
++static void srp_ring_free(struct device *dev, struct srp_buf **ring, size_t 
max,
++                        size_t size)
++{
++      int i;
++
++      for (i = 0; i < max; i++) {
++              dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
++              kfree(ring[i]);
++      }
++}
++
++int srp_target_alloc(struct srp_target *target, struct device *dev,
++                   size_t nr, size_t iu_size)
++{
++      int err;
++
++      spin_lock_init(&target->lock);
++      INIT_LIST_HEAD(&target->cmd_queue);
++
++      target->dev = dev;
++      target->dev->driver_data = target;
++
++      target->srp_iu_size = iu_size;
++      target->rx_ring_size = nr;
++      target->rx_ring = srp_ring_alloc(target->dev, nr, iu_size);
++      if (!target->rx_ring)
++              return -ENOMEM;
++      err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring);
++      if (err)
++              goto free_ring;
++
++      return 0;
++
++free_ring:
++      srp_ring_free(target->dev, target->rx_ring, nr, iu_size);
++      return -ENOMEM;
++}
++EXPORT_SYMBOL_GPL(srp_target_alloc);
++
++void srp_target_free(struct srp_target *target)
++{
++      srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size,
++                    target->srp_iu_size);
++      srp_iu_pool_free(&target->iu_queue);
++}
++EXPORT_SYMBOL_GPL(srp_target_free);
++
++struct iu_entry *srp_iu_get(struct srp_target *target)
++{
++      struct iu_entry *iue = NULL;
++
++      kfifo_get(target->iu_queue.queue, (void *) &iue, sizeof(void *));
++      BUG_ON(!iue);
++
++      iue->target = target;
++      iue->scmd = NULL;
++      INIT_LIST_HEAD(&iue->ilist);
++      iue->flags = 0;
++      return iue;
++}
++EXPORT_SYMBOL_GPL(srp_iu_get);
++
++void srp_iu_put(struct iu_entry *iue)
++{
++      kfifo_put(iue->target->iu_queue.queue, (void *) &iue, sizeof(void *));
++}
++EXPORT_SYMBOL_GPL(srp_iu_put);
++
++static int direct_data(struct scsi_cmnd *scmd, struct srp_direct_buf *md,
++                     enum dma_data_direction dir, rdma_io_t rdma_io)
++{
++      struct iu_entry *iue = (struct iu_entry *) scmd->SCp.ptr;
++      struct srp_target *target = iue->target;
++      struct scatterlist *sg = scmd->request_buffer;
++      int nsg, err;
++
++      dprintk("%p %u %u %u %d\n", iue, scmd->request_bufflen, scmd->bufflen,
++              md->len, scmd->use_sg);
++
++      nsg = dma_map_sg(target->dev, sg, scmd->use_sg, DMA_BIDIRECTIONAL);
++      if (!nsg) {
++              printk("fail to map %p %d\n", iue, scmd->use_sg);
++              return 0;
++      }
++      err = rdma_io(iue, sg, nsg, md, 1, dir,
++                    min(scmd->request_bufflen, md->len));
++
++      dma_unmap_sg(target->dev, sg, nsg, DMA_BIDIRECTIONAL);
++
++      return err;
++}
++
++static int indirect_data(struct scsi_cmnd *scmd, struct srp_cmd *cmd,
++                       struct srp_indirect_buf *id,
++                       enum dma_data_direction dir, rdma_io_t rdma_io)
++{
++      struct iu_entry *iue = (struct iu_entry *) scmd->SCp.ptr;
++      struct srp_target *target = iue->target;
++      struct srp_direct_buf *md;
++      struct scatterlist dummy, *sg = scmd->request_buffer;
++      dma_addr_t token = 0;
++      long err;
++      unsigned int done = 0;
++      int nmd, nsg;
++
++      nmd = id->table_desc.len / sizeof(struct srp_direct_buf);
++
++      dprintk("%p %u %u %u %u %d %d %d\n",
++              iue, scmd->request_bufflen, scmd->bufflen,
++              id->len, scmd->offset, nmd,
++              cmd->data_in_desc_cnt, cmd->data_out_desc_cnt);
++
++      if ((dir == DMA_FROM_DEVICE && nmd == cmd->data_in_desc_cnt) ||
++          (dir == DMA_TO_DEVICE && nmd == cmd->data_out_desc_cnt)) {
++              md = &id->desc_list[0];
++              goto rdma;
++      }
++
++      md = dma_alloc_coherent(target->dev, id->table_desc.len,
++                               &token, GFP_KERNEL);
++      if (!md) {
++              eprintk("Can't get dma memory %u\n", id->table_desc.len);
++              return 0;
++      }
++
++      sg_init_one(&dummy, md, id->table_desc.len);
++      sg_dma_address(&dummy) = token;
++      err = rdma_io(iue, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
++                    id->table_desc.len);
++      if (err < 0) {
++              eprintk("Error copying indirect table %ld\n", err);
++              goto free_mem;
++      }
++
++rdma:
++      nsg = dma_map_sg(target->dev, sg, scmd->use_sg, DMA_BIDIRECTIONAL);
++      if (!nsg) {
++              eprintk("fail to map %p %d\n", iue, scmd->use_sg);
++              goto free_mem;
++      }
++
++      err = rdma_io(iue, sg, nsg, md, nmd, dir,
++                    min(scmd->request_bufflen, id->len));
++      dma_unmap_sg(target->dev, sg, nsg, DMA_BIDIRECTIONAL);
++
++free_mem:
++      if (token)
++              dma_free_coherent(target->dev, id->table_desc.len, md, token);
++
++      return done;
++}
++
++static int data_out_desc_size(struct srp_cmd *cmd)
++{
++      int size = 0;
++      u8 fmt = cmd->buf_fmt >> 4;
++
++      switch (fmt) {
++      case SRP_NO_DATA_DESC:
++              break;
++      case SRP_DATA_DESC_DIRECT:
++              size = sizeof(struct srp_direct_buf);
++              break;
++      case SRP_DATA_DESC_INDIRECT:
++              size = sizeof(struct srp_indirect_buf) +
++                      sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt;
++              break;
++      default:
++              eprintk("client error. Invalid data_out_format %x\n", fmt);
++              break;
++      }
++      return size;
++}
++
++static int __srp_transfer_data(struct scsi_cmnd *scmd, struct srp_cmd *cmd,
++                             enum dma_data_direction dir, rdma_io_t rdma_io)
++{
++      struct srp_direct_buf *md;
++      struct srp_indirect_buf *id;
++      int offset, err = 0;
++      u8 format;
++
++      offset = cmd->add_cdb_len * 4;
++      if (dir == DMA_FROM_DEVICE)
++              offset += data_out_desc_size(cmd);
++
++      if (dir == DMA_TO_DEVICE)
++              format = cmd->buf_fmt >> 4;
++      else
++              format = cmd->buf_fmt & ((1U << 4) - 1);
++
++      switch (format) {
++      case SRP_NO_DATA_DESC:
++              break;
++      case SRP_DATA_DESC_DIRECT:
++              md = (struct srp_direct_buf *)
++                      (cmd->add_data + offset);
++              err = direct_data(scmd, md, dir, rdma_io);
++              break;
++      case SRP_DATA_DESC_INDIRECT:
++              id = (struct srp_indirect_buf *)
++                      (cmd->add_data + offset);
++              err = indirect_data(scmd, cmd, id, dir, rdma_io);
++              break;
++      default:
++              eprintk("Unknown format %d %x\n", dir, format);
++              break;
++      }
++
++      return err;
++}
++
++/* TODO: this can be called multiple times for a single command. */
++int srp_transfer_data(struct scsi_cmnd *scmd, struct srp_cmd *cmd,
++                    rdma_io_t rdma_io)
++{
++      struct iu_entry *iue = (struct iu_entry *) scmd->SCp.ptr;
++      enum dma_data_direction dir;
++
++      if (test_bit(V_WRITE, &iue->flags))
++              dir = DMA_TO_DEVICE;
++      else
++              dir = DMA_FROM_DEVICE;
++      __srp_transfer_data(scmd, cmd, dir, rdma_io);
++      return 0;
++}
++EXPORT_SYMBOL_GPL(srp_transfer_data);
++
++static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction 
dir)
++{
++      struct srp_direct_buf *md;
++      struct srp_indirect_buf *id;
++      int len = 0, offset = cmd->add_cdb_len * 4;
++      u8 fmt;
++
++      if (dir == DMA_TO_DEVICE)
++              fmt = cmd->buf_fmt >> 4;
++      else {
++              fmt = cmd->buf_fmt & ((1U << 4) - 1);
++              offset += data_out_desc_size(cmd);
++      }
++
++      switch (fmt) {
++      case SRP_NO_DATA_DESC:
++              break;
++      case SRP_DATA_DESC_DIRECT:
++              md = (struct srp_direct_buf *) (cmd->add_data + offset);
++              len = md->len;
++              break;
++      case SRP_DATA_DESC_INDIRECT:
++              id = (struct srp_indirect_buf *) (cmd->add_data + offset);
++              len = id->len;
++              break;
++      default:
++              eprintk("invalid data format %x\n", fmt);
++              break;
++      }
++      return len;
++}
++
++static uint8_t getcontrolbyte(u8 *cdb)
++{
++      return cdb[COMMAND_SIZE(cdb[0]) - 1];
++}
++
++static inline uint8_t getlink(struct srp_cmd *cmd)
++{
++      return (getcontrolbyte(cmd->cdb) & 0x01);
++}
++
++int srp_cmd_perform(struct iu_entry *iue, struct srp_cmd *cmd)
++{
++      struct Scsi_Host *shost = iue->target->shost;
++      enum dma_data_direction data_dir;
++      struct scsi_cmnd *scmd;
++      int tag, len;
++
++      if (getlink(cmd))
++              __set_bit(V_LINKED, &iue->flags);
++
++      tag = MSG_SIMPLE_TAG;
++
++      switch (cmd->task_attr) {
++      case SRP_SIMPLE_TASK:
++              tag = MSG_SIMPLE_TAG;
++              break;
++      case SRP_ORDERED_TASK:
++              tag = MSG_ORDERED_TAG;
++              break;
++      case SRP_HEAD_TASK:
++              tag = MSG_HEAD_TAG;
++              break;
++      default:
++              eprintk("Task attribute %d not supported\n", cmd->task_attr);
++              tag = MSG_ORDERED_TAG;
++      }
++
++      switch (cmd->cdb[0]) {
++      case WRITE_6:
++      case WRITE_10:
++      case WRITE_VERIFY:
++      case WRITE_12:
++      case WRITE_VERIFY_12:
++              __set_bit(V_WRITE, &iue->flags);
++      }
++
++      if (cmd->buf_fmt >> 4)
++              data_dir = DMA_TO_DEVICE;
++      else
++              data_dir = DMA_FROM_DEVICE;
++      len = vscsis_data_length(cmd, data_dir);
++
++      dprintk("%p %x %lx %d %d %d %llx\n", iue, cmd->cdb[0],
++              cmd->lun, data_dir, len, tag, (unsigned long long) cmd->tag);
++
++      scmd = scsi_host_get_command(shost, data_dir, GFP_KERNEL);
++      BUG_ON(!scmd);
++      scmd->SCp.ptr = (char *) iue;
++      memcpy(scmd->cmnd, cmd->cdb, MAX_COMMAND_SIZE);
++      scmd->request_buffer = 0;
++      scmd->request_bufflen = len;
++      scmd->tag = tag;
++      iue->scmd = scmd;
++      scsi_tgt_queue_command(scmd, (struct scsi_lun *) &cmd->lun, cmd->tag);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(srp_cmd_perform);
++
++MODULE_DESCRIPTION("SCSI RDAM Protocol lib functions");
++MODULE_AUTHOR("FUJITA Tomonori");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
+index 73994e2..0591b93 100644
+--- a/drivers/scsi/scsi.c
++++ b/drivers/scsi/scsi.c
+@@ -210,8 +210,7 @@ static struct scsi_host_cmd_pool scsi_cm
+ 
+ static DEFINE_MUTEX(host_cmd_pool_mutex);
+ 
+-static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost,
+-                                          gfp_t gfp_mask)
++struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
+ {
+       struct scsi_cmnd *cmd;
+ 
+@@ -232,6 +231,7 @@ static struct scsi_cmnd *__scsi_get_comm
+ 
+       return cmd;
+ }
++EXPORT_SYMBOL_GPL(__scsi_get_command);
+ 
+ /*
+  * Function:  scsi_get_command()
+@@ -268,9 +268,29 @@ struct scsi_cmnd *scsi_get_command(struc
+               put_device(&dev->sdev_gendev);
+ 
+       return cmd;
+-}                             
++}
+ EXPORT_SYMBOL(scsi_get_command);
+ 
++void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
++                      struct device *dev)
++{
++      unsigned long flags;
++
++      /* changing locks here, don't need to restore the irq state */
++      spin_lock_irqsave(&shost->free_list_lock, flags);
++      if (unlikely(list_empty(&shost->free_list))) {
++              list_add(&cmd->list, &shost->free_list);
++              cmd = NULL;
++      }
++      spin_unlock_irqrestore(&shost->free_list_lock, flags);
++
++      if (likely(cmd != NULL))
++              kmem_cache_free(shost->cmd_pool->slab, cmd);
++
++      put_device(dev);
++}
++EXPORT_SYMBOL(__scsi_put_command);
++
+ /*
+  * Function:  scsi_put_command()
+  *
+@@ -285,26 +305,15 @@ EXPORT_SYMBOL(scsi_get_command);
+ void scsi_put_command(struct scsi_cmnd *cmd)
+ {
+       struct scsi_device *sdev = cmd->device;
+-      struct Scsi_Host *shost = sdev->host;
+       unsigned long flags;
+-      
++
+       /* serious error if the command hasn't come from a device list */
+       spin_lock_irqsave(&cmd->device->list_lock, flags);
+       BUG_ON(list_empty(&cmd->list));
+       list_del_init(&cmd->list);
+-      spin_unlock(&cmd->device->list_lock);
+-      /* changing locks here, don't need to restore the irq state */
+-      spin_lock(&shost->free_list_lock);
+-      if (unlikely(list_empty(&shost->free_list))) {
+-              list_add(&cmd->list, &shost->free_list);
+-              cmd = NULL;
+-      }
+-      spin_unlock_irqrestore(&shost->free_list_lock, flags);
++      spin_unlock_irqrestore(&cmd->device->list_lock, flags);
+ 
+-      if (likely(cmd != NULL))
+-              kmem_cache_free(shost->cmd_pool->slab, cmd);
+-
+-      put_device(&sdev->sdev_gendev);
++      __scsi_put_command(cmd->device->host, cmd, &sdev->sdev_gendev);
+ }
+ EXPORT_SYMBOL(scsi_put_command);
+ 
+diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
+index faee475..f8ac3d5 100644
+--- a/drivers/scsi/scsi_lib.c
++++ b/drivers/scsi/scsi_lib.c
+@@ -803,7 +803,7 @@ static struct scsi_cmnd *scsi_end_reques
+       return NULL;
+ }
+ 
+-static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t 
gfp_mask)
++struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+ {
+       struct scsi_host_sg_pool *sgp;
+       struct scatterlist *sgl;
+@@ -844,7 +844,9 @@ static struct scatterlist *scsi_alloc_sg
+       return sgl;
+ }
+ 
+-static void scsi_free_sgtable(struct scatterlist *sgl, int index)
++EXPORT_SYMBOL(scsi_alloc_sgtable);
++
++void scsi_free_sgtable(struct scatterlist *sgl, int index)
+ {
+       struct scsi_host_sg_pool *sgp;
+ 
+@@ -854,6 +856,8 @@ static void scsi_free_sgtable(struct sca
+       mempool_free(sgl, sgp->pool);
+ }
+ 
++EXPORT_SYMBOL(scsi_free_sgtable);
++
+ /*
+  * Function:    scsi_release_buffers()
+  *
+@@ -1714,29 +1718,40 @@ u64 scsi_calculate_bounce_limit(struct S
+ }
+ EXPORT_SYMBOL(scsi_calculate_bounce_limit);
+ 
+-struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
++struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
++                                       request_fn_proc *request_fn)
+ {
+-      struct Scsi_Host *shost = sdev->host;
+       struct request_queue *q;
+ 
+-      q = blk_init_queue(scsi_request_fn, NULL);
++      q = blk_init_queue(request_fn, NULL);
+       if (!q)
+               return NULL;
+ 
+-      blk_queue_prep_rq(q, scsi_prep_fn);
+-
+       blk_queue_max_hw_segments(q, shost->sg_tablesize);
+       blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS);
+       blk_queue_max_sectors(q, shost->max_sectors);
+       blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
+       blk_queue_segment_boundary(q, shost->dma_boundary);
+-      blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
+-      blk_queue_softirq_done(q, scsi_softirq_done);
+ 
+       if (!shost->use_clustering)
+               clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+       return q;
+ }
++EXPORT_SYMBOL(__scsi_alloc_queue);
++
++struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
++{
++      struct request_queue *q;
++
++      q = __scsi_alloc_queue(sdev->host, scsi_request_fn);
++      if (!q)
++              return NULL;
++
++      blk_queue_prep_rq(q, scsi_prep_fn);
++      blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
++      blk_queue_softirq_done(q, scsi_softirq_done);
++      return q;
++}
+ 
+ void scsi_free_queue(struct request_queue *q)
+ {
+diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
+new file mode 100644
+index 0000000..c9d15a7
+--- /dev/null
++++ b/drivers/scsi/scsi_tgt_if.c
+@@ -0,0 +1,316 @@
++/*
++ * SCSI target kernel/user interface 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 <linux/blkdev.h>
++#include <linux/file.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"
++
++struct rbuf {
++      u32 idx;
++      u32 nr_entry;
++      int entry_size;
++      char *buf;
++      int buf_size;
++      spinlock_t lock;
++};
++
++static int chrdev;
++static struct rbuf txbuf, rxbuf;
++static DECLARE_WAIT_QUEUE_HEAD(tgt_poll_wait);
++
++static inline struct rbuf_hdr *head_rbuf_hdr(struct rbuf *rbuf, u32 idx)
++{
++      u32 offset = (idx & (rbuf->nr_entry - 1)) * rbuf->entry_size;
++      return (struct rbuf_hdr *) (rbuf->buf + offset);
++}
++
++static void rbuf_init(struct rbuf *rbuf, char *buf, int bsize, int esize)
++{
++      int i;
++
++      esize += sizeof(struct rbuf_hdr);
++      rbuf->idx = 0;
++      rbuf->entry_size = esize;
++      rbuf->buf = buf;
++      spin_lock_init(&rbuf->lock);
++
++      bsize /= esize;
++      for (i = 0; (1 << i) < bsize && (1 << (i + 1)) <= bsize; i++)
++              ;
++      rbuf->nr_entry = 1 << i;
++}
++
++static int send_event_rsp(u32 type, struct tgt_event *p)
++{
++      struct tgt_event *ev;
++      struct rbuf_hdr *hdr;
++      struct page *sp, *ep;
++      unsigned long flags;
++      int err = 0;
++
++      spin_lock_irqsave(&txbuf.lock, flags);
++
++      hdr = head_rbuf_hdr(&txbuf, txbuf.idx);
++      if (hdr->status)
++              err = 1;
++      else
++              txbuf.idx++;
++
++      spin_unlock_irqrestore(&txbuf.lock, flags);
++
++      if (err)
++              return err;
++
++      ev = (struct tgt_event *) hdr->data;
++      memcpy(ev, p, sizeof(*ev));
++      ev->type = type;
++      hdr->status = 1;
++      mb();
++
++      sp = virt_to_page(hdr);
++      ep = virt_to_page((char *) hdr->data + sizeof(*ev));
++      for (;sp <= ep; sp++)
++              flush_dcache_page(sp);
++
++      wake_up_interruptible(&tgt_poll_wait);
++
++      return 0;
++}
++
++int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 
tag)
++{
++      struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
++      struct tgt_event ev;
++      int err;
++
++      memset(&ev, 0, sizeof(ev));
++      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;
++      memcpy(ev.k.cmd_req.scb, cmd->cmnd, sizeof(ev.k.cmd_req.scb));
++      memcpy(ev.k.cmd_req.lun, lun, sizeof(ev.k.cmd_req.lun));
++      ev.k.cmd_req.attribute = cmd->tag;
++      ev.k.cmd_req.tag = tag;
++      ev.k.cmd_req.uaddr = (u64) (unsigned long) cmd->request_buffer;
++
++      dprintk("%p %d %u %u %x %llx\n", cmd, shost->host_no, ev.k.cmd_req.cid,
++              ev.k.cmd_req.data_len, cmd->tag,
++              (unsigned long long) ev.k.cmd_req.tag);
++
++      err = send_event_rsp(TGT_KEVENT_CMD_REQ, &ev);
++      if (err)
++              eprintk("tx buf is full, could not send\n");
++      return err;
++}
++
++int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd)
++{
++      struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
++      struct tgt_event ev;
++      int err;
++
++      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;
++
++      dprintk("%p %d %u %u %x %llx\n", cmd, shost->host_no, ev.k.cmd_req.cid,
++              ev.k.cmd_req.data_len, cmd->tag,
++              (unsigned long long) ev.k.cmd_req.tag);
++
++      err = send_event_rsp(TGT_KEVENT_CMD_DONE, &ev);
++      if (err)
++              eprintk("tx buf is full, could not send\n");
++      return err;
++}
++
++int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
++                                struct scsi_lun *scsilun, void *data)
++{
++      struct tgt_event ev;
++      int err;
++
++      memset(&ev, 0, sizeof(ev));
++      ev.k.tsk_mgmt_req.host_no = host_no;
++      ev.k.tsk_mgmt_req.function = function;
++      ev.k.tsk_mgmt_req.tag = tag;
++      memcpy(ev.k.tsk_mgmt_req.lun, scsilun, sizeof(ev.k.tsk_mgmt_req.lun));
++      ev.k.tsk_mgmt_req.mid = (u64) (unsigned long) data;
++
++      dprintk("%d %x %llx %llx\n", host_no, function, (unsigned long long) 
tag,
++              (unsigned long long) ev.k.tsk_mgmt_req.mid);
++
++      err = send_event_rsp(TGT_KEVENT_TSK_MGMT_REQ, &ev);
++      if (err)
++              eprintk("tx buf is full, could not send\n");
++      return err;
++}
++
++static int event_recv_msg(struct tgt_event *ev)
++{
++      int err = 0;
++
++      switch (ev->type) {
++      case TGT_UEVENT_CMD_RSP:
++              err = scsi_tgt_kspace_exec(ev->u.cmd_rsp.host_no,
++                                         ev->u.cmd_rsp.cid,
++                                         ev->u.cmd_rsp.result,
++                                         ev->u.cmd_rsp.len,
++                                         ev->u.cmd_rsp.uaddr,
++                                         ev->u.cmd_rsp.rw);
++              break;
++      case TGT_UEVENT_TSK_MGMT_RSP:
++              err = scsi_tgt_kspace_tsk_mgmt(ev->u.tsk_mgmt_rsp.host_no,
++                                             ev->u.tsk_mgmt_rsp.mid,
++                                             ev->u.tsk_mgmt_rsp.result);
++              break;
++      default:
++              eprintk("unknown type %d\n", ev->type);
++              err = -EINVAL;
++      }
++
++      return err;
++}
++
++static ssize_t tgt_write(struct file *file, const char __user * buffer,
++                       size_t count, loff_t * ppos)
++{
++      struct rbuf_hdr *hdr;
++      struct tgt_event *ev;
++      struct page *sp, *ep;
++
++retry:
++      hdr = head_rbuf_hdr(&rxbuf, rxbuf.idx);
++
++      sp = virt_to_page(hdr);
++      ep = virt_to_page((char *) hdr->data + sizeof(*ev));
++      for (;sp <= ep; sp++)
++              flush_dcache_page(sp);
++
++      if (!hdr->status)
++              return count;
++
++      rxbuf.idx++;
++      ev = (struct tgt_event *) hdr->data;
++      event_recv_msg(ev);
++      hdr->status = 0;
++
++      goto retry;
++}
++
++static unsigned int tgt_poll(struct file * file, struct poll_table_struct 
*wait)
++{
++      struct rbuf_hdr *hdr;
++      unsigned long flags;
++      unsigned int mask = 0;
++
++      poll_wait(file, &tgt_poll_wait, wait);
++
++      spin_lock_irqsave(&txbuf.lock, flags);
++
++      hdr = head_rbuf_hdr(&txbuf, txbuf.idx - 1);
++      if (hdr->status)
++              mask |= POLLIN | POLLRDNORM;
++
++      spin_unlock_irqrestore(&txbuf.lock, flags);
++
++      return mask;
++}
++
++static int tgt_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++      unsigned long size, addr;
++      struct page *page;
++      int err, i;
++
++      if (vma->vm_pgoff) {
++              eprintk("bug\n");
++              return -EINVAL;
++      }
++
++      size = vma->vm_end - vma->vm_start;
++      if (size != TGT_RINGBUF_SIZE * 2) {
++              eprintk("%lu\n", size);
++              return -EINVAL;
++      }
++      addr = vma->vm_start;
++      page = virt_to_page(txbuf.buf);
++      for (i = 0; i < size >> PAGE_SHIFT; i++) {
++              err = vm_insert_page(vma, addr, page);
++              if (err) {
++                      eprintk("%d %d %lu\n", err, i, addr);
++                      return -EINVAL;
++              }
++              addr += PAGE_SIZE;
++              page++;
++      }
++
++      return 0;
++}
++
++static struct file_operations tgt_fops = {
++      .owner  = THIS_MODULE,
++      .poll   = tgt_poll,
++      .write  = tgt_write,
++      .mmap   = tgt_mmap,
++};
++
++void __exit scsi_tgt_if_exit(void)
++{
++      int order = long_log2(TGT_RINGBUF_SIZE * 2);
++
++      unregister_chrdev(chrdev, "tgt");
++      free_pages((unsigned long) txbuf.buf, order);
++}
++
++int __init scsi_tgt_if_init(void)
++{
++      u32 bsize = TGT_RINGBUF_SIZE;
++      int order;
++      char *buf;
++
++      chrdev = register_chrdev(0, "tgt", &tgt_fops);
++      if (chrdev < 0)
++              return chrdev;
++
++      order = long_log2((bsize * 2) >> PAGE_SHIFT);
++      buf = (char *) __get_free_pages(GFP_KERNEL | __GFP_COMP | __GFP_ZERO,
++                                      order);
++      if (!buf)
++              goto free_dev;
++      rbuf_init(&txbuf, buf, bsize, sizeof(struct tgt_event));
++      rbuf_init(&rxbuf, buf + bsize, bsize, sizeof(struct tgt_event));
++
++      return 0;
++
++free_dev:
++      unregister_chrdev(chrdev, "tgt");
++
++      return -ENOMEM;
++}
+diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
+new file mode 100644
+index 0000000..447bf88
+--- /dev/null
++++ b/drivers/scsi/scsi_tgt_lib.c
+@@ -0,0 +1,707 @@
++/*
++ * SCSI target lib functions
++ *
++ * Copyright (C) 2005 Mike Christie <michaelc@xxxxxxxxxxx>
++ * Copyright (C) 2005 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/blkdev.h>
++#include <linux/hash.h>
++#include <linux/module.h>
++#include <linux/pagemap.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 <../drivers/md/dm-bio-list.h>
++
++#include "scsi_tgt_priv.h"
++
++static struct workqueue_struct *scsi_tgtd;
++static kmem_cache_t *scsi_tgt_cmd_cache;
++
++/*
++ * TODO: this struct will be killed when the block layer supports large bios
++ * and James's work struct code is in
++ */
++struct scsi_tgt_cmd {
++      /* TODO replace work with James b's code */
++      struct work_struct work;
++      /* TODO replace the lists with a large bio */
++      struct bio_list xfer_done_list;
++      struct bio_list xfer_list;
++
++      struct list_head hash_list;
++      struct request *rq;
++
++      void *buffer;
++      unsigned bufflen;
++};
++
++#define TGT_HASH_ORDER        4
++#define cmd_hashfn(cid)       hash_long((cid), TGT_HASH_ORDER)
++
++struct scsi_tgt_queuedata {
++      struct Scsi_Host *shost;
++      struct list_head cmd_hash[1 << TGT_HASH_ORDER];
++      spinlock_t cmd_hash_lock;
++};
++
++/*
++ * Function:  scsi_host_get_command()
++ *
++ * Purpose:   Allocate and setup a scsi command block and blk request
++ *
++ * Arguments: shost   - scsi host
++ *            data_dir - dma data dir
++ *            gfp_mask- allocator flags
++ *
++ * Returns:   The allocated scsi command structure.
++ *
++ * This should be called by target LLDs to get a command.
++ */
++struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
++                                      enum dma_data_direction data_dir,
++                                      gfp_t gfp_mask)
++{
++      int write = (data_dir == DMA_TO_DEVICE);
++      struct request *rq;
++      struct scsi_cmnd *cmd;
++      struct scsi_tgt_cmd *tcmd;
++
++      /* Bail if we can't get a reference to the device */
++      if (!get_device(&shost->shost_gendev))
++              return NULL;
++
++      tcmd = kmem_cache_alloc(scsi_tgt_cmd_cache, GFP_ATOMIC);
++      if (!tcmd)
++              goto put_dev;
++
++      rq = blk_get_request(shost->uspace_req_q, write, gfp_mask);
++      if (!rq)
++              goto free_tcmd;
++
++      cmd = __scsi_get_command(shost, gfp_mask);
++      if (!cmd)
++              goto release_rq;
++
++      memset(cmd, 0, sizeof(*cmd));
++      cmd->sc_data_direction = data_dir;
++      cmd->jiffies_at_alloc = jiffies;
++      cmd->request = rq;
++
++      rq->special = cmd;
++      rq->flags |= REQ_SPECIAL | REQ_BLOCK_PC;
++      rq->end_io_data = tcmd;
++
++      bio_list_init(&tcmd->xfer_list);
++      bio_list_init(&tcmd->xfer_done_list);
++      tcmd->rq = rq;
++
++      return cmd;
++
++release_rq:
++      blk_put_request(rq);
++free_tcmd:
++      kmem_cache_free(scsi_tgt_cmd_cache, tcmd);
++put_dev:
++      put_device(&shost->shost_gendev);
++      return NULL;
++
++}
++EXPORT_SYMBOL_GPL(scsi_host_get_command);
++
++/*
++ * Function:  scsi_host_put_command()
++ *
++ * Purpose:   Free a scsi command block
++ *
++ * Arguments: shost   - scsi host
++ *            cmd     - command block to free
++ *
++ * Returns:   Nothing.
++ *
++ * Notes:     The command must not belong to any lists.
++ */
++static void scsi_host_put_command(struct Scsi_Host *shost,
++                                struct scsi_cmnd *cmd)
++{
++      struct request_queue *q = shost->uspace_req_q;
++      struct request *rq = cmd->request;
++      struct scsi_tgt_cmd *tcmd = rq->end_io_data;
++      unsigned long flags;
++
++      kmem_cache_free(scsi_tgt_cmd_cache, tcmd);
++
++      spin_lock_irqsave(q->queue_lock, flags);
++      __blk_put_request(q, rq);
++      spin_unlock_irqrestore(q->queue_lock, flags);
++
++      __scsi_put_command(shost, cmd, &shost->shost_gendev);
++}
++
++static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd)
++{
++      struct bio *bio;
++
++      /* must call bio_endio in case bio was bounced */
++      while ((bio = bio_list_pop(&tcmd->xfer_done_list))) {
++              bio_endio(bio, bio->bi_size, 0);
++              bio_unmap_user(bio);
++      }
++
++      while ((bio = bio_list_pop(&tcmd->xfer_list))) {
++              bio_endio(bio, bio->bi_size, 0);
++              bio_unmap_user(bio);
++      }
++}
++
++static void cmd_hashlist_del(struct scsi_cmnd *cmd)
++{
++      struct request_queue *q = cmd->request->q;
++      struct scsi_tgt_queuedata *qdata = q->queuedata;
++      unsigned long flags;
++      struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
++
++      spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
++      list_del(&tcmd->hash_list);
++      spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
++}
++
++static void scsi_tgt_cmd_destroy(void *data)
++{
++      struct scsi_cmnd *cmd = data;
++      struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
++
++      dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction,
++              rq_data_dir(cmd->request));
++
++      cmd_hashlist_del(cmd);
++
++      /*
++       * We must set rq->flags here because bio_map_user and
++       * blk_rq_bio_prep ruined ti.
++       */
++      if (cmd->sc_data_direction == DMA_TO_DEVICE)
++              cmd->request->flags |= 1;
++      else
++              cmd->request->flags &= ~1UL;
++
++      scsi_unmap_user_pages(tcmd);
++      scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd);
++}
++
++static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd)
++{
++      struct scsi_tgt_queuedata *qdata = rq->q->queuedata;
++      unsigned long flags;
++      struct list_head *head;
++      static u32 tag = 0;
++
++      spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
++      rq->tag = tag++;
++      head = &qdata->cmd_hash[cmd_hashfn(rq->tag)];
++      list_add(&tcmd->hash_list, head);
++      spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
++}
++
++/*
++ * scsi_tgt_alloc_queue - setup queue used for message passing
++ * shost: scsi host
++ *
++ * This should be called by the LLD after host allocation.
++ * And will be released when the host is released.
++ */
++int scsi_tgt_alloc_queue(struct Scsi_Host *shost)
++{
++      struct scsi_tgt_queuedata *queuedata;
++      struct request_queue *q;
++      int err, i;
++
++      /*
++       * Do we need to send a netlink event or should uspace
++       * just respond to the hotplug event?
++       */
++      q = __scsi_alloc_queue(shost, NULL);
++      if (!q)
++              return -ENOMEM;
++
++      queuedata = kzalloc(sizeof(*queuedata), GFP_KERNEL);
++      if (!queuedata) {
++              err = -ENOMEM;
++              goto cleanup_queue;
++      }
++      queuedata->shost = shost;
++      q->queuedata = queuedata;
++
++      /*
++       * this is a silly hack. We should probably just queue as many
++       * command as is recvd to userspace. uspace can then make
++       * sure we do not overload the HBA
++       */
++      q->nr_requests = shost->hostt->can_queue;
++      /*
++       * We currently only support software LLDs so this does
++       * not matter for now. Do we need this for the cards we support?
++       * If so we should make it a host template value.
++       */
++      blk_queue_dma_alignment(q, 0);
++      shost->uspace_req_q = q;
++
++      for (i = 0; i < ARRAY_SIZE(queuedata->cmd_hash); i++)
++              INIT_LIST_HEAD(&queuedata->cmd_hash[i]);
++      spin_lock_init(&queuedata->cmd_hash_lock);
++
++      return 0;
++
++cleanup_queue:
++      blk_cleanup_queue(q);
++      return err;
++}
++EXPORT_SYMBOL_GPL(scsi_tgt_alloc_queue);
++
++struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *cmd)
++{
++      struct scsi_tgt_queuedata *queue = cmd->request->q->queuedata;
++      return queue->shost;
++}
++EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host);
++
++/*
++ * scsi_tgt_queue_command - queue command for userspace processing
++ * @cmd:      scsi command
++ * @scsilun:  scsi lun
++ * @tag:      unique value to identify this command for tmf
++ */
++int scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun,
++                         u64 tag)
++{
++      struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
++      int err;
++
++      init_scsi_tgt_cmd(cmd->request, tcmd);
++      err = scsi_tgt_uspace_send_cmd(cmd, scsilun, tag);
++      if (err)
++              cmd_hashlist_del(cmd);
++
++      return err;
++}
++EXPORT_SYMBOL_GPL(scsi_tgt_queue_command);
++
++/*
++ * 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)
++{
++      struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
++
++      dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
++
++      scsi_tgt_uspace_send_status(cmd);
++      INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy, cmd);
++      queue_work(scsi_tgtd, &tcmd->work);
++}
++
++static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
++{
++      struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
++      int err;
++
++      dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
++
++      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;
++      err = scsi_tgt_uspace_send_status(cmd);
++      if (err <= 0)
++              /* the eh will have to pick this up */
++              printk(KERN_ERR "Could not send cmd %p status\n", cmd);
++}
++
++static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
++{
++      struct request *rq = cmd->request;
++      struct scsi_tgt_cmd *tcmd = rq->end_io_data;
++      int count;
++
++      cmd->use_sg = rq->nr_phys_segments;
++      cmd->request_buffer = scsi_alloc_sgtable(cmd, gfp_mask);
++      if (!cmd->request_buffer)
++              return -ENOMEM;
++
++      cmd->request_bufflen = rq->data_len;
++
++      dprintk("cmd %p addr %p cnt %d %lu\n", cmd, tcmd->buffer, cmd->use_sg,
++              rq_data_dir(rq));
++      count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer);
++      if (likely(count <= cmd->use_sg)) {
++              cmd->use_sg = count;
++              return 0;
++      }
++
++      eprintk("cmd %p addr %p cnt %d\n", cmd, tcmd->buffer, cmd->use_sg);
++      scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
++      return -EINVAL;
++}
++
++/* TODO: test this crap and replace bio_map_user with new interface maybe */
++static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd 
*cmd,
++                             int rw)
++{
++      struct request_queue *q = cmd->request->q;
++      struct request *rq = cmd->request;
++      void *uaddr = tcmd->buffer;
++      unsigned int len = tcmd->bufflen;
++      struct bio *bio;
++      int err;
++
++      while (len > 0) {
++              dprintk("%lx %u\n", (unsigned long) uaddr, len);
++              bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw);
++              if (IS_ERR(bio)) {
++                      err = PTR_ERR(bio);
++                      dprintk("fail to map %lx %u %d %x\n",
++                              (unsigned long) uaddr, len, err, cmd->cmnd[0]);
++                      goto unmap_bios;
++              }
++
++              uaddr += bio->bi_size;
++              len -= bio->bi_size;
++
++              /*
++               * The first bio is added and merged. We could probably
++               * try to add others using scsi_merge_bio() but for now
++               * we keep it simple. The first bio should be pretty large
++               * (either hitting the 1 MB bio pages limit or a queue limit)
++               * already but for really large IO we may want to try and
++               * merge these.
++               */
++              if (!rq->bio) {
++                      blk_rq_bio_prep(q, rq, bio);
++                      rq->data_len = bio->bi_size;
++              } else
++                      /* put list of bios to transfer in next go around */
++                      bio_list_add(&tcmd->xfer_list, bio);
++      }
++
++      cmd->offset = 0;
++      err = scsi_tgt_init_cmd(cmd, GFP_KERNEL);
++      if (err)
++              goto unmap_bios;
++
++      return 0;
++
++unmap_bios:
++      if (rq->bio) {
++              bio_unmap_user(rq->bio);
++              while ((bio = bio_list_pop(&tcmd->xfer_list)))
++                      bio_unmap_user(bio);
++      }
++
++      return err;
++}
++
++static int scsi_tgt_transfer_data(struct scsi_cmnd *);
++
++static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd)
++{
++      struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
++      struct bio *bio;
++      int err;
++
++      /* should we free resources here on error ? */
++      if (cmd->result) {
++send_uspace_err:
++              err = scsi_tgt_uspace_send_status(cmd);
++              if (err <= 0)
++                      /* the tgt uspace eh will have to pick this up */
++                      printk(KERN_ERR "Could not send cmd %p status\n", cmd);
++              return;
++      }
++
++      dprintk("cmd %p request_bufflen %u bufflen %u\n",
++              cmd, cmd->request_bufflen, tcmd->bufflen);
++
++      scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
++      bio_list_add(&tcmd->xfer_done_list, cmd->request->bio);
++
++      tcmd->buffer += cmd->request_bufflen;
++      cmd->offset += cmd->request_bufflen;
++
++      if (!tcmd->xfer_list.head) {
++              scsi_tgt_transfer_response(cmd);
++              return;
++      }
++
++      dprintk("cmd2 %p request_bufflen %u bufflen %u\n",
++              cmd, cmd->request_bufflen, tcmd->bufflen);
++
++      bio = bio_list_pop(&tcmd->xfer_list);
++      BUG_ON(!bio);
++
++      blk_rq_bio_prep(cmd->request->q, cmd->request, bio);
++      cmd->request->data_len = bio->bi_size;
++      err = scsi_tgt_init_cmd(cmd, GFP_ATOMIC);
++      if (err) {
++              cmd->result = DID_ERROR << 16;
++              goto send_uspace_err;
++      }
++
++      if (scsi_tgt_transfer_data(cmd)) {
++              cmd->result = DID_NO_CONNECT << 16;
++              goto send_uspace_err;
++      }
++}
++
++static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd)
++{
++      int err;
++      struct Scsi_Host *host = scsi_tgt_cmd_to_host(cmd);
++
++      err = host->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;
++}
++
++static int scsi_tgt_abort_cmd(struct Scsi_Host *host, struct scsi_cmnd *cmd)
++{
++      int err;
++
++      err = host->hostt->eh_abort_handler(cmd);
++      if (err)
++              eprintk("fail to abort %p\n", cmd);
++
++      scsi_tgt_cmd_destroy(cmd);
++      return err;
++}
++
++static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u32 cid)
++{
++      struct scsi_tgt_queuedata *qdata = q->queuedata;
++      struct request *rq = NULL;
++      struct list_head *head;
++      struct scsi_tgt_cmd *tcmd;
++      unsigned long flags;
++
++      head = &qdata->cmd_hash[cmd_hashfn(cid)];
++      spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
++      list_for_each_entry(tcmd, head, hash_list) {
++              if (tcmd->rq->tag == cid) {
++                      rq = tcmd->rq;
++                      break;
++              }
++      }
++      spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
++
++      return rq;
++}
++
++int scsi_tgt_kspace_exec(int host_no, u32 cid, int result, u32 len,
++                       unsigned long uaddr, u8 rw)
++{
++      struct Scsi_Host *shost;
++      struct scsi_cmnd *cmd;
++      struct request *rq;
++      struct scsi_tgt_cmd *tcmd;
++      int err = 0;
++
++      dprintk("%d %u %d %u %lx %u\n", host_no, cid, result,
++              len, uaddr, rw);
++
++      /* 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;
++      }
++
++      if (!shost->uspace_req_q) {
++              printk(KERN_ERR "Not target scsi host %d\n", host_no);
++              goto done;
++      }
++
++      rq = tgt_cmd_hash_lookup(shost->uspace_req_q, cid);
++      if (!rq) {
++              printk(KERN_ERR "Could not find cid %u\n", cid);
++              err = -EINVAL;
++              goto done;
++      }
++      cmd = rq->special;
++
++      dprintk("cmd %p result %d len %d bufflen %u %lu %x\n", cmd,
++              result, len, cmd->request_bufflen, rq_data_dir(rq), 
cmd->cmnd[0]);
++
++      if (result == TASK_ABORTED) {
++              scsi_tgt_abort_cmd(shost, cmd);
++              goto done;
++      }
++      /*
++       * store the userspace values here, the working values are
++       * in the request_* values
++       */
++      tcmd = cmd->request->end_io_data;
++      tcmd->buffer = (void *)uaddr;
++      tcmd->bufflen = len;
++      cmd->result = result;
++
++      if (!tcmd->bufflen || cmd->request_buffer) {
++              err = __scsi_tgt_transfer_response(cmd);
++              goto done;
++      }
++
++      /*
++       * TODO: Do we need to handle case where request does not
++       * align with LLD.
++       */
++      err = scsi_map_user_pages(rq->end_io_data, cmd, rw);
++      if (err) {
++              eprintk("%p %d\n", cmd, err);
++              err = -EAGAIN;
++              goto done;
++      }
++
++      /* userspace failure */
++      if (cmd->result) {
++              if (status_byte(cmd->result) == CHECK_CONDITION)
++                      scsi_tgt_copy_sense(cmd, uaddr, len);
++              err = __scsi_tgt_transfer_response(cmd);
++              goto done;
++      }
++      /* ask the target LLD to transfer the data to the buffer */
++      err = scsi_tgt_transfer_data(cmd);
++
++done:
++      scsi_host_put(shost);
++      return err;
++}
++
++int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, int function, u64 tag,
++                            struct scsi_lun *scsilun, void *data)
++{
++      int err;
++
++      /* TODO: need to retry if this fails. */
++      err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, function,
++                                          tag, scsilun, data);
++      if (err < 0)
++              eprintk("The task management request lost!\n");
++      return err;
++}
++EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request);
++
++int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result)
++{
++      struct Scsi_Host *shost;
++      int err = -EINVAL;
++
++      dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid);
++
++      shost = scsi_host_lookup(host_no);
++      if (IS_ERR(shost)) {
++              printk(KERN_ERR "Could not find host no %d\n", host_no);
++              return -EINVAL;
++      }
++
++      if (!shost->uspace_req_q) {
++              printk(KERN_ERR "Not target scsi host %d\n", host_no);
++              goto done;
++      }
++
++      err = shost->hostt->tsk_mgmt_response(mid, result);
++done:
++      scsi_host_put(shost);
++
++      return err;
++}
++
++static int __init scsi_tgt_init(void)
++{
++      int err;
++
++      scsi_tgt_cmd_cache = kmem_cache_create("scsi_tgt_cmd",
++                                             sizeof(struct scsi_tgt_cmd),
++                                             0, 0, NULL, NULL);
++      if (!scsi_tgt_cmd_cache)
++              return -ENOMEM;
++
++      scsi_tgtd = create_workqueue("scsi_tgtd");
++      if (!scsi_tgtd) {
++              err = -ENOMEM;
++              goto free_kmemcache;
++      }
++
++      err = scsi_tgt_if_init();
++      if (err)
++              goto destroy_wq;
++
++      return 0;
++
++destroy_wq:
++      destroy_workqueue(scsi_tgtd);
++free_kmemcache:
++      kmem_cache_destroy(scsi_tgt_cmd_cache);
++      return err;
++}
++
++static void __exit scsi_tgt_exit(void)
++{
++      destroy_workqueue(scsi_tgtd);
++      scsi_tgt_if_exit();
++      kmem_cache_destroy(scsi_tgt_cmd_cache);
++}
++
++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_priv.h b/drivers/scsi/scsi_tgt_priv.h
+new file mode 100644
+index 0000000..bd16a2c
+--- /dev/null
++++ b/drivers/scsi/scsi_tgt_priv.h
+@@ -0,0 +1,24 @@
++struct scsi_cmnd;
++struct scsi_lun;
++struct Scsi_Host;
++struct task_struct;
++
++/* tmp - will replace with SCSI logging stuff */
++#define eprintk(fmt, args...)                                 \
++do {                                                          \
++      printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);  \
++} while (0)
++
++#define dprintk eprintk
++
++extern void scsi_tgt_if_exit(void);
++extern int scsi_tgt_if_init(void);
++
++extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun 
*lun,
++                                  u64 tag);
++extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd);
++extern int scsi_tgt_kspace_exec(int host_no, u32 cid, int result, u32 len,
++                              unsigned long uaddr, u8 rw);
++extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
++                                       struct scsi_lun *scsilun, void *data);
++extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result);
+diff --git a/fs/bio.c b/fs/bio.c
+index 6a0b9ad..ade77bf 100644
+--- a/fs/bio.c
++++ b/fs/bio.c
+@@ -621,10 +621,9 @@ static struct bio *__bio_map_user_iov(re
+ 
+               nr_pages += end - start;
+               /*
+-               * transfer and buffer must be aligned to at least hardsector
+-               * size for now, in the future we can relax this restriction
++               * buffer must be aligned to at least hardsector size for now
+                */
+-              if ((uaddr & queue_dma_alignment(q)) || (len & 
queue_dma_alignment(q)))
++              if (uaddr & queue_dma_alignment(q))
+                       return ERR_PTR(-EINVAL);
+       }
+ 
+@@ -750,7 +749,6 @@ struct bio *bio_map_user_iov(request_que
+                            int write_to_vm)
+ {
+       struct bio *bio;
+-      int len = 0, i;
+ 
+       bio = __bio_map_user_iov(q, bdev, iov, iov_count, write_to_vm);
+ 
+@@ -765,18 +763,7 @@ struct bio *bio_map_user_iov(request_que
+        */
+       bio_get(bio);
+ 
+-      for (i = 0; i < iov_count; i++)
+-              len += iov[i].iov_len;
+-
+-      if (bio->bi_size == len)
+-              return bio;
+-
+-      /*
+-       * don't support partial mappings
+-       */
+-      bio_endio(bio, bio->bi_size, 0);
+-      bio_unmap_user(bio);
+-      return ERR_PTR(-EINVAL);
++      return bio;
+ }
+ 
+ static void __bio_unmap_user(struct bio *bio)
+diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
+index 59e1259..cec7ccf 100644
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -624,7 +624,8 @@ extern void blk_queue_activity_fn(reques
+ extern int blk_rq_map_user(request_queue_t *, struct request *, void __user 
*, unsigned int);
+ extern int blk_rq_unmap_user(struct bio *, unsigned int);
+ extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, 
unsigned int, gfp_t);
+-extern int blk_rq_map_user_iov(request_queue_t *, struct request *, struct 
sg_iovec *, int);
++extern int blk_rq_map_user_iov(request_queue_t *, struct request *,
++                             struct sg_iovec *, int, unsigned int);
+ extern int blk_execute_rq(request_queue_t *, struct gendisk *,
+                         struct request *, int);
+ extern void blk_execute_rq_nowait(request_queue_t *, struct gendisk *,
+diff --git a/include/scsi/libsrp.h b/include/scsi/libsrp.h
+new file mode 100644
+index 0000000..9dd10ff
+--- /dev/null
++++ b/include/scsi/libsrp.h
+@@ -0,0 +1,75 @@
++#ifndef __LIBSRP_H__
++#define __LIBSRP_H__
++
++#include <linux/list.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_host.h>
++#include <scsi/srp.h>
++
++enum iue_flags {
++      V_DIOVER,
++      V_WRITE,
++      V_LINKED,
++      V_FLYING,
++};
++
++struct srp_buf {
++      dma_addr_t dma;
++      void *buf;
++};
++
++struct srp_queue {
++      void *pool;
++      void *items;
++      struct kfifo *queue;
++      spinlock_t lock;
++};
++
++struct srp_target {
++      struct Scsi_Host *shost;
++      struct device *dev;
++
++      spinlock_t lock;
++      struct list_head cmd_queue;
++
++      size_t srp_iu_size;
++      struct srp_queue iu_queue;
++      size_t rx_ring_size;
++      struct srp_buf **rx_ring;
++
++      /* IB needs tx_ring too */
++
++      void *ldata;
++};
++
++struct iu_entry {
++      struct srp_target *target;
++      struct scsi_cmnd *scmd;
++
++      struct list_head ilist;
++      dma_addr_t remote_token;
++      unsigned long flags;
++
++      struct srp_buf *sbuf;
++};
++
++typedef int (rdma_io_t) (struct iu_entry *, struct scatterlist *, int,
++                       struct srp_direct_buf *, int,
++                       enum dma_data_direction, unsigned int);
++
++static inline struct srp_target *host_to_target(struct Scsi_Host *host)
++{
++      return (struct srp_target *) host->hostdata;
++}
++
++extern int srp_target_alloc(struct srp_target *, struct device *, size_t, 
size_t);
++extern void srp_target_free(struct srp_target *);
++
++extern struct iu_entry *srp_iu_get(struct srp_target *);
++extern void srp_iu_put(struct iu_entry *);
++
++extern int srp_cmd_perform(struct iu_entry *iue, struct srp_cmd *cmd);
++extern int srp_transfer_data(struct scsi_cmnd *scmd, struct srp_cmd *cmd,
++                           rdma_io_t rdma_io);
++
++#endif
+diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
+index 1ace1b9..d69dbf5 100644
+--- a/include/scsi/scsi_cmnd.h
++++ b/include/scsi/scsi_cmnd.h
+@@ -8,6 +8,7 @@
+ 
+ struct request;
+ struct scatterlist;
++struct Scsi_Host;
+ struct scsi_device;
+ struct scsi_request;
+ 
+@@ -84,6 +85,8 @@ struct scsi_cmnd {
+       unsigned short sglist_len;      /* size of malloc'd scatter-gather list 
*/
+       unsigned bufflen;       /* Size of data buffer */
+       void *buffer;           /* Data buffer */
++      /* offset in cmd we are at (for multi-transfer tgt cmds) */
++      unsigned offset;
+ 
+       unsigned underflow;     /* Return error if less than
+                                  this amount is transferred */
+@@ -148,8 +151,13 @@ struct scsi_cmnd {
+ 
+ 
+ extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
++extern struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *, gfp_t);
+ extern void scsi_put_command(struct scsi_cmnd *);
++extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *,
++                             struct device *);
+ extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned 
int);
+ extern void scsi_finish_command(struct scsi_cmnd *cmd);
++extern struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *, gfp_t);
++extern void scsi_free_sgtable(struct scatterlist *, int);
+ 
+ #endif /* _SCSI_SCSI_CMND_H */
+diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
+index de6ce54..353abe5 100644
+--- a/include/scsi/scsi_host.h
++++ b/include/scsi/scsi_host.h
+@@ -7,6 +7,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/mutex.h>
+ 
++struct request_queue;
+ struct block_device;
+ struct completion;
+ struct module;
+@@ -123,6 +124,39 @@ struct scsi_host_template {
+                            void (*done)(struct scsi_cmnd *));
+ 
+       /*
++       * The transfer functions are used to queue a scsi command to
++       * the LLD. When the driver is finished processing the command
++       * the done callback is invoked.
++       *
++       * return values: see queuecommand
++       *
++       * If the LLD accepts the cmd, it should set the result to an
++       * appropriate value when completed before calling the done function.
++       *
++       * STATUS: REQUIRED FOR TARGET DRIVERS
++       */
++      /* TODO: rename */
++      int (* transfer_response)(struct scsi_cmnd *,
++                                void (*done)(struct scsi_cmnd *));
++      /*
++       * This is called to inform the LLD to transfer cmd->request_bufflen
++       * bytes of the cmd at cmd->offset in the cmd. The cmd->use_sg
++       * speciefies the number of scatterlist entried in the command
++       * and cmd->request_buffer contains the scatterlist.
++       *
++       * If the command cannot be processed in one transfer_data call
++       * becuase a scatterlist within the LLD's limits cannot be
++       * created then transfer_data will be called multiple times.
++       * It is initially called from process context, and later
++       * calls are from the interrup context.
++       */
++      int (* transfer_data)(struct scsi_cmnd *,
++                            void (*done)(struct scsi_cmnd *));
++
++      /* Used as callback for the completion of task management request. */
++      int (* tsk_mgmt_response)(u64 mid, int result);
++
++      /*
+        * This is an error handling strategy routine.  You don't need to
+        * define one of these if you don't want to - there is a default
+        * routine that is present that should work in most cases.  For those
+@@ -557,6 +591,12 @@ struct Scsi_Host {
+        */
+       unsigned int max_host_blocked;
+ 
++      /*
++       * q used for scsi_tgt msgs, async events or any other requests that
++       * need to be processed in userspace
++       */
++      struct request_queue *uspace_req_q;
++
+       /* legacy crap */
+       unsigned long base;
+       unsigned long io_port;
+@@ -659,6 +699,9 @@ extern void scsi_unblock_requests(struct
+ extern void scsi_block_requests(struct Scsi_Host *);
+ 
+ struct class_container;
++
++extern struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
++                                           void (*) (struct request_queue *));
+ /*
+  * These two functions are used to allocate and free a pseudo device
+  * which will connect to the host adapter itself rather than any
+diff --git a/include/scsi/scsi_tgt.h b/include/scsi/scsi_tgt.h
+new file mode 100644
+index 0000000..61e8ee9
+--- /dev/null
++++ b/include/scsi/scsi_tgt.h
+@@ -0,0 +1,17 @@
++/*
++ * SCSI target definitions
++ */
++
++#include <linux/dma-mapping.h>
++
++struct Scsi_Host;
++struct scsi_cmnd;
++struct scsi_lun;
++
++extern struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *);
++extern int scsi_tgt_alloc_queue(struct Scsi_Host *);
++extern int scsi_tgt_queue_command(struct scsi_cmnd *, struct scsi_lun *, u64);
++extern int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *, int, u64, struct 
scsi_lun *,
++                                   void *);
++extern struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *,
++                                             enum dma_data_direction, gfp_t);
+diff --git a/include/scsi/scsi_tgt_if.h b/include/scsi/scsi_tgt_if.h
+new file mode 100644
+index 0000000..0cc1b9b
+--- /dev/null
++++ b/include/scsi/scsi_tgt_if.h
+@@ -0,0 +1,91 @@
++/*
++ * SCSI target kernel/user 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
++ */
++#ifndef __SCSI_TARGET_IF_H
++#define __SCSI_TARGET_IF_H
++
++enum tgt_event_type {
++      /* user -> kernel */
++      TGT_UEVENT_CMD_RSP,
++      TGT_UEVENT_TSK_MGMT_RSP,
++
++      /* kernel -> user */
++      TGT_KEVENT_CMD_REQ,
++      TGT_KEVENT_CMD_DONE,
++      TGT_KEVENT_TSK_MGMT_REQ,
++};
++
++struct tgt_event {
++      uint32_t type;
++      /* user-> kernel */
++      union {
++              struct {
++                      int host_no;
++                      uint32_t cid;
++                      uint32_t len;
++                      int result;
++                      uint64_t uaddr;
++                      uint8_t rw;
++              } cmd_rsp;
++              struct {
++                      int host_no;
++                      uint64_t mid;
++                      int result;
++              } tsk_mgmt_rsp;
++      } u;
++
++      /* kernel -> user */
++      union {
++              struct {
++                      int host_no;
++                      uint32_t cid;
++                      uint32_t data_len;
++                      uint8_t scb[16];
++                      uint8_t lun[8];
++                      int attribute;
++                      uint64_t tag;
++                      uint64_t uaddr;
++              } cmd_req;
++              struct {
++                      int host_no;
++                      uint32_t cid;
++                      int result;
++              } cmd_done;
++              struct {
++                      int host_no;
++                      int function;
++                      uint64_t tag;
++                      uint8_t lun[8];
++                      uint64_t mid;
++              } tsk_mgmt_req;
++      } k;
++
++} __attribute__ ((aligned (sizeof(uint64_t))));
++
++#define TGT_RINGBUF_SIZE (1UL << 16)
++
++struct rbuf_hdr {
++      uint32_t status;
++      uint32_t len;
++      uint64_t data[0];
++} __attribute__ ((aligned (sizeof(uint64_t))));
++
++#endif
+-- 
+1.1.5

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.