XXXX introduce drv_sectohz
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_sectohz(1));
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) == NULL) {
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 }
--- EOF ---