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 2017 Nexenta Systems, Inc. All rights reserved.
14 */
15
16 #include <libnvpair.h>
17 #include <scsi/libses.h>
18 #include <scsi/libses_plugin.h>
19 #include <scsi/plugins/ses/framework/ses2_impl.h>
20
21 /*
22 * This is a plugin for Dell's MD3060e JBOD. It updates libses'
23 * ses-description field to indicate drawer and slot numbers,
24 * and overrides the bay number if the invalid bit is set for the
25 * AES descriptor.
26 */
27
28 /*
29 * Override bay number if the invalid bit is set for the AES descriptor.
30 * This is modeled after the LENOVO-D1224J12ESM3P plugin.
31 */
32 static int
33 dell_fix_bay(ses_plugin_t *sp, ses_node_t *np)
34 {
35 ses2_aes_descr_eip_impl_t *dep;
36 ses2_aes_descr_sas0_eip_impl_t *s0ep;
37 size_t len;
38 int nverr;
39 nvlist_t *props = ses_node_props(np);
40
41 /*
42 * The spec conveniently defines the bay number as part of the
43 * additional element status descriptor. However, the AES descriptor
44 * is technically only valid if the device is inserted.
45 * Thankfully, the Dell enclosure defines this value even if
46 * the invalid bit is set, so we override bay value, even for empty
47 * bays.
48 */
49 if ((dep = ses_plugin_page_lookup(sp, ses_node_snapshot(np),
50 SES2_DIAGPAGE_ADDL_ELEM_STATUS, np, &len)) == NULL)
51 return (0);
52
53 if (dep->sadei_protocol_identifier != SPC4_PROTO_SAS ||
54 !dep->sadei_eip || !dep->sadei_invalid)
55 return (0);
56
57 s0ep = (ses2_aes_descr_sas0_eip_impl_t *)dep->sadei_protocol_specific;
58
59 SES_NV_ADD(uint64, nverr, props, SES_PROP_BAY_NUMBER,
60 s0ep->sadsi_bay_number);
61
62 return (0);
63 }
64
65 /*
66 * This updates libses ses-description field for Dell's MD3060e JBOD.
67 * This JBOD is special because it has a physical label attached to it
68 * which splits the slot numbering into 5 drawers, each having slots 0-11.
69 * The description and slot numbering we get from the JBOD has slots
70 * numbered 1-60. We map these 1-60 description "SLOT # " strings
71 * into "Drawer X, Slot Y. ( Global SLOT # )" strings.
72 */
73
74 /*ARGSUSED*/
75 static int
76 dell_parse_node(ses_plugin_t *sp, ses_node_t *np)
77 {
78 uint64_t type, bay;
79 int nverr, rc;
80 nvlist_t *props;
81 char *descr, buf[SES2_MIN_DIAGPAGE_ALLOC];
82 int drawer, drawer_slot;
83
84 if (ses_node_type(np) != SES_NODE_ELEMENT)
85 return (0);
86
87 props = ses_node_props(np);
88 VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, &type) == 0);
89 if (type != SES_ET_ARRAY_DEVICE && type != SES_ET_DEVICE)
90 return (0);
91
92 if ((rc = dell_fix_bay(sp, np)) != 0)
93 return (rc);
94
95 /* bay will range 1-60 */
96 if (nvlist_lookup_uint64(props, SES_PROP_BAY_NUMBER, &bay) != 0)
97 return (0);
98
99 /* description strings will have something like "SLOT ## " */
100 if (nvlist_lookup_string(props, SES_PROP_DESCRIPTION, &descr) != 0)
101 return (0);
102
103 /*
104 * there are 12 slots per drawer; we want drawer numering to
105 * start with 1 and drawer slot numbering to start at 0
106 */
107 drawer = ((bay - 1) / 12) + 1;
108 drawer_slot = (bay - (drawer - 1) * 12) - 1;
109
110 /* modify the descrition to include drawer and a slot within drawer */
111 buf[SES2_MIN_DIAGPAGE_ALLOC - 1] = '\0';
112 if (snprintf(buf, SES2_MIN_DIAGPAGE_ALLOC - 1,
113 "Drawer %d, Slot %d. ( Global %s)", drawer, drawer_slot, descr) < 0)
114 return (0);
115
116 /* replace the ses-description field with the string we created above */
117 SES_NV_ADD(string, nverr, props, SES_PROP_DESCRIPTION, buf);
118
119 return (0);
120 }
121
122 int
123 _ses_init(ses_plugin_t *sp)
124 {
125 ses_plugin_config_t config = {
126 .spc_node_parse = dell_parse_node
127 };
128
129 return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION, &config) != 0);
130 }