xref: /openbsd-src/sys/arch/powerpc64/dev/ipmi_opal.c (revision 3a3d566ba4820308e2e01cf588b22fe100348313)
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
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
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
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
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
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
165 ipmi_opal_reset(struct ipmi_softc *sc)
166 {
167 	return -1;
168 }
169 
170 int
171 ipmi_opal_probe(struct ipmi_softc *sc)
172 {
173 	return 0;
174 }
175