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