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$"); 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); 187162562Sjhb 188162562Sjhb /* Clear OBF */ 189162562Sjhb kcs_clear_obf(sc, status); 190162562Sjhb 191162562Sjhb /* Write start to command */ 192162562Sjhb OUTB(sc, KCS_CTL_STS, KCS_CONTROL_WRITE_START); 193162562Sjhb 194162562Sjhb /* Wait for IBF = 0 */ 195162562Sjhb status = kcs_wait_for_ibf(sc, 0); 196162562Sjhb if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_WRITE) 197162562Sjhb break; 198162562Sjhb DELAY(1000000); 199162562Sjhb } 200162562Sjhb 201162562Sjhb if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE) 202162562Sjhb /* error state */ 203162562Sjhb return (0); 204162562Sjhb 205162562Sjhb /* Clear OBF */ 206162562Sjhb kcs_clear_obf(sc, status); 207162562Sjhb 208162562Sjhb return (1); 209162562Sjhb} 210162562Sjhb 211162562Sjhb/* 212162562Sjhb * Write a byte of the request message, excluding the last byte of the 213162562Sjhb * message which requires special handling. 214162562Sjhb */ 215162562Sjhbstatic int 216162562Sjhbkcs_write_byte(struct ipmi_softc *sc, u_char data) 217162562Sjhb{ 218162562Sjhb int status; 219162562Sjhb 220162562Sjhb /* Data to Data */ 221162562Sjhb OUTB(sc, KCS_DATA, data); 222162562Sjhb 223162562Sjhb /* Wait for IBF = 0 */ 224162562Sjhb status = kcs_wait_for_ibf(sc, 0); 225162562Sjhb 226162562Sjhb if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE) 227162562Sjhb return (0); 228162562Sjhb 229162562Sjhb /* Clear OBF */ 230162562Sjhb kcs_clear_obf(sc, status); 231162562Sjhb return (1); 232162562Sjhb} 233162562Sjhb 234162562Sjhb/* 235162562Sjhb * Write the last byte of a request message. 236162562Sjhb */ 237162562Sjhbstatic int 238162562Sjhbkcs_write_last_byte(struct ipmi_softc *sc, u_char data) 239162562Sjhb{ 240162562Sjhb int status; 241162562Sjhb 242162562Sjhb /* Write end to command */ 243162562Sjhb OUTB(sc, KCS_CTL_STS, KCS_CONTROL_WRITE_END); 244162562Sjhb 245162562Sjhb /* Wait for IBF = 0 */ 246162562Sjhb status = kcs_wait_for_ibf(sc, 0); 247162562Sjhb 248162562Sjhb if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE) 249162562Sjhb /* error state */ 250162562Sjhb return (0); 251162562Sjhb 252162562Sjhb /* Clear OBF */ 253162562Sjhb kcs_clear_obf(sc, status); 254162562Sjhb 255162562Sjhb /* Send data byte to DATA. */ 256162562Sjhb OUTB(sc, KCS_DATA, data); 257162562Sjhb return (1); 258162562Sjhb} 259162562Sjhb 260162562Sjhb/* 261162562Sjhb * Read one byte of the reply message. 262162562Sjhb */ 263162562Sjhbstatic int 264162562Sjhbkcs_read_byte(struct ipmi_softc *sc, u_char *data) 265162562Sjhb{ 266162562Sjhb int status; 267162562Sjhb u_char dummy; 268162562Sjhb 269162562Sjhb /* Wait for IBF = 0 */ 270162562Sjhb status = kcs_wait_for_ibf(sc, 0); 271162562Sjhb 272162562Sjhb /* Read State */ 273162562Sjhb if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) { 274162562Sjhb 275162562Sjhb /* Wait for OBF = 1 */ 276162562Sjhb status = kcs_wait_for_obf(sc, 1); 277162562Sjhb 278162562Sjhb /* Read Data_out */ 279162562Sjhb *data = INB(sc, KCS_DATA); 280162562Sjhb 281162562Sjhb /* Write READ into Data_in */ 282162562Sjhb OUTB(sc, KCS_DATA, KCS_DATA_IN_READ); 283162562Sjhb return (1); 284162562Sjhb } 285162562Sjhb 286162562Sjhb /* Idle State */ 287162562Sjhb if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) { 288162562Sjhb 289162562Sjhb /* Wait for OBF = 1*/ 290162562Sjhb status = kcs_wait_for_obf(sc, 1); 291162562Sjhb 292162562Sjhb /* Read Dummy */ 293162562Sjhb dummy = INB(sc, KCS_DATA); 294162562Sjhb return (2); 295162562Sjhb } 296162562Sjhb 297162562Sjhb /* Error State */ 298162562Sjhb return (0); 299162562Sjhb} 300162562Sjhb 301162562Sjhb/* 302162562Sjhb * Send a request message and collect the reply. Returns true if we 303162562Sjhb * succeed. 304162562Sjhb */ 305162562Sjhbstatic int 306162562Sjhbkcs_polled_request(struct ipmi_softc *sc, struct ipmi_request *req) 307162562Sjhb{ 308162562Sjhb u_char *cp, data; 309162562Sjhb int i, state; 310162562Sjhb 311162562Sjhb /* Send the request. */ 312162562Sjhb if (!kcs_start_write(sc)) { 313162562Sjhb device_printf(sc->ipmi_dev, "KCS: Failed to start write\n"); 314162562Sjhb goto fail; 315162562Sjhb } 316162562Sjhb#ifdef KCS_DEBUG 317162562Sjhb device_printf(sc->ipmi_dev, "KCS: WRITE_START... ok\n"); 318162562Sjhb#endif 319162562Sjhb 320162562Sjhb if (!kcs_write_byte(sc, req->ir_addr)) { 321162562Sjhb device_printf(sc->ipmi_dev, "KCS: Failed to write address\n"); 322162562Sjhb goto fail; 323162562Sjhb } 324162562Sjhb#ifdef KCS_DEBUG 325162562Sjhb device_printf(sc->ipmi_dev, "KCS: Wrote address: %02x\n", req->ir_addr); 326162562Sjhb#endif 327162562Sjhb 328162562Sjhb if (req->ir_requestlen == 0) { 329162562Sjhb if (!kcs_write_last_byte(sc, req->ir_command)) { 330162562Sjhb device_printf(sc->ipmi_dev, 331162562Sjhb "KCS: Failed to write command\n"); 332162562Sjhb goto fail; 333162562Sjhb } 334162562Sjhb#ifdef KCS_DEBUG 335162562Sjhb device_printf(sc->ipmi_dev, "KCS: Wrote command: %02x\n", 336162562Sjhb req->ir_command); 337162562Sjhb#endif 338162562Sjhb } else { 339162562Sjhb if (!kcs_write_byte(sc, req->ir_command)) { 340162562Sjhb device_printf(sc->ipmi_dev, 341162562Sjhb "KCS: Failed to write command\n"); 342162562Sjhb goto fail; 343162562Sjhb } 344162562Sjhb#ifdef KCS_DEBUG 345162562Sjhb device_printf(sc->ipmi_dev, "KCS: Wrote command: %02x\n", 346162562Sjhb req->ir_command); 347162562Sjhb#endif 348162562Sjhb 349162562Sjhb cp = req->ir_request; 350162562Sjhb for (i = 0; i < req->ir_requestlen - 1; i++) { 351162562Sjhb if (!kcs_write_byte(sc, *cp++)) { 352162562Sjhb device_printf(sc->ipmi_dev, 353162562Sjhb "KCS: Failed to write data byte %d\n", 354162562Sjhb i + 1); 355162562Sjhb goto fail; 356162562Sjhb } 357162562Sjhb#ifdef KCS_DEBUG 358162562Sjhb device_printf(sc->ipmi_dev, "KCS: Wrote data: %02x\n", 359162562Sjhb cp[-1]); 360162562Sjhb#endif 361162562Sjhb } 362162562Sjhb 363162562Sjhb if (!kcs_write_last_byte(sc, *cp)) { 364162562Sjhb device_printf(sc->ipmi_dev, 365162562Sjhb "KCS: Failed to write last dta byte\n"); 366162562Sjhb goto fail; 367162562Sjhb } 368162562Sjhb#ifdef KCS_DEBUG 369162562Sjhb device_printf(sc->ipmi_dev, "KCS: Wrote last data: %02x\n", 370162562Sjhb *cp); 371162562Sjhb#endif 372162562Sjhb } 373162562Sjhb 374162562Sjhb /* Read the reply. First, read the NetFn/LUN. */ 375162562Sjhb if (kcs_read_byte(sc, &data) != 1) { 376162562Sjhb device_printf(sc->ipmi_dev, "KCS: Failed to read address\n"); 377162562Sjhb goto fail; 378162562Sjhb } 379162562Sjhb#ifdef KCS_DEBUG 380162562Sjhb device_printf(sc->ipmi_dev, "KCS: Read address: %02x\n", data); 381162562Sjhb#endif 382162562Sjhb if (data != IPMI_REPLY_ADDR(req->ir_addr)) { 383162562Sjhb device_printf(sc->ipmi_dev, "KCS: Reply address mismatch\n"); 384162562Sjhb goto fail; 385162562Sjhb } 386162562Sjhb 387162562Sjhb /* Next we read the command. */ 388162562Sjhb if (kcs_read_byte(sc, &data) != 1) { 389162562Sjhb device_printf(sc->ipmi_dev, "KCS: Failed to read command\n"); 390162562Sjhb goto fail; 391162562Sjhb } 392162562Sjhb#ifdef KCS_DEBUG 393162562Sjhb device_printf(sc->ipmi_dev, "KCS: Read command: %02x\n", data); 394162562Sjhb#endif 395162562Sjhb if (data != req->ir_command) { 396162562Sjhb device_printf(sc->ipmi_dev, "KCS: Command mismatch\n"); 397162562Sjhb goto fail; 398162562Sjhb } 399162562Sjhb 400162562Sjhb /* Next we read the completion code. */ 401162562Sjhb if (kcs_read_byte(sc, &req->ir_compcode) != 1) { 402162562Sjhb device_printf(sc->ipmi_dev, 403162562Sjhb "KCS: Failed to read completion code\n"); 404162562Sjhb goto fail; 405162562Sjhb } 406162562Sjhb#ifdef KCS_DEBUG 407162562Sjhb device_printf(sc->ipmi_dev, "KCS: Read completion code: %02x\n", 408162562Sjhb req->ir_compcode); 409162562Sjhb#endif 410162562Sjhb 411162562Sjhb /* Finally, read the reply from the BMC. */ 412162562Sjhb i = 0; 413162562Sjhb for (;;) { 414162562Sjhb state = kcs_read_byte(sc, &data); 415162562Sjhb if (state == 0) { 416162562Sjhb device_printf(sc->ipmi_dev, 417162562Sjhb "KCS: Read failed on byte %d\n", i + 1); 418162562Sjhb goto fail; 419162562Sjhb } 420162562Sjhb if (state == 2) 421162562Sjhb break; 422162562Sjhb if (i < req->ir_replybuflen) { 423162562Sjhb req->ir_reply[i] = data; 424162562Sjhb#ifdef KCS_DEBUG 425162562Sjhb device_printf(sc->ipmi_dev, "KCS: Read data %02x\n", 426162562Sjhb data); 427162562Sjhb } else { 428162562Sjhb device_printf(sc->ipmi_dev, 429162562Sjhb "KCS: Read short %02x byte %d\n", data, i + 1); 430162562Sjhb#endif 431162562Sjhb } 432162562Sjhb i++; 433162562Sjhb } 434162562Sjhb req->ir_replylen = i; 435162562Sjhb#ifdef KCS_DEBUG 436162562Sjhb device_printf(sc->ipmi_dev, "KCS: READ finished (%d bytes)\n", i); 437162562Sjhb if (req->ir_replybuflen < i) 438162562Sjhb#else 439162562Sjhb if (req->ir_replybuflen < i && req->ir_replybuflen != 0) 440162562Sjhb#endif 441162562Sjhb device_printf(sc->ipmi_dev, 442162562Sjhb "KCS: Read short: %zd buffer, %d actual\n", 443162562Sjhb req->ir_replybuflen, i); 444162562Sjhb return (1); 445162562Sjhbfail: 446162562Sjhb kcs_error(sc); 447162562Sjhb return (0); 448162562Sjhb} 449162562Sjhb 450162562Sjhbstatic void 451162562Sjhbkcs_loop(void *arg) 452162562Sjhb{ 453162562Sjhb struct ipmi_softc *sc = arg; 454162562Sjhb struct ipmi_request *req; 455162562Sjhb int i, ok; 456162562Sjhb 457162562Sjhb IPMI_LOCK(sc); 458162562Sjhb while ((req = ipmi_dequeue_request(sc)) != NULL) { 459162562Sjhb ok = 0; 460162562Sjhb for (i = 0; i < 3 && !ok; i++) 461162562Sjhb ok = kcs_polled_request(sc, req); 462162562Sjhb if (ok) 463162562Sjhb req->ir_error = 0; 464162562Sjhb else 465162562Sjhb req->ir_error = EIO; 466162562Sjhb ipmi_complete_request(sc, req); 467162562Sjhb } 468162562Sjhb IPMI_UNLOCK(sc); 469172836Sjulian kproc_exit(0); 470162562Sjhb} 471162562Sjhb 472162562Sjhbstatic int 473162562Sjhbkcs_startup(struct ipmi_softc *sc) 474162562Sjhb{ 475162562Sjhb 476172836Sjulian return (kproc_create(kcs_loop, sc, &sc->ipmi_kthread, 0, 0, "%s: kcs", 477162562Sjhb device_get_nameunit(sc->ipmi_dev))); 478162562Sjhb} 479162562Sjhb 480162562Sjhbint 481162562Sjhbipmi_kcs_attach(struct ipmi_softc *sc) 482162562Sjhb{ 483162562Sjhb int status; 484162562Sjhb 485162562Sjhb /* Setup function pointers. */ 486162562Sjhb sc->ipmi_startup = kcs_startup; 487162562Sjhb sc->ipmi_enqueue_request = ipmi_polled_enqueue_request; 488162562Sjhb 489162562Sjhb /* See if we can talk to the controller. */ 490162562Sjhb status = INB(sc, KCS_CTL_STS); 491162562Sjhb if (status == 0xff) { 492162562Sjhb device_printf(sc->ipmi_dev, "couldn't find it\n"); 493162562Sjhb return (ENXIO); 494162562Sjhb } 495162562Sjhb 496162562Sjhb#ifdef KCS_DEBUG 497162562Sjhb device_printf(sc->ipmi_dev, "KCS: initial state: %02x\n", status); 498162562Sjhb#endif 499162562Sjhb if (status & KCS_STATUS_OBF || 500162562Sjhb KCS_STATUS_STATE(status) != KCS_STATUS_STATE_IDLE) 501162562Sjhb kcs_error(sc); 502162562Sjhb 503162562Sjhb return (0); 504162562Sjhb} 505162562Sjhb 506162562Sjhb/* 507162562Sjhb * Determine the alignment automatically for a PCI attachment. In this case, 508162562Sjhb * any unused bytes will return 0x00 when read. We make use of the C/D bit 509162562Sjhb * in the CTL_STS register to try to start a GET_STATUS transaction. When 510162562Sjhb * we write the command, that bit should be set, so we should get a non-zero 511162562Sjhb * value back when we read CTL_STS if the offset we are testing is the CTL_STS 512162562Sjhb * register. 513162562Sjhb */ 514162562Sjhbint 515162562Sjhbipmi_kcs_probe_align(struct ipmi_softc *sc) 516162562Sjhb{ 517162562Sjhb int data, status; 518162562Sjhb 519162562Sjhb sc->ipmi_io_spacing = 1; 520162562Sjhbretry: 521162562Sjhb#ifdef KCS_DEBUG 522162562Sjhb device_printf(sc->ipmi_dev, "Trying KCS align %d... ", sc->ipmi_io_spacing); 523162562Sjhb#endif 524162562Sjhb 525162562Sjhb /* Wait for IBF = 0 */ 526162562Sjhb status = INB(sc, KCS_CTL_STS); 527162562Sjhb while (status & KCS_STATUS_IBF) { 528162562Sjhb DELAY(100); 529162562Sjhb status = INB(sc, KCS_CTL_STS); 530162562Sjhb } 531162562Sjhb 532162562Sjhb OUTB(sc, KCS_CTL_STS, KCS_CONTROL_GET_STATUS_ABORT); 533162562Sjhb 534162562Sjhb /* Wait for IBF = 0 */ 535162562Sjhb status = INB(sc, KCS_CTL_STS); 536162562Sjhb while (status & KCS_STATUS_IBF) { 537162562Sjhb DELAY(100); 538162562Sjhb status = INB(sc, KCS_CTL_STS); 539162562Sjhb } 540162562Sjhb 541162562Sjhb /* If we got 0x00 back, then this must not be the CTL_STS register. */ 542162562Sjhb if (status == 0) { 543162562Sjhb#ifdef KCS_DEBUG 544162562Sjhb printf("failed\n"); 545162562Sjhb#endif 546162562Sjhb sc->ipmi_io_spacing <<= 1; 547162562Sjhb if (sc->ipmi_io_spacing > 4) 548162562Sjhb return (0); 549162562Sjhb goto retry; 550162562Sjhb } 551162562Sjhb#ifdef KCS_DEBUG 552162562Sjhb printf("ok\n"); 553162562Sjhb#endif 554162562Sjhb 555162562Sjhb /* Finish out the transaction. */ 556162562Sjhb 557162562Sjhb /* Clear OBF */ 558182321Sjhb if (status & KCS_STATUS_OBF) 559162562Sjhb data = INB(sc, KCS_DATA); 560162562Sjhb 561162562Sjhb /* 0x00 to DATA_IN */ 562162562Sjhb OUTB(sc, KCS_DATA, 0); 563162562Sjhb 564162562Sjhb /* Wait for IBF = 0 */ 565162562Sjhb status = INB(sc, KCS_CTL_STS); 566162562Sjhb while (status & KCS_STATUS_IBF) { 567162562Sjhb DELAY(100); 568162562Sjhb status = INB(sc, KCS_CTL_STS); 569162562Sjhb } 570162562Sjhb 571162562Sjhb if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) { 572162562Sjhb /* Wait for IBF = 1 */ 573162562Sjhb while (!(status & KCS_STATUS_OBF)) { 574162562Sjhb DELAY(100); 575162562Sjhb status = INB(sc, KCS_CTL_STS); 576162562Sjhb } 577162562Sjhb 578162562Sjhb /* Read error status. */ 579162562Sjhb data = INB(sc, KCS_DATA); 580162562Sjhb 581162562Sjhb /* Write dummy READ to DATA_IN. */ 582162562Sjhb OUTB(sc, KCS_DATA, KCS_DATA_IN_READ); 583162562Sjhb 584162562Sjhb /* Wait for IBF = 0 */ 585162562Sjhb status = INB(sc, KCS_CTL_STS); 586162562Sjhb while (status & KCS_STATUS_IBF) { 587162562Sjhb DELAY(100); 588162562Sjhb status = INB(sc, KCS_CTL_STS); 589162562Sjhb } 590162562Sjhb } 591162562Sjhb 592162562Sjhb if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) { 593162562Sjhb /* Wait for IBF = 1 */ 594162562Sjhb while (!(status & KCS_STATUS_OBF)) { 595162562Sjhb DELAY(100); 596162562Sjhb status = INB(sc, KCS_CTL_STS); 597162562Sjhb } 598162562Sjhb 599162562Sjhb /* Clear OBF */ 600182321Sjhb if (status & KCS_STATUS_OBF) 601162562Sjhb data = INB(sc, KCS_DATA); 602162562Sjhb } else 603162562Sjhb device_printf(sc->ipmi_dev, "KCS probe: end state %x\n", 604162562Sjhb KCS_STATUS_STATE(status)); 605162562Sjhb 606162562Sjhb return (1); 607162562Sjhb} 608