summaryrefslogtreecommitdiff
path: root/drivers/target/target_core_xcopy.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/target/target_core_xcopy.c')
-rw-r--r--drivers/target/target_core_xcopy.c184
1 files changed, 111 insertions, 73 deletions
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
index cac5a20a4de0..9ee89e00cd77 100644
--- a/drivers/target/target_core_xcopy.c
+++ b/drivers/target/target_core_xcopy.c
@@ -40,6 +40,8 @@
static struct workqueue_struct *xcopy_wq = NULL;
+static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop);
+
static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
{
int off = 0;
@@ -53,48 +55,60 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
return 0;
}
-static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
- struct se_device **found_dev)
+struct xcopy_dev_search_info {
+ const unsigned char *dev_wwn;
+ struct se_device *found_dev;
+};
+
+static int target_xcopy_locate_se_dev_e4_iter(struct se_device *se_dev,
+ void *data)
{
- struct se_device *se_dev;
+ struct xcopy_dev_search_info *info = data;
unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
int rc;
- mutex_lock(&g_device_mutex);
- list_for_each_entry(se_dev, &g_device_list, g_dev_node) {
+ if (!se_dev->dev_attrib.emulate_3pc)
+ return 0;
- if (!se_dev->dev_attrib.emulate_3pc)
- continue;
+ memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
+ target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
- memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
- target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
+ rc = memcmp(&tmp_dev_wwn[0], info->dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
+ if (rc != 0)
+ return 0;
- rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
- if (rc != 0)
- continue;
+ info->found_dev = se_dev;
+ pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_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) {
+ pr_err("configfs_depend_item attempt failed: %d for se_dev: %p\n",
+ rc, se_dev);
+ return rc;
+ }
- rc = target_depend_item(&se_dev->dev_group.cg_item);
- if (rc != 0) {
- pr_err("configfs_depend_item attempt failed:"
- " %d for se_dev: %p\n", rc, se_dev);
- mutex_unlock(&g_device_mutex);
- return rc;
- }
+ pr_debug("Called configfs_depend_item for se_dev: %p se_dev->se_dev_group: %p\n",
+ se_dev, &se_dev->dev_group);
+ return 1;
+}
- pr_debug("Called configfs_depend_item for se_dev: %p"
- " se_dev->se_dev_group: %p\n", se_dev,
- &se_dev->dev_group);
+static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
+ struct se_device **found_dev)
+{
+ struct xcopy_dev_search_info info;
+ int ret;
+
+ memset(&info, 0, sizeof(info));
+ info.dev_wwn = dev_wwn;
- mutex_unlock(&g_device_mutex);
+ ret = target_for_each_device(target_xcopy_locate_se_dev_e4_iter, &info);
+ if (ret == 1) {
+ *found_dev = info.found_dev;
return 0;
+ } else {
+ pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
+ return -EINVAL;
}
- mutex_unlock(&g_device_mutex);
-
- pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
- return -EINVAL;
}
static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
@@ -311,9 +325,7 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op
(unsigned long long)xop->dst_lba);
if (dc != 0) {
- xop->dbl = (desc[29] & 0xff) << 16;
- xop->dbl |= (desc[30] & 0xff) << 8;
- xop->dbl |= desc[31] & 0xff;
+ xop->dbl = get_unaligned_be24(&desc[29]);
pr_debug("XCOPY seg desc 0x02: DC=1 w/ dbl: %u\n", xop->dbl);
}
@@ -781,13 +793,24 @@ static int target_xcopy_write_destination(
static void target_xcopy_do_work(struct work_struct *work)
{
struct xcopy_op *xop = container_of(work, struct xcopy_op, xop_work);
- struct se_device *src_dev = xop->src_dev, *dst_dev = xop->dst_dev;
struct se_cmd *ec_cmd = xop->xop_se_cmd;
- sector_t src_lba = xop->src_lba, dst_lba = xop->dst_lba, end_lba;
+ struct se_device *src_dev, *dst_dev;
+ sector_t src_lba, dst_lba, end_lba;
unsigned int max_sectors;
- int rc;
- unsigned short nolb = xop->nolb, cur_nolb, max_nolb, copied_nolb = 0;
+ int rc = 0;
+ unsigned short nolb, cur_nolb, max_nolb, copied_nolb = 0;
+
+ if (target_parse_xcopy_cmd(xop) != TCM_NO_SENSE)
+ goto err_free;
+ if (WARN_ON_ONCE(!xop->src_dev) || WARN_ON_ONCE(!xop->dst_dev))
+ goto err_free;
+
+ src_dev = xop->src_dev;
+ dst_dev = xop->dst_dev;
+ src_lba = xop->src_lba;
+ dst_lba = xop->dst_lba;
+ nolb = xop->nolb;
end_lba = src_lba + nolb;
/*
* Break up XCOPY I/O into hw_max_sectors sized I/O based on the
@@ -855,6 +878,8 @@ static void target_xcopy_do_work(struct work_struct *work)
out:
xcopy_pt_undepend_remotedev(xop);
+
+err_free:
kfree(xop);
/*
* Don't override an error scsi status if it has already been set
@@ -867,48 +892,22 @@ out:
target_complete_cmd(ec_cmd, ec_cmd->scsi_status);
}
-sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
+/*
+ * Returns TCM_NO_SENSE upon success or a sense code != TCM_NO_SENSE if parsing
+ * fails.
+ */
+static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop)
{
- struct se_device *dev = se_cmd->se_dev;
- struct xcopy_op *xop = NULL;
+ struct se_cmd *se_cmd = xop->xop_se_cmd;
unsigned char *p = NULL, *seg_desc;
- unsigned int list_id, list_id_usage, sdll, inline_dl, sa;
+ unsigned int list_id, list_id_usage, sdll, inline_dl;
sense_reason_t ret = TCM_INVALID_PARAMETER_LIST;
int rc;
unsigned short tdll;
- if (!dev->dev_attrib.emulate_3pc) {
- pr_err("EXTENDED_COPY operation explicitly disabled\n");
- return TCM_UNSUPPORTED_SCSI_OPCODE;
- }
-
- sa = se_cmd->t_task_cdb[1] & 0x1f;
- if (sa != 0x00) {
- pr_err("EXTENDED_COPY(LID4) not supported\n");
- 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");
- return TCM_OUT_OF_RESOURCES;
- }
- xop->xop_se_cmd = se_cmd;
-
p = transport_kmap_data_sg(se_cmd);
if (!p) {
pr_err("transport_kmap_data_sg() failed in target_do_xcopy\n");
- kfree(xop);
return TCM_OUT_OF_RESOURCES;
}
@@ -977,18 +976,57 @@ 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);
transport_kunmap_data_sg(se_cmd);
-
- INIT_WORK(&xop->xop_work, target_xcopy_do_work);
- queue_work(xcopy_wq, &xop->xop_work);
return TCM_NO_SENSE;
out:
if (p)
transport_kunmap_data_sg(se_cmd);
- kfree(xop);
return ret;
}
+sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
+{
+ struct se_device *dev = se_cmd->se_dev;
+ struct xcopy_op *xop;
+ unsigned int sa;
+
+ if (!dev->dev_attrib.emulate_3pc) {
+ pr_err("EXTENDED_COPY operation explicitly disabled\n");
+ return TCM_UNSUPPORTED_SCSI_OPCODE;
+ }
+
+ sa = se_cmd->t_task_cdb[1] & 0x1f;
+ if (sa != 0x00) {
+ pr_err("EXTENDED_COPY(LID4) not supported\n");
+ 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)
+ goto err;
+ xop->xop_se_cmd = se_cmd;
+ INIT_WORK(&xop->xop_work, target_xcopy_do_work);
+ if (WARN_ON_ONCE(!queue_work(xcopy_wq, &xop->xop_work)))
+ goto free;
+ return TCM_NO_SENSE;
+
+free:
+ kfree(xop);
+
+err:
+ return TCM_OUT_OF_RESOURCES;
+}
+
static sense_reason_t target_rcr_operating_parameters(struct se_cmd *se_cmd)
{
unsigned char *p;