1 /*
2  * CDDL HEADER START
3  *
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) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <sys/scsi/impl/spc3_types.h>
27 
28 #include <stddef.h>
29 #include <string.h>
30 #include <strings.h>
31 #include <libnvpair.h>
32 
33 #include <scsi/libses.h>
34 #include <scsi/libses_plugin.h>
35 #include <scsi/plugins/ses/framework/ses2.h>
36 #include <scsi/plugins/ses/framework/ses2_impl.h>
37 #include <scsi/plugins/ses/framework/libses.h>
38 #include <scsi/plugins/ses/vendor/sun.h>
39 #include <scsi/plugins/ses/vendor/sun_impl.h>
40 
41 /*ARGSUSED*/
42 static int
enc_parse_feature_block(ses_plugin_t * sp,ses_node_t * np)43 enc_parse_feature_block(ses_plugin_t *sp, ses_node_t *np)
44 {
45 	sun_feature_block_impl_t *sfbip;
46 	nvlist_t *encprops;
47 	uint8_t *vsp;
48 	uint_t vsp_len;
49 	uint_t cid_off, cid_len;
50 	uint16_t revision;
51 	uint64_t chunk;
52 	int nverr;
53 
54 	encprops = ses_node_props(np);
55 	if (nvlist_lookup_byte_array(encprops, SES_EN_PROP_VS,
56 	    &vsp, &vsp_len) != 0 ||
57 	    vsp_len < offsetof(sun_feature_block_impl_t, _reserved2))
58 		return (0);
59 
60 	sfbip = (sun_feature_block_impl_t *)vsp;
61 
62 	if (strncmp((char *)sfbip->sfbi_spms_header, "SPMS", 4) != 0 ||
63 	    sfbip->sfbi_spms_major_ver != 1)
64 		return (0);
65 
66 	revision = SCSI_READ16(&sfbip->sfbi_spms_revision);
67 
68 	/*
69 	 * The offset read from the Sun Feature Block needs to be adjusted
70 	 * so that the difference in the sizes of the Enclosure
71 	 * Descriptor and the INQUIRY data format is accounted for.
72 	 */
73 	cid_len = sfbip->sfbi_chassis_id_len;
74 
75 	if (sfbip->sfbi_chassis_id_off >= 96 && cid_len >= 4) {
76 		cid_off = sfbip->sfbi_chassis_id_off -
77 		    (sizeof (ses2_ed_impl_t) - 1);
78 		cid_off += offsetof(ses2_ed_impl_t, st_priv[0]) -
79 		    offsetof(spc3_inquiry_data_t, id_vs_36[0]);
80 
81 		if (cid_off + cid_len <= vsp_len) {
82 			SES_NV_ADD(fixed_string, nverr, encprops,
83 			    LIBSES_EN_PROP_CSN, (char *)(vsp + cid_off),
84 			    cid_len);
85 		}
86 	}
87 
88 	if (revision >= 104) {
89 		SES_NV_ADD(boolean_value, nverr, encprops,
90 		    LIBSES_EN_PROP_INTERNAL, sfbip->sfbi_int);
91 	}
92 
93 	if (revision >= 105) {
94 		if (sfbip->sfbi_fw_upload_max_chunk_sz == 0)
95 			chunk = 512;
96 		else if (sfbip->sfbi_fw_upload_max_chunk_sz == 0x7f)
97 			chunk = 65536;
98 		else
99 			chunk = 512 * sfbip->sfbi_fw_upload_max_chunk_sz;
100 
101 		SES_NV_ADD(uint64, nverr, encprops,
102 		    LIBSES_EN_PROP_FIRMWARE_CHUNK_SIZE, chunk);
103 	}
104 
105 	/*
106 	 * If this is a subchassis, it will have a subchassis index field
107 	 * with a value other than 0.  See SPMS-1r111 4.1.3.1.  If not, we
108 	 * will see 0 and will not create the subchassis member at all; note
109 	 * that this is backward-compatible with pre-111 implementations that
110 	 * treated this as a reserved field.  No such implementation contains
111 	 * a subchassis.
112 	 */
113 	if (sfbip->sfbi_spms_revision >= 111 &&
114 	    sfbip->sfbi_subchassis_index != 0) {
115 		SES_NV_ADD(uint64, nverr, encprops,
116 		    LIBSES_EN_PROP_SUBCHASSIS_ID,
117 		    sfbip->sfbi_subchassis_index - 1);
118 	}
119 
120 	return (0);
121 }
122 
123 int
sun_fill_enclosure_node(ses_plugin_t * sp,ses_node_t * np)124 sun_fill_enclosure_node(ses_plugin_t *sp, ses_node_t *np)
125 {
126 	ses_snap_t *snap = ses_node_snapshot(np);
127 	nvlist_t *props = ses_node_props(np);
128 	sun_fru_descr_impl_t *sfdi;
129 	int err;
130 	size_t len;
131 
132 	if ((err = enc_parse_feature_block(sp, np)) != 0)
133 		return (err);
134 
135 	if ((sfdi = ses_plugin_page_lookup(sp, snap,
136 	    SUN_DIAGPAGE_FRUID, np, &len)) != NULL) {
137 		if ((err = sun_fruid_parse_common(sfdi, props)) != 0)
138 			return (err);
139 	}
140 
141 	return (0);
142 }
143