X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=extras%2Fscsi_id%2Fscsi_serial.c;h=5cde9a54a06a0633c654da89ac2973aab214c32e;hb=1f5a5100f3bdfdaf9ef71b29931574b678ff0d82;hp=7b308a935c44e07b97fb4b38bdcfedcb6027e543;hpb=78715f65c92a8892960e2a5fce945496939f8599;p=elogind.git diff --git a/extras/scsi_id/scsi_serial.c b/extras/scsi_id/scsi_serial.c index 7b308a935..5cde9a54a 100644 --- a/extras/scsi_id/scsi_serial.c +++ b/extras/scsi_id/scsi_serial.c @@ -1,16 +1,20 @@ /* - * scsi_serial.c + * Copyright (C) IBM Corp. 2003 * - * Code related to requesting and getting an id from a scsi device + * Author: Patrick Mansfield * - * Copyright (C) IBM Corp. 2003 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. * - * Author: - * Patrick Mansfield + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 of the License. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ #include @@ -28,8 +32,7 @@ #include #include #include -/* #include */ -#include "bsg.h" +#include #include "libudev.h" #include "libudev-private.h" @@ -45,6 +48,7 @@ * is normally one or some small number of descriptors. */ static const struct scsi_id_search_values id_search_list[] = { + { SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY }, { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII }, { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY }, @@ -86,11 +90,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 @@ -133,13 +141,13 @@ static int sg_err_category_new(struct udev *udev, } return SG_ERR_CAT_SENSE; } - if (!host_status) { + if (host_status) { if ((host_status == DID_NO_CONNECT) || (host_status == DID_BUS_BUSY) || (host_status == DID_TIME_OUT)) return SG_ERR_CAT_TIMEOUT; } - if (!driver_status) { + if (driver_status) { if (driver_status == DRIVER_TIMEOUT) return SG_ERR_CAT_TIMEOUT; } @@ -314,8 +322,10 @@ static int scsi_inquiry(struct udev *udev, { INQUIRY_CMD, evpd, page, 0, buflen, 0 }; unsigned char sense[SENSE_BUFF_LEN]; void *io_buf; - int retval; + struct sg_io_v4 io_v4; + struct sg_io_hdr io_hdr; int retry = 3; /* rather random */ + int retval; if (buflen > SCSI_INQ_BUFF_LEN) { info(udev, "buflen %d too long\n", buflen); @@ -326,8 +336,6 @@ resend: dbg(udev, "%s evpd %d, page 0x%x\n", dev_scsi->kernel, evpd, page); if (dev_scsi->use_sg == 4) { - struct sg_io_v4 io_v4; - memset(&io_v4, 0, sizeof(struct sg_io_v4)); io_v4.guard = 'Q'; io_v4.protocol = BSG_PROTOCOL_SCSI; @@ -340,8 +348,6 @@ resend: io_v4.din_xferp = (uintptr_t)buf; io_buf = (void *)&io_v4; } else { - struct sg_io_hdr io_hdr; - memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(inq_cmd); @@ -421,7 +427,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; } @@ -478,15 +484,22 @@ 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, + char *wwn_vendor_extension, char *tgpt_group) { int i, j, s, len; /* * ASSOCIATION must be with the device (value 0) + * or with the target port for SCSI_ID_TGTPORT */ - if ((page_83[1] & 0x30) != 0) + if ((page_83[1] & 0x30) == 0x10) { + if (id_search->id_type != SCSI_ID_TGTGROUP) + return 1; + } else if ((page_83[1] & 0x30) != 0) { return 1; + } if ((page_83[1] & 0x0f) != id_search->id_type) return 1; @@ -527,6 +540,14 @@ static int check_fill_0x83_id(struct udev *udev, return 1; } + if (id_search->id_type == SCSI_ID_TGTGROUP && tgpt_group != NULL) { + unsigned int group; + + group = ((unsigned int)page_83[6] << 8) | page_83[7]; + sprintf(tgpt_group,"%x", group); + return 1; + } + serial[0] = hex_str[id_search->id_type]; /* @@ -562,6 +583,14 @@ 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); + if (wwn_vendor_extension != NULL) { + strncpy(wwn_vendor_extension, &serial[s + 16], 16); + } + } + return 0; } @@ -579,11 +608,12 @@ static int check_fill_0x83_prespc3(struct udev *udev, /* serial has been memset to zero before */ j = strlen(serial); /* j = 1; */ - for (i = 0; i < page_83[3]; ++i) { + for (i = 0; (i < page_83[3]) && (j < max_len-3); ++i) { serial[j++] = hex_str[(page_83[4+i] & 0xf0) >> 4]; serial[j++] = hex_str[ page_83[4+i] & 0x0f]; } - strcpy(serial_short, serial); + serial[max_len-1] = 0; + strncpy(serial_short, serial, max_len-1); return 0; } @@ -591,12 +621,17 @@ 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, + char *wwn_vendor_extension, char *tgpt_group) { 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 +678,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 +692,9 @@ 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, wwn_vendor_extension, + tgpt_group); 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 +813,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; } @@ -837,21 +879,21 @@ int scsi_get_serial(struct udev *udev, { unsigned char page0[SCSI_INQ_BUFF_LEN]; int fd = -1; - int cnt = 10; + int cnt; int ind; int retval; memset(dev_scsi->serial, 0, len); dbg(udev, "opening %s\n", devname); - while (--cnt) { - const struct timespec duration = { 0, 500 * 1000 * 1000 }; + srand((unsigned int)getpid()); + for (cnt = 20; cnt > 0; cnt--) { + struct timespec duration; fd = open(devname, O_RDONLY | O_NONBLOCK); - if (fd >= 0) - break; - info(udev, "%s: cannot open %s: %s\n", dev_scsi->kernel, devname, strerror(errno)); - if (errno != EBUSY) + if (fd >= 0 || errno != EBUSY) break; + duration.tv_sec = 0; + duration.tv_nsec = (200 * 1000 * 1000) + (rand() % 100 * 1000 * 1000); nanosleep(&duration, NULL); } if (fd < 0) @@ -866,7 +908,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, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { retval = 1; goto completed; } else { @@ -882,7 +924,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, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { retval = 1; goto completed; } else { @@ -922,7 +964,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, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { /* * Success */