ipmi_kcs.c revision 276065
1162562Sjhb/*-
2162562Sjhb * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
3162562Sjhb * All rights reserved.
4162562Sjhb *
5162562Sjhb * Redistribution and use in source and binary forms, with or without
6162562Sjhb * modification, are permitted provided that the following conditions
7162562Sjhb * are met:
8162562Sjhb * 1. Redistributions of source code must retain the above copyright
9162562Sjhb *    notice, this list of conditions and the following disclaimer.
10162562Sjhb * 2. Redistributions in binary form must reproduce the above copyright
11162562Sjhb *    notice, this list of conditions and the following disclaimer in the
12162562Sjhb *    documentation and/or other materials provided with the distribution.
13162562Sjhb *
14162562Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15162562Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16162562Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17162562Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18162562Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19162562Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20162562Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21162562Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22162562Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23162562Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24162562Sjhb * SUCH DAMAGE.
25162562Sjhb */
26162562Sjhb
27162562Sjhb#include <sys/cdefs.h>
28162562Sjhb__FBSDID("$FreeBSD: head/sys/dev/ipmi/ipmi_kcs.c 276065 2014-12-22 16:53:04Z jhb $");
29162562Sjhb
30162562Sjhb#include <sys/param.h>
31162562Sjhb#include <sys/systm.h>
32162562Sjhb#include <sys/bus.h>
33162562Sjhb#include <sys/condvar.h>
34162562Sjhb#include <sys/eventhandler.h>
35162562Sjhb#include <sys/kernel.h>
36162562Sjhb#include <sys/kthread.h>
37162562Sjhb#include <sys/rman.h>
38162562Sjhb#include <sys/selinfo.h>
39162562Sjhb#include <machine/bus.h>
40162562Sjhb
41162562Sjhb#ifdef LOCAL_MODULE
42162562Sjhb#include <ipmi.h>
43162562Sjhb#include <ipmivars.h>
44162562Sjhb#else
45162562Sjhb#include <sys/ipmi.h>
46162562Sjhb#include <dev/ipmi/ipmivars.h>
47162562Sjhb#endif
48162562Sjhb
49162562Sjhbstatic void	kcs_clear_obf(struct ipmi_softc *, int);
50162562Sjhbstatic void	kcs_error(struct ipmi_softc *);
51162562Sjhbstatic int	kcs_wait_for_ibf(struct ipmi_softc *, int);
52162562Sjhbstatic int	kcs_wait_for_obf(struct ipmi_softc *, int);
53162562Sjhb
54162562Sjhbstatic int
55162562Sjhbkcs_wait_for_ibf(struct ipmi_softc *sc, int state)
56162562Sjhb{
57162562Sjhb	int status, start = ticks;
58162562Sjhb
59162562Sjhb	status = INB(sc, KCS_CTL_STS);
60162562Sjhb	if (state == 0) {
61162562Sjhb		/* WAIT FOR IBF = 0 */
62162562Sjhb		while (ticks - start < MAX_TIMEOUT && status & KCS_STATUS_IBF) {
63162562Sjhb			DELAY(100);
64162562Sjhb			status = INB(sc, KCS_CTL_STS);
65162562Sjhb		}
66162562Sjhb	} else {
67162562Sjhb		/* WAIT FOR IBF = 1 */
68162562Sjhb		while (ticks - start < MAX_TIMEOUT &&
69162562Sjhb		    !(status & KCS_STATUS_IBF)) {
70162562Sjhb			DELAY(100);
71162562Sjhb			status = INB(sc, KCS_CTL_STS);
72162562Sjhb		}
73162562Sjhb	}
74162562Sjhb	return (status);
75162562Sjhb}
76162562Sjhb
77162562Sjhbstatic int
78162562Sjhbkcs_wait_for_obf(struct ipmi_softc *sc, int state)
79162562Sjhb{
80162562Sjhb	int status, start = ticks;
81162562Sjhb
82162562Sjhb	status = INB(sc, KCS_CTL_STS);
83162562Sjhb	if (state == 0) {
84162562Sjhb		/* WAIT FOR OBF = 0 */
85162562Sjhb		while (ticks - start < MAX_TIMEOUT && status & KCS_STATUS_OBF) {
86162562Sjhb			DELAY(100);
87162562Sjhb			status = INB(sc, KCS_CTL_STS);
88162562Sjhb		}
89162562Sjhb	} else {
90162562Sjhb		/* WAIT FOR OBF = 1 */
91162562Sjhb		while (ticks - start < MAX_TIMEOUT &&
92162562Sjhb		    !(status & KCS_STATUS_OBF)) {
93162562Sjhb			DELAY(100);
94162562Sjhb			status = INB(sc, KCS_CTL_STS);
95162562Sjhb		}
96162562Sjhb	}
97162562Sjhb	return (status);
98162562Sjhb}
99162562Sjhb
100162562Sjhbstatic void
101162562Sjhbkcs_clear_obf(struct ipmi_softc *sc, int status)
102162562Sjhb{
103162562Sjhb	int data;
104162562Sjhb
105162562Sjhb	/* Clear OBF */
106162562Sjhb	if (status & KCS_STATUS_OBF) {
107162562Sjhb		data = INB(sc, KCS_DATA);
108162562Sjhb	}
109162562Sjhb}
110162562Sjhb
111162562Sjhbstatic void
112162562Sjhbkcs_error(struct ipmi_softc *sc)
113162562Sjhb{
114162562Sjhb	int retry, status;
115162562Sjhb	u_char data;
116162562Sjhb
117162562Sjhb	for (retry = 0; retry < 2; retry++) {
118162562Sjhb
119162562Sjhb		/* Wait for IBF = 0 */
120162562Sjhb		status = kcs_wait_for_ibf(sc, 0);
121162562Sjhb
122162562Sjhb		/* ABORT */
123162562Sjhb		OUTB(sc, KCS_CTL_STS, KCS_CONTROL_GET_STATUS_ABORT);
124162562Sjhb
125162562Sjhb		/* Wait for IBF = 0 */
126162562Sjhb		status = kcs_wait_for_ibf(sc, 0);
127162562Sjhb
128162562Sjhb		/* Clear OBF */
129162562Sjhb		kcs_clear_obf(sc, status);
130162562Sjhb
131162562Sjhb		if (status & KCS_STATUS_OBF) {
132162562Sjhb			data = INB(sc, KCS_DATA);
133162562Sjhb			if (data != 0)
134162562Sjhb				device_printf(sc->ipmi_dev,
135162562Sjhb				    "KCS Error Data %02x\n", data);
136162562Sjhb		}
137162562Sjhb
138162562Sjhb		/* 0x00 to DATA_IN */
139162562Sjhb		OUTB(sc, KCS_DATA, 0x00);
140162562Sjhb
141162562Sjhb		/* Wait for IBF = 0 */
142162562Sjhb		status = kcs_wait_for_ibf(sc, 0);
143162562Sjhb
144162562Sjhb		if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) {
145162562Sjhb
146162562Sjhb			/* Wait for OBF = 1 */
147162562Sjhb			status = kcs_wait_for_obf(sc, 1);
148162562Sjhb
149162562Sjhb			/* Read error status */
150162562Sjhb			data = INB(sc, KCS_DATA);
151162562Sjhb			if (data != 0)
152162562Sjhb				device_printf(sc->ipmi_dev, "KCS error: %02x\n",
153162562Sjhb				    data);
154162562Sjhb
155162562Sjhb			/* Write READ into Data_in */
156162562Sjhb			OUTB(sc, KCS_DATA, KCS_DATA_IN_READ);
157162562Sjhb
158162562Sjhb			/* Wait for IBF = 0 */
159162562Sjhb			status = kcs_wait_for_ibf(sc, 0);
160162562Sjhb		}
161162562Sjhb
162162562Sjhb		/* IDLE STATE */
163162562Sjhb		if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) {
164162562Sjhb			/* Wait for OBF = 1 */
165162562Sjhb			status = kcs_wait_for_obf(sc, 1);
166162562Sjhb
167162562Sjhb			/* Clear OBF */
168162562Sjhb			kcs_clear_obf(sc, status);
169162562Sjhb			return;
170162562Sjhb		}
171162562Sjhb	}
172182321Sjhb	device_printf(sc->ipmi_dev, "KCS: Error retry exhausted\n");
173162562Sjhb}
174162562Sjhb
175162562Sjhb/*
176162562Sjhb * Start to write a request.  Waits for IBF to clear and then sends the
177162562Sjhb * WR_START command.
178162562Sjhb */
179162562Sjhbstatic int
180162562Sjhbkcs_start_write(struct ipmi_softc *sc)
181162562Sjhb{
182162562Sjhb	int retry, status;
183162562Sjhb
184162562Sjhb	for (retry = 0; retry < 10; retry++) {
185162562Sjhb		/* Wait for IBF = 0 */
186162562Sjhb		status = kcs_wait_for_ibf(sc, 0);
187276065Sjhb		if (status & KCS_STATUS_IBF)
188276065Sjhb			return (0);
189162562Sjhb
190162562Sjhb		/* Clear OBF */
191162562Sjhb		kcs_clear_obf(sc, status);
192162562Sjhb
193162562Sjhb		/* Write start to command */
194162562Sjhb		OUTB(sc, KCS_CTL_STS, KCS_CONTROL_WRITE_START);
195162562Sjhb
196162562Sjhb		/* Wait for IBF = 0 */
197162562Sjhb		status = kcs_wait_for_ibf(sc, 0);
198276065Sjhb		if (status & KCS_STATUS_IBF)
199276065Sjhb			return (0);
200276065Sjhb
201162562Sjhb		if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_WRITE)
202162562Sjhb			break;
203162562Sjhb		DELAY(1000000);
204162562Sjhb	}
205162562Sjhb
206162562Sjhb	if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE)
207162562Sjhb		/* error state */
208162562Sjhb		return (0);
209162562Sjhb
210162562Sjhb	/* Clear OBF */
211162562Sjhb	kcs_clear_obf(sc, status);
212162562Sjhb
213162562Sjhb	return (1);
214162562Sjhb}
215162562Sjhb
216162562Sjhb/*
217162562Sjhb * Write a byte of the request message, excluding the last byte of the
218162562Sjhb * message which requires special handling.
219162562Sjhb */
220162562Sjhbstatic int
221162562Sjhbkcs_write_byte(struct ipmi_softc *sc, u_char data)
222162562Sjhb{
223162562Sjhb	int status;
224162562Sjhb
225162562Sjhb	/* Data to Data */
226162562Sjhb	OUTB(sc, KCS_DATA, data);
227162562Sjhb
228162562Sjhb	/* Wait for IBF = 0 */
229162562Sjhb	status = kcs_wait_for_ibf(sc, 0);
230276065Sjhb	if (status & KCS_STATUS_IBF)
231276065Sjhb		return (0);
232162562Sjhb
233162562Sjhb	if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE)
234162562Sjhb		return (0);
235162562Sjhb
236162562Sjhb	/* Clear OBF */
237162562Sjhb	kcs_clear_obf(sc, status);
238162562Sjhb	return (1);
239162562Sjhb}
240162562Sjhb
241162562Sjhb/*
242162562Sjhb * Write the last byte of a request message.
243162562Sjhb */
244162562Sjhbstatic int
245162562Sjhbkcs_write_last_byte(struct ipmi_softc *sc, u_char data)
246162562Sjhb{
247162562Sjhb	int status;
248162562Sjhb
249162562Sjhb	/* Write end to command */
250162562Sjhb	OUTB(sc, KCS_CTL_STS, KCS_CONTROL_WRITE_END);
251162562Sjhb
252162562Sjhb	/* Wait for IBF = 0 */
253162562Sjhb	status = kcs_wait_for_ibf(sc, 0);
254276065Sjhb	if (status & KCS_STATUS_IBF)
255276065Sjhb		return (0);
256162562Sjhb
257162562Sjhb	if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE)
258162562Sjhb		/* error state */
259162562Sjhb		return (0);
260162562Sjhb
261162562Sjhb	/* Clear OBF */
262162562Sjhb	kcs_clear_obf(sc, status);
263162562Sjhb
264162562Sjhb	/* Send data byte to DATA. */
265162562Sjhb	OUTB(sc, KCS_DATA, data);
266162562Sjhb	return (1);
267162562Sjhb}
268162562Sjhb
269162562Sjhb/*
270162562Sjhb * Read one byte of the reply message.
271162562Sjhb */
272162562Sjhbstatic int
273162562Sjhbkcs_read_byte(struct ipmi_softc *sc, u_char *data)
274162562Sjhb{
275162562Sjhb	int status;
276162562Sjhb	u_char dummy;
277162562Sjhb
278162562Sjhb	/* Wait for IBF = 0 */
279162562Sjhb	status = kcs_wait_for_ibf(sc, 0);
280162562Sjhb
281162562Sjhb	/* Read State */
282162562Sjhb	if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) {
283162562Sjhb
284162562Sjhb		/* Wait for OBF = 1 */
285162562Sjhb		status = kcs_wait_for_obf(sc, 1);
286276065Sjhb		if ((status & KCS_STATUS_OBF) == 0)
287276065Sjhb			return (0);
288162562Sjhb
289162562Sjhb		/* Read Data_out */
290162562Sjhb		*data = INB(sc, KCS_DATA);
291162562Sjhb
292162562Sjhb		/* Write READ into Data_in */
293162562Sjhb		OUTB(sc, KCS_DATA, KCS_DATA_IN_READ);
294162562Sjhb		return (1);
295162562Sjhb	}
296162562Sjhb
297162562Sjhb	/* Idle State */
298162562Sjhb	if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) {
299162562Sjhb
300162562Sjhb		/* Wait for OBF = 1*/
301162562Sjhb		status = kcs_wait_for_obf(sc, 1);
302276065Sjhb		if ((status & KCS_STATUS_OBF) == 0)
303276065Sjhb			return (0);
304162562Sjhb
305162562Sjhb		/* Read Dummy */
306162562Sjhb		dummy = INB(sc, KCS_DATA);
307162562Sjhb		return (2);
308162562Sjhb	}
309162562Sjhb
310162562Sjhb	/* Error State */
311162562Sjhb	return (0);
312162562Sjhb}
313162562Sjhb
314162562Sjhb/*
315162562Sjhb * Send a request message and collect the reply.  Returns true if we
316162562Sjhb * succeed.
317162562Sjhb */
318162562Sjhbstatic int
319162562Sjhbkcs_polled_request(struct ipmi_softc *sc, struct ipmi_request *req)
320162562Sjhb{
321162562Sjhb	u_char *cp, data;
322162562Sjhb	int i, state;
323162562Sjhb
324162562Sjhb	/* Send the request. */
325162562Sjhb	if (!kcs_start_write(sc)) {
326162562Sjhb		device_printf(sc->ipmi_dev, "KCS: Failed to start write\n");
327162562Sjhb		goto fail;
328162562Sjhb	}
329162562Sjhb#ifdef KCS_DEBUG
330162562Sjhb	device_printf(sc->ipmi_dev, "KCS: WRITE_START... ok\n");
331162562Sjhb#endif
332162562Sjhb
333162562Sjhb	if (!kcs_write_byte(sc, req->ir_addr)) {
334162562Sjhb		device_printf(sc->ipmi_dev, "KCS: Failed to write address\n");
335162562Sjhb		goto fail;
336162562Sjhb	}
337162562Sjhb#ifdef KCS_DEBUG
338162562Sjhb	device_printf(sc->ipmi_dev, "KCS: Wrote address: %02x\n", req->ir_addr);
339162562Sjhb#endif
340162562Sjhb
341162562Sjhb	if (req->ir_requestlen == 0) {
342162562Sjhb		if (!kcs_write_last_byte(sc, req->ir_command)) {
343162562Sjhb			device_printf(sc->ipmi_dev,
344162562Sjhb			    "KCS: Failed to write command\n");
345162562Sjhb			goto fail;
346162562Sjhb		}
347162562Sjhb#ifdef KCS_DEBUG
348162562Sjhb		device_printf(sc->ipmi_dev, "KCS: Wrote command: %02x\n",
349162562Sjhb		    req->ir_command);
350162562Sjhb#endif
351162562Sjhb	} else {
352162562Sjhb		if (!kcs_write_byte(sc, req->ir_command)) {
353162562Sjhb			device_printf(sc->ipmi_dev,
354162562Sjhb			    "KCS: Failed to write command\n");
355162562Sjhb			goto fail;
356162562Sjhb		}
357162562Sjhb#ifdef KCS_DEBUG
358162562Sjhb		device_printf(sc->ipmi_dev, "KCS: Wrote command: %02x\n",
359162562Sjhb		    req->ir_command);
360162562Sjhb#endif
361162562Sjhb
362162562Sjhb		cp = req->ir_request;
363162562Sjhb		for (i = 0; i < req->ir_requestlen - 1; i++) {
364162562Sjhb			if (!kcs_write_byte(sc, *cp++)) {
365162562Sjhb				device_printf(sc->ipmi_dev,
366162562Sjhb				    "KCS: Failed to write data byte %d\n",
367162562Sjhb				    i + 1);
368162562Sjhb				goto fail;
369162562Sjhb			}
370162562Sjhb#ifdef KCS_DEBUG
371162562Sjhb			device_printf(sc->ipmi_dev, "KCS: Wrote data: %02x\n",
372162562Sjhb			    cp[-1]);
373162562Sjhb#endif
374162562Sjhb		}
375162562Sjhb
376162562Sjhb		if (!kcs_write_last_byte(sc, *cp)) {
377162562Sjhb			device_printf(sc->ipmi_dev,
378162562Sjhb			    "KCS: Failed to write last dta byte\n");
379162562Sjhb			goto fail;
380162562Sjhb		}
381162562Sjhb#ifdef KCS_DEBUG
382162562Sjhb		device_printf(sc->ipmi_dev, "KCS: Wrote last data: %02x\n",
383162562Sjhb		    *cp);
384162562Sjhb#endif
385162562Sjhb	}
386162562Sjhb
387162562Sjhb	/* Read the reply.  First, read the NetFn/LUN. */
388162562Sjhb	if (kcs_read_byte(sc, &data) != 1) {
389162562Sjhb		device_printf(sc->ipmi_dev, "KCS: Failed to read address\n");
390162562Sjhb		goto fail;
391162562Sjhb	}
392162562Sjhb#ifdef KCS_DEBUG
393162562Sjhb	device_printf(sc->ipmi_dev, "KCS: Read address: %02x\n", data);
394162562Sjhb#endif
395162562Sjhb	if (data != IPMI_REPLY_ADDR(req->ir_addr)) {
396162562Sjhb		device_printf(sc->ipmi_dev, "KCS: Reply address mismatch\n");
397162562Sjhb		goto fail;
398162562Sjhb	}
399162562Sjhb
400162562Sjhb	/* Next we read the command. */
401162562Sjhb	if (kcs_read_byte(sc, &data) != 1) {
402162562Sjhb		device_printf(sc->ipmi_dev, "KCS: Failed to read command\n");
403162562Sjhb		goto fail;
404162562Sjhb	}
405162562Sjhb#ifdef KCS_DEBUG
406162562Sjhb	device_printf(sc->ipmi_dev, "KCS: Read command: %02x\n", data);
407162562Sjhb#endif
408162562Sjhb	if (data != req->ir_command) {
409162562Sjhb		device_printf(sc->ipmi_dev, "KCS: Command mismatch\n");
410162562Sjhb		goto fail;
411162562Sjhb	}
412162562Sjhb
413162562Sjhb	/* Next we read the completion code. */
414162562Sjhb	if (kcs_read_byte(sc, &req->ir_compcode) != 1) {
415162562Sjhb		device_printf(sc->ipmi_dev,
416162562Sjhb		    "KCS: Failed to read completion code\n");
417162562Sjhb		goto fail;
418162562Sjhb	}
419162562Sjhb#ifdef KCS_DEBUG
420162562Sjhb	device_printf(sc->ipmi_dev, "KCS: Read completion code: %02x\n",
421162562Sjhb	    req->ir_compcode);
422162562Sjhb#endif
423162562Sjhb
424162562Sjhb	/* Finally, read the reply from the BMC. */
425162562Sjhb	i = 0;
426162562Sjhb	for (;;) {
427162562Sjhb		state = kcs_read_byte(sc, &data);
428162562Sjhb		if (state == 0) {
429162562Sjhb			device_printf(sc->ipmi_dev,
430162562Sjhb			    "KCS: Read failed on byte %d\n", i + 1);
431162562Sjhb			goto fail;
432162562Sjhb		}
433162562Sjhb		if (state == 2)
434162562Sjhb			break;
435162562Sjhb		if (i < req->ir_replybuflen) {
436162562Sjhb			req->ir_reply[i] = data;
437162562Sjhb#ifdef KCS_DEBUG
438162562Sjhb			device_printf(sc->ipmi_dev, "KCS: Read data %02x\n",
439162562Sjhb			    data);
440162562Sjhb		} else {
441162562Sjhb			device_printf(sc->ipmi_dev,
442162562Sjhb			    "KCS: Read short %02x byte %d\n", data, i + 1);
443162562Sjhb#endif
444162562Sjhb		}
445162562Sjhb		i++;
446162562Sjhb	}
447162562Sjhb	req->ir_replylen = i;
448162562Sjhb#ifdef KCS_DEBUG
449162562Sjhb	device_printf(sc->ipmi_dev, "KCS: READ finished (%d bytes)\n", i);
450162562Sjhb	if (req->ir_replybuflen < i)
451162562Sjhb#else
452162562Sjhb	if (req->ir_replybuflen < i && req->ir_replybuflen != 0)
453162562Sjhb#endif
454162562Sjhb		device_printf(sc->ipmi_dev,
455162562Sjhb		    "KCS: Read short: %zd buffer, %d actual\n",
456162562Sjhb		    req->ir_replybuflen, i);
457162562Sjhb	return (1);
458162562Sjhbfail:
459162562Sjhb	kcs_error(sc);
460162562Sjhb	return (0);
461162562Sjhb}
462162562Sjhb
463162562Sjhbstatic void
464162562Sjhbkcs_loop(void *arg)
465162562Sjhb{
466162562Sjhb	struct ipmi_softc *sc = arg;
467162562Sjhb	struct ipmi_request *req;
468162562Sjhb	int i, ok;
469162562Sjhb
470162562Sjhb	IPMI_LOCK(sc);
471162562Sjhb	while ((req = ipmi_dequeue_request(sc)) != NULL) {
472248705Smelifaro		IPMI_UNLOCK(sc);
473162562Sjhb		ok = 0;
474162562Sjhb		for (i = 0; i < 3 && !ok; i++)
475162562Sjhb			ok = kcs_polled_request(sc, req);
476162562Sjhb		if (ok)
477162562Sjhb			req->ir_error = 0;
478162562Sjhb		else
479162562Sjhb			req->ir_error = EIO;
480248705Smelifaro		IPMI_LOCK(sc);
481162562Sjhb		ipmi_complete_request(sc, req);
482162562Sjhb	}
483162562Sjhb	IPMI_UNLOCK(sc);
484172836Sjulian	kproc_exit(0);
485162562Sjhb}
486162562Sjhb
487162562Sjhbstatic int
488162562Sjhbkcs_startup(struct ipmi_softc *sc)
489162562Sjhb{
490162562Sjhb
491172836Sjulian	return (kproc_create(kcs_loop, sc, &sc->ipmi_kthread, 0, 0, "%s: kcs",
492162562Sjhb	    device_get_nameunit(sc->ipmi_dev)));
493162562Sjhb}
494162562Sjhb
495162562Sjhbint
496162562Sjhbipmi_kcs_attach(struct ipmi_softc *sc)
497162562Sjhb{
498162562Sjhb	int status;
499162562Sjhb
500162562Sjhb	/* Setup function pointers. */
501162562Sjhb	sc->ipmi_startup = kcs_startup;
502162562Sjhb	sc->ipmi_enqueue_request = ipmi_polled_enqueue_request;
503162562Sjhb
504162562Sjhb	/* See if we can talk to the controller. */
505162562Sjhb	status = INB(sc, KCS_CTL_STS);
506162562Sjhb	if (status == 0xff) {
507162562Sjhb		device_printf(sc->ipmi_dev, "couldn't find it\n");
508162562Sjhb		return (ENXIO);
509162562Sjhb	}
510162562Sjhb
511162562Sjhb#ifdef KCS_DEBUG
512162562Sjhb	device_printf(sc->ipmi_dev, "KCS: initial state: %02x\n", status);
513162562Sjhb#endif
514162562Sjhb	if (status & KCS_STATUS_OBF ||
515162562Sjhb	    KCS_STATUS_STATE(status) != KCS_STATUS_STATE_IDLE)
516162562Sjhb		kcs_error(sc);
517162562Sjhb
518162562Sjhb	return (0);
519162562Sjhb}
520162562Sjhb
521162562Sjhb/*
522162562Sjhb * Determine the alignment automatically for a PCI attachment.  In this case,
523162562Sjhb * any unused bytes will return 0x00 when read.  We make use of the C/D bit
524162562Sjhb * in the CTL_STS register to try to start a GET_STATUS transaction.  When
525162562Sjhb * we write the command, that bit should be set, so we should get a non-zero
526162562Sjhb * value back when we read CTL_STS if the offset we are testing is the CTL_STS
527162562Sjhb * register.
528162562Sjhb */
529162562Sjhbint
530162562Sjhbipmi_kcs_probe_align(struct ipmi_softc *sc)
531162562Sjhb{
532162562Sjhb	int data, status;
533162562Sjhb
534162562Sjhb	sc->ipmi_io_spacing = 1;
535162562Sjhbretry:
536162562Sjhb#ifdef KCS_DEBUG
537162562Sjhb	device_printf(sc->ipmi_dev, "Trying KCS align %d... ", sc->ipmi_io_spacing);
538162562Sjhb#endif
539162562Sjhb
540162562Sjhb	/* Wait for IBF = 0 */
541162562Sjhb	status = INB(sc, KCS_CTL_STS);
542162562Sjhb	while (status & KCS_STATUS_IBF) {
543162562Sjhb		DELAY(100);
544162562Sjhb		status = INB(sc, KCS_CTL_STS);
545162562Sjhb	}
546162562Sjhb
547162562Sjhb	OUTB(sc, KCS_CTL_STS, KCS_CONTROL_GET_STATUS_ABORT);
548162562Sjhb
549162562Sjhb	/* Wait for IBF = 0 */
550162562Sjhb	status = INB(sc, KCS_CTL_STS);
551162562Sjhb	while (status & KCS_STATUS_IBF) {
552162562Sjhb		DELAY(100);
553162562Sjhb		status = INB(sc, KCS_CTL_STS);
554162562Sjhb	}
555162562Sjhb
556162562Sjhb	/* If we got 0x00 back, then this must not be the CTL_STS register. */
557162562Sjhb	if (status == 0) {
558162562Sjhb#ifdef KCS_DEBUG
559162562Sjhb		printf("failed\n");
560162562Sjhb#endif
561162562Sjhb		sc->ipmi_io_spacing <<= 1;
562162562Sjhb		if (sc->ipmi_io_spacing > 4)
563162562Sjhb			return (0);
564162562Sjhb		goto retry;
565162562Sjhb	}
566162562Sjhb#ifdef KCS_DEBUG
567162562Sjhb	printf("ok\n");
568162562Sjhb#endif
569162562Sjhb
570162562Sjhb	/* Finish out the transaction. */
571162562Sjhb
572162562Sjhb	/* Clear OBF */
573182321Sjhb	if (status & KCS_STATUS_OBF)
574162562Sjhb		data = INB(sc, KCS_DATA);
575162562Sjhb
576162562Sjhb	/* 0x00 to DATA_IN */
577162562Sjhb	OUTB(sc, KCS_DATA, 0);
578162562Sjhb
579162562Sjhb	/* Wait for IBF = 0 */
580162562Sjhb	status = INB(sc, KCS_CTL_STS);
581162562Sjhb	while (status & KCS_STATUS_IBF) {
582162562Sjhb		DELAY(100);
583162562Sjhb		status = INB(sc, KCS_CTL_STS);
584162562Sjhb	}
585162562Sjhb
586162562Sjhb	if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) {
587162562Sjhb		/* Wait for IBF = 1 */
588162562Sjhb		while (!(status & KCS_STATUS_OBF)) {
589162562Sjhb			DELAY(100);
590162562Sjhb			status = INB(sc, KCS_CTL_STS);
591162562Sjhb		}
592162562Sjhb
593162562Sjhb		/* Read error status. */
594162562Sjhb		data = INB(sc, KCS_DATA);
595162562Sjhb
596162562Sjhb		/* Write dummy READ to DATA_IN. */
597162562Sjhb		OUTB(sc, KCS_DATA, KCS_DATA_IN_READ);
598162562Sjhb
599162562Sjhb		/* Wait for IBF = 0 */
600162562Sjhb		status = INB(sc, KCS_CTL_STS);
601162562Sjhb		while (status & KCS_STATUS_IBF) {
602162562Sjhb			DELAY(100);
603162562Sjhb			status = INB(sc, KCS_CTL_STS);
604162562Sjhb		}
605162562Sjhb	}
606162562Sjhb
607162562Sjhb	if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) {
608162562Sjhb		/* Wait for IBF = 1 */
609162562Sjhb		while (!(status & KCS_STATUS_OBF)) {
610162562Sjhb			DELAY(100);
611162562Sjhb			status = INB(sc, KCS_CTL_STS);
612162562Sjhb		}
613162562Sjhb
614162562Sjhb		/* Clear OBF */
615182321Sjhb		if (status & KCS_STATUS_OBF)
616162562Sjhb			data = INB(sc, KCS_DATA);
617162562Sjhb	} else
618162562Sjhb		device_printf(sc->ipmi_dev, "KCS probe: end state %x\n",
619162562Sjhb		    KCS_STATUS_STATE(status));
620162562Sjhb
621162562Sjhb	return (1);
622162562Sjhb}
623