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