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 2007 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 static int
70 check_sunoem(ipmi_handle_t *ihp)
71 {
72 	ipmi_deviceid_t *devid;
73 
74 	if ((devid = ipmi_get_deviceid(ihp)) == NULL)
75 		return (-1);
76 
77 	if (ipmi_devid_manufacturer(devid) != IPMI_OEM_SUN)
78 		return (ipmi_set_error(ihp, EIPMI_INVALID_COMMAND, NULL));
79 
80 	return (0);
81 }
82 
83 static int
84 ipmi_send_sunoem_led_set(ipmi_handle_t *ihp, ipmi_cmd_sunoem_led_set_t *req)
85 {
86 	ipmi_cmd_t cmd, *resp;
87 
88 	cmd.ic_netfn = IPMI_NETFN_OEM;
89 	cmd.ic_cmd = IPMI_CMD_SUNOEM_LED_SET;
90 	cmd.ic_lun = 0;
91 	cmd.ic_data = req;
92 	cmd.ic_dlen = sizeof (*req);
93 
94 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
95 		return (-1);
96 
97 	if (resp->ic_dlen != 0)
98 		return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
99 
100 	return (0);
101 }
102 
103 static int
104 ipmi_send_sunoem_led_get(ipmi_handle_t *ihp, ipmi_cmd_sunoem_led_get_t *req,
105     uint8_t *result)
106 {
107 	ipmi_cmd_t cmd, *resp;
108 
109 	cmd.ic_netfn = IPMI_NETFN_OEM;
110 	cmd.ic_cmd = IPMI_CMD_SUNOEM_LED_GET;
111 	cmd.ic_lun = 0;
112 	cmd.ic_data = req;
113 	cmd.ic_dlen = sizeof (*req);
114 
115 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
116 		return (-1);
117 
118 	if (resp->ic_dlen != 1)
119 		return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
120 
121 	*result = *((uint8_t *)resp->ic_data);
122 	return (0);
123 }
124 
125 int
126 ipmi_sunoem_led_set(ipmi_handle_t *ihp, ipmi_sdr_generic_locator_t *dev,
127     uint8_t mode)
128 {
129 	ipmi_cmd_sunoem_led_set_t cmd = { 0 };
130 
131 	if (check_sunoem(ihp) != 0)
132 		return (-1);
133 
134 	cmd.ic_sls_slaveaddr = dev->is_gl_slaveaddr;
135 	cmd.ic_sls_channel_msb = dev->is_gl_channel_msb;
136 	cmd.ic_sls_type = dev->is_gl_oem;
137 	cmd.ic_sls_accessaddr = dev->is_gl_accessaddr;
138 	cmd.ic_sls_hwinfo = dev->is_gl_oem;
139 	cmd.ic_sls_mode = mode;
140 
141 	return (ipmi_send_sunoem_led_set(ihp, &cmd));
142 }
143 
144 int
145 ipmi_sunoem_led_get(ipmi_handle_t *ihp, ipmi_sdr_generic_locator_t *dev,
146     uint8_t *mode)
147 {
148 	ipmi_cmd_sunoem_led_get_t cmd = { 0 };
149 
150 	if (check_sunoem(ihp) != 0)
151 		return (-1);
152 
153 	cmd.ic_slg_slaveaddr = dev->is_gl_slaveaddr;
154 	cmd.ic_slg_channel_msb = dev->is_gl_channel_msb;
155 	cmd.ic_slg_type = dev->is_gl_oem;
156 	cmd.ic_slg_accessaddr = dev->is_gl_accessaddr;
157 	cmd.ic_slg_hwinfo = dev->is_gl_oem;
158 
159 	return (ipmi_send_sunoem_led_get(ihp, &cmd, mode));
160 }
161 
162 int
163 ipmi_sunoem_uptime(ipmi_handle_t *ihp, uint32_t *uptime, uint32_t *gen)
164 {
165 	ipmi_cmd_t cmd, *resp;
166 	uint8_t unused;
167 
168 	if (check_sunoem(ihp) != 0)
169 		return (-1);
170 
171 	cmd.ic_netfn = IPMI_NETFN_OEM;
172 	cmd.ic_lun = 0;
173 	cmd.ic_cmd = IPMI_CMD_SUNOEM_UPTIME;
174 	cmd.ic_dlen = sizeof (unused);
175 	cmd.ic_data = &unused;
176 
177 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
178 		return (-1);
179 
180 	if (resp->ic_dlen != 2 * sizeof (uint32_t))
181 		return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
182 
183 	if (uptime)
184 		*uptime = BE_32(((uint32_t *)resp->ic_data)[0]);
185 	if (gen)
186 		*gen = BE_32(((uint32_t *)resp->ic_data)[1]);
187 
188 	return (0);
189 }
190 
191 int
192 ipmi_sunoem_update_fru(ipmi_handle_t *ihp, ipmi_sunoem_fru_t *req)
193 {
194 	ipmi_cmd_t cmd, *resp;
195 
196 	if (check_sunoem(ihp) != 0)
197 		return (-1);
198 
199 	switch (req->isf_type) {
200 	case IPMI_SUNOEM_FRU_DIMM:
201 		req->isf_datalen = sizeof (req->isf_data.dimm);
202 		break;
203 
204 	case IPMI_SUNOEM_FRU_CPU:
205 		req->isf_datalen = sizeof (req->isf_data.cpu);
206 		break;
207 
208 	case IPMI_SUNOEM_FRU_BIOS:
209 		req->isf_datalen = sizeof (req->isf_data.bios);
210 		break;
211 
212 	case IPMI_SUNOEM_FRU_DISK:
213 		req->isf_datalen = sizeof (req->isf_data.disk);
214 		break;
215 	}
216 
217 	cmd.ic_netfn = IPMI_NETFN_OEM;
218 	cmd.ic_cmd = IPMI_CMD_SUNOEM_FRU_UPDATE;
219 	cmd.ic_lun = 0;
220 	cmd.ic_dlen = offsetof(ipmi_sunoem_fru_t, isf_data) +
221 	    req->isf_datalen;
222 	cmd.ic_data = req;
223 
224 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
225 		return (-1);
226 
227 	if (resp->ic_dlen != 0)
228 		return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
229 
230 	return (0);
231 }
232