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

Configure Feed

Select the types of activity you want to include in your feed.

scsi: core: Add 'serial' sysfs attribute for SCSI/SATA

Add a 'serial' sysfs attribute for SCSI and SATA devices. This attribute
exposes the Unit Serial Number, which is derived from the Device
Identification Vital Product Data (VPD) page 0x80.

Whitespace is stripped from the retrieved serial number to handle the
different alignment (right-aligned for SCSI, potentially left-aligned for
SATA). As noted in SAT-5 10.5.3, "Although SPC-5 defines the PRODUCT SERIAL
NUMBER field as right-aligned, ACS-5 does not require its SERIAL NUMBER
field to be right-aligned. Therefore, right-alignment of the PRODUCT SERIAL
NUMBER field for the translation is not assured."

This attribute is used by tools such as lsblk to display the serial number
of block devices.

[mkp: length adjustment]

Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Link: https://patch.msgid.link/20260209212151.342151-1-ipylypiv@google.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Igor Pylypiv and committed by
Martin K. Petersen
94c125ba 690d41fa

+64
+47
drivers/scsi/scsi_lib.c
··· 13 13 #include <linux/bitops.h> 14 14 #include <linux/blkdev.h> 15 15 #include <linux/completion.h> 16 + #include <linux/ctype.h> 16 17 #include <linux/kernel.h> 17 18 #include <linux/export.h> 18 19 #include <linux/init.h> ··· 3460 3459 return id_size; 3461 3460 } 3462 3461 EXPORT_SYMBOL(scsi_vpd_lun_id); 3462 + 3463 + /** 3464 + * scsi_vpd_lun_serial - return a unique device serial number 3465 + * @sdev: SCSI device 3466 + * @sn: buffer for the serial number 3467 + * @sn_size: size of the buffer 3468 + * 3469 + * Copies the device serial number into @sn based on the information in 3470 + * the VPD page 0x80 of the device. The string will be null terminated 3471 + * and have leading and trailing whitespace stripped. 3472 + * 3473 + * Returns the length of the serial number or error on failure. 3474 + */ 3475 + int scsi_vpd_lun_serial(struct scsi_device *sdev, char *sn, size_t sn_size) 3476 + { 3477 + const struct scsi_vpd *vpd_pg80; 3478 + const unsigned char *d; 3479 + int len; 3480 + 3481 + guard(rcu)(); 3482 + vpd_pg80 = rcu_dereference(sdev->vpd_pg80); 3483 + if (!vpd_pg80) 3484 + return -ENXIO; 3485 + 3486 + len = vpd_pg80->len - 4; 3487 + d = vpd_pg80->data + 4; 3488 + 3489 + /* Skip leading spaces */ 3490 + while (len > 0 && isspace(*d)) { 3491 + len--; 3492 + d++; 3493 + } 3494 + 3495 + /* Skip trailing spaces */ 3496 + while (len > 0 && isspace(d[len - 1])) 3497 + len--; 3498 + 3499 + if (sn_size < len + 1) 3500 + return -EINVAL; 3501 + 3502 + memcpy(sn, d, len); 3503 + sn[len] = '\0'; 3504 + 3505 + return len; 3506 + } 3507 + EXPORT_SYMBOL(scsi_vpd_lun_serial); 3463 3508 3464 3509 /** 3465 3510 * scsi_vpd_tpg_id - return a target port group identifier
+16
drivers/scsi/scsi_sysfs.c
··· 1051 1051 } 1052 1052 static DEVICE_ATTR(wwid, S_IRUGO, sdev_show_wwid, NULL); 1053 1053 1054 + static ssize_t 1055 + sdev_show_serial(struct device *dev, struct device_attribute *attr, char *buf) 1056 + { 1057 + struct scsi_device *sdev = to_scsi_device(dev); 1058 + ssize_t ret; 1059 + 1060 + ret = scsi_vpd_lun_serial(sdev, buf, PAGE_SIZE - 1); 1061 + if (ret < 0) 1062 + return ret; 1063 + 1064 + buf[ret] = '\n'; 1065 + return ret + 1; 1066 + } 1067 + static DEVICE_ATTR(serial, S_IRUGO, sdev_show_serial, NULL); 1068 + 1054 1069 #define BLIST_FLAG_NAME(name) \ 1055 1070 [const_ilog2((__force __u64)BLIST_##name)] = #name 1056 1071 static const char *const sdev_bflags_name[] = { ··· 1310 1295 &dev_attr_device_busy.attr, 1311 1296 &dev_attr_vendor.attr, 1312 1297 &dev_attr_model.attr, 1298 + &dev_attr_serial.attr, 1313 1299 &dev_attr_rev.attr, 1314 1300 &dev_attr_rescan.attr, 1315 1301 &dev_attr_delete.attr,
+1
include/scsi/scsi_device.h
··· 571 571 extern void sdev_disable_disk_events(struct scsi_device *sdev); 572 572 extern void sdev_enable_disk_events(struct scsi_device *sdev); 573 573 extern int scsi_vpd_lun_id(struct scsi_device *, char *, size_t); 574 + extern int scsi_vpd_lun_serial(struct scsi_device *, char *, size_t); 574 575 extern int scsi_vpd_tpg_id(struct scsi_device *, int *); 575 576 576 577 #ifdef CONFIG_PM