chiark / gitweb /
scsi_id: Export WWN and Unit Serial Number
authorDavid Zeuthen <davidz@redhat.com>
Sat, 21 Nov 2009 01:21:58 +0000 (20:21 -0500)
committerKay Sievers <kay.sievers@vrfy.org>
Mon, 23 Nov 2009 20:38:21 +0000 (21:38 +0100)
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 <davidz@redhat.com>
extras/scsi_id/scsi_id.c
extras/scsi_id/scsi_id.h
extras/scsi_id/scsi_serial.c

index 72a7257113356af7d49e9656209f1ddbe01b9bf3..9c5b2c3a3c7a442f1924c2832bb1bb0f3ad20005 100644 (file)
@@ -549,6 +549,7 @@ static int scsi_id(struct udev *udev, char *maj_min_dev)
        if (export) {
                char serial_str[MAX_SERIAL_LEN];
 
        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);
                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);
                }
                        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;
        }
 
                goto out;
        }
 
index 9fcadec173536407b6b10d6a22a776484e9c96f2..4536cfd4f2596f260aa277296837d68c5f6fa21d 100644 (file)
@@ -39,6 +39,12 @@ struct scsi_id_device {
        char serial[MAX_SERIAL_LEN];
        char serial_short[MAX_SERIAL_LEN];
        int use_sg;
        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);
 };
 
 extern int scsi_std_inquiry(struct udev *udev, struct scsi_id_device *dev_scsi, const char *devname);
index ab0ffd62aaa963c28dd542a3ee0e3b81d22f4f51..5b18b225a5eb6e7e4e9bd0eb15e0a600e011abc1 100644 (file)
@@ -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_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 */
 
 #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
 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) {
                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;
        }
 
                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
                              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;
 
 {
        int i, j, s, len;
 
@@ -561,6 +566,10 @@ static int check_fill_0x83_id(struct udev *udev,
        }
 
        strcpy(serial_short, &serial[s]);
        }
 
        strcpy(serial_short, &serial[s]);
+
+        if (id_search->id_type == SCSI_ID_NAA && wwn != NULL) {
+                strncpy(wwn, &serial[s], 16);
+        }
        return 0;
 }
 
        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,
 /* 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];
 
 {
        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);
        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);
 
        /*
                                               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]);
         */
        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],
                        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,
                        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.
         */
         * 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;
 }
 
        return 0;
 }
 
@@ -866,7 +885,7 @@ int scsi_get_serial(struct udev *udev,
                        goto completed;
                }
        } else if (page_code == PAGE_83) {
                        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  {
                        retval = 1;
                        goto completed;
                } else  {
@@ -882,7 +901,7 @@ int scsi_get_serial(struct udev *udev,
                         * conform to pre-SPC3 expectations.
                         */
                        if (retval == 2) {
                         * 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  {
                                        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,
        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
                                 */
                                /*
                                 * Success
                                 */