Print this page
NEX-7303 USN may contain garbage
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-3705 Need to update libses with LID/USN code from sesctld (lint fix)
NEX-3705 Need to update libses with LID/USN code from sesctld
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/scsi/libscsi/common/scsi_subr.c
          +++ new/usr/src/lib/scsi/libscsi/common/scsi_subr.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  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]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24   25   */
  25   26  
  26   27  #include <sys/types.h>
  27   28  #include <sys/scsi/generic/commands.h>
  28   29  #include <sys/scsi/impl/spc3_types.h>
  29   30  
  30   31  #include <stddef.h>
  31   32  #include <stdlib.h>
  32   33  #include <string.h>
  33   34  #include <strings.h>
  34   35  #include <alloca.h>
  35   36  #include <stdio.h>
  36   37  #include <unistd.h>
  37   38  #include <dlfcn.h>
  38   39  
  39   40  #include <scsi/libscsi.h>
       41 +#include <sys/byteorder.h>
  40   42  #include "libscsi_impl.h"
  41   43  
  42   44  int
  43   45  libscsi_assert(const char *expr, const char *file, int line)
  44   46  {
  45   47          char *msg;
  46   48          size_t len;
  47   49  
  48   50          len = snprintf(NULL, 0,
  49   51              "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
↓ open down ↓ 241 lines elided ↑ open up ↑
 291  293  libscsi_get_inquiry(libscsi_hdl_t *hp, libscsi_target_t *tp)
 292  294  {
 293  295          libscsi_action_t *ap;
 294  296          spc3_inquiry_cdb_t *cp;
 295  297          spc3_inquiry_data_t data;
 296  298          size_t len;
 297  299  
 298  300          if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY,
 299  301              LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data,
 300  302              offsetof(spc3_inquiry_data_t, id_vs_36[0]))) == NULL)
 301      -                return (-1);
      303 +                return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
 302  304  
 303  305          cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap);
 304  306  
 305  307          SCSI_WRITE16(&cp->ic_allocation_length,
 306  308              offsetof(spc3_inquiry_data_t, id_vs_36[0]));
 307  309  
 308  310          if (libscsi_exec(ap, tp) != 0 ||
 309  311              libscsi_action_get_status(ap) != 0) {
 310  312                  libscsi_action_free(ap);
 311  313                  return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
↓ open down ↓ 5 lines elided ↑ open up ↑
 317  319          if (len < offsetof(spc3_inquiry_data_t, id_vs_36))
 318  320                  return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
 319  321  
 320  322          if ((tp->lst_vendor = libscsi_process_inquiry_string(hp,
 321  323              data.id_vendor_id, sizeof (data.id_vendor_id))) == NULL ||
 322  324              (tp->lst_product = libscsi_process_inquiry_string(hp,
 323  325              data.id_product_id, sizeof (data.id_product_id))) == NULL ||
 324  326              (tp->lst_revision = libscsi_process_inquiry_string(hp,
 325  327              data.id_product_revision,
 326  328              sizeof (data.id_product_revision))) == NULL) {
 327      -                return (-1);
      329 +                return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
 328  330          }
 329  331  
 330  332          return (0);
 331  333  }
 332  334  
      335 +/*
      336 + * A designation descriptor consists of the header followed by data.
      337 + * When given a pointer to the header to get to next descriptor we need to add
      338 + * to hdr pointer the number of data bytes plus size of the header itself.
      339 + */
      340 +#define NEXT_DESC(hdr, data_len, hdr_type) ((hdr_type *)((((uint8_t *)hdr) + \
      341 +    data_len + sizeof (hdr_type))))
      342 +
      343 +int
      344 +libscsi_get_inquiry_dev_id(libscsi_hdl_t *hp, libscsi_target_t *tp)
      345 +{
      346 +        libscsi_action_t *ap;
      347 +        spc3_inquiry_cdb_t *cp;
      348 +        spc3_dev_id_vpd_page_impl_t data;
      349 +        size_t len;
      350 +        int des_bytes_left;
      351 +        struct vpd_desc *cur_desc;
      352 +        char lid[17];
      353 +
      354 +        if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY,
      355 +            LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data,
      356 +            sizeof (spc3_dev_id_vpd_page_impl_t))) == NULL)
      357 +                return (libscsi_set_errno(hp, ESCSI_NOMEM));
      358 +
      359 +        cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap);
      360 +        cp->ic_evpd = 1; /* return vital product data for bellow page code */
      361 +        cp->ic_page_code = DEV_ID_VPD_PAGE_CODE;
      362 +        SCSI_WRITE16(&cp->ic_allocation_length,
      363 +            sizeof (spc3_dev_id_vpd_page_impl_t));
      364 +
      365 +        if (libscsi_exec(ap, tp) != 0 ||
      366 +            libscsi_action_get_status(ap) != 0) {
      367 +                libscsi_action_free(ap);
      368 +                return (libscsi_set_errno(hp, ESCSI_IO));
      369 +        }
      370 +
      371 +        (void) libscsi_action_get_buffer(ap, NULL, NULL, &len);
      372 +        libscsi_action_free(ap);
      373 +
      374 +        /* make sure we at least got the header */
      375 +        if (len < offsetof(spc3_dev_id_vpd_page_impl_t, divpi_descrs[0]))
      376 +                return (libscsi_set_errno(hp, ESCSI_BADLENGTH));
      377 +
      378 +        /* make sure we got the page we asked for */
      379 +        if (data.divpi_hdr.page_code != DEV_ID_VPD_PAGE_CODE)
      380 +                return (libscsi_set_errno(hp, ESCSI_IO));
      381 +
      382 +        /* check for page truncation */
      383 +        len = ((data.divpi_hdr.page_len)[0] << 8 |
      384 +            (data.divpi_hdr.page_len)[1]);
      385 +        if (len > sizeof (data.divpi_descrs))
      386 +                return (libscsi_set_errno(hp, ESCSI_BADLENGTH));
      387 +
      388 +        /* get the first descriptor */
      389 +        cur_desc = (struct vpd_desc *)(data.divpi_descrs);
      390 +        /* iterate over descriptors looking for the one we need */
      391 +        des_bytes_left = len;
      392 +        for (; des_bytes_left > sizeof (struct vpd_desc);
      393 +            des_bytes_left -= (sizeof (struct vpd_desc) + cur_desc->len),
      394 +            cur_desc = NEXT_DESC(cur_desc, cur_desc->len, struct vpd_desc)) {
      395 +
      396 +                /*
      397 +                 * Len for the NAA IEEE designators is 12 (aka 0x08).
      398 +                 * Designator type (id_type) 3 means a NAA formatted
      399 +                 * designator.
      400 +                 * Code set for the NAA IEEE designators is 1 (binary format).
      401 +                 * Association 0 means this designator is for a Logical Unit.
      402 +                 * Association 2 means this designator is for a SCSI device
      403 +                 * that contains the Logical Unit.
      404 +                 * With the ASSOCIATION field set to 0 or 2, device shall
      405 +                 * return the same descriptor when it is accessed through any
      406 +                 * other I_T nexus. See SPC4 7.8.6.1
      407 +                 */
      408 +                if (cur_desc->len == 0x08 && cur_desc->id_type == 0x3 &&
      409 +                    cur_desc->code_set == 0x1 &&
      410 +                    (cur_desc->association == 0x0 ||
      411 +                     cur_desc->association == 0x2)) {
      412 +                        /* get to the data - skip the descriptor header */
      413 +                        cur_desc = (struct vpd_desc *)(((uint8_t *)cur_desc) +
      414 +                            sizeof (struct vpd_desc));
      415 +
      416 +                        /*
      417 +                         * Bits 7-4 of the NAA formatted designator hold
      418 +                         * the designator type. We're only interested
      419 +                         * in designator type 0x5 - a 64bit value
      420 +                         * (including this type filed) that represents a
      421 +                         * NAA IEEE Registered designator that we use as
      422 +                         * the LID.
      423 +                         * See SPC4 "NAA designator format" section.
      424 +                         */
      425 +                        if (((*((uint8_t *)cur_desc)) & 0x50) != 0x50) {
      426 +                                /*
      427 +                                 * This is not an IEEE Registered NAA
      428 +                                 * designator, point cur_desc back to the
      429 +                                 * header and skip this designator.
      430 +                                 */
      431 +                                cur_desc = (struct vpd_desc * )
      432 +                                    (((uint8_t *)cur_desc) -
      433 +                                    sizeof (struct vpd_desc));
      434 +                                continue;
      435 +                        }
      436 +
      437 +                        /* byte swap to have LID match what libses displays */
      438 +                        if (snprintf(lid, sizeof (lid), "%llx",
      439 +                                    BE_IN64(cur_desc)) < 0)
      440 +                                return (libscsi_set_errno(hp, ESCSI_UNKNOWN));
      441 +
      442 +                        if ((tp->lst_lid = libscsi_process_inquiry_string(hp,
      443 +                            lid, sizeof (lid))) == NULL)
      444 +                                return (libscsi_set_errno(hp, ESCSI_NOMEM));
      445 +
      446 +                        return (0);
      447 +                }
      448 +        }
      449 +
      450 +        return (libscsi_set_errno(hp, ESCSI_NOTSUP));
      451 +}
      452 +
      453 +/*
      454 + * Execute inquiry for VPD page 0x80 (unit serial #) and extract the USN
      455 + */
      456 +int
      457 +libscsi_get_inquiry_usn(libscsi_hdl_t *hp, libscsi_target_t *tp)
      458 +{
      459 +        libscsi_action_t *ap;
      460 +        spc3_inquiry_cdb_t *cp;
      461 +        spc3_usn_vpd_page_impl_t data;
      462 +        size_t len;
      463 +
      464 +        if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY,
      465 +            LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data,
      466 +            sizeof (spc3_usn_vpd_page_impl_t))) == NULL)
      467 +                return (libscsi_set_errno(hp, ESCSI_NOMEM));
      468 +
      469 +        cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap);
      470 +        cp->ic_evpd = 1; /* return vital product data for bellow page code */
      471 +        cp->ic_page_code = USN_VPD_PAGE_CODE;
      472 +        SCSI_WRITE16(&cp->ic_allocation_length,
      473 +            sizeof (spc3_usn_vpd_page_impl_t));
      474 +
      475 +        if (libscsi_exec(ap, tp) != 0 ||
      476 +            libscsi_action_get_status(ap) != 0) {
      477 +                libscsi_action_free(ap);
      478 +                return (libscsi_set_errno(hp, ESCSI_IO));
      479 +        }
      480 +
      481 +        (void) libscsi_action_get_buffer(ap, NULL, NULL, &len);
      482 +        libscsi_action_free(ap);
      483 +
      484 +        /* make sure we at least got the header */
      485 +        if (len < offsetof(spc3_usn_vpd_page_impl_t, uvpi_usn[0]))
      486 +                return (libscsi_set_errno(hp, ESCSI_BADLENGTH));
      487 +
      488 +        /* make sure we got the page we asked for */
      489 +        if (data.uvpi_hdr.page_code != USN_VPD_PAGE_CODE)
      490 +                return (libscsi_set_errno(hp, ESCSI_IO));
      491 +
      492 +        /* check for USN truncation */
      493 +        len = ((data.uvpi_hdr.page_len)[0] << 8 | (data.uvpi_hdr.page_len)[1]);
      494 +        if (len == 0 || len > sizeof (data.uvpi_usn))
      495 +                return (libscsi_set_errno(hp, ESCSI_BADLENGTH));
      496 +
      497 +        /* USN is ASCII encoded */
      498 +        if ((tp->lst_usn = libscsi_process_inquiry_string(hp,
      499 +            (char *)data.uvpi_usn, len)) == NULL)
      500 +            return (libscsi_set_errno(hp, ESCSI_NOMEM));
      501 +
      502 +        return (0);
      503 +}
      504 +
 333  505  const char *
 334  506  libscsi_vendor(libscsi_target_t *tp)
 335  507  {
 336  508          return (tp->lst_vendor);
 337  509  }
 338  510  
 339  511  const char *
 340  512  libscsi_product(libscsi_target_t *tp)
 341  513  {
 342  514          return (tp->lst_product);
 343  515  }
 344  516  
 345  517  const char *
 346  518  libscsi_revision(libscsi_target_t *tp)
 347  519  {
 348  520          return (tp->lst_revision);
      521 +}
      522 +
      523 +const char *
      524 +libscsi_lid(libscsi_target_t *tp)
      525 +{
      526 +        return (tp->lst_lid);
      527 +}
      528 +
      529 +const char *
      530 +libscsi_usn(libscsi_target_t *tp)
      531 +{
      532 +        return (tp->lst_usn);
 349  533  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX