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