xref: /openbsd/sys/arch/powerpc64/dev/ipmi_opal.c (revision d415bd75)
1 /*	$OpenBSD: ipmi_opal.c,v 1.3 2022/04/06 18:59:27 naddy 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 };
66 
67 int
68 ipmi_opal_match(struct device *parent, void *match, void *aux)
69 {
70 	struct fdt_attach_args *faa = aux;
71 
72 	return OF_is_compatible(faa->fa_node, "ibm,opal-ipmi");
73 }
74 
75 void
76 ipmi_opal_attach(struct device *parent, struct device *self, void *aux)
77 {
78 	struct ipmi_opal_softc *sc = (struct ipmi_opal_softc *)self;
79 	struct fdt_attach_args *faa = aux;
80 	struct ipmi_attach_args iaa;
81 	uint64_t size;
82 	int64_t error;
83 
84 	sc->sc.sc_if = &opal_if;
85 	sc->sc_id = OF_getpropint(faa->fa_node, "ibm,ipmi-interface-id", 0);
86 
87 	/* Clear IPMI message queue. */
88 	do {
89 		size = sizeof(sc->sc.sc_buf);
90 		error = opal_ipmi_recv(sc->sc_id,
91 		    opal_phys(sc->sc.sc_buf), opal_phys(&size));
92 	} while (error == OPAL_SUCCESS);
93 
94 	memset(&iaa, 0, sizeof(iaa));
95 	iaa.iaa_if_type = IPMI_IF_SSIF;
96 	iaa.iaa_if_rev = 0x20;
97 	iaa.iaa_if_irq = -1;
98 	ipmi_attach_common(&sc->sc, &iaa);
99 }
100 
101 #define RSSA_MASK 0xff
102 #define LUN_MASK 0x3
103 #define NETFN_LUN(nf,ln) (((nf) << 2) | ((ln) & LUN_MASK))
104 
105 void
106 ipmi_opal_buildmsg(struct ipmi_cmd *c)
107 {
108 	struct ipmi_softc *sc = c->c_sc;
109 	struct opal_ipmi_msg *msg = (struct opal_ipmi_msg *)sc->sc_buf;
110 
111 	msg->version = OPAL_IPMI_MSG_FORMAT_VERSION_1;
112 	msg->netfn = NETFN_LUN(c->c_netfn, c->c_rslun);
113 	msg->cmd = c->c_cmd;
114 	if (c->c_txlen && c->c_data)
115 		memcpy(msg->data, c->c_data, c->c_txlen);
116 }
117 
118 int
119 ipmi_opal_sendmsg(struct ipmi_cmd *c)
120 {
121 	struct ipmi_opal_softc *sc = (struct ipmi_opal_softc *)c->c_sc;
122 	int64_t error;
123 
124 	error = opal_ipmi_send(sc->sc_id,
125 	    opal_phys(sc->sc.sc_buf), c->c_txlen);
126 
127 	return (error == OPAL_SUCCESS ? 0 : -1);
128 }
129 
130 int
131 ipmi_opal_recvmsg(struct ipmi_cmd *c)
132 {
133 	struct ipmi_opal_softc *sc = (struct ipmi_opal_softc *)c->c_sc;
134 	struct opal_ipmi_msg *msg = (struct opal_ipmi_msg *)sc->sc.sc_buf;
135 	uint64_t size = sizeof(sc->sc.sc_buf);
136 	int64_t error;
137 	int timo;
138 
139 	msg->version = OPAL_IPMI_MSG_FORMAT_VERSION_1;
140 	for (timo = 1000; timo > 0; timo--) {
141 		error = opal_ipmi_recv(sc->sc_id,
142 		    opal_phys(sc->sc.sc_buf), opal_phys(&size));
143 		if (error != OPAL_EMPTY)
144 			break;
145 
146 		tsleep_nsec(sc, PWAIT, "ipmi", MSEC_TO_NSEC(1));
147 		opal_poll_events(NULL);
148 	}
149 
150 	if (error == OPAL_SUCCESS) {
151 		if (msg->version != OPAL_IPMI_MSG_FORMAT_VERSION_1)
152 			return -1;
153 
154 		sc->sc.sc_buf[IPMI_MSG_NFLN] = msg->netfn;
155 		sc->sc.sc_buf[IPMI_MSG_CMD] = msg->cmd;
156 		sc->sc.sc_buf[IPMI_MSG_CCODE] = msg->data[0];
157 		c->c_rxlen = MIN(size, c->c_maxrxlen);
158 	}
159 
160 	return (error == OPAL_SUCCESS ? 0 : -1);
161 }
162 
163 int
164 ipmi_opal_reset(struct ipmi_softc *sc)
165 {
166 	return -1;
167 }
168 
169 int
170 ipmi_opal_probe(struct ipmi_softc *sc)
171 {
172 	return 0;
173 }
174