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:
Bart Van Assche
2010-11-11 09:14:32 +00:00
parent 972959d11a
commit 17d6ca9cea
3 changed files with 423 additions and 196 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);