1a6e6969cSeschrock /*
2a6e6969cSeschrock * CDDL HEADER START
3a6e6969cSeschrock *
4a6e6969cSeschrock * The contents of this file are subject to the terms of the
5a6e6969cSeschrock * Common Development and Distribution License (the "License").
6a6e6969cSeschrock * You may not use this file except in compliance with the License.
7a6e6969cSeschrock *
8a6e6969cSeschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a6e6969cSeschrock * or http://www.opensolaris.org/os/licensing.
10a6e6969cSeschrock * See the License for the specific language governing permissions
11a6e6969cSeschrock * and limitations under the License.
12a6e6969cSeschrock *
13a6e6969cSeschrock * When distributing Covered Code, include this CDDL HEADER in each
14a6e6969cSeschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a6e6969cSeschrock * If applicable, add the following below this CDDL HEADER, with the
16a6e6969cSeschrock * fields enclosed by brackets "[]" replaced with your own identifying
17a6e6969cSeschrock * information: Portions Copyright [yyyy] [name of copyright owner]
18a6e6969cSeschrock *
19a6e6969cSeschrock * CDDL HEADER END
20a6e6969cSeschrock */
21a6e6969cSeschrock
22a6e6969cSeschrock /*
23a6e6969cSeschrock * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24a6e6969cSeschrock * Use is subject to license terms.
25a6e6969cSeschrock */
26a6e6969cSeschrock
27a6e6969cSeschrock #include <string.h>
28a6e6969cSeschrock #include <strings.h>
29a6e6969cSeschrock
30a6e6969cSeschrock #include <scsi/libses.h>
31a6e6969cSeschrock #include <scsi/libses_plugin.h>
32a6e6969cSeschrock
33a6e6969cSeschrock #include <scsi/plugins/ses/framework/ses2_impl.h>
34a6e6969cSeschrock
35a6e6969cSeschrock static int
sun_loki_fix_bay(ses_plugin_t * sp,ses_node_t * np)36a6e6969cSeschrock sun_loki_fix_bay(ses_plugin_t *sp, ses_node_t *np)
37a6e6969cSeschrock {
38a6e6969cSeschrock ses2_aes_descr_eip_impl_t *dep;
39a6e6969cSeschrock ses2_aes_descr_sas0_eip_impl_t *s0ep;
40a6e6969cSeschrock size_t len;
41a6e6969cSeschrock int nverr;
42a6e6969cSeschrock nvlist_t *props = ses_node_props(np);
43a6e6969cSeschrock
44a6e6969cSeschrock /*
45a6e6969cSeschrock * The spec conveniently defines the bay number as part of the
46a6e6969cSeschrock * additional element status descriptor. However, the AES descriptor
47a6e6969cSeschrock * is technically only valid if the device is inserted. This is a
48a6e6969cSeschrock * problem for loki because the bay numbers don't match the element
49a6e6969cSeschrock * class index, so when a device is removed we have no way of knowing
50a6e6969cSeschrock * *which* bay is empty. Thankfully, loki defines this value even if
51a6e6969cSeschrock * the invalid bit is set, so we override this value, even for empty
52a6e6969cSeschrock * bays.
53a6e6969cSeschrock */
54a6e6969cSeschrock if ((dep = ses_plugin_page_lookup(sp, ses_node_snapshot(np),
55a6e6969cSeschrock SES2_DIAGPAGE_ADDL_ELEM_STATUS, np, &len)) == NULL)
56a6e6969cSeschrock return (0);
57a6e6969cSeschrock
58a6e6969cSeschrock if (dep->sadei_protocol_identifier != SPC4_PROTO_SAS ||
59a6e6969cSeschrock !dep->sadei_eip || !dep->sadei_invalid)
60a6e6969cSeschrock return (0);
61a6e6969cSeschrock
62a6e6969cSeschrock s0ep = (ses2_aes_descr_sas0_eip_impl_t *)dep->sadei_protocol_specific;
63a6e6969cSeschrock
64a6e6969cSeschrock SES_NV_ADD(uint64, nverr, props, SES_PROP_BAY_NUMBER,
65a6e6969cSeschrock s0ep->sadsi_bay_number);
66a6e6969cSeschrock
67a6e6969cSeschrock return (0);
68a6e6969cSeschrock }
69a6e6969cSeschrock
70a6e6969cSeschrock static int
sun_loki_parse_node(ses_plugin_t * sp,ses_node_t * np)71a6e6969cSeschrock sun_loki_parse_node(ses_plugin_t *sp, ses_node_t *np)
72a6e6969cSeschrock {
73a6e6969cSeschrock ses_node_t *encp;
74a6e6969cSeschrock nvlist_t *props = ses_node_props(np);
75a6e6969cSeschrock nvlist_t *encprops;
76a6e6969cSeschrock uint8_t *stringin;
77a6e6969cSeschrock uint_t len;
78a6e6969cSeschrock nvlist_t *lid;
79a6e6969cSeschrock int nverr;
80a6e6969cSeschrock char serial[17];
81a6e6969cSeschrock uint8_t fieldlen;
82a6e6969cSeschrock char *field;
83a6e6969cSeschrock uint64_t wwn;
84a6e6969cSeschrock uint64_t type, index;
85a6e6969cSeschrock int i;
86a6e6969cSeschrock
87a6e6969cSeschrock if (ses_node_type(np) != SES_NODE_ENCLOSURE &&
88a6e6969cSeschrock ses_node_type(np) != SES_NODE_ELEMENT)
89a6e6969cSeschrock return (0);
90a6e6969cSeschrock
91a6e6969cSeschrock if (ses_node_type(np) == SES_NODE_ELEMENT) {
92a6e6969cSeschrock VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE,
93a6e6969cSeschrock &type) == 0);
94a6e6969cSeschrock
95a6e6969cSeschrock if (type == SES_ET_ARRAY_DEVICE)
96a6e6969cSeschrock return (sun_loki_fix_bay(sp, np));
97a6e6969cSeschrock
98a6e6969cSeschrock if (type != SES_ET_COOLING &&
99a6e6969cSeschrock type != SES_ET_POWER_SUPPLY)
100a6e6969cSeschrock return (0);
101a6e6969cSeschrock
102a6e6969cSeschrock VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_CLASS_INDEX,
103a6e6969cSeschrock &index) == 0);
104a6e6969cSeschrock }
105a6e6969cSeschrock
106a6e6969cSeschrock /*
107a6e6969cSeschrock * Find the containing enclosure node and extract the STRING IN
108a6e6969cSeschrock * information.
109a6e6969cSeschrock */
110a6e6969cSeschrock for (encp = np; ses_node_type(encp) != SES_NODE_ENCLOSURE;
111a6e6969cSeschrock encp = ses_node_parent(encp))
112a6e6969cSeschrock ;
113a6e6969cSeschrock
114a6e6969cSeschrock encprops = ses_node_props(encp);
115a6e6969cSeschrock if (nvlist_lookup_byte_array(encprops, SES_EN_PROP_STRING,
116*bf82a41bSeschrock &stringin, &len) != 0 || len < 4)
117a6e6969cSeschrock return (0);
118a6e6969cSeschrock
119a6e6969cSeschrock /*
120a6e6969cSeschrock * If this is an enclosure, then calculate the chassis WWN by masking
121a6e6969cSeschrock * off the bottom 8 bits of the WWN.
122a6e6969cSeschrock */
123a6e6969cSeschrock if (ses_node_type(np) == SES_NODE_ENCLOSURE) {
124a6e6969cSeschrock VERIFY(nvlist_lookup_nvlist(props, SES_EN_PROP_LID, &lid) == 0);
125a6e6969cSeschrock VERIFY(nvlist_lookup_uint64(lid, SPC3_NAA_INT, &wwn) == 0);
126a6e6969cSeschrock (void) snprintf(serial, sizeof (serial), "%llx",
127a6e6969cSeschrock wwn & ~0xFFULL);
128a6e6969cSeschrock SES_NV_ADD(string, nverr, props, LIBSES_EN_PROP_CSN, serial);
129a6e6969cSeschrock }
130a6e6969cSeschrock
131a6e6969cSeschrock /*
132a6e6969cSeschrock * The STRING IN data is organized into a series of variable-length
133a6e6969cSeschrock * fields, where each field can be either a key ("Fan PartNUM") or a
134a6e6969cSeschrock * value. If the field length is less than our shortest expected
135a6e6969cSeschrock * identifier, then something has gone awry and we assume that the data
136a6e6969cSeschrock * is corrupt.
137a6e6969cSeschrock */
138*bf82a41bSeschrock fieldlen = stringin[3];
139a6e6969cSeschrock if (fieldlen < 11)
140a6e6969cSeschrock return (0);
141a6e6969cSeschrock
142*bf82a41bSeschrock for (field = (char *)stringin + 4;
143a6e6969cSeschrock field + fieldlen <= (char *)stringin + len; field += fieldlen) {
144*bf82a41bSeschrock if (strncmp(field, "Storage J4500", 13) == 0) {
145a6e6969cSeschrock /*
146a6e6969cSeschrock * This is the part number for the enclosure itself.
147a6e6969cSeschrock */
148a6e6969cSeschrock if (ses_node_type(np) != SES_NODE_ENCLOSURE)
149a6e6969cSeschrock continue;
150a6e6969cSeschrock
151a6e6969cSeschrock field += fieldlen;
152a6e6969cSeschrock if (field + fieldlen > (char *)stringin + len)
153a6e6969cSeschrock break;
154a6e6969cSeschrock
155a6e6969cSeschrock if (ses_node_type(np) == SES_NODE_ENCLOSURE) {
156a6e6969cSeschrock SES_NV_ADD(fixed_string_trunc, nverr, props,
157a6e6969cSeschrock LIBSES_PROP_PART, field, fieldlen);
158a6e6969cSeschrock return (0);
159a6e6969cSeschrock }
160a6e6969cSeschrock
161a6e6969cSeschrock } else if (strncmp(field, "Fan PartNUM", 11) == 0) {
162a6e6969cSeschrock /*
163a6e6969cSeschrock * Part numbers for the fans, of which there are 5.
164a6e6969cSeschrock */
165a6e6969cSeschrock if (ses_node_type(np) != SES_NODE_ELEMENT ||
166*bf82a41bSeschrock type != SES_ET_COOLING) {
167*bf82a41bSeschrock field += fieldlen * 5;
168a6e6969cSeschrock continue;
169*bf82a41bSeschrock }
170a6e6969cSeschrock
171a6e6969cSeschrock field += fieldlen;
172a6e6969cSeschrock
173a6e6969cSeschrock for (i = 0; i < 5 &&
174a6e6969cSeschrock field + fieldlen <= (char *)stringin + len;
175*bf82a41bSeschrock i++, field += fieldlen) {
176a6e6969cSeschrock if (index == i &&
177a6e6969cSeschrock strncmp(field, "Unknown", 7) != 0 &&
178a6e6969cSeschrock strncmp(field, "Not Installed", 13) != 0) {
179a6e6969cSeschrock SES_NV_ADD(fixed_string_trunc, nverr,
180a6e6969cSeschrock props, LIBSES_PROP_PART,
181a6e6969cSeschrock field, fieldlen);
182a6e6969cSeschrock return (0);
183a6e6969cSeschrock }
184a6e6969cSeschrock }
185a6e6969cSeschrock
186a6e6969cSeschrock } else if (strncmp(field, "PS PartNUM", 10) == 0) {
187a6e6969cSeschrock /*
188a6e6969cSeschrock * Part numbers for the power supplies, of which there
189a6e6969cSeschrock * are 2.
190a6e6969cSeschrock */
191a6e6969cSeschrock if (ses_node_type(np) != SES_NODE_ELEMENT ||
192*bf82a41bSeschrock type != SES_ET_POWER_SUPPLY) {
193*bf82a41bSeschrock field += fieldlen * 2;
194a6e6969cSeschrock continue;
195*bf82a41bSeschrock }
196a6e6969cSeschrock
197a6e6969cSeschrock field += fieldlen;
198a6e6969cSeschrock
199a6e6969cSeschrock for (i = 0; i < 2 &&
200a6e6969cSeschrock field + fieldlen <= (char *)stringin + len;
201*bf82a41bSeschrock i++, field += fieldlen) {
202a6e6969cSeschrock if (index == i &&
203a6e6969cSeschrock strncmp(field, "Unknown", 7) != 0 &&
204a6e6969cSeschrock strncmp(field, "Not Installed", 13) != 0) {
205a6e6969cSeschrock SES_NV_ADD(fixed_string_trunc, nverr,
206a6e6969cSeschrock props, LIBSES_PROP_PART,
207a6e6969cSeschrock field, fieldlen);
208a6e6969cSeschrock return (0);
209a6e6969cSeschrock }
210a6e6969cSeschrock }
211a6e6969cSeschrock }
212a6e6969cSeschrock }
213a6e6969cSeschrock
214a6e6969cSeschrock return (0);
215a6e6969cSeschrock }
216a6e6969cSeschrock
217a6e6969cSeschrock int
_ses_init(ses_plugin_t * sp)218a6e6969cSeschrock _ses_init(ses_plugin_t *sp)
219a6e6969cSeschrock {
220a6e6969cSeschrock ses_plugin_config_t config = {
221a6e6969cSeschrock .spc_node_parse = sun_loki_parse_node
222a6e6969cSeschrock };
223a6e6969cSeschrock
224a6e6969cSeschrock return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION,
225a6e6969cSeschrock &config) != 0);
226a6e6969cSeschrock }
227