More conversions towards SCST. There are still several to-do items left though.

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@2098 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Bart Van Assche
2010-09-11 18:20:24 +00:00
parent 6aa2ebca55
commit 2f289c967b
4 changed files with 393 additions and 237 deletions
+2 -3
View File
@@ -7,6 +7,5 @@ EXTRA_CFLAGS += -I$(IBMVSTGT_INC_DIR)
#EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
#EXTRA_CFLAGS += -Wextra -Wno-unused-parameter
obj-m := ibmvstgt.o
ibmvstgt-y += libsrpnew.o
ibmvstgt-y += ibmvstgt.o
obj-m += ibmvstgt.o
obj-m += libsrpnew.o
+356 -195
View File
@@ -24,15 +24,14 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_srp.h>
#ifdef INSIDE_KERNEL_TREE
#include <scst/scst.h>
#include <scst/scst_debug.h>
#else
#include "scst.h"
#include "scst_debug.h"
#endif
#include <scsi/libsrp.h>
#include "libsrpnew.h" /* <scsi/libsrp.h> */
#include <asm/iommu.h>
#ifdef __powerpc__
#include <asm/hvcall.h>
@@ -80,12 +79,10 @@ struct vio_port {
unsigned long liobn;
unsigned long riobn;
struct srp_target *target;
struct srp_rport *rport;
};
static atomic_t ibmvstgt_device_count;
static struct workqueue_struct *vtgtd;
static struct scsi_transport_template *ibmvstgt_transport_template;
/*
* These are fixed for the system and come from the Open Firmware device tree.
@@ -146,7 +143,7 @@ static int send_iu(struct iu_entry *iue, uint64_t length, uint8_t format)
#define SRP_RSP_SENSE_DATA_LEN 18
static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc,
static int send_rsp(struct iu_entry *iue, struct scst_cmd *sc,
unsigned char status, unsigned char asc)
{
union viosrp_iu *iu = vio_iu(iue);
@@ -175,9 +172,16 @@ static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc,
uint8_t *sense = iu->srp.rsp.data;
if (sc) {
uint8_t *sc_sense;
int sense_data_len;
sc_sense = scst_cmd_get_sense_buffer(sc);
sense_data_len = min(scst_cmd_get_sense_buffer_len(sc),
SRP_RSP_SENSE_DATA_LEN);
iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
iu->srp.rsp.sense_data_len = SCSI_SENSE_BUFFERSIZE;
memcpy(sense, sc->sense_buffer, SCSI_SENSE_BUFFERSIZE);
iu->srp.rsp.sense_data_len
= cpu_to_be32(sense_data_len);
memcpy(sense, sc_sense, sense_data_len);
} else {
iu->srp.rsp.status = SAM_STAT_CHECK_CONDITION;
iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
@@ -203,12 +207,12 @@ static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc,
static void handle_cmd_queue(struct srp_target *target)
{
struct scst_session *sess = target->sess;
struct srp_rport *rport = target_to_port(target)->rport;
struct iu_entry *iue;
struct srp_cmd *cmd;
unsigned long flags;
int err;
BUG_ON(!sess);
retry:
spin_lock_irqsave(&target->lock, flags);
@@ -216,8 +220,7 @@ retry:
if (!test_and_set_bit(V_FLYING, &iue->flags)) {
spin_unlock_irqrestore(&target->lock, flags);
cmd = iue->sbuf->buf;
err = srp_cmd_queue(sess, cmd, iue,
(unsigned long)rport);
err = srp_cmd_queue(sess, cmd, iue);
if (err) {
eprintk("cannot queue cmd %p %d\n", cmd, err);
srp_iu_put(iue);
@@ -229,11 +232,11 @@ retry:
spin_unlock_irqrestore(&target->lock, flags);
}
static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
static int ibmvstgt_rdma(struct scst_cmd *sc, struct scatterlist *sg, int nsg,
struct srp_direct_buf *md, int nmd,
enum dma_data_direction dir, unsigned int rest)
{
struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
struct iu_entry *iue = scst_cmd_get_tgt_priv(sc);
struct srp_target *target = iue->target;
struct vio_port *vport = target_to_port(target);
dma_addr_t token;
@@ -292,34 +295,146 @@ static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
return 0;
}
static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
void (*done)(struct scsi_cmnd *))
#if !defined(CONFIG_SCST_PROC)
/**
* ibmvstgt_enable_target() - Allows to enable a target via sysfs.
*/
static int ibmvstgt_enable_target(struct scst_tgt *scst_tgt, bool enable)
{
struct srp_target *target = scst_tgt_get_tgt_priv(scst_tgt);
EXTRACHECKS_WARN_ON_ONCE(irqs_disabled());
TRACE_DBG("%s target %s", enable ? "Enabling" : "Disabling",
target->sess ? target->sess->name : "???");
target->enabled = enable;
return 0;
}
/**
* ibmvstgt_is_target_enabled() - Allows to query a targets status via sysfs.
*/
static bool ibmvstgt_is_target_enabled(struct scst_tgt *scst_tgt)
{
struct srp_target *target = scst_tgt_get_tgt_priv(scst_tgt);
EXTRACHECKS_WARN_ON_ONCE(irqs_disabled());
return target->enabled;
}
#endif
/**
* ibmvstgt_detect() - Returns the number of target adapters.
*
* Callback function called by the SCST core.
*/
static int ibmvstgt_detect(struct scst_tgt_template *tp)
{
return atomic_read(&ibmvstgt_device_count);
}
/**
* ibmvstgt_release() - Free the resources associated with an SCST target.
*
* Callback function called by the SCST core from scst_unregister_target().
*/
static int ibmvstgt_release(struct scst_tgt *scst_tgt)
{
/* To do: implement this function. */
return 0;
}
/**
* ibmvstgt_xmit_response() - Transmits the response to a SCSI command.
*
* Callback function called by the SCST core. Must not block. Must ensure that
* scst_tgt_cmd_done() will get invoked when returning SCST_TGT_RES_SUCCESS.
*/
static int ibmvstgt_xmit_response(struct scst_cmd *sc)
{
struct iu_entry *iue = scst_cmd_get_tgt_priv(sc);
int ret = SCST_TGT_RES_SUCCESS;
enum dma_data_direction dir;
if (unlikely(scst_cmd_aborted(sc))) {
scst_set_delivery_status(sc, SCST_CMD_DELIVERY_ABORTED);
goto out;
}
dir = srp_cmd_direction(&vio_iu(iue)->srp.cmd);
WARN_ON(dir != DMA_FROM_DEVICE && dir != DMA_TO_DEVICE);
/* For read commands, transfer the data to the initiator. */
if (dir == DMA_FROM_DEVICE && scst_cmd_get_resp_data_len(sc)) {
ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
ibmvstgt_rdma, 1, 1);
if (ret != SCST_TGT_RES_SUCCESS) {
PRINT_ERROR("%s: tag= %llu xfer_data failed",
__func__, scst_cmd_get_tag(sc));
scst_set_cmd_error(sc,
SCST_LOAD_SENSE(scst_sense_read_error));
}
}
send_rsp(iue, sc, scst_cmd_get_status(sc), 0);
out:
scst_tgt_cmd_done(sc, SCST_CONTEXT_DIRECT);
return SCST_TGT_RES_SUCCESS;
}
/**
* ibmvstgt_rdy_to_xfer() - Transfers data from initiator to target.
*
* Called by the SCST core to transfer data from the initiator to the target
* (SCST_DATA_WRITE). Must not block.
*/
static int ibmvstgt_rdy_to_xfer(struct scst_cmd *sc)
{
struct iu_entry *iue = scst_cmd_get_tgt_priv(sc);
int ret = SCST_TGT_RES_SUCCESS;
enum dma_data_direction dir;
dir = srp_cmd_direction(&vio_iu(iue)->srp.cmd);
WARN_ON(dir != DMA_FROM_DEVICE && dir != DMA_TO_DEVICE);
/* For write commands, transfer the data from the initiator. */
if (dir == DMA_TO_DEVICE && scst_cmd_get_resp_data_len(sc)) {
ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
ibmvstgt_rdma, 1, 1);
if (ret != SCST_TGT_RES_SUCCESS) {
PRINT_ERROR("%s: tag= %llu xfer_data failed",
__func__, scst_cmd_get_tag(sc));
scst_set_cmd_error(sc,
SCST_LOAD_SENSE(scst_sense_write_error));
}
}
return SCST_TGT_RES_SUCCESS;
}
/**
* ibmvstgt_on_free_cmd() - Free command-private data.
*
* Called by the SCST core. May be called in IRQ context.
*/
static void ibmvstgt_on_free_cmd(struct scst_cmd *sc)
{
unsigned long flags;
struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
struct iu_entry *iue = scst_cmd_get_tgt_priv(sc);
struct srp_target *target = iue->target;
int err = 0;
dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0],
scsi_sg_count(sc));
if (scsi_sg_count(sc))
err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
spin_lock_irqsave(&target->lock, flags);
list_del(&iue->ilist);
spin_unlock_irqrestore(&target->lock, flags);
if (err|| sc->result != SAM_STAT_GOOD) {
eprintk("operation failed %p %d %x\n",
iue, sc->result, vio_iu(iue)->srp.cmd.cdb[0]);
send_rsp(iue, sc, HARDWARE_ERROR, 0x00);
} else
send_rsp(iue, sc, NO_SENSE, 0x00);
done(sc);
srp_iu_put(iue);
return 0;
}
int send_adapter_info(struct iu_entry *iue,
@@ -327,7 +442,6 @@ int send_adapter_info(struct iu_entry *iue,
{
struct srp_target *target = iue->target;
struct vio_port *vport = target_to_port(target);
struct scst_session *sess = target->sess;
dma_addr_t data_token;
struct mad_adapter_info_data *info;
int err;
@@ -355,7 +469,7 @@ int send_adapter_info(struct iu_entry *iue,
info->partition_number = partition_number;
info->mad_version = 1;
info->os_type = 2;
info->port_max_txu[0] = sess->hostt->max_sectors << 9;
info->port_max_txu[0] = 255 << 9;/*sess->hostt->max_sectors << 9;*/
/* Send our info to remote */
err = h_copy_rdma(sizeof(*info), vport->liobn, data_token,
@@ -375,31 +489,52 @@ static void process_login(struct iu_entry *iue)
{
union viosrp_iu *iu = vio_iu(iue);
struct srp_login_rsp *rsp = &iu->srp.login_rsp;
struct srp_login_rej *rej = &iu->srp.login_rej;
uint64_t tag = iu->srp.rsp.tag;
struct scst_session *sess = iue->target->sess;
struct srp_target *target = host_to_srp_target(sess);
struct scst_session *sess;
struct srp_target *target = iue->target;
struct vio_port *vport = target_to_port(target);
struct srp_rport_identifiers ids;
char name[16];
memset(&ids, 0, sizeof(ids));
sprintf(ids.port_id, "%x", vport->dma_dev->unit_address);
ids.roles = SRP_RPORT_ROLE_INITIATOR;
if (!vport->rport)
vport->rport = srp_rport_add(sess, &ids);
BUG_ON(target->sess);
memset(iu, 0, max(sizeof *rsp, sizeof *rej));
snprintf(name, sizeof(name), "%x", vport->dma_dev->unit_address);
BUG_ON(!target);
sess = scst_register_session(target->tgt, 0, name, target, NULL, NULL);
if (!sess) {
rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
TRACE_DBG("%s", "Failed to create SCST session");
goto reject;
}
target->sess = sess;
/* 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;
rsp->buf_fmt
= cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT);
send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT);
return;
reject:
rej->opcode = SRP_LOGIN_REJ;
rej->tag = tag;
rej->buf_fmt =
cpu_to_be16(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)
@@ -412,44 +547,131 @@ static inline void queue_cmd(struct iu_entry *iue)
spin_unlock_irqrestore(&target->lock, flags);
}
/**
* struct mgmt_ctx - management command context information.
* @iue: VIO SRP information unit associated with the management command.
* @sess: SCST session via which the management command has been received.
* @tag: SCSI tag of the management command.
*/
struct mgmt_ctx {
struct iu_entry *iue;
struct scst_session *sess;
};
static int process_tsk_mgmt(struct iu_entry *iue)
{
union viosrp_iu *iu = vio_iu(iue);
struct scst_session *sess = iue->target->sess;
int fn;
struct srp_tsk_mgmt *srp_tsk;
struct mgmt_ctx *mgmt_ctx;
int ret = 0;
dprintk("%p %u\n", iue, iu->srp.tsk_mgmt.tsk_mgmt_func);
srp_tsk = &iu->srp.tsk_mgmt;
switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
dprintk("%p %u\n", iue, srp_tsk->tsk_mgmt_func);
ret = SCST_MGMT_STATUS_FAILED;
mgmt_ctx = kmalloc(sizeof *mgmt_ctx, GFP_ATOMIC);
if (!mgmt_ctx)
goto err;
mgmt_ctx->iue = iue;
mgmt_ctx->sess = sess;
iu->srp.rsp.tag = srp_tsk->tag;
switch (srp_tsk->tsk_mgmt_func) {
case SRP_TSK_ABORT_TASK:
fn = ABORT_TASK;
ret = scst_rx_mgmt_fn_tag(sess, SCST_ABORT_TASK,
srp_tsk->task_tag,
SCST_ATOMIC, mgmt_ctx);
break;
case SRP_TSK_ABORT_TASK_SET:
fn = ABORT_TASK_SET;
ret = scst_rx_mgmt_fn_lun(sess, SCST_ABORT_TASK_SET,
(u8 *) &srp_tsk->lun,
sizeof srp_tsk->lun,
SCST_ATOMIC, mgmt_ctx);
break;
case SRP_TSK_CLEAR_TASK_SET:
fn = CLEAR_TASK_SET;
ret = scst_rx_mgmt_fn_lun(sess, SCST_CLEAR_TASK_SET,
(u8 *) &srp_tsk->lun,
sizeof srp_tsk->lun,
SCST_ATOMIC, mgmt_ctx);
break;
case SRP_TSK_LUN_RESET:
fn = LOGICAL_UNIT_RESET;
ret = scst_rx_mgmt_fn_lun(sess, SCST_LUN_RESET,
(u8 *) &srp_tsk->lun,
sizeof srp_tsk->lun,
SCST_ATOMIC, mgmt_ctx);
break;
case SRP_TSK_CLEAR_ACA:
fn = CLEAR_ACA;
ret = scst_rx_mgmt_fn_lun(sess, SCST_CLEAR_ACA,
(u8 *) &srp_tsk->lun,
sizeof srp_tsk->lun,
SCST_ATOMIC, mgmt_ctx);
break;
default:
fn = 0;
ret = SCST_MGMT_STATUS_FN_NOT_SUPPORTED;
}
if (fn)
scsi_tgt_tsk_mgmt_request(sess,
(unsigned long)sess,
fn,
iu->srp.tsk_mgmt.task_tag,
(struct scsi_lun *) &iu->srp.tsk_mgmt.lun,
iue);
else
send_rsp(iue, NULL, ILLEGAL_REQUEST, 0x20);
return !fn;
if (ret != SCST_MGMT_STATUS_SUCCESS)
goto err;
return ret;
err:
kfree(mgmt_ctx);
return ret;
}
enum {
/* See also table 24 in the T10 r16a document. */
SRP_TSK_MGMT_SUCCESS = 0x00,
SRP_TSK_MGMT_FUNC_NOT_SUPP = 0x04,
SRP_TSK_MGMT_FAILED = 0x05,
};
static u8 scst_to_srp_tsk_mgmt_status(const int scst_mgmt_status)
{
switch (scst_mgmt_status) {
case SCST_MGMT_STATUS_SUCCESS:
return SRP_TSK_MGMT_SUCCESS;
case SCST_MGMT_STATUS_FN_NOT_SUPPORTED:
return SRP_TSK_MGMT_FUNC_NOT_SUPP;
case SCST_MGMT_STATUS_TASK_NOT_EXIST:
case SCST_MGMT_STATUS_LUN_NOT_EXIST:
case SCST_MGMT_STATUS_REJECTED:
case SCST_MGMT_STATUS_FAILED:
default:
break;
}
return SRP_TSK_MGMT_FAILED;
}
static void ibmvstgt_tsk_mgmt_done(struct scst_mgmt_cmd *mcmnd)
{
struct mgmt_ctx *mgmt_ctx;
struct scst_session *sess;
struct iu_entry *iue;
union viosrp_iu *iu;
mgmt_ctx = scst_mgmt_cmd_get_tgt_priv(mcmnd);
BUG_ON(!mgmt_ctx);
sess = mgmt_ctx->sess;
BUG_ON(!sess);
iue = mgmt_ctx->iue;
BUG_ON(!iue);
iu = vio_iu(iue);
TRACE_DBG("%s: tsk_mgmt_done for tag= %lld status=%d",
__func__, mgmt_ctx->tag, scst_mgmt_cmd_get_status(mcmnd));
send_rsp(iue, NULL,
scst_to_srp_tsk_mgmt_status(scst_mgmt_cmd_get_status(mcmnd)),
0/*asc*/);
kfree(mgmt_ctx);
}
static int process_mad_iu(struct iu_entry *iue)
@@ -485,10 +707,10 @@ static int process_mad_iu(struct iu_entry *iue)
return 1;
}
static int process_srp_iu(struct iu_entry *iue)
static bool process_srp_iu(struct iu_entry *iue)
{
union viosrp_iu *iu = vio_iu(iue);
int done = 1;
bool done = true;
u8 opcode = iu->srp.rsp.opcode;
switch (opcode) {
@@ -496,7 +718,7 @@ static int process_srp_iu(struct iu_entry *iue)
process_login(iue);
break;
case SRP_TSK_MGMT:
done = process_tsk_mgmt(iue);
done = process_tsk_mgmt(iue) != SCST_MGMT_STATUS_SUCCESS;
break;
case SRP_CMD:
queue_cmd(iue);
@@ -733,65 +955,6 @@ static void handle_crq(struct work_struct *work)
handle_cmd_queue(target);
}
static int ibmvstgt_eh_abort_handler(struct scsi_cmnd *sc)
{
unsigned long flags;
struct iu_entry *iue = (struct iu_entry *) sc->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(struct scst_session *sess,
u64 itn_id, 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, NULL, status, asc);
srp_iu_put(iue);
return 0;
}
static int ibmvstgt_it_nexus_response(struct scst_session *sess, u64 itn_id,
int result)
{
struct srp_target *target = host_to_srp_target(sess);
struct vio_port *vport = target_to_port(target);
if (result) {
eprintk("%p %d\n", sess, result);
srp_rport_del(vport->rport);
vport->rport = NULL;
}
return 0;
}
static ssize_t system_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -807,40 +970,54 @@ static ssize_t partition_number_show(struct device *dev,
static ssize_t unit_address_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct scst_session *sess = class_to_shost(dev);
struct srp_target *target = host_to_srp_target(sess);
struct srp_target *target = container_of(dev, struct srp_target, dev2);
struct vio_port *vport = target_to_port(target);
return snprintf(buf, PAGE_SIZE, "%x\n", vport->dma_dev->unit_address);
}
static DEVICE_ATTR(system_id, S_IRUGO, system_id_show, NULL);
static DEVICE_ATTR(partition_number, S_IRUGO, partition_number_show, NULL);
static DEVICE_ATTR(unit_address, S_IRUGO, unit_address_show, NULL);
static struct device_attribute *ibmvstgt_attrs[] = {
&dev_attr_system_id,
&dev_attr_partition_number,
&dev_attr_unit_address,
NULL,
static struct class_attribute ibmvstgt_class_attrs[] = {
__ATTR_NULL,
};
static struct scsi_host_template ibmvstgt_sht = {
static struct device_attribute ibmvstgt_attrs[] = {
__ATTR(system_id, S_IRUGO, system_id_show, NULL),
__ATTR(partition_number, S_IRUGO, partition_number_show, NULL),
__ATTR(unit_address, S_IRUGO, unit_address_show, NULL),
__ATTR_NULL,
};
static void ibmvstgt_dev_release(struct device *dev)
{ }
static struct class ibmvstgt_class = {
.name = "ibmvstgt",
.dev_release = ibmvstgt_dev_release,
.class_attrs = ibmvstgt_class_attrs,
.dev_attrs = ibmvstgt_attrs,
};
static struct scst_tgt_template ibmvstgt_template = {
.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,
.eh_abort_handler = ibmvstgt_eh_abort_handler,
.shost_attrs = ibmvstgt_attrs,
.proc_name = TGT_NAME,
.supported_mode = MODE_TARGET,
.sg_tablesize = SCSI_MAX_SG_SEGMENTS,
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
.default_trace_flags = DEFAULT_IBMVSTGT_TRACE_FLAGS,
.trace_flags = &trace_flag,
#endif
#if !defined(CONFIG_SCST_PROC)
.enable_target = ibmvstgt_enable_target,
.is_target_enabled = ibmvstgt_is_target_enabled,
#endif
.detect = ibmvstgt_detect,
.release = ibmvstgt_release,
.xmit_response = ibmvstgt_xmit_response,
.rdy_to_xfer = ibmvstgt_rdy_to_xfer,
.on_free_cmd = ibmvstgt_on_free_cmd,
.task_mgmt_fn_done = ibmvstgt_tsk_mgmt_done,
};
static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
{
struct scst_session *sess;
struct scst_tgt *scst_tgt;
struct srp_target *target;
struct vio_port *vport;
unsigned int *dma, dma_size;
@@ -849,20 +1026,24 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
vport = kzalloc(sizeof(struct vio_port), GFP_KERNEL);
if (!vport)
return err;
sess = scsi_host_alloc(&ibmvstgt_sht, sizeof(struct srp_target));
if (!sess)
goto free_vport;
sess->transportt = ibmvstgt_transport_template;
target = host_to_srp_target(sess);
target->sess = sess;
target = kzalloc(sizeof(struct srp_target), GFP_KERNEL);
if (!target)
goto free_vport;
scst_tgt = scst_register_target(&ibmvstgt_template, NULL);
if (!scst_tgt)
goto free_target;
scst_tgt_set_tgt_priv(scst_tgt, target);
target->tgt = scst_tgt;
vport->dma_dev = dev;
target->ldata = vport;
vport->target = target;
err = srp_target_alloc(target, &dev->dev, INITIAL_SRP_LIMIT,
SRP_MAX_IU_LEN);
if (err)
goto put_host;
goto unregister_target;
dma = (unsigned int *) vio_get_attribute(dev, "ibm,my-dma-window",
&dma_size);
@@ -876,31 +1057,27 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
INIT_WORK(&vport->crq_work, handle_crq);
err = scsi_add_host(sess, target->dev);
err = crq_queue_create(&vport->crq_queue, target);
if (err)
goto free_srp_target;
#if 0
err = scsi_tgt_alloc_queue(sess);
if (err)
goto remove_host;
#endif
target->dev2.class = &ibmvstgt_class;
target->dev2.parent = &dev->dev;
dev_set_name(&target->dev2, "ibmvstgt-%d",
vport->dma_dev->unit_address);
if (device_register(&target->dev2))
/* to do: handle failure */;
err = crq_queue_create(&vport->crq_queue, target);
if (err)
goto free_queue;
atomic_inc(&ibmvstgt_device_count);
return 0;
free_queue:
#if 0
scsi_tgt_free_queue(sess);
remove_host:
#endif
scsi_remove_host(sess);
free_srp_target:
srp_target_free(target);
put_host:
scsi_host_put(sess);
unregister_target:
scst_unregister_target(scst_tgt);
free_target:
kfree(target);
free_vport:
kfree(vport);
return err;
@@ -909,18 +1086,15 @@ free_vport:
static int ibmvstgt_remove(struct vio_dev *dev)
{
struct srp_target *target = dev_get_drvdata(&dev->dev);
struct scst_session *sess = target->sess;
struct vio_port *vport = target->ldata;
atomic_dec(&ibmvstgt_device_count);
crq_queue_destroy(target);
srp_remove_host(sess);
scsi_remove_host(sess);
#if 0
scsi_tgt_free_queue(sess);
#endif
srp_target_free(target);
scst_unregister_target(target->tgt);
kfree(target);
kfree(vport);
scsi_host_put(sess);
return 0;
}
@@ -968,25 +1142,15 @@ static int get_system_info(void)
return 0;
}
static struct srp_function_template ibmvstgt_transport_functions = {
.tsk_mgmt_response = ibmvstgt_tsk_mgmt_response,
.it_nexus_response = ibmvstgt_it_nexus_response,
};
static int ibmvstgt_init(void)
{
int err = -ENOMEM;
printk("IBM eServer i/pSeries Virtual SCSI Target Driver\n");
ibmvstgt_transport_template =
srp_attach_transport(&ibmvstgt_transport_functions);
if (!ibmvstgt_transport_template)
return err;
vtgtd = create_workqueue("ibmvtgtd");
if (!vtgtd)
goto release_transport;
return err;
err = get_system_info();
if (err)
@@ -999,8 +1163,6 @@ static int ibmvstgt_init(void)
return 0;
destroy_wq:
destroy_workqueue(vtgtd);
release_transport:
srp_release_transport(ibmvstgt_transport_template);
return err;
}
@@ -1010,7 +1172,6 @@ static void ibmvstgt_exit(void)
destroy_workqueue(vtgtd);
vio_unregister_driver(&ibmvstgt_driver);
srp_release_transport(ibmvstgt_transport_template);
}
MODULE_DESCRIPTION("IBM Virtual SCSI Target");
+22 -28
View File
@@ -23,17 +23,8 @@
#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 "libsrpnew.h"
#ifdef INSIDE_KERNEL_TREE
#include <scst/scst.h>
#else
#include "scst.h"
#endif
enum srp_task_attributes {
SRP_SIMPLE_TASK = 0,
@@ -190,7 +181,7 @@ void srp_iu_put(struct iu_entry *iue)
}
EXPORT_SYMBOL_GPL(srp_iu_put);
static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
static int srp_direct_data(struct scst_cmd *sc, struct srp_direct_buf *md,
enum dma_data_direction dir, srp_rdma_t rdma_io,
int dma_map, int ext_desc)
{
@@ -199,19 +190,21 @@ static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
int err, nsg = 0, len;
if (dma_map) {
iue = (struct iu_entry *) sc->SCp.ptr;
sg = scsi_sglist(sc);
iue = scst_cmd_get_tgt_priv(sc);
sg = scst_cmd_get_sg(sc);
dprintk("%p %u %u %d\n", iue, scsi_bufflen(sc),
md->len, scsi_sg_count(sc));
md->len, scst_cmd_get_sg_cnt(sc));
nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
nsg = dma_map_sg(iue->target->dev, sg, scst_cmd_get_sg_cnt(sc),
DMA_BIDIRECTIONAL);
if (!nsg) {
printk("fail to map %p %d\n", iue, scsi_sg_count(sc));
printk(KERN_ERR "fail to map %p %d\n", iue,
scst_cmd_get_sg_cnt(sc));
return 0;
}
len = min(scsi_bufflen(sc), md->len);
len = min_t(int, scst_cmd_get_expected_transfer_len(sc),
md->len);
} else
len = md->len;
@@ -223,7 +216,7 @@ static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
return err;
}
static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
static int srp_indirect_data(struct scst_cmd *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)
@@ -236,8 +229,8 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
int nmd, nsg = 0, len;
if (dma_map || ext_desc) {
iue = (struct iu_entry *) sc->SCp.ptr;
sg = scsi_sglist(sc);
iue = scst_cmd_get_tgt_priv(sc);
sg = scst_cmd_get_sg(sc);
dprintk("%p %u %u %d %d\n",
iue, scsi_bufflen(sc), id->len,
@@ -276,14 +269,16 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
rdma:
if (dma_map) {
nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
nsg = dma_map_sg(iue->target->dev, sg, scst_cmd_get_sg_cnt(sc),
DMA_BIDIRECTIONAL);
if (!nsg) {
eprintk("fail to map %p %d\n", iue, scsi_sg_count(sc));
eprintk("fail to map %p %d\n", iue,
scst_cmd_get_sg_cnt(sc));
err = -EIO;
goto free_mem;
}
len = min(scsi_bufflen(sc), id->len);
len = min_t(int, scst_cmd_get_expected_transfer_len(sc),
id->len);
} else
len = id->len;
@@ -325,7 +320,7 @@ static int data_out_desc_size(struct srp_cmd *cmd)
* 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,
int srp_transfer_data(struct scst_cmd *sc, struct srp_cmd *cmd,
srp_rdma_t rdma_io, int dma_map, int ext_desc)
{
struct srp_direct_buf *md;
@@ -400,8 +395,7 @@ static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
return len;
}
int srp_cmd_queue(struct scst_session *sess, struct srp_cmd *cmd, void *info,
u64 itn_id)
int srp_cmd_queue(struct scst_session *sess, struct srp_cmd *cmd, void *info)
{
enum dma_data_direction dir;
struct scst_cmd *sc;
@@ -432,15 +426,15 @@ int srp_cmd_queue(struct scst_session *sess, struct srp_cmd *cmd, void *info,
cmd->lun, dir, len, tag, (unsigned long long) cmd->tag);
sc = scst_rx_cmd(sess, (u8 *) &cmd->lun, sizeof(cmd->lun),
cmd->cdb, 16, SCST_CONTEXT_THREAD);
cmd->cdb, sizeof(cmd->cdb), SCST_CONTEXT_THREAD);
if (!sc)
return -ENOMEM;
scst_cmd_set_queue_type(sc, tag);
scst_cmd_set_tag(sc, cmd->tag);
scst_cmd_set_tgt_priv(sc, info);
scst_cmd_set_expected(sc, dir == DMA_TO_DEVICE
? SCST_DATA_WRITE : SCST_DATA_READ, len);
scst_cmd_set_tgt_priv(sc, info);
scst_cmd_set_tag(sc, itn_id);
scst_cmd_init_done(sc, SCST_CONTEXT_THREAD);
return 0;
+13 -11
View File
@@ -3,9 +3,12 @@
#include <linux/list.h>
#include <linux/kfifo.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
#include <scsi/srp.h>
#ifdef INSIDE_KERNEL_TREE
#include <scst/scst.h>
#else
#include "scst.h"
#endif
enum iue_flags {
V_DIOVER,
@@ -29,8 +32,10 @@ struct srp_queue {
};
struct srp_target {
struct scst_tgt *tgt;
struct scst_session *sess;
struct device *dev;
struct device *dev; /* to do: invent a better name */
struct device dev2; /* to do: invent a better name */
spinlock_t lock;
struct list_head cmd_queue;
@@ -41,6 +46,8 @@ struct srp_target {
struct srp_buf **rx_ring;
void *ldata;
bool enabled;
};
struct iu_entry {
@@ -53,7 +60,7 @@ struct iu_entry {
struct srp_buf *sbuf;
};
typedef int (srp_rdma_t)(struct scsi_cmnd *, struct scatterlist *, int,
typedef int (srp_rdma_t)(struct scst_cmd *, struct scatterlist *, int,
struct srp_direct_buf *, int,
enum dma_data_direction, unsigned int);
extern int srp_target_alloc(struct srp_target *, struct device *, size_t, size_t);
@@ -62,16 +69,11 @@ 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_queue(struct scst_session *, struct srp_cmd *, void *, u64);
extern int srp_transfer_data(struct scsi_cmnd *, struct srp_cmd *,
extern int srp_cmd_queue(struct scst_session *, struct srp_cmd *, void *);
extern int srp_transfer_data(struct scst_cmd *, struct srp_cmd *,
srp_rdma_t, int, int);
static inline struct srp_target *host_to_srp_target(struct Scsi_Host *host)
{
return (struct srp_target *) host->hostdata;
}
static inline int srp_cmd_direction(struct srp_cmd *cmd)
{
return (cmd->buf_fmt >> 4) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;