diff options
-rw-r--r-- | drivers/target/Kconfig | 1 | ||||
-rw-r--r-- | drivers/target/target_core_sbc.c | 178 | ||||
-rw-r--r-- | include/target/target_core_backend.h | 4 |
3 files changed, 183 insertions, 0 deletions
diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig index 18303686eb58..50aad2eeed6e 100644 --- a/drivers/target/Kconfig +++ b/drivers/target/Kconfig | |||
@@ -3,6 +3,7 @@ menuconfig TARGET_CORE | |||
3 | tristate "Generic Target Core Mod (TCM) and ConfigFS Infrastructure" | 3 | tristate "Generic Target Core Mod (TCM) and ConfigFS Infrastructure" |
4 | depends on SCSI && BLOCK | 4 | depends on SCSI && BLOCK |
5 | select CONFIGFS_FS | 5 | select CONFIGFS_FS |
6 | select CRC_T10DIF | ||
6 | default n | 7 | default n |
7 | help | 8 | help |
8 | Say Y or M here to enable the TCM Storage Engine and ConfigFS enabled | 9 | Say Y or M here to enable the TCM Storage Engine and ConfigFS enabled |
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 91a92f354e9f..26e8bfb27787 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/ratelimit.h> | 25 | #include <linux/ratelimit.h> |
26 | #include <linux/crc-t10dif.h> | ||
26 | #include <asm/unaligned.h> | 27 | #include <asm/unaligned.h> |
27 | #include <scsi/scsi.h> | 28 | #include <scsi/scsi.h> |
28 | #include <scsi/scsi_tcq.h> | 29 | #include <scsi/scsi_tcq.h> |
@@ -1024,3 +1025,180 @@ err: | |||
1024 | return ret; | 1025 | return ret; |
1025 | } | 1026 | } |
1026 | EXPORT_SYMBOL(sbc_execute_unmap); | 1027 | EXPORT_SYMBOL(sbc_execute_unmap); |
1028 | |||
1029 | static sense_reason_t | ||
1030 | sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt, | ||
1031 | const void *p, sector_t sector, unsigned int ei_lba) | ||
1032 | { | ||
1033 | int block_size = dev->dev_attrib.block_size; | ||
1034 | __be16 csum; | ||
1035 | |||
1036 | csum = cpu_to_be16(crc_t10dif(p, block_size)); | ||
1037 | |||
1038 | if (sdt->guard_tag != csum) { | ||
1039 | pr_err("DIFv1 checksum failed on sector %llu guard tag 0x%04x" | ||
1040 | " csum 0x%04x\n", (unsigned long long)sector, | ||
1041 | be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum)); | ||
1042 | return TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED; | ||
1043 | } | ||
1044 | |||
1045 | if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT && | ||
1046 | be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { | ||
1047 | pr_err("DIFv1 Type 1 reference failed on sector: %llu tag: 0x%08x" | ||
1048 | " sector MSB: 0x%08x\n", (unsigned long long)sector, | ||
1049 | be32_to_cpu(sdt->ref_tag), (u32)(sector & 0xffffffff)); | ||
1050 | return TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED; | ||
1051 | } | ||
1052 | |||
1053 | if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE2_PROT && | ||
1054 | be32_to_cpu(sdt->ref_tag) != ei_lba) { | ||
1055 | pr_err("DIFv1 Type 2 reference failed on sector: %llu tag: 0x%08x" | ||
1056 | " ei_lba: 0x%08x\n", (unsigned long long)sector, | ||
1057 | be32_to_cpu(sdt->ref_tag), ei_lba); | ||
1058 | return TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED; | ||
1059 | } | ||
1060 | |||
1061 | return 0; | ||
1062 | } | ||
1063 | |||
1064 | static void | ||
1065 | sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, | ||
1066 | struct scatterlist *sg, int sg_off) | ||
1067 | { | ||
1068 | struct se_device *dev = cmd->se_dev; | ||
1069 | struct scatterlist *psg; | ||
1070 | void *paddr, *addr; | ||
1071 | unsigned int i, len, left; | ||
1072 | |||
1073 | left = sectors * dev->prot_length; | ||
1074 | |||
1075 | for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) { | ||
1076 | |||
1077 | len = min(psg->length, left); | ||
1078 | paddr = kmap_atomic(sg_page(psg)) + psg->offset; | ||
1079 | addr = kmap_atomic(sg_page(sg)) + sg_off; | ||
1080 | |||
1081 | if (read) | ||
1082 | memcpy(paddr, addr, len); | ||
1083 | else | ||
1084 | memcpy(addr, paddr, len); | ||
1085 | |||
1086 | left -= len; | ||
1087 | kunmap_atomic(paddr); | ||
1088 | kunmap_atomic(addr); | ||
1089 | } | ||
1090 | } | ||
1091 | |||
1092 | sense_reason_t | ||
1093 | sbc_dif_verify_write(struct se_cmd *cmd, sector_t start, unsigned int sectors, | ||
1094 | unsigned int ei_lba, struct scatterlist *sg, int sg_off) | ||
1095 | { | ||
1096 | struct se_device *dev = cmd->se_dev; | ||
1097 | struct se_dif_v1_tuple *sdt; | ||
1098 | struct scatterlist *dsg, *psg = cmd->t_prot_sg; | ||
1099 | sector_t sector = start; | ||
1100 | void *daddr, *paddr; | ||
1101 | int i, j, offset = 0; | ||
1102 | sense_reason_t rc; | ||
1103 | |||
1104 | for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) { | ||
1105 | daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; | ||
1106 | paddr = kmap_atomic(sg_page(psg)) + psg->offset; | ||
1107 | |||
1108 | for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) { | ||
1109 | |||
1110 | if (offset >= psg->length) { | ||
1111 | kunmap_atomic(paddr); | ||
1112 | psg = sg_next(psg); | ||
1113 | paddr = kmap_atomic(sg_page(psg)) + psg->offset; | ||
1114 | offset = 0; | ||
1115 | } | ||
1116 | |||
1117 | sdt = paddr + offset; | ||
1118 | |||
1119 | pr_debug("DIF WRITE sector: %llu guard_tag: 0x%04x" | ||
1120 | " app_tag: 0x%04x ref_tag: %u\n", | ||
1121 | (unsigned long long)sector, sdt->guard_tag, | ||
1122 | sdt->app_tag, be32_to_cpu(sdt->ref_tag)); | ||
1123 | |||
1124 | rc = sbc_dif_v1_verify(dev, sdt, daddr + j, sector, | ||
1125 | ei_lba); | ||
1126 | if (rc) { | ||
1127 | kunmap_atomic(paddr); | ||
1128 | kunmap_atomic(daddr); | ||
1129 | return rc; | ||
1130 | } | ||
1131 | |||
1132 | sector++; | ||
1133 | ei_lba++; | ||
1134 | offset += sizeof(struct se_dif_v1_tuple); | ||
1135 | } | ||
1136 | |||
1137 | kunmap_atomic(paddr); | ||
1138 | kunmap_atomic(daddr); | ||
1139 | } | ||
1140 | sbc_dif_copy_prot(cmd, sectors, false, sg, sg_off); | ||
1141 | |||
1142 | return 0; | ||
1143 | } | ||
1144 | EXPORT_SYMBOL(sbc_dif_verify_write); | ||
1145 | |||
1146 | sense_reason_t | ||
1147 | sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors, | ||
1148 | unsigned int ei_lba, struct scatterlist *sg, int sg_off) | ||
1149 | { | ||
1150 | struct se_device *dev = cmd->se_dev; | ||
1151 | struct se_dif_v1_tuple *sdt; | ||
1152 | struct scatterlist *dsg; | ||
1153 | sector_t sector = start; | ||
1154 | void *daddr, *paddr; | ||
1155 | int i, j, offset = sg_off; | ||
1156 | sense_reason_t rc; | ||
1157 | |||
1158 | for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) { | ||
1159 | daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; | ||
1160 | paddr = kmap_atomic(sg_page(sg)) + sg->offset; | ||
1161 | |||
1162 | for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) { | ||
1163 | |||
1164 | if (offset >= sg->length) { | ||
1165 | kunmap_atomic(paddr); | ||
1166 | sg = sg_next(sg); | ||
1167 | paddr = kmap_atomic(sg_page(sg)) + sg->offset; | ||
1168 | offset = 0; | ||
1169 | } | ||
1170 | |||
1171 | sdt = paddr + offset; | ||
1172 | |||
1173 | pr_debug("DIF READ sector: %llu guard_tag: 0x%04x" | ||
1174 | " app_tag: 0x%04x ref_tag: %u\n", | ||
1175 | (unsigned long long)sector, sdt->guard_tag, | ||
1176 | sdt->app_tag, be32_to_cpu(sdt->ref_tag)); | ||
1177 | |||
1178 | if (sdt->app_tag == cpu_to_be16(0xffff)) { | ||
1179 | sector++; | ||
1180 | offset += sizeof(struct se_dif_v1_tuple); | ||
1181 | continue; | ||
1182 | } | ||
1183 | |||
1184 | rc = sbc_dif_v1_verify(dev, sdt, daddr + j, sector, | ||
1185 | ei_lba); | ||
1186 | if (rc) { | ||
1187 | kunmap_atomic(paddr); | ||
1188 | kunmap_atomic(daddr); | ||
1189 | return rc; | ||
1190 | } | ||
1191 | |||
1192 | sector++; | ||
1193 | ei_lba++; | ||
1194 | offset += sizeof(struct se_dif_v1_tuple); | ||
1195 | } | ||
1196 | |||
1197 | kunmap_atomic(paddr); | ||
1198 | kunmap_atomic(daddr); | ||
1199 | } | ||
1200 | sbc_dif_copy_prot(cmd, sectors, true, sg, sg_off); | ||
1201 | |||
1202 | return 0; | ||
1203 | } | ||
1204 | EXPORT_SYMBOL(sbc_dif_verify_read); | ||
diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 0dc2745b9b18..7020e33e742e 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h | |||
@@ -73,6 +73,10 @@ sense_reason_t sbc_execute_unmap(struct se_cmd *cmd, | |||
73 | sense_reason_t (*do_unmap_fn)(struct se_cmd *cmd, void *priv, | 73 | sense_reason_t (*do_unmap_fn)(struct se_cmd *cmd, void *priv, |
74 | sector_t lba, sector_t nolb), | 74 | sector_t lba, sector_t nolb), |
75 | void *priv); | 75 | void *priv); |
76 | sense_reason_t sbc_dif_verify_write(struct se_cmd *, sector_t, unsigned int, | ||
77 | unsigned int, struct scatterlist *, int); | ||
78 | sense_reason_t sbc_dif_verify_read(struct se_cmd *, sector_t, unsigned int, | ||
79 | unsigned int, struct scatterlist *, int); | ||
76 | 80 | ||
77 | void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *); | 81 | void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *); |
78 | int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *); | 82 | int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *); |