1/* 2 * scsi_serial.c 3 * 4 * Code related to requesting and getting an id from a scsi device 5 * 6 * Copyright (C) IBM Corp. 2003 7 * 8 * Author: 9 * Patrick Mansfield<patmans@us.ibm.com> 10 * 11 * This program is free software; you can redistribute it and/or modify it 12 * under the terms of the GNU General Public License as published by the 13 * Free Software Foundation version 2 of the License. 14 */ 15 16#include <sys/types.h> 17#include <sys/ioctl.h> 18#include <stdio.h> 19#include <errno.h> 20#include <string.h> 21#include <fcntl.h> 22#include <stdlib.h> 23#include <unistd.h> 24#include <syslog.h> 25#include <scsi/sg.h> 26 27#include "../../udev.h" 28#include "scsi.h" 29#include "scsi_id.h" 30#include "scsi_id_version.h" 31 32/* 33 * A priority based list of id, naa, and binary/ascii for the identifier 34 * descriptor in VPD page 0x83. 35 * 36 * Brute force search for a match starting with the first value in the 37 * following id_search_list. This is not a performance issue, since there 38 * is normally one or some small number of descriptors. 39 */ 40static const struct scsi_id_search_values id_search_list[] = { 41 { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY }, 42 { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII }, 43 { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY }, 44 { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_ASCII }, 45 /* 46 * Devices already exist using NAA values that are now marked 47 * reserved. These should not conflict with other values, or it is 48 * a bug in the device. As long as we find the IEEE extended one 49 * first, we really don't care what other ones are used. Using 50 * don't care here means that a device that returns multiple 51 * non-IEEE descriptors in a random order will get different 52 * names. 53 */ 54 { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, 55 { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, 56 { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, 57 { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, 58 { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, 59 { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, 60 { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, 61 { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, 62}; 63 64static const char hex_str[]="0123456789abcdef"; 65 66/* 67 * Values returned in the result/status, only the ones used by the code 68 * are used here. 69 */ 70 71#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ 72#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ 73#define DID_TIME_OUT 0x03 /* Timed out for some other reason */ 74#define DRIVER_TIMEOUT 0x06 75#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ 76 77/* The following "category" function returns one of the following */ 78#define SG_ERR_CAT_CLEAN 0 /* No errors or other information */ 79#define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */ 80#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ 81#define SG_ERR_CAT_TIMEOUT 3 82#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ 83#define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */ 84#define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */ 85#define SG_ERR_CAT_OTHER 99 /* Some other error/warning */ 86 87static int sg_err_category_new(int scsi_status, int msg_status, int 88 host_status, int driver_status, const 89 unsigned char *sense_buffer, int sb_len) 90{ 91 scsi_status &= 0x7e; 92 93 94 /* 95 * checks msg_status 96 */ 97 if (!scsi_status && !msg_status && !host_status && !driver_status) 98 return SG_ERR_CAT_CLEAN; 99 100 if ((scsi_status == SCSI_CHECK_CONDITION) || 101 (scsi_status == SCSI_COMMAND_TERMINATED) || 102 ((driver_status & 0xf) == DRIVER_SENSE)) { 103 if (sense_buffer && (sb_len > 2)) { 104 int sense_key; 105 unsigned char asc; 106 107 if (sense_buffer[0] & 0x2) { 108 sense_key = sense_buffer[1] & 0xf; 109 asc = sense_buffer[2]; 110 } else { 111 sense_key = sense_buffer[2] & 0xf; 112 asc = (sb_len > 12) ? sense_buffer[12] : 0; 113 } 114 115 if (sense_key == RECOVERED_ERROR) 116 return SG_ERR_CAT_RECOVERED; 117 else if (sense_key == UNIT_ATTENTION) { 118 if (0x28 == asc) 119 return SG_ERR_CAT_MEDIA_CHANGED; 120 if (0x29 == asc) 121 return SG_ERR_CAT_RESET; 122 } else if (sense_key == ILLEGAL_REQUEST) { 123 return SG_ERR_CAT_NOTSUPPORTED; 124 } 125 } 126 return SG_ERR_CAT_SENSE; 127 } 128 if (!host_status) { 129 if ((host_status == DID_NO_CONNECT) || 130 (host_status == DID_BUS_BUSY) || 131 (host_status == DID_TIME_OUT)) 132 return SG_ERR_CAT_TIMEOUT; 133 } 134 if (!driver_status) { 135 if (driver_status == DRIVER_TIMEOUT) 136 return SG_ERR_CAT_TIMEOUT; 137 } 138 return SG_ERR_CAT_OTHER; 139} 140 141static int sg_err_category3(struct sg_io_hdr *hp) 142{ 143 return sg_err_category_new(hp->status, hp->msg_status, 144 hp->host_status, hp->driver_status, 145 hp->sbp, hp->sb_len_wr); 146} 147 148static int scsi_dump_sense(struct sysfs_device *dev_scsi, struct sg_io_hdr *io) 149{ 150 unsigned char *sense_buffer; 151 int s; 152 int sb_len; 153 int code; 154 int sense_class; 155 int sense_key; 156 int descriptor_format; 157 int asc, ascq; 158#ifdef DUMP_SENSE 159 char out_buffer[256]; 160 int i, j; 161#endif 162 163 164 dbg("got check condition\n"); 165 166 sb_len = io->sb_len_wr; 167 if (sb_len < 1) { 168 info("%s: sense buffer empty", dev_scsi->kernel); 169 return -1; 170 } 171 172 sense_buffer = io->sbp; 173 sense_class = (sense_buffer[0] >> 4) & 0x07; 174 code = sense_buffer[0] & 0xf; 175 176 if (sense_class == 7) { 177 /* 178 * extended sense data. 179 */ 180 s = sense_buffer[7] + 8; 181 if (sb_len < s) { 182 info("%s: sense buffer too small %d bytes, %d bytes too short", 183 dev_scsi->kernel, sb_len, s - sb_len); 184 return -1; 185 } 186 if ((code == 0x0) || (code == 0x1)) { 187 descriptor_format = 0; 188 sense_key = sense_buffer[2] & 0xf; 189 if (s < 14) { 190 /* 191 * Possible? 192 */ 193 info("%s: sense result too" " small %d bytes", 194 dev_scsi->kernel, s); 195 return -1; 196 } 197 asc = sense_buffer[12]; 198 ascq = sense_buffer[13]; 199 } else if ((code == 0x2) || (code == 0x3)) { 200 descriptor_format = 1; 201 sense_key = sense_buffer[1] & 0xf; 202 asc = sense_buffer[2]; 203 ascq = sense_buffer[3]; 204 } else { 205 info("%s: invalid sense code 0x%x", 206 dev_scsi->kernel, code); 207 return -1; 208 } 209 info("%s: sense key 0x%x ASC 0x%x ASCQ 0x%x", 210 dev_scsi->kernel, sense_key, asc, ascq); 211 } else { 212 if (sb_len < 4) { 213 info("%s: sense buffer too small %d bytes, %d bytes too short", 214 dev_scsi->kernel, sb_len, 4 - sb_len); 215 return -1; 216 } 217 218 if (sense_buffer[0] < 15) 219 info("%s: old sense key: 0x%x", dev_scsi->kernel, sense_buffer[0] & 0x0f); 220 else 221 info("%s: sense = %2x %2x", 222 dev_scsi->kernel, sense_buffer[0], sense_buffer[2]); 223 info("%s: non-extended sense class %d code 0x%0x", 224 dev_scsi->kernel, sense_class, code); 225 226 } 227 228#ifdef DUMP_SENSE 229 for (i = 0, j = 0; (i < s) && (j < 254); i++) { 230 dbg("i %d, j %d\n", i, j); 231 out_buffer[j++] = hex_str[(sense_buffer[i] & 0xf0) >> 4]; 232 out_buffer[j++] = hex_str[sense_buffer[i] & 0x0f]; 233 out_buffer[j++] = ' '; 234 } 235 out_buffer[j] = '\0'; 236 info("%s: sense dump:", dev_scsi->kernel); 237 info("%s: %s", dev_scsi->kernel, out_buffer); 238 239#endif 240 return -1; 241} 242 243static int scsi_dump(struct sysfs_device *dev_scsi, struct sg_io_hdr *io) 244{ 245 if (!io->status && !io->host_status && !io->msg_status && 246 !io->driver_status) { 247 /* 248 * Impossible, should not be called. 249 */ 250 info("%s: called with no error", __FUNCTION__); 251 return -1; 252 } 253 254 info("%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x", 255 dev_scsi->kernel, io->driver_status, io->host_status, io->msg_status, io->status); 256 if (io->status == SCSI_CHECK_CONDITION) 257 return scsi_dump_sense(dev_scsi, io); 258 else 259 return -1; 260} 261 262static int scsi_inquiry(struct sysfs_device *dev_scsi, int fd, 263 unsigned char evpd, unsigned char page, 264 unsigned char *buf, unsigned int buflen) 265{ 266 unsigned char inq_cmd[INQUIRY_CMDLEN] = 267 { INQUIRY_CMD, evpd, page, 0, buflen, 0 }; 268 unsigned char sense[SENSE_BUFF_LEN]; 269 struct sg_io_hdr io_hdr; 270 int retval; 271 int retry = 3; /* rather random */ 272 273 if (buflen > SCSI_INQ_BUFF_LEN) { 274 info("buflen %d too long", buflen); 275 return -1; 276 } 277 278resend: 279 dbg("%s evpd %d, page 0x%x\n", dev_scsi->kernel, evpd, page); 280 281 memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); 282 io_hdr.interface_id = 'S'; 283 io_hdr.cmd_len = sizeof(inq_cmd); 284 io_hdr.mx_sb_len = sizeof(sense); 285 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; 286 io_hdr.dxfer_len = buflen; 287 io_hdr.dxferp = buf; 288 io_hdr.cmdp = inq_cmd; 289 io_hdr.sbp = sense; 290 io_hdr.timeout = DEF_TIMEOUT; 291 292 if (ioctl(fd, SG_IO, &io_hdr) < 0) { 293 info("%s: ioctl failed: %s", dev_scsi->kernel, strerror(errno)); 294 retval = -1; 295 goto error; 296 } 297 298 retval = sg_err_category3(&io_hdr); 299 300 switch (retval) { 301 case SG_ERR_CAT_NOTSUPPORTED: 302 buf[1] = 0; 303 /* Fallthrough */ 304 case SG_ERR_CAT_CLEAN: 305 case SG_ERR_CAT_RECOVERED: 306 retval = 0; 307 break; 308 309 default: 310 retval = scsi_dump(dev_scsi, &io_hdr); 311 } 312 313 if (!retval) { 314 retval = buflen; 315 } else if (retval > 0) { 316 if (--retry > 0) { 317 dbg("%s: Retrying ...\n", dev_scsi->kernel); 318 goto resend; 319 } 320 retval = -1; 321 } 322 323error: 324 if (retval < 0) 325 info("%s: Unable to get INQUIRY vpd %d page 0x%x.", 326 dev_scsi->kernel, evpd, page); 327 328 return retval; 329} 330 331/* Get list of supported EVPD pages */ 332static int do_scsi_page0_inquiry(struct sysfs_device *dev_scsi, int fd, 333 unsigned char *buffer, unsigned int len) 334{ 335 int retval; 336 const char *vendor; 337 338 memset(buffer, 0, len); 339 retval = scsi_inquiry(dev_scsi, fd, 1, 0x0, buffer, len); 340 if (retval < 0) 341 return 1; 342 343 if (buffer[1] != 0) { 344 info("%s: page 0 not available.", dev_scsi->kernel); 345 return 1; 346 } 347 if (buffer[3] > len) { 348 info("%s: page 0 buffer too long %d", dev_scsi->kernel, buffer[3]); 349 return 1; 350 } 351 352 /* 353 * Following check is based on code once included in the 2.5.x 354 * kernel. 355 * 356 * Some ill behaved devices return the standard inquiry here 357 * rather than the evpd data, snoop the data to verify. 358 */ 359 if (buffer[3] > MODEL_LENGTH) { 360 /* 361 * If the vendor id appears in the page assume the page is 362 * invalid. 363 */ 364 vendor = sysfs_attr_get_value(dev_scsi->devpath, "vendor"); 365 if (!vendor) { 366 info("%s: cannot get model attribute", dev_scsi->kernel); 367 return 1; 368 } 369 if (!strncmp((char *)&buffer[VENDOR_LENGTH], vendor, VENDOR_LENGTH)) { 370 info("%s: invalid page0 data", dev_scsi->kernel); 371 return 1; 372 } 373 } 374 return 0; 375} 376 377/* 378 * The caller checks that serial is long enough to include the vendor + 379 * model. 380 */ 381static int prepend_vendor_model(struct sysfs_device *dev_scsi, char *serial) 382{ 383 const char *attr; 384 int ind; 385 386 attr = sysfs_attr_get_value(dev_scsi->devpath, "vendor"); 387 if (!attr) { 388 info("%s: cannot get vendor attribute", dev_scsi->kernel); 389 return 1; 390 } 391 strncpy(serial, attr, VENDOR_LENGTH); 392 ind = strlen(serial) - 1; 393 394 attr = sysfs_attr_get_value(dev_scsi->devpath, "model"); 395 if (!attr) { 396 info("%s: cannot get model attribute", dev_scsi->kernel); 397 return 1; 398 } 399 strncat(serial, attr, MODEL_LENGTH); 400 ind = strlen(serial) - 1; 401 ind++; 402 403 /* 404 * This is not a complete check, since we are using strncat/cpy 405 * above, ind will never be too large. 406 */ 407 if (ind != (VENDOR_LENGTH + MODEL_LENGTH)) { 408 info("%s: expected length %d, got length %d", 409 dev_scsi->kernel, (VENDOR_LENGTH + MODEL_LENGTH), ind); 410 return 1; 411 } 412 return ind; 413} 414 415/** 416 * check_fill_0x83_id - check the page 0x83 id, if OK allocate and fill 417 * serial number. 418 **/ 419static int check_fill_0x83_id(struct sysfs_device *dev_scsi, 420 unsigned char *page_83, 421 const struct scsi_id_search_values 422 *id_search, char *serial, char *serial_short, int max_len) 423{ 424 int i, j, s, len; 425 426 /* 427 * ASSOCIATION must be with the device (value 0) 428 */ 429 if ((page_83[1] & 0x30) != 0) 430 return 1; 431 432 if ((page_83[1] & 0x0f) != id_search->id_type) 433 return 1; 434 435 /* 436 * Possibly check NAA sub-type. 437 */ 438 if ((id_search->naa_type != SCSI_ID_NAA_DONT_CARE) && 439 (id_search->naa_type != (page_83[4] & 0xf0) >> 4)) 440 return 1; 441 442 /* 443 * Check for matching code set - ASCII or BINARY. 444 */ 445 if ((page_83[0] & 0x0f) != id_search->code_set) 446 return 1; 447 448 /* 449 * page_83[3]: identifier length 450 */ 451 len = page_83[3]; 452 if ((page_83[0] & 0x0f) != SCSI_ID_ASCII) 453 /* 454 * If not ASCII, use two bytes for each binary value. 455 */ 456 len *= 2; 457 458 /* 459 * Add one byte for the NUL termination, and one for the id_type. 460 */ 461 len += 2; 462 if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) 463 len += VENDOR_LENGTH + MODEL_LENGTH; 464 465 if (max_len < len) { 466 info("%s: length %d too short - need %d", 467 dev_scsi->kernel, max_len, len); 468 return 1; 469 } 470 471 serial[0] = hex_str[id_search->id_type]; 472 473 /* 474 * For SCSI_ID_VENDOR_SPECIFIC prepend the vendor and model before 475 * the id since it is not unique across all vendors and models, 476 * this differs from SCSI_ID_T10_VENDOR, where the vendor is 477 * included in the identifier. 478 */ 479 if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) 480 if (prepend_vendor_model(dev_scsi, &serial[1]) < 0) { 481 dbg("prepend failed\n"); 482 return 1; 483 } 484 485 i = 4; /* offset to the start of the identifier */ 486 s = j = strlen(serial); 487 if ((page_83[0] & 0x0f) == SCSI_ID_ASCII) { 488 /* 489 * ASCII descriptor. 490 */ 491 while (i < (4 + page_83[3])) 492 serial[j++] = page_83[i++]; 493 } else { 494 /* 495 * Binary descriptor, convert to ASCII, using two bytes of 496 * ASCII for each byte in the page_83. 497 */ 498 while (i < (4 + page_83[3])) { 499 serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; 500 serial[j++] = hex_str[page_83[i] & 0x0f]; 501 i++; 502 } 503 } 504 505 strcpy(serial_short, &serial[s]); 506 return 0; 507} 508 509/* Extract the raw binary from VPD 0x83 pre-SPC devices */ 510static int check_fill_0x83_prespc3(struct sysfs_device *dev_scsi, 511 unsigned char *page_83, 512 const struct scsi_id_search_values 513 *id_search, char *serial, char *serial_short, int max_len) 514{ 515 int i, j; 516 517 dbg("using pre-spc3-83 for %s.\n", dev_scsi->kernel); 518 serial[0] = hex_str[id_search->id_type]; 519 /* serial has been memset to zero before */ 520 j = strlen(serial); /* j = 1; */ 521 522 for (i = 0; i < page_83[3]; ++i) { 523 serial[j++] = hex_str[(page_83[4+i] & 0xf0) >> 4]; 524 serial[j++] = hex_str[ page_83[4+i] & 0x0f]; 525 } 526 strcpy(serial_short, serial); 527 return 0; 528} 529 530 531/* Get device identification VPD page */ 532static int do_scsi_page83_inquiry(struct sysfs_device *dev_scsi, int fd, 533 char *serial, char *serial_short, int len) 534{ 535 int retval; 536 unsigned int id_ind, j; 537 unsigned char page_83[SCSI_INQ_BUFF_LEN]; 538 539 memset(page_83, 0, SCSI_INQ_BUFF_LEN); 540 retval = scsi_inquiry(dev_scsi, fd, 1, PAGE_83, page_83, 541 SCSI_INQ_BUFF_LEN); 542 if (retval < 0) 543 return 1; 544 545 if (page_83[1] != PAGE_83) { 546 info("%s: Invalid page 0x83", dev_scsi->kernel); 547 return 1; 548 } 549 550 551 /* 552 * Model 4, 5, and (some) model 6 EMC Symmetrix devices return 553 * a page 83 reply according to SCSI-2 format instead of SPC-2/3. 554 * 555 * The SCSI-2 page 83 format returns an IEEE WWN in binary 556 * encoded hexi-decimal in the 16 bytes following the initial 557 * 4-byte page 83 reply header. 558 * 559 * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part 560 * of an Identification descriptor. The 3rd byte of the first 561 * Identification descriptor is a reserved (BSZ) byte field. 562 * 563 * Reference the 7th byte of the page 83 reply to determine 564 * whether the reply is compliant with SCSI-2 or SPC-2/3 565 * specifications. A zero value in the 7th byte indicates 566 * an SPC-2/3 conformant reply, (i.e., the reserved field of the 567 * first Identification descriptor). This byte will be non-zero 568 * for a SCSI-2 conformant page 83 reply from these EMC 569 * Symmetrix models since the 7th byte of the reply corresponds 570 * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, 571 * 0x006048. 572 */ 573 574 if (page_83[6] != 0) 575 return check_fill_0x83_prespc3(dev_scsi, page_83, id_search_list, 576 serial, serial_short, len); 577 578 /* 579 * Search for a match in the prioritized id_search_list. 580 */ 581 for (id_ind = 0; 582 id_ind < sizeof(id_search_list)/sizeof(id_search_list[0]); 583 id_ind++) { 584 /* 585 * Examine each descriptor returned. There is normally only 586 * one or a small number of descriptors. 587 */ 588 for (j = 4; j <= (unsigned int)page_83[3] + 3; j += page_83[j + 3] + 4) { 589 retval = check_fill_0x83_id(dev_scsi, &page_83[j], 590 &id_search_list[id_ind], 591 serial, serial_short, len); 592 dbg("%s id desc %d/%d/%d\n", dev_scsi->kernel, 593 id_search_list[id_ind].id_type, 594 id_search_list[id_ind].naa_type, 595 id_search_list[id_ind].code_set); 596 if (!retval) { 597 dbg(" used\n"); 598 return retval; 599 } else if (retval < 0) { 600 dbg(" failed\n"); 601 return retval; 602 } else { 603 dbg(" not used\n"); 604 } 605 } 606 } 607 return 1; 608} 609 610/* 611 * Get device identification VPD page for older SCSI-2 device which is not 612 * compliant with either SPC-2 or SPC-3 format. 613 * 614 * Return the hard coded error code value 2 if the page 83 reply is not 615 * conformant to the SCSI-2 format. 616 */ 617static int do_scsi_page83_prespc3_inquiry(struct sysfs_device *dev_scsi, int fd, 618 char *serial, char *serial_short, int len) 619{ 620 int retval; 621 int i, j; 622 unsigned char page_83[SCSI_INQ_BUFF_LEN]; 623 624 memset(page_83, 0, SCSI_INQ_BUFF_LEN); 625 retval = scsi_inquiry(dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN); 626 if (retval < 0) 627 return 1; 628 629 if (page_83[1] != PAGE_83) { 630 info("%s: Invalid page 0x83", dev_scsi->kernel); 631 return 1; 632 } 633 /* 634 * Model 4, 5, and (some) model 6 EMC Symmetrix devices return 635 * a page 83 reply according to SCSI-2 format instead of SPC-2/3. 636 * 637 * The SCSI-2 page 83 format returns an IEEE WWN in binary 638 * encoded hexi-decimal in the 16 bytes following the initial 639 * 4-byte page 83 reply header. 640 * 641 * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part 642 * of an Identification descriptor. The 3rd byte of the first 643 * Identification descriptor is a reserved (BSZ) byte field. 644 * 645 * Reference the 7th byte of the page 83 reply to determine 646 * whether the reply is compliant with SCSI-2 or SPC-2/3 647 * specifications. A zero value in the 7th byte indicates 648 * an SPC-2/3 conformant reply, (i.e., the reserved field of the 649 * first Identification descriptor). This byte will be non-zero 650 * for a SCSI-2 conformant page 83 reply from these EMC 651 * Symmetrix models since the 7th byte of the reply corresponds 652 * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, 653 * 0x006048. 654 */ 655 if (page_83[6] == 0) 656 return 2; 657 658 serial[0] = hex_str[id_search_list[0].id_type]; 659 /* 660 * The first four bytes contain data, not a descriptor. 661 */ 662 i = 4; 663 j = strlen(serial); 664 /* 665 * Binary descriptor, convert to ASCII, 666 * using two bytes of ASCII for each byte 667 * in the page_83. 668 */ 669 while (i < (page_83[3]+4)) { 670 serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; 671 serial[j++] = hex_str[page_83[i] & 0x0f]; 672 i++; 673 } 674 dbg("using pre-spc3-83 for %s.\n", dev_scsi->kernel); 675 return 0; 676} 677 678/* Get unit serial number VPD page */ 679static int do_scsi_page80_inquiry(struct sysfs_device *dev_scsi, int fd, 680 char *serial, char *serial_short, int max_len) 681{ 682 int retval; 683 int ser_ind; 684 int i; 685 int len; 686 unsigned char buf[SCSI_INQ_BUFF_LEN]; 687 688 memset(buf, 0, SCSI_INQ_BUFF_LEN); 689 retval = scsi_inquiry(dev_scsi, fd, 1, PAGE_80, buf, SCSI_INQ_BUFF_LEN); 690 if (retval < 0) 691 return retval; 692 693 if (buf[1] != PAGE_80) { 694 info("%s: Invalid page 0x80", dev_scsi->kernel); 695 return 1; 696 } 697 698 len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3]; 699 if (max_len < len) { 700 info("%s: length %d too short - need %d", 701 dev_scsi->kernel, max_len, len); 702 return 1; 703 } 704 /* 705 * Prepend 'S' to avoid unlikely collision with page 0x83 vendor 706 * specific type where we prepend '0' + vendor + model. 707 */ 708 serial[0] = 'S'; 709 ser_ind = prepend_vendor_model(dev_scsi, &serial[1]); 710 if (ser_ind < 0) 711 return 1; 712 len = buf[3]; 713 for (i = 4; i < len + 4; i++, ser_ind++) 714 serial[ser_ind] = buf[i]; 715 memcpy(serial_short, &buf[4], len); 716 serial_short[len] = '\0'; 717 return 0; 718} 719 720int scsi_std_inquiry(struct sysfs_device *dev_scsi, const char *devname, 721 char *vendor, char *model, char *rev, char *type) 722{ 723 int retval; 724 int fd; 725 unsigned char buf[SCSI_INQ_BUFF_LEN]; 726 727 dbg("opening %s\n", devname); 728 fd = open(devname, O_RDONLY | O_NONBLOCK); 729 if (fd < 0) { 730 info("%s: cannot open %s: %s", 731 dev_scsi->kernel, devname, strerror(errno)); 732 return 1; 733 } 734 735 memset(buf, 0, SCSI_INQ_BUFF_LEN); 736 retval = scsi_inquiry(dev_scsi, fd, 0, 0, buf, SCSI_INQ_BUFF_LEN); 737 if (retval < 0) 738 return retval; 739 740 memcpy(vendor, buf + 8, 8); 741 memcpy(model, buf + 16, 16); 742 memcpy(rev, buf + 32, 4); 743 sprintf(type,"%x", buf[0] & 0x1f); 744 745 if (close(fd) < 0) 746 info("%s: close failed: %s", dev_scsi->kernel, strerror(errno)); 747 748 return 0; 749} 750 751int scsi_get_serial (struct sysfs_device *dev_scsi, const char *devname, 752 int page_code, char *serial, char *serial_short, int len) 753{ 754 unsigned char page0[SCSI_INQ_BUFF_LEN]; 755 int fd; 756 int ind; 757 int retval; 758 759 memset(serial, 0, len); 760 dbg("opening %s\n", devname); 761 fd = open(devname, O_RDONLY | O_NONBLOCK); 762 if (fd < 0) { 763 info("%s: cannot open %s: %s", 764 dev_scsi->kernel, devname, strerror(errno)); 765 return 1; 766 } 767 768 if (page_code == PAGE_80) { 769 if (do_scsi_page80_inquiry(dev_scsi, fd, serial, serial_short, len)) { 770 retval = 1; 771 goto completed; 772 } else { 773 retval = 0; 774 goto completed; 775 } 776 } else if (page_code == PAGE_83) { 777 if (do_scsi_page83_inquiry(dev_scsi, fd, serial, serial_short, len)) { 778 retval = 1; 779 goto completed; 780 } else { 781 retval = 0; 782 goto completed; 783 } 784 } else if (page_code == PAGE_83_PRE_SPC3) { 785 retval = do_scsi_page83_prespc3_inquiry(dev_scsi, fd, serial, serial_short, len); 786 if (retval) { 787 /* 788 * Fallback to servicing a SPC-2/3 compliant page 83 789 * inquiry if the page 83 reply format does not 790 * conform to pre-SPC3 expectations. 791 */ 792 if (retval == 2) { 793 if (do_scsi_page83_inquiry(dev_scsi, fd, serial, serial_short, len)) { 794 retval = 1; 795 goto completed; 796 } else { 797 retval = 0; 798 goto completed; 799 } 800 } 801 else { 802 retval = 1; 803 goto completed; 804 } 805 } else { 806 retval = 0; 807 goto completed; 808 } 809 } else if (page_code != 0x00) { 810 info("%s: unsupported page code 0x%d", dev_scsi->kernel, page_code); 811 return 1; 812 } 813 814 /* 815 * Get page 0, the page of the pages. By default, try from best to 816 * worst of supported pages: 0x83 then 0x80. 817 */ 818 if (do_scsi_page0_inquiry(dev_scsi, fd, page0, SCSI_INQ_BUFF_LEN)) { 819 /* 820 * Don't try anything else. Black list if a specific page 821 * should be used for this vendor+model, or maybe have an 822 * optional fall-back to page 0x80 or page 0x83. 823 */ 824 retval = 1; 825 goto completed; 826 } 827 828 dbg("%s: Checking page0\n", dev_scsi->kernel); 829 830 for (ind = 4; ind <= page0[3] + 3; ind++) 831 if (page0[ind] == PAGE_83) 832 if (!do_scsi_page83_inquiry(dev_scsi, fd, 833 serial, serial_short, len)) { 834 /* 835 * Success 836 */ 837 retval = 0; 838 goto completed; 839 } 840 841 for (ind = 4; ind <= page0[3] + 3; ind++) 842 if (page0[ind] == PAGE_80) 843 if (!do_scsi_page80_inquiry(dev_scsi, fd, 844 serial, serial_short, len)) { 845 /* 846 * Success 847 */ 848 retval = 0; 849 goto completed; 850 } 851 retval = 1; 852completed: 853 if (close(fd) < 0) 854 info("%s: close failed: %s", dev_scsi->kernel, strerror(errno)); 855 return retval; 856} 857