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