From 4e9fdfccbdd16f0cfdb5c8fa8484a8ba0f2e69d3 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Fri, 20 Nov 2009 20:21:58 -0500 Subject: [PATCH] scsi_id: Export WWN and Unit Serial Number Since the Unit Serial Number and the WWN are useful bits of information export them as properties in the udev database. These bits of information are often printed on the physical disk, see http://people.freedesktop.org/~david/FUJITSU-MAY2036RC-sas-disk-picture.jpg and displaying them separately in the UI (or in /dev/disk) might help users identify the physical disk. This patch exports these bits of information as ID_WWN and ID_SCSI_SERIAL. Note that ata_id also use the ID_WWN property since commit 66094a4a7fc1d303e80785d586800eae9841502b (2009-11-04). Also print out ID_SCSI=1 so users of the udev database knows the disk speaks SCSI. Here's the scsi_id output from one of my SAS disks with these changes: ID_SCSI=1 ID_VENDOR=FUJITSU ID_VENDOR_ENC=FUJITSU\x20 ID_MODEL=MAY2036RC ID_MODEL_ENC=MAY2036RC\x20\x20\x20\x20\x20\x20\x20 ID_REVISION=0103 ID_TYPE=disk ID_SERIAL=3500000e01b83f520 ID_SERIAL_SHORT=500000e01b83f520 ID_WWN=0x500000e01b83f520 ID_SCSI_SERIAL=B3G1P8500RWT Unfortunately we can't overload ID_SERIAL for two reasons 1. ID_SERIAL (and ID_SERIAL_SHORT) exported by scsi_id isn't really the unit serial number (as defined by SCSI) - it is sometimes the WWN (since it is more unique than the Unit Serial Number) and complex rules (to make the serial unique) govern what value to use. 2. It would break existing setups if the value of ID_SERIAL changed Signed-off-by: David Zeuthen --- extras/scsi_id/scsi_id.c | 7 +++++ extras/scsi_id/scsi_id.h | 6 ++++ extras/scsi_id/scsi_serial.c | 57 ++++++++++++++++++++++++------------ 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/extras/scsi_id/scsi_id.c b/extras/scsi_id/scsi_id.c index 72a725711..9c5b2c3a3 100644 --- a/extras/scsi_id/scsi_id.c +++ b/extras/scsi_id/scsi_id.c @@ -549,6 +549,7 @@ static int scsi_id(struct udev *udev, char *maj_min_dev) if (export) { char serial_str[MAX_SERIAL_LEN]; + printf("ID_SCSI=1\n"); printf("ID_VENDOR=%s\n", vendor_str); printf("ID_VENDOR_ENC=%s\n", vendor_enc_str); printf("ID_MODEL=%s\n", model_str); @@ -563,6 +564,12 @@ static int scsi_id(struct udev *udev, char *maj_min_dev) udev_util_replace_chars(serial_str, NULL); printf("ID_SERIAL_SHORT=%s\n", serial_str); } + if (dev_scsi.wwn[0] != '\0') { + printf("ID_WWN=0x%s\n", dev_scsi.wwn); + } + if (dev_scsi.unit_serial_number[0] != '\0') { + printf("ID_SCSI_SERIAL=%s\n", dev_scsi.unit_serial_number); + } goto out; } diff --git a/extras/scsi_id/scsi_id.h b/extras/scsi_id/scsi_id.h index 9fcadec17..4536cfd4f 100644 --- a/extras/scsi_id/scsi_id.h +++ b/extras/scsi_id/scsi_id.h @@ -39,6 +39,12 @@ struct scsi_id_device { char serial[MAX_SERIAL_LEN]; char serial_short[MAX_SERIAL_LEN]; int use_sg; + + /* Always from page 0x80 e.g. 'B3G1P8500RWT' - may not be unique */ + char unit_serial_number[MAX_SERIAL_LEN]; + + /* NULs if not set - otherwise hex encoding using lower-case e.g. '50014ee0016eb572' */ + char wwn[17]; }; extern int scsi_std_inquiry(struct udev *udev, struct scsi_id_device *dev_scsi, const char *devname); diff --git a/extras/scsi_id/scsi_serial.c b/extras/scsi_id/scsi_serial.c index ab0ffd62a..5b18b225a 100644 --- a/extras/scsi_id/scsi_serial.c +++ b/extras/scsi_id/scsi_serial.c @@ -85,11 +85,15 @@ static const char hex_str[]="0123456789abcdef"; #define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */ #define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ #define SG_ERR_CAT_TIMEOUT 3 -#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ -#define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */ +#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ +#define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */ #define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */ #define SG_ERR_CAT_OTHER 99 /* Some other error/warning */ +static int do_scsi_page80_inquiry(struct udev *udev, + struct scsi_id_device *dev_scsi, int fd, + char *serial, char *serial_short, int max_len); + static int sg_err_category_new(struct udev *udev, int scsi_status, int msg_status, int host_status, int driver_status, const @@ -420,7 +424,7 @@ static int do_scsi_page0_inquiry(struct udev *udev, return 1; } if (buffer[3] > len) { - info(udev, "%s: page 0 buffer too long %d\n", dev_scsi->kernel, buffer[3]); + info(udev, "%s: page 0 buffer too long %d\n", dev_scsi->kernel, buffer[3]); return 1; } @@ -477,7 +481,8 @@ static int check_fill_0x83_id(struct udev *udev, struct scsi_id_device *dev_scsi, unsigned char *page_83, const struct scsi_id_search_values - *id_search, char *serial, char *serial_short, int max_len) + *id_search, char *serial, char *serial_short, int max_len, + char *wwn) { int i, j, s, len; @@ -561,6 +566,10 @@ static int check_fill_0x83_id(struct udev *udev, } strcpy(serial_short, &serial[s]); + + if (id_search->id_type == SCSI_ID_NAA && wwn != NULL) { + strncpy(wwn, &serial[s], 16); + } return 0; } @@ -591,12 +600,16 @@ static int check_fill_0x83_prespc3(struct udev *udev, /* Get device identification VPD page */ static int do_scsi_page83_inquiry(struct udev *udev, struct scsi_id_device *dev_scsi, int fd, - char *serial, char *serial_short, int len) + char *serial, char *serial_short, int len, + char *unit_serial_number, char *wwn) { int retval; unsigned int id_ind, j; unsigned char page_83[SCSI_INQ_BUFF_LEN]; + /* also pick up the page 80 serial number */ + do_scsi_page80_inquiry(udev, dev_scsi, fd, NULL, unit_serial_number, MAX_SERIAL_LEN); + memset(page_83, 0, SCSI_INQ_BUFF_LEN); retval = scsi_inquiry(udev, dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN); @@ -643,7 +656,8 @@ static int do_scsi_page83_inquiry(struct udev *udev, serial, serial_short, len); /* - * Search for a match in the prioritized id_search_list. + * Search for a match in the prioritized id_search_list - since WWN ids + * come first we can pick up the WWN in check_fill_0x83_id(). */ for (id_ind = 0; id_ind < sizeof(id_search_list)/sizeof(id_search_list[0]); @@ -656,7 +670,8 @@ static int do_scsi_page83_inquiry(struct udev *udev, retval = check_fill_0x83_id(udev, dev_scsi, &page_83[j], &id_search_list[id_ind], - serial, serial_short, len); + serial, serial_short, len, + wwn); dbg(udev, "%s id desc %d/%d/%d\n", dev_scsi->kernel, id_search_list[id_ind].id_type, id_search_list[id_ind].naa_type, @@ -775,15 +790,19 @@ static int do_scsi_page80_inquiry(struct udev *udev, * Prepend 'S' to avoid unlikely collision with page 0x83 vendor * specific type where we prepend '0' + vendor + model. */ - serial[0] = 'S'; - ser_ind = prepend_vendor_model(udev, dev_scsi, &serial[1]); - if (ser_ind < 0) - return 1; - len = buf[3]; - for (i = 4; i < len + 4; i++, ser_ind++) - serial[ser_ind] = buf[i]; - memcpy(serial_short, &buf[4], len); - serial_short[len] = '\0'; + len = buf[3]; + if (serial != NULL) { + serial[0] = 'S'; + ser_ind = prepend_vendor_model(udev, dev_scsi, &serial[1]); + if (ser_ind < 0) + return 1; + for (i = 4; i < len + 4; i++, ser_ind++) + serial[ser_ind] = buf[i]; + } + if (serial_short != NULL) { + memcpy(serial_short, &buf[4], len); + serial_short[len] = '\0'; + } return 0; } @@ -866,7 +885,7 @@ int scsi_get_serial(struct udev *udev, goto completed; } } else if (page_code == PAGE_83) { - if (do_scsi_page83_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len)) { + if (do_scsi_page83_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn)) { retval = 1; goto completed; } else { @@ -882,7 +901,7 @@ int scsi_get_serial(struct udev *udev, * conform to pre-SPC3 expectations. */ if (retval == 2) { - if (do_scsi_page83_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len)) { + if (do_scsi_page83_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn)) { retval = 1; goto completed; } else { @@ -922,7 +941,7 @@ int scsi_get_serial(struct udev *udev, for (ind = 4; ind <= page0[3] + 3; ind++) if (page0[ind] == PAGE_83) if (!do_scsi_page83_inquiry(udev, dev_scsi, fd, - dev_scsi->serial, dev_scsi->serial_short, len)) { + dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn)) { /* * Success */ -- 2.30.2