1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * These functions are used to encode SCSI INQUIRY data into 31 * Solaris devid / guid values. 32 */ 33 34 #include <sys/types.h> 35 #include <sys/stropts.h> 36 #include <sys/debug.h> 37 #include <sys/isa_defs.h> 38 #include <sys/dditypes.h> 39 #include <sys/ddi_impldefs.h> 40 #include <sys/scsi/scsi.h> 41 #include "devid_impl.h" 42 43 #define SCSI_INQUIRY_VID_POS 9 44 #define SCSI_INQUIRY_VID_SUN "SUN" 45 #define SCSI_INQUIRY_VID_SUN_LEN 3 46 #define SCSI_INQUIRY_VID_HITACHI "HITACHI" 47 #define SCSI_INQUIRY_VID_HITACHI_LEN 7 48 #define SCSI_INQUIRY_PID_HITACHI_OPEN "OPEN-" 49 #define SCSI_INQUIRY_PID_HITACHI_OPEN_LEN 5 50 #define SCSI_INQUIRY_VID_EMC "EMC " 51 #define SCSI_INQUIRY_VID_EMC_LEN 8 52 #define SCSI_INQUIRY_PID_EMC_SYMMETRIX "SYMMETRIX " 53 #define SCSI_INQUIRY_PID_EMC_SYMMETRIX_LEN 16 54 55 #define MSG_NOT_STANDARDS_COMPLIANT "!Page83 data not standards compliant " 56 #define MSG_NOT_STANDARDS_COMPLIANT_SIZE ( \ 57 sizeof (MSG_NOT_STANDARDS_COMPLIANT) + \ 58 sizeof (((struct scsi_inquiry *)NULL)->inq_vid) + \ 59 sizeof (((struct scsi_inquiry *)NULL)->inq_pid) + \ 60 sizeof (((struct scsi_inquiry *)NULL)->inq_revision) + 4) 61 62 #define IS_DEVID_GUID_TYPE(type) ((type == DEVID_SCSI3_WWN) || \ 63 (IS_DEVID_SCSI3_VPD_TYPE(type))) 64 65 #define IS_DEVID_SCSI_TYPE(type) ((IS_DEVID_GUID_TYPE(type)) || \ 66 (type == DEVID_SCSI_SERIAL)) 67 68 /* 69 * The max inquiry page 83 size as expected in the code today 70 * is 0xf0 bytes. Defining a constant to make it easy incase 71 * this needs to be changed at a later time. 72 */ 73 74 #define SCMD_MAX_INQUIRY_PAGE83_SIZE 0xFF 75 #define SCMD_MIN_INQUIRY_PAGE83_SIZE 0x08 76 #define SCMD_INQUIRY_PAGE83_HDR_SIZE 4 77 #define SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN 16 78 79 #define SCMD_MAX_INQUIRY_PAGE80_SIZE 0xFF 80 #define SCMD_MIN_INQUIRY_PAGE80_SIZE 0x04 81 82 #define SCMD_MIN_STANDARD_INQUIRY_SIZE 0x04 83 84 #define SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE 4 85 86 #define SCMD_INQUIRY_VPD_TYPE_T10 0x01 87 #define SCMD_INQUIRY_VPD_TYPE_EUI 0x02 88 #define SCMD_INQUIRY_VPD_TYPE_NAA 0x03 89 #define SCMD_INQUIRY_VPD_TYPE_RTP 0x04 90 #define SCMD_INQUIRY_VPD_TYPE_TPG 0x05 91 #define SCMD_INQUIRY_VPD_TYPE_LUG 0x06 92 #define SCMD_INQUIRY_VPD_TYPE_MD5 0x07 93 #define SCMD_INQUIRY_VPD_TYPE_SSN 0x08 94 95 static int is_page83_data_valid(uchar_t *inq83, size_t inq83_len); 96 static int is_page80_data_valid(uchar_t *inq80, size_t inq80_len); 97 static int is_initialized_id(uchar_t *id, size_t id_len); 98 99 static void encode_scsi3_page83(int version, uchar_t *inq83, 100 size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type); 101 static void encode_scsi3_page83_emc(int version, uchar_t *inq83, 102 size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type); 103 static void encode_serialnum(int version, uchar_t *inq, uchar_t *inq80, 104 size_t inq80_len, uchar_t **id, size_t *id_len, ushort_t *id_type); 105 static void encode_sun_serialnum(int version, uchar_t *inq, 106 size_t inq_len, uchar_t **id, size_t *id_len, ushort_t *id_type); 107 108 static int devid_scsi_init(char *driver_name, 109 uchar_t *raw_id, size_t raw_id_len, ushort_t raw_id_type, 110 ddi_devid_t *ret_devid); 111 112 static char ctoi(char c); 113 114 /* 115 * Function: ddi_/devid_scsi_encode 116 * 117 * Description: This routine finds and encodes a unique devid 118 * 119 * Arguments: version - id encode algorithm version 120 * driver_name - binding driver name (if ! known use NULL) 121 * inq - standard inquiry buffer 122 * inq_len - standard inquiry buffer length 123 * inq80 - serial number inquiry buffer 124 * inq80_len - serial number inquiry buffer length 125 * inq83 - vpd inquiry buffer 126 * inq83_len - vpd inquiry buffer length 127 * devid - id returned 128 * 129 * Return Code: DEVID_SUCCESS - success 130 * DEVID_FAILURE - failure 131 * DEVID_RETRY - LUN is in a transitional state. A delay should 132 * occur and then this inquiry data should be re-acquired and 133 * this function should be called again. 134 */ 135 int 136 #ifdef _KERNEL 137 ddi_devid_scsi_encode( 138 #else /* ! _KERNEL */ 139 devid_scsi_encode( 140 #endif /* _KERNEL */ 141 int version, /* IN */ 142 char *driver_name, /* IN */ 143 uchar_t *inq, /* IN */ 144 size_t inq_len, /* IN */ 145 uchar_t *inq80, /* IN */ 146 size_t inq80_len, /* IN */ 147 uchar_t *inq83, /* IN */ 148 size_t inq83_len, /* IN */ 149 ddi_devid_t *devid) /* OUT */ 150 { 151 int rval = DEVID_FAILURE; 152 uchar_t *id = NULL; 153 size_t id_len = 0; 154 ushort_t id_type = DEVID_NONE; 155 struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq; 156 #ifdef _KERNEL 157 char *msg = NULL; 158 #endif /* _KERNEL */ 159 160 DEVID_ASSERT(devid != NULL); 161 162 /* verify valid version */ 163 if (version > DEVID_SCSI_ENCODE_VERSION_LATEST) { 164 return (rval); 165 } 166 167 /* make sure minimum inquiry bytes are available */ 168 if (inq_len < SCMD_MIN_STANDARD_INQUIRY_SIZE) { 169 return (rval); 170 } 171 172 /* 173 * If 0x83 is availible, that is the best choice. Our next choice is 174 * 0x80. If neither are availible, we leave it to the caller to 175 * determine possible alternate ID, although discouraged. In the 176 * case of the target drivers they create a fabricated id which is 177 * stored in the acyl. The HBA drivers should avoid using an 178 * alternate id. Although has already created a hack of using the 179 * node wwn in some cases. Which needs to be carried forward for 180 * legacy reasons. 181 */ 182 if (inq83 != NULL) { 183 /* 184 * Perform page 83 validation tests and report offenders. 185 * We cannot enforce the page 83 specification because 186 * many Sun partners (ex. HDS) do not conform to the 187 * standards yet. 188 */ 189 if (is_page83_data_valid(inq83, inq83_len) == 190 DEVID_RET_INVALID) { 191 /* 192 * invalid page 83 data. bug 4939576 introduced 193 * handling for EMC non-standard data. 194 */ 195 if ((bcmp(inq_std->inq_vid, SCSI_INQUIRY_VID_EMC, 196 SCSI_INQUIRY_VID_EMC_LEN) == 0) && 197 (bcmp(inq_std->inq_pid, 198 SCSI_INQUIRY_PID_EMC_SYMMETRIX, 199 SCSI_INQUIRY_PID_EMC_SYMMETRIX_LEN) == 0)) { 200 encode_scsi3_page83_emc(version, inq83, 201 inq83_len, &id, &id_len, &id_type); 202 } 203 #ifdef _KERNEL 204 /* 205 * invalid page 83 data. Special hack for HDS 206 * specific device, to suppress the warning msg. 207 */ 208 if ((bcmp(inq_std->inq_vid, SCSI_INQUIRY_VID_HITACHI, 209 SCSI_INQUIRY_VID_HITACHI_LEN) != 0) || 210 (bcmp(inq_std->inq_pid, 211 SCSI_INQUIRY_PID_HITACHI_OPEN, 212 SCSI_INQUIRY_PID_HITACHI_OPEN_LEN) != 0)) { 213 /* 214 * report the page 0x83 standards violation. 215 */ 216 msg = kmem_alloc( 217 MSG_NOT_STANDARDS_COMPLIANT_SIZE, 218 KM_SLEEP); 219 (void) strcpy(msg, MSG_NOT_STANDARDS_COMPLIANT); 220 (void) strncat(msg, inq_std->inq_vid, 221 sizeof (inq_std->inq_vid)); 222 (void) strcat(msg, " "); 223 (void) strncat(msg, inq_std->inq_pid, 224 sizeof (inq_std->inq_pid)); 225 (void) strcat(msg, " "); 226 (void) strncat(msg, inq_std->inq_revision, 227 sizeof (inq_std->inq_revision)); 228 (void) strcat(msg, "\n"); 229 cmn_err(CE_WARN, msg); 230 kmem_free(msg, 231 MSG_NOT_STANDARDS_COMPLIANT_SIZE); 232 } 233 #endif /* _KERNEL */ 234 } 235 236 if (id_type == DEVID_NONE) { 237 encode_scsi3_page83(version, inq83, 238 inq83_len, &id, &id_len, &id_type); 239 } 240 } 241 242 /* 243 * If no vpd page is available at this point then we 244 * attempt to use a SCSI serial number from page 0x80. 245 */ 246 if ((id_type == DEVID_NONE) && 247 (inq != NULL) && 248 (inq80 != NULL)) { 249 if (is_page80_data_valid(inq80, inq80_len) == DEVID_RET_VALID) { 250 encode_serialnum(version, inq, inq80, 251 inq80_len, &id, &id_len, &id_type); 252 } 253 } 254 255 /* 256 * If no vpd page or serial is available at this point and 257 * it's a SUN disk it conforms to the disk qual. 850 specifications 258 * and we can fabricate a serial number id based on the standard 259 * inquiry page. 260 */ 261 if ((id_type == DEVID_NONE) && 262 (inq != NULL)) { 263 encode_sun_serialnum(version, inq, inq_len, 264 &id, &id_len, &id_type); 265 } 266 267 if (id_type != DEVID_NONE) { 268 if (is_initialized_id(id, id_len) == DEVID_RET_VALID) { 269 rval = devid_scsi_init(driver_name, 270 id, id_len, id_type, devid); 271 } else { 272 rval = DEVID_RETRY; 273 } 274 DEVID_FREE(id, id_len); 275 } 276 277 return (rval); 278 } 279 280 281 /* 282 * Function: is_page83_data_valid 283 * 284 * Description: This routine is used to validate the page 0x83 data 285 * passed in valid based on the standards specification. 286 * 287 * Arguments: inq83 - 288 * inq83_len - 289 * 290 * Return Code: DEVID_RET_VALID 291 * DEVID_RET_INVALID 292 * 293 */ 294 static int 295 is_page83_data_valid(uchar_t *inq83, size_t inq83_len) 296 { 297 298 int covered_desc_len = 0; 299 int dlen = 0; 300 uchar_t *dblk = NULL; 301 302 DEVID_ASSERT(inq83 != NULL); 303 304 /* if not large enough fail */ 305 if (inq83_len < SCMD_MIN_INQUIRY_PAGE83_SIZE) 306 return (DEVID_RET_INVALID); 307 308 /* 309 * Ensuring that the Peripheral device type(bits 0 - 4) has 310 * the valid settings - the value 0x1f indicates no device type. 311 * Only this value can be validated since all other fields are 312 * either used or reserved. 313 */ 314 if ((inq83[0] & DTYPE_MASK) == DTYPE_UNKNOWN) { 315 /* failed-peripheral devtype */ 316 return (DEVID_RET_INVALID); 317 } 318 319 /* 320 * Ensure that the page length field - third and 4th bytes 321 * contain a non zero length value. Our implementation 322 * does not seem to expect more that 255 bytes of data... 323 * what is to be done if the reported size is > 255 bytes? 324 * Yes the device will return only 255 bytes as we provide 325 * buffer to house only that much data but the standards 326 * prevent the targets from reporting the truncated size 327 * in this field. 328 * 329 * Currently reporting sizes more than 255 as failure. 330 * 331 */ 332 333 if ((inq83[2] == 0) && (inq83[3] == 0)) { 334 /* length field is 0! */ 335 return (DEVID_RET_INVALID); 336 } 337 if (inq83[3] > (SCMD_MAX_INQUIRY_PAGE83_SIZE - 3)) { 338 /* length field exceeds expected size of 255 bytes */ 339 return (DEVID_RET_INVALID); 340 } 341 342 /* 343 * Validation of individual descriptor blocks are done in the 344 * following while loop. It is possible to have multiple 345 * descriptor blocks. 346 * the 'dblk' pointer will be pointing to the start of 347 * each entry of the descriptor block. 348 */ 349 covered_desc_len = 0; 350 dblk = &inq83[4]; /* start of first decriptor blk */ 351 while (covered_desc_len < inq83[3]) { 352 353 /* 354 * Ensure that the length field is non zero 355 * Further length validations will be done 356 * along with the 'identifier type' as some of 357 * the lengths are dependent on it. 358 */ 359 dlen = dblk[3]; 360 if (dlen == 0) { 361 /* descr length is 0 */ 362 return (DEVID_RET_INVALID); 363 } 364 365 /* 366 * ensure that the size of the descriptor block does 367 * not claim to be larger than the entire page83 368 * data that has been received. 369 */ 370 if ((covered_desc_len + dlen) > inq83[3]) { 371 /* failed-descr length */ 372 return (DEVID_RET_INVALID); 373 } 374 375 /* 376 * The spec says that if the PIV field is 0 OR the 377 * association field contains value other than 1 and 2, 378 * then the protocol identifier field should be ignored. 379 * If association field contains a value of 1 or 2 380 * and the PIV field is set, then the protocol identifier 381 * field has to be validated. 382 * The protocol identifier values 0 - f are either assigned 383 * or reserved. Nothing to validate here, hence skipping 384 * over to the next check. 385 */ 386 387 /* 388 * Check for valid code set values. 389 * All possible values are reserved or assigned. Nothing 390 * to validate - skipping over. 391 */ 392 393 /* 394 * Identifier Type validation 395 * All SPC3rev22 identified types and the expected lengths 396 * are validated. 397 */ 398 switch (dblk[1] & 0x0f) { 399 case SCMD_INQUIRY_VPD_TYPE_T10: /* T10 vendor Id */ 400 /* No specific length validation required */ 401 break; 402 403 case SCMD_INQUIRY_VPD_TYPE_EUI: /* EUI 64 ID */ 404 /* EUI-64: size is expected to be 8, 12, or 16 bytes */ 405 if ((dlen != 8) && (dlen != 12) && (dlen != 16)) { 406 /* page83 validation failed-EIU64 */ 407 return (DEVID_RET_INVALID); 408 } 409 break; 410 411 case SCMD_INQUIRY_VPD_TYPE_NAA: /* NAA Id type */ 412 413 /* 414 * the size for this varies - 415 * IEEE extended/registered is 8 bytes 416 * IEEE Registered extended is 16 bytes 417 */ 418 switch (dblk[4] & 0xf0) { 419 420 case 0x20: /* IEEE Ext */ 421 case 0x50: /* IEEE Reg */ 422 if (dlen != 8) { 423 /* failed-IEE E/R len */ 424 return (DEVID_RET_INVALID); 425 } 426 /* 427 * the codeSet for this MUST 428 * be set to 1 429 */ 430 if ((dblk[0] & 0x0f) != 1) { 431 /* 432 * failed-IEEE E/R 433 * codeSet != 1. 434 */ 435 return (DEVID_RET_INVALID); 436 } 437 break; 438 439 case 0x60: /* IEEE EXT REG */ 440 if (dlen != 16) { 441 /* failed-IEEE ER len */ 442 return (DEVID_RET_INVALID); 443 } 444 /* 445 * the codeSet for this MUST 446 * be set to 1 447 */ 448 if ((dblk[0] & 0x0f) != 1) { 449 /* 450 * failed-IEEE ER 451 * codeSet != 1. 452 */ 453 return (DEVID_RET_INVALID); 454 } 455 break; 456 457 default: 458 /* reserved values */ 459 break; 460 } 461 break; 462 463 case SCMD_INQUIRY_VPD_TYPE_RTP: /* Relative Target port */ 464 if (dlen != 4) { 465 /* failed-Rel target Port length */ 466 return (DEVID_RET_INVALID); 467 } 468 break; 469 470 case SCMD_INQUIRY_VPD_TYPE_TPG: /* Target port group */ 471 if (dlen != 4) { 472 /* failed-target Port group length */ 473 return (DEVID_RET_INVALID); 474 } 475 break; 476 477 case SCMD_INQUIRY_VPD_TYPE_LUG: /* Logical unit group */ 478 if (dlen != 4) { 479 /* failed-Logical Unit group length */ 480 return (DEVID_RET_INVALID); 481 } 482 break; 483 484 case SCMD_INQUIRY_VPD_TYPE_MD5: /* MD5 unit group */ 485 if (dlen != 16) { 486 /* failed-MD5 Unit grp */ 487 return (DEVID_RET_INVALID); 488 } 489 break; 490 491 default: 492 break; 493 } 494 495 /* 496 * Now lets advance to the next descriptor block 497 * and validate it. 498 * the descriptor block size is <descr Header> + <descr Data> 499 * <descr Header> is equal to 4 bytes 500 * <descr Data> is available in dlen or dblk[3]. 501 */ 502 dblk = &dblk[4 + dlen]; 503 504 /* 505 * update the covered_desc_len so that we can ensure that 506 * the 'while' loop terminates. 507 */ 508 covered_desc_len += (dlen + 4); 509 } 510 return (DEVID_RET_VALID); 511 } 512 513 514 /* 515 * Function: is_initialized_id 516 * 517 * Description: Routine to ensure that the ID calculated is not a 518 * space or zero filled ID. Returning a space / zero 519 * filled ID when the luns on the target are not fully 520 * initialized is a valid response from the target as 521 * per the T10 spec. When a space/zero filled ID is 522 * found its information needs to be polled again 523 * after sometime time to see if the luns are fully 524 * initialized to return a valid guid information. 525 * 526 * Arguments: id - raw id 527 * id_len - raw id len 528 * 529 * Return Code: DEVID_VALID - indicates a non space/zero filled id 530 * DEVID_INVALID - indicates id contains uninitialized data 531 * and suggests retry of the collection commands. 532 */ 533 static int 534 is_initialized_id(uchar_t *id, size_t id_len) 535 { 536 int idx; 537 538 if ((id == NULL) || 539 (id_len == 0)) { 540 /* got id length as 0 fetch info again */ 541 return (DEVID_RET_INVALID); 542 } 543 544 /* First lets check if the guid is filled with spaces */ 545 for (idx = 0; idx < id_len; idx++) { 546 if (id[idx] != ' ') { 547 break; 548 } 549 } 550 551 /* 552 * Lets exit if we find that it contains ALL spaces 553 * saying that it has an uninitialized guid 554 */ 555 if (idx >= id_len) { 556 /* guid filled with spaces found */ 557 return (DEVID_RET_INVALID); 558 } 559 560 /* 561 * Since we have found that it is not filled with spaces 562 * now lets ensure that the guid is not filled with only 563 * zeros. 564 */ 565 for (idx = 0; idx < id_len; idx ++) { 566 if (id[idx] != 0) { 567 return (DEVID_RET_VALID); 568 } 569 } 570 571 /* guid filled with zeros found */ 572 return (DEVID_RET_INVALID); 573 } 574 575 576 /* 577 * Function: is_page80_data_valid 578 * 579 * Description: This routine is used to validate the page 0x80 data 580 * passed in valid based on the standards specification. 581 * 582 * Arguments: inq80 - 583 * inq80_len - 584 * 585 * Return Code: DEVID_RET_VALID 586 * DEVID_RET_INVALID 587 * 588 */ 589 /* ARGSUSED */ 590 static int 591 is_page80_data_valid(uchar_t *inq80, size_t inq80_len) 592 { 593 DEVID_ASSERT(inq80); 594 595 /* if not large enough fail */ 596 if (inq80_len < SCMD_MIN_INQUIRY_PAGE80_SIZE) { 597 return (DEVID_RET_INVALID); 598 } 599 600 /* 601 * (inq80_len - 4) is the size of the buffer space available 602 * for the product serial number. So inq80[3] (ie. product 603 * serial number) should be <= (inq80_len -4). 604 */ 605 if (inq80[3] > (inq80_len - 4)) { 606 return (DEVID_RET_INVALID); 607 } 608 609 return (DEVID_RET_VALID); 610 } 611 612 613 /* 614 * Function: encode_devid_page 615 * 616 * Description: This routine finds the unique devid if available and 617 * fills the devid and length parameters. 618 * 619 * Arguments: version - encode version 620 * inq83 - driver soft state (unit) structure 621 * inq83_len - length of raw inq83 data 622 * id - raw id 623 * id_len - len of raw id 624 * id_type - type of id 625 * 626 * Note: DEVID_NONE is returned in the id_type field 627 * if no supported page 83 id is found. 628 */ 629 static void 630 encode_scsi3_page83(int version, uchar_t *inq83, size_t inq83_len, 631 uchar_t **id, size_t *id_len, ushort_t *id_type) 632 { 633 size_t descriptor_bytes_left = 0; 634 size_t offset = 0; 635 int idx = 0; 636 size_t offset_id_type[4]; 637 638 DEVID_ASSERT(inq83 != NULL); 639 /* inq83 length was already validate in is_page83_valid */ 640 DEVID_ASSERT(id != NULL); 641 DEVID_ASSERT(id_len != NULL); 642 DEVID_ASSERT(id_type != NULL); 643 644 /* preset defaults */ 645 *id = NULL; 646 *id_len = 0; 647 *id_type = DEVID_NONE; 648 649 /* verify we have enough memory for a ident header */ 650 if (inq83_len < SCMD_INQUIRY_PAGE83_HDR_SIZE) { 651 return; 652 } 653 654 /* 655 * Attempt to validate the page data. Once validated, we'll walk 656 * the descriptors, looking for certain identifier types that will 657 * mark this device with a unique id/wwn. Note the comment below 658 * for what we really want to receive. 659 */ 660 661 /* 662 * The format of the inq83 data (Device Identification VPD page) is 663 * a header (containing the total length of the page, from which 664 * descriptor_bytes_left is calculated), followed by a list of 665 * identification descriptors. Each identifcation descriptor has a 666 * header which includes the length of the individual identification 667 * descriptor). 668 * 669 * Set the offset to the beginning byte of the first identification 670 * descriptor. We'll index everything from there. 671 */ 672 offset = SCMD_INQUIRY_PAGE83_HDR_SIZE; 673 descriptor_bytes_left = (size_t)((inq83[2] << 8) | inq83[3]); 674 675 /* 676 * If the raw data states that the data is larger 677 * than what is actually received abort encode. 678 * Otherwise we will run off into unknown memory 679 * on the decode. 680 */ 681 if ((descriptor_bytes_left + offset) > inq83_len) { 682 return; 683 } 684 685 686 /* Zero out our offset array */ 687 bzero(offset_id_type, sizeof (offset_id_type)); 688 689 /* 690 * According to the scsi spec 8.4.3 SPC-2, there could be several 691 * descriptors associated with each lun. Some we care about and some 692 * we don't. This loop is set up to iterate through the descriptors. 693 * We want the 0x03 case which represents an FC-PH, FC-PH3 or FC-FS 694 * Name_Identifier. The spec mentions nothing about ordering, so we 695 * don't assume any. 696 * 697 * We need to check if we've finished walking the list of descriptors, 698 * we also perform additional checks to be sure the newly calculated 699 * offset is within the bounds of the buffer, and the identifier length 700 * (as calculated by the length field in the header) is valid. This is 701 * done to protect against devices which return bad page83 data. 702 */ 703 while ((descriptor_bytes_left > 0) && (offset_id_type[3] == 0) && 704 (offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE <= inq83_len) && 705 (offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE + 706 (size_t)inq83[offset + 3] <= inq83_len)) { 707 /* 708 * Inspect the Identification descriptor list. Store the 709 * offsets in the devid page separately for 0x03, 0x01 and 710 * 0x02. Identifiers 0x00 and 0x04 are not useful as they 711 * don't represent unique identifiers for a lun. We also 712 * check the association by masking with 0x3f because we want 713 * an association of 0x0 - indicating the identifier field is 714 * associated with the addressed physical or logical device 715 * and not the port. 716 */ 717 switch ((inq83[offset + 1] & 0x3f)) { 718 case SCMD_INQUIRY_VPD_TYPE_T10: 719 offset_id_type[SCMD_INQUIRY_VPD_TYPE_T10] = offset; 720 break; 721 case SCMD_INQUIRY_VPD_TYPE_EUI: 722 offset_id_type[SCMD_INQUIRY_VPD_TYPE_EUI] = offset; 723 break; 724 case SCMD_INQUIRY_VPD_TYPE_NAA: 725 offset_id_type[SCMD_INQUIRY_VPD_TYPE_NAA] = offset; 726 break; 727 default: 728 /* Devid page undesired id type */ 729 break; 730 } 731 /* 732 * Calculate the descriptor bytes left and move to 733 * the beginning byte of the next id descriptor. 734 */ 735 descriptor_bytes_left -= (size_t)(inq83[offset + 3] + 736 SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE); 737 offset += (SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE + 738 (size_t)inq83[offset + 3]); 739 } 740 741 offset = 0; 742 743 /* 744 * We can't depend on an order from a device by identifier type, but 745 * once we have them, we'll walk them in the same order to prevent a 746 * firmware upgrade from breaking our algorithm. Start with the one 747 * we want the most: id_offset_type[3]. 748 */ 749 for (idx = 3; idx > 0; idx--) { 750 if (offset_id_type[idx] > 0) { 751 offset = offset_id_type[idx]; 752 break; 753 } 754 } 755 756 /* 757 * We have a valid Device ID page, set the length of the 758 * identifier and copy the value into the wwn. 759 */ 760 if (offset > 0) { 761 *id_len = (size_t)inq83[offset + 3]; 762 if ((*id = DEVID_MALLOC(*id_len)) == NULL) { 763 *id_len = 0; 764 return; 765 } 766 bcopy(&inq83[offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE], 767 *id, *id_len); 768 769 /* set devid type */ 770 switch (version) { 771 /* In version 1 all page 83 types were grouped */ 772 case DEVID_SCSI_ENCODE_VERSION1: 773 *id_type = DEVID_SCSI3_WWN; 774 break; 775 /* In version 2 we break page 83 apart to be unique */ 776 case DEVID_SCSI_ENCODE_VERSION2: 777 switch (idx) { 778 case 3: 779 *id_type = DEVID_SCSI3_VPD_NAA; 780 break; 781 case 2: 782 *id_type = DEVID_SCSI3_VPD_EUI; 783 break; 784 case 1: 785 *id_type = DEVID_SCSI3_VPD_T10; 786 break; 787 default: 788 DEVID_FREE(*id, *id_len); 789 *id_len = 0; 790 break; 791 } 792 break; 793 default: 794 DEVID_FREE(*id, *id_len); 795 *id_len = 0; 796 break; 797 } 798 } 799 } 800 801 802 /* 803 * Function: encode_scsi3_page83_emc 804 * 805 * Description: Routine to handle proprietary page 83 of EMC Symmetrix 806 * device. Called by ssfcp_handle_page83() 807 * 808 * Arguments: version - encode version 809 * inq83 - scsi page 83 buffer 810 * inq83_len - scsi page 83 buffer size 811 * id - raw emc id 812 * id_len - len of raw emc id 813 * id_type - type of emc id 814 */ 815 static void 816 encode_scsi3_page83_emc(int version, uchar_t *inq83, 817 size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type) 818 { 819 uchar_t *guidp = NULL; 820 821 DEVID_ASSERT(inq83 != NULL); 822 DEVID_ASSERT(id != NULL); 823 DEVID_ASSERT(id_len != NULL); 824 DEVID_ASSERT(id_type != NULL); 825 826 /* preset defaults */ 827 *id = NULL; 828 *id_len = 0; 829 *id_type = DEVID_NONE; 830 831 /* The initial devid algorithm didn't use EMC page 83 data */ 832 if (version == DEVID_SCSI_ENCODE_VERSION1) { 833 return; 834 } 835 836 /* EMC page 83 requires atleast 20 bytes */ 837 if (inq83_len < (SCMD_INQUIRY_PAGE83_HDR_SIZE + 838 SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN)) { 839 return; 840 } 841 842 /* 843 * The 4th byte in the page 83 info returned is most likely 844 * indicating the length of the id - which 0x10(16 bytes) 845 * and the 5th byte is indicating that the id is of 846 * IEEE Registered Extended Name format(6). Validate 847 * these code prints before proceeding further as the 848 * following proprietary approach is tied to the specific 849 * device type and incase the EMC firmware changes, we will 850 * have to validate for the changed device before we start 851 * supporting such a device. 852 */ 853 if ((inq83[3] != 0x10) || (inq83[4] != 0x60)) { 854 /* unsupported emc symtx device type */ 855 return; 856 } else { 857 guidp = &inq83[SCMD_INQUIRY_PAGE83_HDR_SIZE]; 858 /* 859 * The GUID returned by the EMC device is 860 * in the IEEE Registered Extended Name format(6) 861 * as a result it is of 16 bytes in length. 862 * An IEEE Registered Name format(5) will be of 863 * 8 bytes which is NOT what is being returned 864 * by the device type for which we are providing 865 * the support. 866 */ 867 *id_len = SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN; 868 if ((*id = DEVID_MALLOC(*id_len)) == NULL) { 869 *id_len = 0; 870 return; 871 } 872 bcopy(guidp, *id, *id_len); 873 874 /* emc id matches type 3 */ 875 *id_type = DEVID_SCSI3_VPD_NAA; 876 } 877 } 878 879 880 /* 881 * Function: encode_serialnum 882 * 883 * Description: This routine finds the unique devid from the inquiry page 884 * 0x80, serial number page. If available and fills the wwn 885 * and length parameters. 886 * 887 * Arguments: version - encode version 888 * inq - standard inquiry data 889 * inq80 - serial inquiry data 890 * inq80_len - serial inquiry data len 891 * id - raw id 892 * id_len - raw id len 893 * id_type - raw id type 894 */ 895 /* ARGSUSED */ 896 static void 897 encode_serialnum(int version, uchar_t *inq, uchar_t *inq80, 898 size_t inq80_len, uchar_t **id, size_t *id_len, ushort_t *id_type) 899 { 900 struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq; 901 int idx = 0; 902 903 DEVID_ASSERT(inq != NULL); 904 DEVID_ASSERT(inq80 != NULL); 905 DEVID_ASSERT(id != NULL); 906 DEVID_ASSERT(id_len != NULL); 907 DEVID_ASSERT(id_type != NULL); 908 909 /* preset defaults */ 910 *id = NULL; 911 *id_len = 0; 912 *id_type = DEVID_NONE; 913 914 /* verify inq80 buffer is large enough for a header */ 915 if (inq80_len < SCMD_MIN_INQUIRY_PAGE80_SIZE) { 916 return; 917 } 918 919 /* 920 * Attempt to validate the page data. Once validated, we'll check 921 * the serial number. 922 */ 923 *id_len = (size_t)inq80[3]; /* Store Product Serial Number length */ 924 925 /* verify buffer is large enough for serial number */ 926 if (inq80_len < (*id_len + SCMD_MIN_INQUIRY_PAGE80_SIZE)) { 927 return; 928 } 929 930 /* 931 * Device returns ASCII space (20h) in all the bytes of successful data 932 * transfer, if the product serial number is not available. So we end 933 * up having to check all the bytes for a space until we reach 934 * something else. 935 */ 936 for (idx = 0; idx < *id_len; idx++) { 937 if (inq80[4 + idx] == ' ') { 938 continue; 939 } 940 /* 941 * The serial number is valid, but since this is only vendor 942 * unique, we'll combine the inquiry vid and pid with the 943 * serial number. 944 */ 945 *id_len += sizeof (inq_std->inq_vid); 946 *id_len += sizeof (inq_std->inq_pid); 947 948 if ((*id = DEVID_MALLOC(*id_len)) == NULL) { 949 *id_len = 0; 950 return; 951 } 952 953 bcopy(&inq_std->inq_vid, *id, sizeof (inq_std->inq_vid)); 954 bcopy(&inq_std->inq_pid, &(*id)[sizeof (inq_std->inq_vid)], 955 sizeof (inq_std->inq_pid)); 956 bcopy(&inq80[4], &(*id)[sizeof (inq_std->inq_vid) + 957 sizeof (inq_std->inq_pid)], inq80[3]); 958 959 *id_type = DEVID_SCSI_SERIAL; 960 break; 961 } 962 963 /* 964 * The spec suggests that the command could succeed but return all 965 * spaces if the product serial number is not available. In this case 966 * we need to fail this routine. To accomplish this, we compare our 967 * length to the serial number length. If they are the same, then we 968 * never copied in the vid and updated the length. That being the case, 969 * we must not have found a valid serial number. 970 */ 971 if (*id_len == (size_t)inq80[3]) { 972 /* empty unit serial number */ 973 if (*id != NULL) { 974 DEVID_FREE(*id, *id_len); 975 } 976 *id = NULL; 977 *id_len = 0; 978 } 979 } 980 981 982 /* 983 * Function: encode_sun_serialnum 984 * 985 * Description: This routine finds the unique devid from the inquiry page 986 * 0x80, serial number page. If available and fills the wwn 987 * and length parameters. 988 * 989 * Arguments: version - encode version 990 * inq - standard inquiry data 991 * inq_len - standard inquiry data len 992 * id - raw id 993 * id_len - raw id len 994 * id_type - raw id type 995 * 996 * Return Code: DEVID_SUCCESS 997 * DEVID_FAILURE 998 */ 999 /* ARGSUSED */ 1000 static void 1001 encode_sun_serialnum(int version, uchar_t *inq, 1002 size_t inq_len, uchar_t **id, size_t *id_len, ushort_t *id_type) 1003 { 1004 struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq; 1005 1006 DEVID_ASSERT(inq != NULL); 1007 DEVID_ASSERT(id != NULL); 1008 DEVID_ASSERT(id_len != NULL); 1009 DEVID_ASSERT(id_type != NULL); 1010 1011 /* verify enough buffer is available */ 1012 if (inq_len < SCMD_MIN_STANDARD_INQUIRY_SIZE) { 1013 return; 1014 } 1015 1016 /* sun qual drive */ 1017 if ((inq_std != NULL) && 1018 (bcmp(&inq_std->inq_pid[SCSI_INQUIRY_VID_POS], 1019 SCSI_INQUIRY_VID_SUN, SCSI_INQUIRY_VID_SUN_LEN) == 0)) { 1020 /* 1021 * VPD pages 0x83 and 0x80 are unavailable. This 1022 * is a Sun qualified disks as indicated by 1023 * "SUN" in bytes 25-27 of the inquiry data 1024 * (bytes 9-11 of the pid). Devid's are created 1025 * for Sun qualified disks by combining the 1026 * vendor id with the product id with the serial 1027 * number located in bytes 36-47 of the inquiry data. 1028 */ 1029 1030 /* get data size */ 1031 *id_len = sizeof (inq_std->inq_vid) + 1032 sizeof (inq_std->inq_pid) + 1033 sizeof (inq_std->inq_serial); 1034 1035 if ((*id = DEVID_MALLOC(*id_len)) == NULL) { 1036 *id_len = 0; 1037 return; 1038 } 1039 1040 /* copy the vid at the beginning */ 1041 bcopy(&inq_std->inq_vid, *id, 1042 sizeof (inq_std->inq_vid)); 1043 /* copy the pid after the vid */ 1044 bcopy(&inq_std->inq_pid, 1045 &(*id)[sizeof (inq_std->inq_vid)], 1046 sizeof (inq_std->inq_pid)); 1047 /* copy the serial number after the vid and pid */ 1048 bcopy(&inq_std->inq_serial, 1049 &(*id)[sizeof (inq_std->inq_vid) + 1050 sizeof (inq_std->inq_pid)], 1051 sizeof (inq_std->inq_serial)); 1052 /* devid formed from inquiry data */ 1053 *id_type = DEVID_SCSI_SERIAL; 1054 } 1055 } 1056 1057 1058 /* 1059 * Function: devid_scsi_init 1060 * 1061 * Description: This routine is used to create a devid for a scsi 1062 * devid type. 1063 * 1064 * Arguments: hint - driver soft state (unit) structure 1065 * raw_id - pass by reference variable to hold wwn 1066 * raw_id_len - wwn length 1067 * raw_id_type - 1068 * ret_devid - 1069 * 1070 * Return Code: DEVID_SUCCESS 1071 * DEVID_FAILURE 1072 * 1073 */ 1074 static int 1075 devid_scsi_init( 1076 char *driver_name, 1077 uchar_t *raw_id, 1078 size_t raw_id_len, 1079 ushort_t raw_id_type, 1080 ddi_devid_t *ret_devid) 1081 { 1082 impl_devid_t *i_devid = NULL; 1083 int i_devid_len = 0; 1084 int driver_name_len = 0; 1085 ushort_t u_raw_id_len = 0; 1086 1087 DEVID_ASSERT(raw_id != NULL); 1088 DEVID_ASSERT(ret_devid != NULL); 1089 1090 if (!IS_DEVID_SCSI_TYPE(raw_id_type)) { 1091 *ret_devid = NULL; 1092 return (DEVID_FAILURE); 1093 } 1094 1095 i_devid_len = sizeof (*i_devid) + raw_id_len - sizeof (i_devid->did_id); 1096 if ((i_devid = DEVID_MALLOC(i_devid_len)) == NULL) { 1097 *ret_devid = NULL; 1098 return (DEVID_FAILURE); 1099 } 1100 1101 i_devid->did_magic_hi = DEVID_MAGIC_MSB; 1102 i_devid->did_magic_lo = DEVID_MAGIC_LSB; 1103 i_devid->did_rev_hi = DEVID_REV_MSB; 1104 i_devid->did_rev_lo = DEVID_REV_LSB; 1105 DEVID_FORMTYPE(i_devid, raw_id_type); 1106 u_raw_id_len = raw_id_len; 1107 DEVID_FORMLEN(i_devid, u_raw_id_len); 1108 1109 /* Fill in driver name hint */ 1110 if (driver_name != NULL) { 1111 driver_name_len = strlen(driver_name); 1112 if (driver_name_len > DEVID_HINT_SIZE) { 1113 /* Pick up last four characters of driver name */ 1114 driver_name += driver_name_len - DEVID_HINT_SIZE; 1115 driver_name_len = DEVID_HINT_SIZE; 1116 } 1117 bcopy(driver_name, i_devid->did_driver, driver_name_len); 1118 } else { 1119 bzero(i_devid->did_driver, DEVID_HINT_SIZE); 1120 } 1121 1122 bcopy(raw_id, i_devid->did_id, raw_id_len); 1123 1124 /* return device id */ 1125 *ret_devid = (ddi_devid_t)i_devid; 1126 return (DEVID_SUCCESS); 1127 } 1128 1129 1130 /* 1131 * Function: devid_to_guid 1132 * 1133 * Description: This routine extracts a guid string form a devid. 1134 * The common use of this guid is for a HBA driver 1135 * to pass into mdi_pi_alloc(). 1136 * 1137 * Arguments: devid - devid to extract guid from 1138 * 1139 * Return Code: guid string - success 1140 * NULL - failure 1141 */ 1142 char * 1143 #ifdef _KERNEL 1144 ddi_devid_to_guid(ddi_devid_t devid) 1145 #else /* !_KERNEL */ 1146 devid_to_guid(ddi_devid_t devid) 1147 #endif /* _KERNEL */ 1148 { 1149 impl_devid_t *id = (impl_devid_t *)devid; 1150 int len = 0; 1151 int idx = 0; 1152 int num = 0; 1153 char *guid = NULL; 1154 char *ptr = NULL; 1155 char *dp = NULL; 1156 1157 DEVID_ASSERT(devid != NULL); 1158 1159 /* NULL devid -> NULL guid */ 1160 if (devid == NULL) 1161 return (NULL); 1162 1163 if (!IS_DEVID_GUID_TYPE(DEVID_GETTYPE(id))) 1164 return (NULL); 1165 1166 /* guid is always converted to ascii, append NULL */ 1167 len = DEVID_GETLEN(id); 1168 1169 /* allocate guid string */ 1170 if ((guid = DEVID_MALLOC((len * 2) + 1)) == NULL) 1171 return (NULL); 1172 1173 /* perform encode of id to hex string */ 1174 ptr = guid; 1175 for (idx = 0, dp = &id->did_id[0]; idx < len; idx++, dp++) { 1176 num = ((*dp) >> 4) & 0xF; 1177 *ptr++ = (num < 10) ? (num + '0') : (num + ('a' - 10)); 1178 num = (*dp) & 0xF; 1179 *ptr++ = (num < 10) ? (num + '0') : (num + ('a' - 10)); 1180 } 1181 *ptr = 0; 1182 1183 return (guid); 1184 } 1185 1186 /* 1187 * Function: devid_free_guid 1188 * 1189 * Description: This routine frees a guid allocated by 1190 * devid_to_guid(). 1191 * 1192 * Arguments: guid - guid to free 1193 */ 1194 void 1195 #ifdef _KERNEL 1196 ddi_devid_free_guid(char *guid) 1197 #else /* !_KERNEL */ 1198 devid_free_guid(char *guid) 1199 #endif /* _KERNEL */ 1200 { 1201 if (guid != NULL) { 1202 DEVID_FREE(guid, strlen(guid) + 1); 1203 } 1204 } 1205 1206 static char 1207 ctoi(char c) 1208 { 1209 if ((c >= '0') && (c <= '9')) 1210 c -= '0'; 1211 else if ((c >= 'A') && (c <= 'F')) 1212 c = c - 'A' + 10; 1213 else if ((c >= 'a') && (c <= 'f')) 1214 c = c - 'a' + 10; 1215 else 1216 c = -1; 1217 return (c); 1218 } 1219 1220 /* 1221 * Function: devid_str_to_wwn 1222 * 1223 * Description: This routine translates wwn from string to uint64 type. 1224 * 1225 * Arguments: string - the string wwn to be transformed 1226 * wwn - the pointer to 64 bit wwn 1227 */ 1228 int 1229 #ifdef _KERNEL 1230 ddi_devid_str_to_wwn(const char *string, uint64_t *wwn) 1231 #else /* !_KERNEL */ 1232 devid_str_to_wwn(const char *string, uint64_t *wwn) 1233 #endif /* _KERNEL */ 1234 { 1235 int i; 1236 char cl, ch; 1237 uint64_t tmp; 1238 1239 if (wwn == NULL || strlen(string) != 16) { 1240 return (DDI_FAILURE); 1241 } 1242 1243 *wwn = 0; 1244 for (i = 0; i < 8; i++) { 1245 ch = ctoi(*string++); 1246 cl = ctoi(*string++); 1247 if (cl == -1 || ch == -1) { 1248 return (DDI_FAILURE); 1249 } 1250 tmp = (ch << 4) + cl; 1251 *wwn = (*wwn << 8) | tmp; 1252 } 1253 return (DDI_SUCCESS); 1254 } 1255