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