xref: /freebsd/sys/dev/ipmi/ipmi_smic.c (revision 366d6a424e1faad9c151c5794978e218a79fbed8)
1d72a0786SJohn Baldwin /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4d72a0786SJohn Baldwin  * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
5d72a0786SJohn Baldwin  * All rights reserved.
6d72a0786SJohn Baldwin  *
7d72a0786SJohn Baldwin  * Redistribution and use in source and binary forms, with or without
8d72a0786SJohn Baldwin  * modification, are permitted provided that the following conditions
9d72a0786SJohn Baldwin  * are met:
10d72a0786SJohn Baldwin  * 1. Redistributions of source code must retain the above copyright
11d72a0786SJohn Baldwin  *    notice, this list of conditions and the following disclaimer.
12d72a0786SJohn Baldwin  * 2. Redistributions in binary form must reproduce the above copyright
13d72a0786SJohn Baldwin  *    notice, this list of conditions and the following disclaimer in the
14d72a0786SJohn Baldwin  *    documentation and/or other materials provided with the distribution.
15d72a0786SJohn Baldwin  *
16d72a0786SJohn Baldwin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17d72a0786SJohn Baldwin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18d72a0786SJohn Baldwin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19d72a0786SJohn Baldwin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20d72a0786SJohn Baldwin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21d72a0786SJohn Baldwin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22d72a0786SJohn Baldwin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23d72a0786SJohn Baldwin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24d72a0786SJohn Baldwin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25d72a0786SJohn Baldwin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26d72a0786SJohn Baldwin  * SUCH DAMAGE.
27d72a0786SJohn Baldwin  */
28d72a0786SJohn Baldwin 
29d72a0786SJohn Baldwin #include <sys/param.h>
30d72a0786SJohn Baldwin #include <sys/systm.h>
31d72a0786SJohn Baldwin #include <sys/bus.h>
32d72a0786SJohn Baldwin #include <sys/condvar.h>
33d72a0786SJohn Baldwin #include <sys/eventhandler.h>
34d72a0786SJohn Baldwin #include <sys/kernel.h>
35d72a0786SJohn Baldwin #include <sys/kthread.h>
36d72a0786SJohn Baldwin #include <sys/module.h>
37d72a0786SJohn Baldwin #include <sys/rman.h>
38d72a0786SJohn Baldwin #include <sys/selinfo.h>
39d72a0786SJohn Baldwin #include <machine/bus.h>
40d72a0786SJohn Baldwin 
41d72a0786SJohn Baldwin #ifdef LOCAL_MODULE
42d72a0786SJohn Baldwin #include <ipmi.h>
43d72a0786SJohn Baldwin #include <ipmivars.h>
44d72a0786SJohn Baldwin #else
45d72a0786SJohn Baldwin #include <sys/ipmi.h>
46d72a0786SJohn Baldwin #include <dev/ipmi/ipmivars.h>
47d72a0786SJohn Baldwin #endif
48d72a0786SJohn Baldwin 
49d72a0786SJohn Baldwin static void	smic_wait_for_tx_okay(struct ipmi_softc *);
50d72a0786SJohn Baldwin static void	smic_wait_for_rx_okay(struct ipmi_softc *);
51d72a0786SJohn Baldwin static void	smic_wait_for_not_busy(struct ipmi_softc *);
52d72a0786SJohn Baldwin static void	smic_set_busy(struct ipmi_softc *);
53d72a0786SJohn Baldwin 
54d72a0786SJohn Baldwin static void
smic_wait_for_tx_okay(struct ipmi_softc * sc)55d72a0786SJohn Baldwin smic_wait_for_tx_okay(struct ipmi_softc *sc)
56d72a0786SJohn Baldwin {
57d72a0786SJohn Baldwin 	int flags;
58d72a0786SJohn Baldwin 
59d72a0786SJohn Baldwin 	do {
60d72a0786SJohn Baldwin 		flags = INB(sc, SMIC_FLAGS);
61d72a0786SJohn Baldwin 	} while (!(flags & SMIC_STATUS_TX_RDY));
62d72a0786SJohn Baldwin }
63d72a0786SJohn Baldwin 
64d72a0786SJohn Baldwin static void
smic_wait_for_rx_okay(struct ipmi_softc * sc)65d72a0786SJohn Baldwin smic_wait_for_rx_okay(struct ipmi_softc *sc)
66d72a0786SJohn Baldwin {
67d72a0786SJohn Baldwin 	int flags;
68d72a0786SJohn Baldwin 
69d72a0786SJohn Baldwin 	do {
70d72a0786SJohn Baldwin 		flags = INB(sc, SMIC_FLAGS);
71d72a0786SJohn Baldwin 	} while (!(flags & SMIC_STATUS_RX_RDY));
72d72a0786SJohn Baldwin }
73d72a0786SJohn Baldwin 
74d72a0786SJohn Baldwin static void
smic_wait_for_not_busy(struct ipmi_softc * sc)75d72a0786SJohn Baldwin smic_wait_for_not_busy(struct ipmi_softc *sc)
76d72a0786SJohn Baldwin {
77d72a0786SJohn Baldwin 	int flags;
78d72a0786SJohn Baldwin 
79d72a0786SJohn Baldwin 	do {
80d72a0786SJohn Baldwin 		flags = INB(sc, SMIC_FLAGS);
81d72a0786SJohn Baldwin 	} while (flags & SMIC_STATUS_BUSY);
82d72a0786SJohn Baldwin }
83d72a0786SJohn Baldwin 
84d72a0786SJohn Baldwin static void
smic_set_busy(struct ipmi_softc * sc)85d72a0786SJohn Baldwin smic_set_busy(struct ipmi_softc *sc)
86d72a0786SJohn Baldwin {
87d72a0786SJohn Baldwin 	int flags;
88d72a0786SJohn Baldwin 
89d72a0786SJohn Baldwin 	flags = INB(sc, SMIC_FLAGS);
90d72a0786SJohn Baldwin 	flags |= SMIC_STATUS_BUSY;
91d72a0786SJohn Baldwin 	flags &= ~SMIC_STATUS_RESERVED;
92d72a0786SJohn Baldwin 	OUTB(sc, SMIC_FLAGS, flags);
93d72a0786SJohn Baldwin }
94d72a0786SJohn Baldwin 
95d72a0786SJohn Baldwin /*
96d72a0786SJohn Baldwin  * Start a transfer with a WR_START transaction that sends the NetFn/LUN
97d72a0786SJohn Baldwin  * address.
98d72a0786SJohn Baldwin  */
99d72a0786SJohn Baldwin static int
smic_start_write(struct ipmi_softc * sc,u_char data)100d72a0786SJohn Baldwin smic_start_write(struct ipmi_softc *sc, u_char data)
101d72a0786SJohn Baldwin {
102d72a0786SJohn Baldwin 	u_char error, status;
103d72a0786SJohn Baldwin 
104d72a0786SJohn Baldwin 	smic_wait_for_not_busy(sc);
105d72a0786SJohn Baldwin 
106d72a0786SJohn Baldwin 	OUTB(sc, SMIC_CTL_STS, SMIC_CC_SMS_WR_START);
107d72a0786SJohn Baldwin 	OUTB(sc, SMIC_DATA, data);
108d72a0786SJohn Baldwin 	smic_set_busy(sc);
109d72a0786SJohn Baldwin 	smic_wait_for_not_busy(sc);
110d72a0786SJohn Baldwin 	status = INB(sc, SMIC_CTL_STS);
111d72a0786SJohn Baldwin 	if (status != SMIC_SC_SMS_WR_START) {
112d72a0786SJohn Baldwin 		error = INB(sc, SMIC_DATA);
113d72a0786SJohn Baldwin 		device_printf(sc->ipmi_dev, "SMIC: Write did not start %02x\n",
114d72a0786SJohn Baldwin 		    error);
115d72a0786SJohn Baldwin 		return (0);
116d72a0786SJohn Baldwin 	}
117d72a0786SJohn Baldwin 	return (1);
118d72a0786SJohn Baldwin }
119d72a0786SJohn Baldwin 
120d72a0786SJohn Baldwin /*
121d72a0786SJohn Baldwin  * Write a byte in the middle of the message (either the command or one of
122d72a0786SJohn Baldwin  * the data bytes) using a WR_NEXT transaction.
123d72a0786SJohn Baldwin  */
124d72a0786SJohn Baldwin static int
smic_write_next(struct ipmi_softc * sc,u_char data)125d72a0786SJohn Baldwin smic_write_next(struct ipmi_softc *sc, u_char data)
126d72a0786SJohn Baldwin {
127d72a0786SJohn Baldwin 	u_char error, status;
128d72a0786SJohn Baldwin 
129d72a0786SJohn Baldwin 	smic_wait_for_tx_okay(sc);
130fab2d1adSJohn Baldwin 	OUTB(sc, SMIC_CTL_STS, SMIC_CC_SMS_WR_NEXT);
131d72a0786SJohn Baldwin 	OUTB(sc, SMIC_DATA, data);
132d72a0786SJohn Baldwin 	smic_set_busy(sc);
133d72a0786SJohn Baldwin 	smic_wait_for_not_busy(sc);
134d72a0786SJohn Baldwin 	status = INB(sc, SMIC_CTL_STS);
135d72a0786SJohn Baldwin 	if (status != SMIC_SC_SMS_WR_NEXT) {
136d72a0786SJohn Baldwin 		error = INB(sc, SMIC_DATA);
137d72a0786SJohn Baldwin 		device_printf(sc->ipmi_dev, "SMIC: Write did not next %02x\n",
138d72a0786SJohn Baldwin 		    error);
139d72a0786SJohn Baldwin 		return (0);
140d72a0786SJohn Baldwin 	}
141d72a0786SJohn Baldwin 	return (1);
142d72a0786SJohn Baldwin }
143d72a0786SJohn Baldwin 
144d72a0786SJohn Baldwin /*
145d72a0786SJohn Baldwin  * Write the last byte of a transfer to end the write phase via a WR_END
146d72a0786SJohn Baldwin  * transaction.
147d72a0786SJohn Baldwin  */
148d72a0786SJohn Baldwin static int
smic_write_last(struct ipmi_softc * sc,u_char data)149d72a0786SJohn Baldwin smic_write_last(struct ipmi_softc *sc, u_char data)
150d72a0786SJohn Baldwin {
151d72a0786SJohn Baldwin 	u_char error, status;
152d72a0786SJohn Baldwin 
153d72a0786SJohn Baldwin 	smic_wait_for_tx_okay(sc);
154fab2d1adSJohn Baldwin 	OUTB(sc, SMIC_CTL_STS, SMIC_CC_SMS_WR_END);
155d72a0786SJohn Baldwin 	OUTB(sc, SMIC_DATA, data);
156d72a0786SJohn Baldwin 	smic_set_busy(sc);
157d72a0786SJohn Baldwin 	smic_wait_for_not_busy(sc);
158d72a0786SJohn Baldwin 	status = INB(sc, SMIC_CTL_STS);
159d72a0786SJohn Baldwin 	if (status != SMIC_SC_SMS_WR_END) {
160d72a0786SJohn Baldwin 		error = INB(sc, SMIC_DATA);
161d72a0786SJohn Baldwin 		device_printf(sc->ipmi_dev, "SMIC: Write did not end %02x\n",
162d72a0786SJohn Baldwin 		    error);
163d72a0786SJohn Baldwin 		return (0);
164d72a0786SJohn Baldwin 	}
165d72a0786SJohn Baldwin 	return (1);
166d72a0786SJohn Baldwin }
167d72a0786SJohn Baldwin 
168d72a0786SJohn Baldwin /*
169d72a0786SJohn Baldwin  * Start the read phase of a transfer with a RD_START transaction.
170d72a0786SJohn Baldwin  */
171d72a0786SJohn Baldwin static int
smic_start_read(struct ipmi_softc * sc,u_char * data)172d72a0786SJohn Baldwin smic_start_read(struct ipmi_softc *sc, u_char *data)
173d72a0786SJohn Baldwin {
174d72a0786SJohn Baldwin 	u_char error, status;
175d72a0786SJohn Baldwin 
176d72a0786SJohn Baldwin 	smic_wait_for_not_busy(sc);
177d72a0786SJohn Baldwin 
178d72a0786SJohn Baldwin 	smic_wait_for_rx_okay(sc);
179fab2d1adSJohn Baldwin 	OUTB(sc, SMIC_CTL_STS, SMIC_CC_SMS_RD_START);
180d72a0786SJohn Baldwin 	smic_set_busy(sc);
181d72a0786SJohn Baldwin 	smic_wait_for_not_busy(sc);
182d72a0786SJohn Baldwin 	status = INB(sc, SMIC_CTL_STS);
183d72a0786SJohn Baldwin 	if (status != SMIC_SC_SMS_RD_START) {
184d72a0786SJohn Baldwin 		error = INB(sc, SMIC_DATA);
185d72a0786SJohn Baldwin 		device_printf(sc->ipmi_dev, "SMIC: Read did not start %02x\n",
186d72a0786SJohn Baldwin 		    error);
187d72a0786SJohn Baldwin 		return (0);
188d72a0786SJohn Baldwin 	}
189d72a0786SJohn Baldwin 	*data = INB(sc, SMIC_DATA);
190d72a0786SJohn Baldwin 	return (1);
191d72a0786SJohn Baldwin }
192d72a0786SJohn Baldwin 
193d72a0786SJohn Baldwin /*
194d72a0786SJohn Baldwin  * Read a byte via a RD_NEXT transaction.  If this was the last byte, return
195d72a0786SJohn Baldwin  * 2 rather than 1.
196d72a0786SJohn Baldwin  */
197d72a0786SJohn Baldwin static int
smic_read_byte(struct ipmi_softc * sc,u_char * data)198d72a0786SJohn Baldwin smic_read_byte(struct ipmi_softc *sc, u_char *data)
199d72a0786SJohn Baldwin {
200d72a0786SJohn Baldwin 	u_char error, status;
201d72a0786SJohn Baldwin 
202d72a0786SJohn Baldwin 	smic_wait_for_rx_okay(sc);
203fab2d1adSJohn Baldwin 	OUTB(sc, SMIC_CTL_STS, SMIC_SC_SMS_RD_NEXT);
204d72a0786SJohn Baldwin 	smic_set_busy(sc);
205d72a0786SJohn Baldwin 	smic_wait_for_not_busy(sc);
206d72a0786SJohn Baldwin 	status = INB(sc, SMIC_CTL_STS);
207d72a0786SJohn Baldwin 	if (status != SMIC_SC_SMS_RD_NEXT &&
208d72a0786SJohn Baldwin 	    status != SMIC_SC_SMS_RD_END) {
209d72a0786SJohn Baldwin 		error = INB(sc, SMIC_DATA);
210d72a0786SJohn Baldwin 		device_printf(sc->ipmi_dev, "SMIC: Read did not next %02x\n",
211d72a0786SJohn Baldwin 		    error);
212d72a0786SJohn Baldwin 		return (0);
213d72a0786SJohn Baldwin 	}
214d72a0786SJohn Baldwin 	*data = INB(sc, SMIC_DATA);
215d72a0786SJohn Baldwin 	if (status == SMIC_SC_SMS_RD_NEXT)
216d72a0786SJohn Baldwin 		return (1);
217d72a0786SJohn Baldwin 	else
218d72a0786SJohn Baldwin 		return (2);
219d72a0786SJohn Baldwin }
220d72a0786SJohn Baldwin 
221d72a0786SJohn Baldwin /* Complete a transfer via a RD_END transaction after reading the last byte. */
222d72a0786SJohn Baldwin static int
smic_read_end(struct ipmi_softc * sc)223d72a0786SJohn Baldwin smic_read_end(struct ipmi_softc *sc)
224d72a0786SJohn Baldwin {
225d72a0786SJohn Baldwin 	u_char error, status;
226d72a0786SJohn Baldwin 
227d72a0786SJohn Baldwin 	OUTB(sc, SMIC_CTL_STS, SMIC_CC_SMS_RD_END);
228d72a0786SJohn Baldwin 	smic_set_busy(sc);
229d72a0786SJohn Baldwin 	smic_wait_for_not_busy(sc);
230d72a0786SJohn Baldwin 	status = INB(sc, SMIC_CTL_STS);
231d72a0786SJohn Baldwin 	if (status != SMIC_SC_SMS_RDY) {
232d72a0786SJohn Baldwin 		error = INB(sc, SMIC_DATA);
233d72a0786SJohn Baldwin 		device_printf(sc->ipmi_dev, "SMIC: Read did not end %02x\n",
234d72a0786SJohn Baldwin 		    error);
235d72a0786SJohn Baldwin 		return (0);
236d72a0786SJohn Baldwin 	}
237d72a0786SJohn Baldwin 	return (1);
238d72a0786SJohn Baldwin }
239d72a0786SJohn Baldwin 
240d72a0786SJohn Baldwin static int
smic_polled_request(struct ipmi_softc * sc,struct ipmi_request * req)241d72a0786SJohn Baldwin smic_polled_request(struct ipmi_softc *sc, struct ipmi_request *req)
242d72a0786SJohn Baldwin {
243d72a0786SJohn Baldwin 	u_char *cp, data;
244d72a0786SJohn Baldwin 	int i, state;
245d72a0786SJohn Baldwin 
246d72a0786SJohn Baldwin 	/* First, start the message with the address. */
247d72a0786SJohn Baldwin 	if (!smic_start_write(sc, req->ir_addr))
248d72a0786SJohn Baldwin 		return (0);
249b4828cc1SJohn Baldwin #ifdef SMIC_DEBUG
250b4828cc1SJohn Baldwin 	device_printf(sc->ipmi_dev, "SMIC: WRITE_START address: %02x\n",
251b4828cc1SJohn Baldwin 	    req->ir_addr);
252b4828cc1SJohn Baldwin #endif
253d72a0786SJohn Baldwin 
254d72a0786SJohn Baldwin 	if (req->ir_requestlen == 0) {
255d72a0786SJohn Baldwin 		/* Send the command as the last byte. */
256d72a0786SJohn Baldwin 		if (!smic_write_last(sc, req->ir_command))
257d72a0786SJohn Baldwin 			return (0);
258b4828cc1SJohn Baldwin #ifdef SMIC_DEBUG
259b4828cc1SJohn Baldwin 		device_printf(sc->ipmi_dev, "SMIC: Wrote command: %02x\n",
260b4828cc1SJohn Baldwin 		    req->ir_command);
261b4828cc1SJohn Baldwin #endif
262d72a0786SJohn Baldwin 	} else {
263d72a0786SJohn Baldwin 		/* Send the command. */
264d72a0786SJohn Baldwin 		if (!smic_write_next(sc, req->ir_command))
265d72a0786SJohn Baldwin 			return (0);
266b4828cc1SJohn Baldwin #ifdef SMIC_DEBUG
267b4828cc1SJohn Baldwin 		device_printf(sc->ipmi_dev, "SMIC: Wrote command: %02x\n",
268b4828cc1SJohn Baldwin 		    req->ir_command);
269b4828cc1SJohn Baldwin #endif
270d72a0786SJohn Baldwin 
271d72a0786SJohn Baldwin 		/* Send the payload. */
272d72a0786SJohn Baldwin 		cp = req->ir_request;
273b4828cc1SJohn Baldwin 		for (i = 0; i < req->ir_requestlen - 1; i++) {
274d72a0786SJohn Baldwin 			if (!smic_write_next(sc, *cp++))
275d72a0786SJohn Baldwin 				return (0);
276b4828cc1SJohn Baldwin #ifdef SMIC_DEBUG
277b4828cc1SJohn Baldwin 			device_printf(sc->ipmi_dev, "SMIC: Wrote data: %02x\n",
278b4828cc1SJohn Baldwin 			    cp[-1]);
279b4828cc1SJohn Baldwin #endif
280b4828cc1SJohn Baldwin 		}
281d72a0786SJohn Baldwin 		if (!smic_write_last(sc, *cp))
282d72a0786SJohn Baldwin 			return (0);
283b4828cc1SJohn Baldwin #ifdef SMIC_DEBUG
284b4828cc1SJohn Baldwin 		device_printf(sc->ipmi_dev, "SMIC: Write last data: %02x\n",
285b4828cc1SJohn Baldwin 		    *cp);
286b4828cc1SJohn Baldwin #endif
287d72a0786SJohn Baldwin 	}
288d72a0786SJohn Baldwin 
289d72a0786SJohn Baldwin 	/* Start the read phase by reading the NetFn/LUN. */
290d72a0786SJohn Baldwin 	if (smic_start_read(sc, &data) != 1)
291d72a0786SJohn Baldwin 		return (0);
292b4828cc1SJohn Baldwin #ifdef SMIC_DEBUG
293b4828cc1SJohn Baldwin 	device_printf(sc->ipmi_dev, "SMIC: Read address: %02x\n", data);
294b4828cc1SJohn Baldwin #endif
295d72a0786SJohn Baldwin 	if (data != IPMI_REPLY_ADDR(req->ir_addr)) {
296d72a0786SJohn Baldwin 		device_printf(sc->ipmi_dev, "SMIC: Reply address mismatch\n");
297d72a0786SJohn Baldwin 		return (0);
298d72a0786SJohn Baldwin 	}
299d72a0786SJohn Baldwin 
300d72a0786SJohn Baldwin 	/* Read the command. */
301d72a0786SJohn Baldwin 	if (smic_read_byte(sc, &data) != 1)
302d72a0786SJohn Baldwin 		return (0);
303b4828cc1SJohn Baldwin #ifdef SMIC_DEBUG
304b4828cc1SJohn Baldwin 	device_printf(sc->ipmi_dev, "SMIC: Read command: %02x\n", data);
305b4828cc1SJohn Baldwin #endif
306d72a0786SJohn Baldwin 	if (data != req->ir_command) {
307d72a0786SJohn Baldwin 		device_printf(sc->ipmi_dev, "SMIC: Command mismatch\n");
308d72a0786SJohn Baldwin 		return (0);
309d72a0786SJohn Baldwin 	}
310d72a0786SJohn Baldwin 
311d72a0786SJohn Baldwin 	/* Read the completion code. */
312d72a0786SJohn Baldwin 	state = smic_read_byte(sc, &req->ir_compcode);
313d72a0786SJohn Baldwin 	if (state == 0)
314d72a0786SJohn Baldwin 		return (0);
315b4828cc1SJohn Baldwin #ifdef SMIC_DEBUG
316b4828cc1SJohn Baldwin 	device_printf(sc->ipmi_dev, "SMIC: Read completion code: %02x\n",
317b4828cc1SJohn Baldwin 	    req->ir_compcode);
318b4828cc1SJohn Baldwin #endif
319d72a0786SJohn Baldwin 
320d72a0786SJohn Baldwin 	/* Finally, read the reply from the BMC. */
321d72a0786SJohn Baldwin 	i = 0;
322d72a0786SJohn Baldwin 	while (state == 1) {
323d72a0786SJohn Baldwin 		state = smic_read_byte(sc, &data);
324d72a0786SJohn Baldwin 		if (state == 0)
325d72a0786SJohn Baldwin 			return (0);
326b4828cc1SJohn Baldwin 		if (i < req->ir_replybuflen) {
327d72a0786SJohn Baldwin 			req->ir_reply[i] = data;
328b4828cc1SJohn Baldwin #ifdef SMIC_DEBUG
329b4828cc1SJohn Baldwin 			device_printf(sc->ipmi_dev, "SMIC: Read data: %02x\n",
330b4828cc1SJohn Baldwin 			    data);
331b4828cc1SJohn Baldwin 		} else {
332b4828cc1SJohn Baldwin 			device_printf(sc->ipmi_dev,
333b4828cc1SJohn Baldwin 			    "SMIC: Read short %02x byte %d\n", data, i + 1);
334b4828cc1SJohn Baldwin #endif
335b4828cc1SJohn Baldwin 		}
336d72a0786SJohn Baldwin 		i++;
337d72a0786SJohn Baldwin 	}
338d72a0786SJohn Baldwin 
339d72a0786SJohn Baldwin 	/* Terminate the transfer. */
340d72a0786SJohn Baldwin 	if (!smic_read_end(sc))
341d72a0786SJohn Baldwin 		return (0);
342d72a0786SJohn Baldwin 	req->ir_replylen = i;
343b4828cc1SJohn Baldwin #ifdef SMIC_DEBUG
344b4828cc1SJohn Baldwin 	device_printf(sc->ipmi_dev, "SMIC: READ finished (%d bytes)\n", i);
345b4828cc1SJohn Baldwin 	if (req->ir_replybuflen < i)
346b4828cc1SJohn Baldwin #else
347d72a0786SJohn Baldwin 	if (req->ir_replybuflen < i && req->ir_replybuflen != 0)
348b4828cc1SJohn Baldwin #endif
349d72a0786SJohn Baldwin 		device_printf(sc->ipmi_dev,
350d72a0786SJohn Baldwin 		    "SMIC: Read short: %zd buffer, %d actual\n",
351d72a0786SJohn Baldwin 		    req->ir_replybuflen, i);
352d72a0786SJohn Baldwin 	return (1);
353d72a0786SJohn Baldwin }
354d72a0786SJohn Baldwin 
355d72a0786SJohn Baldwin static void
smic_loop(void * arg)356d72a0786SJohn Baldwin smic_loop(void *arg)
357d72a0786SJohn Baldwin {
358d72a0786SJohn Baldwin 	struct ipmi_softc *sc = arg;
359d72a0786SJohn Baldwin 	struct ipmi_request *req;
360d72a0786SJohn Baldwin 	int i, ok;
361d72a0786SJohn Baldwin 
362d72a0786SJohn Baldwin 	IPMI_LOCK(sc);
363d72a0786SJohn Baldwin 	while ((req = ipmi_dequeue_request(sc)) != NULL) {
36458e8e6e6SAlexander V. Chernikov 		IPMI_UNLOCK(sc);
365d72a0786SJohn Baldwin 		ok = 0;
366c869aa71SJohn Baldwin 		for (i = 0; i < 3 && !ok; i++) {
367c869aa71SJohn Baldwin 			IPMI_IO_LOCK(sc);
368d72a0786SJohn Baldwin 			ok = smic_polled_request(sc, req);
369c869aa71SJohn Baldwin 			IPMI_IO_UNLOCK(sc);
370c869aa71SJohn Baldwin 		}
371d72a0786SJohn Baldwin 		if (ok)
372d72a0786SJohn Baldwin 			req->ir_error = 0;
373d72a0786SJohn Baldwin 		else
374d72a0786SJohn Baldwin 			req->ir_error = EIO;
37558e8e6e6SAlexander V. Chernikov 		IPMI_LOCK(sc);
376d72a0786SJohn Baldwin 		ipmi_complete_request(sc, req);
377d72a0786SJohn Baldwin 	}
378d72a0786SJohn Baldwin 	IPMI_UNLOCK(sc);
3793745c395SJulian Elischer 	kproc_exit(0);
380d72a0786SJohn Baldwin }
381d72a0786SJohn Baldwin 
382d72a0786SJohn Baldwin static int
smic_startup(struct ipmi_softc * sc)383d72a0786SJohn Baldwin smic_startup(struct ipmi_softc *sc)
384d72a0786SJohn Baldwin {
385d72a0786SJohn Baldwin 
3863745c395SJulian Elischer 	return (kproc_create(smic_loop, sc, &sc->ipmi_kthread, 0, 0,
387d72a0786SJohn Baldwin 	    "%s: smic", device_get_nameunit(sc->ipmi_dev)));
388d72a0786SJohn Baldwin }
389d72a0786SJohn Baldwin 
390c869aa71SJohn Baldwin static int
smic_driver_request(struct ipmi_softc * sc,struct ipmi_request * req)391*366d6a42SGleb Smirnoff smic_driver_request(struct ipmi_softc *sc, struct ipmi_request *req)
392c869aa71SJohn Baldwin {
393c869aa71SJohn Baldwin 	int i, ok;
394c869aa71SJohn Baldwin 
395c869aa71SJohn Baldwin 	ok = 0;
396c869aa71SJohn Baldwin 	for (i = 0; i < 3 && !ok; i++) {
397c869aa71SJohn Baldwin 		IPMI_IO_LOCK(sc);
398c869aa71SJohn Baldwin 		ok = smic_polled_request(sc, req);
399c869aa71SJohn Baldwin 		IPMI_IO_UNLOCK(sc);
400c869aa71SJohn Baldwin 	}
401c869aa71SJohn Baldwin 	if (ok)
402c869aa71SJohn Baldwin 		req->ir_error = 0;
403c869aa71SJohn Baldwin 	else
404c869aa71SJohn Baldwin 		req->ir_error = EIO;
405c869aa71SJohn Baldwin 	return (req->ir_error);
406c869aa71SJohn Baldwin }
407c869aa71SJohn Baldwin 
408d72a0786SJohn Baldwin int
ipmi_smic_attach(struct ipmi_softc * sc)409d72a0786SJohn Baldwin ipmi_smic_attach(struct ipmi_softc *sc)
410d72a0786SJohn Baldwin {
411d72a0786SJohn Baldwin 	int flags;
412d72a0786SJohn Baldwin 
413d72a0786SJohn Baldwin 	/* Setup function pointers. */
414d72a0786SJohn Baldwin 	sc->ipmi_startup = smic_startup;
415d72a0786SJohn Baldwin 	sc->ipmi_enqueue_request = ipmi_polled_enqueue_request;
416c869aa71SJohn Baldwin 	sc->ipmi_driver_request = smic_driver_request;
4179662eef5SJohn Baldwin 	sc->ipmi_driver_requests_polled = 1;
418d72a0786SJohn Baldwin 
419d72a0786SJohn Baldwin 	/* See if we can talk to the controller. */
420d72a0786SJohn Baldwin 	flags = INB(sc, SMIC_FLAGS);
421d72a0786SJohn Baldwin 	if (flags == 0xff) {
422d72a0786SJohn Baldwin 		device_printf(sc->ipmi_dev, "couldn't find it\n");
423d72a0786SJohn Baldwin 		return (ENXIO);
424d72a0786SJohn Baldwin 	}
425d72a0786SJohn Baldwin 
426b4828cc1SJohn Baldwin #ifdef SMIC_DEBUG
427b4828cc1SJohn Baldwin 	device_printf(sc->ipmi_dev, "SMIC: initial state: %02x\n", flags);
428b4828cc1SJohn Baldwin #endif
429b4828cc1SJohn Baldwin 
430d72a0786SJohn Baldwin 	return (0);
431d72a0786SJohn Baldwin }
432