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