/*
- * scsi_serial.c
+ * Copyright (C) IBM Corp. 2003
*
- * Code related to requesting and getting an id from a scsi device
+ * Author: Patrick Mansfield<patmans@us.ibm.com>
*
- * 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<patmans@us.ibm.com>
+ * 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 <http://www.gnu.org/licenses/>.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
+#include <time.h>
#include <inttypes.h>
#include <scsi/scsi.h>
#include <scsi/sg.h>
#include <linux/types.h>
-/* #include <linux/bsg.h> */
-#include "bsg.h"
+#include <linux/bsg.h>
#include "libudev.h"
#include "libudev-private.h"
#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
int code;
int sense_class;
int sense_key;
- int descriptor_format;
int asc, ascq;
#ifdef DUMP_SENSE
char out_buffer[256];
return -1;
}
if ((code == 0x0) || (code == 0x1)) {
- descriptor_format = 0;
sense_key = sense_buffer[2] & 0xf;
if (s < 14) {
/*
asc = sense_buffer[12];
ascq = sense_buffer[13];
} else if ((code == 0x2) || (code == 0x3)) {
- descriptor_format = 1;
sense_key = sense_buffer[1] & 0xf;
asc = sense_buffer[2];
ascq = sense_buffer[3];
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;
}
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)
{
int i, j, s, len;
}
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;
}
/* 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;
}
/* 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)
{
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);
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]);
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);
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,
* 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;
}
{
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) {
+ 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;
- usleep(500000 + (rand() % 100000) );
+ duration.tv_sec = 0;
+ duration.tv_nsec = (200 * 1000 * 1000) + (rand() % 100 * 1000 * 1000);
+ nanosleep(&duration, NULL);
}
if (fd < 0)
return 1;
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)) {
retval = 1;
goto completed;
} else {
* 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)) {
retval = 1;
goto completed;
} else {
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)) {
/*
* Success
*/