Line data Source code
1 : /* $OpenBSD: ipmi.c,v 1.102 2018/06/15 12:21:41 yasuoka Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2015 Masao Uebayashi
5 : * Copyright (c) 2005 Jordan Hargrave
6 : * All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
21 : * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 : * SUCH DAMAGE.
28 : */
29 :
30 : #include <sys/param.h>
31 : #include <sys/systm.h>
32 : #include <sys/kernel.h>
33 : #include <sys/device.h>
34 : #include <sys/ioctl.h>
35 : #include <sys/extent.h>
36 : #include <sys/sensors.h>
37 : #include <sys/malloc.h>
38 : #include <sys/kthread.h>
39 : #include <sys/task.h>
40 :
41 : #include <machine/bus.h>
42 : #include <machine/smbiosvar.h>
43 :
44 : #include <dev/isa/isareg.h>
45 : #include <dev/isa/isavar.h>
46 :
47 : #include <dev/ipmivar.h>
48 : #include <dev/ipmi.h>
49 :
50 : struct ipmi_sensor {
51 : u_int8_t *i_sdr;
52 : int i_num;
53 : int stype;
54 : int etype;
55 : struct ksensor i_sensor;
56 : SLIST_ENTRY(ipmi_sensor) list;
57 : };
58 :
59 : int ipmi_enabled = 0;
60 :
61 : #define SENSOR_REFRESH_RATE (5 * hz)
62 :
63 : #define SMBIOS_TYPE_IPMI 0x26
64 :
65 : #define DEVNAME(s) ((s)->sc_dev.dv_xname)
66 :
67 : /*
68 : * Format of SMBIOS IPMI Flags
69 : *
70 : * bit0: interrupt trigger mode (1=level, 0=edge)
71 : * bit1: interrupt polarity (1=active high, 0=active low)
72 : * bit2: reserved
73 : * bit3: address LSB (1=odd,0=even)
74 : * bit4: interrupt (1=specified, 0=not specified)
75 : * bit5: reserved
76 : * bit6/7: register spacing (1,4,2,err)
77 : */
78 : #define SMIPMI_FLAG_IRQLVL (1L << 0)
79 : #define SMIPMI_FLAG_IRQEN (1L << 3)
80 : #define SMIPMI_FLAG_ODDOFFSET (1L << 4)
81 : #define SMIPMI_FLAG_IFSPACING(x) (((x)>>6)&0x3)
82 : #define IPMI_IOSPACING_BYTE 0
83 : #define IPMI_IOSPACING_WORD 2
84 : #define IPMI_IOSPACING_DWORD 1
85 :
86 : #define IPMI_BTMSG_LEN 0
87 : #define IPMI_BTMSG_NFLN 1
88 : #define IPMI_BTMSG_SEQ 2
89 : #define IPMI_BTMSG_CMD 3
90 : #define IPMI_BTMSG_CCODE 4
91 : #define IPMI_BTMSG_DATASND 4
92 : #define IPMI_BTMSG_DATARCV 5
93 :
94 : #define IPMI_MSG_NFLN 0
95 : #define IPMI_MSG_CMD 1
96 : #define IPMI_MSG_CCODE 2
97 : #define IPMI_MSG_DATASND 2
98 : #define IPMI_MSG_DATARCV 3
99 :
100 : #define IPMI_SENSOR_TYPE_TEMP 0x0101
101 : #define IPMI_SENSOR_TYPE_VOLT 0x0102
102 : #define IPMI_SENSOR_TYPE_FAN 0x0104
103 : #define IPMI_SENSOR_TYPE_INTRUSION 0x6F05
104 : #define IPMI_SENSOR_TYPE_PWRSUPPLY 0x6F08
105 :
106 : #define IPMI_NAME_UNICODE 0x00
107 : #define IPMI_NAME_BCDPLUS 0x01
108 : #define IPMI_NAME_ASCII6BIT 0x02
109 : #define IPMI_NAME_ASCII8BIT 0x03
110 :
111 : #define IPMI_ENTITY_PWRSUPPLY 0x0A
112 :
113 : #define IPMI_INVALID_SENSOR (1L << 5)
114 : #define IPMI_DISABLED_SENSOR (1L << 6)
115 :
116 : #define IPMI_SDR_TYPEFULL 1
117 : #define IPMI_SDR_TYPECOMPACT 2
118 :
119 : #define byteof(x) ((x) >> 3)
120 : #define bitof(x) (1L << ((x) & 0x7))
121 : #define TB(b,m) (data[2+byteof(b)] & bitof(b))
122 :
123 : #ifdef IPMI_DEBUG
124 : int ipmi_dbg = 0;
125 : #define dbg_printf(lvl, fmt...) \
126 : if (ipmi_dbg >= lvl) \
127 : printf(fmt);
128 : #define dbg_dump(lvl, msg, len, buf) \
129 : if (len && ipmi_dbg >= lvl) \
130 : dumpb(msg, len, (const u_int8_t *)(buf));
131 : #else
132 : #define dbg_printf(lvl, fmt...)
133 : #define dbg_dump(lvl, msg, len, buf)
134 : #endif
135 :
136 : long signextend(unsigned long, int);
137 :
138 : SLIST_HEAD(ipmi_sensors_head, ipmi_sensor);
139 : struct ipmi_sensors_head ipmi_sensor_list =
140 : SLIST_HEAD_INITIALIZER(ipmi_sensor_list);
141 :
142 : void dumpb(const char *, int, const u_int8_t *);
143 :
144 : int read_sensor(struct ipmi_softc *, struct ipmi_sensor *);
145 : int add_sdr_sensor(struct ipmi_softc *, u_int8_t *, int);
146 : int get_sdr_partial(struct ipmi_softc *, u_int16_t, u_int16_t,
147 : u_int8_t, u_int8_t, void *, u_int16_t *);
148 : int get_sdr(struct ipmi_softc *, u_int16_t, u_int16_t *);
149 :
150 : int ipmi_sendcmd(struct ipmi_cmd *);
151 : int ipmi_recvcmd(struct ipmi_cmd *);
152 : void ipmi_cmd(struct ipmi_cmd *);
153 : void ipmi_cmd_poll(struct ipmi_cmd *);
154 : void ipmi_cmd_wait(struct ipmi_cmd *);
155 : void ipmi_cmd_wait_cb(void *);
156 :
157 : int ipmi_watchdog(void *, int);
158 : void ipmi_watchdog_tickle(void *);
159 : void ipmi_watchdog_set(void *);
160 :
161 : int ipmi_match(struct device *, void *, void *);
162 : void ipmi_attach(struct device *, struct device *, void *);
163 : int ipmi_activate(struct device *, int);
164 : struct ipmi_softc *ipmilookup(dev_t dev);
165 :
166 : int ipmiopen(dev_t, int, int, struct proc *);
167 : int ipmiclose(dev_t, int, int, struct proc *);
168 : int ipmiioctl(dev_t, u_long, caddr_t, int, struct proc *);
169 :
170 : long ipow(long, int);
171 : long ipmi_convert(u_int8_t, struct sdrtype1 *, long);
172 : int ipmi_sensor_name(char *, int, u_int8_t, u_int8_t *, int);
173 :
174 : /* BMC Helper Functions */
175 : u_int8_t bmc_read(struct ipmi_softc *, int);
176 : void bmc_write(struct ipmi_softc *, int, u_int8_t);
177 : int bmc_io_wait(struct ipmi_softc *, struct ipmi_iowait *);
178 :
179 : void bt_buildmsg(struct ipmi_cmd *);
180 : void cmn_buildmsg(struct ipmi_cmd *);
181 :
182 : int getbits(u_int8_t *, int, int);
183 : int ipmi_sensor_type(int, int, int);
184 :
185 : void ipmi_smbios_probe(struct smbios_ipmi *, struct ipmi_attach_args *);
186 : void ipmi_refresh_sensors(struct ipmi_softc *sc);
187 : int ipmi_map_regs(struct ipmi_softc *sc, struct ipmi_attach_args *ia);
188 : void ipmi_unmap_regs(struct ipmi_softc *);
189 :
190 : void *scan_sig(long, long, int, int, const void *);
191 :
192 : int ipmi_sensor_status(struct ipmi_softc *, struct ipmi_sensor *,
193 : u_int8_t *);
194 :
195 : int add_child_sensors(struct ipmi_softc *, u_int8_t *, int, int, int,
196 : int, int, int, const char *);
197 :
198 : struct ipmi_if kcs_if = {
199 : "KCS",
200 : IPMI_IF_KCS_NREGS,
201 : cmn_buildmsg,
202 : kcs_sendmsg,
203 : kcs_recvmsg,
204 : kcs_reset,
205 : kcs_probe,
206 : IPMI_MSG_DATASND,
207 : IPMI_MSG_DATARCV,
208 : };
209 :
210 : struct ipmi_if smic_if = {
211 : "SMIC",
212 : IPMI_IF_SMIC_NREGS,
213 : cmn_buildmsg,
214 : smic_sendmsg,
215 : smic_recvmsg,
216 : smic_reset,
217 : smic_probe,
218 : IPMI_MSG_DATASND,
219 : IPMI_MSG_DATARCV,
220 : };
221 :
222 : struct ipmi_if bt_if = {
223 : "BT",
224 : IPMI_IF_BT_NREGS,
225 : bt_buildmsg,
226 : bt_sendmsg,
227 : bt_recvmsg,
228 : bt_reset,
229 : bt_probe,
230 : IPMI_BTMSG_DATASND,
231 : IPMI_BTMSG_DATARCV,
232 : };
233 :
234 : struct ipmi_if *ipmi_get_if(int);
235 :
236 : struct ipmi_if *
237 0 : ipmi_get_if(int iftype)
238 : {
239 0 : switch (iftype) {
240 : case IPMI_IF_KCS:
241 0 : return (&kcs_if);
242 : case IPMI_IF_SMIC:
243 0 : return (&smic_if);
244 : case IPMI_IF_BT:
245 0 : return (&bt_if);
246 : }
247 :
248 0 : return (NULL);
249 0 : }
250 :
251 : /*
252 : * BMC Helper Functions
253 : */
254 : u_int8_t
255 0 : bmc_read(struct ipmi_softc *sc, int offset)
256 : {
257 0 : return (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
258 : offset * sc->sc_if_iospacing));
259 : }
260 :
261 : void
262 0 : bmc_write(struct ipmi_softc *sc, int offset, u_int8_t val)
263 : {
264 0 : bus_space_write_1(sc->sc_iot, sc->sc_ioh,
265 : offset * sc->sc_if_iospacing, val);
266 0 : }
267 :
268 : int
269 0 : bmc_io_wait(struct ipmi_softc *sc, struct ipmi_iowait *a)
270 : {
271 0 : volatile u_int8_t v;
272 : int count = 5000000; /* == 5s XXX can be shorter */
273 :
274 0 : while (count--) {
275 0 : v = bmc_read(sc, a->offset);
276 0 : if ((v & a->mask) == a->value)
277 0 : return v;
278 :
279 0 : delay(1);
280 : }
281 :
282 : dbg_printf(1, "%s: bmc_io_wait fails : *v=%.2x m=%.2x b=%.2x %s\n",
283 : DEVNAME(sc), v, a->mask, a->value, a->lbl);
284 0 : return (-1);
285 :
286 0 : }
287 :
288 : #define RSSA_MASK 0xff
289 : #define LUN_MASK 0x3
290 : #define NETFN_LUN(nf,ln) (((nf) << 2) | ((ln) & LUN_MASK))
291 :
292 : /*
293 : * BT interface
294 : */
295 : #define _BT_CTRL_REG 0
296 : #define BT_CLR_WR_PTR (1L << 0)
297 : #define BT_CLR_RD_PTR (1L << 1)
298 : #define BT_HOST2BMC_ATN (1L << 2)
299 : #define BT_BMC2HOST_ATN (1L << 3)
300 : #define BT_EVT_ATN (1L << 4)
301 : #define BT_HOST_BUSY (1L << 6)
302 : #define BT_BMC_BUSY (1L << 7)
303 :
304 : #define BT_READY (BT_HOST_BUSY|BT_HOST2BMC_ATN|BT_BMC2HOST_ATN)
305 :
306 : #define _BT_DATAIN_REG 1
307 : #define _BT_DATAOUT_REG 1
308 :
309 : #define _BT_INTMASK_REG 2
310 : #define BT_IM_HIRQ_PEND (1L << 1)
311 : #define BT_IM_SCI_EN (1L << 2)
312 : #define BT_IM_SMI_EN (1L << 3)
313 : #define BT_IM_NMI2SMI (1L << 4)
314 :
315 : int bt_read(struct ipmi_softc *, int);
316 : int bt_write(struct ipmi_softc *, int, uint8_t);
317 :
318 : int
319 0 : bt_read(struct ipmi_softc *sc, int reg)
320 : {
321 0 : return bmc_read(sc, reg);
322 : }
323 :
324 : int
325 0 : bt_write(struct ipmi_softc *sc, int reg, uint8_t data)
326 : {
327 0 : struct ipmi_iowait a;
328 :
329 0 : a.offset = _BT_CTRL_REG;
330 0 : a.mask = BT_BMC_BUSY;
331 0 : a.value = 0;
332 0 : a.lbl = "bt_write";
333 0 : if (bmc_io_wait(sc, &a) < 0)
334 0 : return (-1);
335 :
336 0 : bmc_write(sc, reg, data);
337 0 : return (0);
338 0 : }
339 :
340 : int
341 0 : bt_sendmsg(struct ipmi_cmd *c)
342 : {
343 0 : struct ipmi_softc *sc = c->c_sc;
344 0 : struct ipmi_iowait a;
345 : int i;
346 :
347 0 : bt_write(sc, _BT_CTRL_REG, BT_CLR_WR_PTR);
348 0 : for (i = 0; i < c->c_txlen; i++)
349 0 : bt_write(sc, _BT_DATAOUT_REG, sc->sc_buf[i]);
350 :
351 0 : bt_write(sc, _BT_CTRL_REG, BT_HOST2BMC_ATN);
352 0 : a.offset = _BT_CTRL_REG;
353 0 : a.mask = BT_HOST2BMC_ATN | BT_BMC_BUSY;
354 0 : a.value = 0;
355 0 : a.lbl = "bt_sendwait";
356 0 : if (bmc_io_wait(sc, &a) < 0)
357 0 : return (-1);
358 :
359 0 : return (0);
360 0 : }
361 :
362 : int
363 0 : bt_recvmsg(struct ipmi_cmd *c)
364 : {
365 0 : struct ipmi_softc *sc = c->c_sc;
366 0 : struct ipmi_iowait a;
367 : u_int8_t len, v, i, j;
368 :
369 0 : a.offset = _BT_CTRL_REG;
370 0 : a.mask = BT_BMC2HOST_ATN;
371 0 : a.value = BT_BMC2HOST_ATN;
372 0 : a.lbl = "bt_recvwait";
373 0 : if (bmc_io_wait(sc, &a) < 0)
374 0 : return (-1);
375 :
376 0 : bt_write(sc, _BT_CTRL_REG, BT_HOST_BUSY);
377 0 : bt_write(sc, _BT_CTRL_REG, BT_BMC2HOST_ATN);
378 0 : bt_write(sc, _BT_CTRL_REG, BT_CLR_RD_PTR);
379 0 : len = bt_read(sc, _BT_DATAIN_REG);
380 0 : for (i = IPMI_BTMSG_NFLN, j = 0; i <= len; i++) {
381 0 : v = bt_read(sc, _BT_DATAIN_REG);
382 0 : if (i != IPMI_BTMSG_SEQ)
383 0 : *(sc->sc_buf + j++) = v;
384 : }
385 0 : bt_write(sc, _BT_CTRL_REG, BT_HOST_BUSY);
386 0 : c->c_rxlen = len - 1;
387 :
388 0 : return (0);
389 0 : }
390 :
391 : int
392 0 : bt_reset(struct ipmi_softc *sc)
393 : {
394 0 : return (-1);
395 : }
396 :
397 : int
398 0 : bt_probe(struct ipmi_softc *sc)
399 : {
400 : u_int8_t rv;
401 :
402 0 : rv = bmc_read(sc, _BT_CTRL_REG);
403 0 : rv &= BT_HOST_BUSY;
404 0 : rv |= BT_CLR_WR_PTR|BT_CLR_RD_PTR|BT_BMC2HOST_ATN|BT_HOST2BMC_ATN;
405 0 : bmc_write(sc, _BT_CTRL_REG, rv);
406 :
407 0 : rv = bmc_read(sc, _BT_INTMASK_REG);
408 0 : rv &= BT_IM_SCI_EN|BT_IM_SMI_EN|BT_IM_NMI2SMI;
409 0 : rv |= BT_IM_HIRQ_PEND;
410 0 : bmc_write(sc, _BT_INTMASK_REG, rv);
411 :
412 : #if 0
413 : printf("bt_probe: %2x\n", v);
414 : printf(" WR : %2x\n", v & BT_CLR_WR_PTR);
415 : printf(" RD : %2x\n", v & BT_CLR_RD_PTR);
416 : printf(" H2B : %2x\n", v & BT_HOST2BMC_ATN);
417 : printf(" B2H : %2x\n", v & BT_BMC2HOST_ATN);
418 : printf(" EVT : %2x\n", v & BT_EVT_ATN);
419 : printf(" HBSY : %2x\n", v & BT_HOST_BUSY);
420 : printf(" BBSY : %2x\n", v & BT_BMC_BUSY);
421 : #endif
422 0 : return (0);
423 : }
424 :
425 : /*
426 : * SMIC interface
427 : */
428 : #define _SMIC_DATAIN_REG 0
429 : #define _SMIC_DATAOUT_REG 0
430 :
431 : #define _SMIC_CTRL_REG 1
432 : #define SMS_CC_GET_STATUS 0x40
433 : #define SMS_CC_START_TRANSFER 0x41
434 : #define SMS_CC_NEXT_TRANSFER 0x42
435 : #define SMS_CC_END_TRANSFER 0x43
436 : #define SMS_CC_START_RECEIVE 0x44
437 : #define SMS_CC_NEXT_RECEIVE 0x45
438 : #define SMS_CC_END_RECEIVE 0x46
439 : #define SMS_CC_TRANSFER_ABORT 0x47
440 :
441 : #define SMS_SC_READY 0xc0
442 : #define SMS_SC_WRITE_START 0xc1
443 : #define SMS_SC_WRITE_NEXT 0xc2
444 : #define SMS_SC_WRITE_END 0xc3
445 : #define SMS_SC_READ_START 0xc4
446 : #define SMS_SC_READ_NEXT 0xc5
447 : #define SMS_SC_READ_END 0xc6
448 :
449 : #define _SMIC_FLAG_REG 2
450 : #define SMIC_BUSY (1L << 0)
451 : #define SMIC_SMS_ATN (1L << 2)
452 : #define SMIC_EVT_ATN (1L << 3)
453 : #define SMIC_SMI (1L << 4)
454 : #define SMIC_TX_DATA_RDY (1L << 6)
455 : #define SMIC_RX_DATA_RDY (1L << 7)
456 :
457 : int smic_wait(struct ipmi_softc *, u_int8_t, u_int8_t, const char *);
458 : int smic_write_cmd_data(struct ipmi_softc *, u_int8_t, const u_int8_t *);
459 : int smic_read_data(struct ipmi_softc *, u_int8_t *);
460 :
461 : int
462 0 : smic_wait(struct ipmi_softc *sc, u_int8_t mask, u_int8_t val, const char *lbl)
463 : {
464 0 : struct ipmi_iowait a;
465 : int v;
466 :
467 : /* Wait for expected flag bits */
468 0 : a.offset = _SMIC_FLAG_REG;
469 0 : a.mask = mask;
470 0 : a.value = val;
471 0 : a.lbl = "smicwait";
472 0 : v = bmc_io_wait(sc, &a);
473 0 : if (v < 0)
474 0 : return (-1);
475 :
476 : /* Return current status */
477 0 : v = bmc_read(sc, _SMIC_CTRL_REG);
478 : dbg_printf(99, "smic_wait = %.2x\n", v);
479 0 : return (v);
480 0 : }
481 :
482 : int
483 0 : smic_write_cmd_data(struct ipmi_softc *sc, u_int8_t cmd, const u_int8_t *data)
484 : {
485 : int sts, v;
486 :
487 : dbg_printf(50, "smic_wcd: %.2x %.2x\n", cmd, data ? *data : -1);
488 0 : sts = smic_wait(sc, SMIC_TX_DATA_RDY | SMIC_BUSY, SMIC_TX_DATA_RDY,
489 : "smic_write_cmd_data ready");
490 0 : if (sts < 0)
491 0 : return (sts);
492 :
493 0 : bmc_write(sc, _SMIC_CTRL_REG, cmd);
494 0 : if (data)
495 0 : bmc_write(sc, _SMIC_DATAOUT_REG, *data);
496 :
497 : /* Toggle BUSY bit, then wait for busy bit to clear */
498 0 : v = bmc_read(sc, _SMIC_FLAG_REG);
499 0 : bmc_write(sc, _SMIC_FLAG_REG, v | SMIC_BUSY);
500 :
501 0 : return (smic_wait(sc, SMIC_BUSY, 0, "smic_write_cmd_data busy"));
502 0 : }
503 :
504 : int
505 0 : smic_read_data(struct ipmi_softc *sc, u_int8_t *data)
506 : {
507 : int sts;
508 :
509 0 : sts = smic_wait(sc, SMIC_RX_DATA_RDY | SMIC_BUSY, SMIC_RX_DATA_RDY,
510 : "smic_read_data");
511 0 : if (sts >= 0) {
512 0 : *data = bmc_read(sc, _SMIC_DATAIN_REG);
513 : dbg_printf(50, "smic_readdata: %.2x\n", *data);
514 0 : }
515 0 : return (sts);
516 : }
517 :
518 : #define ErrStat(a,b) if (a) printf(b);
519 :
520 : int
521 0 : smic_sendmsg(struct ipmi_cmd *c)
522 : {
523 0 : struct ipmi_softc *sc = c->c_sc;
524 : int sts, idx;
525 :
526 0 : sts = smic_write_cmd_data(sc, SMS_CC_START_TRANSFER, &sc->sc_buf[0]);
527 0 : ErrStat(sts != SMS_SC_WRITE_START, "wstart");
528 0 : for (idx = 1; idx < c->c_txlen - 1; idx++) {
529 0 : sts = smic_write_cmd_data(sc, SMS_CC_NEXT_TRANSFER,
530 : &sc->sc_buf[idx]);
531 0 : ErrStat(sts != SMS_SC_WRITE_NEXT, "write");
532 : }
533 0 : sts = smic_write_cmd_data(sc, SMS_CC_END_TRANSFER, &sc->sc_buf[idx]);
534 0 : if (sts != SMS_SC_WRITE_END) {
535 : dbg_printf(50, "smic_sendmsg %d/%d = %.2x\n", idx, c->c_txlen, sts);
536 0 : return (-1);
537 : }
538 :
539 0 : return (0);
540 0 : }
541 :
542 : int
543 0 : smic_recvmsg(struct ipmi_cmd *c)
544 : {
545 0 : struct ipmi_softc *sc = c->c_sc;
546 : int sts, idx;
547 :
548 0 : c->c_rxlen = 0;
549 0 : sts = smic_wait(sc, SMIC_RX_DATA_RDY, SMIC_RX_DATA_RDY, "smic_recvmsg");
550 0 : if (sts < 0)
551 0 : return (-1);
552 :
553 0 : sts = smic_write_cmd_data(sc, SMS_CC_START_RECEIVE, NULL);
554 0 : ErrStat(sts != SMS_SC_READ_START, "rstart");
555 0 : for (idx = 0;; ) {
556 0 : sts = smic_read_data(sc, &sc->sc_buf[idx++]);
557 0 : if (sts != SMS_SC_READ_START && sts != SMS_SC_READ_NEXT)
558 : break;
559 0 : smic_write_cmd_data(sc, SMS_CC_NEXT_RECEIVE, NULL);
560 : }
561 0 : ErrStat(sts != SMS_SC_READ_END, "rend");
562 :
563 0 : c->c_rxlen = idx;
564 :
565 0 : sts = smic_write_cmd_data(sc, SMS_CC_END_RECEIVE, NULL);
566 0 : if (sts != SMS_SC_READY) {
567 : dbg_printf(50, "smic_recvmsg %d/%d = %.2x\n", idx, c->c_maxrxlen, sts);
568 0 : return (-1);
569 : }
570 :
571 0 : return (0);
572 0 : }
573 :
574 : int
575 0 : smic_reset(struct ipmi_softc *sc)
576 : {
577 0 : return (-1);
578 : }
579 :
580 : int
581 0 : smic_probe(struct ipmi_softc *sc)
582 : {
583 : /* Flag register should not be 0xFF on a good system */
584 0 : if (bmc_read(sc, _SMIC_FLAG_REG) == 0xFF)
585 0 : return (-1);
586 :
587 0 : return (0);
588 0 : }
589 :
590 : /*
591 : * KCS interface
592 : */
593 : #define _KCS_DATAIN_REGISTER 0
594 : #define _KCS_DATAOUT_REGISTER 0
595 : #define KCS_READ_NEXT 0x68
596 :
597 : #define _KCS_COMMAND_REGISTER 1
598 : #define KCS_GET_STATUS 0x60
599 : #define KCS_WRITE_START 0x61
600 : #define KCS_WRITE_END 0x62
601 :
602 : #define _KCS_STATUS_REGISTER 1
603 : #define KCS_OBF (1L << 0)
604 : #define KCS_IBF (1L << 1)
605 : #define KCS_SMS_ATN (1L << 2)
606 : #define KCS_CD (1L << 3)
607 : #define KCS_OEM1 (1L << 4)
608 : #define KCS_OEM2 (1L << 5)
609 : #define KCS_STATE_MASK 0xc0
610 : #define KCS_IDLE_STATE 0x00
611 : #define KCS_READ_STATE 0x40
612 : #define KCS_WRITE_STATE 0x80
613 : #define KCS_ERROR_STATE 0xC0
614 :
615 : int kcs_wait(struct ipmi_softc *, u_int8_t, u_int8_t, const char *);
616 : int kcs_write_cmd(struct ipmi_softc *, u_int8_t);
617 : int kcs_write_data(struct ipmi_softc *, u_int8_t);
618 : int kcs_read_data(struct ipmi_softc *, u_int8_t *);
619 :
620 : int
621 0 : kcs_wait(struct ipmi_softc *sc, u_int8_t mask, u_int8_t value, const char *lbl)
622 : {
623 0 : struct ipmi_iowait a;
624 : int v;
625 :
626 0 : a.offset = _KCS_STATUS_REGISTER;
627 0 : a.mask = mask;
628 0 : a.value = value;
629 0 : a.lbl = lbl;
630 0 : v = bmc_io_wait(sc, &a);
631 0 : if (v < 0)
632 0 : return (v);
633 :
634 : /* Check if output buffer full, read dummy byte */
635 0 : if ((v & (KCS_OBF | KCS_STATE_MASK)) == (KCS_OBF | KCS_WRITE_STATE))
636 0 : bmc_read(sc, _KCS_DATAIN_REGISTER);
637 :
638 : /* Check for error state */
639 0 : if ((v & KCS_STATE_MASK) == KCS_ERROR_STATE) {
640 0 : bmc_write(sc, _KCS_COMMAND_REGISTER, KCS_GET_STATUS);
641 0 : while (bmc_read(sc, _KCS_STATUS_REGISTER) & KCS_IBF)
642 0 : continue;
643 0 : printf("%s: error code: %x\n", DEVNAME(sc),
644 0 : bmc_read(sc, _KCS_DATAIN_REGISTER));
645 0 : }
646 :
647 0 : return (v & KCS_STATE_MASK);
648 0 : }
649 :
650 : int
651 0 : kcs_write_cmd(struct ipmi_softc *sc, u_int8_t cmd)
652 : {
653 : /* ASSERT: IBF and OBF are clear */
654 : dbg_printf(50, "kcswritecmd: %.2x\n", cmd);
655 0 : bmc_write(sc, _KCS_COMMAND_REGISTER, cmd);
656 :
657 0 : return (kcs_wait(sc, KCS_IBF, 0, "write_cmd"));
658 : }
659 :
660 : int
661 0 : kcs_write_data(struct ipmi_softc *sc, u_int8_t data)
662 : {
663 : /* ASSERT: IBF and OBF are clear */
664 : dbg_printf(50, "kcswritedata: %.2x\n", data);
665 0 : bmc_write(sc, _KCS_DATAOUT_REGISTER, data);
666 :
667 0 : return (kcs_wait(sc, KCS_IBF, 0, "write_data"));
668 : }
669 :
670 : int
671 0 : kcs_read_data(struct ipmi_softc *sc, u_int8_t * data)
672 : {
673 : int sts;
674 :
675 0 : sts = kcs_wait(sc, KCS_IBF | KCS_OBF, KCS_OBF, "read_data");
676 0 : if (sts != KCS_READ_STATE)
677 0 : return (sts);
678 :
679 : /* ASSERT: OBF is set read data, request next byte */
680 0 : *data = bmc_read(sc, _KCS_DATAIN_REGISTER);
681 0 : bmc_write(sc, _KCS_DATAOUT_REGISTER, KCS_READ_NEXT);
682 :
683 : dbg_printf(50, "kcsreaddata: %.2x\n", *data);
684 :
685 0 : return (sts);
686 0 : }
687 :
688 : /* Exported KCS functions */
689 : int
690 0 : kcs_sendmsg(struct ipmi_cmd *c)
691 : {
692 0 : struct ipmi_softc *sc = c->c_sc;
693 : int idx, sts;
694 :
695 : /* ASSERT: IBF is clear */
696 : dbg_dump(50, "kcs sendmsg", c->c_txlen, sc->sc_buf);
697 0 : sts = kcs_write_cmd(sc, KCS_WRITE_START);
698 0 : for (idx = 0; idx < c->c_txlen; idx++) {
699 0 : if (idx == c->c_txlen - 1)
700 0 : sts = kcs_write_cmd(sc, KCS_WRITE_END);
701 :
702 0 : if (sts != KCS_WRITE_STATE)
703 : break;
704 :
705 0 : sts = kcs_write_data(sc, sc->sc_buf[idx]);
706 : }
707 0 : if (sts != KCS_READ_STATE) {
708 : dbg_printf(1, "kcs sendmsg = %d/%d <%.2x>\n", idx, c->c_txlen, sts);
709 : dbg_dump(1, "kcs_sendmsg", c->c_txlen, sc->sc_buf);
710 0 : return (-1);
711 : }
712 :
713 0 : return (0);
714 0 : }
715 :
716 : int
717 0 : kcs_recvmsg(struct ipmi_cmd *c)
718 : {
719 0 : struct ipmi_softc *sc = c->c_sc;
720 : int idx, sts;
721 :
722 0 : for (idx = 0; idx < c->c_maxrxlen; idx++) {
723 0 : sts = kcs_read_data(sc, &sc->sc_buf[idx]);
724 0 : if (sts != KCS_READ_STATE)
725 : break;
726 : }
727 0 : sts = kcs_wait(sc, KCS_IBF, 0, "recv");
728 0 : c->c_rxlen = idx;
729 0 : if (sts != KCS_IDLE_STATE) {
730 : dbg_printf(1, "kcs recvmsg = %d/%d <%.2x>\n", idx, c->c_maxrxlen, sts);
731 0 : return (-1);
732 : }
733 :
734 : dbg_dump(50, "kcs recvmsg", idx, sc->sc_buf);
735 :
736 0 : return (0);
737 0 : }
738 :
739 : int
740 0 : kcs_reset(struct ipmi_softc *sc)
741 : {
742 0 : return (-1);
743 : }
744 :
745 : int
746 0 : kcs_probe(struct ipmi_softc *sc)
747 : {
748 : u_int8_t v;
749 :
750 0 : v = bmc_read(sc, _KCS_STATUS_REGISTER);
751 0 : if ((v & KCS_STATE_MASK) == KCS_ERROR_STATE)
752 0 : return (1);
753 : #if 0
754 : printf("kcs_probe: %2x\n", v);
755 : printf(" STS: %2x\n", v & KCS_STATE_MASK);
756 : printf(" ATN: %2x\n", v & KCS_SMS_ATN);
757 : printf(" C/D: %2x\n", v & KCS_CD);
758 : printf(" IBF: %2x\n", v & KCS_IBF);
759 : printf(" OBF: %2x\n", v & KCS_OBF);
760 : #endif
761 0 : return (0);
762 0 : }
763 :
764 : /*
765 : * IPMI code
766 : */
767 : #define READ_SMS_BUFFER 0x37
768 : #define WRITE_I2C 0x50
769 :
770 : #define GET_MESSAGE_CMD 0x33
771 : #define SEND_MESSAGE_CMD 0x34
772 :
773 : #define IPMB_CHANNEL_NUMBER 0
774 :
775 : #define PUBLIC_BUS 0
776 :
777 : #define MIN_I2C_PACKET_SIZE 3
778 : #define MIN_IMB_PACKET_SIZE 7 /* one byte for cksum */
779 :
780 : #define MIN_BTBMC_REQ_SIZE 4
781 : #define MIN_BTBMC_RSP_SIZE 5
782 : #define MIN_BMC_REQ_SIZE 2
783 : #define MIN_BMC_RSP_SIZE 3
784 :
785 : #define BMC_SA 0x20 /* BMC/ESM3 */
786 : #define FPC_SA 0x22 /* front panel */
787 : #define BP_SA 0xC0 /* Primary Backplane */
788 : #define BP2_SA 0xC2 /* Secondary Backplane */
789 : #define PBP_SA 0xC4 /* Peripheral Backplane */
790 : #define DRAC_SA 0x28 /* DRAC-III */
791 : #define DRAC3_SA 0x30 /* DRAC-III */
792 : #define BMC_LUN 0
793 : #define SMS_LUN 2
794 :
795 : struct ipmi_request {
796 : u_int8_t rsSa;
797 : u_int8_t rsLun;
798 : u_int8_t netFn;
799 : u_int8_t cmd;
800 : u_int8_t data_len;
801 : u_int8_t *data;
802 : };
803 :
804 : struct ipmi_response {
805 : u_int8_t cCode;
806 : u_int8_t data_len;
807 : u_int8_t *data;
808 : };
809 :
810 : struct ipmi_bmc_request {
811 : u_int8_t bmc_nfLn;
812 : u_int8_t bmc_cmd;
813 : u_int8_t bmc_data_len;
814 : u_int8_t bmc_data[1];
815 : };
816 :
817 : struct ipmi_bmc_response {
818 : u_int8_t bmc_nfLn;
819 : u_int8_t bmc_cmd;
820 : u_int8_t bmc_cCode;
821 : u_int8_t bmc_data_len;
822 : u_int8_t bmc_data[1];
823 : };
824 :
825 : struct cfattach ipmi_ca = {
826 : sizeof(struct ipmi_softc), ipmi_match, ipmi_attach,
827 : NULL, ipmi_activate
828 : };
829 :
830 : struct cfdriver ipmi_cd = {
831 : NULL, "ipmi", DV_DULL
832 : };
833 :
834 : /* Scan memory for signature */
835 : void *
836 0 : scan_sig(long start, long end, int skip, int len, const void *data)
837 : {
838 : void *va;
839 :
840 0 : while (start < end) {
841 0 : va = ISA_HOLE_VADDR(start);
842 0 : if (memcmp(va, data, len) == 0)
843 0 : return (va);
844 :
845 0 : start += skip;
846 : }
847 :
848 0 : return (NULL);
849 0 : }
850 :
851 : void
852 0 : dumpb(const char *lbl, int len, const u_int8_t *data)
853 : {
854 : int idx;
855 :
856 0 : printf("%s: ", lbl);
857 0 : for (idx = 0; idx < len; idx++)
858 0 : printf("%.2x ", data[idx]);
859 :
860 0 : printf("\n");
861 0 : }
862 :
863 : void
864 0 : ipmi_smbios_probe(struct smbios_ipmi *pipmi, struct ipmi_attach_args *ia)
865 : {
866 :
867 : dbg_printf(1, "ipmi_smbios_probe: %02x %02x %02x %02x %08llx %02x "
868 : "%02x\n",
869 : pipmi->smipmi_if_type,
870 : pipmi->smipmi_if_rev,
871 : pipmi->smipmi_i2c_address,
872 : pipmi->smipmi_nvram_address,
873 : pipmi->smipmi_base_address,
874 : pipmi->smipmi_base_flags,
875 : pipmi->smipmi_irq);
876 :
877 0 : ia->iaa_if_type = pipmi->smipmi_if_type;
878 0 : ia->iaa_if_rev = pipmi->smipmi_if_rev;
879 0 : ia->iaa_if_irq = (pipmi->smipmi_base_flags & SMIPMI_FLAG_IRQEN) ?
880 0 : pipmi->smipmi_irq : -1;
881 0 : ia->iaa_if_irqlvl = (pipmi->smipmi_base_flags & SMIPMI_FLAG_IRQLVL) ?
882 : IST_LEVEL : IST_EDGE;
883 :
884 0 : switch (SMIPMI_FLAG_IFSPACING(pipmi->smipmi_base_flags)) {
885 : case IPMI_IOSPACING_BYTE:
886 0 : ia->iaa_if_iospacing = 1;
887 0 : break;
888 :
889 : case IPMI_IOSPACING_DWORD:
890 0 : ia->iaa_if_iospacing = 4;
891 0 : break;
892 :
893 : case IPMI_IOSPACING_WORD:
894 0 : ia->iaa_if_iospacing = 2;
895 0 : break;
896 :
897 : default:
898 0 : ia->iaa_if_iospacing = 1;
899 0 : printf("ipmi: unknown register spacing\n");
900 0 : }
901 :
902 : /* Calculate base address (PCI BAR format) */
903 0 : if (pipmi->smipmi_base_address & 0x1) {
904 0 : ia->iaa_if_iotype = 'i';
905 0 : ia->iaa_if_iobase = pipmi->smipmi_base_address & ~0x1;
906 0 : } else {
907 0 : ia->iaa_if_iotype = 'm';
908 0 : ia->iaa_if_iobase = pipmi->smipmi_base_address & ~0xF;
909 : }
910 0 : if (pipmi->smipmi_base_flags & SMIPMI_FLAG_ODDOFFSET)
911 0 : ia->iaa_if_iobase++;
912 :
913 0 : if (pipmi->smipmi_base_flags == 0x7f) {
914 : /* IBM 325 eServer workaround */
915 0 : ia->iaa_if_iospacing = 1;
916 0 : ia->iaa_if_iobase = pipmi->smipmi_base_address;
917 0 : ia->iaa_if_iotype = 'i';
918 0 : return;
919 : }
920 0 : }
921 :
922 : /*
923 : * bt_buildmsg builds an IPMI message from a nfLun, cmd, and data
924 : * This is used by BT protocol
925 : */
926 : void
927 0 : bt_buildmsg(struct ipmi_cmd *c)
928 : {
929 0 : struct ipmi_softc *sc = c->c_sc;
930 0 : u_int8_t *buf = sc->sc_buf;
931 :
932 0 : buf[IPMI_BTMSG_LEN] = c->c_txlen + (IPMI_BTMSG_DATASND - 1);
933 0 : buf[IPMI_BTMSG_NFLN] = NETFN_LUN(c->c_netfn, c->c_rslun);
934 0 : buf[IPMI_BTMSG_SEQ] = sc->sc_btseq++;
935 0 : buf[IPMI_BTMSG_CMD] = c->c_cmd;
936 0 : if (c->c_txlen && c->c_data)
937 0 : memcpy(buf + IPMI_BTMSG_DATASND, c->c_data, c->c_txlen);
938 0 : }
939 :
940 : /*
941 : * cmn_buildmsg builds an IPMI message from a nfLun, cmd, and data
942 : * This is used by both SMIC and KCS protocols
943 : */
944 : void
945 0 : cmn_buildmsg(struct ipmi_cmd *c)
946 : {
947 0 : struct ipmi_softc *sc = c->c_sc;
948 0 : u_int8_t *buf = sc->sc_buf;
949 :
950 0 : buf[IPMI_MSG_NFLN] = NETFN_LUN(c->c_netfn, c->c_rslun);
951 0 : buf[IPMI_MSG_CMD] = c->c_cmd;
952 0 : if (c->c_txlen && c->c_data)
953 0 : memcpy(buf + IPMI_MSG_DATASND, c->c_data, c->c_txlen);
954 0 : }
955 :
956 : /* Send an IPMI command */
957 : int
958 0 : ipmi_sendcmd(struct ipmi_cmd *c)
959 : {
960 0 : struct ipmi_softc *sc = c->c_sc;
961 : int rc = -1;
962 :
963 : dbg_printf(50, "ipmi_sendcmd: rssa=%.2x nfln=%.2x cmd=%.2x len=%.2x\n",
964 : c->c_rssa, NETFN_LUN(c->c_netfn, c->c_rslun), c->c_cmd, c->c_txlen);
965 : dbg_dump(10, " send", c->c_txlen, c->c_data);
966 0 : if (c->c_rssa != BMC_SA) {
967 : #if 0
968 : sc->sc_if->buildmsg(c);
969 : pI2C->bus = (sc->if_ver == 0x09) ?
970 : PUBLIC_BUS :
971 : IPMB_CHANNEL_NUMBER;
972 :
973 : imbreq->rsSa = rssa;
974 : imbreq->nfLn = NETFN_LUN(netfn, rslun);
975 : imbreq->cSum1 = -(imbreq->rsSa + imbreq->nfLn);
976 : imbreq->rqSa = BMC_SA;
977 : imbreq->seqLn = NETFN_LUN(sc->imb_seq++, SMS_LUN);
978 : imbreq->cmd = cmd;
979 : if (txlen)
980 : memcpy(imbreq->data, data, txlen);
981 : /* Set message checksum */
982 : imbreq->data[txlen] = cksum8(&imbreq->rqSa, txlen + 3);
983 : #endif
984 : goto done;
985 : } else
986 0 : sc->sc_if->buildmsg(c);
987 :
988 0 : c->c_txlen += sc->sc_if->datasnd;
989 0 : rc = sc->sc_if->sendmsg(c);
990 :
991 : done:
992 0 : return (rc);
993 : }
994 :
995 : /* Receive an IPMI command */
996 : int
997 0 : ipmi_recvcmd(struct ipmi_cmd *c)
998 : {
999 0 : struct ipmi_softc *sc = c->c_sc;
1000 0 : u_int8_t *buf = sc->sc_buf, rc = 0;
1001 :
1002 : /* Receive message from interface, copy out result data */
1003 0 : c->c_maxrxlen += sc->sc_if->datarcv;
1004 0 : if (sc->sc_if->recvmsg(c) ||
1005 0 : c->c_rxlen < sc->sc_if->datarcv) {
1006 0 : return (-1);
1007 : }
1008 :
1009 0 : c->c_rxlen -= sc->sc_if->datarcv;
1010 0 : if (c->c_rxlen > 0 && c->c_data)
1011 0 : memcpy(c->c_data, buf + sc->sc_if->datarcv, c->c_rxlen);
1012 :
1013 0 : rc = buf[IPMI_MSG_CCODE];
1014 : #ifdef IPMI_DEBUG
1015 : if (rc != 0)
1016 : dbg_printf(1, "ipmi_recvcmd: nfln=%.2x cmd=%.2x err=%.2x\n",
1017 : buf[IPMI_MSG_NFLN], buf[IPMI_MSG_CMD], buf[IPMI_MSG_CCODE]);
1018 : #endif
1019 :
1020 : dbg_printf(50, "ipmi_recvcmd: nfln=%.2x cmd=%.2x err=%.2x len=%.2x\n",
1021 : buf[IPMI_MSG_NFLN], buf[IPMI_MSG_CMD], buf[IPMI_MSG_CCODE],
1022 : c->c_rxlen);
1023 : dbg_dump(10, " recv", c->c_rxlen, c->c_data);
1024 :
1025 0 : return (rc);
1026 0 : }
1027 :
1028 : void
1029 0 : ipmi_cmd(struct ipmi_cmd *c)
1030 : {
1031 0 : if (cold || panicstr != NULL)
1032 0 : ipmi_cmd_poll(c);
1033 : else
1034 0 : ipmi_cmd_wait(c);
1035 0 : }
1036 :
1037 : void
1038 0 : ipmi_cmd_poll(struct ipmi_cmd *c)
1039 : {
1040 0 : mtx_enter(&c->c_sc->sc_cmd_mtx);
1041 :
1042 0 : if ((c->c_ccode = ipmi_sendcmd(c)))
1043 0 : printf("%s: sendcmd fails\n", DEVNAME(c->c_sc));
1044 : else
1045 0 : c->c_ccode = ipmi_recvcmd(c);
1046 :
1047 0 : mtx_leave(&c->c_sc->sc_cmd_mtx);
1048 0 : }
1049 :
1050 : void
1051 0 : ipmi_cmd_wait(struct ipmi_cmd *c)
1052 : {
1053 0 : struct task t;
1054 : int res;
1055 :
1056 0 : task_set(&t, ipmi_cmd_wait_cb, c);
1057 0 : res = task_add(c->c_sc->sc_cmd_taskq, &t);
1058 0 : KASSERT(res == 1);
1059 :
1060 0 : tsleep(c, PWAIT, "ipmicmd", 0);
1061 :
1062 0 : res = task_del(c->c_sc->sc_cmd_taskq, &t);
1063 0 : KASSERT(res == 0);
1064 0 : }
1065 :
1066 : void
1067 0 : ipmi_cmd_wait_cb(void *arg)
1068 : {
1069 0 : struct ipmi_cmd *c = arg;
1070 :
1071 0 : ipmi_cmd_poll(c);
1072 0 : wakeup(c);
1073 0 : }
1074 :
1075 : /* Read a partial SDR entry */
1076 : int
1077 0 : get_sdr_partial(struct ipmi_softc *sc, u_int16_t recordId, u_int16_t reserveId,
1078 : u_int8_t offset, u_int8_t length, void *buffer, u_int16_t *nxtRecordId)
1079 : {
1080 0 : u_int8_t cmd[IPMI_GET_WDOG_MAX + 255]; /* 8 + max of length */
1081 : int len;
1082 :
1083 0 : ((u_int16_t *) cmd)[0] = reserveId;
1084 0 : ((u_int16_t *) cmd)[1] = recordId;
1085 0 : cmd[4] = offset;
1086 0 : cmd[5] = length;
1087 :
1088 0 : struct ipmi_cmd c;
1089 0 : c.c_sc = sc;
1090 0 : c.c_rssa = BMC_SA;
1091 0 : c.c_rslun = BMC_LUN;
1092 0 : c.c_netfn = STORAGE_NETFN;
1093 0 : c.c_cmd = STORAGE_GET_SDR;
1094 0 : c.c_txlen = IPMI_SET_WDOG_MAX;
1095 0 : c.c_rxlen = 0;
1096 0 : c.c_maxrxlen = 8 + length;
1097 0 : c.c_data = cmd;
1098 0 : ipmi_cmd(&c);
1099 0 : len = c.c_rxlen;
1100 :
1101 0 : if (nxtRecordId)
1102 0 : *nxtRecordId = *(uint16_t *) cmd;
1103 0 : if (len > 2)
1104 0 : memcpy(buffer, cmd + 2, len - 2);
1105 : else
1106 0 : return (1);
1107 :
1108 0 : return (0);
1109 0 : }
1110 :
1111 : int maxsdrlen = 0x10;
1112 :
1113 : /* Read an entire SDR; pass to add sensor */
1114 : int
1115 0 : get_sdr(struct ipmi_softc *sc, u_int16_t recid, u_int16_t *nxtrec)
1116 : {
1117 0 : u_int16_t resid = 0;
1118 : int len, sdrlen, offset;
1119 : u_int8_t *psdr;
1120 0 : struct sdrhdr shdr;
1121 :
1122 : /* Reserve SDR */
1123 0 : struct ipmi_cmd c;
1124 0 : c.c_sc = sc;
1125 0 : c.c_rssa = BMC_SA;
1126 0 : c.c_rslun = BMC_LUN;
1127 0 : c.c_netfn = STORAGE_NETFN;
1128 0 : c.c_cmd = STORAGE_RESERVE_SDR;
1129 0 : c.c_txlen = 0;
1130 0 : c.c_maxrxlen = sizeof(resid);
1131 0 : c.c_rxlen = 0;
1132 0 : c.c_data = &resid;
1133 0 : ipmi_cmd(&c);
1134 :
1135 : /* Get SDR Header */
1136 0 : if (get_sdr_partial(sc, recid, resid, 0, sizeof shdr, &shdr, nxtrec)) {
1137 0 : printf("%s: get header fails\n", DEVNAME(sc));
1138 0 : return (1);
1139 : }
1140 : /* Allocate space for entire SDR Length of SDR in header does not
1141 : * include header length */
1142 0 : sdrlen = sizeof(shdr) + shdr.record_length;
1143 0 : psdr = malloc(sdrlen, M_DEVBUF, M_NOWAIT);
1144 0 : if (psdr == NULL)
1145 0 : return (1);
1146 :
1147 0 : memcpy(psdr, &shdr, sizeof(shdr));
1148 :
1149 : /* Read SDR Data maxsdrlen bytes at a time */
1150 0 : for (offset = sizeof(shdr); offset < sdrlen; offset += maxsdrlen) {
1151 0 : len = sdrlen - offset;
1152 0 : if (len > maxsdrlen)
1153 0 : len = maxsdrlen;
1154 :
1155 0 : if (get_sdr_partial(sc, recid, resid, offset, len,
1156 0 : psdr + offset, NULL)) {
1157 0 : printf("%s: get chunk: %d,%d fails\n", DEVNAME(sc),
1158 : offset, len);
1159 0 : free(psdr, M_DEVBUF, sdrlen);
1160 0 : return (1);
1161 : }
1162 : }
1163 :
1164 : /* Add SDR to sensor list, if not wanted, free buffer */
1165 0 : if (add_sdr_sensor(sc, psdr, sdrlen) == 0)
1166 0 : free(psdr, M_DEVBUF, sdrlen);
1167 :
1168 0 : return (0);
1169 0 : }
1170 :
1171 : int
1172 0 : getbits(u_int8_t *bytes, int bitpos, int bitlen)
1173 : {
1174 : int v;
1175 : int mask;
1176 :
1177 0 : bitpos += bitlen - 1;
1178 0 : for (v = 0; bitlen--;) {
1179 0 : v <<= 1;
1180 0 : mask = 1L << (bitpos & 7);
1181 0 : if (bytes[bitpos >> 3] & mask)
1182 0 : v |= 1;
1183 0 : bitpos--;
1184 : }
1185 :
1186 0 : return (v);
1187 : }
1188 :
1189 : /* Decode IPMI sensor name */
1190 : int
1191 0 : ipmi_sensor_name(char *name, int len, u_int8_t typelen, u_int8_t *bits,
1192 : int bitslen)
1193 : {
1194 : int i, slen;
1195 0 : char bcdplus[] = "0123456789 -.:,_";
1196 :
1197 0 : slen = typelen & 0x1F;
1198 0 : switch (typelen >> 6) {
1199 : case IPMI_NAME_UNICODE:
1200 : //unicode
1201 : break;
1202 :
1203 : case IPMI_NAME_BCDPLUS:
1204 : /* Characters are encoded in 4-bit BCDPLUS */
1205 0 : if (len < slen * 2 + 1)
1206 0 : slen = (len >> 1) - 1;
1207 0 : if (slen > bitslen)
1208 0 : return (0);
1209 0 : for (i = 0; i < slen; i++) {
1210 0 : *(name++) = bcdplus[bits[i] >> 4];
1211 0 : *(name++) = bcdplus[bits[i] & 0xF];
1212 : }
1213 : break;
1214 :
1215 : case IPMI_NAME_ASCII6BIT:
1216 : /* Characters are encoded in 6-bit ASCII
1217 : * 0x00 - 0x3F maps to 0x20 - 0x5F */
1218 : /* XXX: need to calculate max len: slen = 3/4 * len */
1219 0 : if (len < slen + 1)
1220 0 : slen = len - 1;
1221 0 : if (slen * 6 / 8 > bitslen)
1222 0 : return (0);
1223 0 : for (i = 0; i < slen * 8; i += 6) {
1224 0 : *(name++) = getbits(bits, i, 6) + ' ';
1225 : }
1226 : break;
1227 :
1228 : case IPMI_NAME_ASCII8BIT:
1229 : /* Characters are 8-bit ascii */
1230 0 : if (len < slen + 1)
1231 0 : slen = len - 1;
1232 0 : if (slen > bitslen)
1233 0 : return (0);
1234 0 : while (slen--)
1235 0 : *(name++) = *(bits++);
1236 : break;
1237 : }
1238 0 : *name = 0;
1239 :
1240 0 : return (1);
1241 0 : }
1242 :
1243 : /* Calculate val * 10^exp */
1244 : long
1245 0 : ipow(long val, int exp)
1246 : {
1247 0 : while (exp > 0) {
1248 0 : val *= 10;
1249 0 : exp--;
1250 : }
1251 :
1252 0 : while (exp < 0) {
1253 0 : val /= 10;
1254 0 : exp++;
1255 : }
1256 :
1257 0 : return (val);
1258 : }
1259 :
1260 : /* Sign extend a n-bit value */
1261 : long
1262 0 : signextend(unsigned long val, int bits)
1263 : {
1264 0 : long msk = (1L << (bits-1))-1;
1265 :
1266 0 : return (-(val & ~msk) | val);
1267 : }
1268 :
1269 : /* Convert IPMI reading from sensor factors */
1270 : long
1271 0 : ipmi_convert(u_int8_t v, struct sdrtype1 *s1, long adj)
1272 : {
1273 : short M, B;
1274 : char K1, K2;
1275 : long val;
1276 :
1277 : /* Calculate linear reading variables */
1278 0 : M = signextend((((short)(s1->m_tolerance & 0xC0)) << 2) + s1->m, 10);
1279 0 : B = signextend((((short)(s1->b_accuracy & 0xC0)) << 2) + s1->b, 10);
1280 0 : K1 = signextend(s1->rbexp & 0xF, 4);
1281 0 : K2 = signextend(s1->rbexp >> 4, 4);
1282 :
1283 : /* Calculate sensor reading:
1284 : * y = L((M * v + (B * 10^K1)) * 10^(K2+adj)
1285 : *
1286 : * This commutes out to:
1287 : * y = L(M*v * 10^(K2+adj) + B * 10^(K1+K2+adj)); */
1288 0 : val = ipow(M * v, K2 + adj) + ipow(B, K1 + K2 + adj);
1289 :
1290 : /* Linearization function: y = f(x) 0 : y = x 1 : y = ln(x) 2 : y =
1291 : * log10(x) 3 : y = log2(x) 4 : y = e^x 5 : y = 10^x 6 : y = 2^x 7 : y
1292 : * = 1/x 8 : y = x^2 9 : y = x^3 10 : y = square root(x) 11 : y = cube
1293 : * root(x) */
1294 0 : return (val);
1295 : }
1296 :
1297 : int
1298 0 : ipmi_sensor_status(struct ipmi_softc *sc, struct ipmi_sensor *psensor,
1299 : u_int8_t *reading)
1300 : {
1301 0 : struct sdrtype1 *s1 = (struct sdrtype1 *)psensor->i_sdr;
1302 : int etype;
1303 :
1304 : /* Get reading of sensor */
1305 0 : switch (psensor->i_sensor.type) {
1306 : case SENSOR_TEMP:
1307 0 : psensor->i_sensor.value = ipmi_convert(reading[0], s1, 6);
1308 0 : psensor->i_sensor.value += 273150000;
1309 0 : break;
1310 :
1311 : case SENSOR_VOLTS_DC:
1312 0 : psensor->i_sensor.value = ipmi_convert(reading[0], s1, 6);
1313 0 : break;
1314 :
1315 : case SENSOR_FANRPM:
1316 0 : psensor->i_sensor.value = ipmi_convert(reading[0], s1, 0);
1317 0 : if (((s1->units1>>3)&0x7) == 0x3)
1318 0 : psensor->i_sensor.value *= 60; // RPS -> RPM
1319 : break;
1320 : default:
1321 : break;
1322 : }
1323 :
1324 : /* Return Sensor Status */
1325 0 : etype = (psensor->etype << 8) + psensor->stype;
1326 0 : switch (etype) {
1327 : case IPMI_SENSOR_TYPE_TEMP:
1328 : case IPMI_SENSOR_TYPE_VOLT:
1329 : case IPMI_SENSOR_TYPE_FAN:
1330 : /* non-recoverable threshold */
1331 0 : if (reading[2] & ((1 << 5) | (1 << 2)))
1332 0 : return (SENSOR_S_CRIT);
1333 : /* critical threshold */
1334 0 : else if (reading[2] & ((1 << 4) | (1 << 1)))
1335 0 : return (SENSOR_S_CRIT);
1336 : /* non-critical threshold */
1337 0 : else if (reading[2] & ((1 << 3) | (1 << 0)))
1338 0 : return (SENSOR_S_WARN);
1339 : break;
1340 :
1341 : case IPMI_SENSOR_TYPE_INTRUSION:
1342 0 : psensor->i_sensor.value = (reading[2] & 1) ? 1 : 0;
1343 0 : if (reading[2] & 0x1)
1344 0 : return (SENSOR_S_CRIT);
1345 : break;
1346 :
1347 : case IPMI_SENSOR_TYPE_PWRSUPPLY:
1348 : /* Reading: 1 = present+powered, 0 = otherwise */
1349 0 : psensor->i_sensor.value = (reading[2] & 1) ? 1 : 0;
1350 0 : if (reading[2] & 0x10) {
1351 : /* XXX: Need sysctl type for Power Supply types
1352 : * ok: power supply installed && powered
1353 : * warn: power supply installed && !powered
1354 : * crit: power supply !installed
1355 : */
1356 0 : return (SENSOR_S_CRIT);
1357 : }
1358 0 : if (reading[2] & 0x08) {
1359 : /* Power supply AC lost */
1360 0 : return (SENSOR_S_WARN);
1361 : }
1362 : break;
1363 : }
1364 :
1365 0 : return (SENSOR_S_OK);
1366 0 : }
1367 :
1368 : int
1369 0 : read_sensor(struct ipmi_softc *sc, struct ipmi_sensor *psensor)
1370 : {
1371 0 : struct sdrtype1 *s1 = (struct sdrtype1 *) psensor->i_sdr;
1372 0 : u_int8_t data[8];
1373 : int rv = -1;
1374 :
1375 0 : memset(data, 0, sizeof(data));
1376 0 : data[0] = psensor->i_num;
1377 :
1378 0 : struct ipmi_cmd c;
1379 0 : c.c_sc = sc;
1380 0 : c.c_rssa = s1->owner_id;
1381 0 : c.c_rslun = s1->owner_lun;
1382 0 : c.c_netfn = SE_NETFN;
1383 0 : c.c_cmd = SE_GET_SENSOR_READING;
1384 0 : c.c_txlen = 1;
1385 0 : c.c_maxrxlen = sizeof(data);
1386 0 : c.c_rxlen = 0;
1387 0 : c.c_data = data;
1388 0 : ipmi_cmd(&c);
1389 :
1390 : dbg_printf(10, "values=%.2x %.2x %.2x %.2x %s\n",
1391 : data[0],data[1],data[2],data[3], psensor->i_sensor.desc);
1392 0 : psensor->i_sensor.flags &= ~SENSOR_FINVALID;
1393 0 : if ((data[1] & IPMI_INVALID_SENSOR) ||
1394 0 : ((data[1] & IPMI_DISABLED_SENSOR) == 0 && data[0] == 0))
1395 0 : psensor->i_sensor.flags |= SENSOR_FINVALID;
1396 0 : psensor->i_sensor.status = ipmi_sensor_status(sc, psensor, data);
1397 : rv = 0;
1398 0 : return (rv);
1399 0 : }
1400 :
1401 : int
1402 0 : ipmi_sensor_type(int type, int ext_type, int entity)
1403 : {
1404 0 : switch (ext_type << 8L | type) {
1405 : case IPMI_SENSOR_TYPE_TEMP:
1406 0 : return (SENSOR_TEMP);
1407 :
1408 : case IPMI_SENSOR_TYPE_VOLT:
1409 0 : return (SENSOR_VOLTS_DC);
1410 :
1411 : case IPMI_SENSOR_TYPE_FAN:
1412 0 : return (SENSOR_FANRPM);
1413 :
1414 : case IPMI_SENSOR_TYPE_PWRSUPPLY:
1415 0 : if (entity == IPMI_ENTITY_PWRSUPPLY)
1416 0 : return (SENSOR_INDICATOR);
1417 : break;
1418 :
1419 : case IPMI_SENSOR_TYPE_INTRUSION:
1420 0 : return (SENSOR_INDICATOR);
1421 : }
1422 :
1423 0 : return (-1);
1424 0 : }
1425 :
1426 : /* Add Sensor to BSD Sysctl interface */
1427 : int
1428 0 : add_sdr_sensor(struct ipmi_softc *sc, u_int8_t *psdr, int sdrlen)
1429 : {
1430 : int rc;
1431 0 : struct sdrtype1 *s1 = (struct sdrtype1 *)psdr;
1432 0 : struct sdrtype2 *s2 = (struct sdrtype2 *)psdr;
1433 0 : char name[64];
1434 :
1435 0 : switch (s1->sdrhdr.record_type) {
1436 : case IPMI_SDR_TYPEFULL:
1437 0 : rc = ipmi_sensor_name(name, sizeof(name), s1->typelen,
1438 0 : s1->name, sdrlen - (int)offsetof(struct sdrtype1, name));
1439 0 : if (rc == 0)
1440 0 : return (0);
1441 0 : rc = add_child_sensors(sc, psdr, 1, s1->sensor_num,
1442 0 : s1->sensor_type, s1->event_code, 0, s1->entity_id, name);
1443 0 : break;
1444 :
1445 : case IPMI_SDR_TYPECOMPACT:
1446 0 : rc = ipmi_sensor_name(name, sizeof(name), s2->typelen,
1447 0 : s2->name, sdrlen - (int)offsetof(struct sdrtype2, name));
1448 0 : if (rc == 0)
1449 0 : return (0);
1450 0 : rc = add_child_sensors(sc, psdr, s2->share1 & 0xF,
1451 0 : s2->sensor_num, s2->sensor_type, s2->event_code,
1452 0 : s2->share2 & 0x7F, s2->entity_id, name);
1453 0 : break;
1454 :
1455 : default:
1456 0 : return (0);
1457 : }
1458 :
1459 0 : return rc;
1460 0 : }
1461 :
1462 : int
1463 0 : add_child_sensors(struct ipmi_softc *sc, u_int8_t *psdr, int count,
1464 : int sensor_num, int sensor_type, int ext_type, int sensor_base,
1465 : int entity, const char *name)
1466 : {
1467 : int typ, idx;
1468 : struct ipmi_sensor *psensor;
1469 : #ifdef IPMI_DEBUG
1470 : struct sdrtype1 *s1 = (struct sdrtype1 *)psdr;
1471 : #endif
1472 :
1473 0 : typ = ipmi_sensor_type(sensor_type, ext_type, entity);
1474 0 : if (typ == -1) {
1475 : dbg_printf(5, "Unknown sensor type:%.2x et:%.2x sn:%.2x "
1476 : "name:%s\n", sensor_type, ext_type, sensor_num, name);
1477 0 : return 0;
1478 : }
1479 0 : for (idx = 0; idx < count; idx++) {
1480 0 : psensor = malloc(sizeof(*psensor), M_DEVBUF, M_NOWAIT | M_ZERO);
1481 0 : if (psensor == NULL)
1482 : break;
1483 :
1484 : /* Initialize BSD Sensor info */
1485 0 : psensor->i_sdr = psdr;
1486 0 : psensor->i_num = sensor_num + idx;
1487 0 : psensor->stype = sensor_type;
1488 0 : psensor->etype = ext_type;
1489 0 : psensor->i_sensor.type = typ;
1490 0 : if (count > 1)
1491 0 : snprintf(psensor->i_sensor.desc,
1492 : sizeof(psensor->i_sensor.desc),
1493 0 : "%s - %d", name, sensor_base + idx);
1494 : else
1495 0 : strlcpy(psensor->i_sensor.desc, name,
1496 : sizeof(psensor->i_sensor.desc));
1497 :
1498 : dbg_printf(5, "add sensor:%.4x %.2x:%d ent:%.2x:%.2x %s\n",
1499 : s1->sdrhdr.record_id, s1->sensor_type,
1500 : typ, s1->entity_id, s1->entity_instance,
1501 : psensor->i_sensor.desc);
1502 0 : if (read_sensor(sc, psensor) == 0) {
1503 0 : SLIST_INSERT_HEAD(&ipmi_sensor_list, psensor, list);
1504 0 : sensor_attach(&sc->sc_sensordev, &psensor->i_sensor);
1505 : dbg_printf(5, " reading: %lld [%s]\n",
1506 : psensor->i_sensor.value,
1507 : psensor->i_sensor.desc);
1508 0 : }
1509 : }
1510 :
1511 0 : return (1);
1512 0 : }
1513 :
1514 : /* Handle IPMI Timer - reread sensor values */
1515 : void
1516 0 : ipmi_refresh_sensors(struct ipmi_softc *sc)
1517 : {
1518 0 : if (SLIST_EMPTY(&ipmi_sensor_list))
1519 : return;
1520 :
1521 0 : sc->current_sensor = SLIST_NEXT(sc->current_sensor, list);
1522 0 : if (sc->current_sensor == NULL)
1523 0 : sc->current_sensor = SLIST_FIRST(&ipmi_sensor_list);
1524 :
1525 0 : if (read_sensor(sc, sc->current_sensor)) {
1526 : dbg_printf(1, "%s: error reading: %s\n", DEVNAME(sc),
1527 : sc->current_sensor->i_sensor.desc);
1528 : return;
1529 : }
1530 0 : }
1531 :
1532 : int
1533 0 : ipmi_map_regs(struct ipmi_softc *sc, struct ipmi_attach_args *ia)
1534 : {
1535 0 : sc->sc_if = ipmi_get_if(ia->iaa_if_type);
1536 0 : if (sc->sc_if == NULL)
1537 0 : return (-1);
1538 :
1539 0 : if (ia->iaa_if_iotype == 'i')
1540 0 : sc->sc_iot = ia->iaa_iot;
1541 : else
1542 0 : sc->sc_iot = ia->iaa_memt;
1543 :
1544 0 : sc->sc_if_rev = ia->iaa_if_rev;
1545 0 : sc->sc_if_iospacing = ia->iaa_if_iospacing;
1546 0 : if (bus_space_map(sc->sc_iot, ia->iaa_if_iobase,
1547 0 : sc->sc_if->nregs * sc->sc_if_iospacing,
1548 0 : 0, &sc->sc_ioh)) {
1549 0 : printf("%s: bus_space_map(%lx %x %x 0 %p) failed\n",
1550 0 : DEVNAME(sc),
1551 0 : (unsigned long)sc->sc_iot, ia->iaa_if_iobase,
1552 0 : sc->sc_if->nregs * sc->sc_if_iospacing, &sc->sc_ioh);
1553 0 : return (-1);
1554 : }
1555 0 : return (0);
1556 0 : }
1557 :
1558 : void
1559 0 : ipmi_unmap_regs(struct ipmi_softc *sc)
1560 : {
1561 0 : bus_space_unmap(sc->sc_iot, sc->sc_ioh,
1562 0 : sc->sc_if->nregs * sc->sc_if_iospacing);
1563 0 : }
1564 :
1565 : void
1566 0 : ipmi_poll_thread(void *arg)
1567 : {
1568 0 : struct ipmi_thread *thread = arg;
1569 0 : struct ipmi_softc *sc = thread->sc;
1570 0 : u_int16_t rec;
1571 :
1572 : /* Scan SDRs, add sensors */
1573 0 : for (rec = 0; rec != 0xFFFF;) {
1574 0 : if (get_sdr(sc, rec, &rec)) {
1575 0 : ipmi_unmap_regs(sc);
1576 0 : printf("%s: no SDRs IPMI disabled\n", DEVNAME(sc));
1577 0 : goto done;
1578 : }
1579 0 : while (tsleep(sc, PWAIT, "ipmirun", 1) != EWOULDBLOCK)
1580 0 : continue;
1581 : }
1582 :
1583 : /* initialize sensor list for thread */
1584 0 : if (SLIST_EMPTY(&ipmi_sensor_list))
1585 : goto done;
1586 : else
1587 0 : sc->current_sensor = SLIST_FIRST(&ipmi_sensor_list);
1588 :
1589 0 : strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
1590 : sizeof(sc->sc_sensordev.xname));
1591 0 : sensordev_install(&sc->sc_sensordev);
1592 :
1593 0 : while (thread->running) {
1594 0 : ipmi_refresh_sensors(sc);
1595 0 : tsleep(thread, PWAIT, "ipmi_poll", SENSOR_REFRESH_RATE);
1596 : }
1597 :
1598 : done:
1599 0 : kthread_exit(0);
1600 : }
1601 :
1602 : void
1603 0 : ipmi_create_thread(void *arg)
1604 : {
1605 0 : struct ipmi_softc *sc = arg;
1606 :
1607 0 : if (kthread_create(ipmi_poll_thread, sc->sc_thread, NULL,
1608 0 : DEVNAME(sc)) != 0) {
1609 0 : printf("%s: unable to create run thread, ipmi disabled\n",
1610 : DEVNAME(sc));
1611 0 : return;
1612 : }
1613 0 : }
1614 :
1615 : int
1616 0 : ipmi_probe(void *aux)
1617 : {
1618 0 : struct ipmi_attach_args *ia = aux;
1619 : struct dmd_ipmi *pipmi;
1620 0 : struct smbtable tbl;
1621 :
1622 0 : tbl.cookie = 0;
1623 0 : if (smbios_find_table(SMBIOS_TYPE_IPMIDEV, &tbl))
1624 0 : ipmi_smbios_probe(tbl.tblhdr, ia);
1625 : else {
1626 0 : pipmi = (struct dmd_ipmi *)scan_sig(0xC0000L, 0xFFFFFL, 16, 4,
1627 : "IPMI");
1628 : /* XXX hack to find Dell PowerEdge 8450 */
1629 0 : if (pipmi == NULL) {
1630 : /* no IPMI found */
1631 0 : return (0);
1632 : }
1633 :
1634 : /* we have an IPMI signature, fill in attach arg structure */
1635 0 : ia->iaa_if_type = pipmi->dmd_if_type;
1636 0 : ia->iaa_if_rev = pipmi->dmd_if_rev;
1637 : }
1638 :
1639 0 : return (1);
1640 0 : }
1641 :
1642 : int
1643 0 : ipmi_match(struct device *parent, void *match, void *aux)
1644 : {
1645 : struct ipmi_softc *sc;
1646 0 : struct ipmi_attach_args *ia = aux;
1647 0 : struct cfdata *cf = match;
1648 0 : u_int8_t cmd[32];
1649 : int rv = 0;
1650 :
1651 0 : if (strcmp(ia->iaa_name, cf->cf_driver->cd_name))
1652 0 : return (0);
1653 :
1654 : /* XXX local softc is wrong wrong wrong */
1655 0 : sc = malloc(sizeof(*sc), M_TEMP, M_WAITOK | M_ZERO);
1656 0 : mtx_init(&sc->sc_cmd_mtx, IPL_MPFLOOR);
1657 0 : strlcpy(sc->sc_dev.dv_xname, "ipmi0", sizeof(sc->sc_dev.dv_xname));
1658 :
1659 : /* Map registers */
1660 0 : if (ipmi_map_regs(sc, ia) == 0) {
1661 0 : sc->sc_if->probe(sc);
1662 :
1663 : /* Identify BMC device early to detect lying bios */
1664 0 : struct ipmi_cmd c;
1665 0 : c.c_sc = sc;
1666 0 : c.c_rssa = BMC_SA;
1667 0 : c.c_rslun = BMC_LUN;
1668 0 : c.c_netfn = APP_NETFN;
1669 0 : c.c_cmd = APP_GET_DEVICE_ID;
1670 0 : c.c_txlen = 0;
1671 0 : c.c_maxrxlen = sizeof(cmd);
1672 0 : c.c_rxlen = 0;
1673 0 : c.c_data = cmd;
1674 0 : ipmi_cmd(&c);
1675 :
1676 : dbg_dump(1, "bmc data", c.c_rxlen, cmd);
1677 : rv = 1; /* GETID worked, we got IPMI */
1678 0 : ipmi_unmap_regs(sc);
1679 0 : }
1680 :
1681 0 : free(sc, M_TEMP, sizeof(*sc));
1682 :
1683 0 : return (rv);
1684 0 : }
1685 :
1686 : void
1687 0 : ipmi_attach(struct device *parent, struct device *self, void *aux)
1688 : {
1689 0 : struct ipmi_softc *sc = (void *) self;
1690 0 : struct ipmi_attach_args *ia = aux;
1691 0 : struct ipmi_cmd *c = &sc->sc_ioctl.cmd;
1692 :
1693 : /* Map registers */
1694 0 : ipmi_map_regs(sc, ia);
1695 :
1696 0 : sc->sc_thread = malloc(sizeof(struct ipmi_thread), M_DEVBUF, M_NOWAIT);
1697 0 : if (sc->sc_thread == NULL) {
1698 0 : printf(": unable to allocate thread\n");
1699 0 : return;
1700 : }
1701 0 : sc->sc_thread->sc = sc;
1702 0 : sc->sc_thread->running = 1;
1703 :
1704 : /* Setup threads */
1705 0 : kthread_create_deferred(ipmi_create_thread, sc);
1706 :
1707 0 : printf(": version %d.%d interface %s %sbase 0x%x/%x spacing %d",
1708 0 : ia->iaa_if_rev >> 4, ia->iaa_if_rev & 0xF, sc->sc_if->name,
1709 0 : ia->iaa_if_iotype == 'i' ? "io" : "mem", ia->iaa_if_iobase,
1710 0 : ia->iaa_if_iospacing * sc->sc_if->nregs, ia->iaa_if_iospacing);
1711 0 : if (ia->iaa_if_irq != -1)
1712 0 : printf(" irq %d", ia->iaa_if_irq);
1713 0 : printf("\n");
1714 :
1715 : /* setup flag to exclude iic */
1716 0 : ipmi_enabled = 1;
1717 :
1718 : /* Setup Watchdog timer */
1719 0 : sc->sc_wdog_period = 0;
1720 0 : task_set(&sc->sc_wdog_tickle_task, ipmi_watchdog_tickle, sc);
1721 0 : wdog_register(ipmi_watchdog, sc);
1722 :
1723 0 : rw_init(&sc->sc_ioctl.lock, DEVNAME(sc));
1724 0 : sc->sc_ioctl.req.msgid = -1;
1725 0 : c->c_sc = sc;
1726 0 : c->c_ccode = -1;
1727 :
1728 0 : sc->sc_cmd_taskq = taskq_create("ipmicmd", 1, IPL_NONE, TASKQ_MPSAFE);
1729 0 : mtx_init(&sc->sc_cmd_mtx, IPL_MPFLOOR);
1730 0 : }
1731 :
1732 : int
1733 0 : ipmi_activate(struct device *self, int act)
1734 : {
1735 0 : switch (act) {
1736 : case DVACT_POWERDOWN:
1737 0 : wdog_shutdown(self);
1738 0 : break;
1739 : }
1740 :
1741 0 : return (0);
1742 : }
1743 :
1744 : struct ipmi_softc *
1745 0 : ipmilookup(dev_t dev)
1746 : {
1747 0 : return (struct ipmi_softc *)device_lookup(&ipmi_cd, minor(dev));
1748 : }
1749 :
1750 : int
1751 0 : ipmiopen(dev_t dev, int flags, int mode, struct proc *p)
1752 : {
1753 0 : struct ipmi_softc *sc = ipmilookup(dev);
1754 :
1755 0 : if (sc == NULL)
1756 0 : return (ENXIO);
1757 0 : return (0);
1758 0 : }
1759 :
1760 : int
1761 0 : ipmiclose(dev_t dev, int flags, int mode, struct proc *p)
1762 : {
1763 0 : struct ipmi_softc *sc = ipmilookup(dev);
1764 :
1765 0 : if (sc == NULL)
1766 0 : return (ENXIO);
1767 0 : return (0);
1768 0 : }
1769 :
1770 : int
1771 0 : ipmiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *proc)
1772 : {
1773 0 : struct ipmi_softc *sc = ipmilookup(dev);
1774 0 : struct ipmi_req *req = (struct ipmi_req *)data;
1775 0 : struct ipmi_recv *recv = (struct ipmi_recv *)data;
1776 0 : struct ipmi_cmd *c = &sc->sc_ioctl.cmd;
1777 : int iv;
1778 : int len;
1779 0 : u_char ccode;
1780 : int rc = 0;
1781 :
1782 0 : if (sc == NULL)
1783 0 : return (ENXIO);
1784 :
1785 0 : rw_enter_write(&sc->sc_ioctl.lock);
1786 :
1787 0 : c->c_maxrxlen = sizeof(sc->sc_ioctl.buf);
1788 0 : c->c_data = sc->sc_ioctl.buf;
1789 :
1790 0 : switch (cmd) {
1791 : case IPMICTL_SEND_COMMAND:
1792 0 : if (req->msgid == -1) {
1793 : rc = EINVAL;
1794 0 : goto reset;
1795 : }
1796 0 : if (sc->sc_ioctl.req.msgid != -1) {
1797 : rc = EBUSY;
1798 0 : goto reset;
1799 : }
1800 0 : len = req->msg.data_len;
1801 0 : if (len < 0) {
1802 : rc = EINVAL;
1803 0 : goto reset;
1804 : }
1805 0 : if (len > c->c_maxrxlen) {
1806 : rc = E2BIG;
1807 0 : goto reset;
1808 : }
1809 0 : sc->sc_ioctl.req = *req;
1810 0 : c->c_ccode = -1;
1811 0 : rc = copyin(req->msg.data, c->c_data, len);
1812 0 : if (rc != 0)
1813 : goto reset;
1814 0 : KASSERT(c->c_ccode == -1);
1815 :
1816 : /* Execute a command synchronously. */
1817 0 : c->c_netfn = req->msg.netfn;
1818 0 : c->c_cmd = req->msg.cmd;
1819 0 : c->c_txlen = req->msg.data_len;
1820 0 : c->c_rxlen = 0;
1821 0 : ipmi_cmd(c);
1822 0 : break;
1823 : case IPMICTL_RECEIVE_MSG_TRUNC:
1824 : case IPMICTL_RECEIVE_MSG:
1825 0 : if (sc->sc_ioctl.req.msgid == -1) {
1826 : rc = EINVAL;
1827 0 : goto reset;
1828 : }
1829 0 : if (c->c_ccode == -1) {
1830 : rc = EAGAIN;
1831 0 : goto reset;
1832 : }
1833 0 : ccode = c->c_ccode & 0xff;
1834 0 : rc = copyout(&ccode, recv->msg.data, 1);
1835 0 : if (rc != 0)
1836 : goto reset;
1837 :
1838 : /* Return a command result. */
1839 0 : recv->recv_type = IPMI_RESPONSE_RECV_TYPE;
1840 0 : recv->msgid = sc->sc_ioctl.req.msgid;
1841 0 : recv->msg.netfn = sc->sc_ioctl.req.msg.netfn;
1842 0 : recv->msg.cmd = sc->sc_ioctl.req.msg.cmd;
1843 0 : recv->msg.data_len = c->c_rxlen + 1;
1844 :
1845 0 : rc = copyout(c->c_data, recv->msg.data + 1, c->c_rxlen);
1846 : /* Always reset state after command completion. */
1847 0 : goto reset;
1848 : case IPMICTL_SET_MY_ADDRESS_CMD:
1849 0 : iv = *(int *)data;
1850 0 : if (iv < 0 || iv > RSSA_MASK) {
1851 : rc = EINVAL;
1852 0 : goto reset;
1853 : }
1854 0 : c->c_rssa = iv;
1855 0 : break;
1856 : case IPMICTL_GET_MY_ADDRESS_CMD:
1857 0 : *(int *)data = c->c_rssa;
1858 0 : break;
1859 : case IPMICTL_SET_MY_LUN_CMD:
1860 0 : iv = *(int *)data;
1861 0 : if (iv < 0 || iv > LUN_MASK) {
1862 : rc = EINVAL;
1863 0 : goto reset;
1864 : }
1865 0 : c->c_rslun = iv;
1866 0 : break;
1867 : case IPMICTL_GET_MY_LUN_CMD:
1868 0 : *(int *)data = c->c_rslun;
1869 0 : break;
1870 : case IPMICTL_SET_GETS_EVENTS_CMD:
1871 : break;
1872 : case IPMICTL_REGISTER_FOR_CMD:
1873 : case IPMICTL_UNREGISTER_FOR_CMD:
1874 : default:
1875 : break;
1876 : }
1877 : done:
1878 0 : rw_exit_write(&sc->sc_ioctl.lock);
1879 0 : return (rc);
1880 : reset:
1881 0 : sc->sc_ioctl.req.msgid = -1;
1882 0 : c->c_ccode = -1;
1883 0 : goto done;
1884 0 : }
1885 :
1886 : #define MIN_PERIOD 10
1887 :
1888 : int
1889 0 : ipmi_watchdog(void *arg, int period)
1890 : {
1891 0 : struct ipmi_softc *sc = arg;
1892 :
1893 0 : if (sc->sc_wdog_period == period) {
1894 0 : if (period != 0) {
1895 : struct task *t;
1896 : int res;
1897 :
1898 0 : t = &sc->sc_wdog_tickle_task;
1899 0 : (void)task_del(systq, t);
1900 0 : res = task_add(systq, t);
1901 0 : KASSERT(res == 1);
1902 0 : }
1903 0 : return (period);
1904 : }
1905 :
1906 0 : if (period < MIN_PERIOD && period > 0)
1907 0 : period = MIN_PERIOD;
1908 0 : sc->sc_wdog_period = period;
1909 0 : ipmi_watchdog_set(sc);
1910 0 : printf("%s: watchdog %sabled\n", DEVNAME(sc),
1911 0 : (period == 0) ? "dis" : "en");
1912 0 : return (period);
1913 0 : }
1914 :
1915 : void
1916 0 : ipmi_watchdog_tickle(void *arg)
1917 : {
1918 0 : struct ipmi_softc *sc = arg;
1919 0 : struct ipmi_cmd c;
1920 :
1921 0 : c.c_sc = sc;
1922 0 : c.c_rssa = BMC_SA;
1923 0 : c.c_rslun = BMC_LUN;
1924 0 : c.c_netfn = APP_NETFN;
1925 0 : c.c_cmd = APP_RESET_WATCHDOG;
1926 0 : c.c_txlen = 0;
1927 0 : c.c_maxrxlen = 0;
1928 0 : c.c_rxlen = 0;
1929 0 : c.c_data = NULL;
1930 0 : ipmi_cmd(&c);
1931 0 : }
1932 :
1933 : void
1934 0 : ipmi_watchdog_set(void *arg)
1935 : {
1936 0 : struct ipmi_softc *sc = arg;
1937 0 : uint8_t wdog[IPMI_GET_WDOG_MAX];
1938 0 : struct ipmi_cmd c;
1939 :
1940 0 : c.c_sc = sc;
1941 0 : c.c_rssa = BMC_SA;
1942 0 : c.c_rslun = BMC_LUN;
1943 0 : c.c_netfn = APP_NETFN;
1944 0 : c.c_cmd = APP_GET_WATCHDOG_TIMER;
1945 0 : c.c_txlen = 0;
1946 0 : c.c_maxrxlen = IPMI_GET_WDOG_MAX;
1947 0 : c.c_rxlen = 0;
1948 0 : c.c_data = wdog;
1949 0 : ipmi_cmd(&c);
1950 :
1951 : /* Period is 10ths/sec */
1952 0 : uint16_t timo = htole16(sc->sc_wdog_period * 10);
1953 :
1954 0 : memcpy(&wdog[IPMI_SET_WDOG_TIMOL], &timo, 2);
1955 0 : wdog[IPMI_SET_WDOG_TIMER] &= ~IPMI_WDOG_DONTSTOP;
1956 0 : wdog[IPMI_SET_WDOG_TIMER] |= (sc->sc_wdog_period == 0) ?
1957 : 0 : IPMI_WDOG_DONTSTOP;
1958 0 : wdog[IPMI_SET_WDOG_ACTION] &= ~IPMI_WDOG_MASK;
1959 0 : wdog[IPMI_SET_WDOG_ACTION] |= (sc->sc_wdog_period == 0) ?
1960 : IPMI_WDOG_DISABLED : IPMI_WDOG_REBOOT;
1961 :
1962 0 : c.c_cmd = APP_SET_WATCHDOG_TIMER;
1963 0 : c.c_txlen = IPMI_SET_WDOG_MAX;
1964 0 : c.c_maxrxlen = 0;
1965 0 : c.c_rxlen = 0;
1966 0 : c.c_data = wdog;
1967 0 : ipmi_cmd(&c);
1968 0 : }
|