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 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <libipmi.h>
28 #include <stddef.h>
29 
30 #include "ipmi_impl.h"
31 
32 #define	IPMI_CMD_SUNOEM_LED_GET		0x21
33 #define	IPMI_CMD_SUNOEM_LED_SET		0x22
34 
35 typedef struct ipmi_cmd_sunoem_led_set {
36 	DECL_BITFIELD2(
37 	    ic_sls_channel_msb		:1,	/* device slave address */
38 	    ic_sls_slaveaddr		:7);	/* (from SDR record) */
39 	uint8_t		ic_sls_type;		/* led type */
40 	DECL_BITFIELD2(
41 	    __reserved			:1,	/* device access address */
42 	    ic_sls_accessaddr		:7);	/* (from SDR record */
43 	uint8_t		ic_sls_hwinfo;		/* OEM hardware info */
44 	uint8_t		ic_sls_mode;		/* LED mode */
45 	uint8_t		ic_sls_eid;		/* entity ID */
46 	uint8_t		ic_sls_einst;		/* entity instance */
47 	uint8_t		ic_sls_force;		/* force direct access */
48 	uint8_t		ic_sls_role;		/* BMC authorization */
49 } ipmi_cmd_sunoem_led_set_t;
50 
51 typedef struct ipmi_cmd_sunoem_led_get {
52 	DECL_BITFIELD2(
53 	    ic_slg_channel_msb		:1,	/* device slave address */
54 	    ic_slg_slaveaddr		:7);	/* (from SDR record) */
55 	uint8_t		ic_slg_type;		/* led type */
56 	DECL_BITFIELD2(
57 	    __reserved			:1,	/* device access address */
58 	    ic_slg_accessaddr		:7);	/* (from SDR record */
59 	uint8_t		ic_slg_hwinfo;		/* OEM hardware info */
60 	uint8_t		ic_slg_eid;		/* entity ID */
61 	uint8_t		ic_slg_einst;		/* entity instance */
62 	uint8_t		ic_slg_force;		/* force direct access */
63 } ipmi_cmd_sunoem_led_get_t;
64 
65 #define	IPMI_SUNOEM_LED_TYPE_OK2RM	0
66 #define	IPMI_SUNOEM_LED_TYPE_SERVICE	1
67 #define	IPMI_SUNOEM_LED_TYPE_ACT	2
68 #define	IPMI_SUNOEM_LED_TYPE_LOCATE	3
69 #define	IPMI_SUNOEM_LED_TYPE_ANY	0xFF
70 
71 boolean_t
ipmi_is_sun_ilom(ipmi_deviceid_t * dp)72 ipmi_is_sun_ilom(ipmi_deviceid_t *dp)
73 {
74 	return (ipmi_devid_manufacturer(dp) == IPMI_OEM_SUN &&
75 	    ipmi_devid_product(dp) == IPMI_PROD_SUN_ILOM);
76 }
77 
78 static int
check_sunoem(ipmi_handle_t * ihp)79 check_sunoem(ipmi_handle_t *ihp)
80 {
81 	ipmi_deviceid_t *devid;
82 
83 	if ((devid = ipmi_get_deviceid(ihp)) == NULL)
84 		return (-1);
85 
86 	if (!ipmi_is_sun_ilom(devid))
87 		return (ipmi_set_error(ihp, EIPMI_INVALID_COMMAND, NULL));
88 
89 	return (0);
90 }
91 
92 static int
ipmi_send_sunoem_led_set(ipmi_handle_t * ihp,ipmi_cmd_sunoem_led_set_t * req)93 ipmi_send_sunoem_led_set(ipmi_handle_t *ihp, ipmi_cmd_sunoem_led_set_t *req)
94 {
95 	ipmi_cmd_t cmd, *resp;
96 
97 	cmd.ic_netfn = IPMI_NETFN_OEM;
98 	cmd.ic_cmd = IPMI_CMD_SUNOEM_LED_SET;
99 	cmd.ic_lun = 0;
100 	cmd.ic_data = req;
101 	cmd.ic_dlen = sizeof (*req);
102 
103 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
104 		return (-1);
105 
106 	if (resp->ic_dlen != 0)
107 		return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
108 
109 	return (0);
110 }
111 
112 static int
ipmi_send_sunoem_led_get(ipmi_handle_t * ihp,ipmi_cmd_sunoem_led_get_t * req,uint8_t * result)113 ipmi_send_sunoem_led_get(ipmi_handle_t *ihp, ipmi_cmd_sunoem_led_get_t *req,
114     uint8_t *result)
115 {
116 	ipmi_cmd_t cmd, *resp;
117 
118 	cmd.ic_netfn = IPMI_NETFN_OEM;
119 	cmd.ic_cmd = IPMI_CMD_SUNOEM_LED_GET;
120 	cmd.ic_lun = 0;
121 	cmd.ic_data = req;
122 	cmd.ic_dlen = sizeof (*req);
123 
124 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
125 		return (-1);
126 
127 	if (resp->ic_dlen != 1)
128 		return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
129 
130 	*result = *((uint8_t *)resp->ic_data);
131 	return (0);
132 }
133 
134 int
ipmi_sunoem_led_set(ipmi_handle_t * ihp,ipmi_sdr_generic_locator_t * dev,uint8_t mode)135 ipmi_sunoem_led_set(ipmi_handle_t *ihp, ipmi_sdr_generic_locator_t *dev,
136     uint8_t mode)
137 {
138 	ipmi_cmd_sunoem_led_set_t cmd = { 0 };
139 
140 	if (check_sunoem(ihp) != 0)
141 		return (-1);
142 
143 	cmd.ic_sls_slaveaddr = dev->is_gl_slaveaddr;
144 	cmd.ic_sls_channel_msb = dev->is_gl_channel_msb;
145 	cmd.ic_sls_type = dev->is_gl_oem;
146 	cmd.ic_sls_accessaddr = dev->is_gl_accessaddr;
147 	cmd.ic_sls_hwinfo = dev->is_gl_oem;
148 	cmd.ic_sls_mode = mode;
149 	cmd.ic_sls_eid = dev->is_gl_entity;
150 	cmd.ic_sls_einst = dev->is_gl_instance;
151 
152 	return (ipmi_send_sunoem_led_set(ihp, &cmd));
153 }
154 
155 int
ipmi_sunoem_led_get(ipmi_handle_t * ihp,ipmi_sdr_generic_locator_t * dev,uint8_t * mode)156 ipmi_sunoem_led_get(ipmi_handle_t *ihp, ipmi_sdr_generic_locator_t *dev,
157     uint8_t *mode)
158 {
159 	ipmi_cmd_sunoem_led_get_t cmd = { 0 };
160 
161 	if (check_sunoem(ihp) != 0)
162 		return (-1);
163 
164 	cmd.ic_slg_slaveaddr = dev->is_gl_slaveaddr;
165 	cmd.ic_slg_channel_msb = dev->is_gl_channel_msb;
166 	cmd.ic_slg_type = dev->is_gl_oem;
167 	cmd.ic_slg_accessaddr = dev->is_gl_accessaddr;
168 	cmd.ic_slg_hwinfo = dev->is_gl_oem;
169 	cmd.ic_slg_eid = dev->is_gl_entity;
170 	cmd.ic_slg_einst = dev->is_gl_instance;
171 
172 	return (ipmi_send_sunoem_led_get(ihp, &cmd, mode));
173 }
174 
175 int
ipmi_sunoem_uptime(ipmi_handle_t * ihp,uint32_t * uptime,uint32_t * gen)176 ipmi_sunoem_uptime(ipmi_handle_t *ihp, uint32_t *uptime, uint32_t *gen)
177 {
178 	ipmi_cmd_t cmd, *resp;
179 	uint8_t unused;
180 
181 	if (check_sunoem(ihp) != 0)
182 		return (-1);
183 
184 	cmd.ic_netfn = IPMI_NETFN_OEM;
185 	cmd.ic_lun = 0;
186 	cmd.ic_cmd = IPMI_CMD_SUNOEM_UPTIME;
187 	cmd.ic_dlen = sizeof (unused);
188 	cmd.ic_data = &unused;
189 
190 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
191 		return (-1);
192 
193 	if (resp->ic_dlen != 2 * sizeof (uint32_t))
194 		return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
195 
196 	if (uptime)
197 		*uptime = BE_IN32(&((uint32_t *)resp->ic_data)[0]);
198 	if (gen)
199 		*gen = BE_IN32(&((uint32_t *)resp->ic_data)[1]);
200 
201 	return (0);
202 }
203 
204 int
ipmi_sunoem_update_fru(ipmi_handle_t * ihp,ipmi_sunoem_fru_t * req)205 ipmi_sunoem_update_fru(ipmi_handle_t *ihp, ipmi_sunoem_fru_t *req)
206 {
207 	ipmi_cmd_t cmd, *resp;
208 
209 	if (check_sunoem(ihp) != 0)
210 		return (-1);
211 
212 	switch (req->isf_type) {
213 	case IPMI_SUNOEM_FRU_DIMM:
214 		req->isf_datalen = sizeof (req->isf_data.dimm);
215 		break;
216 
217 	case IPMI_SUNOEM_FRU_CPU:
218 		req->isf_datalen = sizeof (req->isf_data.cpu);
219 		break;
220 
221 	case IPMI_SUNOEM_FRU_BIOS:
222 		req->isf_datalen = sizeof (req->isf_data.bios);
223 		break;
224 
225 	case IPMI_SUNOEM_FRU_DISK:
226 		req->isf_datalen = sizeof (req->isf_data.disk);
227 		break;
228 	}
229 
230 	cmd.ic_netfn = IPMI_NETFN_OEM;
231 	cmd.ic_cmd = IPMI_CMD_SUNOEM_FRU_UPDATE;
232 	cmd.ic_lun = 0;
233 	cmd.ic_dlen = offsetof(ipmi_sunoem_fru_t, isf_data) +
234 	    req->isf_datalen;
235 	cmd.ic_data = req;
236 
237 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
238 		return (-1);
239 
240 	if (resp->ic_dlen != 0)
241 		return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
242 
243 	return (0);
244 }
245