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>
32f0f3e3e9SChuck Silvers #include <sys/conf.h>
33d72a0786SJohn Baldwin #include <sys/condvar.h>
34d72a0786SJohn Baldwin #include <sys/eventhandler.h>
35d72a0786SJohn Baldwin #include <sys/kernel.h>
36d72a0786SJohn Baldwin #include <sys/kthread.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
4915242987SJonathan T. Looney #define POLLING_DELAY_MIN 4 /* Waits are 2-3 usecs on typical systems */
5015242987SJonathan T. Looney #define POLLING_DELAY_MAX 256
5115242987SJonathan T. Looney
52d72a0786SJohn Baldwin static void kcs_clear_obf(struct ipmi_softc *, int);
53d72a0786SJohn Baldwin static void kcs_error(struct ipmi_softc *);
5415242987SJonathan T. Looney static int kcs_wait_for_ibf(struct ipmi_softc *, bool);
5515242987SJonathan T. Looney static int kcs_wait_for_obf(struct ipmi_softc *, bool);
56d72a0786SJohn Baldwin
57d72a0786SJohn Baldwin static int
kcs_wait(struct ipmi_softc * sc,int value,int mask)5815242987SJonathan T. Looney kcs_wait(struct ipmi_softc *sc, int value, int mask)
59d72a0786SJohn Baldwin {
60d72a0786SJohn Baldwin int status, start = ticks;
6115242987SJonathan T. Looney int delay_usec = POLLING_DELAY_MIN;
62d72a0786SJohn Baldwin
63d72a0786SJohn Baldwin status = INB(sc, KCS_CTL_STS);
6415242987SJonathan T. Looney while (ticks - start < MAX_TIMEOUT && (status & mask) != value) {
6515242987SJonathan T. Looney /*
6615242987SJonathan T. Looney * The wait delay is increased exponentially to avoid putting
6715242987SJonathan T. Looney * significant load on I/O bus.
6815242987SJonathan T. Looney */
6915242987SJonathan T. Looney DELAY(delay_usec);
70d72a0786SJohn Baldwin status = INB(sc, KCS_CTL_STS);
7115242987SJonathan T. Looney if (delay_usec < POLLING_DELAY_MAX)
7215242987SJonathan T. Looney delay_usec *= 2;
73d72a0786SJohn Baldwin }
74d72a0786SJohn Baldwin return (status);
75d72a0786SJohn Baldwin }
76d72a0786SJohn Baldwin
77d72a0786SJohn Baldwin static int
kcs_wait_for_ibf(struct ipmi_softc * sc,bool level)7815242987SJonathan T. Looney kcs_wait_for_ibf(struct ipmi_softc *sc, bool level)
79d72a0786SJohn Baldwin {
80d72a0786SJohn Baldwin
8115242987SJonathan T. Looney return (kcs_wait(sc, level ? KCS_STATUS_IBF : 0, KCS_STATUS_IBF));
82d72a0786SJohn Baldwin }
8315242987SJonathan T. Looney
8415242987SJonathan T. Looney static int
kcs_wait_for_obf(struct ipmi_softc * sc,bool level)8515242987SJonathan T. Looney kcs_wait_for_obf(struct ipmi_softc *sc, bool level)
8615242987SJonathan T. Looney {
8715242987SJonathan T. Looney
8815242987SJonathan T. Looney return (kcs_wait(sc, level ? KCS_STATUS_OBF : 0, KCS_STATUS_OBF));
89d72a0786SJohn Baldwin }
90d72a0786SJohn Baldwin
91d72a0786SJohn Baldwin static void
kcs_clear_obf(struct ipmi_softc * sc,int status)92d72a0786SJohn Baldwin kcs_clear_obf(struct ipmi_softc *sc, int status)
93d72a0786SJohn Baldwin {
94d72a0786SJohn Baldwin
95d72a0786SJohn Baldwin /* Clear OBF */
96d72a0786SJohn Baldwin if (status & KCS_STATUS_OBF) {
978707108fSWarner Losh INB(sc, KCS_DATA);
98d72a0786SJohn Baldwin }
99d72a0786SJohn Baldwin }
100d72a0786SJohn Baldwin
101d72a0786SJohn Baldwin static void
kcs_error(struct ipmi_softc * sc)102d72a0786SJohn Baldwin kcs_error(struct ipmi_softc *sc)
103d72a0786SJohn Baldwin {
104d72a0786SJohn Baldwin int retry, status;
105d72a0786SJohn Baldwin u_char data;
106d72a0786SJohn Baldwin
107d72a0786SJohn Baldwin for (retry = 0; retry < 2; retry++) {
108d72a0786SJohn Baldwin
109d72a0786SJohn Baldwin /* Wait for IBF = 0 */
110d72a0786SJohn Baldwin status = kcs_wait_for_ibf(sc, 0);
111d72a0786SJohn Baldwin
112d72a0786SJohn Baldwin /* ABORT */
113d72a0786SJohn Baldwin OUTB(sc, KCS_CTL_STS, KCS_CONTROL_GET_STATUS_ABORT);
114d72a0786SJohn Baldwin
115d72a0786SJohn Baldwin /* Wait for IBF = 0 */
116d72a0786SJohn Baldwin status = kcs_wait_for_ibf(sc, 0);
117d72a0786SJohn Baldwin
118d72a0786SJohn Baldwin /* Clear OBF */
119d72a0786SJohn Baldwin kcs_clear_obf(sc, status);
120d72a0786SJohn Baldwin
121d72a0786SJohn Baldwin if (status & KCS_STATUS_OBF) {
122d72a0786SJohn Baldwin data = INB(sc, KCS_DATA);
123d72a0786SJohn Baldwin if (data != 0)
124d72a0786SJohn Baldwin device_printf(sc->ipmi_dev,
125d72a0786SJohn Baldwin "KCS Error Data %02x\n", data);
126d72a0786SJohn Baldwin }
127d72a0786SJohn Baldwin
128d72a0786SJohn Baldwin /* 0x00 to DATA_IN */
129d72a0786SJohn Baldwin OUTB(sc, KCS_DATA, 0x00);
130d72a0786SJohn Baldwin
131d72a0786SJohn Baldwin /* Wait for IBF = 0 */
132d72a0786SJohn Baldwin status = kcs_wait_for_ibf(sc, 0);
133d72a0786SJohn Baldwin
134d72a0786SJohn Baldwin if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) {
135d72a0786SJohn Baldwin
136d72a0786SJohn Baldwin /* Wait for OBF = 1 */
137d72a0786SJohn Baldwin status = kcs_wait_for_obf(sc, 1);
138d72a0786SJohn Baldwin
139d72a0786SJohn Baldwin /* Read error status */
140d72a0786SJohn Baldwin data = INB(sc, KCS_DATA);
14174800c5aSJonathan T. Looney if (data != 0 && (data != 0xff || bootverbose))
142d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS error: %02x\n",
143d72a0786SJohn Baldwin data);
144d72a0786SJohn Baldwin
145d72a0786SJohn Baldwin /* Write READ into Data_in */
146d72a0786SJohn Baldwin OUTB(sc, KCS_DATA, KCS_DATA_IN_READ);
147d72a0786SJohn Baldwin
148d72a0786SJohn Baldwin /* Wait for IBF = 0 */
149d72a0786SJohn Baldwin status = kcs_wait_for_ibf(sc, 0);
150d72a0786SJohn Baldwin }
151d72a0786SJohn Baldwin
152d72a0786SJohn Baldwin /* IDLE STATE */
153d72a0786SJohn Baldwin if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) {
154d72a0786SJohn Baldwin /* Wait for OBF = 1 */
155d72a0786SJohn Baldwin status = kcs_wait_for_obf(sc, 1);
156d72a0786SJohn Baldwin
157d72a0786SJohn Baldwin /* Clear OBF */
158d72a0786SJohn Baldwin kcs_clear_obf(sc, status);
159d72a0786SJohn Baldwin return;
160d72a0786SJohn Baldwin }
161d72a0786SJohn Baldwin }
16293269b71SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Error retry exhausted\n");
163d72a0786SJohn Baldwin }
164d72a0786SJohn Baldwin
165d72a0786SJohn Baldwin /*
166d72a0786SJohn Baldwin * Start to write a request. Waits for IBF to clear and then sends the
167d72a0786SJohn Baldwin * WR_START command.
168d72a0786SJohn Baldwin */
169d72a0786SJohn Baldwin static int
kcs_start_write(struct ipmi_softc * sc)170d72a0786SJohn Baldwin kcs_start_write(struct ipmi_softc *sc)
171d72a0786SJohn Baldwin {
172d72a0786SJohn Baldwin int retry, status;
173d72a0786SJohn Baldwin
174d72a0786SJohn Baldwin for (retry = 0; retry < 10; retry++) {
175d72a0786SJohn Baldwin /* Wait for IBF = 0 */
176d72a0786SJohn Baldwin status = kcs_wait_for_ibf(sc, 0);
17751f25040SJohn Baldwin if (status & KCS_STATUS_IBF)
17851f25040SJohn Baldwin return (0);
179d72a0786SJohn Baldwin
180d72a0786SJohn Baldwin /* Clear OBF */
181d72a0786SJohn Baldwin kcs_clear_obf(sc, status);
182d72a0786SJohn Baldwin
183d72a0786SJohn Baldwin /* Write start to command */
184d72a0786SJohn Baldwin OUTB(sc, KCS_CTL_STS, KCS_CONTROL_WRITE_START);
185d72a0786SJohn Baldwin
186d72a0786SJohn Baldwin /* Wait for IBF = 0 */
187d72a0786SJohn Baldwin status = kcs_wait_for_ibf(sc, 0);
18851f25040SJohn Baldwin if (status & KCS_STATUS_IBF)
18951f25040SJohn Baldwin return (0);
19051f25040SJohn Baldwin
191d72a0786SJohn Baldwin if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_WRITE)
192d72a0786SJohn Baldwin break;
193d72a0786SJohn Baldwin DELAY(1000000);
194d72a0786SJohn Baldwin }
195d72a0786SJohn Baldwin
196d72a0786SJohn Baldwin if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE)
197d72a0786SJohn Baldwin /* error state */
198d72a0786SJohn Baldwin return (0);
199d72a0786SJohn Baldwin
200d72a0786SJohn Baldwin /* Clear OBF */
201d72a0786SJohn Baldwin kcs_clear_obf(sc, status);
202d72a0786SJohn Baldwin
203d72a0786SJohn Baldwin return (1);
204d72a0786SJohn Baldwin }
205d72a0786SJohn Baldwin
206d72a0786SJohn Baldwin /*
207d72a0786SJohn Baldwin * Write a byte of the request message, excluding the last byte of the
208d72a0786SJohn Baldwin * message which requires special handling.
209d72a0786SJohn Baldwin */
210d72a0786SJohn Baldwin static int
kcs_write_byte(struct ipmi_softc * sc,u_char data)211d72a0786SJohn Baldwin kcs_write_byte(struct ipmi_softc *sc, u_char data)
212d72a0786SJohn Baldwin {
213d72a0786SJohn Baldwin int status;
214d72a0786SJohn Baldwin
215d72a0786SJohn Baldwin /* Data to Data */
216d72a0786SJohn Baldwin OUTB(sc, KCS_DATA, data);
217d72a0786SJohn Baldwin
218d72a0786SJohn Baldwin /* Wait for IBF = 0 */
219d72a0786SJohn Baldwin status = kcs_wait_for_ibf(sc, 0);
22051f25040SJohn Baldwin if (status & KCS_STATUS_IBF)
22151f25040SJohn Baldwin return (0);
222d72a0786SJohn Baldwin
223d72a0786SJohn Baldwin if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE)
224d72a0786SJohn Baldwin return (0);
225d72a0786SJohn Baldwin
226d72a0786SJohn Baldwin /* Clear OBF */
227d72a0786SJohn Baldwin kcs_clear_obf(sc, status);
228d72a0786SJohn Baldwin return (1);
229d72a0786SJohn Baldwin }
230d72a0786SJohn Baldwin
231d72a0786SJohn Baldwin /*
232d72a0786SJohn Baldwin * Write the last byte of a request message.
233d72a0786SJohn Baldwin */
234d72a0786SJohn Baldwin static int
kcs_write_last_byte(struct ipmi_softc * sc,u_char data)235d72a0786SJohn Baldwin kcs_write_last_byte(struct ipmi_softc *sc, u_char data)
236d72a0786SJohn Baldwin {
237d72a0786SJohn Baldwin int status;
238d72a0786SJohn Baldwin
239d72a0786SJohn Baldwin /* Write end to command */
240d72a0786SJohn Baldwin OUTB(sc, KCS_CTL_STS, KCS_CONTROL_WRITE_END);
241d72a0786SJohn Baldwin
242d72a0786SJohn Baldwin /* Wait for IBF = 0 */
243d72a0786SJohn Baldwin status = kcs_wait_for_ibf(sc, 0);
24451f25040SJohn Baldwin if (status & KCS_STATUS_IBF)
24551f25040SJohn Baldwin return (0);
246d72a0786SJohn Baldwin
247d72a0786SJohn Baldwin if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE)
248d72a0786SJohn Baldwin /* error state */
249d72a0786SJohn Baldwin return (0);
250d72a0786SJohn Baldwin
251d72a0786SJohn Baldwin /* Clear OBF */
252d72a0786SJohn Baldwin kcs_clear_obf(sc, status);
253d72a0786SJohn Baldwin
254d72a0786SJohn Baldwin /* Send data byte to DATA. */
255d72a0786SJohn Baldwin OUTB(sc, KCS_DATA, data);
256d72a0786SJohn Baldwin return (1);
257d72a0786SJohn Baldwin }
258d72a0786SJohn Baldwin
259d72a0786SJohn Baldwin /*
260d72a0786SJohn Baldwin * Read one byte of the reply message.
261d72a0786SJohn Baldwin */
262d72a0786SJohn Baldwin static int
kcs_read_byte(struct ipmi_softc * sc,u_char * data)263d72a0786SJohn Baldwin kcs_read_byte(struct ipmi_softc *sc, u_char *data)
264d72a0786SJohn Baldwin {
265d72a0786SJohn Baldwin int status;
266d72a0786SJohn Baldwin
267d72a0786SJohn Baldwin /* Wait for IBF = 0 */
268d72a0786SJohn Baldwin status = kcs_wait_for_ibf(sc, 0);
269d72a0786SJohn Baldwin
270d72a0786SJohn Baldwin /* Read State */
271d72a0786SJohn Baldwin if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) {
272d72a0786SJohn Baldwin
273d72a0786SJohn Baldwin /* Wait for OBF = 1 */
274d72a0786SJohn Baldwin status = kcs_wait_for_obf(sc, 1);
27551f25040SJohn Baldwin if ((status & KCS_STATUS_OBF) == 0)
27651f25040SJohn Baldwin return (0);
277d72a0786SJohn Baldwin
278d72a0786SJohn Baldwin /* Read Data_out */
279d72a0786SJohn Baldwin *data = INB(sc, KCS_DATA);
280d72a0786SJohn Baldwin
281d72a0786SJohn Baldwin /* Write READ into Data_in */
282d72a0786SJohn Baldwin OUTB(sc, KCS_DATA, KCS_DATA_IN_READ);
283d72a0786SJohn Baldwin return (1);
284d72a0786SJohn Baldwin }
285d72a0786SJohn Baldwin
286d72a0786SJohn Baldwin /* Idle State */
287d72a0786SJohn Baldwin if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) {
288d72a0786SJohn Baldwin
289d72a0786SJohn Baldwin /* Wait for OBF = 1*/
290d72a0786SJohn Baldwin status = kcs_wait_for_obf(sc, 1);
29151f25040SJohn Baldwin if ((status & KCS_STATUS_OBF) == 0)
29251f25040SJohn Baldwin return (0);
293d72a0786SJohn Baldwin
294d72a0786SJohn Baldwin /* Read Dummy */
2958707108fSWarner Losh INB(sc, KCS_DATA);
296d72a0786SJohn Baldwin return (2);
297d72a0786SJohn Baldwin }
298d72a0786SJohn Baldwin
299d72a0786SJohn Baldwin /* Error State */
300d72a0786SJohn Baldwin return (0);
301d72a0786SJohn Baldwin }
302d72a0786SJohn Baldwin
303d72a0786SJohn Baldwin /*
304d72a0786SJohn Baldwin * Send a request message and collect the reply. Returns true if we
305d72a0786SJohn Baldwin * succeed.
306d72a0786SJohn Baldwin */
307d72a0786SJohn Baldwin static int
kcs_polled_request(struct ipmi_softc * sc,struct ipmi_request * req)308d72a0786SJohn Baldwin kcs_polled_request(struct ipmi_softc *sc, struct ipmi_request *req)
309d72a0786SJohn Baldwin {
310d72a0786SJohn Baldwin u_char *cp, data;
311d72a0786SJohn Baldwin int i, state;
312d72a0786SJohn Baldwin
313c869aa71SJohn Baldwin IPMI_IO_LOCK(sc);
314c869aa71SJohn Baldwin
315d72a0786SJohn Baldwin /* Send the request. */
316d72a0786SJohn Baldwin if (!kcs_start_write(sc)) {
317d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Failed to start write\n");
318d72a0786SJohn Baldwin goto fail;
319d72a0786SJohn Baldwin }
320d72a0786SJohn Baldwin #ifdef KCS_DEBUG
321d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: WRITE_START... ok\n");
322d72a0786SJohn Baldwin #endif
323d72a0786SJohn Baldwin
324d72a0786SJohn Baldwin if (!kcs_write_byte(sc, req->ir_addr)) {
325d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Failed to write address\n");
326d72a0786SJohn Baldwin goto fail;
327d72a0786SJohn Baldwin }
328d72a0786SJohn Baldwin #ifdef KCS_DEBUG
329d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Wrote address: %02x\n", req->ir_addr);
330d72a0786SJohn Baldwin #endif
331d72a0786SJohn Baldwin
332d72a0786SJohn Baldwin if (req->ir_requestlen == 0) {
333d72a0786SJohn Baldwin if (!kcs_write_last_byte(sc, req->ir_command)) {
334d72a0786SJohn Baldwin device_printf(sc->ipmi_dev,
335d72a0786SJohn Baldwin "KCS: Failed to write command\n");
336d72a0786SJohn Baldwin goto fail;
337d72a0786SJohn Baldwin }
338d72a0786SJohn Baldwin #ifdef KCS_DEBUG
339d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Wrote command: %02x\n",
340d72a0786SJohn Baldwin req->ir_command);
341d72a0786SJohn Baldwin #endif
342d72a0786SJohn Baldwin } else {
343d72a0786SJohn Baldwin if (!kcs_write_byte(sc, req->ir_command)) {
344d72a0786SJohn Baldwin device_printf(sc->ipmi_dev,
345d72a0786SJohn Baldwin "KCS: Failed to write command\n");
346d72a0786SJohn Baldwin goto fail;
347d72a0786SJohn Baldwin }
348d72a0786SJohn Baldwin #ifdef KCS_DEBUG
349d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Wrote command: %02x\n",
350d72a0786SJohn Baldwin req->ir_command);
351d72a0786SJohn Baldwin #endif
352d72a0786SJohn Baldwin
353d72a0786SJohn Baldwin cp = req->ir_request;
354d72a0786SJohn Baldwin for (i = 0; i < req->ir_requestlen - 1; i++) {
355d72a0786SJohn Baldwin if (!kcs_write_byte(sc, *cp++)) {
356d72a0786SJohn Baldwin device_printf(sc->ipmi_dev,
357d72a0786SJohn Baldwin "KCS: Failed to write data byte %d\n",
358d72a0786SJohn Baldwin i + 1);
359d72a0786SJohn Baldwin goto fail;
360d72a0786SJohn Baldwin }
361d72a0786SJohn Baldwin #ifdef KCS_DEBUG
362d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Wrote data: %02x\n",
363d72a0786SJohn Baldwin cp[-1]);
364d72a0786SJohn Baldwin #endif
365d72a0786SJohn Baldwin }
366d72a0786SJohn Baldwin
367d72a0786SJohn Baldwin if (!kcs_write_last_byte(sc, *cp)) {
368d72a0786SJohn Baldwin device_printf(sc->ipmi_dev,
369d72a0786SJohn Baldwin "KCS: Failed to write last dta byte\n");
370d72a0786SJohn Baldwin goto fail;
371d72a0786SJohn Baldwin }
372d72a0786SJohn Baldwin #ifdef KCS_DEBUG
373d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Wrote last data: %02x\n",
374d72a0786SJohn Baldwin *cp);
375d72a0786SJohn Baldwin #endif
376d72a0786SJohn Baldwin }
377d72a0786SJohn Baldwin
378d72a0786SJohn Baldwin /* Read the reply. First, read the NetFn/LUN. */
379d72a0786SJohn Baldwin if (kcs_read_byte(sc, &data) != 1) {
380d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Failed to read address\n");
381d72a0786SJohn Baldwin goto fail;
382d72a0786SJohn Baldwin }
383d72a0786SJohn Baldwin #ifdef KCS_DEBUG
384d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Read address: %02x\n", data);
385d72a0786SJohn Baldwin #endif
386d72a0786SJohn Baldwin if (data != IPMI_REPLY_ADDR(req->ir_addr)) {
387d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Reply address mismatch\n");
388d72a0786SJohn Baldwin goto fail;
389d72a0786SJohn Baldwin }
390d72a0786SJohn Baldwin
391d72a0786SJohn Baldwin /* Next we read the command. */
392d72a0786SJohn Baldwin if (kcs_read_byte(sc, &data) != 1) {
393d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Failed to read command\n");
394d72a0786SJohn Baldwin goto fail;
395d72a0786SJohn Baldwin }
396d72a0786SJohn Baldwin #ifdef KCS_DEBUG
397d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Read command: %02x\n", data);
398d72a0786SJohn Baldwin #endif
399d72a0786SJohn Baldwin if (data != req->ir_command) {
400d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Command mismatch\n");
401d72a0786SJohn Baldwin goto fail;
402d72a0786SJohn Baldwin }
403d72a0786SJohn Baldwin
404d72a0786SJohn Baldwin /* Next we read the completion code. */
405d72a0786SJohn Baldwin if (kcs_read_byte(sc, &req->ir_compcode) != 1) {
40674800c5aSJonathan T. Looney if (bootverbose) {
407d72a0786SJohn Baldwin device_printf(sc->ipmi_dev,
408d72a0786SJohn Baldwin "KCS: Failed to read completion code\n");
40974800c5aSJonathan T. Looney }
410d72a0786SJohn Baldwin goto fail;
411d72a0786SJohn Baldwin }
412d72a0786SJohn Baldwin #ifdef KCS_DEBUG
413d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Read completion code: %02x\n",
414d72a0786SJohn Baldwin req->ir_compcode);
415d72a0786SJohn Baldwin #endif
416d72a0786SJohn Baldwin
417d72a0786SJohn Baldwin /* Finally, read the reply from the BMC. */
418d72a0786SJohn Baldwin i = 0;
419d72a0786SJohn Baldwin for (;;) {
420d72a0786SJohn Baldwin state = kcs_read_byte(sc, &data);
421d72a0786SJohn Baldwin if (state == 0) {
422d72a0786SJohn Baldwin device_printf(sc->ipmi_dev,
423d72a0786SJohn Baldwin "KCS: Read failed on byte %d\n", i + 1);
424d72a0786SJohn Baldwin goto fail;
425d72a0786SJohn Baldwin }
426d72a0786SJohn Baldwin if (state == 2)
427d72a0786SJohn Baldwin break;
428d72a0786SJohn Baldwin if (i < req->ir_replybuflen) {
429d72a0786SJohn Baldwin req->ir_reply[i] = data;
430d72a0786SJohn Baldwin #ifdef KCS_DEBUG
431d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: Read data %02x\n",
432d72a0786SJohn Baldwin data);
433d72a0786SJohn Baldwin } else {
434d72a0786SJohn Baldwin device_printf(sc->ipmi_dev,
435d72a0786SJohn Baldwin "KCS: Read short %02x byte %d\n", data, i + 1);
436d72a0786SJohn Baldwin #endif
437d72a0786SJohn Baldwin }
438d72a0786SJohn Baldwin i++;
439d72a0786SJohn Baldwin }
440c869aa71SJohn Baldwin IPMI_IO_UNLOCK(sc);
441d72a0786SJohn Baldwin req->ir_replylen = i;
442d72a0786SJohn Baldwin #ifdef KCS_DEBUG
443d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: READ finished (%d bytes)\n", i);
444d72a0786SJohn Baldwin if (req->ir_replybuflen < i)
445d72a0786SJohn Baldwin #else
446d72a0786SJohn Baldwin if (req->ir_replybuflen < i && req->ir_replybuflen != 0)
447d72a0786SJohn Baldwin #endif
448d72a0786SJohn Baldwin device_printf(sc->ipmi_dev,
449d72a0786SJohn Baldwin "KCS: Read short: %zd buffer, %d actual\n",
450d72a0786SJohn Baldwin req->ir_replybuflen, i);
451d72a0786SJohn Baldwin return (1);
452d72a0786SJohn Baldwin fail:
453d72a0786SJohn Baldwin kcs_error(sc);
454c869aa71SJohn Baldwin IPMI_IO_UNLOCK(sc);
455d72a0786SJohn Baldwin return (0);
456d72a0786SJohn Baldwin }
457d72a0786SJohn Baldwin
458d72a0786SJohn Baldwin static void
kcs_loop(void * arg)459d72a0786SJohn Baldwin kcs_loop(void *arg)
460d72a0786SJohn Baldwin {
461d72a0786SJohn Baldwin struct ipmi_softc *sc = arg;
462d72a0786SJohn Baldwin struct ipmi_request *req;
463d72a0786SJohn Baldwin int i, ok;
464d72a0786SJohn Baldwin
465d72a0786SJohn Baldwin IPMI_LOCK(sc);
466d72a0786SJohn Baldwin while ((req = ipmi_dequeue_request(sc)) != NULL) {
46758e8e6e6SAlexander V. Chernikov IPMI_UNLOCK(sc);
468d72a0786SJohn Baldwin ok = 0;
469d72a0786SJohn Baldwin for (i = 0; i < 3 && !ok; i++)
470d72a0786SJohn Baldwin ok = kcs_polled_request(sc, req);
471d72a0786SJohn Baldwin if (ok)
472d72a0786SJohn Baldwin req->ir_error = 0;
473d72a0786SJohn Baldwin else
474d72a0786SJohn Baldwin req->ir_error = EIO;
47558e8e6e6SAlexander V. Chernikov IPMI_LOCK(sc);
476d72a0786SJohn Baldwin ipmi_complete_request(sc, req);
477d72a0786SJohn Baldwin }
478d72a0786SJohn Baldwin IPMI_UNLOCK(sc);
4793745c395SJulian Elischer kproc_exit(0);
480d72a0786SJohn Baldwin }
481d72a0786SJohn Baldwin
482d72a0786SJohn Baldwin static int
kcs_startup(struct ipmi_softc * sc)483d72a0786SJohn Baldwin kcs_startup(struct ipmi_softc *sc)
484d72a0786SJohn Baldwin {
485d72a0786SJohn Baldwin
4863745c395SJulian Elischer return (kproc_create(kcs_loop, sc, &sc->ipmi_kthread, 0, 0, "%s: kcs",
487d72a0786SJohn Baldwin device_get_nameunit(sc->ipmi_dev)));
488d72a0786SJohn Baldwin }
489d72a0786SJohn Baldwin
490c869aa71SJohn Baldwin static int
kcs_driver_request_queue(struct ipmi_softc * sc,struct ipmi_request * req)491*366d6a42SGleb Smirnoff kcs_driver_request_queue(struct ipmi_softc *sc, struct ipmi_request *req)
492f0f3e3e9SChuck Silvers {
493f0f3e3e9SChuck Silvers int error;
494f0f3e3e9SChuck Silvers
495f0f3e3e9SChuck Silvers IPMI_LOCK(sc);
496f0f3e3e9SChuck Silvers ipmi_polled_enqueue_request_highpri(sc, req);
497*366d6a42SGleb Smirnoff error = msleep(req, &sc->ipmi_requests_lock, 0, "ipmireq", 0);
498f0f3e3e9SChuck Silvers if (error == 0)
499f0f3e3e9SChuck Silvers error = req->ir_error;
500f0f3e3e9SChuck Silvers IPMI_UNLOCK(sc);
501f0f3e3e9SChuck Silvers return (error);
502f0f3e3e9SChuck Silvers }
503f0f3e3e9SChuck Silvers
504f0f3e3e9SChuck Silvers static int
kcs_driver_request_poll(struct ipmi_softc * sc,struct ipmi_request * req)505f0f3e3e9SChuck Silvers kcs_driver_request_poll(struct ipmi_softc *sc, struct ipmi_request *req)
506c869aa71SJohn Baldwin {
507c869aa71SJohn Baldwin int i, ok;
508c869aa71SJohn Baldwin
509c869aa71SJohn Baldwin ok = 0;
510c869aa71SJohn Baldwin for (i = 0; i < 3 && !ok; i++)
511c869aa71SJohn Baldwin ok = kcs_polled_request(sc, req);
512c869aa71SJohn Baldwin if (ok)
513c869aa71SJohn Baldwin req->ir_error = 0;
514c869aa71SJohn Baldwin else
515c869aa71SJohn Baldwin req->ir_error = EIO;
516c869aa71SJohn Baldwin return (req->ir_error);
517c869aa71SJohn Baldwin }
518c869aa71SJohn Baldwin
519f0f3e3e9SChuck Silvers static int
kcs_driver_request(struct ipmi_softc * sc,struct ipmi_request * req)520*366d6a42SGleb Smirnoff kcs_driver_request(struct ipmi_softc *sc, struct ipmi_request *req)
521f0f3e3e9SChuck Silvers {
522f0f3e3e9SChuck Silvers
523f0f3e3e9SChuck Silvers if (KERNEL_PANICKED() || dumping)
524f0f3e3e9SChuck Silvers return (kcs_driver_request_poll(sc, req));
525f0f3e3e9SChuck Silvers else
526*366d6a42SGleb Smirnoff return (kcs_driver_request_queue(sc, req));
527f0f3e3e9SChuck Silvers }
528f0f3e3e9SChuck Silvers
529f0f3e3e9SChuck Silvers
530d72a0786SJohn Baldwin int
ipmi_kcs_attach(struct ipmi_softc * sc)531d72a0786SJohn Baldwin ipmi_kcs_attach(struct ipmi_softc *sc)
532d72a0786SJohn Baldwin {
533d72a0786SJohn Baldwin int status;
534d72a0786SJohn Baldwin
535d72a0786SJohn Baldwin /* Setup function pointers. */
536d72a0786SJohn Baldwin sc->ipmi_startup = kcs_startup;
537d72a0786SJohn Baldwin sc->ipmi_enqueue_request = ipmi_polled_enqueue_request;
538c869aa71SJohn Baldwin sc->ipmi_driver_request = kcs_driver_request;
5399662eef5SJohn Baldwin sc->ipmi_driver_requests_polled = 1;
540d72a0786SJohn Baldwin
541d72a0786SJohn Baldwin /* See if we can talk to the controller. */
542d72a0786SJohn Baldwin status = INB(sc, KCS_CTL_STS);
543d72a0786SJohn Baldwin if (status == 0xff) {
544d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "couldn't find it\n");
545d72a0786SJohn Baldwin return (ENXIO);
546d72a0786SJohn Baldwin }
547d72a0786SJohn Baldwin
548d72a0786SJohn Baldwin #ifdef KCS_DEBUG
549d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS: initial state: %02x\n", status);
550d72a0786SJohn Baldwin #endif
551d72a0786SJohn Baldwin if (status & KCS_STATUS_OBF ||
552d72a0786SJohn Baldwin KCS_STATUS_STATE(status) != KCS_STATUS_STATE_IDLE)
553d72a0786SJohn Baldwin kcs_error(sc);
554d72a0786SJohn Baldwin
555d72a0786SJohn Baldwin return (0);
556d72a0786SJohn Baldwin }
557d72a0786SJohn Baldwin
558d72a0786SJohn Baldwin /*
559d72a0786SJohn Baldwin * Determine the alignment automatically for a PCI attachment. In this case,
560d72a0786SJohn Baldwin * any unused bytes will return 0x00 when read. We make use of the C/D bit
561d72a0786SJohn Baldwin * in the CTL_STS register to try to start a GET_STATUS transaction. When
562d72a0786SJohn Baldwin * we write the command, that bit should be set, so we should get a non-zero
563d72a0786SJohn Baldwin * value back when we read CTL_STS if the offset we are testing is the CTL_STS
564d72a0786SJohn Baldwin * register.
565d72a0786SJohn Baldwin */
566d72a0786SJohn Baldwin int
ipmi_kcs_probe_align(struct ipmi_softc * sc)567d72a0786SJohn Baldwin ipmi_kcs_probe_align(struct ipmi_softc *sc)
568d72a0786SJohn Baldwin {
5698707108fSWarner Losh int status;
570d72a0786SJohn Baldwin
571d72a0786SJohn Baldwin sc->ipmi_io_spacing = 1;
572d72a0786SJohn Baldwin retry:
573d72a0786SJohn Baldwin #ifdef KCS_DEBUG
574d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "Trying KCS align %d... ", sc->ipmi_io_spacing);
575d72a0786SJohn Baldwin #endif
576d72a0786SJohn Baldwin
577d72a0786SJohn Baldwin /* Wait for IBF = 0 */
578d72a0786SJohn Baldwin status = INB(sc, KCS_CTL_STS);
579d72a0786SJohn Baldwin while (status & KCS_STATUS_IBF) {
580d72a0786SJohn Baldwin DELAY(100);
581d72a0786SJohn Baldwin status = INB(sc, KCS_CTL_STS);
582d72a0786SJohn Baldwin }
583d72a0786SJohn Baldwin
584d72a0786SJohn Baldwin OUTB(sc, KCS_CTL_STS, KCS_CONTROL_GET_STATUS_ABORT);
585d72a0786SJohn Baldwin
586d72a0786SJohn Baldwin /* Wait for IBF = 0 */
587d72a0786SJohn Baldwin status = INB(sc, KCS_CTL_STS);
588d72a0786SJohn Baldwin while (status & KCS_STATUS_IBF) {
589d72a0786SJohn Baldwin DELAY(100);
590d72a0786SJohn Baldwin status = INB(sc, KCS_CTL_STS);
591d72a0786SJohn Baldwin }
592d72a0786SJohn Baldwin
593d72a0786SJohn Baldwin /* If we got 0x00 back, then this must not be the CTL_STS register. */
594d72a0786SJohn Baldwin if (status == 0) {
595d72a0786SJohn Baldwin #ifdef KCS_DEBUG
596d72a0786SJohn Baldwin printf("failed\n");
597d72a0786SJohn Baldwin #endif
598d72a0786SJohn Baldwin sc->ipmi_io_spacing <<= 1;
599d72a0786SJohn Baldwin if (sc->ipmi_io_spacing > 4)
600d72a0786SJohn Baldwin return (0);
601d72a0786SJohn Baldwin goto retry;
602d72a0786SJohn Baldwin }
603d72a0786SJohn Baldwin #ifdef KCS_DEBUG
604d72a0786SJohn Baldwin printf("ok\n");
605d72a0786SJohn Baldwin #endif
606d72a0786SJohn Baldwin
607d72a0786SJohn Baldwin /* Finish out the transaction. */
608d72a0786SJohn Baldwin
609d72a0786SJohn Baldwin /* Clear OBF */
61093269b71SJohn Baldwin if (status & KCS_STATUS_OBF)
6118707108fSWarner Losh INB(sc, KCS_DATA);
612d72a0786SJohn Baldwin
613d72a0786SJohn Baldwin /* 0x00 to DATA_IN */
614d72a0786SJohn Baldwin OUTB(sc, KCS_DATA, 0);
615d72a0786SJohn Baldwin
616d72a0786SJohn Baldwin /* Wait for IBF = 0 */
617d72a0786SJohn Baldwin status = INB(sc, KCS_CTL_STS);
618d72a0786SJohn Baldwin while (status & KCS_STATUS_IBF) {
619d72a0786SJohn Baldwin DELAY(100);
620d72a0786SJohn Baldwin status = INB(sc, KCS_CTL_STS);
621d72a0786SJohn Baldwin }
622d72a0786SJohn Baldwin
623d72a0786SJohn Baldwin if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) {
624d72a0786SJohn Baldwin /* Wait for IBF = 1 */
625d72a0786SJohn Baldwin while (!(status & KCS_STATUS_OBF)) {
626d72a0786SJohn Baldwin DELAY(100);
627d72a0786SJohn Baldwin status = INB(sc, KCS_CTL_STS);
628d72a0786SJohn Baldwin }
629d72a0786SJohn Baldwin
630d72a0786SJohn Baldwin /* Read error status. */
6318707108fSWarner Losh INB(sc, KCS_DATA);
632d72a0786SJohn Baldwin
633d72a0786SJohn Baldwin /* Write dummy READ to DATA_IN. */
634d72a0786SJohn Baldwin OUTB(sc, KCS_DATA, KCS_DATA_IN_READ);
635d72a0786SJohn Baldwin
636d72a0786SJohn Baldwin /* Wait for IBF = 0 */
637d72a0786SJohn Baldwin status = INB(sc, KCS_CTL_STS);
638d72a0786SJohn Baldwin while (status & KCS_STATUS_IBF) {
639d72a0786SJohn Baldwin DELAY(100);
640d72a0786SJohn Baldwin status = INB(sc, KCS_CTL_STS);
641d72a0786SJohn Baldwin }
642d72a0786SJohn Baldwin }
643d72a0786SJohn Baldwin
644d72a0786SJohn Baldwin if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) {
645d72a0786SJohn Baldwin /* Wait for IBF = 1 */
646d72a0786SJohn Baldwin while (!(status & KCS_STATUS_OBF)) {
647d72a0786SJohn Baldwin DELAY(100);
648d72a0786SJohn Baldwin status = INB(sc, KCS_CTL_STS);
649d72a0786SJohn Baldwin }
650d72a0786SJohn Baldwin
651d72a0786SJohn Baldwin /* Clear OBF */
65293269b71SJohn Baldwin if (status & KCS_STATUS_OBF)
6538707108fSWarner Losh INB(sc, KCS_DATA);
654d72a0786SJohn Baldwin } else
655d72a0786SJohn Baldwin device_printf(sc->ipmi_dev, "KCS probe: end state %x\n",
656d72a0786SJohn Baldwin KCS_STATUS_STATE(status));
657d72a0786SJohn Baldwin
658d72a0786SJohn Baldwin return (1);
659d72a0786SJohn Baldwin }
660