Commit cb38b453 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'scsi-target-for-v4.10' of...

Merge branch 'scsi-target-for-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/bvanassche/linux

Pull scsi target fixes from Bart Van Assche:

 - a series of bug fixes for the XCOPY implementation from David
   Disseldorp

 - one bug fix for the ibmvscsis driver, a driver that is used for
   communication between partitions on IBM POWER systems.

* 'scsi-target-for-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/bvanassche/linux:
  ibmvscsis: Fix srp_transfer_data fail return code
  target: support XCOPY requests without parameters
  target: check for XCOPY parameter truncation
  target: use XCOPY segment descriptor CSCD IDs
  target: check XCOPY segment descriptor CSCD IDs
  target: simplify XCOPY wwn->se_dev lookup helper
  target: return UNSUPPORTED TARGET/SEGMENT DESC TYPE CODE sense
  target: bounds check XCOPY total descriptor list length
  target: bounds check XCOPY segment descriptor list
  target: use XCOPY TOO MANY TARGET DESCRIPTORS sense
  target: add XCOPY target/segment desc sense codes
parents 607ae5f2 7c9d8d0c
......@@ -3585,7 +3585,7 @@ static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
1, 1);
if (rc) {
pr_err("srp_transfer_data() failed: %d\n", rc);
return -EAGAIN;
return -EIO;
}
/*
* We now tell TCM to add this WRITE CDB directly into the TCM storage
......
......@@ -1693,6 +1693,10 @@ void transport_generic_request_failure(struct se_cmd *cmd,
case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE:
case TCM_TOO_MANY_TARGET_DESCS:
case TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE:
case TCM_TOO_MANY_SEGMENT_DESCS:
case TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE:
break;
case TCM_OUT_OF_RESOURCES:
sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
......@@ -2808,6 +2812,26 @@ static const struct sense_info sense_info_table[] = {
.key = ILLEGAL_REQUEST,
.asc = 0x26, /* INVALID FIELD IN PARAMETER LIST */
},
[TCM_TOO_MANY_TARGET_DESCS] = {
.key = ILLEGAL_REQUEST,
.asc = 0x26,
.ascq = 0x06, /* TOO MANY TARGET DESCRIPTORS */
},
[TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE] = {
.key = ILLEGAL_REQUEST,
.asc = 0x26,
.ascq = 0x07, /* UNSUPPORTED TARGET DESCRIPTOR TYPE CODE */
},
[TCM_TOO_MANY_SEGMENT_DESCS] = {
.key = ILLEGAL_REQUEST,
.asc = 0x26,
.ascq = 0x08, /* TOO MANY SEGMENT DESCRIPTORS */
},
[TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE] = {
.key = ILLEGAL_REQUEST,
.asc = 0x26,
.ascq = 0x09, /* UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE */
},
[TCM_PARAMETER_LIST_LENGTH_ERROR] = {
.key = ILLEGAL_REQUEST,
.asc = 0x1a, /* PARAMETER LIST LENGTH ERROR */
......
......@@ -53,18 +53,13 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
return 0;
}
static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
bool src)
static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
struct se_device **found_dev)
{
struct se_device *se_dev;
unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn;
unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
int rc;
if (src)
dev_wwn = &xop->dst_tid_wwn[0];
else
dev_wwn = &xop->src_tid_wwn[0];
mutex_lock(&g_device_mutex);
list_for_each_entry(se_dev, &g_device_list, g_dev_node) {
......@@ -78,15 +73,8 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
if (rc != 0)
continue;
if (src) {
xop->dst_dev = se_dev;
pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located"
" se_dev\n", xop->dst_dev);
} else {
xop->src_dev = se_dev;
pr_debug("XCOPY 0xe4: Setting xop->src_dev: %p from located"
" se_dev\n", xop->src_dev);
}
*found_dev = se_dev;
pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
rc = target_depend_item(&se_dev->dev_group.cg_item);
if (rc != 0) {
......@@ -110,7 +98,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
}
static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
unsigned char *p, bool src)
unsigned char *p, unsigned short cscd_index)
{
unsigned char *desc = p;
unsigned short ript;
......@@ -155,7 +143,13 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op
return -EINVAL;
}
if (src) {
if (cscd_index != xop->stdi && cscd_index != xop->dtdi) {
pr_debug("XCOPY 0xe4: ignoring CSCD entry %d - neither src nor "
"dest\n", cscd_index);
return 0;
}
if (cscd_index == xop->stdi) {
memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
/*
* Determine if the source designator matches the local device
......@@ -167,10 +161,15 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op
pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source"
" received xop\n", xop->src_dev);
}
} else {
}
if (cscd_index == xop->dtdi) {
memcpy(&xop->dst_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
/*
* Determine if the destination designator matches the local device
* Determine if the destination designator matches the local
* device. If @cscd_index corresponds to both source (stdi) and
* destination (dtdi), or dtdi comes after stdi, then
* XCOL_DEST_RECV_OP wins.
*/
if (!memcmp(&xop->local_dev_wwn[0], &xop->dst_tid_wwn[0],
XCOPY_NAA_IEEE_REGEX_LEN)) {
......@@ -190,20 +189,23 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
{
struct se_device *local_dev = se_cmd->se_dev;
unsigned char *desc = p;
int offset = tdll % XCOPY_TARGET_DESC_LEN, rc, ret = 0;
int offset = tdll % XCOPY_TARGET_DESC_LEN, rc;
unsigned short cscd_index = 0;
unsigned short start = 0;
bool src = true;
*sense_ret = TCM_INVALID_PARAMETER_LIST;
if (offset != 0) {
pr_err("XCOPY target descriptor list length is not"
" multiple of %d\n", XCOPY_TARGET_DESC_LEN);
*sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE;
return -EINVAL;
}
if (tdll > 64) {
if (tdll > RCR_OP_MAX_TARGET_DESC_COUNT * XCOPY_TARGET_DESC_LEN) {
pr_err("XCOPY target descriptor supports a maximum"
" two src/dest descriptors, tdll: %hu too large..\n", tdll);
/* spc4r37 6.4.3.4 CSCD DESCRIPTOR LIST LENGTH field */
*sense_ret = TCM_TOO_MANY_TARGET_DESCS;
return -EINVAL;
}
/*
......@@ -215,37 +217,43 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
while (start < tdll) {
/*
* Check target descriptor identification with 0xE4 type with
* use VPD 0x83 WWPN matching ..
* Check target descriptor identification with 0xE4 type, and
* compare the current index with the CSCD descriptor IDs in
* the segment descriptor. Use VPD 0x83 WWPN matching ..
*/
switch (desc[0]) {
case 0xe4:
rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop,
&desc[0], src);
&desc[0], cscd_index);
if (rc != 0)
goto out;
/*
* Assume target descriptors are in source -> destination order..
*/
if (src)
src = false;
else
src = true;
start += XCOPY_TARGET_DESC_LEN;
desc += XCOPY_TARGET_DESC_LEN;
ret++;
cscd_index++;
break;
default:
pr_err("XCOPY unsupported descriptor type code:"
" 0x%02x\n", desc[0]);
*sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE;
goto out;
}
}
if (xop->op_origin == XCOL_SOURCE_RECV_OP)
rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true);
else
rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false);
switch (xop->op_origin) {
case XCOL_SOURCE_RECV_OP:
rc = target_xcopy_locate_se_dev_e4(xop->dst_tid_wwn,
&xop->dst_dev);
break;
case XCOL_DEST_RECV_OP:
rc = target_xcopy_locate_se_dev_e4(xop->src_tid_wwn,
&xop->src_dev);
break;
default:
pr_err("XCOPY CSCD descriptor IDs not found in CSCD list - "
"stdi: %hu dtdi: %hu\n", xop->stdi, xop->dtdi);
rc = -EINVAL;
break;
}
/*
* If a matching IEEE NAA 0x83 descriptor for the requested device
* is not located on this node, return COPY_ABORTED with ASQ/ASQC
......@@ -262,7 +270,7 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
pr_debug("XCOPY TGT desc: Dest dev: %p NAA IEEE WWN: 0x%16phN\n",
xop->dst_dev, &xop->dst_tid_wwn[0]);
return ret;
return cscd_index;
out:
return -EINVAL;
......@@ -284,6 +292,14 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op
xop->stdi = get_unaligned_be16(&desc[4]);
xop->dtdi = get_unaligned_be16(&desc[6]);
if (xop->stdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX ||
xop->dtdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX) {
pr_err("XCOPY segment desc 0x02: unsupported CSCD ID > 0x%x; stdi: %hu dtdi: %hu\n",
XCOPY_CSCD_DESC_ID_LIST_OFF_MAX, xop->stdi, xop->dtdi);
return -EINVAL;
}
pr_debug("XCOPY seg desc 0x02: desc_len: %hu stdi: %hu dtdi: %hu, DC: %d\n",
desc_len, xop->stdi, xop->dtdi, dc);
......@@ -306,15 +322,25 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op
static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd,
struct xcopy_op *xop, unsigned char *p,
unsigned int sdll)
unsigned int sdll, sense_reason_t *sense_ret)
{
unsigned char *desc = p;
unsigned int start = 0;
int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0;
*sense_ret = TCM_INVALID_PARAMETER_LIST;
if (offset != 0) {
pr_err("XCOPY segment descriptor list length is not"
" multiple of %d\n", XCOPY_SEGMENT_DESC_LEN);
*sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE;
return -EINVAL;
}
if (sdll > RCR_OP_MAX_SG_DESC_COUNT * XCOPY_SEGMENT_DESC_LEN) {
pr_err("XCOPY supports %u segment descriptor(s), sdll: %u too"
" large..\n", RCR_OP_MAX_SG_DESC_COUNT, sdll);
/* spc4r37 6.4.3.5 SEGMENT DESCRIPTOR LIST LENGTH field */
*sense_ret = TCM_TOO_MANY_SEGMENT_DESCS;
return -EINVAL;
}
......@@ -335,6 +361,7 @@ static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd,
default:
pr_err("XCOPY unsupported segment descriptor"
"type: 0x%02x\n", desc[0]);
*sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE;
goto out;
}
}
......@@ -861,6 +888,16 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
return TCM_UNSUPPORTED_SCSI_OPCODE;
}
if (se_cmd->data_length == 0) {
target_complete_cmd(se_cmd, SAM_STAT_GOOD);
return TCM_NO_SENSE;
}
if (se_cmd->data_length < XCOPY_HDR_LEN) {
pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n",
se_cmd->data_length, XCOPY_HDR_LEN);
return TCM_PARAMETER_LIST_LENGTH_ERROR;
}
xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
if (!xop) {
pr_err("Unable to allocate xcopy_op\n");
......@@ -883,6 +920,12 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
*/
tdll = get_unaligned_be16(&p[2]);
sdll = get_unaligned_be32(&p[8]);
if (tdll + sdll > RCR_OP_MAX_DESC_LIST_LEN) {
pr_err("XCOPY descriptor list length %u exceeds maximum %u\n",
tdll + sdll, RCR_OP_MAX_DESC_LIST_LEN);
ret = TCM_PARAMETER_LIST_LENGTH_ERROR;
goto out;
}
inline_dl = get_unaligned_be32(&p[12]);
if (inline_dl != 0) {
......@@ -890,10 +933,32 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
goto out;
}
if (se_cmd->data_length < (XCOPY_HDR_LEN + tdll + sdll + inline_dl)) {
pr_err("XCOPY parameter truncation: data length %u too small "
"for tdll: %hu sdll: %u inline_dl: %u\n",
se_cmd->data_length, tdll, sdll, inline_dl);
ret = TCM_PARAMETER_LIST_LENGTH_ERROR;
goto out;
}
pr_debug("Processing XCOPY with list_id: 0x%02x list_id_usage: 0x%02x"
" tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage,
tdll, sdll, inline_dl);
/*
* skip over the target descriptors until segment descriptors
* have been passed - CSCD ids are needed to determine src and dest.
*/
seg_desc = &p[16] + tdll;
rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc,
sdll, &ret);
if (rc <= 0)
goto out;
pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
rc * XCOPY_SEGMENT_DESC_LEN);
rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret);
if (rc <= 0)
goto out;
......@@ -911,18 +976,8 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc,
rc * XCOPY_TARGET_DESC_LEN);
seg_desc = &p[16];
seg_desc += (rc * XCOPY_TARGET_DESC_LEN);
rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, sdll);
if (rc <= 0) {
xcopy_pt_undepend_remotedev(xop);
goto out;
}
transport_kunmap_data_sg(se_cmd);
pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
rc * XCOPY_SEGMENT_DESC_LEN);
INIT_WORK(&xop->xop_work, target_xcopy_do_work);
queue_work(xcopy_wq, &xop->xop_work);
return TCM_NO_SENSE;
......
#include <target/target_core_base.h>
#define XCOPY_HDR_LEN 16
#define XCOPY_TARGET_DESC_LEN 32
#define XCOPY_SEGMENT_DESC_LEN 28
#define XCOPY_NAA_IEEE_REGEX_LEN 16
#define XCOPY_MAX_SECTORS 1024
/*
* SPC4r37 6.4.6.1
* Table 150 — CSCD descriptor ID values
*/
#define XCOPY_CSCD_DESC_ID_LIST_OFF_MAX 0x07FF
enum xcopy_origin_list {
XCOL_SOURCE_RECV_OP = 0x01,
XCOL_DEST_RECV_OP = 0x02,
......
......@@ -174,6 +174,10 @@ enum tcm_sense_reason_table {
TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED = R(0x16),
TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED = R(0x17),
TCM_COPY_TARGET_DEVICE_NOT_REACHABLE = R(0x18),
TCM_TOO_MANY_TARGET_DESCS = R(0x19),
TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE = R(0x1a),
TCM_TOO_MANY_SEGMENT_DESCS = R(0x1b),
TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE = R(0x1c),
#undef R
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment