.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /******************************************************************************* |
---|
2 | 3 | * Filename: target_core_configfs.c |
---|
3 | 4 | * |
---|
.. | .. |
---|
9 | 10 | * |
---|
10 | 11 | * based on configfs Copyright (C) 2005 Oracle. All rights reserved. |
---|
11 | 12 | * |
---|
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 | 13 | ****************************************************************************/ |
---|
22 | 14 | |
---|
23 | 15 | #include <linux/module.h> |
---|
.. | .. |
---|
172 | 164 | |
---|
173 | 165 | mutex_lock(&g_tf_lock); |
---|
174 | 166 | list_for_each_entry(tf, &g_tf_list, tf_list) { |
---|
175 | | - if (!strcmp(tf->tf_ops->name, name)) { |
---|
| 167 | + const char *cmp_name = tf->tf_ops->fabric_alias; |
---|
| 168 | + if (!cmp_name) |
---|
| 169 | + cmp_name = tf->tf_ops->fabric_name; |
---|
| 170 | + if (!strcmp(cmp_name, name)) { |
---|
176 | 171 | atomic_inc(&tf->tf_access_cnt); |
---|
177 | 172 | mutex_unlock(&g_tf_lock); |
---|
178 | 173 | return tf; |
---|
.. | .. |
---|
249 | 244 | return ERR_PTR(-EINVAL); |
---|
250 | 245 | } |
---|
251 | 246 | pr_debug("Target_Core_ConfigFS: REGISTER -> Located fabric:" |
---|
252 | | - " %s\n", tf->tf_ops->name); |
---|
| 247 | + " %s\n", tf->tf_ops->fabric_name); |
---|
253 | 248 | /* |
---|
254 | 249 | * On a successful target_core_get_fabric() look, the returned |
---|
255 | 250 | * struct target_fabric_configfs *tf will contain a usage reference. |
---|
.. | .. |
---|
282 | 277 | " tf list\n", config_item_name(item)); |
---|
283 | 278 | |
---|
284 | 279 | pr_debug("Target_Core_ConfigFS: DEREGISTER -> located fabric:" |
---|
285 | | - " %s\n", tf->tf_ops->name); |
---|
| 280 | + " %s\n", tf->tf_ops->fabric_name); |
---|
286 | 281 | atomic_dec(&tf->tf_access_cnt); |
---|
287 | 282 | |
---|
288 | 283 | pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing ci" |
---|
.. | .. |
---|
342 | 337 | |
---|
343 | 338 | static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) |
---|
344 | 339 | { |
---|
345 | | - if (!tfo->name) { |
---|
346 | | - pr_err("Missing tfo->name\n"); |
---|
| 340 | + if (tfo->fabric_alias) { |
---|
| 341 | + if (strlen(tfo->fabric_alias) >= TARGET_FABRIC_NAME_SIZE) { |
---|
| 342 | + pr_err("Passed alias: %s exceeds " |
---|
| 343 | + "TARGET_FABRIC_NAME_SIZE\n", tfo->fabric_alias); |
---|
| 344 | + return -EINVAL; |
---|
| 345 | + } |
---|
| 346 | + } |
---|
| 347 | + if (!tfo->fabric_name) { |
---|
| 348 | + pr_err("Missing tfo->fabric_name\n"); |
---|
347 | 349 | return -EINVAL; |
---|
348 | 350 | } |
---|
349 | | - if (strlen(tfo->name) >= TARGET_FABRIC_NAME_SIZE) { |
---|
350 | | - pr_err("Passed name: %s exceeds TARGET_FABRIC" |
---|
351 | | - "_NAME_SIZE\n", tfo->name); |
---|
352 | | - return -EINVAL; |
---|
353 | | - } |
---|
354 | | - if (!tfo->get_fabric_name) { |
---|
355 | | - pr_err("Missing tfo->get_fabric_name()\n"); |
---|
| 351 | + if (strlen(tfo->fabric_name) >= TARGET_FABRIC_NAME_SIZE) { |
---|
| 352 | + pr_err("Passed name: %s exceeds " |
---|
| 353 | + "TARGET_FABRIC_NAME_SIZE\n", tfo->fabric_name); |
---|
356 | 354 | return -EINVAL; |
---|
357 | 355 | } |
---|
358 | 356 | if (!tfo->tpg_get_wwn) { |
---|
.. | .. |
---|
393 | 391 | } |
---|
394 | 392 | if (!tfo->write_pending) { |
---|
395 | 393 | pr_err("Missing tfo->write_pending()\n"); |
---|
396 | | - return -EINVAL; |
---|
397 | | - } |
---|
398 | | - if (!tfo->write_pending_status) { |
---|
399 | | - pr_err("Missing tfo->write_pending_status()\n"); |
---|
400 | 394 | return -EINVAL; |
---|
401 | 395 | } |
---|
402 | 396 | if (!tfo->set_default_node_attributes) { |
---|
.. | .. |
---|
486 | 480 | |
---|
487 | 481 | mutex_lock(&g_tf_lock); |
---|
488 | 482 | list_for_each_entry(t, &g_tf_list, tf_list) { |
---|
489 | | - if (!strcmp(t->tf_ops->name, fo->name)) { |
---|
| 483 | + if (!strcmp(t->tf_ops->fabric_name, fo->fabric_name)) { |
---|
490 | 484 | BUG_ON(atomic_read(&t->tf_access_cnt)); |
---|
491 | 485 | list_del(&t->tf_list); |
---|
492 | 486 | mutex_unlock(&g_tf_lock); |
---|
.. | .. |
---|
532 | 526 | DEF_CONFIGFS_ATTRIB_SHOW(emulate_tpws); |
---|
533 | 527 | DEF_CONFIGFS_ATTRIB_SHOW(emulate_caw); |
---|
534 | 528 | DEF_CONFIGFS_ATTRIB_SHOW(emulate_3pc); |
---|
| 529 | +DEF_CONFIGFS_ATTRIB_SHOW(emulate_pr); |
---|
535 | 530 | DEF_CONFIGFS_ATTRIB_SHOW(pi_prot_type); |
---|
536 | 531 | DEF_CONFIGFS_ATTRIB_SHOW(hw_pi_prot_type); |
---|
537 | | -DEF_CONFIGFS_ATTRIB_SHOW(pi_prot_format); |
---|
538 | 532 | DEF_CONFIGFS_ATTRIB_SHOW(pi_prot_verify); |
---|
539 | 533 | DEF_CONFIGFS_ATTRIB_SHOW(enforce_pr_isids); |
---|
540 | 534 | DEF_CONFIGFS_ATTRIB_SHOW(is_nonrot); |
---|
.. | .. |
---|
592 | 586 | DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_fua_write); |
---|
593 | 587 | DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_caw); |
---|
594 | 588 | DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_3pc); |
---|
| 589 | +DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_pr); |
---|
595 | 590 | DEF_CONFIGFS_ATTRIB_STORE_BOOL(enforce_pr_isids); |
---|
596 | 591 | DEF_CONFIGFS_ATTRIB_STORE_BOOL(is_nonrot); |
---|
597 | 592 | |
---|
.. | .. |
---|
613 | 608 | const char *configname; |
---|
614 | 609 | |
---|
615 | 610 | configname = config_item_name(&dev->dev_group.cg_item); |
---|
616 | | - if (strlen(configname) >= 16) { |
---|
| 611 | + if (strlen(configname) >= INQUIRY_MODEL_LEN) { |
---|
617 | 612 | pr_warn("dev[%p]: Backstore name '%s' is too long for " |
---|
618 | | - "INQUIRY_MODEL, truncating to 16 bytes\n", dev, |
---|
| 613 | + "INQUIRY_MODEL, truncating to 15 characters\n", dev, |
---|
619 | 614 | configname); |
---|
620 | 615 | } |
---|
621 | | - snprintf(&dev->t10_wwn.model[0], 16, "%s", configname); |
---|
| 616 | + /* |
---|
| 617 | + * XXX We can't use sizeof(dev->t10_wwn.model) (INQUIRY_MODEL_LEN + 1) |
---|
| 618 | + * here without potentially breaking existing setups, so continue to |
---|
| 619 | + * truncate one byte shorter than what can be carried in INQUIRY. |
---|
| 620 | + */ |
---|
| 621 | + strlcpy(dev->t10_wwn.model, configname, INQUIRY_MODEL_LEN); |
---|
622 | 622 | } |
---|
623 | 623 | |
---|
624 | 624 | static ssize_t emulate_model_alias_store(struct config_item *item, |
---|
.. | .. |
---|
640 | 640 | if (ret < 0) |
---|
641 | 641 | return ret; |
---|
642 | 642 | |
---|
| 643 | + BUILD_BUG_ON(sizeof(dev->t10_wwn.model) != INQUIRY_MODEL_LEN + 1); |
---|
643 | 644 | if (flag) { |
---|
644 | 645 | dev_set_t10_wwn_model_alias(dev); |
---|
645 | 646 | } else { |
---|
646 | | - strncpy(&dev->t10_wwn.model[0], |
---|
647 | | - dev->transport->inquiry_prod, 16); |
---|
| 647 | + strlcpy(dev->t10_wwn.model, dev->transport->inquiry_prod, |
---|
| 648 | + sizeof(dev->t10_wwn.model)); |
---|
648 | 649 | } |
---|
649 | 650 | da->emulate_model_alias = flag; |
---|
650 | 651 | return count; |
---|
.. | .. |
---|
683 | 684 | if (ret < 0) |
---|
684 | 685 | return ret; |
---|
685 | 686 | |
---|
686 | | - if (val != 0 && val != 1 && val != 2) { |
---|
| 687 | + if (val != TARGET_UA_INTLCK_CTRL_CLEAR |
---|
| 688 | + && val != TARGET_UA_INTLCK_CTRL_NO_CLEAR |
---|
| 689 | + && val != TARGET_UA_INTLCK_CTRL_ESTABLISH_UA) { |
---|
687 | 690 | pr_err("Illegal value %d\n", val); |
---|
688 | 691 | return -EINVAL; |
---|
689 | 692 | } |
---|
.. | .. |
---|
837 | 840 | da->pi_prot_verify = (bool) da->pi_prot_type; |
---|
838 | 841 | pr_debug("dev[%p]: SE Device Protection Type: %d\n", dev, flag); |
---|
839 | 842 | return count; |
---|
| 843 | +} |
---|
| 844 | + |
---|
| 845 | +/* always zero, but attr needs to remain RW to avoid userspace breakage */ |
---|
| 846 | +static ssize_t pi_prot_format_show(struct config_item *item, char *page) |
---|
| 847 | +{ |
---|
| 848 | + return snprintf(page, PAGE_SIZE, "0\n"); |
---|
840 | 849 | } |
---|
841 | 850 | |
---|
842 | 851 | static ssize_t pi_prot_format_store(struct config_item *item, |
---|
.. | .. |
---|
1090 | 1099 | static ssize_t alua_support_show(struct config_item *item, char *page) |
---|
1091 | 1100 | { |
---|
1092 | 1101 | struct se_dev_attrib *da = to_attrib(item); |
---|
1093 | | - u8 flags = da->da_dev->transport->transport_flags; |
---|
| 1102 | + u8 flags = da->da_dev->transport_flags; |
---|
1094 | 1103 | |
---|
1095 | 1104 | return snprintf(page, PAGE_SIZE, "%d\n", |
---|
1096 | 1105 | flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA ? 0 : 1); |
---|
1097 | 1106 | } |
---|
1098 | 1107 | |
---|
| 1108 | +static ssize_t alua_support_store(struct config_item *item, |
---|
| 1109 | + const char *page, size_t count) |
---|
| 1110 | +{ |
---|
| 1111 | + struct se_dev_attrib *da = to_attrib(item); |
---|
| 1112 | + struct se_device *dev = da->da_dev; |
---|
| 1113 | + bool flag, oldflag; |
---|
| 1114 | + int ret; |
---|
| 1115 | + |
---|
| 1116 | + ret = strtobool(page, &flag); |
---|
| 1117 | + if (ret < 0) |
---|
| 1118 | + return ret; |
---|
| 1119 | + |
---|
| 1120 | + oldflag = !(dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA); |
---|
| 1121 | + if (flag == oldflag) |
---|
| 1122 | + return count; |
---|
| 1123 | + |
---|
| 1124 | + if (!(dev->transport->transport_flags_changeable & |
---|
| 1125 | + TRANSPORT_FLAG_PASSTHROUGH_ALUA)) { |
---|
| 1126 | + pr_err("dev[%p]: Unable to change SE Device alua_support:" |
---|
| 1127 | + " alua_support has fixed value\n", dev); |
---|
| 1128 | + return -ENOSYS; |
---|
| 1129 | + } |
---|
| 1130 | + |
---|
| 1131 | + if (flag) |
---|
| 1132 | + dev->transport_flags &= ~TRANSPORT_FLAG_PASSTHROUGH_ALUA; |
---|
| 1133 | + else |
---|
| 1134 | + dev->transport_flags |= TRANSPORT_FLAG_PASSTHROUGH_ALUA; |
---|
| 1135 | + return count; |
---|
| 1136 | +} |
---|
| 1137 | + |
---|
1099 | 1138 | static ssize_t pgr_support_show(struct config_item *item, char *page) |
---|
1100 | 1139 | { |
---|
1101 | 1140 | struct se_dev_attrib *da = to_attrib(item); |
---|
1102 | | - u8 flags = da->da_dev->transport->transport_flags; |
---|
| 1141 | + u8 flags = da->da_dev->transport_flags; |
---|
1103 | 1142 | |
---|
1104 | 1143 | return snprintf(page, PAGE_SIZE, "%d\n", |
---|
1105 | 1144 | flags & TRANSPORT_FLAG_PASSTHROUGH_PGR ? 0 : 1); |
---|
| 1145 | +} |
---|
| 1146 | + |
---|
| 1147 | +static ssize_t pgr_support_store(struct config_item *item, |
---|
| 1148 | + const char *page, size_t count) |
---|
| 1149 | +{ |
---|
| 1150 | + struct se_dev_attrib *da = to_attrib(item); |
---|
| 1151 | + struct se_device *dev = da->da_dev; |
---|
| 1152 | + bool flag, oldflag; |
---|
| 1153 | + int ret; |
---|
| 1154 | + |
---|
| 1155 | + ret = strtobool(page, &flag); |
---|
| 1156 | + if (ret < 0) |
---|
| 1157 | + return ret; |
---|
| 1158 | + |
---|
| 1159 | + oldflag = !(dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR); |
---|
| 1160 | + if (flag == oldflag) |
---|
| 1161 | + return count; |
---|
| 1162 | + |
---|
| 1163 | + if (!(dev->transport->transport_flags_changeable & |
---|
| 1164 | + TRANSPORT_FLAG_PASSTHROUGH_PGR)) { |
---|
| 1165 | + pr_err("dev[%p]: Unable to change SE Device pgr_support:" |
---|
| 1166 | + " pgr_support has fixed value\n", dev); |
---|
| 1167 | + return -ENOSYS; |
---|
| 1168 | + } |
---|
| 1169 | + |
---|
| 1170 | + if (flag) |
---|
| 1171 | + dev->transport_flags &= ~TRANSPORT_FLAG_PASSTHROUGH_PGR; |
---|
| 1172 | + else |
---|
| 1173 | + dev->transport_flags |= TRANSPORT_FLAG_PASSTHROUGH_PGR; |
---|
| 1174 | + return count; |
---|
1106 | 1175 | } |
---|
1107 | 1176 | |
---|
1108 | 1177 | CONFIGFS_ATTR(, emulate_model_alias); |
---|
.. | .. |
---|
1116 | 1185 | CONFIGFS_ATTR(, emulate_tpws); |
---|
1117 | 1186 | CONFIGFS_ATTR(, emulate_caw); |
---|
1118 | 1187 | CONFIGFS_ATTR(, emulate_3pc); |
---|
| 1188 | +CONFIGFS_ATTR(, emulate_pr); |
---|
1119 | 1189 | CONFIGFS_ATTR(, pi_prot_type); |
---|
1120 | 1190 | CONFIGFS_ATTR_RO(, hw_pi_prot_type); |
---|
1121 | 1191 | CONFIGFS_ATTR(, pi_prot_format); |
---|
.. | .. |
---|
1136 | 1206 | CONFIGFS_ATTR(, unmap_granularity_alignment); |
---|
1137 | 1207 | CONFIGFS_ATTR(, unmap_zeroes_data); |
---|
1138 | 1208 | CONFIGFS_ATTR(, max_write_same_len); |
---|
1139 | | -CONFIGFS_ATTR_RO(, alua_support); |
---|
1140 | | -CONFIGFS_ATTR_RO(, pgr_support); |
---|
| 1209 | +CONFIGFS_ATTR(, alua_support); |
---|
| 1210 | +CONFIGFS_ATTR(, pgr_support); |
---|
1141 | 1211 | |
---|
1142 | 1212 | /* |
---|
1143 | 1213 | * dev_attrib attributes for devices using the target core SBC/SPC |
---|
.. | .. |
---|
1156 | 1226 | &attr_emulate_tpws, |
---|
1157 | 1227 | &attr_emulate_caw, |
---|
1158 | 1228 | &attr_emulate_3pc, |
---|
| 1229 | + &attr_emulate_pr, |
---|
1159 | 1230 | &attr_pi_prot_type, |
---|
1160 | 1231 | &attr_hw_pi_prot_type, |
---|
1161 | 1232 | &attr_pi_prot_format, |
---|
.. | .. |
---|
1192 | 1263 | &attr_hw_block_size, |
---|
1193 | 1264 | &attr_hw_max_sectors, |
---|
1194 | 1265 | &attr_hw_queue_depth, |
---|
| 1266 | + &attr_emulate_pr, |
---|
1195 | 1267 | &attr_alua_support, |
---|
1196 | 1268 | &attr_pgr_support, |
---|
1197 | 1269 | NULL, |
---|
1198 | 1270 | }; |
---|
1199 | 1271 | EXPORT_SYMBOL(passthrough_attrib_attrs); |
---|
| 1272 | + |
---|
| 1273 | +/* |
---|
| 1274 | + * pr related dev_attrib attributes for devices passing through CDBs, |
---|
| 1275 | + * but allowing in core pr emulation. |
---|
| 1276 | + */ |
---|
| 1277 | +struct configfs_attribute *passthrough_pr_attrib_attrs[] = { |
---|
| 1278 | + &attr_enforce_pr_isids, |
---|
| 1279 | + &attr_force_pr_aptpl, |
---|
| 1280 | + NULL, |
---|
| 1281 | +}; |
---|
| 1282 | +EXPORT_SYMBOL(passthrough_pr_attrib_attrs); |
---|
1200 | 1283 | |
---|
1201 | 1284 | TB_CIT_SETUP_DRV(dev_attrib, NULL, NULL); |
---|
1202 | 1285 | TB_CIT_SETUP_DRV(dev_action, NULL, NULL); |
---|
.. | .. |
---|
1208 | 1291 | static struct t10_wwn *to_t10_wwn(struct config_item *item) |
---|
1209 | 1292 | { |
---|
1210 | 1293 | return container_of(to_config_group(item), struct t10_wwn, t10_wwn_group); |
---|
| 1294 | +} |
---|
| 1295 | + |
---|
| 1296 | +static ssize_t target_check_inquiry_data(char *buf) |
---|
| 1297 | +{ |
---|
| 1298 | + size_t len; |
---|
| 1299 | + int i; |
---|
| 1300 | + |
---|
| 1301 | + len = strlen(buf); |
---|
| 1302 | + |
---|
| 1303 | + /* |
---|
| 1304 | + * SPC 4.3.1: |
---|
| 1305 | + * ASCII data fields shall contain only ASCII printable characters |
---|
| 1306 | + * (i.e., code values 20h to 7Eh) and may be terminated with one or |
---|
| 1307 | + * more ASCII null (00h) characters. |
---|
| 1308 | + */ |
---|
| 1309 | + for (i = 0; i < len; i++) { |
---|
| 1310 | + if (buf[i] < 0x20 || buf[i] > 0x7E) { |
---|
| 1311 | + pr_err("Emulated T10 Inquiry Data contains non-ASCII-printable characters\n"); |
---|
| 1312 | + return -EINVAL; |
---|
| 1313 | + } |
---|
| 1314 | + } |
---|
| 1315 | + |
---|
| 1316 | + return len; |
---|
| 1317 | +} |
---|
| 1318 | + |
---|
| 1319 | +/* |
---|
| 1320 | + * STANDARD and VPD page 0x83 T10 Vendor Identification |
---|
| 1321 | + */ |
---|
| 1322 | +static ssize_t target_wwn_vendor_id_show(struct config_item *item, |
---|
| 1323 | + char *page) |
---|
| 1324 | +{ |
---|
| 1325 | + return sprintf(page, "%s\n", &to_t10_wwn(item)->vendor[0]); |
---|
| 1326 | +} |
---|
| 1327 | + |
---|
| 1328 | +static ssize_t target_wwn_vendor_id_store(struct config_item *item, |
---|
| 1329 | + const char *page, size_t count) |
---|
| 1330 | +{ |
---|
| 1331 | + struct t10_wwn *t10_wwn = to_t10_wwn(item); |
---|
| 1332 | + struct se_device *dev = t10_wwn->t10_dev; |
---|
| 1333 | + /* +2 to allow for a trailing (stripped) '\n' and null-terminator */ |
---|
| 1334 | + unsigned char buf[INQUIRY_VENDOR_LEN + 2]; |
---|
| 1335 | + char *stripped = NULL; |
---|
| 1336 | + size_t len; |
---|
| 1337 | + ssize_t ret; |
---|
| 1338 | + |
---|
| 1339 | + len = strlcpy(buf, page, sizeof(buf)); |
---|
| 1340 | + if (len < sizeof(buf)) { |
---|
| 1341 | + /* Strip any newline added from userspace. */ |
---|
| 1342 | + stripped = strstrip(buf); |
---|
| 1343 | + len = strlen(stripped); |
---|
| 1344 | + } |
---|
| 1345 | + if (len > INQUIRY_VENDOR_LEN) { |
---|
| 1346 | + pr_err("Emulated T10 Vendor Identification exceeds" |
---|
| 1347 | + " INQUIRY_VENDOR_LEN: " __stringify(INQUIRY_VENDOR_LEN) |
---|
| 1348 | + "\n"); |
---|
| 1349 | + return -EOVERFLOW; |
---|
| 1350 | + } |
---|
| 1351 | + |
---|
| 1352 | + ret = target_check_inquiry_data(stripped); |
---|
| 1353 | + |
---|
| 1354 | + if (ret < 0) |
---|
| 1355 | + return ret; |
---|
| 1356 | + |
---|
| 1357 | + /* |
---|
| 1358 | + * Check to see if any active exports exist. If they do exist, fail |
---|
| 1359 | + * here as changing this information on the fly (underneath the |
---|
| 1360 | + * initiator side OS dependent multipath code) could cause negative |
---|
| 1361 | + * effects. |
---|
| 1362 | + */ |
---|
| 1363 | + if (dev->export_count) { |
---|
| 1364 | + pr_err("Unable to set T10 Vendor Identification while" |
---|
| 1365 | + " active %d exports exist\n", dev->export_count); |
---|
| 1366 | + return -EINVAL; |
---|
| 1367 | + } |
---|
| 1368 | + |
---|
| 1369 | + BUILD_BUG_ON(sizeof(dev->t10_wwn.vendor) != INQUIRY_VENDOR_LEN + 1); |
---|
| 1370 | + strlcpy(dev->t10_wwn.vendor, stripped, sizeof(dev->t10_wwn.vendor)); |
---|
| 1371 | + |
---|
| 1372 | + pr_debug("Target_Core_ConfigFS: Set emulated T10 Vendor Identification:" |
---|
| 1373 | + " %s\n", dev->t10_wwn.vendor); |
---|
| 1374 | + |
---|
| 1375 | + return count; |
---|
| 1376 | +} |
---|
| 1377 | + |
---|
| 1378 | +static ssize_t target_wwn_product_id_show(struct config_item *item, |
---|
| 1379 | + char *page) |
---|
| 1380 | +{ |
---|
| 1381 | + return sprintf(page, "%s\n", &to_t10_wwn(item)->model[0]); |
---|
| 1382 | +} |
---|
| 1383 | + |
---|
| 1384 | +static ssize_t target_wwn_product_id_store(struct config_item *item, |
---|
| 1385 | + const char *page, size_t count) |
---|
| 1386 | +{ |
---|
| 1387 | + struct t10_wwn *t10_wwn = to_t10_wwn(item); |
---|
| 1388 | + struct se_device *dev = t10_wwn->t10_dev; |
---|
| 1389 | + /* +2 to allow for a trailing (stripped) '\n' and null-terminator */ |
---|
| 1390 | + unsigned char buf[INQUIRY_MODEL_LEN + 2]; |
---|
| 1391 | + char *stripped = NULL; |
---|
| 1392 | + size_t len; |
---|
| 1393 | + ssize_t ret; |
---|
| 1394 | + |
---|
| 1395 | + len = strlcpy(buf, page, sizeof(buf)); |
---|
| 1396 | + if (len < sizeof(buf)) { |
---|
| 1397 | + /* Strip any newline added from userspace. */ |
---|
| 1398 | + stripped = strstrip(buf); |
---|
| 1399 | + len = strlen(stripped); |
---|
| 1400 | + } |
---|
| 1401 | + if (len > INQUIRY_MODEL_LEN) { |
---|
| 1402 | + pr_err("Emulated T10 Vendor exceeds INQUIRY_MODEL_LEN: " |
---|
| 1403 | + __stringify(INQUIRY_MODEL_LEN) |
---|
| 1404 | + "\n"); |
---|
| 1405 | + return -EOVERFLOW; |
---|
| 1406 | + } |
---|
| 1407 | + |
---|
| 1408 | + ret = target_check_inquiry_data(stripped); |
---|
| 1409 | + |
---|
| 1410 | + if (ret < 0) |
---|
| 1411 | + return ret; |
---|
| 1412 | + |
---|
| 1413 | + /* |
---|
| 1414 | + * Check to see if any active exports exist. If they do exist, fail |
---|
| 1415 | + * here as changing this information on the fly (underneath the |
---|
| 1416 | + * initiator side OS dependent multipath code) could cause negative |
---|
| 1417 | + * effects. |
---|
| 1418 | + */ |
---|
| 1419 | + if (dev->export_count) { |
---|
| 1420 | + pr_err("Unable to set T10 Model while active %d exports exist\n", |
---|
| 1421 | + dev->export_count); |
---|
| 1422 | + return -EINVAL; |
---|
| 1423 | + } |
---|
| 1424 | + |
---|
| 1425 | + BUILD_BUG_ON(sizeof(dev->t10_wwn.model) != INQUIRY_MODEL_LEN + 1); |
---|
| 1426 | + strlcpy(dev->t10_wwn.model, stripped, sizeof(dev->t10_wwn.model)); |
---|
| 1427 | + |
---|
| 1428 | + pr_debug("Target_Core_ConfigFS: Set emulated T10 Model Identification: %s\n", |
---|
| 1429 | + dev->t10_wwn.model); |
---|
| 1430 | + |
---|
| 1431 | + return count; |
---|
| 1432 | +} |
---|
| 1433 | + |
---|
| 1434 | +static ssize_t target_wwn_revision_show(struct config_item *item, |
---|
| 1435 | + char *page) |
---|
| 1436 | +{ |
---|
| 1437 | + return sprintf(page, "%s\n", &to_t10_wwn(item)->revision[0]); |
---|
| 1438 | +} |
---|
| 1439 | + |
---|
| 1440 | +static ssize_t target_wwn_revision_store(struct config_item *item, |
---|
| 1441 | + const char *page, size_t count) |
---|
| 1442 | +{ |
---|
| 1443 | + struct t10_wwn *t10_wwn = to_t10_wwn(item); |
---|
| 1444 | + struct se_device *dev = t10_wwn->t10_dev; |
---|
| 1445 | + /* +2 to allow for a trailing (stripped) '\n' and null-terminator */ |
---|
| 1446 | + unsigned char buf[INQUIRY_REVISION_LEN + 2]; |
---|
| 1447 | + char *stripped = NULL; |
---|
| 1448 | + size_t len; |
---|
| 1449 | + ssize_t ret; |
---|
| 1450 | + |
---|
| 1451 | + len = strlcpy(buf, page, sizeof(buf)); |
---|
| 1452 | + if (len < sizeof(buf)) { |
---|
| 1453 | + /* Strip any newline added from userspace. */ |
---|
| 1454 | + stripped = strstrip(buf); |
---|
| 1455 | + len = strlen(stripped); |
---|
| 1456 | + } |
---|
| 1457 | + if (len > INQUIRY_REVISION_LEN) { |
---|
| 1458 | + pr_err("Emulated T10 Revision exceeds INQUIRY_REVISION_LEN: " |
---|
| 1459 | + __stringify(INQUIRY_REVISION_LEN) |
---|
| 1460 | + "\n"); |
---|
| 1461 | + return -EOVERFLOW; |
---|
| 1462 | + } |
---|
| 1463 | + |
---|
| 1464 | + ret = target_check_inquiry_data(stripped); |
---|
| 1465 | + |
---|
| 1466 | + if (ret < 0) |
---|
| 1467 | + return ret; |
---|
| 1468 | + |
---|
| 1469 | + /* |
---|
| 1470 | + * Check to see if any active exports exist. If they do exist, fail |
---|
| 1471 | + * here as changing this information on the fly (underneath the |
---|
| 1472 | + * initiator side OS dependent multipath code) could cause negative |
---|
| 1473 | + * effects. |
---|
| 1474 | + */ |
---|
| 1475 | + if (dev->export_count) { |
---|
| 1476 | + pr_err("Unable to set T10 Revision while active %d exports exist\n", |
---|
| 1477 | + dev->export_count); |
---|
| 1478 | + return -EINVAL; |
---|
| 1479 | + } |
---|
| 1480 | + |
---|
| 1481 | + BUILD_BUG_ON(sizeof(dev->t10_wwn.revision) != INQUIRY_REVISION_LEN + 1); |
---|
| 1482 | + strlcpy(dev->t10_wwn.revision, stripped, sizeof(dev->t10_wwn.revision)); |
---|
| 1483 | + |
---|
| 1484 | + pr_debug("Target_Core_ConfigFS: Set emulated T10 Revision: %s\n", |
---|
| 1485 | + dev->t10_wwn.revision); |
---|
| 1486 | + |
---|
| 1487 | + return count; |
---|
1211 | 1488 | } |
---|
1212 | 1489 | |
---|
1213 | 1490 | /* |
---|
.. | .. |
---|
1356 | 1633 | /* VPD page 0x83 Association: SCSI Target Device */ |
---|
1357 | 1634 | DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_scsi_target_device, 0x20); |
---|
1358 | 1635 | |
---|
| 1636 | +CONFIGFS_ATTR(target_wwn_, vendor_id); |
---|
| 1637 | +CONFIGFS_ATTR(target_wwn_, product_id); |
---|
| 1638 | +CONFIGFS_ATTR(target_wwn_, revision); |
---|
1359 | 1639 | CONFIGFS_ATTR(target_wwn_, vpd_unit_serial); |
---|
1360 | 1640 | CONFIGFS_ATTR_RO(target_wwn_, vpd_protocol_identifier); |
---|
1361 | 1641 | CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_logical_unit); |
---|
.. | .. |
---|
1363 | 1643 | CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_scsi_target_device); |
---|
1364 | 1644 | |
---|
1365 | 1645 | static struct configfs_attribute *target_core_dev_wwn_attrs[] = { |
---|
| 1646 | + &target_wwn_attr_vendor_id, |
---|
| 1647 | + &target_wwn_attr_product_id, |
---|
| 1648 | + &target_wwn_attr_revision, |
---|
1366 | 1649 | &target_wwn_attr_vpd_unit_serial, |
---|
1367 | 1650 | &target_wwn_attr_vpd_protocol_identifier, |
---|
1368 | 1651 | &target_wwn_attr_vpd_assoc_logical_unit, |
---|
.. | .. |
---|
1400 | 1683 | core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN); |
---|
1401 | 1684 | |
---|
1402 | 1685 | return sprintf(page, "SPC-3 Reservation: %s Initiator: %s%s\n", |
---|
1403 | | - se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), |
---|
| 1686 | + se_nacl->se_tpg->se_tpg_tfo->fabric_name, |
---|
1404 | 1687 | se_nacl->initiatorname, i_buf); |
---|
1405 | 1688 | } |
---|
1406 | 1689 | |
---|
1407 | 1690 | static ssize_t target_core_dev_pr_show_spc2_res(struct se_device *dev, |
---|
1408 | 1691 | char *page) |
---|
1409 | 1692 | { |
---|
| 1693 | + struct se_session *sess = dev->reservation_holder; |
---|
1410 | 1694 | struct se_node_acl *se_nacl; |
---|
1411 | 1695 | ssize_t len; |
---|
1412 | 1696 | |
---|
1413 | | - se_nacl = dev->dev_reserved_node_acl; |
---|
1414 | | - if (se_nacl) { |
---|
| 1697 | + if (sess) { |
---|
| 1698 | + se_nacl = sess->se_node_acl; |
---|
1415 | 1699 | len = sprintf(page, |
---|
1416 | 1700 | "SPC-2 Reservation: %s Initiator: %s\n", |
---|
1417 | | - se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), |
---|
| 1701 | + se_nacl->se_tpg->se_tpg_tfo->fabric_name, |
---|
1418 | 1702 | se_nacl->initiatorname); |
---|
1419 | 1703 | } else { |
---|
1420 | 1704 | len = sprintf(page, "No SPC-2 Reservation holder\n"); |
---|
.. | .. |
---|
1427 | 1711 | struct se_device *dev = pr_to_dev(item); |
---|
1428 | 1712 | int ret; |
---|
1429 | 1713 | |
---|
1430 | | - if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR) |
---|
| 1714 | + if (!dev->dev_attrib.emulate_pr) |
---|
| 1715 | + return sprintf(page, "SPC_RESERVATIONS_DISABLED\n"); |
---|
| 1716 | + |
---|
| 1717 | + if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR) |
---|
1431 | 1718 | return sprintf(page, "Passthrough\n"); |
---|
1432 | 1719 | |
---|
1433 | 1720 | spin_lock(&dev->dev_reservation_lock); |
---|
.. | .. |
---|
1489 | 1776 | tfo = se_tpg->se_tpg_tfo; |
---|
1490 | 1777 | |
---|
1491 | 1778 | len += sprintf(page+len, "SPC-3 Reservation: %s" |
---|
1492 | | - " Target Node Endpoint: %s\n", tfo->get_fabric_name(), |
---|
| 1779 | + " Target Node Endpoint: %s\n", tfo->fabric_name, |
---|
1493 | 1780 | tfo->tpg_get_wwn(se_tpg)); |
---|
1494 | 1781 | len += sprintf(page+len, "SPC-3 Reservation: Relative Port" |
---|
1495 | 1782 | " Identifier Tag: %hu %s Portal Group Tag: %hu" |
---|
1496 | 1783 | " %s Logical Unit: %llu\n", pr_reg->tg_pt_sep_rtpi, |
---|
1497 | | - tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg), |
---|
1498 | | - tfo->get_fabric_name(), pr_reg->pr_aptpl_target_lun); |
---|
| 1784 | + tfo->fabric_name, tfo->tpg_get_tag(se_tpg), |
---|
| 1785 | + tfo->fabric_name, pr_reg->pr_aptpl_target_lun); |
---|
1499 | 1786 | |
---|
1500 | 1787 | out_unlock: |
---|
1501 | 1788 | spin_unlock(&dev->dev_reservation_lock); |
---|
.. | .. |
---|
1526 | 1813 | core_pr_dump_initiator_port(pr_reg, i_buf, |
---|
1527 | 1814 | PR_REG_ISID_ID_LEN); |
---|
1528 | 1815 | sprintf(buf, "%s Node: %s%s Key: 0x%016Lx PRgen: 0x%08x\n", |
---|
1529 | | - tfo->get_fabric_name(), |
---|
| 1816 | + tfo->fabric_name, |
---|
1530 | 1817 | pr_reg->pr_reg_nacl->initiatorname, i_buf, pr_reg->pr_res_key, |
---|
1531 | 1818 | pr_reg->pr_res_generation); |
---|
1532 | 1819 | |
---|
.. | .. |
---|
1567 | 1854 | { |
---|
1568 | 1855 | struct se_device *dev = pr_to_dev(item); |
---|
1569 | 1856 | |
---|
1570 | | - if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR) |
---|
| 1857 | + if (!dev->dev_attrib.emulate_pr) |
---|
| 1858 | + return sprintf(page, "SPC_RESERVATIONS_DISABLED\n"); |
---|
| 1859 | + if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR) |
---|
1571 | 1860 | return sprintf(page, "SPC_PASSTHROUGH\n"); |
---|
1572 | | - else if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) |
---|
| 1861 | + if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) |
---|
1573 | 1862 | return sprintf(page, "SPC2_RESERVATIONS\n"); |
---|
1574 | | - else |
---|
1575 | | - return sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n"); |
---|
| 1863 | + |
---|
| 1864 | + return sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n"); |
---|
1576 | 1865 | } |
---|
1577 | 1866 | |
---|
1578 | 1867 | static ssize_t target_pr_res_aptpl_active_show(struct config_item *item, |
---|
.. | .. |
---|
1580 | 1869 | { |
---|
1581 | 1870 | struct se_device *dev = pr_to_dev(item); |
---|
1582 | 1871 | |
---|
1583 | | - if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR) |
---|
| 1872 | + if (!dev->dev_attrib.emulate_pr || |
---|
| 1873 | + (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)) |
---|
1584 | 1874 | return 0; |
---|
1585 | 1875 | |
---|
1586 | 1876 | return sprintf(page, "APTPL Bit Status: %s\n", |
---|
.. | .. |
---|
1592 | 1882 | { |
---|
1593 | 1883 | struct se_device *dev = pr_to_dev(item); |
---|
1594 | 1884 | |
---|
1595 | | - if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR) |
---|
| 1885 | + if (!dev->dev_attrib.emulate_pr || |
---|
| 1886 | + (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)) |
---|
1596 | 1887 | return 0; |
---|
1597 | 1888 | |
---|
1598 | 1889 | return sprintf(page, "Ready to process PR APTPL metadata..\n"); |
---|
.. | .. |
---|
1638 | 1929 | u16 tpgt = 0; |
---|
1639 | 1930 | u8 type = 0; |
---|
1640 | 1931 | |
---|
1641 | | - if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR) |
---|
| 1932 | + if (!dev->dev_attrib.emulate_pr || |
---|
| 1933 | + (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)) |
---|
1642 | 1934 | return count; |
---|
1643 | 1935 | if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) |
---|
1644 | 1936 | return count; |
---|
.. | .. |
---|
2746 | 3038 | struct se_portal_group *tpg = lun->lun_tpg; |
---|
2747 | 3039 | |
---|
2748 | 3040 | cur_len = snprintf(buf, TG_PT_GROUP_NAME_BUF, "%s/%s/tpgt_%hu" |
---|
2749 | | - "/%s\n", tpg->se_tpg_tfo->get_fabric_name(), |
---|
| 3041 | + "/%s\n", tpg->se_tpg_tfo->fabric_name, |
---|
2750 | 3042 | tpg->se_tpg_tfo->tpg_get_wwn(tpg), |
---|
2751 | 3043 | tpg->se_tpg_tfo->tpg_get_tag(tpg), |
---|
2752 | 3044 | config_item_name(&lun->lun_group.cg_item)); |
---|
.. | .. |
---|
3360 | 3652 | MODULE_DESCRIPTION("Target_Core_Mod/ConfigFS"); |
---|
3361 | 3653 | MODULE_AUTHOR("nab@Linux-iSCSI.org"); |
---|
3362 | 3654 | MODULE_LICENSE("GPL"); |
---|
| 3655 | +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); |
---|
3363 | 3656 | |
---|
3364 | 3657 | module_init(target_core_init_configfs); |
---|
3365 | 3658 | module_exit(target_core_exit_configfs); |
---|