diff options
| author | Nicholas Bellinger <nab@daterainc.com> | 2013-08-20 18:38:55 -0400 |
|---|---|---|
| committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-09-10 19:48:43 -0400 |
| commit | cbf031f425fd0b30ff10ba83b612753189a6bbbf (patch) | |
| tree | dcc5696e342739cf9f8b2d9791b19036025075c7 | |
| parent | 89c12cc925a7d0982dc53b743a42108acc76aef4 (diff) | |
target: Add support for EXTENDED_COPY copy offload emulation
This patch adds support for EXTENDED_COPY emulation from SPC-3, that
enables full copy offload target support within both a single virtual
backend device, and across multiple virtual backend devices. It also
functions independent of target fabric, and supports copy offload
across multiple target fabric ports.
This implemenation supports both EXTENDED_COPY PUSH and PULL models
of operation, so the actual CDB may be received on either source or
desination logical unit.
For Target Descriptors, it currently supports the NAA IEEE Registered
Extended designator (type 0xe4), which allows the reference of target
ports to occur independent of fabric type using EVPD 0x83 WWNs.
For Segment Descriptors, it currently supports copy from block to
block (0x02) mode.
It also honors any present SCSI reservations of the destination target
port. Note that only Supports No List Identifier (SNLID=1) mode is
supported.
Also included is basic RECEIVE_COPY_RESULTS with service action type
OPERATING PARAMETERS (0x03) required for SNLID=1 operation.
v3 changes:
- Fix incorrect return type in target_do_receive_copy_results()
(Fengguang)
v2 changes:
- Use target_alloc_sgl() instead of transport_generic_get_mem()
- Convert debug output to use pr_debug()
- Convert target_xcopy_parse_target_descriptors() NAA IEEN WWN
dump to use 0x%16phN format specification
- Drop unnecessary xcopy_pt_cmd->xpt_passthrough_wsem, and
associated usage in xcopy_pt_write_pending() and
target_xcopy_issue_pt_cmd()
- Add check for unsupported EXTENDED_COPY(LID4) service action
bits in target_do_xcopy()
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Martin Petersen <martin.petersen@oracle.com>
Cc: Chris Mason <chris.mason@fusionio.com>
Cc: Roland Dreier <roland@purestorage.com>
Cc: Zach Brown <zab@redhat.com>
Cc: James Bottomley <JBottomley@Parallels.com>
Cc: Nicholas Bellinger <nab@linux-iscsi.org>
Signed-off-by: Nicholas Bellinger <nab@daterainc.com>
| -rw-r--r-- | drivers/target/Makefile | 3 | ||||
| -rw-r--r-- | drivers/target/target_core_xcopy.c | 1082 | ||||
| -rw-r--r-- | drivers/target/target_core_xcopy.h | 62 | ||||
| -rw-r--r-- | include/target/target_core_base.h | 1 |
4 files changed, 1147 insertions, 1 deletions
diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 9fdcb561422f..85b012d2f89b 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile | |||
| @@ -13,7 +13,8 @@ target_core_mod-y := target_core_configfs.o \ | |||
| 13 | target_core_spc.o \ | 13 | target_core_spc.o \ |
| 14 | target_core_ua.o \ | 14 | target_core_ua.o \ |
| 15 | target_core_rd.o \ | 15 | target_core_rd.o \ |
| 16 | target_core_stat.o | 16 | target_core_stat.o \ |
| 17 | target_core_xcopy.o | ||
| 17 | 18 | ||
| 18 | obj-$(CONFIG_TARGET_CORE) += target_core_mod.o | 19 | obj-$(CONFIG_TARGET_CORE) += target_core_mod.o |
| 19 | 20 | ||
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c new file mode 100644 index 000000000000..cf566a114911 --- /dev/null +++ b/drivers/target/target_core_xcopy.c | |||
| @@ -0,0 +1,1082 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Filename: target_core_xcopy.c | ||
| 3 | * | ||
| 4 | * This file contains support for SPC-4 Extended-Copy offload with generic | ||
| 5 | * TCM backends. | ||
| 6 | * | ||
| 7 | * Copyright (c) 2011-2013 Datera, Inc. All rights reserved. | ||
| 8 | * | ||
| 9 | * Author: | ||
| 10 | * Nicholas A. Bellinger <nab@daterainc.com> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2 of the License, or | ||
| 15 | * (at your option) any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | ******************************************************************************/ | ||
| 23 | |||
| 24 | #include <linux/version.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | #include <linux/spinlock.h> | ||
| 27 | #include <linux/list.h> | ||
| 28 | #include <linux/configfs.h> | ||
| 29 | #include <scsi/scsi.h> | ||
| 30 | #include <scsi/scsi_cmnd.h> | ||
| 31 | #include <asm/unaligned.h> | ||
| 32 | |||
| 33 | #include <target/target_core_base.h> | ||
| 34 | #include <target/target_core_backend.h> | ||
| 35 | #include <target/target_core_fabric.h> | ||
| 36 | #include <target/target_core_configfs.h> | ||
| 37 | |||
| 38 | #include "target_core_pr.h" | ||
| 39 | #include "target_core_ua.h" | ||
| 40 | #include "target_core_xcopy.h" | ||
| 41 | |||
| 42 | static struct workqueue_struct *xcopy_wq = NULL; | ||
| 43 | /* | ||
| 44 | * From target_core_spc.c | ||
| 45 | */ | ||
| 46 | extern void spc_parse_naa_6h_vendor_specific(struct se_device *, unsigned char *); | ||
| 47 | /* | ||
| 48 | * From target_core_device.c | ||
| 49 | */ | ||
| 50 | extern struct mutex g_device_mutex; | ||
| 51 | extern struct list_head g_device_list; | ||
| 52 | /* | ||
| 53 | * From target_core_configfs.c | ||
| 54 | */ | ||
| 55 | extern struct configfs_subsystem *target_core_subsystem[]; | ||
| 56 | |||
| 57 | static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf) | ||
| 58 | { | ||
| 59 | int off = 0; | ||
| 60 | |||
| 61 | buf[off++] = (0x6 << 4); | ||
| 62 | buf[off++] = 0x01; | ||
| 63 | buf[off++] = 0x40; | ||
| 64 | buf[off] = (0x5 << 4); | ||
| 65 | |||
| 66 | spc_parse_naa_6h_vendor_specific(dev, &buf[off]); | ||
| 67 | return 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, | ||
| 71 | bool src) | ||
| 72 | { | ||
| 73 | struct se_device *se_dev; | ||
| 74 | struct configfs_subsystem *subsys = target_core_subsystem[0]; | ||
| 75 | unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn; | ||
| 76 | int rc; | ||
| 77 | |||
| 78 | if (src == true) | ||
| 79 | dev_wwn = &xop->dst_tid_wwn[0]; | ||
| 80 | else | ||
| 81 | dev_wwn = &xop->src_tid_wwn[0]; | ||
| 82 | |||
| 83 | mutex_lock(&g_device_mutex); | ||
| 84 | list_for_each_entry(se_dev, &g_device_list, g_dev_node) { | ||
| 85 | |||
| 86 | memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN); | ||
| 87 | target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]); | ||
| 88 | |||
| 89 | rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN); | ||
| 90 | if (rc != 0) | ||
| 91 | continue; | ||
| 92 | |||
| 93 | if (src == true) { | ||
| 94 | xop->dst_dev = se_dev; | ||
| 95 | pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located" | ||
| 96 | " se_dev\n", xop->dst_dev); | ||
| 97 | } else { | ||
| 98 | xop->src_dev = se_dev; | ||
| 99 | pr_debug("XCOPY 0xe4: Setting xop->src_dev: %p from located" | ||
| 100 | " se_dev\n", xop->src_dev); | ||
| 101 | } | ||
| 102 | |||
| 103 | rc = configfs_depend_item(subsys, | ||
| 104 | &se_dev->dev_group.cg_item); | ||
| 105 | if (rc != 0) { | ||
| 106 | pr_err("configfs_depend_item attempt failed:" | ||
| 107 | " %d for se_dev: %p\n", rc, se_dev); | ||
| 108 | mutex_unlock(&g_device_mutex); | ||
| 109 | return rc; | ||
| 110 | } | ||
| 111 | |||
| 112 | pr_debug("Called configfs_depend_item for subsys: %p se_dev: %p" | ||
| 113 | " se_dev->se_dev_group: %p\n", subsys, se_dev, | ||
| 114 | &se_dev->dev_group); | ||
| 115 | |||
| 116 | mutex_unlock(&g_device_mutex); | ||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | mutex_unlock(&g_device_mutex); | ||
| 120 | |||
| 121 | pr_err("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n"); | ||
| 122 | return -EINVAL; | ||
| 123 | } | ||
| 124 | |||
| 125 | static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, | ||
| 126 | unsigned char *p, bool src) | ||
| 127 | { | ||
| 128 | unsigned char *desc = p; | ||
| 129 | unsigned short ript; | ||
| 130 | u8 desig_len; | ||
| 131 | /* | ||
| 132 | * Extract RELATIVE INITIATOR PORT IDENTIFIER | ||
| 133 | */ | ||
| 134 | ript = get_unaligned_be16(&desc[2]); | ||
| 135 | pr_debug("XCOPY 0xe4: RELATIVE INITIATOR PORT IDENTIFIER: %hu\n", ript); | ||
| 136 | /* | ||
| 137 | * Check for supported code set, association, and designator type | ||
| 138 | */ | ||
| 139 | if ((desc[4] & 0x0f) != 0x1) { | ||
| 140 | pr_err("XCOPY 0xe4: code set of non binary type not supported\n"); | ||
| 141 | return -EINVAL; | ||
| 142 | } | ||
| 143 | if ((desc[5] & 0x30) != 0x00) { | ||
| 144 | pr_err("XCOPY 0xe4: association other than LUN not supported\n"); | ||
| 145 | return -EINVAL; | ||
| 146 | } | ||
| 147 | if ((desc[5] & 0x0f) != 0x3) { | ||
| 148 | pr_err("XCOPY 0xe4: designator type unsupported: 0x%02x\n", | ||
| 149 | (desc[5] & 0x0f)); | ||
| 150 | return -EINVAL; | ||
| 151 | } | ||
| 152 | /* | ||
| 153 | * Check for matching 16 byte length for NAA IEEE Registered Extended | ||
| 154 | * Assigned designator | ||
| 155 | */ | ||
| 156 | desig_len = desc[7]; | ||
| 157 | if (desig_len != 16) { | ||
| 158 | pr_err("XCOPY 0xe4: invalid desig_len: %d\n", (int)desig_len); | ||
| 159 | return -EINVAL; | ||
| 160 | } | ||
| 161 | pr_debug("XCOPY 0xe4: desig_len: %d\n", (int)desig_len); | ||
| 162 | /* | ||
| 163 | * Check for NAA IEEE Registered Extended Assigned header.. | ||
| 164 | */ | ||
| 165 | if ((desc[8] & 0xf0) != 0x60) { | ||
