1 /* $OpenBSD: ipmi_opal.c,v 1.4 2024/10/09 00:38:26 jsg Exp $ */
2 /*
3 * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/device.h>
20 #include <sys/systm.h>
21
22 #include <machine/fdt.h>
23 #include <machine/opal.h>
24
25 #include <dev/ofw/openfirm.h>
26 #include <dev/ofw/fdt.h>
27
28 #include <dev/ipmivar.h>
29
30 struct ipmi_opal_softc {
31 struct ipmi_softc sc;
32 int sc_id;
33 };
34
35 void ipmi_opal_buildmsg(struct ipmi_cmd *);
36 int ipmi_opal_sendmsg(struct ipmi_cmd *);
37 int ipmi_opal_recvmsg(struct ipmi_cmd *);
38 int ipmi_opal_reset(struct ipmi_softc *);
39 int ipmi_opal_probe(struct ipmi_softc *);
40
41 #define IPMI_OPALMSG_VERSION 0
42 #define IPMI_OPALMSG_NFLN 1
43 #define IPMI_OPALMSG_CMD 2
44 #define IPMI_OPALMSG_CCODE 3
45 #define IPMI_OPALMSG_DATASND 3
46 #define IPMI_OPALMSG_DATARCV 4
47
48 struct ipmi_if opal_if = {
49 "OPAL",
50 0,
51 ipmi_opal_buildmsg,
52 ipmi_opal_sendmsg,
53 ipmi_opal_recvmsg,
54 ipmi_opal_reset,
55 ipmi_opal_probe,
56 IPMI_OPALMSG_DATASND,
57 IPMI_OPALMSG_DATARCV
58 };
59
60 int ipmi_opal_match(struct device *, void *, void *);
61 void ipmi_opal_attach(struct device *, struct device *, void *);
62
63 const struct cfattach ipmi_opal_ca = {
64 sizeof (struct ipmi_opal_softc), ipmi_opal_match, ipmi_opal_attach,
65 NULL, ipmi_activate
66 };
67
68 int
ipmi_opal_match(struct device * parent,void * match,void * aux)69 ipmi_opal_match(struct device *parent, void *match, void *aux)
70 {
71 struct fdt_attach_args *faa = aux;
72
73 return OF_is_compatible(faa->fa_node, "ibm,opal-ipmi");
74 }
75
76 void
ipmi_opal_attach(struct device * parent,struct device * self,void * aux)77 ipmi_opal_attach(struct device *parent, struct device *self, void *aux)
78 {
79 struct ipmi_opal_softc *sc = (struct ipmi_opal_softc *)self;
80 struct fdt_attach_args *faa = aux;
81 struct ipmi_attach_args iaa;
82 uint64_t size;
83 int64_t error;
84
85 sc->sc.sc_if = &opal_if;
86 sc->sc_id = OF_getpropint(faa->fa_node, "ibm,ipmi-interface-id", 0);
87
88 /* Clear IPMI message queue. */
89 do {
90 size = sizeof(sc->sc.sc_buf);
91 error = opal_ipmi_recv(sc->sc_id,
92 opal_phys(sc->sc.sc_buf), opal_phys(&size));
93 } while (error == OPAL_SUCCESS);
94
95 memset(&iaa, 0, sizeof(iaa));
96 iaa.iaa_if_type = IPMI_IF_SSIF;
97 iaa.iaa_if_rev = 0x20;
98 iaa.iaa_if_irq = -1;
99 ipmi_attach_common(&sc->sc, &iaa);
100 }
101
102 #define RSSA_MASK 0xff
103 #define LUN_MASK 0x3
104 #define NETFN_LUN(nf,ln) (((nf) << 2) | ((ln) & LUN_MASK))
105
106 void
ipmi_opal_buildmsg(struct ipmi_cmd * c)107 ipmi_opal_buildmsg(struct ipmi_cmd *c)
108 {
109 struct ipmi_softc *sc = c->c_sc;
110 struct opal_ipmi_msg *msg = (struct opal_ipmi_msg *)sc->sc_buf;
111
112 msg->version = OPAL_IPMI_MSG_FORMAT_VERSION_1;
113 msg->netfn = NETFN_LUN(c->c_netfn, c->c_rslun);
114 msg->cmd = c->c_cmd;
115 if (c->c_txlen && c->c_data)
116 memcpy(msg->data, c->c_data, c->c_txlen);
117 }
118
119 int
ipmi_opal_sendmsg(struct ipmi_cmd * c)120 ipmi_opal_sendmsg(struct ipmi_cmd *c)
121 {
122 struct ipmi_opal_softc *sc = (struct ipmi_opal_softc *)c->c_sc;
123 int64_t error;
124
125 error = opal_ipmi_send(sc->sc_id,
126 opal_phys(sc->sc.sc_buf), c->c_txlen);
127
128 return (error == OPAL_SUCCESS ? 0 : -1);
129 }
130
131 int
ipmi_opal_recvmsg(struct ipmi_cmd * c)132 ipmi_opal_recvmsg(struct ipmi_cmd *c)
133 {
134 struct ipmi_opal_softc *sc = (struct ipmi_opal_softc *)c->c_sc;
135 struct opal_ipmi_msg *msg = (struct opal_ipmi_msg *)sc->sc.sc_buf;
136 uint64_t size = sizeof(sc->sc.sc_buf);
137 int64_t error;
138 int timo;
139
140 msg->version = OPAL_IPMI_MSG_FORMAT_VERSION_1;
141 for (timo = 1000; timo > 0; timo--) {
142 error = opal_ipmi_recv(sc->sc_id,
143 opal_phys(sc->sc.sc_buf), opal_phys(&size));
144 if (error != OPAL_EMPTY)
145 break;
146
147 tsleep_nsec(sc, PWAIT, "ipmi", MSEC_TO_NSEC(1));
148 opal_poll_events(NULL);
149 }
150
151 if (error == OPAL_SUCCESS) {
152 if (msg->version != OPAL_IPMI_MSG_FORMAT_VERSION_1)
153 return -1;
154
155 sc->sc.sc_buf[IPMI_MSG_NFLN] = msg->netfn;
156 sc->sc.sc_buf[IPMI_MSG_CMD] = msg->cmd;
157 sc->sc.sc_buf[IPMI_MSG_CCODE] = msg->data[0];
158 c->c_rxlen = MIN(size, c->c_maxrxlen);
159 }
160
161 return (error == OPAL_SUCCESS ? 0 : -1);
162 }
163
164 int
ipmi_opal_reset(struct ipmi_softc * sc)165 ipmi_opal_reset(struct ipmi_softc *sc)
166 {
167 return -1;
168 }
169
170 int
ipmi_opal_probe(struct ipmi_softc * sc)171 ipmi_opal_probe(struct ipmi_softc *sc)
172 {
173 return 0;
174 }
175