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