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>


   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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.

  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/scsi/generic/commands.h>
  28 #include <sys/scsi/impl/spc3_types.h>
  29 
  30 #include <stddef.h>
  31 #include <stdlib.h>
  32 #include <string.h>
  33 #include <strings.h>
  34 #include <alloca.h>
  35 #include <stdio.h>
  36 #include <unistd.h>
  37 #include <dlfcn.h>
  38 
  39 #include <scsi/libscsi.h>

  40 #include "libscsi_impl.h"
  41 
  42 int
  43 libscsi_assert(const char *expr, const char *file, int line)
  44 {
  45         char *msg;
  46         size_t len;
  47 
  48         len = snprintf(NULL, 0,
  49             "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
  50 
  51         msg = alloca(len + 1);
  52 
  53         (void) snprintf(msg, len + 1,
  54             "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
  55 
  56         (void) write(STDERR_FILENO, msg, strlen(msg));
  57 
  58         abort();
  59         _exit(1);


 281         buf[len] = '\0';
 282 
 283         return (libscsi_strdup(hp, buf));
 284 }
 285 
 286 /*
 287  * As part of basic initialization, we always retrieve the INQUIRY information
 288  * to have the vendor/product/revision information available for all consumers.
 289  */
 290 int
 291 libscsi_get_inquiry(libscsi_hdl_t *hp, libscsi_target_t *tp)
 292 {
 293         libscsi_action_t *ap;
 294         spc3_inquiry_cdb_t *cp;
 295         spc3_inquiry_data_t data;
 296         size_t len;
 297 
 298         if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY,
 299             LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data,
 300             offsetof(spc3_inquiry_data_t, id_vs_36[0]))) == NULL)
 301                 return (-1);
 302 
 303         cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap);
 304 
 305         SCSI_WRITE16(&cp->ic_allocation_length,
 306             offsetof(spc3_inquiry_data_t, id_vs_36[0]));
 307 
 308         if (libscsi_exec(ap, tp) != 0 ||
 309             libscsi_action_get_status(ap) != 0) {
 310                 libscsi_action_free(ap);
 311                 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
 312         }
 313 
 314         (void) libscsi_action_get_buffer(ap, NULL, NULL, &len);
 315         libscsi_action_free(ap);
 316 
 317         if (len < offsetof(spc3_inquiry_data_t, id_vs_36))
 318                 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
 319 
 320         if ((tp->lst_vendor = libscsi_process_inquiry_string(hp,
 321             data.id_vendor_id, sizeof (data.id_vendor_id))) == NULL ||
 322             (tp->lst_product = libscsi_process_inquiry_string(hp,
 323             data.id_product_id, sizeof (data.id_product_id))) == NULL ||
 324             (tp->lst_revision = libscsi_process_inquiry_string(hp,
 325             data.id_product_revision,
 326             sizeof (data.id_product_revision))) == NULL) {
 327                 return (-1);
 328         }
 329 
 330         return (0);
 331 }
 332 










































































































































































 333 const char *
 334 libscsi_vendor(libscsi_target_t *tp)
 335 {
 336         return (tp->lst_vendor);
 337 }
 338 
 339 const char *
 340 libscsi_product(libscsi_target_t *tp)
 341 {
 342         return (tp->lst_product);
 343 }
 344 
 345 const char *
 346 libscsi_revision(libscsi_target_t *tp)
 347 {
 348         return (tp->lst_revision);












 349 }


   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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 #include <sys/types.h>
  28 #include <sys/scsi/generic/commands.h>
  29 #include <sys/scsi/impl/spc3_types.h>
  30 
  31 #include <stddef.h>
  32 #include <stdlib.h>
  33 #include <string.h>
  34 #include <strings.h>
  35 #include <alloca.h>
  36 #include <stdio.h>
  37 #include <unistd.h>
  38 #include <dlfcn.h>
  39 
  40 #include <scsi/libscsi.h>
  41 #include <sys/byteorder.h>
  42 #include "libscsi_impl.h"
  43 
  44 int
  45 libscsi_assert(const char *expr, const char *file, int line)
  46 {
  47         char *msg;
  48         size_t len;
  49 
  50         len = snprintf(NULL, 0,
  51             "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
  52 
  53         msg = alloca(len + 1);
  54 
  55         (void) snprintf(msg, len + 1,
  56             "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
  57 
  58         (void) write(STDERR_FILENO, msg, strlen(msg));
  59 
  60         abort();
  61         _exit(1);


 283         buf[len] = '\0';
 284 
 285         return (libscsi_strdup(hp, buf));
 286 }
 287 
 288 /*
 289  * As part of basic initialization, we always retrieve the INQUIRY information
 290  * to have the vendor/product/revision information available for all consumers.
 291  */
 292 int
 293 libscsi_get_inquiry(libscsi_hdl_t *hp, libscsi_target_t *tp)
 294 {
 295         libscsi_action_t *ap;
 296         spc3_inquiry_cdb_t *cp;
 297         spc3_inquiry_data_t data;
 298         size_t len;
 299 
 300         if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY,
 301             LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data,
 302             offsetof(spc3_inquiry_data_t, id_vs_36[0]))) == NULL)
 303                 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
 304 
 305         cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap);
 306 
 307         SCSI_WRITE16(&cp->ic_allocation_length,
 308             offsetof(spc3_inquiry_data_t, id_vs_36[0]));
 309 
 310         if (libscsi_exec(ap, tp) != 0 ||
 311             libscsi_action_get_status(ap) != 0) {
 312                 libscsi_action_free(ap);
 313                 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
 314         }
 315 
 316         (void) libscsi_action_get_buffer(ap, NULL, NULL, &len);
 317         libscsi_action_free(ap);
 318 
 319         if (len < offsetof(spc3_inquiry_data_t, id_vs_36))
 320                 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
 321 
 322         if ((tp->lst_vendor = libscsi_process_inquiry_string(hp,
 323             data.id_vendor_id, sizeof (data.id_vendor_id))) == NULL ||
 324             (tp->lst_product = libscsi_process_inquiry_string(hp,
 325             data.id_product_id, sizeof (data.id_product_id))) == NULL ||
 326             (tp->lst_revision = libscsi_process_inquiry_string(hp,
 327             data.id_product_revision,
 328             sizeof (data.id_product_revision))) == NULL) {
 329                 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
 330         }
 331 
 332         return (0);
 333 }
 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 
 505 const char *
 506 libscsi_vendor(libscsi_target_t *tp)
 507 {
 508         return (tp->lst_vendor);
 509 }
 510 
 511 const char *
 512 libscsi_product(libscsi_target_t *tp)
 513 {
 514         return (tp->lst_product);
 515 }
 516 
 517 const char *
 518 libscsi_revision(libscsi_target_t *tp)
 519 {
 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);
 533 }