mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-22 05:01:27 +00:00
Merged the ibmvstgt-port branch (svn merge -r2369:2654 https://scst.svn.sourceforge.net/svnroot/scst/branches/ibmvstgt-port).
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@2660 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -57,16 +57,22 @@
|
||||
|
||||
#include "ibmvscsi.h"
|
||||
|
||||
#define INITIAL_SRP_LIMIT 16
|
||||
#define DEFAULT_MAX_SECTORS 256
|
||||
#define VSCSI_REQ_LIM 16
|
||||
#define MAD_REQ_LIM 1
|
||||
#define SRP_REQ_LIM (VSCSI_REQ_LIM - MAD_REQ_LIM)
|
||||
/* Minimal trfr size that must be supported by a PAPR-compliant hypervisor. */
|
||||
#define MAX_H_COPY_RDMA (128*1024)
|
||||
|
||||
#define TGT_NAME "ibmvstgt"
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
|
||||
/* Force a compilation error if a constant expression is not a power of 2 */
|
||||
#define BUILD_BUG_ON_NOT_POWER_OF_2(n) \
|
||||
BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
|
||||
#endif
|
||||
/*
|
||||
* 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)\
|
||||
@@ -77,17 +83,25 @@
|
||||
/* tmp - will replace with SCSI logging stuff */
|
||||
#define eprintk(fmt, args...) \
|
||||
do { \
|
||||
printk("%s(%d) " fmt, __func__, __LINE__, ##args); \
|
||||
printk(KERN_ERR "%s(%d) " fmt, __func__, __LINE__, ##args); \
|
||||
} while (0)
|
||||
/* #define dprintk eprintk */
|
||||
#define dprintk(fmt, args...)
|
||||
|
||||
/* iu_entry.flags */
|
||||
enum iue_flags {
|
||||
V_DIOVER,
|
||||
V_WRITE,
|
||||
V_LINKED,
|
||||
};
|
||||
|
||||
struct vio_port {
|
||||
struct vio_dev *dma_dev;
|
||||
|
||||
struct crq_queue crq_queue;
|
||||
struct work_struct crq_work;
|
||||
|
||||
atomic_t req_lim_delta;
|
||||
unsigned long liobn;
|
||||
unsigned long riobn;
|
||||
struct srp_target *target;
|
||||
@@ -104,6 +118,8 @@ struct vio_port {
|
||||
|
||||
static atomic_t ibmvstgt_device_count;
|
||||
static struct workqueue_struct *vtgtd;
|
||||
static unsigned max_vdma_size = MAX_H_COPY_RDMA;
|
||||
static struct scst_tgt_template ibmvstgt_template;
|
||||
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
#define DEFAULT_IBMVSTGT_TRACE_FLAGS \
|
||||
@@ -121,6 +137,29 @@ static char system_id[64] = "";
|
||||
static char partition_name[97] = "UNKNOWN";
|
||||
static unsigned int partition_number = -1;
|
||||
|
||||
static long h_copy_rdma(u64 length, unsigned long siobn, dma_addr_t saddr,
|
||||
unsigned long diobn, dma_addr_t daddr)
|
||||
{
|
||||
u64 bytes_copied = 0;
|
||||
long rc;
|
||||
|
||||
while (bytes_copied < length) {
|
||||
u64 bytes_to_copy;
|
||||
|
||||
bytes_to_copy = min_t(u64, length - bytes_copied,
|
||||
max_vdma_size);
|
||||
rc = plpar_hcall_norets(H_COPY_RDMA, bytes_to_copy, siobn,
|
||||
saddr, diobn, daddr);
|
||||
if (rc != H_SUCCESS)
|
||||
return rc;
|
||||
|
||||
bytes_copied += bytes_to_copy;
|
||||
saddr += bytes_to_copy;
|
||||
daddr += bytes_to_copy;
|
||||
}
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static struct vio_port *target_to_port(struct srp_target *target)
|
||||
{
|
||||
return (struct vio_port *) target->ldata;
|
||||
@@ -160,6 +199,8 @@ static int send_iu(struct iu_entry *iue, uint64_t length, uint8_t format)
|
||||
else
|
||||
crq.cooked.status = 0x00;
|
||||
|
||||
srp_iu_put(iue);
|
||||
|
||||
rc1 = h_send_crq(vport->dma_dev->unit_address, crq.raw[0], crq.raw[1]);
|
||||
|
||||
if (rc1) {
|
||||
@@ -175,6 +216,8 @@ static int send_iu(struct iu_entry *iue, uint64_t length, uint8_t format)
|
||||
static int send_rsp(struct iu_entry *iue, struct scst_cmd *sc,
|
||||
unsigned char status, unsigned char asc)
|
||||
{
|
||||
struct srp_target *target = iue->target;
|
||||
struct vio_port *vport = target_to_port(target);
|
||||
union viosrp_iu *iu = vio_iu(iue);
|
||||
uint64_t tag = iu->srp.rsp.tag;
|
||||
|
||||
@@ -184,7 +227,8 @@ static int send_rsp(struct iu_entry *iue, struct scst_cmd *sc,
|
||||
|
||||
memset(iu, 0, sizeof(struct srp_rsp));
|
||||
iu->srp.rsp.opcode = SRP_RSP;
|
||||
iu->srp.rsp.req_lim_delta = 1;
|
||||
iu->srp.rsp.req_lim_delta = __constant_cpu_to_be32(1
|
||||
+ atomic_xchg(&vport->req_lim_delta, 0));
|
||||
iu->srp.rsp.tag = tag;
|
||||
|
||||
if (test_bit(V_DIOVER, &iue->flags))
|
||||
@@ -205,15 +249,20 @@ static int send_rsp(struct iu_entry *iue, struct scst_cmd *sc,
|
||||
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 = sense_data_len;
|
||||
memcpy(sense, sc_sense, sense_data_len);
|
||||
if (SCST_SENSE_VALID(sc_sense)) {
|
||||
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
|
||||
= 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;
|
||||
iu->srp.rsp.sense_data_len = SRP_RSP_SENSE_DATA_LEN;
|
||||
iu->srp.rsp.sense_data_len
|
||||
= __constant_cpu_to_be32(SRP_RSP_SENSE_DATA_LEN);
|
||||
|
||||
/* Valid bit and 'current errors' */
|
||||
sense[0] = (0x1 << 7 | 0x70);
|
||||
@@ -232,34 +281,6 @@ static int send_rsp(struct iu_entry *iue, struct scst_cmd *sc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_cmd_queue(struct srp_target *target)
|
||||
{
|
||||
struct vio_port *vport = target_to_port(target);
|
||||
struct scst_session *sess = vport->sess;
|
||||
struct iu_entry *iue;
|
||||
struct srp_cmd *cmd;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
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);
|
||||
cmd = iue->sbuf->buf;
|
||||
err = srp_cmd_queue(sess, cmd, iue);
|
||||
if (err) {
|
||||
eprintk("cannot queue cmd %p %d\n", cmd, err);
|
||||
srp_iu_put(iue);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&target->lock, flags);
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -269,7 +290,6 @@ static int ibmvstgt_rdma(struct scst_cmd *sc, struct scatterlist *sg, int nsg,
|
||||
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;
|
||||
@@ -278,22 +298,22 @@ static int ibmvstgt_rdma(struct scst_cmd *sc, struct scatterlist *sg, int nsg,
|
||||
for (i = 0; i < nmd && rest; i++) {
|
||||
unsigned int mdone, mlen;
|
||||
|
||||
mlen = min(rest, md[i].len);
|
||||
mlen = min(rest, be32_to_cpu(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);
|
||||
vport->riobn,
|
||||
be64_to_cpu(md[i].va) + mdone,
|
||||
vport->liobn,
|
||||
token + soff);
|
||||
else
|
||||
err = h_copy_rdma(slen,
|
||||
vport->liobn,
|
||||
token + soff,
|
||||
vport->riobn,
|
||||
md[i].va + mdone);
|
||||
vport->liobn,
|
||||
token + soff,
|
||||
vport->riobn,
|
||||
be64_to_cpu(md[i].va) + mdone);
|
||||
|
||||
if (err != H_SUCCESS) {
|
||||
eprintk("rdma error %d %d %ld\n", dir, slen, err);
|
||||
@@ -303,7 +323,6 @@ static int ibmvstgt_rdma(struct scst_cmd *sc, struct scatterlist *sg, int nsg,
|
||||
mlen -= slen;
|
||||
mdone += slen;
|
||||
soff += slen;
|
||||
done += slen;
|
||||
|
||||
if (soff == sg_dma_len(sg + sidx)) {
|
||||
sidx++;
|
||||
@@ -316,7 +335,7 @@ static int ibmvstgt_rdma(struct scst_cmd *sc, struct scatterlist *sg, int nsg,
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
rest -= mlen;
|
||||
}
|
||||
@@ -391,7 +410,8 @@ static int ibmvstgt_release(struct scst_tgt *scst_tgt)
|
||||
vport->releasing = true;
|
||||
spin_unlock_irqrestore(&target->lock, flags);
|
||||
|
||||
scst_unregister_session(sess, 0, NULL);
|
||||
if (sess)
|
||||
scst_unregister_session(sess, 0, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -405,23 +425,34 @@ static int ibmvstgt_release(struct scst_tgt *scst_tgt)
|
||||
static int ibmvstgt_xmit_response(struct scst_cmd *sc)
|
||||
{
|
||||
struct iu_entry *iue = scst_cmd_get_tgt_priv(sc);
|
||||
struct srp_target *target = iue->target;
|
||||
struct vio_port *vport = target_to_port(target);
|
||||
struct srp_cmd *srp_cmd;
|
||||
int ret;
|
||||
enum dma_data_direction dir;
|
||||
|
||||
if (unlikely(scst_cmd_aborted(sc))) {
|
||||
scst_set_delivery_status(sc, SCST_CMD_DELIVERY_ABORTED);
|
||||
atomic_inc(&vport->req_lim_delta);
|
||||
srp_iu_put(iue);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dir = srp_cmd_direction(&vio_iu(iue)->srp.cmd);
|
||||
srp_cmd = &vio_iu(iue)->srp.cmd;
|
||||
dir = srp_cmd_direction(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_adjusted_resp_data_len(sc)) {
|
||||
ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
|
||||
ibmvstgt_rdma, 1, 1);
|
||||
if (ret)
|
||||
ret = srp_transfer_data(sc, srp_cmd, ibmvstgt_rdma, true, true);
|
||||
if (ret == -ENOMEM)
|
||||
return SCST_TGT_RES_QUEUE_FULL;
|
||||
else if (ret) {
|
||||
PRINT_ERROR("%s: tag= %llu xmit_response failed",
|
||||
__func__, (long long unsigned)
|
||||
scst_cmd_get_tag(sc));
|
||||
scst_set_delivery_status(sc, SCST_CMD_DELIVERY_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
send_rsp(iue, sc, scst_cmd_get_status(sc), 0);
|
||||
@@ -441,17 +472,20 @@ out:
|
||||
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;
|
||||
struct srp_cmd *srp_cmd = &vio_iu(iue)->srp.cmd;
|
||||
int ret;
|
||||
|
||||
WARN_ON(srp_cmd_direction(&vio_iu(iue)->srp.cmd) != DMA_TO_DEVICE);
|
||||
WARN_ON(srp_cmd_direction(srp_cmd) != DMA_TO_DEVICE);
|
||||
|
||||
/* Transfer the data from the initiator to the target. */
|
||||
ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
|
||||
if (ret == 0) {
|
||||
ret = srp_transfer_data(sc, srp_cmd, ibmvstgt_rdma, true, true);
|
||||
if (ret == 0)
|
||||
scst_rx_data(sc, SCST_RX_STATUS_SUCCESS, SCST_CONTEXT_SAME);
|
||||
} else {
|
||||
else if (ret == -ENOMEM)
|
||||
return SCST_TGT_RES_QUEUE_FULL;
|
||||
else {
|
||||
PRINT_ERROR("%s: tag= %llu xfer_data failed", __func__,
|
||||
(long long unsigned)be64_to_cpu(scst_cmd_get_tag(sc)));
|
||||
(long long unsigned)scst_cmd_get_tag(sc));
|
||||
scst_rx_data(sc, SCST_RX_STATUS_ERROR, SCST_CONTEXT_SAME);
|
||||
}
|
||||
|
||||
@@ -465,15 +499,6 @@ static int ibmvstgt_rdy_to_xfer(struct scst_cmd *sc)
|
||||
*/
|
||||
static void ibmvstgt_on_free_cmd(struct scst_cmd *sc)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct iu_entry *iue = scst_cmd_get_tgt_priv(sc);
|
||||
struct srp_target *target = iue->target;
|
||||
|
||||
spin_lock_irqsave(&target->lock, flags);
|
||||
list_del(&iue->ilist);
|
||||
spin_unlock_irqrestore(&target->lock, flags);
|
||||
|
||||
srp_iu_put(iue);
|
||||
}
|
||||
|
||||
static int send_adapter_info(struct iu_entry *iue,
|
||||
@@ -508,7 +533,7 @@ static 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] = DEFAULT_MAX_SECTORS << 9;
|
||||
info->port_max_txu[0] = ibmvstgt_template.sg_tablesize * PAGE_SIZE;
|
||||
|
||||
/* Send our info to remote */
|
||||
err = h_copy_rdma(sizeof(*info), vport->liobn, data_token,
|
||||
@@ -535,7 +560,9 @@ static void process_login(struct iu_entry *iue)
|
||||
struct vio_port *vport = target_to_port(target);
|
||||
char name[16];
|
||||
|
||||
BUG_ON(vport->sess);
|
||||
BUG_ON(!target);
|
||||
BUG_ON(!target->tgt);
|
||||
BUG_ON(!vport);
|
||||
|
||||
memset(iu, 0, max(sizeof *rsp, sizeof *rej));
|
||||
|
||||
@@ -549,8 +576,14 @@ static void process_login(struct iu_entry *iue)
|
||||
goto reject;
|
||||
}
|
||||
|
||||
BUG_ON(!target);
|
||||
sess = scst_register_session(target->tgt, 0, name, target, NULL, NULL);
|
||||
if (vport->sess) {
|
||||
PRINT_INFO("Closing session %s (%p) because a new login request"
|
||||
" has been received", name, vport->sess);
|
||||
scst_unregister_session(vport->sess, 0, NULL);
|
||||
vport->sess = NULL;
|
||||
}
|
||||
|
||||
sess = scst_register_session(target->tgt, 0, name, vport, NULL, NULL);
|
||||
if (!sess) {
|
||||
rej->reason =
|
||||
__constant_cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
|
||||
@@ -564,10 +597,15 @@ static void process_login(struct iu_entry *iue)
|
||||
* buffer format is wrong
|
||||
*/
|
||||
rsp->opcode = SRP_LOGIN_RSP;
|
||||
rsp->req_lim_delta = INITIAL_SRP_LIMIT;
|
||||
/*
|
||||
* Avoid BUSY conditions by limiting the number of buffers used
|
||||
* for the SRP protocol to the SCST SCSI command queue size.
|
||||
*/
|
||||
rsp->req_lim_delta = cpu_to_be32(min(SRP_REQ_LIM,
|
||||
scst_get_max_lun_commands(NULL, 0)));
|
||||
rsp->tag = tag;
|
||||
rsp->max_it_iu_len = sizeof(union srp_iu);
|
||||
rsp->max_ti_iu_len = sizeof(union srp_iu);
|
||||
rsp->max_it_iu_len = __constant_cpu_to_be32(sizeof(union srp_iu));
|
||||
rsp->max_ti_iu_len = __constant_cpu_to_be32(sizeof(union srp_iu));
|
||||
/* direct and indirect */
|
||||
rsp->buf_fmt = __constant_cpu_to_be16(SRP_BUF_FORMAT_DIRECT
|
||||
| SRP_BUF_FORMAT_INDIRECT);
|
||||
@@ -585,16 +623,6 @@ reject:
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct mgmt_ctx - management command context information.
|
||||
* @iue: VIO SRP information unit associated with the management command.
|
||||
@@ -669,6 +697,7 @@ static int process_tsk_mgmt(struct iu_entry *iue)
|
||||
|
||||
err:
|
||||
kfree(mgmt_ctx);
|
||||
srp_iu_put(iue);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -715,7 +744,7 @@ static void ibmvstgt_tsk_mgmt_done(struct scst_mgmt_cmd *mcmnd)
|
||||
iu = vio_iu(iue);
|
||||
|
||||
TRACE_DBG("%s: tag %lld status %d",
|
||||
__func__, (long long unsigned)be64_to_cpu(iu->srp.rsp.tag),
|
||||
__func__, (long long unsigned)iu->srp.rsp.tag,
|
||||
scst_mgmt_cmd_get_status(mcmnd));
|
||||
|
||||
send_rsp(iue, NULL,
|
||||
@@ -725,7 +754,7 @@ static void ibmvstgt_tsk_mgmt_done(struct scst_mgmt_cmd *mcmnd)
|
||||
kfree(mgmt_ctx);
|
||||
}
|
||||
|
||||
static int process_mad_iu(struct iu_entry *iue)
|
||||
static void process_mad_iu(struct iu_entry *iue)
|
||||
{
|
||||
union viosrp_iu *iu = vio_iu(iue);
|
||||
struct viosrp_adapter_info *info;
|
||||
@@ -734,6 +763,7 @@ static int process_mad_iu(struct iu_entry *iue)
|
||||
switch (iu->mad.empty_iu.common.type) {
|
||||
case VIOSRP_EMPTY_IU_TYPE:
|
||||
eprintk("%s\n", "Unsupported EMPTY MAD IU");
|
||||
srp_iu_put(iue);
|
||||
break;
|
||||
case VIOSRP_ERROR_LOG_TYPE:
|
||||
eprintk("%s\n", "Unsupported ERROR LOG MAD IU");
|
||||
@@ -753,24 +783,24 @@ static int process_mad_iu(struct iu_entry *iue)
|
||||
break;
|
||||
default:
|
||||
eprintk("Unknown type %u\n", iu->srp.rsp.opcode);
|
||||
srp_iu_put(iue);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int process_srp_iu(struct iu_entry *iue)
|
||||
static void process_srp_iu(struct iu_entry *iue)
|
||||
{
|
||||
unsigned long flags;
|
||||
union viosrp_iu *iu = vio_iu(iue);
|
||||
struct srp_target *target = iue->target;
|
||||
struct vio_port *vport = target_to_port(target);
|
||||
int done = 1;
|
||||
int err;
|
||||
u8 opcode = iu->srp.rsp.opcode;
|
||||
|
||||
spin_lock_irqsave(&target->lock, flags);
|
||||
if (vport->releasing) {
|
||||
spin_unlock_irqrestore(&target->lock, flags);
|
||||
return done;
|
||||
srp_iu_put(iue);
|
||||
return;
|
||||
}
|
||||
spin_unlock_irqrestore(&target->lock, flags);
|
||||
|
||||
@@ -779,11 +809,14 @@ static int process_srp_iu(struct iu_entry *iue)
|
||||
process_login(iue);
|
||||
break;
|
||||
case SRP_TSK_MGMT:
|
||||
done = process_tsk_mgmt(iue) != SCST_MGMT_STATUS_SUCCESS;
|
||||
process_tsk_mgmt(iue);
|
||||
break;
|
||||
case SRP_CMD:
|
||||
queue_cmd(iue);
|
||||
done = 0;
|
||||
err = srp_cmd_queue(vport->sess, &iu->srp.cmd, iue);
|
||||
if (err) {
|
||||
eprintk("cannot queue cmd %p %d\n", &iu->srp.cmd, err);
|
||||
srp_iu_put(iue);
|
||||
}
|
||||
break;
|
||||
case SRP_LOGIN_RSP:
|
||||
case SRP_I_LOGOUT:
|
||||
@@ -794,12 +827,12 @@ static int process_srp_iu(struct iu_entry *iue)
|
||||
case SRP_AER_REQ:
|
||||
case SRP_AER_RSP:
|
||||
eprintk("Unsupported type %u\n", opcode);
|
||||
srp_iu_put(iue);
|
||||
break;
|
||||
default:
|
||||
eprintk("Unknown type %u\n", opcode);
|
||||
srp_iu_put(iue);
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
static void process_iu(struct viosrp_crq *crq, struct srp_target *target)
|
||||
@@ -807,7 +840,6 @@ 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;
|
||||
int done = 1;
|
||||
|
||||
iue = srp_iu_get(target);
|
||||
if (!iue) {
|
||||
@@ -822,16 +854,13 @@ static void process_iu(struct viosrp_crq *crq, struct srp_target *target)
|
||||
|
||||
if (err != H_SUCCESS) {
|
||||
eprintk("%ld transferring data error %p\n", err, iue);
|
||||
goto out;
|
||||
srp_iu_put(iue);
|
||||
}
|
||||
|
||||
if (crq->format == VIOSRP_MAD_FORMAT)
|
||||
done = process_mad_iu(iue);
|
||||
process_mad_iu(iue);
|
||||
else
|
||||
done = process_srp_iu(iue);
|
||||
out:
|
||||
if (done)
|
||||
srp_iu_put(iue);
|
||||
process_srp_iu(iue);
|
||||
}
|
||||
|
||||
#ifdef RHEL_MAJOR
|
||||
@@ -897,7 +926,7 @@ static int crq_queue_create(struct crq_queue *queue, struct srp_target *target)
|
||||
|
||||
vio_enable_interrupts(vport->dma_dev);
|
||||
|
||||
h_send_crq(vport->dma_dev->unit_address, 0xC001000000000000, 0);
|
||||
h_send_crq(vport->dma_dev->unit_address, 0xC001000000000000ULL, 0);
|
||||
|
||||
queue->cur = 0;
|
||||
spin_lock_init(&queue->lock);
|
||||
@@ -947,7 +976,7 @@ static void process_crq(struct viosrp_crq *crq, struct srp_target *target)
|
||||
switch (crq->format) {
|
||||
case 0x01:
|
||||
h_send_crq(vport->dma_dev->unit_address,
|
||||
0xC002000000000000, 0);
|
||||
0xC002000000000000ULL, 0);
|
||||
break;
|
||||
case 0x02:
|
||||
break;
|
||||
@@ -997,6 +1026,13 @@ static inline struct viosrp_crq *next_crq(struct crq_queue *queue)
|
||||
return crq;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_crq() - Process the command/response queue.
|
||||
*
|
||||
* Note: Although this function is not thread-safe because of how it is
|
||||
* scheduled it is guaranteed that this function is running on at most one CPU
|
||||
* at any given time.
|
||||
*/
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) && !defined(BACKPORT_LINUX_WORKQUEUE_TO_2_6_19)
|
||||
static void handle_crq(void *ctx)
|
||||
#else
|
||||
@@ -1028,8 +1064,97 @@ static void handle_crq(struct work_struct *work)
|
||||
} else
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
handle_cmd_queue(target);
|
||||
static void ibmvstgt_get_product_id(const struct scst_tgt_dev *tgt_dev,
|
||||
char *buf, const int size)
|
||||
{
|
||||
WARN_ON(size != 16);
|
||||
|
||||
/*
|
||||
* AIX uses hardcoded device names. The AIX SCSI initiator even won't
|
||||
* work unless we use the names VDASD and VOPTA.
|
||||
*/
|
||||
switch (tgt_dev->dev->type) {
|
||||
case TYPE_DISK:
|
||||
memcpy(buf, "VDASD blkdev ", 16);
|
||||
break;
|
||||
case TYPE_ROM:
|
||||
memcpy(buf, "VOPTA blkdev ", 16);
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, size, "(devtype %d) ", tgt_dev->dev->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract target, bus and LUN information from a 64-bit LUN in CPU-order.
|
||||
*/
|
||||
#define GETTARGET(x) ((((uint16_t)(x) >> 8) & 0x003f))
|
||||
#define GETBUS(x) ((((uint16_t)(x) >> 5) & 0x0007))
|
||||
#define GETLUN(x) ((((uint16_t)(x) >> 0) & 0x001f))
|
||||
|
||||
static int ibmvstgt_get_serial(const struct scst_tgt_dev *tgt_dev, char *buf,
|
||||
int size)
|
||||
{
|
||||
struct scst_session *sess = tgt_dev->sess;
|
||||
struct vio_port *vport = scst_sess_get_tgt_priv(sess);
|
||||
uint64_t lun = tgt_dev->lun;
|
||||
|
||||
return snprintf(buf, size,
|
||||
"IBM-VSCSI-%s-P%d-%x-%d-%d-%d\n",
|
||||
system_id, partition_number,
|
||||
vport->dma_dev->unit_address,
|
||||
GETBUS(lun), GETTARGET(lun), GETLUN(lun));
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvstgt_get_transportid() - SCST TransportID callback function.
|
||||
*
|
||||
* See also SPC-3, section 7.5.4.5, TransportID for initiator ports using SRP.
|
||||
*/
|
||||
static int ibmvstgt_get_transportid(struct scst_session *sess,
|
||||
uint8_t **transport_id)
|
||||
{
|
||||
struct vio_port *vport;
|
||||
struct spc_rdma_transport_id {
|
||||
uint8_t protocol_identifier;
|
||||
uint8_t reserved[7];
|
||||
union {
|
||||
uint8_t id8[16];
|
||||
__be32 id32[4];
|
||||
} i_port_id;
|
||||
};
|
||||
struct spc_rdma_transport_id *tr_id;
|
||||
int res;
|
||||
|
||||
if (!sess) {
|
||||
res = SCSI_TRANSPORTID_PROTOCOLID_SRP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vport = scst_sess_get_tgt_priv(sess);
|
||||
BUG_ON(!vport);
|
||||
|
||||
BUILD_BUG_ON(sizeof(*tr_id) != 24);
|
||||
|
||||
res = -ENOMEM;
|
||||
tr_id = kzalloc(sizeof(struct spc_rdma_transport_id), GFP_KERNEL);
|
||||
if (!tr_id) {
|
||||
PRINT_ERROR("%s", "Allocation of TransportID failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
tr_id->protocol_identifier = SCSI_TRANSPORTID_PROTOCOLID_SRP;
|
||||
memset(&tr_id->i_port_id, 0, sizeof(tr_id->i_port_id));
|
||||
tr_id->i_port_id.id32[3] = cpu_to_be32(vport->dma_dev->unit_address);
|
||||
|
||||
*transport_id = (uint8_t *)tr_id;
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
|
||||
@@ -1102,11 +1227,19 @@ static struct class ibmvstgt_class = {
|
||||
|
||||
static struct scst_tgt_template ibmvstgt_template = {
|
||||
.name = TGT_NAME,
|
||||
.preferred_addr_method = SCST_LUN_ADDR_METHOD_LUN,
|
||||
#ifdef RHEL_MAJOR
|
||||
.sg_tablesize = 1024,
|
||||
#else
|
||||
.sg_tablesize = SCSI_MAX_SG_SEGMENTS,
|
||||
#endif
|
||||
.vendor = "IBM ",
|
||||
.revision = "0001",
|
||||
.fake_aca = true,
|
||||
.get_product_id = ibmvstgt_get_product_id,
|
||||
.get_serial = ibmvstgt_get_serial,
|
||||
.get_vend_specific = ibmvstgt_get_serial,
|
||||
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = DEFAULT_IBMVSTGT_TRACE_FLAGS,
|
||||
.trace_flags = &trace_flag,
|
||||
@@ -1121,6 +1254,7 @@ static struct scst_tgt_template ibmvstgt_template = {
|
||||
.rdy_to_xfer = ibmvstgt_rdy_to_xfer,
|
||||
.on_free_cmd = ibmvstgt_on_free_cmd,
|
||||
.task_mgmt_fn_done = ibmvstgt_tsk_mgmt_done,
|
||||
.get_initiator_port_transport_id = ibmvstgt_get_transportid,
|
||||
};
|
||||
|
||||
static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
|
||||
@@ -1128,7 +1262,8 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
|
||||
struct scst_tgt *scst_tgt;
|
||||
struct srp_target *target;
|
||||
struct vio_port *vport;
|
||||
unsigned int *dma, dma_size;
|
||||
const unsigned int *dma;
|
||||
unsigned dma_size;
|
||||
int err = -ENOMEM;
|
||||
|
||||
vport = kzalloc(sizeof(struct vio_port), GFP_KERNEL);
|
||||
@@ -1148,13 +1283,13 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
|
||||
vport->dma_dev = dev;
|
||||
target->ldata = vport;
|
||||
vport->target = target;
|
||||
err = srp_target_alloc(target, &dev->dev, INITIAL_SRP_LIMIT,
|
||||
BUILD_BUG_ON_NOT_POWER_OF_2(VSCSI_REQ_LIM);
|
||||
err = srp_target_alloc(target, &dev->dev, VSCSI_REQ_LIM,
|
||||
SRP_MAX_IU_LEN);
|
||||
if (err)
|
||||
goto unregister_target;
|
||||
|
||||
dma = (unsigned int *) vio_get_attribute(dev, "ibm,my-dma-window",
|
||||
&dma_size);
|
||||
dma = 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;
|
||||
@@ -1179,9 +1314,12 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
|
||||
#else
|
||||
vport->dev.parent = &dev->dev;
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
|
||||
snprintf(vport->dev.class_id, BUS_ID_SIZE, "ibmvstgt-%d",
|
||||
vport->dma_dev->unit_address);
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
|
||||
snprintf(vport->dev.bus_id, BUS_ID_SIZE, "ibmvstgt-%d",
|
||||
vport->dma_dev->unit_address);
|
||||
#else
|
||||
dev_set_name(&vport->dev, "ibmvstgt-%d",
|
||||
vport->dma_dev->unit_address);
|
||||
@@ -1212,11 +1350,21 @@ free_vport:
|
||||
|
||||
static int ibmvstgt_remove(struct vio_dev *dev)
|
||||
{
|
||||
struct srp_target *target = dev_get_drvdata(&dev->dev);
|
||||
struct vio_port *vport = target->ldata;
|
||||
struct srp_target *target;
|
||||
struct vio_port *vport;
|
||||
|
||||
target = dev_get_drvdata(&dev->dev);
|
||||
if (!target)
|
||||
return 0;
|
||||
|
||||
atomic_dec(&ibmvstgt_device_count);
|
||||
|
||||
vport = target->ldata;
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
|
||||
class_device_unregister(&vport->dev);
|
||||
#else
|
||||
device_unregister(&vport->dev);
|
||||
#endif
|
||||
crq_queue_destroy(target);
|
||||
srp_target_free(target);
|
||||
scst_unregister_target(target->tgt);
|
||||
@@ -1225,6 +1373,65 @@ static int ibmvstgt_remove(struct vio_dev *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
static int ibmvstgt_trace_level_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
return scst_proc_log_entry_read(seq, trace_flag, NULL);
|
||||
}
|
||||
|
||||
static ssize_t ibmvstgt_proc_trace_level_write(struct file *file,
|
||||
const char __user *buf, size_t length, loff_t *off)
|
||||
{
|
||||
return scst_proc_log_entry_write(file, buf, length, &trace_flag,
|
||||
DEFAULT_IBMVSTGT_TRACE_FLAGS, NULL);
|
||||
}
|
||||
|
||||
static struct scst_proc_data ibmvstgt_log_proc_data = {
|
||||
SCST_DEF_RW_SEQ_OP(ibmvstgt_proc_trace_level_write)
|
||||
.show = ibmvstgt_trace_level_show,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int ibmvstgt_register_procfs_entry(struct scst_tgt_template *tgt)
|
||||
{
|
||||
int res = -ENOMEM;
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
struct proc_dir_entry *p, *root;
|
||||
|
||||
root = scst_proc_get_tgt_root(tgt);
|
||||
if (!root)
|
||||
goto out;
|
||||
/*
|
||||
* Fill in the scst_proc_data::data pointer, which is used in
|
||||
* a printk(KERN_INFO ...) statement in
|
||||
* scst_proc_log_entry_write() in scst_proc.c.
|
||||
*/
|
||||
ibmvstgt_log_proc_data.data = (char *)tgt->name;
|
||||
p = scst_create_proc_entry(root, "trace_level",
|
||||
&ibmvstgt_log_proc_data);
|
||||
if (p)
|
||||
res = 0;
|
||||
#endif
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static void ibmvstgt_unregister_procfs_entry(struct scst_tgt_template *tgt)
|
||||
{
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
struct proc_dir_entry *root;
|
||||
|
||||
root = scst_proc_get_tgt_root(tgt);
|
||||
if (!root)
|
||||
goto out;
|
||||
remove_proc_entry("trace_level", root);
|
||||
out:
|
||||
;
|
||||
#endif
|
||||
}
|
||||
#endif /*CONFIG_SCST_PROC*/
|
||||
|
||||
static struct vio_device_id ibmvstgt_device_table[] __devinitdata = {
|
||||
{"v-scsi-host", "IBM,v-scsi-host"},
|
||||
{"",""}
|
||||
@@ -1244,7 +1451,7 @@ static struct vio_driver ibmvstgt_driver = {
|
||||
|
||||
static int get_system_info(void)
|
||||
{
|
||||
struct device_node *rootdn;
|
||||
struct device_node *rootdn, *vdevdn;
|
||||
const char *id, *model, *name;
|
||||
const unsigned int *num;
|
||||
|
||||
@@ -1266,6 +1473,18 @@ static int get_system_info(void)
|
||||
partition_number = *num;
|
||||
|
||||
of_node_put(rootdn);
|
||||
|
||||
vdevdn = of_find_node_by_path("/vdevice");
|
||||
if (vdevdn) {
|
||||
const unsigned *mvds;
|
||||
|
||||
mvds = of_get_property(vdevdn, "ibm,max-virtual-dma-size",
|
||||
NULL);
|
||||
if (mvds)
|
||||
max_vdma_size = *mvds;
|
||||
of_node_put(vdevdn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1281,7 +1500,11 @@ static int __init ibmvstgt_init(void)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
|
||||
printk("IBM eServer i/pSeries Virtual SCSI Target Driver\n");
|
||||
printk(KERN_INFO "IBM eServer i/pSeries Virtual SCSI Target Driver\n");
|
||||
|
||||
err = get_system_info();
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = class_register(&ibmvstgt_class);
|
||||
if (err)
|
||||
@@ -1295,16 +1518,22 @@ static int __init ibmvstgt_init(void)
|
||||
if (!vtgtd)
|
||||
goto unregister_tgt;
|
||||
|
||||
err = get_system_info();
|
||||
if (err)
|
||||
goto destroy_wq;
|
||||
|
||||
err = vio_register_driver(&ibmvstgt_driver);
|
||||
if (err)
|
||||
goto destroy_wq;
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
err = ibmvstgt_register_procfs_entry(&ibmvstgt_template);
|
||||
if (err)
|
||||
goto unregister_driver;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
unregister_driver:
|
||||
vio_unregister_driver(&ibmvstgt_driver);
|
||||
#endif
|
||||
destroy_wq:
|
||||
destroy_workqueue(vtgtd);
|
||||
unregister_tgt:
|
||||
@@ -1317,8 +1546,11 @@ out:
|
||||
|
||||
static void __exit ibmvstgt_exit(void)
|
||||
{
|
||||
printk("Unregister IBM virtual SCSI driver\n");
|
||||
printk(KERN_INFO "Unregister IBM virtual SCSI driver\n");
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
ibmvstgt_unregister_procfs_entry(&ibmvstgt_template);
|
||||
#endif
|
||||
vio_unregister_driver(&ibmvstgt_driver);
|
||||
destroy_workqueue(vtgtd);
|
||||
scst_unregister_target_template(&ibmvstgt_template);
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
/* tmp - will replace with SCSI logging stuff */
|
||||
#define eprintk(fmt, args...) \
|
||||
do { \
|
||||
printk("%s(%d) " fmt, __func__, __LINE__, ##args); \
|
||||
printk(KERN_ERR "%s(%d) " fmt, __func__, __LINE__, ##args); \
|
||||
} while (0)
|
||||
/* #define dprintk eprintk */
|
||||
#define dprintk(fmt, args...)
|
||||
@@ -139,10 +139,8 @@ int srp_target_alloc(struct srp_target *target, struct device *dev,
|
||||
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;
|
||||
@@ -152,6 +150,7 @@ int srp_target_alloc(struct srp_target *target, struct device *dev,
|
||||
err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring);
|
||||
if (err)
|
||||
goto free_ring;
|
||||
dev_set_drvdata(target->dev, target);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -163,6 +162,7 @@ EXPORT_SYMBOL_GPL(srp_target_alloc);
|
||||
|
||||
void srp_target_free(struct srp_target *target)
|
||||
{
|
||||
dev_set_drvdata(target->dev, NULL);
|
||||
srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size,
|
||||
target->srp_iu_size);
|
||||
srp_iu_pool_free(&target->iu_queue);
|
||||
@@ -185,7 +185,6 @@ struct iu_entry *srp_iu_get(struct srp_target *target)
|
||||
if (!iue)
|
||||
return iue;
|
||||
iue->target = target;
|
||||
INIT_LIST_HEAD(&iue->ilist);
|
||||
iue->flags = 0;
|
||||
return iue;
|
||||
}
|
||||
@@ -204,39 +203,42 @@ EXPORT_SYMBOL_GPL(srp_iu_put);
|
||||
|
||||
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)
|
||||
int dma_map)
|
||||
{
|
||||
struct iu_entry *iue = NULL;
|
||||
struct scatterlist *sg = NULL;
|
||||
int err, nsg = 0, len, sg_cnt;
|
||||
u32 tsize;
|
||||
enum dma_data_direction dma_dir;
|
||||
|
||||
iue = scst_cmd_get_tgt_priv(sc);
|
||||
if (dir == DMA_TO_DEVICE) {
|
||||
scst_cmd_get_write_fields(sc, &sg, &sg_cnt);
|
||||
tsize = scst_cmd_get_bufflen(sc);
|
||||
dma_dir = DMA_FROM_DEVICE;
|
||||
} else {
|
||||
sg = scst_cmd_get_sg(sc);
|
||||
sg_cnt = scst_cmd_get_sg_cnt(sc);
|
||||
tsize = scst_cmd_get_adjusted_resp_data_len(sc);
|
||||
dma_dir = DMA_TO_DEVICE;
|
||||
}
|
||||
|
||||
dprintk("%p %u %u %d\n", iue, tsize, be32_to_cpu(md->len), sg_cnt);
|
||||
|
||||
len = min(tsize, be32_to_cpu(md->len));
|
||||
|
||||
if (dma_map) {
|
||||
iue = scst_cmd_get_tgt_priv(sc);
|
||||
if (dir == DMA_TO_DEVICE) {
|
||||
scst_cmd_get_write_fields(sc, &sg, &sg_cnt);
|
||||
} else {
|
||||
sg = scst_cmd_get_sg(sc);
|
||||
sg_cnt = scst_cmd_get_sg_cnt(sc);
|
||||
}
|
||||
|
||||
dprintk("%p %u %u %d\n", iue, scsi_bufflen(sc),
|
||||
md->len, sg_cnt);
|
||||
|
||||
nsg = dma_map_sg(iue->target->dev, sg, sg_cnt,
|
||||
DMA_BIDIRECTIONAL);
|
||||
nsg = dma_map_sg(iue->target->dev, sg, sg_cnt, dma_dir);
|
||||
if (!nsg) {
|
||||
printk(KERN_ERR "fail to map %p %d\n", iue, sg_cnt);
|
||||
return 0;
|
||||
eprintk(KERN_ERR "fail to map %p %d\n", iue, sg_cnt);
|
||||
return -ENOMEM;
|
||||
}
|
||||
len = min_t(unsigned, scst_cmd_get_expected_transfer_len(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);
|
||||
dma_unmap_sg(iue->target->dev, sg, nsg, dma_dir);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -251,23 +253,29 @@ static int srp_indirect_data(struct scst_cmd *sc, struct srp_cmd *cmd,
|
||||
struct scatterlist dummy, *sg = NULL;
|
||||
dma_addr_t token = 0;
|
||||
int err = 0;
|
||||
int nmd, nsg = 0, len, sg_cnt;
|
||||
int nmd, nsg = 0, len, sg_cnt = 0;
|
||||
u32 tsize = 0;
|
||||
enum dma_data_direction dma_dir;
|
||||
|
||||
if (dma_map || ext_desc) {
|
||||
iue = scst_cmd_get_tgt_priv(sc);
|
||||
if (dir == DMA_TO_DEVICE) {
|
||||
scst_cmd_get_write_fields(sc, &sg, &sg_cnt);
|
||||
} else {
|
||||
sg = scst_cmd_get_sg(sc);
|
||||
sg_cnt = scst_cmd_get_sg_cnt(sc);
|
||||
}
|
||||
|
||||
dprintk("%p %u %u %d %d\n",
|
||||
iue, scsi_bufflen(sc), id->len,
|
||||
cmd->data_in_desc_cnt, cmd->data_out_desc_cnt);
|
||||
iue = scst_cmd_get_tgt_priv(sc);
|
||||
if (dir == DMA_TO_DEVICE) {
|
||||
scst_cmd_get_write_fields(sc, &sg, &sg_cnt);
|
||||
tsize = scst_cmd_get_bufflen(sc);
|
||||
dma_dir = DMA_FROM_DEVICE;
|
||||
} else {
|
||||
sg = scst_cmd_get_sg(sc);
|
||||
sg_cnt = scst_cmd_get_sg_cnt(sc);
|
||||
tsize = scst_cmd_get_adjusted_resp_data_len(sc);
|
||||
dma_dir = DMA_TO_DEVICE;
|
||||
}
|
||||
|
||||
nmd = id->table_desc.len / sizeof(struct srp_direct_buf);
|
||||
dprintk("%p %u %u %d %d\n", iue, tsize, be32_to_cpu(id->len),
|
||||
be32_to_cpu(cmd->data_in_desc_cnt),
|
||||
be32_to_cpu(cmd->data_out_desc_cnt));
|
||||
|
||||
len = min(tsize, be32_to_cpu(id->len));
|
||||
|
||||
nmd = be32_to_cpu(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)) {
|
||||
@@ -276,18 +284,19 @@ static int srp_indirect_data(struct scst_cmd *sc, struct srp_cmd *cmd,
|
||||
}
|
||||
|
||||
if (ext_desc && dma_map) {
|
||||
md = dma_alloc_coherent(iue->target->dev, id->table_desc.len,
|
||||
&token, GFP_KERNEL);
|
||||
md = dma_alloc_coherent(iue->target->dev,
|
||||
be32_to_cpu(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_init_one(&dummy, md, be32_to_cpu(id->table_desc.len));
|
||||
sg_dma_address(&dummy) = token;
|
||||
sg_dma_len(&dummy) = id->table_desc.len;
|
||||
sg_dma_len(&dummy) = be32_to_cpu(id->table_desc.len);
|
||||
err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
|
||||
id->table_desc.len);
|
||||
be32_to_cpu(id->table_desc.len));
|
||||
if (err) {
|
||||
eprintk("Error copying indirect table %d\n", err);
|
||||
goto free_mem;
|
||||
@@ -299,26 +308,23 @@ static int srp_indirect_data(struct scst_cmd *sc, struct srp_cmd *cmd,
|
||||
|
||||
rdma:
|
||||
if (dma_map) {
|
||||
nsg = dma_map_sg(iue->target->dev, sg, sg_cnt,
|
||||
DMA_BIDIRECTIONAL);
|
||||
nsg = dma_map_sg(iue->target->dev, sg, sg_cnt, dma_dir);
|
||||
if (!nsg) {
|
||||
eprintk("fail to map %p %d\n", iue, sg_cnt);
|
||||
err = -EIO;
|
||||
err = -ENOMEM;
|
||||
goto free_mem;
|
||||
}
|
||||
len = min_t(unsigned, scst_cmd_get_expected_transfer_len(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);
|
||||
dma_unmap_sg(iue->target->dev, sg, nsg, dma_dir);
|
||||
|
||||
free_mem:
|
||||
if (token && dma_map)
|
||||
dma_free_coherent(iue->target->dev, id->table_desc.len, md, token);
|
||||
dma_free_coherent(iue->target->dev,
|
||||
be32_to_cpu(id->table_desc.len), md, token);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -345,10 +351,6 @@ static int data_out_desc_size(struct srp_cmd *cmd)
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: this can be called multiple times for a single command if it
|
||||
* has very long data.
|
||||
*/
|
||||
int srp_transfer_data(struct scst_cmd *sc, struct srp_cmd *cmd,
|
||||
srp_rdma_t rdma_io, int dma_map, int ext_desc)
|
||||
{
|
||||
@@ -375,7 +377,7 @@ int srp_transfer_data(struct scst_cmd *sc, struct srp_cmd *cmd,
|
||||
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);
|
||||
err = srp_direct_data(sc, md, dir, rdma_io, dma_map);
|
||||
break;
|
||||
case SRP_DATA_DESC_INDIRECT:
|
||||
id = (struct srp_indirect_buf *)
|
||||
@@ -392,7 +394,7 @@ int srp_transfer_data(struct scst_cmd *sc, struct srp_cmd *cmd,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(srp_transfer_data);
|
||||
|
||||
static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
|
||||
int srp_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
|
||||
{
|
||||
struct srp_direct_buf *md;
|
||||
struct srp_indirect_buf *id;
|
||||
@@ -411,11 +413,11 @@ static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
|
||||
break;
|
||||
case SRP_DATA_DESC_DIRECT:
|
||||
md = (struct srp_direct_buf *) (cmd->add_data + offset);
|
||||
len = md->len;
|
||||
len = be32_to_cpu(md->len);
|
||||
break;
|
||||
case SRP_DATA_DESC_INDIRECT:
|
||||
id = (struct srp_indirect_buf *) (cmd->add_data + offset);
|
||||
len = id->len;
|
||||
len = be32_to_cpu(id->len);
|
||||
break;
|
||||
default:
|
||||
eprintk("invalid data format %x\n", fmt);
|
||||
@@ -423,6 +425,7 @@ static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
|
||||
}
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(srp_data_length);
|
||||
|
||||
int srp_cmd_queue(struct scst_session *sess, struct srp_cmd *cmd, void *info)
|
||||
{
|
||||
@@ -449,7 +452,7 @@ int srp_cmd_queue(struct scst_session *sess, struct srp_cmd *cmd, void *info)
|
||||
}
|
||||
|
||||
dir = srp_cmd_direction(cmd);
|
||||
len = vscsis_data_length(cmd, dir);
|
||||
len = srp_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);
|
||||
|
||||
@@ -10,13 +10,6 @@
|
||||
#endif
|
||||
#include <scsi/srp.h>
|
||||
|
||||
enum iue_flags {
|
||||
V_DIOVER,
|
||||
V_WRITE,
|
||||
V_LINKED,
|
||||
V_FLYING,
|
||||
};
|
||||
|
||||
struct srp_buf {
|
||||
dma_addr_t dma;
|
||||
void *buf;
|
||||
@@ -38,7 +31,6 @@ struct srp_target {
|
||||
struct device *dev;
|
||||
|
||||
spinlock_t lock;
|
||||
struct list_head cmd_queue;
|
||||
|
||||
size_t srp_iu_size;
|
||||
struct srp_queue iu_queue;
|
||||
@@ -51,7 +43,6 @@ struct srp_target {
|
||||
struct iu_entry {
|
||||
struct srp_target *target;
|
||||
|
||||
struct list_head ilist;
|
||||
dma_addr_t remote_token;
|
||||
unsigned long flags;
|
||||
|
||||
@@ -67,6 +58,7 @@ 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_data_length(struct srp_cmd *, enum dma_data_direction);
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user