Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: target: Add device product id and revision configfs attributes

The product_id and revision attributes will allow for the modification of
the T10 Model and Revision strings returned in inquiry responses. Its
value can be viewed and modified via the ConfigFS path at:

target/core/$backstore/$name/wwn/product_id
target/core/$backstore/$name/wwn/revision

[mkp: dropped parentheses as requested by Bart]

Signed-off-by: Alan Adamson <alan.adamson@oracle.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Alan Adamson and committed by
Martin K. Petersen
0322913c 171f1887

+142 -15
+142 -15
drivers/target/target_core_configfs.c
··· 1227 1227 return container_of(to_config_group(item), struct t10_wwn, t10_wwn_group); 1228 1228 } 1229 1229 1230 + static ssize_t target_check_inquiry_data(char *buf) 1231 + { 1232 + size_t len; 1233 + int i; 1234 + 1235 + len = strlen(buf); 1236 + 1237 + /* 1238 + * SPC 4.3.1: 1239 + * ASCII data fields shall contain only ASCII printable characters 1240 + * (i.e., code values 20h to 7Eh) and may be terminated with one or 1241 + * more ASCII null (00h) characters. 1242 + */ 1243 + for (i = 0; i < len; i++) { 1244 + if (buf[i] < 0x20 || buf[i] > 0x7E) { 1245 + pr_err("Emulated T10 Inquiry Data contains non-ASCII-printable characters\n"); 1246 + return -EINVAL; 1247 + } 1248 + } 1249 + 1250 + return len; 1251 + } 1252 + 1230 1253 /* 1231 1254 * STANDARD and VPD page 0x83 T10 Vendor Identification 1232 1255 */ ··· 1267 1244 /* +2 to allow for a trailing (stripped) '\n' and null-terminator */ 1268 1245 unsigned char buf[INQUIRY_VENDOR_LEN + 2]; 1269 1246 char *stripped = NULL; 1270 - size_t len; 1271 - int i; 1247 + size_t len, ret; 1272 1248 1273 1249 len = strlcpy(buf, page, sizeof(buf)); 1274 1250 if (len < sizeof(buf)) { ··· 1282 1260 return -EOVERFLOW; 1283 1261 } 1284 1262 1285 - /* 1286 - * SPC 4.3.1: 1287 - * ASCII data fields shall contain only ASCII printable characters (i.e., 1288 - * code values 20h to 7Eh) and may be terminated with one or more ASCII 1289 - * null (00h) characters. 1290 - */ 1291 - for (i = 0; i < len; i++) { 1292 - if ((stripped[i] < 0x20) || (stripped[i] > 0x7E)) { 1293 - pr_err("Emulated T10 Vendor Identification contains" 1294 - " non-ASCII-printable characters\n"); 1295 - return -EINVAL; 1296 - } 1297 - } 1263 + ret = target_check_inquiry_data(stripped); 1264 + 1265 + if (ret < 0) 1266 + return ret; 1298 1267 1299 1268 /* 1300 1269 * Check to see if any active exports exist. If they do exist, fail ··· 1304 1291 1305 1292 pr_debug("Target_Core_ConfigFS: Set emulated T10 Vendor Identification:" 1306 1293 " %s\n", dev->t10_wwn.vendor); 1294 + 1295 + return count; 1296 + } 1297 + 1298 + static ssize_t target_wwn_product_id_show(struct config_item *item, 1299 + char *page) 1300 + { 1301 + return sprintf(page, "%s\n", &to_t10_wwn(item)->model[0]); 1302 + } 1303 + 1304 + static ssize_t target_wwn_product_id_store(struct config_item *item, 1305 + const char *page, size_t count) 1306 + { 1307 + struct t10_wwn *t10_wwn = to_t10_wwn(item); 1308 + struct se_device *dev = t10_wwn->t10_dev; 1309 + /* +2 to allow for a trailing (stripped) '\n' and null-terminator */ 1310 + unsigned char buf[INQUIRY_MODEL_LEN + 2]; 1311 + char *stripped = NULL; 1312 + size_t len, ret; 1313 + 1314 + len = strlcpy(buf, page, sizeof(buf)); 1315 + if (len < sizeof(buf)) { 1316 + /* Strip any newline added from userspace. */ 1317 + stripped = strstrip(buf); 1318 + len = strlen(stripped); 1319 + } 1320 + if (len > INQUIRY_MODEL_LEN) { 1321 + pr_err("Emulated T10 Vendor exceeds INQUIRY_MODEL_LEN: " 1322 + __stringify(INQUIRY_MODEL_LEN) 1323 + "\n"); 1324 + return -EOVERFLOW; 1325 + } 1326 + 1327 + ret = target_check_inquiry_data(stripped); 1328 + 1329 + if (ret < 0) 1330 + return ret; 1331 + 1332 + /* 1333 + * Check to see if any active exports exist. If they do exist, fail 1334 + * here as changing this information on the fly (underneath the 1335 + * initiator side OS dependent multipath code) could cause negative 1336 + * effects. 1337 + */ 1338 + if (dev->export_count) { 1339 + pr_err("Unable to set T10 Model while active %d exports exist\n", 1340 + dev->export_count); 1341 + return -EINVAL; 1342 + } 1343 + 1344 + BUILD_BUG_ON(sizeof(dev->t10_wwn.model) != INQUIRY_MODEL_LEN + 1); 1345 + strlcpy(dev->t10_wwn.model, stripped, sizeof(dev->t10_wwn.model)); 1346 + 1347 + pr_debug("Target_Core_ConfigFS: Set emulated T10 Model Identification: %s\n", 1348 + dev->t10_wwn.model); 1349 + 1350 + return count; 1351 + } 1352 + 1353 + static ssize_t target_wwn_revision_show(struct config_item *item, 1354 + char *page) 1355 + { 1356 + return sprintf(page, "%s\n", &to_t10_wwn(item)->revision[0]); 1357 + } 1358 + 1359 + static ssize_t target_wwn_revision_store(struct config_item *item, 1360 + const char *page, size_t count) 1361 + { 1362 + struct t10_wwn *t10_wwn = to_t10_wwn(item); 1363 + struct se_device *dev = t10_wwn->t10_dev; 1364 + /* +2 to allow for a trailing (stripped) '\n' and null-terminator */ 1365 + unsigned char buf[INQUIRY_REVISION_LEN + 2]; 1366 + char *stripped = NULL; 1367 + size_t len, ret; 1368 + 1369 + len = strlcpy(buf, page, sizeof(buf)); 1370 + if (len < sizeof(buf)) { 1371 + /* Strip any newline added from userspace. */ 1372 + stripped = strstrip(buf); 1373 + len = strlen(stripped); 1374 + } 1375 + if (len > INQUIRY_REVISION_LEN) { 1376 + pr_err("Emulated T10 Revision exceeds INQUIRY_REVISION_LEN: " 1377 + __stringify(INQUIRY_REVISION_LEN) 1378 + "\n"); 1379 + return -EOVERFLOW; 1380 + } 1381 + 1382 + ret = target_check_inquiry_data(stripped); 1383 + 1384 + if (ret < 0) 1385 + return ret; 1386 + 1387 + /* 1388 + * Check to see if any active exports exist. If they do exist, fail 1389 + * here as changing this information on the fly (underneath the 1390 + * initiator side OS dependent multipath code) could cause negative 1391 + * effects. 1392 + */ 1393 + if (dev->export_count) { 1394 + pr_err("Unable to set T10 Revision while active %d exports exist\n", 1395 + dev->export_count); 1396 + return -EINVAL; 1397 + } 1398 + 1399 + BUILD_BUG_ON(sizeof(dev->t10_wwn.revision) != INQUIRY_REVISION_LEN + 1); 1400 + strlcpy(dev->t10_wwn.revision, stripped, sizeof(dev->t10_wwn.revision)); 1401 + 1402 + pr_debug("Target_Core_ConfigFS: Set emulated T10 Revision: %s\n", 1403 + dev->t10_wwn.revision); 1307 1404 1308 1405 return count; 1309 1406 } ··· 1565 1442 DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_scsi_target_device, 0x20); 1566 1443 1567 1444 CONFIGFS_ATTR(target_wwn_, vendor_id); 1445 + CONFIGFS_ATTR(target_wwn_, product_id); 1446 + CONFIGFS_ATTR(target_wwn_, revision); 1568 1447 CONFIGFS_ATTR(target_wwn_, vpd_unit_serial); 1569 1448 CONFIGFS_ATTR_RO(target_wwn_, vpd_protocol_identifier); 1570 1449 CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_logical_unit); ··· 1575 1450 1576 1451 static struct configfs_attribute *target_core_dev_wwn_attrs[] = { 1577 1452 &target_wwn_attr_vendor_id, 1453 + &target_wwn_attr_product_id, 1454 + &target_wwn_attr_revision, 1578 1455 &target_wwn_attr_vpd_unit_serial, 1579 1456 &target_wwn_attr_vpd_protocol_identifier, 1580 1457 &target_wwn_attr_vpd_assoc_logical_unit,