mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-21 12:41:26 +00:00
Added out-of-tree build infrastructure for the ibmvstgt driver together with copies of the relevant ibmvstgt source files from Linux 2.6.35.
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1977 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
44
ibmvstgt/Makefile
Normal file
44
ibmvstgt/Makefile
Normal file
@@ -0,0 +1,44 @@
|
||||
#
|
||||
# Makefile for ibmvstgt.ko.
|
||||
#
|
||||
|
||||
SCST_DIR := $(shell pwd)/../scst/src
|
||||
SUBDIRS := $(shell pwd)
|
||||
|
||||
ifeq ($(KVER),)
|
||||
ifeq ($(KDIR),)
|
||||
KVER = $(shell uname -r)
|
||||
KDIR ?= /lib/modules/$(KVER)/build
|
||||
else
|
||||
KVER = $$KERNELRELEASE
|
||||
endif
|
||||
else
|
||||
KDIR ?= /lib/modules/$(KVER)/build
|
||||
endif
|
||||
|
||||
# The file Modules.symvers has been renamed in the 2.6.18 kernel to
|
||||
# Module.symvers. Find out which name to use by looking in $(KDIR).
|
||||
MODULE_SYMVERS:=$(shell if [ -e $(KDIR)/Module.symvers ]; then \
|
||||
echo Module.symvers; else echo Modules.symvers; fi)
|
||||
|
||||
|
||||
all: src/$(MODULE_SYMVERS)
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/src modules
|
||||
|
||||
install: all src/ib_srpt.ko
|
||||
@eval `sed -n 's/#define UTS_RELEASE /KERNELRELEASE=/p' $(KDIR)/include/linux/version.h $(KDIR)/include/linux/utsrelease.h 2>/dev/null`; \
|
||||
install -vD -m 644 src/ib_srpt.ko \
|
||||
$(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra/ib_srpt.ko
|
||||
-/sbin/depmod -aq $(KVER)
|
||||
|
||||
src/Module.symvers src/Modules.symvers: $(SCST_DIR)/$(MODULE_SYMVERS)
|
||||
cp $< $@;
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/src clean
|
||||
rm -f src/Modules.symvers src/Module.symvers src/Module.markers \
|
||||
src/modules.order
|
||||
|
||||
extraclean: clean
|
||||
|
||||
.PHONY: all install clean extraclean
|
||||
10
ibmvstgt/src/Makefile
Normal file
10
ibmvstgt/src/Makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
IBMVSTGT_INC_DIR := $(SUBDIRS)/../../scst/include/
|
||||
|
||||
EXTRA_CFLAGS += -I$(SCST_INC_DIR)
|
||||
#EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
|
||||
#EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG
|
||||
#EXTRA_CFLAGS += -g -fno-inline -fno-inline-functions
|
||||
#EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
|
||||
#EXTRA_CFLAGS += -Wextra -Wno-unused-parameter
|
||||
|
||||
obj-m += libsrp.o ibmvstgt.o
|
||||
129
ibmvstgt/src/ibmvscsi.h
Normal file
129
ibmvstgt/src/ibmvscsi.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/* ------------------------------------------------------------
|
||||
* ibmvscsi.h
|
||||
* (C) Copyright IBM Corporation 1994, 2003
|
||||
* Authors: Colin DeVilbiss (devilbis@us.ibm.com)
|
||||
* Santiago Leon (santil@us.ibm.com)
|
||||
* Dave Boutcher (sleddog@us.ibm.com)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* ------------------------------------------------------------
|
||||
* Emulation of a SCSI host adapter for Virtual I/O devices
|
||||
*
|
||||
* This driver allows the Linux SCSI peripheral drivers to directly
|
||||
* access devices in the hosting partition, either on an iSeries
|
||||
* hypervisor system or a converged hypervisor system.
|
||||
*/
|
||||
#ifndef IBMVSCSI_H
|
||||
#define IBMVSCSI_H
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include "viosrp.h"
|
||||
|
||||
struct scsi_cmnd;
|
||||
struct Scsi_Host;
|
||||
|
||||
/* Number of indirect bufs...the list of these has to fit in the
|
||||
* additional data of the srp_cmd struct along with the indirect
|
||||
* descriptor
|
||||
*/
|
||||
#define MAX_INDIRECT_BUFS 10
|
||||
|
||||
#define IBMVSCSI_MAX_REQUESTS_DEFAULT 100
|
||||
#define IBMVSCSI_CMDS_PER_LUN_DEFAULT 16
|
||||
#define IBMVSCSI_MAX_SECTORS_DEFAULT 256 /* 32 * 8 = default max I/O 32 pages */
|
||||
#define IBMVSCSI_MAX_CMDS_PER_LUN 64
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
* Data Structures
|
||||
*/
|
||||
/* an RPA command/response transport queue */
|
||||
struct crq_queue {
|
||||
struct viosrp_crq *msgs;
|
||||
int size, cur;
|
||||
dma_addr_t msg_token;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/* a unit of work for the hosting partition */
|
||||
struct srp_event_struct {
|
||||
union viosrp_iu *xfer_iu;
|
||||
struct scsi_cmnd *cmnd;
|
||||
struct list_head list;
|
||||
void (*done) (struct srp_event_struct *);
|
||||
struct viosrp_crq crq;
|
||||
struct ibmvscsi_host_data *hostdata;
|
||||
atomic_t free;
|
||||
union viosrp_iu iu;
|
||||
void (*cmnd_done) (struct scsi_cmnd *);
|
||||
struct completion comp;
|
||||
struct timer_list timer;
|
||||
union viosrp_iu *sync_srp;
|
||||
struct srp_direct_buf *ext_list;
|
||||
dma_addr_t ext_list_token;
|
||||
};
|
||||
|
||||
/* a pool of event structs for use */
|
||||
struct event_pool {
|
||||
struct srp_event_struct *events;
|
||||
u32 size;
|
||||
int next;
|
||||
union viosrp_iu *iu_storage;
|
||||
dma_addr_t iu_token;
|
||||
};
|
||||
|
||||
/* all driver data associated with a host adapter */
|
||||
struct ibmvscsi_host_data {
|
||||
atomic_t request_limit;
|
||||
int client_migrated;
|
||||
struct device *dev;
|
||||
struct event_pool pool;
|
||||
struct crq_queue queue;
|
||||
struct tasklet_struct srp_task;
|
||||
struct list_head sent;
|
||||
struct Scsi_Host *host;
|
||||
struct mad_adapter_info_data madapter_info;
|
||||
struct capabilities caps;
|
||||
dma_addr_t caps_addr;
|
||||
dma_addr_t adapter_info_addr;
|
||||
};
|
||||
|
||||
/* routines for managing a command/response queue */
|
||||
void ibmvscsi_handle_crq(struct viosrp_crq *crq,
|
||||
struct ibmvscsi_host_data *hostdata);
|
||||
|
||||
struct ibmvscsi_ops {
|
||||
int (*init_crq_queue)(struct crq_queue *queue,
|
||||
struct ibmvscsi_host_data *hostdata,
|
||||
int max_requests);
|
||||
void (*release_crq_queue)(struct crq_queue *queue,
|
||||
struct ibmvscsi_host_data *hostdata,
|
||||
int max_requests);
|
||||
int (*reset_crq_queue)(struct crq_queue *queue,
|
||||
struct ibmvscsi_host_data *hostdata);
|
||||
int (*reenable_crq_queue)(struct crq_queue *queue,
|
||||
struct ibmvscsi_host_data *hostdata);
|
||||
int (*send_crq)(struct ibmvscsi_host_data *hostdata,
|
||||
u64 word1, u64 word2);
|
||||
int (*resume) (struct ibmvscsi_host_data *hostdata);
|
||||
};
|
||||
|
||||
extern struct ibmvscsi_ops iseriesvscsi_ops;
|
||||
extern struct ibmvscsi_ops rpavscsi_ops;
|
||||
|
||||
#endif /* IBMVSCSI_H */
|
||||
1004
ibmvstgt/src/ibmvstgt.c
Normal file
1004
ibmvstgt/src/ibmvstgt.c
Normal file
File diff suppressed because it is too large
Load Diff
446
ibmvstgt/src/libsrp.c
Normal file
446
ibmvstgt/src/libsrp.c
Normal file
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
* SCSI RDMA Protocol lib functions
|
||||
*
|
||||
* Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/dma-mapping.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, __func__, __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);
|
||||
kfifo_init(&q->queue, (void *) q->pool, max * sizeof(void *));
|
||||
|
||||
for (i = 0, iue = q->items; i < max; i++) {
|
||||
kfifo_in(&q->queue, (void *) &iue, sizeof(void *));
|
||||
iue->sbuf = ring[i];
|
||||
iue++;
|
||||
}
|
||||
return 0;
|
||||
|
||||
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]);
|
||||
}
|
||||
kfree(ring);
|
||||
}
|
||||
|
||||
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;
|
||||
dev_set_drvdata(target->dev, 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;
|
||||
|
||||
if (kfifo_out_locked(&target->iu_queue.queue, (void *) &iue,
|
||||
sizeof(void *), &target->iu_queue.lock) != sizeof(void *)) {
|
||||
WARN_ONCE(1, "unexpected fifo state");
|
||||
return NULL;
|
||||
}
|
||||
if (!iue)
|
||||
return iue;
|
||||
iue->target = target;
|
||||
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_in_locked(&iue->target->iu_queue.queue, (void *) &iue,
|
||||
sizeof(void *), &iue->target->iu_queue.lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(srp_iu_put);
|
||||
|
||||
static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
|
||||
enum dma_data_direction dir, srp_rdma_t rdma_io,
|
||||
int dma_map, int ext_desc)
|
||||
{
|
||||
struct iu_entry *iue = NULL;
|
||||
struct scatterlist *sg = NULL;
|
||||
int err, nsg = 0, len;
|
||||
|
||||
if (dma_map) {
|
||||
iue = (struct iu_entry *) sc->SCp.ptr;
|
||||
sg = scsi_sglist(sc);
|
||||
|
||||
dprintk("%p %u %u %d\n", iue, scsi_bufflen(sc),
|
||||
md->len, scsi_sg_count(sc));
|
||||
|
||||
nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
|
||||
DMA_BIDIRECTIONAL);
|
||||
if (!nsg) {
|
||||
printk("fail to map %p %d\n", iue, scsi_sg_count(sc));
|
||||
return 0;
|
||||
}
|
||||
len = min(scsi_bufflen(sc), md->len);
|
||||
} else
|
||||
len = md->len;
|
||||
|
||||
err = rdma_io(sc, sg, nsg, md, 1, dir, len);
|
||||
|
||||
if (dma_map)
|
||||
dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
|
||||
struct srp_indirect_buf *id,
|
||||
enum dma_data_direction dir, srp_rdma_t rdma_io,
|
||||
int dma_map, int ext_desc)
|
||||
{
|
||||
struct iu_entry *iue = NULL;
|
||||
struct srp_direct_buf *md = NULL;
|
||||
struct scatterlist dummy, *sg = NULL;
|
||||
dma_addr_t token = 0;
|
||||
int err = 0;
|
||||
int nmd, nsg = 0, len;
|
||||
|
||||
if (dma_map || ext_desc) {
|
||||
iue = (struct iu_entry *) sc->SCp.ptr;
|
||||
sg = scsi_sglist(sc);
|
||||
|
||||
dprintk("%p %u %u %d %d\n",
|
||||
iue, scsi_bufflen(sc), id->len,
|
||||
cmd->data_in_desc_cnt, cmd->data_out_desc_cnt);
|
||||
}
|
||||
|
||||
nmd = id->table_desc.len / sizeof(struct srp_direct_buf);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (ext_desc && dma_map) {
|
||||
md = dma_alloc_coherent(iue->target->dev, id->table_desc.len,
|
||||
&token, GFP_KERNEL);
|
||||
if (!md) {
|
||||
eprintk("Can't get dma memory %u\n", id->table_desc.len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sg_init_one(&dummy, md, id->table_desc.len);
|
||||
sg_dma_address(&dummy) = token;
|
||||
sg_dma_len(&dummy) = id->table_desc.len;
|
||||
err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
|
||||
id->table_desc.len);
|
||||
if (err) {
|
||||
eprintk("Error copying indirect table %d\n", err);
|
||||
goto free_mem;
|
||||
}
|
||||
} else {
|
||||
eprintk("This command uses external indirect buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rdma:
|
||||
if (dma_map) {
|
||||
nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
|
||||
DMA_BIDIRECTIONAL);
|
||||
if (!nsg) {
|
||||
eprintk("fail to map %p %d\n", iue, scsi_sg_count(sc));
|
||||
err = -EIO;
|
||||
goto free_mem;
|
||||
}
|
||||
len = min(scsi_bufflen(sc), id->len);
|
||||
} else
|
||||
len = id->len;
|
||||
|
||||
err = rdma_io(sc, sg, nsg, md, nmd, dir, len);
|
||||
|
||||
if (dma_map)
|
||||
dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
|
||||
|
||||
free_mem:
|
||||
if (token && dma_map)
|
||||
dma_free_coherent(iue->target->dev, id->table_desc.len, md, token);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: this can be called multiple times for a single command if it
|
||||
* has very long data.
|
||||
*/
|
||||
int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
|
||||
srp_rdma_t rdma_io, int dma_map, int ext_desc)
|
||||
{
|
||||
struct srp_direct_buf *md;
|
||||
struct srp_indirect_buf *id;
|
||||
enum dma_data_direction dir;
|
||||
int offset, err = 0;
|
||||
u8 format;
|
||||
|
||||
offset = cmd->add_cdb_len & ~3;
|
||||
|
||||
dir = srp_cmd_direction(cmd);
|
||||
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 = srp_direct_data(sc, md, dir, rdma_io, dma_map, ext_desc);
|
||||
break;
|
||||
case SRP_DATA_DESC_INDIRECT:
|
||||
id = (struct srp_indirect_buf *)
|
||||
(cmd->add_data + offset);
|
||||
err = srp_indirect_data(sc, cmd, id, dir, rdma_io, dma_map,
|
||||
ext_desc);
|
||||
break;
|
||||
default:
|
||||
eprintk("Unknown format %d %x\n", dir, format);
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
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 & ~3;
|
||||
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;
|
||||
}
|
||||
|
||||
int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info,
|
||||
u64 itn_id, u64 addr)
|
||||
{
|
||||
enum dma_data_direction dir;
|
||||
struct scsi_cmnd *sc;
|
||||
int tag, len, err;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
dir = srp_cmd_direction(cmd);
|
||||
len = vscsis_data_length(cmd, dir);
|
||||
|
||||
dprintk("%p %x %lx %d %d %d %llx\n", info, cmd->cdb[0],
|
||||
cmd->lun, dir, len, tag, (unsigned long long) cmd->tag);
|
||||
|
||||
sc = scsi_host_get_command(shost, dir, GFP_KERNEL);
|
||||
if (!sc)
|
||||
return -ENOMEM;
|
||||
|
||||
sc->SCp.ptr = info;
|
||||
memcpy(sc->cmnd, cmd->cdb, MAX_COMMAND_SIZE);
|
||||
sc->sdb.length = len;
|
||||
sc->sdb.table.sgl = (void *) (unsigned long) addr;
|
||||
sc->tag = tag;
|
||||
err = scsi_tgt_queue_command(sc, itn_id, (struct scsi_lun *)&cmd->lun,
|
||||
cmd->tag);
|
||||
if (err)
|
||||
scsi_host_put_command(shost, sc);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(srp_cmd_queue);
|
||||
|
||||
MODULE_DESCRIPTION("SCSI RDMA Protocol lib functions");
|
||||
MODULE_AUTHOR("FUJITA Tomonori");
|
||||
MODULE_LICENSE("GPL");
|
||||
217
ibmvstgt/src/viosrp.h
Normal file
217
ibmvstgt/src/viosrp.h
Normal file
@@ -0,0 +1,217 @@
|
||||
/*****************************************************************************/
|
||||
/* srp.h -- SCSI RDMA Protocol definitions */
|
||||
/* */
|
||||
/* Written By: Colin Devilbis, IBM Corporation */
|
||||
/* */
|
||||
/* Copyright (C) 2003 IBM Corporation */
|
||||
/* */
|
||||
/* 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 */
|
||||
/* */
|
||||
/* */
|
||||
/* This file contains structures and definitions for IBM RPA (RS/6000 */
|
||||
/* platform architecture) implementation of the SRP (SCSI RDMA Protocol) */
|
||||
/* standard. SRP is used on IBM iSeries and pSeries platforms to send SCSI */
|
||||
/* commands between logical partitions. */
|
||||
/* */
|
||||
/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ) */
|
||||
/* between partitions. The definitions in this file are architected, */
|
||||
/* and cannot be changed without breaking compatibility with other versions */
|
||||
/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/
|
||||
/* between logical partitions */
|
||||
/*****************************************************************************/
|
||||
#ifndef VIOSRP_H
|
||||
#define VIOSRP_H
|
||||
#include <scsi/srp.h>
|
||||
|
||||
#define SRP_VERSION "16.a"
|
||||
#define SRP_MAX_IU_LEN 256
|
||||
#define SRP_MAX_LOC_LEN 32
|
||||
|
||||
union srp_iu {
|
||||
struct srp_login_req login_req;
|
||||
struct srp_login_rsp login_rsp;
|
||||
struct srp_login_rej login_rej;
|
||||
struct srp_i_logout i_logout;
|
||||
struct srp_t_logout t_logout;
|
||||
struct srp_tsk_mgmt tsk_mgmt;
|
||||
struct srp_cmd cmd;
|
||||
struct srp_rsp rsp;
|
||||
u8 reserved[SRP_MAX_IU_LEN];
|
||||
};
|
||||
|
||||
enum viosrp_crq_formats {
|
||||
VIOSRP_SRP_FORMAT = 0x01,
|
||||
VIOSRP_MAD_FORMAT = 0x02,
|
||||
VIOSRP_OS400_FORMAT = 0x03,
|
||||
VIOSRP_AIX_FORMAT = 0x04,
|
||||
VIOSRP_LINUX_FORMAT = 0x06,
|
||||
VIOSRP_INLINE_FORMAT = 0x07
|
||||
};
|
||||
|
||||
enum viosrp_crq_status {
|
||||
VIOSRP_OK = 0x0,
|
||||
VIOSRP_NONRECOVERABLE_ERR = 0x1,
|
||||
VIOSRP_VIOLATES_MAX_XFER = 0x2,
|
||||
VIOSRP_PARTNER_PANIC = 0x3,
|
||||
VIOSRP_DEVICE_BUSY = 0x8,
|
||||
VIOSRP_ADAPTER_FAIL = 0x10,
|
||||
VIOSRP_OK2 = 0x99,
|
||||
};
|
||||
|
||||
struct viosrp_crq {
|
||||
u8 valid; /* used by RPA */
|
||||
u8 format; /* SCSI vs out-of-band */
|
||||
u8 reserved;
|
||||
u8 status; /* non-scsi failure? (e.g. DMA failure) */
|
||||
u16 timeout; /* in seconds */
|
||||
u16 IU_length; /* in bytes */
|
||||
u64 IU_data_ptr; /* the TCE for transferring data */
|
||||
};
|
||||
|
||||
/* MADs are Management requests above and beyond the IUs defined in the SRP
|
||||
* standard.
|
||||
*/
|
||||
enum viosrp_mad_types {
|
||||
VIOSRP_EMPTY_IU_TYPE = 0x01,
|
||||
VIOSRP_ERROR_LOG_TYPE = 0x02,
|
||||
VIOSRP_ADAPTER_INFO_TYPE = 0x03,
|
||||
VIOSRP_HOST_CONFIG_TYPE = 0x04,
|
||||
VIOSRP_CAPABILITIES_TYPE = 0x05,
|
||||
VIOSRP_ENABLE_FAST_FAIL = 0x08,
|
||||
};
|
||||
|
||||
enum viosrp_mad_status {
|
||||
VIOSRP_MAD_SUCCESS = 0x00,
|
||||
VIOSRP_MAD_NOT_SUPPORTED = 0xF1,
|
||||
VIOSRP_MAD_FAILED = 0xF7,
|
||||
};
|
||||
|
||||
enum viosrp_capability_type {
|
||||
MIGRATION_CAPABILITIES = 0x01,
|
||||
RESERVATION_CAPABILITIES = 0x02,
|
||||
};
|
||||
|
||||
enum viosrp_capability_support {
|
||||
SERVER_DOES_NOT_SUPPORTS_CAP = 0x0,
|
||||
SERVER_SUPPORTS_CAP = 0x01,
|
||||
SERVER_CAP_DATA = 0x02,
|
||||
};
|
||||
|
||||
enum viosrp_reserve_type {
|
||||
CLIENT_RESERVE_SCSI_2 = 0x01,
|
||||
};
|
||||
|
||||
enum viosrp_capability_flag {
|
||||
CLIENT_MIGRATED = 0x01,
|
||||
CLIENT_RECONNECT = 0x02,
|
||||
CAP_LIST_SUPPORTED = 0x04,
|
||||
CAP_LIST_DATA = 0x08,
|
||||
};
|
||||
|
||||
/*
|
||||
* Common MAD header
|
||||
*/
|
||||
struct mad_common {
|
||||
u32 type;
|
||||
u16 status;
|
||||
u16 length;
|
||||
u64 tag;
|
||||
};
|
||||
|
||||
/*
|
||||
* All SRP (and MAD) requests normally flow from the
|
||||
* client to the server. There is no way for the server to send
|
||||
* an asynchronous message back to the client. The Empty IU is used
|
||||
* to hang out a meaningless request to the server so that it can respond
|
||||
* asynchrouously with something like a SCSI AER
|
||||
*/
|
||||
struct viosrp_empty_iu {
|
||||
struct mad_common common;
|
||||
u64 buffer;
|
||||
u32 port;
|
||||
};
|
||||
|
||||
struct viosrp_error_log {
|
||||
struct mad_common common;
|
||||
u64 buffer;
|
||||
};
|
||||
|
||||
struct viosrp_adapter_info {
|
||||
struct mad_common common;
|
||||
u64 buffer;
|
||||
};
|
||||
|
||||
struct viosrp_host_config {
|
||||
struct mad_common common;
|
||||
u64 buffer;
|
||||
};
|
||||
|
||||
struct viosrp_fast_fail {
|
||||
struct mad_common common;
|
||||
};
|
||||
|
||||
struct viosrp_capabilities {
|
||||
struct mad_common common;
|
||||
u64 buffer;
|
||||
};
|
||||
|
||||
struct mad_capability_common {
|
||||
u32 cap_type;
|
||||
u16 length;
|
||||
u16 server_support;
|
||||
};
|
||||
|
||||
struct mad_reserve_cap {
|
||||
struct mad_capability_common common;
|
||||
u32 type;
|
||||
};
|
||||
|
||||
struct mad_migration_cap {
|
||||
struct mad_capability_common common;
|
||||
u32 ecl;
|
||||
};
|
||||
|
||||
struct capabilities{
|
||||
u32 flags;
|
||||
char name[SRP_MAX_LOC_LEN];
|
||||
char loc[SRP_MAX_LOC_LEN];
|
||||
struct mad_migration_cap migration;
|
||||
struct mad_reserve_cap reserve;
|
||||
};
|
||||
|
||||
union mad_iu {
|
||||
struct viosrp_empty_iu empty_iu;
|
||||
struct viosrp_error_log error_log;
|
||||
struct viosrp_adapter_info adapter_info;
|
||||
struct viosrp_host_config host_config;
|
||||
struct viosrp_fast_fail fast_fail;
|
||||
struct viosrp_capabilities capabilities;
|
||||
};
|
||||
|
||||
union viosrp_iu {
|
||||
union srp_iu srp;
|
||||
union mad_iu mad;
|
||||
};
|
||||
|
||||
struct mad_adapter_info_data {
|
||||
char srp_version[8];
|
||||
char partition_name[96];
|
||||
u32 partition_number;
|
||||
u32 mad_version;
|
||||
u32 os_type;
|
||||
u32 port_max_txu[8]; /* per-port maximum transfer */
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user