| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: ipmi.c,v 1.38 2009/07/11 05:03:11 pgoyette Exp $ */ | | 1 | /* $NetBSD: ipmi.c,v 1.39 2009/07/20 19:11:30 dyoung Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2006 Manuel Bouyer. | | 4 | * Copyright (c) 2006 Manuel Bouyer. |
5 | * | | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions | | 7 | * modification, are permitted provided that the following conditions |
8 | * are met: | | 8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright | | 9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. | | 10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright | | 11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the | | 12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. | | 13 | * documentation and/or other materials provided with the distribution. |
14 | * 3. All advertising materials mentioning features or use of this software | | 14 | * 3. All advertising materials mentioning features or use of this software |
| @@ -47,27 +47,27 @@ | | | @@ -47,27 +47,27 @@ |
47 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 47 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
48 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 48 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
49 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR | | 49 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR |
50 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 50 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
51 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 51 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
52 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 52 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
53 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 53 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
54 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 54 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
55 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 55 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
56 | * SUCH DAMAGE. | | 56 | * SUCH DAMAGE. |
57 | */ | | 57 | */ |
58 | | | 58 | |
59 | #include <sys/cdefs.h> | | 59 | #include <sys/cdefs.h> |
60 | __KERNEL_RCSID(0, "$NetBSD: ipmi.c,v 1.38 2009/07/11 05:03:11 pgoyette Exp $"); | | 60 | __KERNEL_RCSID(0, "$NetBSD: ipmi.c,v 1.39 2009/07/20 19:11:30 dyoung Exp $"); |
61 | | | 61 | |
62 | #include <sys/types.h> | | 62 | #include <sys/types.h> |
63 | #include <sys/param.h> | | 63 | #include <sys/param.h> |
64 | #include <sys/systm.h> | | 64 | #include <sys/systm.h> |
65 | #include <sys/kernel.h> | | 65 | #include <sys/kernel.h> |
66 | #include <sys/device.h> | | 66 | #include <sys/device.h> |
67 | #include <sys/extent.h> | | 67 | #include <sys/extent.h> |
68 | #include <sys/callout.h> | | 68 | #include <sys/callout.h> |
69 | #include <sys/envsys.h> | | 69 | #include <sys/envsys.h> |
70 | #include <sys/malloc.h> | | 70 | #include <sys/malloc.h> |
71 | #include <sys/kthread.h> | | 71 | #include <sys/kthread.h> |
72 | #include <sys/bus.h> | | 72 | #include <sys/bus.h> |
73 | #include <sys/intr.h> | | 73 | #include <sys/intr.h> |
| @@ -85,27 +85,26 @@ struct ipmi_sensor { | | | @@ -85,27 +85,26 @@ struct ipmi_sensor { |
85 | uint8_t *i_sdr; | | 85 | uint8_t *i_sdr; |
86 | int i_num; | | 86 | int i_num; |
87 | int i_stype; | | 87 | int i_stype; |
88 | int i_etype; | | 88 | int i_etype; |
89 | char i_envdesc[64]; | | 89 | char i_envdesc[64]; |
90 | int i_envtype; /* envsys compatible type */ | | 90 | int i_envtype; /* envsys compatible type */ |
91 | int i_envnum; /* envsys index */ | | 91 | int i_envnum; /* envsys index */ |
92 | sysmon_envsys_lim_t i_limits; | | 92 | sysmon_envsys_lim_t i_limits; |
93 | SLIST_ENTRY(ipmi_sensor) i_list; | | 93 | SLIST_ENTRY(ipmi_sensor) i_list; |
94 | }; | | 94 | }; |
95 | | | 95 | |
96 | int ipmi_nintr; | | 96 | int ipmi_nintr; |
97 | int ipmi_dbg = 0; | | 97 | int ipmi_dbg = 0; |
98 | int ipmi_poll = 1; | | | |
99 | int ipmi_enabled = 0; | | 98 | int ipmi_enabled = 0; |
100 | | | 99 | |
101 | #define SENSOR_REFRESH_RATE (5 * hz) | | 100 | #define SENSOR_REFRESH_RATE (5 * hz) |
102 | | | 101 | |
103 | #define SMBIOS_TYPE_IPMI 0x26 | | 102 | #define SMBIOS_TYPE_IPMI 0x26 |
104 | | | 103 | |
105 | /* | | 104 | /* |
106 | * Format of SMBIOS IPMI Flags | | 105 | * Format of SMBIOS IPMI Flags |
107 | * | | 106 | * |
108 | * bit0: interrupt trigger mode (1=level, 0=edge) | | 107 | * bit0: interrupt trigger mode (1=level, 0=edge) |
109 | * bit1: interrupt polarity (1=active high, 0=active low) | | 108 | * bit1: interrupt polarity (1=active high, 0=active low) |
110 | * bit2: reserved | | 109 | * bit2: reserved |
111 | * bit3: address LSB (1=odd,0=even) | | 110 | * bit3: address LSB (1=odd,0=even) |
| @@ -168,49 +167,51 @@ long signextend(unsigned long, int); | | | @@ -168,49 +167,51 @@ long signextend(unsigned long, int); |
168 | | | 167 | |
169 | SLIST_HEAD(ipmi_sensors_head, ipmi_sensor); | | 168 | SLIST_HEAD(ipmi_sensors_head, ipmi_sensor); |
170 | struct ipmi_sensors_head ipmi_sensor_list = | | 169 | struct ipmi_sensors_head ipmi_sensor_list = |
171 | SLIST_HEAD_INITIALIZER(&ipmi_sensor_list); | | 170 | SLIST_HEAD_INITIALIZER(&ipmi_sensor_list); |
172 | | | 171 | |
173 | void dumpb(const char *, int, const uint8_t *); | | 172 | void dumpb(const char *, int, const uint8_t *); |
174 | | | 173 | |
175 | int read_sensor(struct ipmi_softc *, struct ipmi_sensor *); | | 174 | int read_sensor(struct ipmi_softc *, struct ipmi_sensor *); |
176 | int add_sdr_sensor(struct ipmi_softc *, uint8_t *); | | 175 | int add_sdr_sensor(struct ipmi_softc *, uint8_t *); |
177 | int get_sdr_partial(struct ipmi_softc *, uint16_t, uint16_t, | | 176 | int get_sdr_partial(struct ipmi_softc *, uint16_t, uint16_t, |
178 | uint8_t, uint8_t, void *, uint16_t *); | | 177 | uint8_t, uint8_t, void *, uint16_t *); |
179 | int get_sdr(struct ipmi_softc *, uint16_t, uint16_t *); | | 178 | int get_sdr(struct ipmi_softc *, uint16_t, uint16_t *); |
180 | | | 179 | |
| | | 180 | char *ipmi_buf_acquire(struct ipmi_softc *, size_t); |
| | | 181 | void ipmi_buf_release(struct ipmi_softc *, char *); |
181 | int ipmi_sendcmd(struct ipmi_softc *, int, int, int, int, int, const void*); | | 182 | int ipmi_sendcmd(struct ipmi_softc *, int, int, int, int, int, const void*); |
182 | int ipmi_recvcmd(struct ipmi_softc *, int, int *, void *); | | 183 | int ipmi_recvcmd(struct ipmi_softc *, int, int *, void *); |
183 | void ipmi_delay(struct ipmi_softc *, int); | | 184 | void ipmi_delay(struct ipmi_softc *, int); |
184 | | | 185 | |
185 | int ipmi_watchdog_setmode(struct sysmon_wdog *); | | 186 | int ipmi_watchdog_setmode(struct sysmon_wdog *); |
186 | int ipmi_watchdog_tickle(struct sysmon_wdog *); | | 187 | int ipmi_watchdog_tickle(struct sysmon_wdog *); |
| | | 188 | void ipmi_dotickle(struct ipmi_softc *); |
187 | | | 189 | |
188 | int ipmi_intr(void *); | | 190 | int ipmi_intr(void *); |
189 | int ipmi_match(device_t, cfdata_t, void *); | | 191 | int ipmi_match(device_t, cfdata_t, void *); |
190 | void ipmi_attach(device_t, device_t, void *); | | 192 | void ipmi_attach(device_t, device_t, void *); |
191 | static int ipmi_detach(device_t, int); | | 193 | static int ipmi_detach(device_t, int); |
192 | | | 194 | |
193 | long ipow(long, int); | | 195 | long ipow(long, int); |
194 | long ipmi_convert(uint8_t, struct sdrtype1 *, long); | | 196 | long ipmi_convert(uint8_t, struct sdrtype1 *, long); |
195 | void ipmi_sensor_name(char *, int, uint8_t, uint8_t *); | | 197 | void ipmi_sensor_name(char *, int, uint8_t, uint8_t *); |
196 | | | 198 | |
197 | /* BMC Helper Functions */ | | 199 | /* BMC Helper Functions */ |
198 | uint8_t bmc_read(struct ipmi_softc *, int); | | 200 | uint8_t bmc_read(struct ipmi_softc *, int); |
199 | void bmc_write(struct ipmi_softc *, int, uint8_t); | | 201 | void bmc_write(struct ipmi_softc *, int, uint8_t); |
200 | int bmc_io_wait(struct ipmi_softc *, int, uint8_t, uint8_t, const char *); | | 202 | int bmc_io_wait(struct ipmi_softc *, int, uint8_t, uint8_t, const char *); |
201 | int bmc_io_wait_spin(struct ipmi_softc *, int, uint8_t, uint8_t, | | 203 | int bmc_io_wait_spin(struct ipmi_softc *, int, uint8_t, uint8_t); |
202 | const char *); | | 204 | int bmc_io_wait_sleep(struct ipmi_softc *, int, uint8_t, uint8_t); |
203 | void _bmc_io_wait(void *); | | | |
204 | | | 205 | |
205 | void *bt_buildmsg(struct ipmi_softc *, int, int, int, const void *, int *); | | 206 | void *bt_buildmsg(struct ipmi_softc *, int, int, int, const void *, int *); |
206 | void *cmn_buildmsg(struct ipmi_softc *, int, int, int, const void *, int *); | | 207 | void *cmn_buildmsg(struct ipmi_softc *, int, int, int, const void *, int *); |
207 | | | 208 | |
208 | int getbits(uint8_t *, int, int); | | 209 | int getbits(uint8_t *, int, int); |
209 | int ipmi_sensor_type(int, int, int); | | 210 | int ipmi_sensor_type(int, int, int); |
210 | | | 211 | |
211 | void ipmi_smbios_probe(struct smbios_ipmi *, struct ipmi_attach_args *); | | 212 | void ipmi_smbios_probe(struct smbios_ipmi *, struct ipmi_attach_args *); |
212 | void ipmi_refresh_sensors(struct ipmi_softc *sc); | | 213 | void ipmi_refresh_sensors(struct ipmi_softc *sc); |
213 | int ipmi_map_regs(struct ipmi_softc *sc, struct ipmi_attach_args *ia); | | 214 | int ipmi_map_regs(struct ipmi_softc *sc, struct ipmi_attach_args *ia); |
214 | void ipmi_unmap_regs(struct ipmi_softc *sc); | | 215 | void ipmi_unmap_regs(struct ipmi_softc *sc); |
215 | | | 216 | |
216 | void *scan_sig(long, long, int, int, const void *); | | 217 | void *scan_sig(long, long, int, int, const void *); |
| @@ -282,88 +283,62 @@ uint8_t | | | @@ -282,88 +283,62 @@ uint8_t |
282 | bmc_read(struct ipmi_softc *sc, int offset) | | 283 | bmc_read(struct ipmi_softc *sc, int offset) |
283 | { | | 284 | { |
284 | return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, | | 285 | return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, |
285 | offset * sc->sc_if_iospacing)); | | 286 | offset * sc->sc_if_iospacing)); |
286 | } | | 287 | } |
287 | | | 288 | |
288 | void | | 289 | void |
289 | bmc_write(struct ipmi_softc *sc, int offset, uint8_t val) | | 290 | bmc_write(struct ipmi_softc *sc, int offset, uint8_t val) |
290 | { | | 291 | { |
291 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, | | 292 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, |
292 | offset * sc->sc_if_iospacing, val); | | 293 | offset * sc->sc_if_iospacing, val); |
293 | } | | 294 | } |
294 | | | 295 | |
295 | void | | 296 | int |
296 | _bmc_io_wait(void *arg) | | 297 | bmc_io_wait_sleep(struct ipmi_softc *sc, int offset, uint8_t mask, |
| | | 298 | uint8_t value) |
297 | { | | 299 | { |
298 | struct ipmi_softc *sc = arg; | | 300 | int retries; |
299 | struct ipmi_bmc_args *a = sc->sc_iowait_args; | | 301 | uint8_t v; |
300 | | | 302 | |
301 | *a->v = bmc_read(sc, a->offset); | | 303 | KASSERT(mutex_owned(&sc->sc_cmd_mtx)); |
302 | if ((*a->v & a->mask) == a->value) { | | | |
303 | sc->sc_wakeup = 0; | | | |
304 | wakeup(sc); | | | |
305 | return; | | | |
306 | } | | | |
307 | | | 304 | |
308 | if (++sc->sc_retries > sc->sc_max_retries) { | | 305 | for (retries = 0; retries < sc->sc_max_retries; retries++) { |
309 | sc->sc_wakeup = 0; | | 306 | v = bmc_read(sc, offset); |
310 | wakeup(sc); | | 307 | if ((v & mask) == value) |
311 | return; | | 308 | return v; |
| | | 309 | cv_timedwait(&sc->sc_cmd_sleep, &sc->sc_cmd_mtx, 1); |
312 | } | | 310 | } |
313 | | | 311 | return -1; |
314 | callout_schedule(&sc->sc_callout, 1); | | | |
315 | } | | 312 | } |
316 | | | 313 | |
317 | int | | 314 | int |
318 | bmc_io_wait(struct ipmi_softc *sc, int offset, uint8_t mask, uint8_t value, | | 315 | bmc_io_wait(struct ipmi_softc *sc, int offset, uint8_t mask, uint8_t value, |
319 | const char *lbl) | | 316 | const char *lbl) |
320 | { | | 317 | { |
321 | volatile uint8_t v; | | 318 | int v; |
322 | int u; | | | |
323 | struct ipmi_bmc_args args; | | | |
324 | | | | |
325 | u = bmc_io_wait_spin(sc, offset, mask, value, lbl); | | | |
326 | if (cold || u != -1) | | | |
327 | return u; | | | |
328 | | | | |
329 | sc->sc_retries = 0; | | | |
330 | sc->sc_wakeup = 1; | | | |
331 | | | | |
332 | args.offset = offset; | | | |
333 | args.mask = mask; | | | |
334 | args.value = value; | | | |
335 | args.v = &v; | | | |
336 | sc->sc_iowait_args = &args; | | | |
337 | | | | |
338 | _bmc_io_wait(sc); | | | |
339 | | | | |
340 | while (sc->sc_wakeup) | | | |
341 | tsleep(sc, PWAIT, lbl, 0); | | | |
342 | | | | |
343 | if (sc->sc_retries > sc->sc_max_retries) { | | | |
344 | dbg_printf(1, "ipmi: bmc_io_wait fails : v=%.2x m=%.2x " | | | |
345 | "b=%.2x %s\n", v, mask, value, lbl); | | | |
346 | return (-1); | | | |
347 | } | | | |
348 | | | 319 | |
349 | return (v); | | 320 | v = bmc_io_wait_spin(sc, offset, mask, value); |
| | | 321 | if (cold || v != -1) |
| | | 322 | return v; |
| | | 323 | |
| | | 324 | return bmc_io_wait_sleep(sc, offset, mask, value); |
350 | } | | 325 | } |
351 | | | 326 | |
352 | int | | 327 | int |
353 | bmc_io_wait_spin(struct ipmi_softc *sc, int offset, uint8_t mask, | | 328 | bmc_io_wait_spin(struct ipmi_softc *sc, int offset, uint8_t mask, |
354 | uint8_t value, const char *lbl) | | 329 | uint8_t value) |
355 | { | | 330 | { |
356 | volatile uint8_t v; | | 331 | uint8_t v; |
357 | int count = cold ? 5000 : 500; | | 332 | int count = cold ? 5000 : 500; |
358 | /* ~us */ | | 333 | /* ~us */ |
359 | | | 334 | |
360 | while (count--) { | | 335 | while (count--) { |
361 | v = bmc_read(sc, offset); | | 336 | v = bmc_read(sc, offset); |
362 | if ((v & mask) == value) | | 337 | if ((v & mask) == value) |
363 | return v; | | 338 | return v; |
364 | | | 339 | |
365 | delay(1); | | 340 | delay(1); |
366 | } | | 341 | } |
367 | | | 342 | |
368 | return (-1); | | 343 | return (-1); |
369 | | | 344 | |
| @@ -971,27 +946,27 @@ ipmi_smbios_probe(struct smbios_ipmi *pi | | | @@ -971,27 +946,27 @@ ipmi_smbios_probe(struct smbios_ipmi *pi |
971 | * This is used by BT protocol | | 946 | * This is used by BT protocol |
972 | * | | 947 | * |
973 | * Returns a buffer to an allocated message, txlen contains length | | 948 | * Returns a buffer to an allocated message, txlen contains length |
974 | * of allocated message | | 949 | * of allocated message |
975 | */ | | 950 | */ |
976 | void * | | 951 | void * |
977 | bt_buildmsg(struct ipmi_softc *sc, int nfLun, int cmd, int len, | | 952 | bt_buildmsg(struct ipmi_softc *sc, int nfLun, int cmd, int len, |
978 | const void *data, int *txlen) | | 953 | const void *data, int *txlen) |
979 | { | | 954 | { |
980 | uint8_t *buf; | | 955 | uint8_t *buf; |
981 | | | 956 | |
982 | /* Block transfer needs 4 extra bytes: length/netfn/seq/cmd + data */ | | 957 | /* Block transfer needs 4 extra bytes: length/netfn/seq/cmd + data */ |
983 | *txlen = len + 4; | | 958 | *txlen = len + 4; |
984 | buf = malloc(*txlen, M_DEVBUF, M_WAITOK|M_CANFAIL); | | 959 | buf = ipmi_buf_acquire(sc, *txlen); |
985 | if (buf == NULL) | | 960 | if (buf == NULL) |
986 | return (NULL); | | 961 | return (NULL); |
987 | | | 962 | |
988 | buf[IPMI_BTMSG_LEN] = len + 3; | | 963 | buf[IPMI_BTMSG_LEN] = len + 3; |
989 | buf[IPMI_BTMSG_NFLN] = nfLun; | | 964 | buf[IPMI_BTMSG_NFLN] = nfLun; |
990 | buf[IPMI_BTMSG_SEQ] = sc->sc_btseq++; | | 965 | buf[IPMI_BTMSG_SEQ] = sc->sc_btseq++; |
991 | buf[IPMI_BTMSG_CMD] = cmd; | | 966 | buf[IPMI_BTMSG_CMD] = cmd; |
992 | if (len && data) | | 967 | if (len && data) |
993 | memcpy(buf + IPMI_BTMSG_DATASND, data, len); | | 968 | memcpy(buf + IPMI_BTMSG_DATASND, data, len); |
994 | | | 969 | |
995 | return (buf); | | 970 | return (buf); |
996 | } | | 971 | } |
997 | | | 972 | |
| @@ -1000,39 +975,43 @@ bt_buildmsg(struct ipmi_softc *sc, int n | | | @@ -1000,39 +975,43 @@ bt_buildmsg(struct ipmi_softc *sc, int n |
1000 | * This is used by both SMIC and KCS protocols | | 975 | * This is used by both SMIC and KCS protocols |
1001 | * | | 976 | * |
1002 | * Returns a buffer to an allocated message, txlen contains length | | 977 | * Returns a buffer to an allocated message, txlen contains length |
1003 | * of allocated message | | 978 | * of allocated message |
1004 | */ | | 979 | */ |
1005 | void * | | 980 | void * |
1006 | cmn_buildmsg(struct ipmi_softc *sc, int nfLun, int cmd, int len, | | 981 | cmn_buildmsg(struct ipmi_softc *sc, int nfLun, int cmd, int len, |
1007 | const void *data, int *txlen) | | 982 | const void *data, int *txlen) |
1008 | { | | 983 | { |
1009 | uint8_t *buf; | | 984 | uint8_t *buf; |
1010 | | | 985 | |
1011 | /* Common needs two extra bytes: nfLun/cmd + data */ | | 986 | /* Common needs two extra bytes: nfLun/cmd + data */ |
1012 | *txlen = len + 2; | | 987 | *txlen = len + 2; |
1013 | buf = malloc(*txlen, M_DEVBUF, M_WAITOK|M_CANFAIL); | | 988 | buf = ipmi_buf_acquire(sc, *txlen); |
1014 | if (buf == NULL) | | 989 | if (buf == NULL) |
1015 | return (NULL); | | 990 | return (NULL); |
1016 | | | 991 | |
1017 | buf[IPMI_MSG_NFLN] = nfLun; | | 992 | buf[IPMI_MSG_NFLN] = nfLun; |
1018 | buf[IPMI_MSG_CMD] = cmd; | | 993 | buf[IPMI_MSG_CMD] = cmd; |
1019 | if (len && data) | | 994 | if (len && data) |
1020 | memcpy(buf + IPMI_MSG_DATASND, data, len); | | 995 | memcpy(buf + IPMI_MSG_DATASND, data, len); |
1021 | | | 996 | |
1022 | return (buf); | | 997 | return (buf); |
1023 | } | | 998 | } |
1024 | | | 999 | |
1025 | /* Send an IPMI command */ | | 1000 | /* |
| | | 1001 | * ipmi_sendcmd: caller must hold sc_cmd_mtx. |
| | | 1002 | * |
| | | 1003 | * Send an IPMI command |
| | | 1004 | */ |
1026 | int | | 1005 | int |
1027 | ipmi_sendcmd(struct ipmi_softc *sc, int rssa, int rslun, int netfn, int cmd, | | 1006 | ipmi_sendcmd(struct ipmi_softc *sc, int rssa, int rslun, int netfn, int cmd, |
1028 | int txlen, const void *data) | | 1007 | int txlen, const void *data) |
1029 | { | | 1008 | { |
1030 | uint8_t *buf; | | 1009 | uint8_t *buf; |
1031 | int rc = -1; | | 1010 | int rc = -1; |
1032 | | | 1011 | |
1033 | dbg_printf(50, "ipmi_sendcmd: rssa=%.2x nfln=%.2x cmd=%.2x len=%.2x\n", | | 1012 | dbg_printf(50, "ipmi_sendcmd: rssa=%.2x nfln=%.2x cmd=%.2x len=%.2x\n", |
1034 | rssa, NETFN_LUN(netfn, rslun), cmd, txlen); | | 1013 | rssa, NETFN_LUN(netfn, rslun), cmd, txlen); |
1035 | dbg_dump(10, " send", txlen, data); | | 1014 | dbg_dump(10, " send", txlen, data); |
1036 | if (rssa != BMC_SA) { | | 1015 | if (rssa != BMC_SA) { |
1037 | #if 0 | | 1016 | #if 0 |
1038 | buf = sc->sc_if->buildmsg(sc, NETFN_LUN(APP_NETFN, BMC_LUN), | | 1017 | buf = sc->sc_if->buildmsg(sc, NETFN_LUN(APP_NETFN, BMC_LUN), |
| @@ -1052,126 +1031,159 @@ ipmi_sendcmd(struct ipmi_softc *sc, int | | | @@ -1052,126 +1031,159 @@ ipmi_sendcmd(struct ipmi_softc *sc, int |
1052 | /* Set message checksum */ | | 1031 | /* Set message checksum */ |
1053 | imbreq->data[txlen] = cksum8(&imbreq->rqSa, txlen + 3); | | 1032 | imbreq->data[txlen] = cksum8(&imbreq->rqSa, txlen + 3); |
1054 | #endif | | 1033 | #endif |
1055 | goto done; | | 1034 | goto done; |
1056 | } else | | 1035 | } else |
1057 | buf = sc->sc_if->buildmsg(sc, NETFN_LUN(netfn, rslun), cmd, | | 1036 | buf = sc->sc_if->buildmsg(sc, NETFN_LUN(netfn, rslun), cmd, |
1058 | txlen, data, &txlen); | | 1037 | txlen, data, &txlen); |
1059 | | | 1038 | |
1060 | if (buf == NULL) { | | 1039 | if (buf == NULL) { |
1061 | printf("ipmi: sendcmd malloc fails\n"); | | 1040 | printf("ipmi: sendcmd malloc fails\n"); |
1062 | goto done; | | 1041 | goto done; |
1063 | } | | 1042 | } |
1064 | rc = sc->sc_if->sendmsg(sc, txlen, buf); | | 1043 | rc = sc->sc_if->sendmsg(sc, txlen, buf); |
1065 | free(buf, M_DEVBUF); | | 1044 | ipmi_buf_release(sc, buf); |
1066 | | | 1045 | |
1067 | ipmi_delay(sc, 50); /* give bmc chance to digest command */ | | 1046 | ipmi_delay(sc, 50); /* give bmc chance to digest command */ |
1068 | | | 1047 | |
1069 | done: | | 1048 | done: |
1070 | return (rc); | | 1049 | return (rc); |
1071 | } | | 1050 | } |
1072 | | | 1051 | |
| | | 1052 | void |
| | | 1053 | ipmi_buf_release(struct ipmi_softc *sc, char *buf) |
| | | 1054 | { |
| | | 1055 | KASSERT(sc->sc_buf_rsvd); |
| | | 1056 | KASSERT(sc->sc_buf == buf); |
| | | 1057 | sc->sc_buf_rsvd = false; |
| | | 1058 | } |
| | | 1059 | |
| | | 1060 | char * |
| | | 1061 | ipmi_buf_acquire(struct ipmi_softc *sc, size_t len) |
| | | 1062 | { |
| | | 1063 | KASSERT(len <= sizeof(sc->sc_buf)); |
| | | 1064 | |
| | | 1065 | if (sc->sc_buf_rsvd || len > sizeof(sc->sc_buf)) |
| | | 1066 | return NULL; |
| | | 1067 | sc->sc_buf_rsvd = true; |
| | | 1068 | return sc->sc_buf; |
| | | 1069 | } |
| | | 1070 | |
| | | 1071 | /* |
| | | 1072 | * ipmi_recvcmd: caller must hold sc_cmd_mtx. |
| | | 1073 | */ |
1073 | int | | 1074 | int |
1074 | ipmi_recvcmd(struct ipmi_softc *sc, int maxlen, int *rxlen, void *data) | | 1075 | ipmi_recvcmd(struct ipmi_softc *sc, int maxlen, int *rxlen, void *data) |
1075 | { | | 1076 | { |
1076 | uint8_t *buf, rc = 0; | | 1077 | uint8_t *buf, rc = 0; |
1077 | int rawlen; | | 1078 | int rawlen; |
1078 | | | 1079 | |
1079 | /* Need three extra bytes: netfn/cmd/ccode + data */ | | 1080 | /* Need three extra bytes: netfn/cmd/ccode + data */ |
1080 | buf = malloc(maxlen + 3, M_DEVBUF, M_WAITOK|M_CANFAIL); | | 1081 | buf = ipmi_buf_acquire(sc, maxlen + 3); |
1081 | if (buf == NULL) { | | 1082 | if (buf == NULL) { |
1082 | printf("ipmi: ipmi_recvcmd: malloc fails\n"); | | 1083 | printf("ipmi: ipmi_recvcmd: malloc fails\n"); |
1083 | return (-1); | | 1084 | return (-1); |
1084 | } | | 1085 | } |
1085 | /* Receive message from interface, copy out result data */ | | 1086 | /* Receive message from interface, copy out result data */ |
1086 | if (sc->sc_if->recvmsg(sc, maxlen + 3, &rawlen, buf)) | | 1087 | if (sc->sc_if->recvmsg(sc, maxlen + 3, &rawlen, buf)) |
1087 | return (-1); | | 1088 | return (-1); |
1088 | | | 1089 | |
1089 | *rxlen = rawlen - IPMI_MSG_DATARCV; | | 1090 | *rxlen = rawlen - IPMI_MSG_DATARCV; |
1090 | if (*rxlen > 0 && data) | | 1091 | if (*rxlen > 0 && data) |
1091 | memcpy(data, buf + IPMI_MSG_DATARCV, *rxlen); | | 1092 | memcpy(data, buf + IPMI_MSG_DATARCV, *rxlen); |
1092 | | | 1093 | |
1093 | if ((rc = buf[IPMI_MSG_CCODE]) != 0) | | 1094 | if ((rc = buf[IPMI_MSG_CCODE]) != 0) |
1094 | dbg_printf(1, "ipmi_recvmsg: nfln=%.2x cmd=%.2x err=%.2x\n", | | 1095 | dbg_printf(1, "ipmi_recvmsg: nfln=%.2x cmd=%.2x err=%.2x\n", |
1095 | buf[IPMI_MSG_NFLN], buf[IPMI_MSG_CMD], buf[IPMI_MSG_CCODE]); | | 1096 | buf[IPMI_MSG_NFLN], buf[IPMI_MSG_CMD], buf[IPMI_MSG_CCODE]); |
1096 | | | 1097 | |
1097 | dbg_printf(50, "ipmi_recvcmd: nfln=%.2x cmd=%.2x err=%.2x len=%.2x\n", | | 1098 | dbg_printf(50, "ipmi_recvcmd: nfln=%.2x cmd=%.2x err=%.2x len=%.2x\n", |
1098 | buf[IPMI_MSG_NFLN], buf[IPMI_MSG_CMD], buf[IPMI_MSG_CCODE], | | 1099 | buf[IPMI_MSG_NFLN], buf[IPMI_MSG_CMD], buf[IPMI_MSG_CCODE], |
1099 | *rxlen); | | 1100 | *rxlen); |
1100 | dbg_dump(10, " recv", *rxlen, data); | | 1101 | dbg_dump(10, " recv", *rxlen, data); |
1101 | | | 1102 | |
1102 | free(buf, M_DEVBUF); | | 1103 | ipmi_buf_release(sc, buf); |
1103 | | | 1104 | |
1104 | return (rc); | | 1105 | return (rc); |
1105 | } | | 1106 | } |
1106 | | | 1107 | |
| | | 1108 | /* |
| | | 1109 | * ipmi_delay: caller must hold sc_cmd_mtx. |
| | | 1110 | */ |
1107 | void | | 1111 | void |
1108 | ipmi_delay(struct ipmi_softc *sc, int ms) | | 1112 | ipmi_delay(struct ipmi_softc *sc, int ms) |
1109 | { | | 1113 | { |
1110 | if (cold) | | 1114 | if (cold) |
1111 | delay(ms * 1000); | | 1115 | delay(ms * 1000); |
1112 | else | | 1116 | else |
1113 | while (tsleep(sc, PWAIT, "ipmicmd", mstohz(ms)) != EWOULDBLOCK); | | 1117 | cv_timedwait(&sc->sc_cmd_sleep, &sc->sc_cmd_mtx, mstohz(ms)); |
1114 | } | | 1118 | } |
1115 | | | 1119 | |
1116 | /* Read a partial SDR entry */ | | 1120 | /* Read a partial SDR entry */ |
1117 | int | | 1121 | int |
1118 | get_sdr_partial(struct ipmi_softc *sc, uint16_t recordId, uint16_t reserveId, | | 1122 | get_sdr_partial(struct ipmi_softc *sc, uint16_t recordId, uint16_t reserveId, |
1119 | uint8_t offset, uint8_t length, void *buffer, uint16_t *nxtRecordId) | | 1123 | uint8_t offset, uint8_t length, void *buffer, uint16_t *nxtRecordId) |
1120 | { | | 1124 | { |
1121 | uint8_t cmd[256 + 8]; | | 1125 | uint8_t cmd[256 + 8]; |
1122 | int len; | | 1126 | int len; |
1123 | | | 1127 | |
1124 | ((uint16_t *) cmd)[0] = reserveId; | | 1128 | ((uint16_t *) cmd)[0] = reserveId; |
1125 | ((uint16_t *) cmd)[1] = recordId; | | 1129 | ((uint16_t *) cmd)[1] = recordId; |
1126 | cmd[4] = offset; | | 1130 | cmd[4] = offset; |
1127 | cmd[5] = length; | | 1131 | cmd[5] = length; |
| | | 1132 | mutex_enter(&sc->sc_cmd_mtx); |
1128 | if (ipmi_sendcmd(sc, BMC_SA, 0, STORAGE_NETFN, STORAGE_GET_SDR, 6, | | 1133 | if (ipmi_sendcmd(sc, BMC_SA, 0, STORAGE_NETFN, STORAGE_GET_SDR, 6, |
1129 | cmd)) { | | 1134 | cmd)) { |
| | | 1135 | mutex_exit(&sc->sc_cmd_mtx); |
1130 | printf("ipmi: sendcmd fails\n"); | | 1136 | printf("ipmi: sendcmd fails\n"); |
1131 | return (-1); | | 1137 | return (-1); |
1132 | } | | 1138 | } |
1133 | if (ipmi_recvcmd(sc, 8 + length, &len, cmd)) { | | 1139 | if (ipmi_recvcmd(sc, 8 + length, &len, cmd)) { |
| | | 1140 | mutex_exit(&sc->sc_cmd_mtx); |
1134 | printf("ipmi: getSdrPartial: recvcmd fails\n"); | | 1141 | printf("ipmi: getSdrPartial: recvcmd fails\n"); |
1135 | return (-1); | | 1142 | return (-1); |
1136 | } | | 1143 | } |
| | | 1144 | mutex_exit(&sc->sc_cmd_mtx); |
1137 | if (nxtRecordId) | | 1145 | if (nxtRecordId) |
1138 | *nxtRecordId = *(uint16_t *) cmd; | | 1146 | *nxtRecordId = *(uint16_t *) cmd; |
1139 | memcpy(buffer, cmd + 2, len - 2); | | 1147 | memcpy(buffer, cmd + 2, len - 2); |
1140 | | | 1148 | |
1141 | return (0); | | 1149 | return (0); |
1142 | } | | 1150 | } |
1143 | | | 1151 | |
1144 | int maxsdrlen = 0x10; | | 1152 | int maxsdrlen = 0x10; |
1145 | | | 1153 | |
1146 | /* Read an entire SDR; pass to add sensor */ | | 1154 | /* Read an entire SDR; pass to add sensor */ |
1147 | int | | 1155 | int |
1148 | get_sdr(struct ipmi_softc *sc, uint16_t recid, uint16_t *nxtrec) | | 1156 | get_sdr(struct ipmi_softc *sc, uint16_t recid, uint16_t *nxtrec) |
1149 | { | | 1157 | { |
1150 | uint16_t resid = 0; | | 1158 | uint16_t resid = 0; |
1151 | int len, sdrlen, offset; | | 1159 | int len, sdrlen, offset; |
1152 | uint8_t *psdr; | | 1160 | uint8_t *psdr; |
1153 | struct sdrhdr shdr; | | 1161 | struct sdrhdr shdr; |
1154 | | | 1162 | |
| | | 1163 | mutex_enter(&sc->sc_cmd_mtx); |
1155 | /* Reserve SDR */ | | 1164 | /* Reserve SDR */ |
1156 | if (ipmi_sendcmd(sc, BMC_SA, 0, STORAGE_NETFN, STORAGE_RESERVE_SDR, | | 1165 | if (ipmi_sendcmd(sc, BMC_SA, 0, STORAGE_NETFN, STORAGE_RESERVE_SDR, |
1157 | 0, NULL)) { | | 1166 | 0, NULL)) { |
| | | 1167 | mutex_exit(&sc->sc_cmd_mtx); |
1158 | printf("ipmi: reserve send fails\n"); | | 1168 | printf("ipmi: reserve send fails\n"); |
1159 | return (-1); | | 1169 | return (-1); |
1160 | } | | 1170 | } |
1161 | if (ipmi_recvcmd(sc, sizeof(resid), &len, &resid)) { | | 1171 | if (ipmi_recvcmd(sc, sizeof(resid), &len, &resid)) { |
| | | 1172 | mutex_exit(&sc->sc_cmd_mtx); |
1162 | printf("ipmi: reserve recv fails\n"); | | 1173 | printf("ipmi: reserve recv fails\n"); |
1163 | return (-1); | | 1174 | return (-1); |
1164 | } | | 1175 | } |
| | | 1176 | mutex_exit(&sc->sc_cmd_mtx); |
1165 | /* Get SDR Header */ | | 1177 | /* Get SDR Header */ |
1166 | if (get_sdr_partial(sc, recid, resid, 0, sizeof shdr, &shdr, nxtrec)) { | | 1178 | if (get_sdr_partial(sc, recid, resid, 0, sizeof shdr, &shdr, nxtrec)) { |
1167 | printf("ipmi: get header fails\n"); | | 1179 | printf("ipmi: get header fails\n"); |
1168 | return (-1); | | 1180 | return (-1); |
1169 | } | | 1181 | } |
1170 | /* Allocate space for entire SDR Length of SDR in header does not | | 1182 | /* Allocate space for entire SDR Length of SDR in header does not |
1171 | * include header length */ | | 1183 | * include header length */ |
1172 | sdrlen = sizeof(shdr) + shdr.record_length; | | 1184 | sdrlen = sizeof(shdr) + shdr.record_length; |
1173 | psdr = malloc(sdrlen, M_DEVBUF, M_WAITOK|M_CANFAIL); | | 1185 | psdr = malloc(sdrlen, M_DEVBUF, M_WAITOK|M_CANFAIL); |
1174 | if (psdr == NULL) | | 1186 | if (psdr == NULL) |
1175 | return -1; | | 1187 | return -1; |
1176 | | | 1188 | |
1177 | memcpy(psdr, &shdr, sizeof(shdr)); | | 1189 | memcpy(psdr, &shdr, sizeof(shdr)); |
| @@ -1370,34 +1382,39 @@ ipmi_get_limits(struct sysmon_envsys *sm | | | @@ -1370,34 +1382,39 @@ ipmi_get_limits(struct sysmon_envsys *sm |
1370 | ipmi_get_sensor_limits(sc, ipmi_s, limits); | | 1382 | ipmi_get_sensor_limits(sc, ipmi_s, limits); |
1371 | ipmi_s->i_limits = *limits; | | 1383 | ipmi_s->i_limits = *limits; |
1372 | return; | | 1384 | return; |
1373 | } | | 1385 | } |
1374 | } | | 1386 | } |
1375 | return; | | 1387 | return; |
1376 | } | | 1388 | } |
1377 | | | 1389 | |
1378 | void | | 1390 | void |
1379 | ipmi_get_sensor_limits(struct ipmi_softc *sc, struct ipmi_sensor *psensor, | | 1391 | ipmi_get_sensor_limits(struct ipmi_softc *sc, struct ipmi_sensor *psensor, |
1380 | sysmon_envsys_lim_t *limits) | | 1392 | sysmon_envsys_lim_t *limits) |
1381 | { | | 1393 | { |
1382 | struct sdrtype1 *s1 = (struct sdrtype1 *)psensor->i_sdr; | | 1394 | struct sdrtype1 *s1 = (struct sdrtype1 *)psensor->i_sdr; |
| | | 1395 | bool failure; |
1383 | int rxlen; | | 1396 | int rxlen; |
1384 | uint8_t data[32]; | | 1397 | uint8_t data[32]; |
1385 | | | 1398 | |
1386 | limits->sel_flags = 0; | | 1399 | limits->sel_flags = 0; |
1387 | data[0] = psensor->i_num; | | 1400 | data[0] = psensor->i_num; |
1388 | if (ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun, | | 1401 | mutex_enter(&sc->sc_cmd_mtx); |
| | | 1402 | failure = |
| | | 1403 | ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun, |
1389 | SE_NETFN, SE_GET_SENSOR_THRESHOLD, 1, data) || | | 1404 | SE_NETFN, SE_GET_SENSOR_THRESHOLD, 1, data) || |
1390 | ipmi_recvcmd(sc, sizeof(data), &rxlen, data)) | | 1405 | ipmi_recvcmd(sc, sizeof(data), &rxlen, data); |
| | | 1406 | mutex_exit(&sc->sc_cmd_mtx); |
| | | 1407 | if (failure) |
1391 | return; | | 1408 | return; |
1392 | | | 1409 | |
1393 | dbg_printf(25, "recvdata: %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", | | 1410 | dbg_printf(25, "recvdata: %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", |
1394 | data[0], data[1], data[2], data[3], data[4], data[5], data[6]); | | 1411 | data[0], data[1], data[2], data[3], data[4], data[5], data[6]); |
1395 | | | 1412 | |
1396 | if (data[0] & 0x20 && data[6] != 0xff) { | | 1413 | if (data[0] & 0x20 && data[6] != 0xff) { |
1397 | limits->sel_critmax = ipmi_convert_sensor(&data[6], psensor); | | 1414 | limits->sel_critmax = ipmi_convert_sensor(&data[6], psensor); |
1398 | limits->sel_flags |= PROP_CRITMAX; | | 1415 | limits->sel_flags |= PROP_CRITMAX; |
1399 | } | | 1416 | } |
1400 | if (data[0] & 0x10 && data[5] != 0xff) { | | 1417 | if (data[0] & 0x10 && data[5] != 0xff) { |
1401 | limits->sel_critmax = ipmi_convert_sensor(&data[5], psensor); | | 1418 | limits->sel_critmax = ipmi_convert_sensor(&data[5], psensor); |
1402 | limits->sel_flags |= PROP_CRITMAX; | | 1419 | limits->sel_flags |= PROP_CRITMAX; |
1403 | } | | 1420 | } |
| @@ -1475,50 +1492,53 @@ ipmi_sensor_status(struct ipmi_softc *sc | | | @@ -1475,50 +1492,53 @@ ipmi_sensor_status(struct ipmi_softc *sc |
1475 | return ENVSYS_SWARNOVER; | | 1492 | return ENVSYS_SWARNOVER; |
1476 | } | | 1493 | } |
1477 | break; | | 1494 | break; |
1478 | } | | 1495 | } |
1479 | | | 1496 | |
1480 | return ENVSYS_SVALID; | | 1497 | return ENVSYS_SVALID; |
1481 | } | | 1498 | } |
1482 | | | 1499 | |
1483 | int | | 1500 | int |
1484 | read_sensor(struct ipmi_softc *sc, struct ipmi_sensor *psensor) | | 1501 | read_sensor(struct ipmi_softc *sc, struct ipmi_sensor *psensor) |
1485 | { | | 1502 | { |
1486 | struct sdrtype1 *s1 = (struct sdrtype1 *) psensor->i_sdr; | | 1503 | struct sdrtype1 *s1 = (struct sdrtype1 *) psensor->i_sdr; |
1487 | uint8_t data[8]; | | 1504 | uint8_t data[8]; |
1488 | int rxlen, rv = -1; | | 1505 | int rxlen; |
1489 | envsys_data_t *edata = &sc->sc_sensor[psensor->i_envnum]; | | 1506 | envsys_data_t *edata = &sc->sc_sensor[psensor->i_envnum]; |
1490 | | | 1507 | |
1491 | mutex_enter(&sc->sc_lock); | | | |
1492 | memset(data, 0, sizeof(data)); | | 1508 | memset(data, 0, sizeof(data)); |
1493 | data[0] = psensor->i_num; | | 1509 | data[0] = psensor->i_num; |
| | | 1510 | |
| | | 1511 | mutex_enter(&sc->sc_cmd_mtx); |
1494 | if (ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun, SE_NETFN, | | 1512 | if (ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun, SE_NETFN, |
1495 | SE_GET_SENSOR_READING, 1, data)) | | 1513 | SE_GET_SENSOR_READING, 1, data)) |
1496 | goto done; | | 1514 | goto err; |
1497 | | | 1515 | |
1498 | if (ipmi_recvcmd(sc, sizeof(data), &rxlen, data)) | | 1516 | if (ipmi_recvcmd(sc, sizeof(data), &rxlen, data)) |
1499 | goto done; | | 1517 | goto err; |
| | | 1518 | mutex_exit(&sc->sc_cmd_mtx); |
| | | 1519 | |
1500 | dbg_printf(10, "values=%.2x %.2x %.2x %.2x %s\n", | | 1520 | dbg_printf(10, "values=%.2x %.2x %.2x %.2x %s\n", |
1501 | data[0],data[1],data[2],data[3], edata->desc); | | 1521 | data[0],data[1],data[2],data[3], edata->desc); |
1502 | if (data[1] & IPMI_INVALID_SENSOR) { | | 1522 | if (data[1] & IPMI_INVALID_SENSOR) { |
1503 | /* Check if sensor is valid */ | | 1523 | /* Check if sensor is valid */ |
1504 | edata->state = ENVSYS_SINVALID; | | 1524 | edata->state = ENVSYS_SINVALID; |
1505 | } else { | | 1525 | } else { |
1506 | edata->state = ipmi_sensor_status(sc, psensor, edata, data); | | 1526 | edata->state = ipmi_sensor_status(sc, psensor, edata, data); |
1507 | } | | 1527 | } |
1508 | rv = 0; | | 1528 | return 0; |
1509 | done: | | 1529 | err: |
1510 | mutex_exit(&sc->sc_lock); | | 1530 | mutex_exit(&sc->sc_cmd_mtx); |
1511 | return (rv); | | 1531 | return -1; |
1512 | } | | 1532 | } |
1513 | | | 1533 | |
1514 | int | | 1534 | int |
1515 | ipmi_sensor_type(int type, int ext_type, int entity) | | 1535 | ipmi_sensor_type(int type, int ext_type, int entity) |
1516 | { | | 1536 | { |
1517 | switch (ext_type << 8L | type) { | | 1537 | switch (ext_type << 8L | type) { |
1518 | case IPMI_SENSOR_TYPE_TEMP: | | 1538 | case IPMI_SENSOR_TYPE_TEMP: |
1519 | return (ENVSYS_STEMP); | | 1539 | return (ENVSYS_STEMP); |
1520 | | | 1540 | |
1521 | case IPMI_SENSOR_TYPE_VOLT: | | 1541 | case IPMI_SENSOR_TYPE_VOLT: |
1522 | return (ENVSYS_SVOLTS_DC); | | 1542 | return (ENVSYS_SVOLTS_DC); |
1523 | | | 1543 | |
1524 | case IPMI_SENSOR_TYPE_FAN: | | 1544 | case IPMI_SENSOR_TYPE_FAN: |
| @@ -1665,29 +1685,26 @@ ipmi_intr(void *arg) | | | @@ -1665,29 +1685,26 @@ ipmi_intr(void *arg) |
1665 | | | 1685 | |
1666 | v = bmc_read(sc, _KCS_STATUS_REGISTER); | | 1686 | v = bmc_read(sc, _KCS_STATUS_REGISTER); |
1667 | if (v & KCS_OBF) | | 1687 | if (v & KCS_OBF) |
1668 | ++ipmi_nintr; | | 1688 | ++ipmi_nintr; |
1669 | | | 1689 | |
1670 | return (0); | | 1690 | return (0); |
1671 | } | | 1691 | } |
1672 | | | 1692 | |
1673 | /* Handle IPMI Timer - reread sensor values */ | | 1693 | /* Handle IPMI Timer - reread sensor values */ |
1674 | void | | 1694 | void |
1675 | ipmi_refresh_sensors(struct ipmi_softc *sc) | | 1695 | ipmi_refresh_sensors(struct ipmi_softc *sc) |
1676 | { | | 1696 | { |
1677 | | | 1697 | |
1678 | if (!ipmi_poll) | | | |
1679 | return; | | | |
1680 | | | | |
1681 | if (SLIST_EMPTY(&ipmi_sensor_list)) | | 1698 | if (SLIST_EMPTY(&ipmi_sensor_list)) |
1682 | return; | | 1699 | return; |
1683 | | | 1700 | |
1684 | sc->current_sensor = SLIST_NEXT(sc->current_sensor, i_list); | | 1701 | sc->current_sensor = SLIST_NEXT(sc->current_sensor, i_list); |
1685 | if (sc->current_sensor == NULL) | | 1702 | if (sc->current_sensor == NULL) |
1686 | sc->current_sensor = SLIST_FIRST(&ipmi_sensor_list); | | 1703 | sc->current_sensor = SLIST_FIRST(&ipmi_sensor_list); |
1687 | | | 1704 | |
1688 | if (read_sensor(sc, sc->current_sensor)) { | | 1705 | if (read_sensor(sc, sc->current_sensor)) { |
1689 | dbg_printf(1, "ipmi: error reading\n"); | | 1706 | dbg_printf(1, "ipmi: error reading\n"); |
1690 | } | | 1707 | } |
1691 | } | | 1708 | } |
1692 | | | 1709 | |
1693 | int | | 1710 | int |
| @@ -1754,74 +1771,82 @@ ipmi_probe(struct ipmi_attach_args *ia) | | | @@ -1754,74 +1771,82 @@ ipmi_probe(struct ipmi_attach_args *ia) |
1754 | | | 1771 | |
1755 | return (1); | | 1772 | return (1); |
1756 | } | | 1773 | } |
1757 | | | 1774 | |
1758 | int | | 1775 | int |
1759 | ipmi_match(device_t parent, cfdata_t cf, void *aux) | | 1776 | ipmi_match(device_t parent, cfdata_t cf, void *aux) |
1760 | { | | 1777 | { |
1761 | struct ipmi_softc sc; | | 1778 | struct ipmi_softc sc; |
1762 | struct ipmi_attach_args *ia = aux; | | 1779 | struct ipmi_attach_args *ia = aux; |
1763 | uint8_t cmd[32]; | | 1780 | uint8_t cmd[32]; |
1764 | int len; | | 1781 | int len; |
1765 | int rv = 0; | | 1782 | int rv = 0; |
1766 | | | 1783 | |
| | | 1784 | memset(&sc, 0, sizeof(sc)); |
| | | 1785 | |
1767 | /* Map registers */ | | 1786 | /* Map registers */ |
1768 | if (ipmi_map_regs(&sc, ia) != 0) | | 1787 | if (ipmi_map_regs(&sc, ia) != 0) |
1769 | return 0; | | 1788 | return 0; |
1770 | | | 1789 | |
1771 | sc.sc_if->probe(&sc); | | 1790 | sc.sc_if->probe(&sc); |
1772 | | | 1791 | |
| | | 1792 | mutex_init(&sc.sc_cmd_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK); |
| | | 1793 | mutex_enter(&sc.sc_cmd_mtx); |
1773 | /* Identify BMC device early to detect lying bios */ | | 1794 | /* Identify BMC device early to detect lying bios */ |
1774 | if (ipmi_sendcmd(&sc, BMC_SA, 0, APP_NETFN, APP_GET_DEVICE_ID, | | 1795 | if (ipmi_sendcmd(&sc, BMC_SA, 0, APP_NETFN, APP_GET_DEVICE_ID, |
1775 | 0, NULL)) { | | 1796 | 0, NULL)) { |
| | | 1797 | mutex_exit(&sc.sc_cmd_mtx); |
1776 | dbg_printf(1, ": unable to send get device id " | | 1798 | dbg_printf(1, ": unable to send get device id " |
1777 | "command\n"); | | 1799 | "command\n"); |
1778 | goto unmap; | | 1800 | goto unmap; |
1779 | } | | 1801 | } |
1780 | if (ipmi_recvcmd(&sc, sizeof(cmd), &len, cmd)) { | | 1802 | if (ipmi_recvcmd(&sc, sizeof(cmd), &len, cmd)) { |
| | | 1803 | mutex_exit(&sc.sc_cmd_mtx); |
1781 | dbg_printf(1, ": unable to retrieve device id\n"); | | 1804 | dbg_printf(1, ": unable to retrieve device id\n"); |
1782 | goto unmap; | | 1805 | goto unmap; |
1783 | } | | 1806 | } |
| | | 1807 | mutex_exit(&sc.sc_cmd_mtx); |
1784 | | | 1808 | |
1785 | dbg_dump(1, "bmc data", len, cmd); | | 1809 | dbg_dump(1, "bmc data", len, cmd); |
1786 | rv = 1; /* GETID worked, we got IPMI */ | | 1810 | rv = 1; /* GETID worked, we got IPMI */ |
1787 | unmap: | | 1811 | unmap: |
| | | 1812 | mutex_destroy(&sc.sc_cmd_mtx); |
1788 | ipmi_unmap_regs(&sc); | | 1813 | ipmi_unmap_regs(&sc); |
1789 | | | 1814 | |
1790 | return rv; | | 1815 | return rv; |
1791 | } | | 1816 | } |
1792 | | | 1817 | |
1793 | static void | | 1818 | static void |
1794 | ipmi_thread(void *cookie) | | 1819 | ipmi_thread(void *cookie) |
1795 | { | | 1820 | { |
1796 | device_t self = cookie; | | 1821 | device_t self = cookie; |
1797 | struct ipmi_softc *sc = device_private(self); | | 1822 | struct ipmi_softc *sc = device_private(self); |
1798 | struct ipmi_attach_args *ia = &sc->sc_ia; | | 1823 | struct ipmi_attach_args *ia = &sc->sc_ia; |
1799 | uint16_t rec; | | 1824 | uint16_t rec; |
1800 | struct ipmi_sensor *ipmi_s; | | 1825 | struct ipmi_sensor *ipmi_s; |
1801 | int i; | | 1826 | int i; |
1802 | int current_index_typ[ENVSYS_NSENSORS]; | | 1827 | int current_index_typ[ENVSYS_NSENSORS]; |
1803 | | | 1828 | |
1804 | sc->sc_thread_running = 1; | | 1829 | sc->sc_thread_running = true; |
1805 | | | 1830 | |
1806 | /* lock around read_sensor so that no one messes with the bmc regs */ | | 1831 | /* lock around read_sensor so that no one messes with the bmc regs */ |
1807 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); | | 1832 | mutex_init(&sc->sc_cmd_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK); |
| | | 1833 | cv_init(&sc->sc_cmd_sleep, "ipmicmd"); |
| | | 1834 | |
| | | 1835 | mutex_init(&sc->sc_poll_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK); |
| | | 1836 | cv_init(&sc->sc_poll_cv, "ipmi_poll"); |
1808 | | | 1837 | |
1809 | /* setup ticker */ | | 1838 | /* setup ticker */ |
1810 | sc->sc_retries = 0; | | | |
1811 | sc->sc_wakeup = 0; | | | |
1812 | sc->sc_max_retries = hz * 90; /* 90 seconds max */ | | 1839 | sc->sc_max_retries = hz * 90; /* 90 seconds max */ |
1813 | callout_init(&sc->sc_callout, 0); | | | |
1814 | callout_setfunc(&sc->sc_callout, _bmc_io_wait, sc); | | | |
1815 | | | 1840 | |
1816 | /* Map registers */ | | 1841 | /* Map registers */ |
1817 | ipmi_map_regs(sc, ia); | | 1842 | ipmi_map_regs(sc, ia); |
1818 | | | 1843 | |
1819 | /* Scan SDRs, add sensors to list */ | | 1844 | /* Scan SDRs, add sensors to list */ |
1820 | for (rec = 0; rec != 0xFFFF;) | | 1845 | for (rec = 0; rec != 0xFFFF;) |
1821 | if (get_sdr(sc, rec, &rec)) | | 1846 | if (get_sdr(sc, rec, &rec)) |
1822 | break; | | 1847 | break; |
1823 | | | 1848 | |
1824 | /* fill in sensor infos: */ | | 1849 | /* fill in sensor infos: */ |
1825 | /* get indexes for each unit, and number of units */ | | 1850 | /* get indexes for each unit, and number of units */ |
1826 | current_index_typ[0] = 0; | | 1851 | current_index_typ[0] = 0; |
1827 | for (i = 1; i < ENVSYS_NSENSORS; i++) { | | 1852 | for (i = 1; i < ENVSYS_NSENSORS; i++) { |
| @@ -1890,58 +1915,66 @@ ipmi_thread(void *cookie) | | | @@ -1890,58 +1915,66 @@ ipmi_thread(void *cookie) |
1890 | if (ia->iaa_if_irq != -1) | | 1915 | if (ia->iaa_if_irq != -1) |
1891 | aprint_verbose_dev(self, " irq %d\n", ia->iaa_if_irq); | | 1916 | aprint_verbose_dev(self, " irq %d\n", ia->iaa_if_irq); |
1892 | | | 1917 | |
1893 | /* setup flag to exclude iic */ | | 1918 | /* setup flag to exclude iic */ |
1894 | ipmi_enabled = 1; | | 1919 | ipmi_enabled = 1; |
1895 | | | 1920 | |
1896 | /* Setup Watchdog timer */ | | 1921 | /* Setup Watchdog timer */ |
1897 | sc->sc_wdog.smw_name = device_xname(sc->sc_dev); | | 1922 | sc->sc_wdog.smw_name = device_xname(sc->sc_dev); |
1898 | sc->sc_wdog.smw_cookie = sc; | | 1923 | sc->sc_wdog.smw_cookie = sc; |
1899 | sc->sc_wdog.smw_setmode = ipmi_watchdog_setmode; | | 1924 | sc->sc_wdog.smw_setmode = ipmi_watchdog_setmode; |
1900 | sc->sc_wdog.smw_tickle = ipmi_watchdog_tickle; | | 1925 | sc->sc_wdog.smw_tickle = ipmi_watchdog_tickle; |
1901 | sysmon_wdog_register(&sc->sc_wdog); | | 1926 | sysmon_wdog_register(&sc->sc_wdog); |
1902 | | | 1927 | |
| | | 1928 | mutex_enter(&sc->sc_poll_mtx); |
1903 | while (sc->sc_thread_running) { | | 1929 | while (sc->sc_thread_running) { |
1904 | ipmi_refresh_sensors(sc); | | 1930 | ipmi_refresh_sensors(sc); |
1905 | tsleep(&sc->sc_thread_running, PWAIT, "ipmi_poll", | | 1931 | cv_timedwait(&sc->sc_poll_cv, &sc->sc_poll_mtx, |
1906 | SENSOR_REFRESH_RATE); | | 1932 | SENSOR_REFRESH_RATE); |
| | | 1933 | if (sc->sc_tickle_due) { |
| | | 1934 | ipmi_dotickle(sc); |
| | | 1935 | sc->sc_tickle_due = false; |
| | | 1936 | } |
1907 | } | | 1937 | } |
| | | 1938 | mutex_exit(&sc->sc_poll_mtx); |
1908 | kthread_exit(0); | | 1939 | kthread_exit(0); |
1909 | } | | 1940 | } |
1910 | | | 1941 | |
1911 | void | | 1942 | void |
1912 | ipmi_attach(device_t parent, device_t self, void *aux) | | 1943 | ipmi_attach(device_t parent, device_t self, void *aux) |
1913 | { | | 1944 | { |
1914 | struct ipmi_softc *sc = device_private(self); | | 1945 | struct ipmi_softc *sc = device_private(self); |
1915 | | | 1946 | |
1916 | sc->sc_ia = *(struct ipmi_attach_args *)aux; | | 1947 | sc->sc_ia = *(struct ipmi_attach_args *)aux; |
1917 | sc->sc_dev = self; | | 1948 | sc->sc_dev = self; |
1918 | aprint_normal("\n"); | | 1949 | aprint_normal("\n"); |
1919 | | | 1950 | |
1920 | if (kthread_create(PRI_NONE, 0, NULL, ipmi_thread, self, | | 1951 | if (kthread_create(PRI_NONE, 0, NULL, ipmi_thread, self, |
1921 | &sc->sc_kthread, "ipmi") != 0) { | | 1952 | &sc->sc_kthread, "ipmi") != 0) { |
1922 | aprint_error("ipmi: unable to create thread, disabled\n"); | | 1953 | aprint_error("ipmi: unable to create thread, disabled\n"); |
1923 | } | | 1954 | } |
1924 | } | | 1955 | } |
1925 | | | 1956 | |
1926 | static int | | 1957 | static int |
1927 | ipmi_detach(device_t self, int flags) | | 1958 | ipmi_detach(device_t self, int flags) |
1928 | { | | 1959 | { |
1929 | struct ipmi_sensor *i; | | 1960 | struct ipmi_sensor *i; |
1930 | int rc; | | 1961 | int rc; |
1931 | struct ipmi_softc *sc = device_private(self); | | 1962 | struct ipmi_softc *sc = device_private(self); |
1932 | | | 1963 | |
1933 | sc->sc_thread_running = 0; | | 1964 | mutex_enter(&sc->sc_poll_mtx); |
1934 | wakeup(&sc->sc_thread_running); | | 1965 | sc->sc_thread_running = false; |
| | | 1966 | cv_signal(&sc->sc_poll_cv); |
| | | 1967 | mutex_exit(&sc->sc_poll_mtx); |
1935 | | | 1968 | |
1936 | if ((rc = sysmon_wdog_unregister(&sc->sc_wdog)) != 0) { | | 1969 | if ((rc = sysmon_wdog_unregister(&sc->sc_wdog)) != 0) { |
1937 | if (rc == ERESTART) | | 1970 | if (rc == ERESTART) |
1938 | rc = EINTR; | | 1971 | rc = EINTR; |
1939 | return rc; | | 1972 | return rc; |
1940 | } | | 1973 | } |
1941 | | | 1974 | |
1942 | /* cancel any pending countdown */ | | 1975 | /* cancel any pending countdown */ |
1943 | sc->sc_wdog.smw_mode &= ~WDOG_MODE_MASK; | | 1976 | sc->sc_wdog.smw_mode &= ~WDOG_MODE_MASK; |
1944 | sc->sc_wdog.smw_mode |= WDOG_MODE_DISARMED; | | 1977 | sc->sc_wdog.smw_mode |= WDOG_MODE_DISARMED; |
1945 | sc->sc_wdog.smw_period = WDOG_PERIOD_DEFAULT; | | 1978 | sc->sc_wdog.smw_period = WDOG_PERIOD_DEFAULT; |
1946 | | | 1979 | |
1947 | if ((rc = ipmi_watchdog_setmode(&sc->sc_wdog)) != 0) | | 1980 | if ((rc = ipmi_watchdog_setmode(&sc->sc_wdog)) != 0) |
| @@ -1957,86 +1990,97 @@ ipmi_detach(device_t self, int flags) | | | @@ -1957,86 +1990,97 @@ ipmi_detach(device_t self, int flags) |
1957 | | | 1990 | |
1958 | while ((i = SLIST_FIRST(&ipmi_sensor_list)) != NULL) { | | 1991 | while ((i = SLIST_FIRST(&ipmi_sensor_list)) != NULL) { |
1959 | SLIST_REMOVE_HEAD(&ipmi_sensor_list, i_list); | | 1992 | SLIST_REMOVE_HEAD(&ipmi_sensor_list, i_list); |
1960 | free(i, M_DEVBUF); | | 1993 | free(i, M_DEVBUF); |
1961 | } | | 1994 | } |
1962 | | | 1995 | |
1963 | if (sc->sc_sensor != NULL) { | | 1996 | if (sc->sc_sensor != NULL) { |
1964 | free(sc->sc_sensor, M_DEVBUF); | | 1997 | free(sc->sc_sensor, M_DEVBUF); |
1965 | sc->sc_sensor = NULL; | | 1998 | sc->sc_sensor = NULL; |
1966 | } | | 1999 | } |
1967 | | | 2000 | |
1968 | ipmi_unmap_regs(sc); | | 2001 | ipmi_unmap_regs(sc); |
1969 | | | 2002 | |
1970 | callout_destroy(&sc->sc_callout); | | 2003 | cv_destroy(&sc->sc_poll_cv); |
1971 | mutex_destroy(&sc->sc_lock); | | 2004 | mutex_destroy(&sc->sc_poll_mtx); |
| | | 2005 | cv_destroy(&sc->sc_cmd_sleep); |
| | | 2006 | mutex_destroy(&sc->sc_cmd_mtx); |
1972 | | | 2007 | |
1973 | return 0; | | 2008 | return 0; |
1974 | } | | 2009 | } |
1975 | | | 2010 | |
1976 | int | | 2011 | int |
1977 | ipmi_watchdog_setmode(struct sysmon_wdog *smwdog) | | 2012 | ipmi_watchdog_setmode(struct sysmon_wdog *smwdog) |
1978 | { | | 2013 | { |
1979 | struct ipmi_softc *sc = smwdog->smw_cookie; | | 2014 | struct ipmi_softc *sc = smwdog->smw_cookie; |
1980 | struct ipmi_get_watchdog gwdog; | | 2015 | struct ipmi_get_watchdog gwdog; |
1981 | struct ipmi_set_watchdog swdog; | | 2016 | struct ipmi_set_watchdog swdog; |
1982 | int s, rc, len; | | 2017 | int rc, len; |
1983 | | | 2018 | |
1984 | if (smwdog->smw_period < 10) | | 2019 | if (smwdog->smw_period < 10) |
1985 | return EINVAL; | | 2020 | return EINVAL; |
1986 | if (smwdog->smw_period == WDOG_PERIOD_DEFAULT) | | 2021 | if (smwdog->smw_period == WDOG_PERIOD_DEFAULT) |
1987 | sc->sc_wdog.smw_period = 10; | | 2022 | sc->sc_wdog.smw_period = 10; |
1988 | else | | 2023 | else |
1989 | sc->sc_wdog.smw_period = smwdog->smw_period; | | 2024 | sc->sc_wdog.smw_period = smwdog->smw_period; |
1990 | | | 2025 | |
1991 | s = splsoftclock(); | | 2026 | mutex_enter(&sc->sc_cmd_mtx); |
1992 | /* see if we can properly task to the watchdog */ | | 2027 | /* see if we can properly task to the watchdog */ |
1993 | rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN, | | 2028 | rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN, |
1994 | APP_GET_WATCHDOG_TIMER, 0, NULL); | | 2029 | APP_GET_WATCHDOG_TIMER, 0, NULL); |
1995 | rc = ipmi_recvcmd(sc, sizeof(gwdog), &len, &gwdog); | | 2030 | rc = ipmi_recvcmd(sc, sizeof(gwdog), &len, &gwdog); |
| | | 2031 | mutex_exit(&sc->sc_cmd_mtx); |
1996 | if (rc) { | | 2032 | if (rc) { |
1997 | printf("ipmi: APP_GET_WATCHDOG_TIMER returned 0x%x\n", rc); | | 2033 | printf("ipmi: APP_GET_WATCHDOG_TIMER returned 0x%x\n", rc); |
1998 | splx(s); | | | |
1999 | return EIO; | | 2034 | return EIO; |
2000 | } | | 2035 | } |
2001 | | | 2036 | |
2002 | memset(&swdog, 0, sizeof(swdog)); | | 2037 | memset(&swdog, 0, sizeof(swdog)); |
2003 | /* Period is 10ths/sec */ | | 2038 | /* Period is 10ths/sec */ |
2004 | swdog.wdog_timeout = htole32(sc->sc_wdog.smw_period * 10); | | 2039 | swdog.wdog_timeout = htole16(sc->sc_wdog.smw_period * 10); |
2005 | swdog.wdog_action = 0; | | 2040 | if ((smwdog->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) |
2006 | if ((smwdog->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) { | | 2041 | swdog.wdog_action = IPMI_WDOG_ACT_DISABLED; |
2007 | swdog.wdog_action |= IPMI_WDOG_ACT_DISABLED; | | 2042 | else |
2008 | } else { | | 2043 | swdog.wdog_action = IPMI_WDOG_ACT_RESET; |
2009 | swdog.wdog_action |= IPMI_WDOG_ACT_RESET; | | | |
2010 | } | | | |
2011 | swdog.wdog_use = IPMI_WDOG_USE_USE_OS; | | 2044 | swdog.wdog_use = IPMI_WDOG_USE_USE_OS; |
2012 | | | 2045 | |
2013 | rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN, | | 2046 | mutex_enter(&sc->sc_cmd_mtx); |
2014 | APP_SET_WATCHDOG_TIMER, sizeof(swdog), &swdog); | | 2047 | if ((rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN, |
2015 | rc = ipmi_recvcmd(sc, 0, &len, NULL); | | 2048 | APP_SET_WATCHDOG_TIMER, sizeof(swdog), &swdog)) == 0) |
2016 | splx(s); | | 2049 | rc = ipmi_recvcmd(sc, 0, &len, NULL); |
| | | 2050 | mutex_exit(&sc->sc_cmd_mtx); |
2017 | if (rc) { | | 2051 | if (rc) { |
2018 | printf("ipmi: APP_SET_WATCHDOG_TIMER returned 0x%x\n", rc); | | 2052 | printf("ipmi: APP_SET_WATCHDOG_TIMER returned 0x%x\n", rc); |
2019 | return EIO; | | 2053 | return EIO; |
2020 | } | | 2054 | } |
2021 | | | 2055 | |
2022 | return (0); | | 2056 | return (0); |
2023 | } | | 2057 | } |
2024 | | | 2058 | |
2025 | int | | 2059 | int |
2026 | ipmi_watchdog_tickle(struct sysmon_wdog *smwdog) | | 2060 | ipmi_watchdog_tickle(struct sysmon_wdog *smwdog) |
2027 | { | | 2061 | { |
2028 | struct ipmi_softc *sc = smwdog->smw_cookie; | | 2062 | struct ipmi_softc *sc = smwdog->smw_cookie; |
2029 | int s, rc, len; | | | |
2030 | | | 2063 | |
2031 | s = splsoftclock(); | | 2064 | mutex_enter(&sc->sc_poll_mtx); |
| | | 2065 | sc->sc_tickle_due = true; |
| | | 2066 | cv_signal(&sc->sc_poll_cv); |
| | | 2067 | mutex_exit(&sc->sc_poll_mtx); |
| | | 2068 | return 0; |
| | | 2069 | } |
| | | 2070 | |
| | | 2071 | void |
| | | 2072 | ipmi_dotickle(struct ipmi_softc *sc) |
| | | 2073 | { |
| | | 2074 | int rc, len; |
| | | 2075 | |
| | | 2076 | mutex_enter(&sc->sc_cmd_mtx); |
2032 | /* tickle the watchdog */ | | 2077 | /* tickle the watchdog */ |
2033 | rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN, | | 2078 | if ((rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN, |
2034 | APP_RESET_WATCHDOG, 0, NULL); | | 2079 | APP_RESET_WATCHDOG, 0, NULL)) == 0) |
2035 | rc = ipmi_recvcmd(sc, 0, &len, NULL); | | 2080 | rc = ipmi_recvcmd(sc, 0, &len, NULL); |
2036 | splx(s); | | 2081 | mutex_exit(&sc->sc_cmd_mtx); |
2037 | if (rc) { | | 2082 | if (rc != 0) { |
2038 | printf("ipmi: watchdog tickle returned 0x%x\n", rc); | | 2083 | printf("%s: watchdog tickle returned 0x%x\n", |
2039 | return EIO; | | 2084 | device_xname(sc->sc_dev), rc); |
2040 | } | | 2085 | } |
2041 | return (0); | | | |
2042 | } | | 2086 | } |