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); 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 324278321Sjhb IPMI_IO_LOCK(sc); 325278321Sjhb 326162562Sjhb /* Send the request. */ 327162562Sjhb if (!kcs_start_write(sc)) { 328162562Sjhb device_printf(sc->ipmi_dev, "KCS: Failed to start write\n"); 329162562Sjhb goto fail; 330162562Sjhb } 331162562Sjhb#ifdef KCS_DEBUG 332162562Sjhb device_printf(sc->ipmi_dev, "KCS: WRITE_START... ok\n"); 333162562Sjhb#endif 334162562Sjhb 335162562Sjhb if (!kcs_write_byte(sc, req->ir_addr)) { 336162562Sjhb device_printf(sc->ipmi_dev, "KCS: Failed to write address\n"); 337162562Sjhb goto fail; 338162562Sjhb } 339162562Sjhb#ifdef KCS_DEBUG 340162562Sjhb device_printf(sc->ipmi_dev, "KCS: Wrote address: %02x\n", req->ir_addr); 341162562Sjhb#endif 342162562Sjhb 343162562Sjhb if (req->ir_requestlen == 0) { 344162562Sjhb if (!kcs_write_last_byte(sc, req->ir_command)) { 345162562Sjhb device_printf(sc->ipmi_dev, 346162562Sjhb "KCS: Failed to write command\n"); 347162562Sjhb goto fail; 348162562Sjhb } 349162562Sjhb#ifdef KCS_DEBUG 350162562Sjhb device_printf(sc->ipmi_dev, "KCS: Wrote command: %02x\n", 351162562Sjhb req->ir_command); 352162562Sjhb#endif 353162562Sjhb } else { 354162562Sjhb if (!kcs_write_byte(sc, req->ir_command)) { 355162562Sjhb device_printf(sc->ipmi_dev, 356162562Sjhb "KCS: Failed to write command\n"); 357162562Sjhb goto fail; 358162562Sjhb } 359162562Sjhb#ifdef KCS_DEBUG 360162562Sjhb device_printf(sc->ipmi_dev, "KCS: Wrote command: %02x\n", 361162562Sjhb req->ir_command); 362162562Sjhb#endif 363162562Sjhb 364162562Sjhb cp = req->ir_request; 365162562Sjhb for (i = 0; i < req->ir_requestlen - 1; i++) { 366162562Sjhb if (!kcs_write_byte(sc, *cp++)) { 367162562Sjhb device_printf(sc->ipmi_dev, 368162562Sjhb "KCS: Failed to write data byte %d\n", 369162562Sjhb i + 1); 370162562Sjhb goto fail; 371162562Sjhb } 372162562Sjhb#ifdef KCS_DEBUG 373162562Sjhb device_printf(sc->ipmi_dev, "KCS: Wrote data: %02x\n", 374162562Sjhb cp[-1]); 375162562Sjhb#endif 376162562Sjhb } 377162562Sjhb 378162562Sjhb if (!kcs_write_last_byte(sc, *cp)) { 379162562Sjhb device_printf(sc->ipmi_dev, 380162562Sjhb "KCS: Failed to write last dta byte\n"); 381162562Sjhb goto fail; 382162562Sjhb } 383162562Sjhb#ifdef KCS_DEBUG 384162562Sjhb device_printf(sc->ipmi_dev, "KCS: Wrote last data: %02x\n", 385162562Sjhb *cp); 386162562Sjhb#endif 387162562Sjhb } 388162562Sjhb 389162562Sjhb /* Read the reply. First, read the NetFn/LUN. */ 390162562Sjhb if (kcs_read_byte(sc, &data) != 1) { 391162562Sjhb device_printf(sc->ipmi_dev, "KCS: Failed to read address\n"); 392162562Sjhb goto fail; 393162562Sjhb } 394162562Sjhb#ifdef KCS_DEBUG 395162562Sjhb device_printf(sc->ipmi_dev, "KCS: Read address: %02x\n", data); 396162562Sjhb#endif 397162562Sjhb if (data != IPMI_REPLY_ADDR(req->ir_addr)) { 398162562Sjhb device_printf(sc->ipmi_dev, "KCS: Reply address mismatch\n"); 399162562Sjhb goto fail; 400162562Sjhb } 401162562Sjhb 402162562Sjhb /* Next we read the command. */ 403162562Sjhb if (kcs_read_byte(sc, &data) != 1) { 404162562Sjhb device_printf(sc->ipmi_dev, "KCS: Failed to read command\n"); 405162562Sjhb goto fail; 406162562Sjhb } 407162562Sjhb#ifdef KCS_DEBUG 408162562Sjhb device_printf(sc->ipmi_dev, "KCS: Read command: %02x\n", data); 409162562Sjhb#endif 410162562Sjhb if (data != req->ir_command) { 411162562Sjhb device_printf(sc->ipmi_dev, "KCS: Command mismatch\n"); 412162562Sjhb goto fail; 413162562Sjhb } 414162562Sjhb 415162562Sjhb /* Next we read the completion code. */ 416162562Sjhb if (kcs_read_byte(sc, &req->ir_compcode) != 1) { 417162562Sjhb device_printf(sc->ipmi_dev, 418162562Sjhb "KCS: Failed to read completion code\n"); 419162562Sjhb goto fail; 420162562Sjhb } 421162562Sjhb#ifdef KCS_DEBUG 422162562Sjhb device_printf(sc->ipmi_dev, "KCS: Read completion code: %02x\n", 423162562Sjhb req->ir_compcode); 424162562Sjhb#endif 425162562Sjhb 426162562Sjhb /* Finally, read the reply from the BMC. */ 427162562Sjhb i = 0; 428162562Sjhb for (;;) { 429162562Sjhb state = kcs_read_byte(sc, &data); 430162562Sjhb if (state == 0) { 431162562Sjhb device_printf(sc->ipmi_dev, 432162562Sjhb "KCS: Read failed on byte %d\n", i + 1); 433162562Sjhb goto fail; 434162562Sjhb } 435162562Sjhb if (state == 2) 436162562Sjhb break; 437162562Sjhb if (i < req->ir_replybuflen) { 438162562Sjhb req->ir_reply[i] = data; 439162562Sjhb#ifdef KCS_DEBUG 440162562Sjhb device_printf(sc->ipmi_dev, "KCS: Read data %02x\n", 441162562Sjhb data); 442162562Sjhb } else { 443162562Sjhb device_printf(sc->ipmi_dev, 444162562Sjhb "KCS: Read short %02x byte %d\n", data, i + 1); 445162562Sjhb#endif 446162562Sjhb } 447162562Sjhb i++; 448162562Sjhb } 449278321Sjhb IPMI_IO_UNLOCK(sc); 450162562Sjhb req->ir_replylen = i; 451162562Sjhb#ifdef KCS_DEBUG 452162562Sjhb device_printf(sc->ipmi_dev, "KCS: READ finished (%d bytes)\n", i); 453162562Sjhb if (req->ir_replybuflen < i) 454162562Sjhb#else 455162562Sjhb if (req->ir_replybuflen < i && req->ir_replybuflen != 0) 456162562Sjhb#endif 457162562Sjhb device_printf(sc->ipmi_dev, 458162562Sjhb "KCS: Read short: %zd buffer, %d actual\n", 459162562Sjhb req->ir_replybuflen, i); 460162562Sjhb return (1); 461162562Sjhbfail: 462162562Sjhb kcs_error(sc); 463278321Sjhb IPMI_IO_UNLOCK(sc); 464162562Sjhb return (0); 465162562Sjhb} 466162562Sjhb 467162562Sjhbstatic void 468162562Sjhbkcs_loop(void *arg) 469162562Sjhb{ 470162562Sjhb struct ipmi_softc *sc = arg; 471162562Sjhb struct ipmi_request *req; 472162562Sjhb int i, ok; 473162562Sjhb 474162562Sjhb IPMI_LOCK(sc); 475162562Sjhb while ((req = ipmi_dequeue_request(sc)) != NULL) { 476248705Smelifaro IPMI_UNLOCK(sc); 477162562Sjhb ok = 0; 478162562Sjhb for (i = 0; i < 3 && !ok; i++) 479162562Sjhb ok = kcs_polled_request(sc, req); 480162562Sjhb if (ok) 481162562Sjhb req->ir_error = 0; 482162562Sjhb else 483162562Sjhb req->ir_error = EIO; 484248705Smelifaro IPMI_LOCK(sc); 485162562Sjhb ipmi_complete_request(sc, req); 486162562Sjhb } 487162562Sjhb IPMI_UNLOCK(sc); 488172836Sjulian kproc_exit(0); 489162562Sjhb} 490162562Sjhb 491162562Sjhbstatic int 492162562Sjhbkcs_startup(struct ipmi_softc *sc) 493162562Sjhb{ 494162562Sjhb 495172836Sjulian return (kproc_create(kcs_loop, sc, &sc->ipmi_kthread, 0, 0, "%s: kcs", 496162562Sjhb device_get_nameunit(sc->ipmi_dev))); 497162562Sjhb} 498162562Sjhb 499278321Sjhbstatic int 500278321Sjhbkcs_driver_request(struct ipmi_softc *sc, struct ipmi_request *req, int timo) 501278321Sjhb{ 502278321Sjhb int i, ok; 503278321Sjhb 504278321Sjhb ok = 0; 505278321Sjhb for (i = 0; i < 3 && !ok; i++) 506278321Sjhb ok = kcs_polled_request(sc, req); 507278321Sjhb if (ok) 508278321Sjhb req->ir_error = 0; 509278321Sjhb else 510278321Sjhb req->ir_error = EIO; 511278321Sjhb return (req->ir_error); 512278321Sjhb} 513278321Sjhb 514162562Sjhbint 515162562Sjhbipmi_kcs_attach(struct ipmi_softc *sc) 516162562Sjhb{ 517162562Sjhb int status; 518162562Sjhb 519162562Sjhb /* Setup function pointers. */ 520162562Sjhb sc->ipmi_startup = kcs_startup; 521162562Sjhb sc->ipmi_enqueue_request = ipmi_polled_enqueue_request; 522278321Sjhb sc->ipmi_driver_request = kcs_driver_request; 523281941Sjhb sc->ipmi_driver_requests_polled = 1; 524162562Sjhb 525162562Sjhb /* See if we can talk to the controller. */ 526162562Sjhb status = INB(sc, KCS_CTL_STS); 527162562Sjhb if (status == 0xff) { 528162562Sjhb device_printf(sc->ipmi_dev, "couldn't find it\n"); 529162562Sjhb return (ENXIO); 530162562Sjhb } 531162562Sjhb 532162562Sjhb#ifdef KCS_DEBUG 533162562Sjhb device_printf(sc->ipmi_dev, "KCS: initial state: %02x\n", status); 534162562Sjhb#endif 535162562Sjhb if (status & KCS_STATUS_OBF || 536162562Sjhb KCS_STATUS_STATE(status) != KCS_STATUS_STATE_IDLE) 537162562Sjhb kcs_error(sc); 538162562Sjhb 539162562Sjhb return (0); 540162562Sjhb} 541162562Sjhb 542162562Sjhb/* 543162562Sjhb * Determine the alignment automatically for a PCI attachment. In this case, 544162562Sjhb * any unused bytes will return 0x00 when read. We make use of the C/D bit 545162562Sjhb * in the CTL_STS register to try to start a GET_STATUS transaction. When 546162562Sjhb * we write the command, that bit should be set, so we should get a non-zero 547162562Sjhb * value back when we read CTL_STS if the offset we are testing is the CTL_STS 548162562Sjhb * register. 549162562Sjhb */ 550162562Sjhbint 551162562Sjhbipmi_kcs_probe_align(struct ipmi_softc *sc) 552162562Sjhb{ 553162562Sjhb int data, status; 554162562Sjhb 555162562Sjhb sc->ipmi_io_spacing = 1; 556162562Sjhbretry: 557162562Sjhb#ifdef KCS_DEBUG 558162562Sjhb device_printf(sc->ipmi_dev, "Trying KCS align %d... ", sc->ipmi_io_spacing); 559162562Sjhb#endif 560162562Sjhb 561162562Sjhb /* Wait for IBF = 0 */ 562162562Sjhb status = INB(sc, KCS_CTL_STS); 563162562Sjhb while (status & KCS_STATUS_IBF) { 564162562Sjhb DELAY(100); 565162562Sjhb status = INB(sc, KCS_CTL_STS); 566162562Sjhb } 567162562Sjhb 568162562Sjhb OUTB(sc, KCS_CTL_STS, KCS_CONTROL_GET_STATUS_ABORT); 569162562Sjhb 570162562Sjhb /* Wait for IBF = 0 */ 571162562Sjhb status = INB(sc, KCS_CTL_STS); 572162562Sjhb while (status & KCS_STATUS_IBF) { 573162562Sjhb DELAY(100); 574162562Sjhb status = INB(sc, KCS_CTL_STS); 575162562Sjhb } 576162562Sjhb 577162562Sjhb /* If we got 0x00 back, then this must not be the CTL_STS register. */ 578162562Sjhb if (status == 0) { 579162562Sjhb#ifdef KCS_DEBUG 580162562Sjhb printf("failed\n"); 581162562Sjhb#endif 582162562Sjhb sc->ipmi_io_spacing <<= 1; 583162562Sjhb if (sc->ipmi_io_spacing > 4) 584162562Sjhb return (0); 585162562Sjhb goto retry; 586162562Sjhb } 587162562Sjhb#ifdef KCS_DEBUG 588162562Sjhb printf("ok\n"); 589162562Sjhb#endif 590162562Sjhb 591162562Sjhb /* Finish out the transaction. */ 592162562Sjhb 593162562Sjhb /* Clear OBF */ 594182321Sjhb if (status & KCS_STATUS_OBF) 595162562Sjhb data = INB(sc, KCS_DATA); 596162562Sjhb 597162562Sjhb /* 0x00 to DATA_IN */ 598162562Sjhb OUTB(sc, KCS_DATA, 0); 599162562Sjhb 600162562Sjhb /* Wait for IBF = 0 */ 601162562Sjhb status = INB(sc, KCS_CTL_STS); 602162562Sjhb while (status & KCS_STATUS_IBF) { 603162562Sjhb DELAY(100); 604162562Sjhb status = INB(sc, KCS_CTL_STS); 605162562Sjhb } 606162562Sjhb 607162562Sjhb if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) { 608162562Sjhb /* Wait for IBF = 1 */ 609162562Sjhb while (!(status & KCS_STATUS_OBF)) { 610162562Sjhb DELAY(100); 611162562Sjhb status = INB(sc, KCS_CTL_STS); 612162562Sjhb } 613162562Sjhb 614162562Sjhb /* Read error status. */ 615162562Sjhb data = INB(sc, KCS_DATA); 616162562Sjhb 617162562Sjhb /* Write dummy READ to DATA_IN. */ 618162562Sjhb OUTB(sc, KCS_DATA, KCS_DATA_IN_READ); 619162562Sjhb 620162562Sjhb /* Wait for IBF = 0 */ 621162562Sjhb status = INB(sc, KCS_CTL_STS); 622162562Sjhb while (status & KCS_STATUS_IBF) { 623162562Sjhb DELAY(100); 624162562Sjhb status = INB(sc, KCS_CTL_STS); 625162562Sjhb } 626162562Sjhb } 627162562Sjhb 628162562Sjhb if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) { 629162562Sjhb /* Wait for IBF = 1 */ 630162562Sjhb while (!(status & KCS_STATUS_OBF)) { 631162562Sjhb DELAY(100); 632162562Sjhb status = INB(sc, KCS_CTL_STS); 633162562Sjhb } 634162562Sjhb 635162562Sjhb /* Clear OBF */ 636182321Sjhb if (status & KCS_STATUS_OBF) 637162562Sjhb data = INB(sc, KCS_DATA); 638162562Sjhb } else 639162562Sjhb device_printf(sc->ipmi_dev, "KCS probe: end state %x\n", 640162562Sjhb KCS_STATUS_STATE(status)); 641162562Sjhb 642162562Sjhb return (1); 643162562Sjhb} 644