xref: /illumos-gate/usr/src/uts/intel/io/ipmi/ipmi_kcs.c (revision abc79d9d)
1 /*
2  * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /* $FreeBSD: src/sys/dev/ipmi/ipmi_kcs.c,v 1.3 2008/08/28 02:11:04 jhb */
28 
29 /*
30  * Copyright 2012, Joyent, Inc.  All rights reserved.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/disp.h>
35 #include <sys/systm.h>
36 #include <sys/condvar.h>
37 #include <sys/cmn_err.h>
38 #include <sys/ddi.h>
39 #include <sys/sunddi.h>
40 
41 #include <sys/ipmi.h>
42 #include "ipmivars.h"
43 
44 static void	kcs_clear_obf(struct ipmi_softc *, int);
45 static void	kcs_error(struct ipmi_softc *);
46 static int	kcs_wait_for_ibf(struct ipmi_softc *, int);
47 static int	kcs_wait_for_obf(struct ipmi_softc *, int);
48 
49 #define	RETRY_USECS	100
50 static clock_t timeout_usecs;
51 
52 static int
53 kcs_wait_for_ibf(struct ipmi_softc *sc, int state)
54 {
55 	int status;
56 	clock_t i;
57 
58 	status = INB(sc, KCS_CTL_STS);
59 	if (state == 0) {
60 		/* WAIT FOR IBF = 0 */
61 		for (i = 0; i < timeout_usecs && status & KCS_STATUS_IBF;
62 		    i += RETRY_USECS) {
63 			drv_usecwait(RETRY_USECS);
64 			status = INB(sc, KCS_CTL_STS);
65 		}
66 	} else {
67 		/* WAIT FOR IBF = 1 */
68 		for (i = 0; i < timeout_usecs && !(status & KCS_STATUS_IBF);
69 		    i += RETRY_USECS) {
70 			drv_usecwait(RETRY_USECS);
71 			status = INB(sc, KCS_CTL_STS);
72 		}
73 	}
74 	return (status);
75 }
76 
77 static int
78 kcs_wait_for_obf(struct ipmi_softc *sc, int state)
79 {
80 	int status;
81 	clock_t i;
82 
83 	status = INB(sc, KCS_CTL_STS);
84 	if (state == 0) {
85 		/* WAIT FOR OBF = 0 */
86 		for (i = 0; i < timeout_usecs && status & KCS_STATUS_OBF;
87 		    i += RETRY_USECS) {
88 			drv_usecwait(RETRY_USECS);
89 			status = INB(sc, KCS_CTL_STS);
90 		}
91 	} else {
92 		/* WAIT FOR OBF = 1 */
93 		for (i = 0; i < timeout_usecs && !(status & KCS_STATUS_OBF);
94 		    i += RETRY_USECS) {
95 			drv_usecwait(RETRY_USECS);
96 			status = INB(sc, KCS_CTL_STS);
97 		}
98 	}
99 	return (status);
100 }
101 
102 static void
103 kcs_clear_obf(struct ipmi_softc *sc, int status)
104 {
105 	/* Clear OBF */
106 	if (status & KCS_STATUS_OBF) {
107 		(void) INB(sc, KCS_DATA);
108 	}
109 }
110 
111 static void
112 kcs_error(struct ipmi_softc *sc)
113 {
114 	int retry, status;
115 	uchar_t data;
116 
117 	for (retry = 0; retry < 2; retry++) {
118 
119 		/* Wait for IBF = 0 */
120 		status = kcs_wait_for_ibf(sc, 0);
121 
122 		/* ABORT */
123 		OUTB(sc, KCS_CTL_STS, KCS_CONTROL_GET_STATUS_ABORT);
124 
125 		/* Wait for IBF = 0 */
126 		status = kcs_wait_for_ibf(sc, 0);
127 
128 		/* Clear OBF */
129 		kcs_clear_obf(sc, status);
130 
131 		if (status & KCS_STATUS_OBF) {
132 			data = INB(sc, KCS_DATA);
133 			if (data != 0)
134 				cmn_err(CE_WARN,
135 				    "KCS Error Data %02x", data);
136 		}
137 
138 		/* 0x00 to DATA_IN */
139 		OUTB(sc, KCS_DATA, 0x00);
140 
141 		/* Wait for IBF = 0 */
142 		status = kcs_wait_for_ibf(sc, 0);
143 
144 		if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) {
145 
146 			/* Wait for OBF = 1 */
147 			status = kcs_wait_for_obf(sc, 1);
148 
149 			/* Read error status */
150 			data = INB(sc, KCS_DATA);
151 			if (data != 0)
152 				cmn_err(CE_WARN, "KCS error: %02x", data);
153 
154 			/* Write READ into Data_in */
155 			OUTB(sc, KCS_DATA, KCS_DATA_IN_READ);
156 
157 			/* Wait for IBF = 0 */
158 			status = kcs_wait_for_ibf(sc, 0);
159 		}
160 
161 		/* IDLE STATE */
162 		if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) {
163 			/* Wait for OBF = 1 */
164 			status = kcs_wait_for_obf(sc, 1);
165 
166 			/* Clear OBF */
167 			kcs_clear_obf(sc, status);
168 			return;
169 		}
170 	}
171 	cmn_err(CE_WARN, "KCS: Error retry exhausted");
172 }
173 
174 /*
175  * Start to write a request.  Waits for IBF to clear and then sends the
176  * WR_START command.
177  */
178 static int
179 kcs_start_write(struct ipmi_softc *sc)
180 {
181 	int retry, status;
182 
183 	for (retry = 0; retry < 10; retry++) {
184 		/* Wait for IBF = 0 */
185 		status = kcs_wait_for_ibf(sc, 0);
186 
187 		/* Clear OBF */
188 		kcs_clear_obf(sc, status);
189 
190 		/* Write start to command */
191 		OUTB(sc, KCS_CTL_STS, KCS_CONTROL_WRITE_START);
192 
193 		/* Wait for IBF = 0 */
194 		status = kcs_wait_for_ibf(sc, 0);
195 		if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_WRITE)
196 			break;
197 		delay(1000000);
198 	}
199 
200 	if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE)
201 		/* error state */
202 		return (0);
203 
204 	/* Clear OBF */
205 	kcs_clear_obf(sc, status);
206 
207 	return (1);
208 }
209 
210 /*
211  * Write a byte of the request message, excluding the last byte of the
212  * message which requires special handling.
213  */
214 static int
215 kcs_write_byte(struct ipmi_softc *sc, uchar_t data)
216 {
217 	int status;
218 
219 	/* Data to Data */
220 	OUTB(sc, KCS_DATA, data);
221 
222 	/* Wait for IBF = 0 */
223 	status = kcs_wait_for_ibf(sc, 0);
224 
225 	if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE)
226 		return (0);
227 
228 	/* Clear OBF */
229 	kcs_clear_obf(sc, status);
230 	return (1);
231 }
232 
233 /*
234  * Write the last byte of a request message.
235  */
236 static int
237 kcs_write_last_byte(struct ipmi_softc *sc, uchar_t data)
238 {
239 	int status;
240 
241 	/* Write end to command */
242 	OUTB(sc, KCS_CTL_STS, KCS_CONTROL_WRITE_END);
243 
244 	/* Wait for IBF = 0 */
245 	status = kcs_wait_for_ibf(sc, 0);
246 
247 	if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE)
248 		/* error state */
249 		return (0);
250 
251 	/* Clear OBF */
252 	kcs_clear_obf(sc, status);
253 
254 	/* Send data byte to DATA. */
255 	OUTB(sc, KCS_DATA, data);
256 	return (1);
257 }
258 
259 /*
260  * Read one byte of the reply message.
261  */
262 static int
263 kcs_read_byte(struct ipmi_softc *sc, uchar_t *data)
264 {
265 	int status;
266 
267 	/* Wait for IBF = 0 */
268 	status = kcs_wait_for_ibf(sc, 0);
269 
270 	/* Read State */
271 	if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) {
272 
273 		/* Wait for OBF = 1 */
274 		status = kcs_wait_for_obf(sc, 1);
275 
276 		/* Read Data_out */
277 		*data = INB(sc, KCS_DATA);
278 
279 		/* Write READ into Data_in */
280 		OUTB(sc, KCS_DATA, KCS_DATA_IN_READ);
281 		return (1);
282 	}
283 
284 	/* Idle State */
285 	if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) {
286 
287 		/* Wait for OBF = 1 */
288 		status = kcs_wait_for_obf(sc, 1);
289 
290 		/* Read Dummy */
291 		(void) INB(sc, KCS_DATA);
292 		return (2);
293 	}
294 
295 	/* Error State */
296 	return (0);
297 }
298 
299 /*
300  * Send a request message and collect the reply.  Returns true if we
301  * succeed.
302  */
303 static int
304 kcs_polled_request(struct ipmi_softc *sc, struct ipmi_request *req)
305 {
306 	uchar_t *cp, data;
307 	int i, state;
308 
309 	/* Send the request. */
310 	if (!kcs_start_write(sc)) {
311 		cmn_err(CE_WARN, "KCS: Failed to start write");
312 		goto fail;
313 	}
314 #ifdef KCS_DEBUG
315 	cmn_err(CE_NOTE, "KCS: WRITE_START... ok");
316 #endif
317 
318 	if (!kcs_write_byte(sc, req->ir_addr)) {
319 		cmn_err(CE_WARN, "KCS: Failed to write address");
320 		goto fail;
321 	}
322 #ifdef KCS_DEBUG
323 	cmn_err(CE_NOTE, "KCS: Wrote address: %02x", req->ir_addr);
324 #endif
325 
326 	if (req->ir_requestlen == 0) {
327 		if (!kcs_write_last_byte(sc, req->ir_command)) {
328 			cmn_err(CE_WARN,
329 			    "KCS: Failed to write command");
330 			goto fail;
331 		}
332 #ifdef KCS_DEBUG
333 		cmn_err(CE_NOTE, "KCS: Wrote command: %02x",
334 		    req->ir_command);
335 #endif
336 	} else {
337 		if (!kcs_write_byte(sc, req->ir_command)) {
338 			cmn_err(CE_WARN,
339 			    "KCS: Failed to write command");
340 			goto fail;
341 		}
342 #ifdef KCS_DEBUG
343 		cmn_err(CE_NOTE, "KCS: Wrote command: %02x",
344 		    req->ir_command);
345 #endif
346 
347 		cp = req->ir_request;
348 		for (i = 0; i < req->ir_requestlen - 1; i++) {
349 			if (!kcs_write_byte(sc, *cp++)) {
350 				cmn_err(CE_WARN,
351 				    "KCS: Failed to write data byte %d",
352 				    i + 1);
353 				goto fail;
354 			}
355 #ifdef KCS_DEBUG
356 			cmn_err(CE_NOTE, "KCS: Wrote data: %02x",
357 			    cp[-1]);
358 #endif
359 		}
360 
361 		if (!kcs_write_last_byte(sc, *cp)) {
362 			cmn_err(CE_WARN,
363 			    "KCS: Failed to write last dta byte");
364 			goto fail;
365 		}
366 #ifdef KCS_DEBUG
367 		cmn_err(CE_NOTE, "KCS: Wrote last data: %02x",
368 		    *cp);
369 #endif
370 	}
371 
372 	/* Read the reply.  First, read the NetFn/LUN. */
373 	if (kcs_read_byte(sc, &data) != 1) {
374 		cmn_err(CE_WARN, "KCS: Failed to read address");
375 		goto fail;
376 	}
377 #ifdef KCS_DEBUG
378 	cmn_err(CE_NOTE, "KCS: Read address: %02x", data);
379 #endif
380 	if (data != IPMI_REPLY_ADDR(req->ir_addr)) {
381 		cmn_err(CE_WARN, "KCS: Reply address mismatch");
382 		goto fail;
383 	}
384 
385 	/* Next we read the command. */
386 	if (kcs_read_byte(sc, &data) != 1) {
387 		cmn_err(CE_WARN, "KCS: Failed to read command");
388 		goto fail;
389 	}
390 #ifdef KCS_DEBUG
391 	cmn_err(CE_NOTE, "KCS: Read command: %02x", data);
392 #endif
393 	if (data != req->ir_command) {
394 		cmn_err(CE_WARN, "KCS: Command mismatch");
395 		goto fail;
396 	}
397 
398 	/* Next we read the completion code. */
399 	if (kcs_read_byte(sc, &req->ir_compcode) != 1) {
400 		cmn_err(CE_WARN, "KCS: Failed to read completion code");
401 		goto fail;
402 	}
403 #ifdef KCS_DEBUG
404 	cmn_err(CE_NOTE, "KCS: Read completion code: %02x",
405 	    req->ir_compcode);
406 #endif
407 
408 	/* Finally, read the reply from the BMC. */
409 	i = 0;
410 	for (;;) {
411 		state = kcs_read_byte(sc, &data);
412 		if (state == 0) {
413 			cmn_err(CE_WARN,
414 			    "KCS: Read failed on byte %d", i + 1);
415 			goto fail;
416 		}
417 		if (state == 2)
418 			break;
419 		if (i < req->ir_replybuflen) {
420 			req->ir_reply[i] = data;
421 #ifdef KCS_DEBUG
422 			cmn_err(CE_NOTE, "KCS: Read data %02x",
423 			    data);
424 		} else {
425 			cmn_err(CE_WARN,
426 			    "KCS: Read short %02x byte %d", data, i + 1);
427 #endif
428 		}
429 		i++;
430 	}
431 	req->ir_replylen = i;
432 #ifdef KCS_DEBUG
433 	cmn_err(CE_NOTE, "KCS: READ finished (%d bytes)", i);
434 	if (req->ir_replybuflen < i)
435 #else
436 	if (req->ir_replybuflen < i && req->ir_replybuflen != 0)
437 #endif
438 		cmn_err(CE_WARN, "KCS: Read short: %d buffer, %d actual",
439 		    (int)(req->ir_replybuflen), i);
440 	return (1);
441 fail:
442 	kcs_error(sc);
443 	return (0);
444 }
445 
446 static void
447 kcs_loop(void *arg)
448 {
449 	struct ipmi_softc *sc = arg;
450 	struct ipmi_request *req;
451 	int i, ok;
452 
453 	IPMI_LOCK(sc);
454 	while ((req = ipmi_dequeue_request(sc)) != NULL) {
455 		ok = 0;
456 		for (i = 0; i < 3 && !ok; i++)
457 			ok = kcs_polled_request(sc, req);
458 		if (ok)
459 			req->ir_error = 0;
460 		else
461 			req->ir_error = EIO;
462 		ipmi_complete_request(sc, req);
463 	}
464 	IPMI_UNLOCK(sc);
465 }
466 
467 static int
468 kcs_startup(struct ipmi_softc *sc)
469 {
470 	sc->ipmi_kthread = taskq_create_proc("ipmi_kcs", 1, minclsyspri, 1, 1,
471 	    curzone->zone_zsched, TASKQ_PREPOPULATE);
472 
473 	if (taskq_dispatch(sc->ipmi_kthread, kcs_loop, (void *) sc,
474 	    TQ_SLEEP) == NULL) {
475 		taskq_destroy(sc->ipmi_kthread);
476 		return (1);
477 	}
478 
479 	return (0);
480 }
481 
482 int
483 ipmi_kcs_attach(struct ipmi_softc *sc)
484 {
485 	int status;
486 
487 	/* Setup function pointers. */
488 	sc->ipmi_startup = kcs_startup;
489 	sc->ipmi_enqueue_request = ipmi_polled_enqueue_request;
490 
491 	/* See if we can talk to the controller. */
492 	status = INB(sc, KCS_CTL_STS);
493 	if (status == 0xff) {
494 		cmn_err(CE_CONT, "!KCS couldn't find it");
495 		return (ENXIO);
496 	}
497 
498 	timeout_usecs = drv_hztousec(MAX_TIMEOUT);
499 
500 #ifdef KCS_DEBUG
501 	cmn_err(CE_NOTE, "KCS: initial state: %02x", status);
502 #endif
503 	if (status & KCS_STATUS_OBF ||
504 	    KCS_STATUS_STATE(status) != KCS_STATUS_STATE_IDLE)
505 		kcs_error(sc);
506 
507 	return (0);
508 }
509