diff options
Diffstat (limited to 'drivers/target/target_core_xcopy.c')
-rw-r--r-- | drivers/target/target_core_xcopy.c | 184 |
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; |