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