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 }