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