1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 #include <scsi/libses.h>
  17 #include <scsi/plugins/ses/framework/ses2_impl.h>
  18 
  19 /*
  20  * Override bay number if the invalid bit is set for the AES descriptor
  21  */
  22 static int
  23 lenovo_d12_fix_bay(ses_plugin_t *sp, ses_node_t *np)
  24 {
  25         ses2_aes_descr_eip_impl_t *dep;
  26         ses2_aes_descr_sas0_eip_impl_t *s0ep;
  27         size_t len;
  28         int nverr;
  29         nvlist_t *props = ses_node_props(np);
  30 
  31         /*
  32          * The spec conveniently defines the bay number as part of the
  33          * additional element status descriptor. However, the AES descriptor
  34          * is technically only valid if the device is inserted.
  35          * Thankfully, the Lenovo enclosure defines this value even if
  36          * the invalid bit is set, so we override bay value, even for empty
  37          * bays.
  38          */
  39         if ((dep = ses_plugin_page_lookup(sp, ses_node_snapshot(np),
  40             SES2_DIAGPAGE_ADDL_ELEM_STATUS, np, &len)) == NULL)
  41                 return (0);
  42 
  43         if (dep->sadei_protocol_identifier != SPC4_PROTO_SAS ||
  44             !dep->sadei_eip || !dep->sadei_invalid)
  45                 return (0);
  46 
  47         s0ep = (ses2_aes_descr_sas0_eip_impl_t *)dep->sadei_protocol_specific;
  48 
  49         SES_NV_ADD(uint64, nverr, props, SES_PROP_BAY_NUMBER,
  50             s0ep->sadsi_bay_number);
  51 
  52         return (0);
  53 }
  54 
  55 /*
  56  * Lenovo specific ses node parsing is needed to get bay numbers from empty bays
  57  */
  58 static int
  59 lenovo_d12_parse_node(ses_plugin_t *sp, ses_node_t *np)
  60 {
  61         uint64_t type;
  62         nvlist_t *props;
  63 
  64         if (ses_node_type(np) != SES_NODE_ELEMENT)
  65                 return (0);
  66 
  67         props = ses_node_props(np);
  68         type = fnvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE);
  69         if (type != SES_ET_ARRAY_DEVICE)
  70                 return (0);
  71 
  72         return (lenovo_d12_fix_bay(sp, np));
  73 }
  74 
  75 int
  76 _ses_init(ses_plugin_t *sp)
  77 {
  78         ses_plugin_config_t config = {
  79                 .spc_node_parse = lenovo_d12_parse_node
  80         };
  81 
  82         return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION, &config) != 0);
  83 }